diff --git a/db_sql/log_payment.sql b/db_sql/log_payment.sql new file mode 100644 index 0000000..41da81a --- /dev/null +++ b/db_sql/log_payment.sql @@ -0,0 +1,100 @@ +-- +-- , , VIN + +-- ID +CREATE SEQUENCE payment_logs_seq + START WITH 1 + INCREMENT BY 1 + CACHE 100; + +-- +CREATE TABLE payment_logs ( + log_id NUMBER PRIMARY KEY, + + -- + user_id NUMBER NOT NULL, + user_first_name VARCHAR2(255), + user_last_name VARCHAR2(255), + user_username VARCHAR2(255), + user_language_code VARCHAR2(10), + user_is_premium NUMBER(1) DEFAULT 0, + + -- + service_type VARCHAR2(50) NOT NULL, -- 'decode_vin', 'check_salvage', 'get_photos' + vin_number VARCHAR2(17) NOT NULL, + + -- + payment_amount NUMBER(10,2) NOT NULL, + transaction_id VARCHAR2(255), + payment_status VARCHAR2(50) DEFAULT 'completed', -- 'completed', 'pending', 'failed' + payment_currency VARCHAR2(10) DEFAULT 'XTR', + + -- + service_status VARCHAR2(50), -- 'success', 'failed', 'no_data', 'error' + data_found_count NUMBER DEFAULT 0, -- / + refund_status VARCHAR2(50) DEFAULT 'no_refund', -- 'no_refund', 'auto_refund', 'manual_refund', 'admin_refund' + refund_reason VARCHAR2(500), + + -- + vehicle_make VARCHAR2(100), + vehicle_model VARCHAR2(100), + vehicle_year VARCHAR2(10), + + -- + error_message CLOB, + created_date DATE DEFAULT SYSDATE, + ip_address VARCHAR2(45), -- + + -- + CONSTRAINT chk_service_type CHECK (service_type IN ('decode_vin', 'check_salvage', 'get_photos')), + CONSTRAINT chk_payment_status CHECK (payment_status IN ('completed', 'pending', 'failed')), + CONSTRAINT chk_service_status CHECK (service_status IN ('success', 'failed', 'no_data', 'error', 'pending')), + CONSTRAINT chk_refund_status CHECK (refund_status IN ('no_refund', 'auto_refund', 'manual_refund', 'admin_refund')) +); + +-- +CREATE INDEX idx_payment_logs_user_id ON payment_logs(user_id); +CREATE INDEX idx_payment_logs_vin ON payment_logs(vin_number); +CREATE INDEX idx_payment_logs_service_type ON payment_logs(service_type); +CREATE INDEX idx_payment_logs_date ON payment_logs(created_date); +CREATE INDEX idx_payment_logs_transaction_id ON payment_logs(transaction_id); +CREATE INDEX idx_payment_logs_status ON payment_logs(payment_status, service_status); + +-- +COMMENT ON TABLE payment_logs IS ' '; +COMMENT ON COLUMN payment_logs.log_id IS ' '; +COMMENT ON COLUMN payment_logs.user_id IS 'ID Telegram'; +COMMENT ON COLUMN payment_logs.service_type IS ' : decode_vin, check_salvage, get_photos'; +COMMENT ON COLUMN payment_logs.vin_number IS 'VIN '; +COMMENT ON COLUMN payment_logs.payment_amount IS ' Telegram Stars'; +COMMENT ON COLUMN payment_logs.transaction_id IS 'ID Telegram'; +COMMENT ON COLUMN payment_logs.data_found_count IS ' (, ..)'; +COMMENT ON COLUMN payment_logs.refund_status IS ' '; +COMMENT ON COLUMN payment_logs.created_date IS ' '; + +-- +CREATE OR REPLACE VIEW payment_analytics AS +SELECT + service_type, + COUNT(*) as total_transactions, + SUM(payment_amount) as total_revenue, + AVG(payment_amount) as avg_payment, + COUNT(CASE WHEN refund_status != 'no_refund' THEN 1 END) as refunds_count, + COUNT(CASE WHEN service_status = 'success' THEN 1 END) as successful_services, + ROUND(COUNT(CASE WHEN service_status = 'success' THEN 1 END) * 100.0 / COUNT(*), 2) as success_rate, + TRUNC(created_date) as date_created +FROM payment_logs +GROUP BY service_type, TRUNC(created_date) +ORDER BY date_created DESC, service_type; + + +-- created_date +CREATE OR REPLACE TRIGGER trg_payment_logs_created_date + BEFORE INSERT ON payment_logs + FOR EACH ROW +BEGIN + IF :NEW.created_date IS NULL THEN + :NEW.created_date := SYSDATE; + END IF; +END; +/ diff --git a/main.py b/main.py index d754ee2..b86c41c 100644 --- a/main.py +++ b/main.py @@ -473,6 +473,62 @@ async def help_callback(callback: CallbackQuery, db: OracleDatabase = None): await callback.answer() +@dp.callback_query(lambda c: c.data == "prices") +async def prices_callback(callback: CallbackQuery, db: OracleDatabase = None): + # Используем переданный db или глобальный oracle_db + database = db or oracle_db + + # Сохраняем данные пользователя при просмотре цен + await database.save_user(callback.from_user, "prices_button") + + prices_text = ( + "💰 **Our Service Prices**\n\n" + + "🔍 **VIN Decoding Service:**\n" + f"• Basic info (make, model, year): **FREE** 🆓\n" + f"• Detailed specifications: **{DECODE_PRICE} ⭐**\n" + f" └ Engine details, transmission, safety features\n" + f" └ Dimensions, construction, brake system\n" + f" └ Lighting, additional features, NCSA data\n\n" + + "🚨 **Salvage Check Service:**\n" + f"• Records count check: **FREE** 🆓\n" + f"• Detailed damage history: **{CHECK_PRICE} ⭐**\n" + f" └ Primary and secondary damage types\n" + f" └ Sale dates and auction locations\n" + f" └ Odometer readings and repair costs\n" + f" └ Engine/drive status information\n\n" + + "📸 **Vehicle Photos Service:**\n" + f"• Photo availability check: **FREE** 🆓\n" + f"• Access to damage photos: **{IMG_PRICE} ⭐**\n" + f" └ High-quality auction images\n" + f" └ Multiple angles of vehicle damage\n" + f" └ Before and after condition photos\n\n" + + "⭐ **Payment Information:**\n" + "• All payments made with **Telegram Stars**\n" + "• Instant delivery after successful payment\n" + "• Automatic refund if no data found\n" + "• Admin users get automatic refunds\n\n" + + "💡 **Money-back guarantee:** If we can't provide the requested data, " + "your payment will be automatically refunded!" + ) + + builder = InlineKeyboardBuilder() + builder.button(text=f"🔍 Decode for {DECODE_PRICE} ⭐", callback_data="decode_vin") + builder.button(text=f"🚨 Check for {CHECK_PRICE} ⭐", callback_data="check_vin") + builder.button(text=f"📸 Photos for {IMG_PRICE} ⭐", callback_data="search_car_photo") + builder.adjust(3) + builder.button(text="ℹ️ Help", callback_data="help") + builder.button(text="🏠 Back to Main Menu", callback_data="main_menu") + builder.adjust(2, 1) + + await callback.message.answer(prices_text, reply_markup=builder.as_markup(), parse_mode="Markdown") + await callback.answer() + + @dp.callback_query(lambda c: c.data and c.data.startswith("pay_detailed_info:")) async def pay_detailed_info_callback(callback: CallbackQuery, db: OracleDatabase = None): # Используем переданный db или глобальный oracle_db