From 2c3816badbab2fbc17f51004453a8395890408b7 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Tue, 16 Jun 2026 22:44:11 +0300 Subject: [PATCH] Update: 2026-06-16 22:44:11 --- INFRASTRUCTURE_REPORT.md | 460 +++++++++ scratch/payment_simulation.py | 289 ++++++ .../reports/problems/problems-report.html | 2 +- walletintaleq.intaleq.xyz/WalletDB.sql | 970 ++++++++++++++++++ .../v2/main/jwtconnect.php | 99 +- .../v2/main/ride/cliq/finalize_payment.php | 12 +- .../v2/main/ride/driverWallet/add.php | 150 ++- .../main/ride/driverWallet/addFromAdmin.php | 124 ++- .../ride/driverWallet/sendEmailTransfer.php | 12 +- .../v2/main/ride/driverWallet/transfer.php | 8 +- .../main/ride/ecash/driver/ecash_verify.php | 148 +++ .../main/ride/ecash/driver/ecash_webhook.php | 91 ++ .../ride/ecash/driver/finalize_payment.php | 79 ++ .../main/ride/ecash/driver/payWithEcash.php | 88 ++ .../ride/ecash/driver/webhook_connect.php | 42 + .../v2/main/ride/ecash/ecash_config.php | 44 + .../main/ride/ecash/logs/ecash_production.log | 264 +++++ .../ride/ecash/logs/payment_verification.log | 9 + .../ride/ecash/passenger/ecash_verify.php | 181 ++++ .../ride/ecash/passenger/ecash_webhook.php | 91 ++ .../ride/ecash/passenger/finalize_payment.php | 79 ++ .../ride/ecash/passenger/payWithEcash.php | 88 ++ .../ride/ecash/passenger/webhook_connect.php | 42 + .../v2/main/ride/ecash/payWithEcash.php | 73 ++ .../v2/main/ride/ecash/webhook_ecash.php | 310 ++++++ .../main/ride/mtn/driver/confirm_payment.php | 125 +++ .../mtn/driver/finalize_wallet_payment.php | 103 ++ .../v2/main/ride/mtn/driver/generate_keys.php | 47 + .../main/ride/mtn/driver/initiate_payment.php | 54 + .../v2/main/ride/mtn/driver/key.php | 56 + .../v2/main/ride/mtn/driver/mtn_start.php | 129 +++ .../v2/main/ride/mtn/driver/private_key.pem | 15 + .../v2/main/ride/mtn/driver/public_key.pem | 6 + .../v2/main/ride/mtn/driver_payout_syria.php | 115 +++ .../ride/mtn/passenger/confirm_payment.php | 169 +++ .../mtn/passenger/finalize_wallet_payment.php | 103 ++ .../main/ride/mtn/passenger/generate_keys.php | 47 + .../ride/mtn/passenger/initiate_payment.php | 54 + .../v2/main/ride/mtn/passenger/key.php | 56 + .../main/ride/mtn/passenger/mtn_confirm.php | 247 +++++ .../v2/main/ride/mtn/passenger/mtn_start.php | 130 +++ .../main/ride/mtn/passenger/private_key.pem | 15 + .../v2/main/ride/mtn/passenger/public_key.pem | 6 + .../v2/main/ride/mtn_new/finalize_payment.php | 12 +- .../v2/main/ride/payMob/error_log | 0 .../v2/main/ride/payMob/payWithPayMob.php | 100 ++ .../v2/main/ride/payMob/paymet_verfy.php | 358 +++++++ .../v2/main/ride/payMob/paymet_verfy.php.zip | Bin 0 -> 6293 bytes .../ride/payMob/paymob_driver/payWithCard.php | 100 ++ .../payMob/paymob_driver/payWithWallet.php | 118 +++ .../payMob/paymob_driver/paymet_verfy.php | 146 +++ .../payMob/paymob_driver/paymob_payout.php | 110 ++ .../paymob_driver/paymob_webHookWallet.php | 142 +++ .../payMob/paymob_driver/paymob_webhook.php | 142 +++ .../v2/main/ride/payMob/paymob_webhook.log | 33 + .../v2/main/ride/payMob/paymob_webhook.php | 137 +++ .../v2/main/ride/payMob/wallet/error_log | 27 + .../main/ride/payMob/wallet/payWithPayMob.php | 129 +++ .../main/ride/payMob/wallet/paymet_verfy.php | 358 +++++++ .../ride/payMob/wallet/paymob_webhook.php | 137 +++ .../v2/main/ride/shamcash/check_status.php | 22 + .../ride/shamcash/create_invoice_shamcash.php | 45 + .../v2/main/ride/shamcash/deposit_errors.log | 7 + .../main/ride/shamcash/finalize_deposit.php | 120 +++ .../v2/main/ride/shamcash/last_id.txt | 1 + .../ride/shamcash/passenger/check_status.php | 22 + .../shamcash/passenger/create_invoice.php | 41 + .../shamcash/passenger/finalize_deposit.php | 127 +++ .../main/ride/shamcash/save_transactions.php | 121 +++ .../ride/shamcash/save_transactions_new.php | 117 +++ .../v2/main/ride/shamcash/server_check.php | 60 ++ .../v2/main/ride/shamcash/transactions.log | 100 ++ .../ride/{seferWallet => siroWallet}/add.php | 6 +- .../ride/{seferWallet => siroWallet}/get.php | 2 +- .../v2/main/ride/syriatel/archive.zip | Bin 0 -> 6175 bytes .../ride/syriatel/driver/confirm_payment.php | 237 +++++ .../driver/finalize_wallet_payment.php | 127 +++ .../ride/syriatel/driver/start_payment.php | 141 +++ .../driver/syriatel_token_handler.php | 74 ++ .../syriatel/logs/payment_verification.log | 25 + .../syriatel/passenger/confirm_payment.php | 201 ++++ .../ride/syriatel/passenger/start_payment.php | 124 +++ .../syriatel/passenger/syriatel_token.cache | 1 + .../passenger/syriatel_token_handler.php | 74 ++ .../v2/main/sms_webhook/archive.zip | Bin 0 -> 8994 bytes .../main/sms_webhook/check_invoice_status.php | 44 + .../check_invoice_status_passenger.php | 36 + .../v2/main/sms_webhook/create_invoice.php | 103 ++ .../sms_webhook/create_invoice_passenger.php | 126 +++ .../v2/main/sms_webhook/finalize_payout.php | 127 +++ .../sms_webhook/finalize_wallet_payment.php | 112 ++ .../process_passenger_sms_payment.php | 255 +++++ .../main/sms_webhook/process_with_gemini.php | 132 +++ .../v2/main/sms_webhook/request_payout.php | 84 ++ .../v2/main/sms_webhook/save_raw_sms.php | 37 + .../sms_webhook/save_raw_sms_passenger.php | 37 + .../v2/main/sms_webhook/webhook.php | 84 ++ 97 files changed, 10137 insertions(+), 116 deletions(-) create mode 100644 INFRASTRUCTURE_REPORT.md create mode 100644 scratch/payment_simulation.py create mode 100644 walletintaleq.intaleq.xyz/WalletDB.sql create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_verify.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_webhook.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/finalize_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/payWithEcash.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/webhook_connect.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/ecash_config.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/ecash_production.log create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/payment_verification.log create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_verify.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_webhook.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/finalize_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/payWithEcash.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/webhook_connect.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/payWithEcash.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/ecash/webhook_ecash.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/confirm_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/finalize_wallet_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/generate_keys.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/initiate_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/key.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/mtn_start.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/private_key.pem create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/public_key.pem create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver_payout_syria.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/confirm_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/finalize_wallet_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/generate_keys.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/initiate_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/key.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_confirm.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_start.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/private_key.pem create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/public_key.pem create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/error_log create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/payWithPayMob.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php.zip create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithCard.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithWallet.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymet_verfy.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_payout.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webHookWallet.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webhook.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.log create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/error_log create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/payWithPayMob.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymet_verfy.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymob_webhook.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/check_status.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/create_invoice_shamcash.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/deposit_errors.log create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/finalize_deposit.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/last_id.txt create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/check_status.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/create_invoice.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/finalize_deposit.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions_new.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/server_check.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/shamcash/transactions.log rename walletintaleq.intaleq.xyz/v2/main/ride/{seferWallet => siroWallet}/add.php (95%) rename walletintaleq.intaleq.xyz/v2/main/ride/{seferWallet => siroWallet}/get.php (92%) create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/archive.zip create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/finalize_wallet_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/start_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/syriatel_token_handler.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/logs/payment_verification.log create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/start_payment.php create mode 100644 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token.cache create mode 100755 walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token_handler.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/archive.zip create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status_passenger.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice_passenger.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_payout.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_wallet_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_passenger_sms_payment.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_with_gemini.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/request_payout.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms_passenger.php create mode 100755 walletintaleq.intaleq.xyz/v2/main/sms_webhook/webhook.php diff --git a/INFRASTRUCTURE_REPORT.md b/INFRASTRUCTURE_REPORT.md new file mode 100644 index 0000000..45e78db --- /dev/null +++ b/INFRASTRUCTURE_REPORT.md @@ -0,0 +1,460 @@ +# تقرير البنية التحتية لنظام سيرو (Siro) - النشر في سوريا + +**التاريخ:** 16 يونيو 2026 +**المشروع:** Siro - تطبيق نقل الركاب +**الموقع:** سوريا + +--- + +## 📊 ملخص الخدمات المطلوبة + +| الخدمة | الدور | بروتوكول | بوابات | +|--------|-------|-----------|--------| +| **Load Balancer** | توزيع الأحمال على API | HTTP/HTTPS | 80, 443 | +| **API Server x2** | المعالجة الرئيسية | HTTP/HTTPS | 8080 (داخلي) | +| **MySQL Server** | قاعدة البيانات الرئيسية | MySQL | 3306 (داخلي) | +| **Redis Server** | كاش + مواقع السائقين | Redis | 6379 (داخلي) | +| **Driver Socket** | WebSocket للسائقين | WS/WSS + HTTP | 2020, 2021 | +| **Passenger Socket** | WebSocket للركاب | WS/WSS + HTTP | 3030, 3031 | +| **Wallet Server** | نظام المحفظة والمدفوعات | HTTP/HTTPS | 8081 (داخلي) | +| **OSRM Server (1-2)** | محرك التوجيه والخرائط | HTTP | 5000 (داخلي) | +| **Map SaaS** | خدمات الخرائط المخصصة | HTTP/HTTPS | 8082 | + +--- + +## 🖥️ 1. Load Balancer (موازن الأحمال) + +**الجهاز/السيرفر: جهاز واحد - عقدة أمامية** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 2 Core (Xeon / AMD EPYC) | لا يحتاج طاقة معالجة، فقط توجيه الطلبات | +| **الرام** | 4 GB | HAProxy/Nginx يستهلك القليل | +| **التخزين** | 50 GB SSD | نظام تشغيل + سجلات | +| **الشبكة** | 1 Gbps | استيعاب حجم الطلبات | +| **نظام التشغيل** | Ubuntu 22.04 LTS أو Rocky Linux 9 | | + +**البرامج المطلوبة:** +- Nginx ( reverse proxy + SSL termination + load balancing upstream للـ API servers ) +- HAProxy (اختياري للـ TCP load balancing للسوكتات) +- Keepalived (لـ High Availability إذا أردت أكثر من موازن) +- Certbot / Let's Encrypt (لشهادات SSL) + +**نظام التوزيع المقترح:** +``` +Nginx upstream → API Server 1 (weight=5) + API Server 2 (weight=5) + └── Round Robin أو Least Connections +``` + +--- + +## 🖥️ 2. API Backend Server (سيرفر الباك إند الرئيسي) + +**العدد: 2 سيرفرات خلف الـ Load Balancer** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 8 Core (Xeon / AMD EPYC) | PHP-FPM يحتاج عدة عمال لكل نواة؛ 8cores = 16-24 worker | +| **الرام** | 16 GB | PHP worker ~50MB/worker + نظام + كاش | +| **التخزين** | 100 GB NVMe SSD | كود المصدر + صور السائقين + سجلات | +| **الشبكة** | 1 Gbps | اتصال مع الـ DB والخدمات الأخرى | +| **نظام التشغيل** | Ubuntu 22.04 LTS | | + +**البرامج المطلوبة:** +- PHP 8.2/8.3 (مع extensions: pdo_mysql, redis, openssl, mbstring, gd) +- PHP-FPM (مع pm.max_children = 40-50 لكل سيرفر) +- Nginx للمحتوى الثابت +- Supervisor (لإدارة العمليات) + +**توجيه الطلبات من كل سيرفر:** +- `api-syria.siromove.com/siro_v3` → Main API +- `ride-syria.siromove.com/siro` → Ride API +- `location-syria.siromove.com/siro/ride/location` → Location API +- كل هذه على نفس السيرفر، نفس قاعدة البيانات الرئيسية + +**PHP-FPM Configuration:** +```ini +pm = dynamic +pm.max_children = 50 +pm.start_servers = 8 +pm.min_spare_servers = 4 +pm.max_spare_servers = 12 +pm.max_requests = 1000 +``` + +--- + +## 🗄️ 3. MySQL Database Server (سيرفر قاعدة البيانات الرئيسية) + +**العدد: 1 + 1 Replica (اختياري للنسخ الاحتياطي)** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 16 Core (Xeon / AMD EPYC) | MySQL يتوسع أفقياً مع عدد النوى | +| **الرام** | 64 GB | InnoDB Buffer Pool يحتاج ذاكرة كبيرة للأداء | +| **التخزين** | 1 TB NVMe SSD | 3 قواعد بيانات (intaleqDB1, ridesDB, locationDB) ~ 100-300 GB + سجلات | +| **الشبكة** | 10 Gbps | عمليات كتابة/قراءة مكثفة من سيرفرين API + سوكتات | +| **نظام التشغيل** | Ubuntu 22.04 LTS | | + +**ضبط MySQL المقترح:** +```ini +innodb_buffer_pool_size = 40G # 60-70% من الرام +innodb_log_file_size = 2G +innodb_flush_log_at_trx_commit = 2 # أداء أفضل للتحديثات +innodb_flush_method = O_DIRECT +max_connections = 300 # 150 لكل API server + 50 للسوكتات +tmp_table_size = 256M +max_heap_table_size = 256M +query_cache_type = 0 # OFF (MySQL 8.0 ألغاه) +``` + +**الجداول الحساسة للأداء:** +- `car_locations` - يستخدم SPATIAL indexes + GEOMETRY - تأكد من `SRID=4326` +- `car_tracks` - 2.5M+ سجل - يحتاج أرشفة دورية أو partitioning +- `ride` + `waitingRides` - استعلامات متكررة مع SPATIAL +- `palces11` - FULLTEXT search + +**ملاحظة: قاعدة بيانات الخرائط والتتبع (locationDB) هي الأكبر من حيث حجم الكتابة، يمكن وضعها على NVMe منفصل.** + +--- + +## ⚡ 4. Redis Server (سيرفر الكاش والمواقع اللحظية) + +**العدد: 1 (أو 1 + 1 Sentinel للتبديل التلقائي)** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 8 Core | Redis single-threaded للعمليات الأساسية لكن له عمليات خلفية | +| **الرام** | 32 GB | بيانات GEO (مواقع السائقين) + كاش الجلسات + rate limiting | +| **التخزين** | 100 GB NVMe | RDB/AOF persistence | +| **الشبكة** | 10 Gbps | زمن استجابة منخفض جداً مطلوب | +| **نظام التشغيل** | Ubuntu 22.04 LTS | | + +**ملاحظات هامة:** +- يجب أن يكون Redis على نفس الشبكة الداخلية (Latency < 1ms) +- الـ Socket servers (driver + passenger) يعتمدان على Redis بشكل كبير (GEOADD/GEORADIUS كل 500ms) +- حجم الذاكرة المطلوب يعتمد على عدد السائقين النشطين: كل موقع سائق ~ 200 bytes → 1M سجل = 200MB فقط +- لكن الكاش الإضافي (driver:profile:*، الجلسات) يحتاج مساحة إضافية + +**نظام الكاش:** +``` +driver_socket → Redis GEO (GEOADD) +passenger_socket → Redis GEORADIUS +API servers → Redis GET/SET (profile cache) +Rate Limiting → Redis INCR + EXPIRE +Session Store → Redis SETEX +``` + +--- + +## 🔌 5. WebSocket Servers (سيرفرات السوكت) + +### 5.1 Driver Socket Server + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 8 Core | Workerman PHP event loop مع 500ms batch | +| **الرام** | 16 GB | كل اتصال WebSocket يستهلك ذاكرة + buffer | +| **التخزين** | 50 GB SSD | سجلات فقط | +| **الشبكة** | 1 Gbps | | + +**البوابات:** `2020` (WebSocket للسائقين)، `2021` (Internal HTTP بين السوكتات) + +### 5.2 Passenger Socket Server + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 4-8 Core | أقل تحميلاً من driver socket | +| **الرام** | 8 GB | | +| **التخزين** | 50 GB SSD | | +| **الشبكة** | 1 Gbps | | + +**البوابات:** `3030` (WebSocket للركاب)، `3031` (Internal HTTP) + +**ملاحظة:** يمكن دمج السوكتين في سيرفر واحد (Driver + Passenger على نفس الجهاز) لتوفير التكاليف إذا كان عدد المستخدمين متوسطاً. أما إذا توقعتم نمواً كبيراً، فالأفضل فصلهما. + +**نظام التشغيل للسوكتات:** يفضل Ubuntu 22.04 LTS ويحتاج PHP-CLI وليس PHP-FPM + +--- + +## 💳 6. Wallet / Payment Server (سيرفر المحفظة والمدفوعات) + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 4 Core | طلبات أقل تواتراً لكنها حسّاسة | +| **الرام** | 8 GB | | +| **التخزين** | 50 GB SSD | كود + سجلات | +| **الشبكة** | 1 Gbps | | + +**ملاحظات:** +- يمكن فصله كخدمة مستقلة أو وضعه على أحد API servers +- يحتاج اتصال مع بوابات الدفع (PayMob، MTN، Syriatel Cash) +- **هام:** يحتاج HTTPS إلزامي (ضروري لأمان المدفوعات) +- إذا كانت المدفوعات محليّة في سوريا فقط، قد تحتاج بوابات دفع سورية (MTN Cash, Syriatel Cash) + +--- + +## 🗺️ 7. OSRM Routing Server (محرك التوجيه) + +**العدد: 1-2 سيرفر (حسب عدد المسارات المطلوبة)** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 16 Core | OSRM routing requests تستهلك CPU عالٍ | +| **الرام** | 32 GB | OSRM يحمل خريطة كاملة في الذاكرة | +| **التخزين** | 200 GB NVMe | بيانات OSM لسوريا + ملفات OSRM processed | +| **الشبكة** | 1 Gbps | | + +**حجم OSM لسوريا:** +- ملف الخريطة (syria-latest.osm.pbf) ~ 100-200 MB +- بعد معالجة OSRM (contracted graph) ~ 500 MB - 1 GB +- الذاكرة المطلوبة للتشغيل ~ 8-16 GB للخريطة نفسها + +**يمكنك تشغيله على Docker:** +```bash +docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/syria-latest.osm.pbf +docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-contract /data/syria-latest.osrm +docker run -t -i -p 5000:5000 -v "${PWD}:/data" osrm/osrm-backend osrm-routed --algorithm mld /data/syria-latest.osrm +``` + +--- + +## 🗺️ 8. Map SaaS Server (سيرفر الخرائط المخصص) + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 4-8 Core | | +| **الرام** | 16 GB | للـ tile caching والـ geocoding | +| **التخزين** | 200 GB SSD | Tile cache + بيانات جغرافية | +| **الشبكة** | 1 Gbps | | + +هذا السيرفر يقوم بـ: +- Reverse Geocoding (تحويل إحداثيات إلى عنوان) +- Place Search (البحث عن الأماكن) +- Route calculation (قد يمرر طلبات إلى OSRM) +- يمكن استخدام Nominatim + PostgreSQL/PostGIS للتجيكودينغ + +--- + +## 🌐 9. الشبكة (Network Topology) + +### 9.1 الشبكة الداخلية (Internal Network) + +**مفضّلة**: شبكة داخلية خاصة (VLAN / Private Subnet) + +``` + ┌─────────────┐ + │ Internet │ + └──────┬──────┘ + │ + ┌──────┴──────┐ + │ Firewall │ + │ (iptables/ │ + │ nftables) │ + └──────┬──────┘ + │ + ┌──────┴──────┐ + │Load Balancer │ + │(Nginx/HAProxy)│ + │ Public IP │ + └──────┬──────┘ + │ + ┌────────────────┼────────────────┐ + │ │ │ + ┌──────┴──────┐ ┌─────┴──────┐ ┌─────┴──────┐ + │ API SRV 1 │ │ API SRV 2 │ │ Socket SV │ + │ 10.0.1.10 │ │ 10.0.1.11 │ │10.0.1.20-21 │ + └──────┬──────┘ └─────┬──────┘ └──────┬──────┘ + │ │ │ + └────────────────┼────────────────┘ + │ + ┌────────────────┼────────────────┐ + │ │ │ + ┌──────┴──────┐ ┌─────┴──────┐ ┌─────┴──────┐ + │ MySQL DB │ │ Redis │ │ OSRM │ + │ 10.0.1.30 │ │ 10.0.1.31 │ │ 10.0.1.40 │ + └─────────────┘ └────────────┘ └────────────┘ + + ┌─────────────┐ ┌────────────┐ + │ Wallet SV │ │ Map SaaS │ + │ 10.0.1.50 │ │ 10.0.1.60 │ + └─────────────┘ └────────────┘ +``` + +**نطاق الشبكة الداخلية:** `10.0.1.0/24` (أي نطاق خاص) + +### 9.2 الشبكة الخارجية + +- السيرفرات التي تحتاج IP عام: **Load Balancer فقط** +- Socket Servers: يمكن تشغيل WebSocket على نفس Load Balancer (رفع بروتوكول WS إلى WSS) +- OSRM و Map SaaS: داخليان فقط (API servers تتصل بهم داخلياً) +- قاعدة البيانات: **ليست عامة أبداً** - فقط وصلات داخلية + +### 9.3 الإجراءات الأمنية + +- **Firewall**: فتح المنافذ التالية فقط من الخارج: + - 80 (HTTP → redirect to 443) + - 443 (HTTPS) + - 2020 (WebSocket driver - اختياري إذا прямо WS) + - 3030 (WebSocket passenger - اختياري) + - 22 (SSH - فقط من IPs محددة) + +- **Fail2ban**: على Load Balancer لحماية SSH و API +- **UFW/iptables**: على كل سيرفر لحجب المنافذ غير المستخدمة +- **VPN**: للوصول إلى الإدارة (Tailscale أو WireGuard) +- **SSL/TLS**: جميع الاتصالات الخارجية مشفرة + +### 9.4 هل شبكة داخلية أم خارجية؟ + +| الخدمة | المفضل | +|--------|--------| +| API ↔ Database | **داخلي** (VLAN 10.0.1.x) | +| API ↔ Redis | **داخلي** | +| Socket ↔ Database | **داخلي** | +| API ↔ Wallet | **داخلي** (أو خارجي إذا wallet على سيرفر مختلف كلياً) | +| API ↔ OSRM | **داخلي** | +| API ↔ Map SaaS | **داخلي** | +| Internet ↔ Load Balancer | **خارجي** | +| Driver App ↔ Socket | **خارجي** (لكن عبر Load Balancer أيضاً) | + +--- + +## 📍 10. اعتبارات خاصة لسوريا + +### 10.1 استضافة السيرفرات + +**الخيارات الموصى بها (بالترتيب):** + +1. **مراكز البيانات السورية:** + - **شركة الاتصالات السورية (STE)** - خدمات hosting واستضافة + - **Ayaa Cloud** - مزود خدمات سحابية سوري + - **SNS (Syrian Network Systems)** - colocation واستضافة + +2. **السيرفرات في دول مجاورة (للأداء):** + - **لبنان** (IDM، Ogero) - أقرب وأقل زمن استجابة (< 30ms) + - **الأردن** - خيار ممتاز (زمن استجابة ~ 30-50ms) + - **تركيا** - أقرب لشمال سوريا + - **الإمارات / السعودية** - استقرار أكبر لكن زمن استجابة أعلى (~ 80-100ms) + +3. **سيرفرات عالمية:** + - **Hetzner (ألمانيا/فنلندا)** - أفضل قيمة مقابل سعر (~ 150-200ms latency) + - **OVH (فرنسا)** - جيد + - **DigitalOcean / Linode** - للاستضافة السحابية + +### 10.2 مشاكل الإنترنت في سوريا + +| المشكلة | الحل | +|---------|------| +| **انقطاع الكهرباء** | UPS لكل سيرفر + مولد كهربائي للمركز | +| **ضعف سرعة الإنترنت** | استخدام Content Delivery (CDN) للملفات الثابتة | +| **الحجب (بعض الخدمات)** | استخدام VPN أو proxy للاتصال بخدمات خارجية (PayMob، Firebase) إذا لزم الأمر | +| **تكاليف النطاق العالي** | ضغط البيانات (gzip) + تحجيم الصور + lazy loading | +| **تذبذب الاتصال (Packet Loss)** | TCP tuning, BBR congestion control على السيرفرات | + +### 10.3 سرعة الإنترنت في سوريا + +| الخدمة | السرعة المتوقعة | ملاحظة | +|--------|-----------------|--------| +| ADSL | 4-16 Mbps | الأكثر انتشاراً | +| Fiber (FTTH) | 20-100 Mbps | متوفرة في المدن الكبرى | +| 4G/LTE | 10-50 Mbps | جيد للمستخدمين النهائيين | +| Business Line | 50-200 Mbps | المطلوب للسيرفرات | + +**لتطبيق مثالي في سوريا:** +- حجم API response يجب أن يكون < 50 KB +- حجم الصور مضغوط (WebP) +- استخدام Lazy loading للخرائط +- تفعيل HTTP/2 على الـ Load Balancer + +### 10.4 استهلاك النطاق الترددي المقدر + +| الخدمة | الاستهلاك التقريبي (شهرياً) | +|--------|---------------------------| +| API Requests (REST) | 200-500 GB | +| WebSocket Data | 500 GB - 2 TB | +| Map Tiles & Routing | 200-500 GB | +| Uploads (صور، وثائق) | 100-200 GB | +| **المجموع التقريبي** | **1-3 TB شهرياً** | + +--- + +## 📐 11. الترتيب المقترح للتنفيذ + +``` +المرحلة 1: البنية الأساسية +├── تجهيز Load Balancer (Nginx + SSL) +├── تجهيز MySQL Server (تركيب + ضبط + تحميل البيانات) +└── تجهيز Redis Server + +المرحلة 2: السيرفرات الأساسية +├── تجهيز API Server 1 (PHP + Nginx + FPM) +├── تجهيز API Server 2 (clone من 1) +└── ربط API Servers مع Load Balancer + +المرحلة 3: السيرفرات المساعدة +├── تجهيز Socket Server (Driver Socket + Passenger Socket) +├── تجهيز Wallet Server +└── ربط الكل مع قاعدة البيانات و Redis + +المرحلة 4: الخرائط +├── تجهيز OSRM Server (تحميل OSM سوريا + معالجة) +├── تجهيز Map SaaS Server +└── اختبار التوجيه والتجيكودينغ + +المرحلة 5: الاختبار والإطلاق +├── اختبار تحميل (Load Testing) - استخدام K6 أو Locust +├── اختبار WebSocket مع 1000+ مستخدم وهمي +├── مراقبة (Prometheus + Grafana) +└── الإطلاق التدريجي +``` + +--- + +## 💰 12. التكلفة التقديرية الشهرية (للسيرفرات) + +| السيرفر | المواصفات | التكلفة التقريبية (شهرياً) | +|---------|-----------|--------------------------| +| Load Balancer | 2 Core, 4GB | $20 - $40 | +| API Server x2 | 8 Core, 16GB (لكل) | $100 - $200 (لكل) | +| MySQL Server | 16 Core, 64GB, 1TB NVMe | $300 - $600 | +| Redis Server | 8 Core, 32GB | $100 - $200 | +| Socket Server(s) | 8 Core, 16GB | $80 - $150 | +| Wallet Server | 4 Core, 8GB | $40 - $80 | +| OSRM Server | 16 Core, 32GB | $200 - $400 | +| Map SaaS | 4 Core, 16GB | $60 - $120 | +| **المجموع التقريبي** | | **$900 - $1,890 شهرياً** | + +**ملاحظة:** الأسعار تقديرية وقد تختلف حسب المزود. السيرفرات داخل سوريا قد تكون أرخص ولكن بجودة شبكة أقل. + +--- + +## ✅ 13. الخلاصة والتوصيات + +1. **أفضل نموذج لنشر سيرفرات سوريا هو:** + - استضافة السيرفرات في **مركز بيانات سوري** أو **لبناني/أردني** + - استخدام **شبكة داخلية (VLAN)** لكل الاتصالات بين السيرفرات + - وضع **Load Balancer** واحد أمام API Servers (2) + - قاعدة البيانات الرئيسية + Redis على نفس الشبكة الداخلية مع اتصال 10 Gbps + +2. **توزيع الأدوار:** + - API Servers: 8 Cores + 16 GB RAM ✅ (كافٍ) + - Database: 16 Cores + 64 GB RAM ✅ (ضروري) + - Redis: 8 Cores + 32 GB RAM ✅ (ضروري للأداء اللحظي) + - Socket: 8 Cores + 16 GB RAM ✅ (كحد أدنى) + +3. **توفير التكاليف:** + - يمكن دمج Socket Servers في جهاز واحد (Driver + Passenger) لتوفير سيرفر + - يمكن دمج Wallet مع أحد API Servers + - يمكن استخدام OSRM Server واحد لسوريا (الخريطة صغيرة نسبياً) + +4. **أولوية الأداء في سوريا:** + - **Redis** هو أهم عنصر لأداء التطبيق (مواقع السائقين + كاش) + - **MySQL Buffer Pool** يحدد سرعة الاستعلامات + - **الـ Load Balancer** يوزع الضغط عن API servers + +5. **الأمان:** + - API Servers → قاعدة البيانات عبر مستخدم MySQL مخصص بصلاحيات محدودة + - Redis محمي بكلمة مرور (requirepass + rename-command FLUSHALL) + - جميع المفاتيح السرية في `.env` مع صلاحيات 600 + - JWT + HMAC للمدفوعات +--- diff --git a/scratch/payment_simulation.py b/scratch/payment_simulation.py new file mode 100644 index 0000000..83d1772 --- /dev/null +++ b/scratch/payment_simulation.py @@ -0,0 +1,289 @@ +import hmac +import hashlib +import json +import base64 +import uuid + +# Simulation configuration / Secrets +SECRET_KEY = "siro_super_secret_jwt_key" +SECRET_KEY_HMAC = "siro_super_secret_hmac_key" +FP_PEPPER = "siro_fp_pepper_salt" +S2S_SHARED_KEY = "s2s_shared_key_12345" + +# Mock Database +db = { + "payments": [], + "passengerWallet": {}, + "driverWallet": {}, + "invoices": {}, + "security_logs": [] +} + +def init_user(user_id, balance, is_driver=False): + if is_driver: + db["driverWallet"][user_id] = balance + else: + db["passengerWallet"][user_id] = balance + +# Helper functions for Client +def generate_jwt(user_id, device_fp): + # Mock JWT creation payload + header = base64.b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()).decode().replace("=", "") + hashed_fp = hashlib.sha256((device_fp + FP_PEPPER).encode()).hexdigest() + payload = base64.b64encode(json.dumps({ + "iss": "Tripz-Wallet", + "user_id": user_id, + "fingerPrint": hashed_fp, + "exp": 1900000000 # future exp + }).encode()).decode().replace("=", "") + signature = hmac.new(SECRET_KEY.encode(), f"{header}.{payload}".encode(), hashlib.sha256).digest() + encoded_signature = base64.b64encode(signature).decode().replace("=", "").replace("+", "-").replace("/", "_") + return f"{header}.{payload}.{encoded_signature}" + +def calculate_hmac_header(user_id): + return hmac.new(SECRET_KEY_HMAC.encode(), user_id.encode(), hashlib.sha256).hexdigest() + +# Helper functions for Server Authentication +def authenticate_request(headers, payload_user_id): + # 1. JWT verification + auth_header = headers.get("Authorization", "") + if not auth_header.startswith("Bearer "): + return False, "Authorization token required" + token = auth_header.split(" ")[1] + + try: + parts = token.split(".") + if len(parts) != 3: + return False, "Invalid token structure" + # Parse payload + payload_b64 = parts[1] + payload_b64 += "=" * ((4 - len(payload_b64) % 4) % 4) + payload = json.loads(base64.b64decode(payload_b64).decode()) + except Exception as e: + return False, f"JWT decode failed: {str(e)}" + + # Check Issuer + if payload.get("iss") != "Tripz-Wallet": + return False, "Invalid token issuer" + + # Check User ID match + token_user_id = payload.get("user_id") + if token_user_id != payload_user_id: + return False, "User ID mismatch with token" + + # 2. Device Fingerprint verification + device_fp_header = headers.get("X-Device-FP") + fp_in_token = payload.get("fingerPrint") + if device_fp_header and fp_in_token: + expected_fp = hashlib.sha256((device_fp_header + FP_PEPPER).encode()).hexdigest() + if not hmac.compare_digest(expected_fp, fp_in_token): + db["security_logs"].append(f"[WARNING] Device mismatch for user {payload_user_id}!") + return False, "Device mismatch (possible Session Hijacking)" + + # 3. HMAC Auth verification + hmac_header = headers.get("X-HMAC-Auth") + if hmac_header: + expected_hmac = hmac.new(SECRET_KEY_HMAC.encode(), payload_user_id.encode(), hashlib.sha256).hexdigest() + if not hmac.compare_digest(expected_hmac, hmac_header): + db["security_logs"].append(f"[WARNING] HMAC mismatch for user {payload_user_id}!") + return False, "Invalid HMAC (possible payload/identity tampering)" + + return True, "Authenticated" + +# AI verification simulation (Mocking Gemini API) +def mock_gemini_verify_payment(invoice_number, amount, proof_text): + print(f"[Gemini AI Processing] Verifying proof for Invoice {invoice_number} of amount {amount}...") + print(f"[Gemini AI Input Proof] '{proof_text}'") + # Mocking semantic check on proof text + success = False + reason = "" + + proof_lower = proof_text.lower() + amount_str = str(int(amount)) if amount == int(amount) else str(amount) + + if amount_str in proof_lower and ("successful" in proof_lower or "transferred" in proof_lower or "تم تحويل" in proof_lower or "نجاح" in proof_lower): + success = True + reason = "Proof text verified successfully. Amount matches invoice." + else: + reason = f"Verification failed: Proof text does not indicate successful transfer of {amount}." + + print(f"[Gemini AI Output] Verified: {success}, Reason: {reason}") + return {"verified": success, "reason": reason} + +# Atomic transaction simulation for ride payment +def process_ride_payment(ride_id, driver_id, passenger_id, amount, payment_method, wallet_checked, s2s_key): + # S2S auth check + if s2s_key != S2S_SHARED_KEY: + return {"status": "failure", "message": "Unauthorized S2S call"} + + print(f"\n--- Database Transaction Initiated for Ride {ride_id} ---") + + # Save a rollback point + rollback_db = { + "payments": list(db["payments"]), + "passengerWallet": dict(db["passengerWallet"]), + "driverWallet": dict(db["driverWallet"]) + } + + try: + # 1. Insert payment record + final_method = payment_method + "Ride" if wallet_checked else payment_method + payment_record = { + "id": str(uuid.uuid4().int)[:15], + "amount": amount, + "payment_method": final_method, + "passengerID": passenger_id, + "rideId": ride_id, + "driverID": driver_id + } + db["payments"].append(payment_record) + print(f"[DB] Inserted payment record: {payment_record}") + + # 2. Deduct from passenger wallet + if wallet_checked: + if passenger_id not in db["passengerWallet"]: + db["passengerWallet"][passenger_id] = 0.0 + + db["passengerWallet"][passenger_id] -= amount + print(f"[DB] Deducted {amount} from Passenger {passenger_id}. New balance: {db["passengerWallet"][passenger_id]}") + + # Settle debt if balance was negative before (example scenario) + # here we just apply deduction. + + # 3. Deduct driver points (8% platform commission) + commission = amount * 0.08 + if driver_id not in db["driverWallet"]: + db["driverWallet"][driver_id] = 0.0 + db["driverWallet"][driver_id] -= commission + print(f"[DB] Subtracted 8% commission ({commission}) from Driver {driver_id} points. New points balance: {db["driverWallet"][driver_id]}") + + print(f"[DB] Transaction Committed successfully.") + return {"status": "success", "message": "Transaction committed"} + + except Exception as e: + # Rollback + db["payments"] = rollback_db["payments"] + db["passengerWallet"] = rollback_db["passengerWallet"] + db["driverWallet"] = rollback_db["driverWallet"] + print(f"[DB ERROR] Transaction Failed. Rolled back changes. Error: {str(e)}") + return {"status": "failure", "message": f"Transaction failed: {str(e)}"} + +# Run Scenario Simulations +def run_egypt_simulation(): + print("\n" + "="*50) + print("SCENARIO 1: EGYPT - CREDIT CARD / PAYMOB (Ahmed)") + print("="*50) + user_id = "egypt_passenger_101" + driver_id = "egypt_driver_501" + device_fp = "ahmed_iphone_13_fp_hash" + + init_user(user_id, 500.0) # passenger wallet balance + init_user(driver_id, 100.0, is_driver=True) # driver wallet points + + # 1. Client signs request + jwt = generate_jwt(user_id, device_fp) + hmac_header = calculate_hmac_header(user_id) + + headers = { + "Authorization": f"Bearer {jwt}", + "X-Device-FP": device_fp, + "X-HMAC-Auth": hmac_header + } + + print(f"Passenger {user_id} initiating payment for Egypt ride. Ride cost: 120 EGP.") + + # 2. Server authenticates headers + auth_ok, msg = authenticate_request(headers, user_id) + print(f"[Server Auth] Result: {auth_ok}, Message: {msg}") + + if auth_ok: + # S2S transaction + res = process_ride_payment( + ride_id="ride_eg_999", + driver_id=driver_id, + passenger_id=user_id, + amount=120.0, + payment_method="PayMob", + wallet_checked=True, + s2s_key=S2S_SHARED_KEY + ) + print(f"[Final Result] {res}") + +def run_syria_simulation(): + print("\n" + "="*50) + print("SCENARIO 2: SYRIA - MTN CASH WITH AI VERIFICATION (Bassel)") + print("="*50) + user_id = "syria_passenger_202" + driver_id = "syria_driver_602" + device_fp = "bassel_galaxy_s22_fp_hash" + + init_user(user_id, 0.0) # passenger starts with 0.0 + init_user(driver_id, 50.0, is_driver=True) # driver starts with 50 points + + jwt = generate_jwt(user_id, device_fp) + hmac_header = calculate_hmac_header(user_id) + headers = { + "Authorization": f"Bearer {jwt}", + "X-Device-FP": device_fp, + "X-HMAC-Auth": hmac_header + } + + invoice_number = "INV-MTN-8877" + amount = 50000.0 # 50,000 SYP for the ride/wallet load + + print(f"Passenger {user_id} loads wallet via MTN Cash for invoice {invoice_number} of {amount} SYP.") + print("User transfers money and uploads transaction SMS proof.") + + proof_text = "MTN Cash: You have successfully transferred 50000 SYP to SIRO system. Ref: 9812739182." + + # 1. Server authenticates headers + auth_ok, msg = authenticate_request(headers, user_id) + print(f"[Server Auth] Result: {auth_ok}, Message: {msg}") + + if auth_ok: + # 2. AI verifies proof text + ai_res = mock_gemini_verify_payment(invoice_number, amount, proof_text) + + if ai_res["verified"]: + print(f"[Server] AI verified payment. Settle wallet.") + # Atomic settlement + print(f"\n--- Wallet Settlement Transaction Initiated (Syria) ---") + db["passengerWallet"][user_id] += amount + print(f"[DB] Added {amount} SYP to passenger {user_id} wallet. New balance: {db["passengerWallet"][user_id]} SYP") + print("[DB] Transaction Committed.") + else: + print(f"[Server] Payment rejected: {ai_res['reason']}") + +def run_jordan_simulation(): + print("\n" + "="*50) + print("SCENARIO 3: JORDAN - CLIQ WITH TAMPERED DEVICE FINGERPRINT (Rania)") + print("="*50) + user_id = "jordan_passenger_303" + device_fp = "rania_oneplus_11_fp_hash" + tampered_fp = "hijacked_device_fp_hash" # Attacker trying to reuse Rania's token from a different device + + # 1. Client token generated for Rania on her real device + jwt = generate_jwt(user_id, device_fp) + hmac_header = calculate_hmac_header(user_id) + + # Attacker sends request with correct JWT but hijacked/different device fingerprint header + headers = { + "Authorization": f"Bearer {jwt}", + "X-Device-FP": tampered_fp, # Hijacked device header + "X-HMAC-Auth": hmac_header + } + + print(f"Attacker attempts to trigger payment under Rania's user_id using hijacked token on different device.") + + # 2. Server authenticates headers + auth_ok, msg = authenticate_request(headers, user_id) + print(f"[Server Auth] Result: {auth_ok}, Message: {msg}") + + if not auth_ok: + print("[Server Alert] Attack blocked successfully! Session Hijacking thwarted.") + print(f"Security logs: {db['security_logs']}") + +if __name__ == "__main__": + run_egypt_simulation() + run_syria_simulation() + run_jordan_simulation() diff --git a/siro_admin/android/build/reports/problems/problems-report.html b/siro_admin/android/build/reports/problems/problems-report.html index 7eb1b63..36e7f14 100644 --- a/siro_admin/android/build/reports/problems/problems-report.html +++ b/siro_admin/android/build/reports/problems/problems-report.html @@ -650,7 +650,7 @@ code + .copy-button { diff --git a/walletintaleq.intaleq.xyz/WalletDB.sql b/walletintaleq.intaleq.xyz/WalletDB.sql new file mode 100644 index 0000000..c746303 --- /dev/null +++ b/walletintaleq.intaleq.xyz/WalletDB.sql @@ -0,0 +1,970 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.2 +-- https://www.phpmyadmin.net/ +-- +-- Host: 127.0.0.1:3306 +-- Generation Time: Jun 16, 2026 at 05:29 PM +-- Server version: 8.0.43-0ubuntu0.22.04.2 +-- PHP Version: 8.1.33 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `WalletIntaleqDB` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `adminUser` +-- + +CREATE TABLE `adminUser` ( + `id` int NOT NULL, + `device_number` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cliq_invoices` +-- + +CREATE TABLE `cliq_invoices` ( + `id` int NOT NULL, + `invoice_number` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, + `user_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, + `user_type` varchar(20) COLLATE utf8mb4_general_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `cliq_phone` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, + `status` varchar(20) COLLATE utf8mb4_general_ci DEFAULT 'pending', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driver` +-- + +CREATE TABLE `driver` ( + `id` varchar(100) NOT NULL, + `phone` varchar(20) NOT NULL, + `email` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `gender` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'Male', + `license_type` varchar(255) DEFAULT NULL, + `national_number` varchar(255) DEFAULT NULL, + `name_arabic` varchar(255) DEFAULT NULL, + `name_english` varchar(255) DEFAULT NULL, + `issue_date` date DEFAULT NULL, + `expiry_date` date DEFAULT NULL, + `license_categories` varchar(255) DEFAULT NULL, + `address` text, + `card_id` varchar(255) DEFAULT NULL, + `occupation` varchar(255) DEFAULT NULL, + `licenseIssueDate` varchar(50) DEFAULT NULL, + `religion` varchar(255) DEFAULT NULL, + `status` varchar(20) NOT NULL DEFAULT 'notDeleted', + `birthdate` varchar(20) NOT NULL, + `site` varchar(255) NOT NULL, + `first_name` varchar(255) NOT NULL, + `last_name` varchar(255) NOT NULL, + `accountBank` varchar(55) NOT NULL DEFAULT 'yet', + `bankCode` varchar(20) NOT NULL DEFAULT 'CIB', + `education` varchar(255) DEFAULT NULL, + `employmentType` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `maritalStatus` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `fullNameMaritial` varchar(255) DEFAULT NULL, + `expirationDate` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driverToken` +-- + +CREATE TABLE `driverToken` ( + `id` int NOT NULL, + `token` varchar(255) NOT NULL, + `captain_id` varchar(255) NOT NULL, + `fingerPrint` varchar(100) NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driverWallet` +-- + +CREATE TABLE `driverWallet` ( + `id` int NOT NULL, + `driverID` varchar(100) NOT NULL, + `paymentID` varchar(200) NOT NULL, + `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `amount` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL, + `paymentMethod` varchar(20) NOT NULL, + `dateUpdated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driver_withdrawal_requests` +-- + +CREATE TABLE `driver_withdrawal_requests` ( + `id` int NOT NULL, + `driver_id` varchar(255) NOT NULL, + `driver_name` varchar(255) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `wallet_type` varchar(50) NOT NULL, + `wallet_number` varchar(50) NOT NULL, + `status` varchar(50) NOT NULL DEFAULT 'pending', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ecash_transactions` +-- + +CREATE TABLE `ecash_transactions` ( + `id` bigint UNSIGNED NOT NULL, + `order_ref` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `passenger_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', + `ecash_transaction_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ecash_transactions_driver` +-- + +CREATE TABLE `ecash_transactions_driver` ( + `id` bigint UNSIGNED NOT NULL, + `order_ref` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `driver_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', + `ecash_transaction_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_shamcash` +-- + +CREATE TABLE `invoices_shamcash` ( + `id` int NOT NULL, + `invoice_number` int NOT NULL, + `driverID` varchar(44) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending', + `transaction_id` varchar(50) DEFAULT NULL COMMENT 'رقم عملية شام كاش لمنع التكرار', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `paid_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_shamcash_passenger` +-- + +CREATE TABLE `invoices_shamcash_passenger` ( + `id` int NOT NULL, + `invoice_number` int NOT NULL, + `passengerID` varchar(33) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending', + `transaction_id` varchar(50) DEFAULT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `paid_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_sms` +-- + +CREATE TABLE `invoices_sms` ( + `id` int NOT NULL, + `invoice_number` varchar(20) NOT NULL, + `user_phone` varchar(20) NOT NULL, + `amount` decimal(10,3) NOT NULL, + `status` enum('pending','completed','failed') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `driverID` varchar(33) DEFAULT NULL, + `currency` varchar(8) DEFAULT 'SYP' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_sms_passenger` +-- + +CREATE TABLE `invoices_sms_passenger` ( + `id` int NOT NULL, + `invoice_number` varchar(20) NOT NULL, + `user_phone` varchar(20) NOT NULL, + `amount` decimal(10,0) NOT NULL, + `status` enum('pending','completed','failed') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `passengerID` varchar(33) NOT NULL, + `currency` varchar(8) NOT NULL DEFAULT 'SYP' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `kazan` +-- + +CREATE TABLE `kazan` ( + `id` int NOT NULL, + `country` varchar(30) NOT NULL, + `kazan` varchar(10) NOT NULL, + `comfortPrice` varchar(10) NOT NULL, + `speedPrice` varchar(10) NOT NULL, + `deliveryPrice` varchar(11) NOT NULL, + `freePrice` varchar(11) NOT NULL, + `latePrice` varchar(10) NOT NULL, + `heavyPrice` varchar(10) NOT NULL, + `adminId` varchar(100) NOT NULL, + `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `naturePrice` varchar(10) NOT NULL, + `fuelPrice` varchar(6) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `mtn_invoices` +-- + +CREATE TABLE `mtn_invoices` ( + `id` int NOT NULL, + `invoice_number` varchar(20) NOT NULL, + `user_id` varchar(50) NOT NULL, + `user_type` enum('driver','passenger') NOT NULL COMMENT 'يحدد هل المستخدم سائق أم راكب', + `amount` decimal(10,2) NOT NULL, + `mtn_phone` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'رقم MTN الذي سيتم الدفع منه', + `status` enum('pending','completed','failed','expired') NOT NULL DEFAULT 'pending', + `mtn_transaction_id` varchar(255) DEFAULT NULL COMMENT 'معرّف العملية من طرف MTN بعد الدفع', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `passengers` +-- + +CREATE TABLE `passengers` ( + `id` varchar(100) NOT NULL, + `phone` varchar(15) NOT NULL, + `email` varchar(255) NOT NULL, + `password` varchar(100) NOT NULL, + `gender` varchar(25) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `status` varchar(20) NOT NULL DEFAULT 'notDeleted', + `birthdate` varchar(44) NOT NULL, + `site` varchar(255) NOT NULL, + `first_name` varchar(255) NOT NULL, + `last_name` varchar(255) NOT NULL, + `sosPhone` varchar(33) NOT NULL DEFAULT 'sos', + `education` varchar(30) NOT NULL DEFAULT 'none', + `employmentType` varchar(30) NOT NULL DEFAULT 'none', + `maritalStatus` varchar(30) NOT NULL DEFAULT 'none', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `passengerWallet` +-- + +CREATE TABLE `passengerWallet` ( + `id` int NOT NULL, + `passenger_id` varchar(100) NOT NULL, + `balance` decimal(10,2) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payments` +-- + +CREATE TABLE `payments` ( + `id` varchar(111) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` varchar(255) NOT NULL, + `passengerID` varchar(100) NOT NULL, + `rideId` varchar(100) NOT NULL, + `driverID` varchar(100) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `isGiven` varchar(20) NOT NULL DEFAULT 'waiting' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsDriverPoints` +-- + +CREATE TABLE `paymentsDriverPoints` ( + `id` int NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` varchar(50) NOT NULL, + `driverID` varchar(60) NOT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsLog` +-- + +CREATE TABLE `paymentsLog` ( + `id` int NOT NULL, + `payment_id` varchar(255) NOT NULL, + `user_id` char(40) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` tinyint NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsLogSyria` +-- + +CREATE TABLE `paymentsLogSyria` ( + `id` int NOT NULL, + `user_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` tinyint NOT NULL DEFAULT '0', + `order_ref` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'ecash', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsLogSyriaDriver` +-- + +CREATE TABLE `paymentsLogSyriaDriver` ( + `id` int NOT NULL, + `user_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `amount` decimal(10,2) NOT NULL DEFAULT '0.00', + `status` tinyint NOT NULL DEFAULT '2', + `processed_wallet` tinyint(1) NOT NULL DEFAULT '0', + `order_ref` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'ecash', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payment_log_driver` +-- + +CREATE TABLE `payment_log_driver` ( + `id` int NOT NULL, + `payment_id` varchar(255) NOT NULL, + `user_id` char(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` tinyint(1) NOT NULL DEFAULT '0', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payment_tokens` +-- + +CREATE TABLE `payment_tokens` ( + `id` int NOT NULL, + `token` varchar(255) NOT NULL, + `driverID` varchar(255) NOT NULL, + `dateCreated` datetime NOT NULL, + `amount` decimal(10,2) NOT NULL, + `isUsed` tinyint(1) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payment_tokens_passenger` +-- + +CREATE TABLE `payment_tokens_passenger` ( + `id` int NOT NULL, + `token` varchar(255) NOT NULL, + `passengerId` varchar(255) NOT NULL, + `dateCreated` datetime NOT NULL, + `amount` decimal(10,2) NOT NULL, + `isUsed` tinyint(1) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payout_requests` +-- + +CREATE TABLE `payout_requests` ( + `id` int NOT NULL, + `driver_id` varchar(35) NOT NULL, + `driver_phone` varchar(20) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `wallet_type` varchar(50) DEFAULT NULL, + `status` enum('pending','completed','failed') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `completed_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `phone_verification` +-- + +CREATE TABLE `phone_verification` ( + `id` int NOT NULL, + `phone_number` varchar(20) NOT NULL, + `driverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet', + `email` varchar(50) NOT NULL DEFAULT 'yet', + `token_code` varchar(10) NOT NULL, + `expiration_time` datetime NOT NULL, + `is_verified` tinyint(1) DEFAULT '0', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `phone_verification_passenger` +-- + +CREATE TABLE `phone_verification_passenger` ( + `id` int NOT NULL, + `phone_number` varchar(15) NOT NULL, + `token` varchar(6) NOT NULL, + `expiration_time` datetime NOT NULL, + `verified` tinyint(1) DEFAULT '0', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `raw_sms_log` +-- + +CREATE TABLE `raw_sms_log` ( + `id` int NOT NULL, + `sender` varchar(50) NOT NULL, + `message_body` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `status` enum('pending','processed','failed') NOT NULL DEFAULT 'pending', + `gemini_result` json DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `siroWallet` +-- + +CREATE TABLE `siroWallet` ( + `id` int NOT NULL, + `driverId` varchar(100) NOT NULL, + `passengerId` varchar(100) NOT NULL, + `amount` varchar(10) NOT NULL, + `paymentMethod` varchar(50) NOT NULL, + `token` varchar(100) NOT NULL, + `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `smsSender` +-- + +CREATE TABLE `smsSender` ( + `id` int NOT NULL, + `senderId` varchar(20) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tokens` +-- + +CREATE TABLE `tokens` ( + `id` int NOT NULL, + `token` varchar(333) NOT NULL, + `passengerID` varchar(111) NOT NULL, + `fingerPrint` varchar(300) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `adminUser` +-- +ALTER TABLE `adminUser` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `cliq_invoices` +-- +ALTER TABLE `cliq_invoices` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `invoice_number` (`invoice_number`); + +-- +-- Indexes for table `driver` +-- +ALTER TABLE `driver` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `phone` (`phone`,`email`), + ADD UNIQUE KEY `national_number` (`national_number`); + +-- +-- Indexes for table `driverToken` +-- +ALTER TABLE `driverToken` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `driverWallet` +-- +ALTER TABLE `driverWallet` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `driver_withdrawal_requests` +-- +ALTER TABLE `driver_withdrawal_requests` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `ecash_transactions` +-- +ALTER TABLE `ecash_transactions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_ref_unique` (`order_ref`), + ADD KEY `user_id_index` (`user_id`), + ADD KEY `passenger_id_index` (`passenger_id`); + +-- +-- Indexes for table `ecash_transactions_driver` +-- +ALTER TABLE `ecash_transactions_driver` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_ref_unique_driver` (`order_ref`), + ADD KEY `driver_id_index` (`driver_id`); + +-- +-- Indexes for table `invoices_shamcash` +-- +ALTER TABLE `invoices_shamcash` + ADD PRIMARY KEY (`id`), + ADD KEY `invoice_number` (`invoice_number`), + ADD KEY `status` (`status`); + +-- +-- Indexes for table `invoices_shamcash_passenger` +-- +ALTER TABLE `invoices_shamcash_passenger` + ADD PRIMARY KEY (`id`), + ADD KEY `invoice_number` (`invoice_number`), + ADD KEY `status` (`status`); + +-- +-- Indexes for table `invoices_sms` +-- +ALTER TABLE `invoices_sms` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `invoice_number` (`invoice_number`), + ADD KEY `idx_user_phone` (`user_phone`), + ADD KEY `idx_status` (`status`); + +-- +-- Indexes for table `invoices_sms_passenger` +-- +ALTER TABLE `invoices_sms_passenger` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `uniq_invoice_number_passenger` (`invoice_number`); + +-- +-- Indexes for table `kazan` +-- +ALTER TABLE `kazan` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `mtn_invoices` +-- +ALTER TABLE `mtn_invoices` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `invoice_number` (`invoice_number`), + ADD KEY `idx_user` (`user_id`,`user_type`), + ADD KEY `idx_status` (`status`); + +-- +-- Indexes for table `passengers` +-- +ALTER TABLE `passengers` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `phone` (`phone`,`email`); + +-- +-- Indexes for table `passengerWallet` +-- +ALTER TABLE `passengerWallet` + ADD PRIMARY KEY (`id`), + ADD KEY `passenger_id` (`passenger_id`); + +-- +-- Indexes for table `payments` +-- +ALTER TABLE `payments` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `rideId` (`rideId`); + +-- +-- Indexes for table `paymentsDriverPoints` +-- +ALTER TABLE `paymentsDriverPoints` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `paymentsLog` +-- +ALTER TABLE `paymentsLog` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `payment_id` (`payment_id`); + +-- +-- Indexes for table `paymentsLogSyria` +-- +ALTER TABLE `paymentsLogSyria` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `paymentsLogSyriaDriver` +-- +ALTER TABLE `paymentsLogSyriaDriver` + ADD PRIMARY KEY (`id`), + ADD KEY `order_ref_index` (`order_ref`); + +-- +-- Indexes for table `payment_log_driver` +-- +ALTER TABLE `payment_log_driver` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `payment_id` (`payment_id`); + +-- +-- Indexes for table `payment_tokens` +-- +ALTER TABLE `payment_tokens` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `payment_tokens_passenger` +-- +ALTER TABLE `payment_tokens_passenger` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `payout_requests` +-- +ALTER TABLE `payout_requests` + ADD PRIMARY KEY (`id`), + ADD KEY `driver_id_status` (`driver_id`,`status`); + +-- +-- Indexes for table `phone_verification` +-- +ALTER TABLE `phone_verification` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `phone_verification_passenger` +-- +ALTER TABLE `phone_verification_passenger` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `phone_number` (`phone_number`); + +-- +-- Indexes for table `raw_sms_log` +-- +ALTER TABLE `raw_sms_log` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `siroWallet` +-- +ALTER TABLE `siroWallet` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `smsSender` +-- +ALTER TABLE `smsSender` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `tokens` +-- +ALTER TABLE `tokens` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `passengerID` (`passengerID`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `adminUser` +-- +ALTER TABLE `adminUser` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `cliq_invoices` +-- +ALTER TABLE `cliq_invoices` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `driverToken` +-- +ALTER TABLE `driverToken` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `driverWallet` +-- +ALTER TABLE `driverWallet` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `driver_withdrawal_requests` +-- +ALTER TABLE `driver_withdrawal_requests` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `ecash_transactions` +-- +ALTER TABLE `ecash_transactions` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `ecash_transactions_driver` +-- +ALTER TABLE `ecash_transactions_driver` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_shamcash` +-- +ALTER TABLE `invoices_shamcash` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_shamcash_passenger` +-- +ALTER TABLE `invoices_shamcash_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_sms` +-- +ALTER TABLE `invoices_sms` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_sms_passenger` +-- +ALTER TABLE `invoices_sms_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `kazan` +-- +ALTER TABLE `kazan` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `mtn_invoices` +-- +ALTER TABLE `mtn_invoices` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `passengerWallet` +-- +ALTER TABLE `passengerWallet` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsDriverPoints` +-- +ALTER TABLE `paymentsDriverPoints` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsLog` +-- +ALTER TABLE `paymentsLog` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsLogSyria` +-- +ALTER TABLE `paymentsLogSyria` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsLogSyriaDriver` +-- +ALTER TABLE `paymentsLogSyriaDriver` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payment_log_driver` +-- +ALTER TABLE `payment_log_driver` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payment_tokens` +-- +ALTER TABLE `payment_tokens` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payment_tokens_passenger` +-- +ALTER TABLE `payment_tokens_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payout_requests` +-- +ALTER TABLE `payout_requests` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `phone_verification` +-- +ALTER TABLE `phone_verification` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `phone_verification_passenger` +-- +ALTER TABLE `phone_verification_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `raw_sms_log` +-- +ALTER TABLE `raw_sms_log` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `siroWallet` +-- +ALTER TABLE `siroWallet` + ADD AUTO_INCREMENT = 1; + + +-- +-- AUTO_INCREMENT for table `smsSender` +-- +ALTER TABLE `smsSender` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `tokens` +-- +ALTER TABLE `tokens` + MODIFY `id` int NOT NULL AUTO_INCREMENT; +-- +-- Table structure for table `admin_audit_log` +-- + +CREATE TABLE `admin_audit_log` ( + `id` int NOT NULL AUTO_INCREMENT, + `admin_id` varchar(150) NOT NULL, + `action` varchar(255) NOT NULL, + `table_name` varchar(255) DEFAULT NULL, + `record_id` varchar(255) DEFAULT NULL, + `details` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php b/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php index 4151d2d..abda192 100755 --- a/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php +++ b/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php @@ -1,4 +1,21 @@ + * + * أي طلب بدون أي مصادقة → يُرفض تلقائياً من authenticateJWT() + * ═══════════════════════════════════════════════════════════════ + */ + // Load environment variables from .env file require_once realpath(__DIR__ . '/../vendor/autoload.php'); require_once 'load_env.php'; @@ -10,7 +27,7 @@ $secretKey = getenv('SECRET_KEY'); // Only need the secret key now // --- CORS Headers --- $allowedOrigins = [ - 'https://walletintaleq.intaleq.xyz', + 'https://wallet.siromove.com', 'https://wallet-syria.siromove.com', 'https://wallet-egypt.siromove.com', @@ -22,17 +39,19 @@ if (in_array($origin, $allowedOrigins)) { } else { header("Access-Control-Allow-Origin: https://walletintaleq.intaleq.xyz"); } -header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // Adjust as needed -header("Access-Control-Allow-Headers: Content-Type, Authorization"); -header('Content-Type: application/json'); // Set content type to JSON +header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); +header("Access-Control-Allow-Headers: Content-Type, Authorization, X-S2S-Api-Key, PAYMENT_KEY, X-Auth-Token, X-Cron-Key, X-HMAC-Auth, X-Device-FP"); +header('Content-Type: application/json'); // Handle preflight requests (OPTIONS) if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { http_response_code(200); exit; } - $dbname = getenv('dbname'); -// --- Database Connection (Still needed for your application logic) --- + +$dbname = getenv('dbname'); + +// --- Database Connection --- try { $dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4"; $options = [ @@ -41,19 +60,75 @@ try { PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8" ]; - $user = getenv('USER'); // Still used for DB connection - $pass = getenv('PASS'); // Still used for DB connection + $user = getenv('USER'); + $pass = getenv('PASS'); $con = new PDO($dsn, $user, $pass, $options); - // --- JWT Authentication --- - include "functions.php"; // Include the functions file + // --- Load Functions --- + include "functions.php"; - + // ═══════════════════════════════════════════════════════════ + // UNIFIED AUTHENTICATION GATEWAY (بوابة المصادقة الموحدة) + // ═══════════════════════════════════════════════════════════ + $authMethod = null; + $decodedToken = null; + + // --- Path 1: S2S API Key (server-to-server calls) --- + $s2sKey = $_SERVER['HTTP_X_S2S_API_KEY'] ?? ''; + $expectedS2s = getenv('S2S_SHARED_KEY'); + + if (!empty($s2sKey) && !empty($expectedS2s) && hash_equals($expectedS2s, $s2sKey)) { + $authMethod = 'S2S'; + } + + // --- Path 2: Payment Key (transfer endpoint) --- + if (!$authMethod) { + $paymentKey = $_SERVER['HTTP_PAYMENT_KEY'] ?? ''; + $expectedPayment = getenv('PAYMENT_KEY'); + + if (!empty($paymentKey) && !empty($expectedPayment) && hash_equals($expectedPayment, $paymentKey)) { + $authMethod = 'PAYMENT_KEY'; + } + } + + // --- Path 3: Webhook Auth Token (MTN/Cliq external services) --- + // ملاحظة: البوابة تعترف بوجود الهيدر فقط. كل webhook يتحقق من القيمة الفعلية بنفسه. + if (!$authMethod) { + $webhookToken = $_SERVER['HTTP_X_AUTH_TOKEN'] ?? ''; + + if (!empty($webhookToken)) { + $authMethod = 'WEBHOOK'; + } + } + + // --- Path 4: Cron Key / CLI execution --- + if (!$authMethod) { + // 4a: CLI execution (php script.php directly) + if (php_sapi_name() === 'cli' || php_sapi_name() === 'cli-server') { + $authMethod = 'CLI'; + } else { + // 4b: HTTP cron call with key header + $cronKey = $_SERVER['HTTP_X_CRON_KEY'] ?? ''; + $expectedCron = getenv('CRON_KEY'); + + if (!empty($cronKey) && !empty($expectedCron) && hash_equals($expectedCron, $cronKey)) { + $authMethod = 'CRON'; + } + } + } + + // --- Path 5 (DEFAULT): JWT Authentication --- + // إذا لم يتم التعرف على أي مسار آخر، يُفرض JWT. + // authenticateJWT() ستُرجع 401 وتوقف التنفيذ إذا لم يكن هناك JWT صالح. + if (!$authMethod) { + $decodedToken = authenticateJWT(); + $authMethod = 'JWT'; + } } catch (PDOException $e) { error_log($e->getMessage()); - http_response_code(500); // Internal Server Error + http_response_code(500); echo json_encode(['error' => 'A database error occurred.']); exit; } diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php index baaf782..adb7862 100755 --- a/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php @@ -64,9 +64,9 @@ function finalizeForDriver(PDO $con, int $driverId, float $amount, string $payme if ($stmtDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed.'); // إضافة سجل محاسبي لمحفظة سفر - $stmtSefer = $con->prepare("INSERT INTO seferWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)"); - $stmtSefer->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); - if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed.'); + $stmtSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)"); + $stmtSiro->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); + if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed.'); return ['success' => true, 'message' => 'Driver wallets updated.']; } @@ -90,9 +90,9 @@ function finalizeForPassenger(PDO $con, string $passengerId, float $amount, stri if ($stmtPassenger->rowCount() === 0) throw new Exception('Update passengerWallet failed.'); // إضافة سجل محاسبي لمحفظة سفر - $stmtSefer = $con->prepare("INSERT INTO seferWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)"); - $stmtSefer->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); - if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet for passenger failed.'); + $stmtSiro = $con->prepare("INSERT INTO siroWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)"); + $stmtSiro->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); + if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet for passenger failed.'); return ['success' => true, 'message' => 'Passenger wallets updated.']; } diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php index 90a31a3..e6a207f 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php @@ -1,58 +1,104 @@ user_id ?? $decodedToken->sub ?? null; + +// ── 2. استخراج والتحقق من البيانات ────────────────────────── +$driverID = filterRequest("driverID"); +$paymentID = filterRequest("paymentID"); +$amount = filterRequest("amount"); $paymentMethod = filterRequest("paymentMethod"); -$token = filterRequest("token"); +$token = filterRequest("token"); -// Retrieve token details from the database -$stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE"); -$stmt->execute(array( - ':token' => $token -)); - -$tokenData = $stmt->fetch(); - -if ($tokenData) { - // Add payment to the driver's wallet table - $sql = "INSERT INTO `driverWallet` ( - `driverID`, - `paymentID`, - `amount`, - `paymentMethod` - ) VALUES ( - :driverID, - :paymentID, - :amount, - :paymentMethod - );"; - - $stmt = $con->prepare($sql); - $stmt->execute(array( - ':driverID' => $driverID, - ':paymentID' => $paymentID, - ':amount' => $amount, - ':paymentMethod' => $paymentMethod - )); - - if ($stmt->rowCount() > 0) { - // Print a success message - printSuccess("Record saved successfully"); - - // Mark the token as used in the database - $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID"); - $stmt->execute(array( - ':tokenID' => $tokenData['id'] - )); - } else { - // Print a failure message - printFailure("Failed to save record"); - } -} else { - printFailure("Invalid or already used token"); +if (empty($driverID) || !isset($amount) || empty($paymentMethod) || empty($token)) { + printFailure("Missing required parameters"); + exit; } + +// ── 3. التحقق من ملكية الحساب ──────────────────────────────── +// السائق المصادق يمكنه فقط إضافة رصيد لمحفظته الشخصية +if ($jwtUserId !== null && $driverID !== $jwtUserId) { + error_log(sprintf( + '⚠️ [SECURITY] Ownership mismatch in add.php | jwt_user=%s | requested_driverID=%s | IP=%s', + $jwtUserId, $driverID, $_SERVER['REMOTE_ADDR'] ?? 'unknown' + )); + http_response_code(403); + printFailure("Forbidden: You can only modify your own wallet"); + exit; +} + +// ── 4. التحقق من المبلغ ───────────────────────────────────── +$amount = floatval($amount); +if ($amount <= 0 || $amount > 1000000) { + printFailure("Invalid amount"); + exit; +} + +// ── 5. العملية الذرية ───────────────────────────────────────── +try { + $con->beginTransaction(); + + // التحقق من التوكن مع قفل السجل (FOR UPDATE) لمنع Race Condition + $stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE FOR UPDATE"); + $stmt->execute([':token' => $token]); + $tokenData = $stmt->fetch(); + + if ($tokenData) { + // إدخال سجل المحفظة + $sql = "INSERT INTO `driverWallet` ( + `driverID`, + `paymentID`, + `amount`, + `paymentMethod` + ) VALUES ( + :driverID, + :paymentID, + :amount, + :paymentMethod + );"; + + $stmt = $con->prepare($sql); + $stmt->execute([ + ':driverID' => $driverID, + ':paymentID' => $paymentID, + ':amount' => $amount, + ':paymentMethod' => $paymentMethod + ]); + + if ($stmt->rowCount() > 0) { + // تحديث حالة التوكن + $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID"); + $stmt->execute([':tokenID' => $tokenData['id']]); + + $con->commit(); + printSuccess("Record saved successfully"); + } else { + $con->rollBack(); + printFailure("Failed to save record"); + } + } else { + $con->rollBack(); + printFailure("Invalid or already used token"); + } +} catch (Exception $e) { + if ($con->inTransaction()) { + $con->rollBack(); + } + error_log("[driverWallet/add] " . $e->getMessage()); + printFailure("An error occurred"); +} + diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php index 94bf50b..803653b 100755 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php @@ -1,17 +1,67 @@ user_id ?? $decodedToken->sub ?? null; +$adminRole = $decodedToken->role ?? null; + +// ── 2. التحقق من صلاحيات المسؤول ──────────────────────────── +// فقط المسؤول يمكنه إضافة رصيد يدوياً +if ($adminRole !== 'admin' && $adminRole !== 'super_admin') { + error_log(sprintf( + '⚠️ [SECURITY] Non-admin attempted addFromAdmin | user=%s | role=%s | IP=%s', + $adminUserId, + $adminRole ?? '(null)', + $_SERVER['REMOTE_ADDR'] ?? 'unknown' + )); + http_response_code(403); + printFailure("Forbidden: Admin access required"); + exit; +} + +// ── 3. استخراج والتحقق من البيانات ────────────────────────── +$driverID = filterRequest("driverID"); +$paymentID = filterRequest("paymentID"); +$amount = filterRequest("amount"); $paymentMethod = filterRequest("paymentMethod"); -$phone = filterRequest("phone"); +$phone = filterRequest("phone"); +if (empty($driverID) || !isset($amount) || empty($paymentMethod)) { + printFailure("Missing required parameters: driverID, amount, paymentMethod"); + exit; +} - // Add payment to the driver's wallet table +// ── 4. التحقق من المبلغ ───────────────────────────────────── +$amount = floatval($amount); +if ($amount <= 0 || $amount > 1000000) { + error_log(sprintf( + '⚠️ [SECURITY] Invalid amount in addFromAdmin | admin=%s | amount=%s | driverID=%s', + $adminUserId, $amount, $driverID + )); + printFailure("Invalid amount: must be between 0 and 1,000,000"); + exit; +} + +// ── 5. العملية الذرية ───────────────────────────────────────── +try { + $con->beginTransaction(); + + // إدخال سجل المحفظة $sql = "INSERT INTO `driverWallet` ( `driverID`, `paymentID`, @@ -25,27 +75,51 @@ $phone = filterRequest("phone"); );"; $stmt = $con->prepare($sql); - $stmt->execute(array( - ':driverID' => $driverID, - ':paymentID' => $paymentID, - ':amount' => $amount, + $stmt->execute([ + ':driverID' => $driverID, + ':paymentID' => $paymentID ?? ('admin_' . time() . '_' . bin2hex(random_bytes(4))), + ':amount' => $amount, ':paymentMethod' => $paymentMethod - )); + ]); if ($stmt->rowCount() > 0) { - // Print a success message + // ── 6. تسجيل تدقيق (Audit Log) ───────────────────────── + $auditStmt = $con->prepare( + "INSERT INTO `admin_audit_log` (`admin_id`, `action`, `table_name`, `record_id`, `details`) + VALUES (:admin_id, :action, :table_name, :record_id, :details)" + ); + $auditStmt->execute([ + ':admin_id' => $adminUserId, + ':action' => 'addFromAdmin_wallet', + ':table_name' => 'driverWallet', + ':record_id' => $driverID, + ':details' => json_encode([ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'phone' => $phone, + 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown', + 'timestamp' => date('Y-m-d H:i:s') + ], JSON_UNESCAPED_UNICODE) + ]); + + $con->commit(); + printSuccess("Record saved successfully"); - $messageBody = "تم إضافة رصيد بقيمة $amount إلى محفظتك بنجاح."; // "Balance of $amount added successfully." - - sendWhatsAppFromServer($phone, $messageBody); - - // Mark the token as used in the database - /* $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID"); - $stmt->execute(array( - ':tokenID' => $tokenData['id'] - ));*/ + + // إرسال إشعار واتساب للسائق + if (!empty($phone)) { + $messageBody = "تم إضافة رصيد بقيمة $amount إلى محفظتك بنجاح."; + sendWhatsAppFromServer($phone, $messageBody); + } } else { - // Print a failure message + $con->rollBack(); printFailure("Failed to save record"); } +} catch (Exception $e) { + if ($con->inTransaction()) { + $con->rollBack(); + } + error_log("[addFromAdmin] Error: " . $e->getMessage()); + printFailure("An error occurred"); +} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php index acbe062..6df9668 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php @@ -91,28 +91,28 @@ if ($language === 'ar') {
- SEFER App Logo + SIRO App Logo -

Your SEFER Transfer Details

+

Your SIRO Transfer Details

Thank you for using our service. We hope you have a great day!

We want to inform you that an amount of $amount has been transferred from your account to the new driver: $newDriverName (Phone: $driverPhone).

-

Regards,
SEFER Team

+

Regards,
SIRO Team

"; } // Email headers -$supportEmail = 'seferteam@sefer.live'; +$supportEmail = 'siroteam@siro.live'; $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers .= "From: $supportEmail\r\n"; // Send email if (!empty($driverEmail)) { - if (mail($driverEmail, "Your SEFER Transfer Details", $bodyEmail, $headers)) { + if (mail($driverEmail, "Your SIRO Transfer Details", $bodyEmail, $headers)) { - mail($newEmail, "Your SEFER Transfer Details", $bodyEmail, $headers); + mail($newEmail, "Your SIRO Transfer Details", $bodyEmail, $headers); echo "Email sent successfully."; } else { echo "Email sending failed."; diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php index 1b8d628..795dbdb 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php @@ -84,7 +84,7 @@ try { $paymentID2 = "transfer_recv_" . time() . bin2hex(random_bytes(4)); $token1 = bin2hex(random_bytes(32)); $token2 = bin2hex(random_bytes(32)); - $seferToken = bin2hex(random_bytes(32)); + $siroToken = bin2hex(random_bytes(32)); // 4. Deduct from Sender (payments table) $deductAmount = -$amount; @@ -108,12 +108,12 @@ try { ':token' => $token2 ]); - // 6. Add Fee to Sefer Wallet - $stmt = $con->prepare("INSERT INTO seferWallet (amount, paymentMethod, passengerId, token, driverId) + // 6. Add Fee to Siro Wallet + $stmt = $con->prepare("INSERT INTO siroWallet (amount, paymentMethod, passengerId, token, driverId) VALUES (:fee, 'payout fee', 'driver', :token, :senderID)"); $stmt->execute([ ':fee' => $fee, - ':token' => $seferToken, + ':token' => $siroToken, ':senderID' => $senderID ]); diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_verify.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_verify.php new file mode 100755 index 0000000..d8cf292 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_verify.php @@ -0,0 +1,148 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + return $stmt->rowCount() > 0 ? $token : null; +} + +/** + * تسجيل دفعة في جدول النقاط وإعادة المعرف الخاص بها + * Logs a payment in the points table and returns its ID. + */ +function generatePaymentID($con, $driverId, $amount, $method): ?string +{ + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; +} + + +// ------------------------------------------------- +// المنطق الرئيسي للمعالجة +// Main processing logic +// ------------------------------------------------- + +// 1. استقبال الرقم المرجعي من الرابط +// 1. Receive the order reference from the URL. +$orderRef = $_GET['orderRef'] ?? null; +if (empty($orderRef)) { + echo "

خطأ: الرقم المرجعي للطلب مفقود.

"; + exit; +} + +// 2. الانتظار والتأكد من وصول الـ Webhook +// 2. Wait and verify that the webhook has updated the status. +$payment = null; +$max_attempts = 5; // محاولة لمدة 10 ثوانٍ - Poll for 10 seconds +for ($attempts = 0; $attempts < $max_attempts; $attempts++) { + // تأكد من أن اسم الجدول صحيح + // Make sure the table name is correct. + $stmt = $con->prepare("SELECT * FROM `paymentsLogSyriaDriver` WHERE order_ref = :order_ref AND status = 1 LIMIT 1"); + $stmt->execute([':order_ref' => $orderRef]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($payment) { + break; // تم العثور على الدفعة الناجحة - Successful payment found + } + sleep(2); // الانتظار لمدة ثانيتين قبل المحاولة التالية - Wait 2 seconds before retrying +} + +// 3. التحقق من نتيجة البحث +// 3. Check the polling result. +if (!$payment) { + echo "

خطأ في تأكيد الدفع

لم نتمكن من تأكيد دفعتك. قد تستغرق العملية بضع لحظات. يرجى التحقق من رصيدك في التطبيق لاحقاً أو التواصل مع الدعم الفني.

"; + exit; +} + +// 4. تمت عملية الدفع بنجاح، لنقم بإضافة الرصيد +// 4. Payment successful, proceed to add balance. +try { + $driverId = $payment['user_id']; + // eCash لا تحتاج للقسمة على 100 + // eCash amount does not need division by 100. + $originalAmount = floatval($payment['amount']); + $paymentMethod = $payment['payment_method'] ?? 'ecash'; + + // حساب المكافأة + // Calculate the bonus. + $bonusAmount = match ((int)$originalAmount) { + 80 => 80.0, + 200 => 215.0, + 400 => 450.0, + 1000 => 1140.0, + default => $originalAmount, + }; + + // --- تنفيذ منطق تحديث المحافظ --- + // --- Execute wallet update logic --- + + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + if (!$tokenDriver) throw new Exception('Failed to generate token for driver wallet.'); + + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) throw new Exception('Failed to generate token for siro wallet.'); + + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + if (!$paymentID) throw new Exception('Failed to generate payment ID.'); + + // إضافة الرصيد إلى driverWallet + // Add balance to driverWallet + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([':driverID' => $driverId, ':paymentID' => $paymentID, ':amount' => $bonusAmount, ':paymentMethod' => $paymentMethod]); + if ($insertDriver->rowCount() === 0) throw new Exception('Failed to insert into driverWallet.'); + + $markTokenDriver = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token"); + $markTokenDriver->execute([':token' => $tokenDriver]); + + // إضافة الرصيد إلى siroWallet + // Add balance to siroWallet + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token, CURRENT_TIMESTAMP)"); + $insertSiro->execute([':driverId' => $driverId, ':passengerId' => 'driver', ':amount' => $originalAmount, ':paymentMethod' => $paymentMethod, ':token' => $tokenSiro]); + + $markTokenSiro = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token"); + $markTokenSiro->execute([':token' => $tokenSiro]); + + // 5. عرض صفحة النجاح النهائية + // 5. Display final success page. + echo "

تمت العملية بنجاح

تمت إضافة الرصيد إلى محفظتك. يمكنك الآن العودة إلى التطبيق.

"; + +} catch (Throwable $e) { + // في حال حدوث خطأ، يتم تسجيله وعرض رسالة للمستخدم + // In case of an error, log it and display a message to the user. + error_log("VERIFY_ERROR: " . $e->getMessage() . " | OrderRef: " . $orderRef); + echo "

حدث خطأ

لقد تم استلام دفعتك بنجاح، ولكن حدث خطأ أثناء تحديث رصيدك. يرجى التواصل مع الدعم الفني وتزويدهم بالرقم المرجعي: " . htmlspecialchars($orderRef) . "

"; +} + +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_webhook.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_webhook.php new file mode 100755 index 0000000..72e30de --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_webhook.php @@ -0,0 +1,91 @@ +prepare( + "UPDATE `paymentsLogSyriaDriver` SET status = :status, updated_at = NOW() WHERE order_ref = :order_ref AND status = 2" + ); + $stmt->execute([ + ':status' => $payment_status, + + ':order_ref' => $orderRef + ]); + + if ($stmt->rowCount() > 0) { + http_response_code(200); + file_put_contents($log_file, "SUCCESS: Database updated." . PHP_EOL, FILE_APPEND); + } else { + http_response_code(200); + file_put_contents($log_file, "INFO: Order not found or already processed." . PHP_EOL, FILE_APPEND); + } + +} catch (PDOException $e) { + http_response_code(500); + file_put_contents($log_file, "FATAL: Database update failed: " . $e->getMessage() . PHP_EOL, FILE_APPEND); +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/finalize_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/finalize_payment.php new file mode 100755 index 0000000..41eff64 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/finalize_payment.php @@ -0,0 +1,79 @@ +prepare( + "SELECT * FROM `paymentsLogSyria` + WHERE user_id = :user_id + AND status = 1 + AND updated_at >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) + ORDER BY updated_at DESC + LIMIT 1" + ); + $stmt->bindParam(':user_id', $userId, PDO::PARAM_STR); + $stmt->execute(); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + printFailure("لم يتم العثور على دفعة ناجحة حديثة."); + exit; + } + + // خطوة 2: الحصول على المبلغ (لا يحتاج للقسمة على 100) + $amount = $payment['amount']; + + // خطوة 3: حساب المكافأة + $finalAmount = calculateBonus($amount); // استخدم دالة حساب المكافآت الخاصة بك + + $passengerId = $userId; // نفترض أن معرّف المستخدم هو نفسه معرّف الراكب + + // --- هنا تضع نفس منطق إضافة الرصيد الذي كان في ملف payment_verify.php القديم --- + // (مثال) + // $token = generatePaymentToken($passengerId, $finalAmount); + // addToPassengerWallet($passengerId, $finalAmount, $token); + // ... إلخ + + // --- النجاح النهائي --- + printSuccess("تمت معالجة الدفع وتحديث الرصيد بنجاح."); + +} catch (PDOException $e) { + error_log("Finalize Payment Error: " . $e->getMessage()); + printFailure("حدث خطأ في قاعدة البيانات أثناء إتمام العملية."); +} + +// --- يمكنك وضع دوال المساعدة هنا (calculateBonus, etc.) --- +function calculateBonus($amount) { + $result = $amount; + if ($amount == 200) $result = 215; + else if ($amount == 400) $result = 450; + else if ($amount == 100) $result = 100.0; + else if ($amount == 1000) $result = 1140; + return $result; +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/payWithEcash.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/payWithEcash.php new file mode 100755 index 0000000..86b4793 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/payWithEcash.php @@ -0,0 +1,88 @@ +prepare( + "INSERT INTO `paymentsLogSyriaDriver`( `user_id`, `amount`, `status`, `order_ref`, `payment_method`, `created_at`) + VALUES (:user_id, :amount, 2, :order_ref,'ecash-driver', NOW())" + ); + $stmt->execute([ + ':user_id' => $driverId, + ':amount' => $amount, + ':order_ref' => $orderRef + ]); +} catch (PDOException $e) { + error_log("eCash - فشل تسجيل الدفعة المبدئية: " . $e->getMessage()); + printFailure("حدث خطأ أثناء بدء عملية الدفع. يرجى المحاولة مرة أخرى."); + exit; +} + +// --- إعادة رابط الدفع إلى تطبيق فلاتر --- +// التطبيق سيستقبل هذا الرابط ويفتحه في WebView +// نرسل الرابط داخل حقل 'message' كما يتوقع كود فلاتر +printSuccess($paymentUrl); + +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/webhook_connect.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/webhook_connect.php new file mode 100755 index 0000000..2615948 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/webhook_connect.php @@ -0,0 +1,42 @@ + false, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8" + ]; + $user = getenv('USER'); + $pass = getenv('PASS'); + $con = new PDO($dsn, $user, $pass, $options); + +} catch (PDOException $e) { + error_log("Webhook DB Connection Error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(['error' => 'Internal Server Error']); + exit; +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/ecash_config.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/ecash_config.php new file mode 100755 index 0000000..5a3dc25 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/ecash_config.php @@ -0,0 +1,44 @@ + 'error', 'message' => 'Payment gateway not configured correctly.']); + exit; +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/ecash_production.log b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/ecash_production.log new file mode 100644 index 0000000..9ef6d7a --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/ecash_production.log @@ -0,0 +1,264 @@ +--- NEW WEBHOOK --- +2025-07-21 17:33:55 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108408","TransactionNo":"2515118257","Amount":"10000.00","Token":"386BBEDFFA3FBCEFCCF7F546FB4BC622"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2251511825710000.00tripz_109270481246447459618_1753108408 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2515118257 + - Amount Used: 10000.00 + - OrderRef Used: tripz_109270481246447459618_1753108408 +CALCULATED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +RECEIVED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:34:00 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108408","TransactionNo":"2515118257","Amount":"10000.00","Token":"386BBEDFFA3FBCEFCCF7F546FB4BC622"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2251511825710000.00tripz_109270481246447459618_1753108408 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2515118257 + - Amount Used: 10000.00 + - OrderRef Used: tripz_109270481246447459618_1753108408 +CALCULATED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +RECEIVED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:34:05 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108408","TransactionNo":"2515118257","Amount":"10000.00","Token":"386BBEDFFA3FBCEFCCF7F546FB4BC622"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2251511825710000.00tripz_109270481246447459618_1753108408 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2515118257 + - Amount Used: 10000.00 + - OrderRef Used: tripz_109270481246447459618_1753108408 +CALCULATED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +RECEIVED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:34:11 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108408","TransactionNo":"2515118257","Amount":"10000.00","Token":"386BBEDFFA3FBCEFCCF7F546FB4BC622"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2251511825710000.00tripz_109270481246447459618_1753108408 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2515118257 + - Amount Used: 10000.00 + - OrderRef Used: tripz_109270481246447459618_1753108408 +CALCULATED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +RECEIVED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:34:16 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108408","TransactionNo":"2515118257","Amount":"10000.00","Token":"386BBEDFFA3FBCEFCCF7F546FB4BC622"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2251511825710000.00tripz_109270481246447459618_1753108408 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2515118257 + - Amount Used: 10000.00 + - OrderRef Used: tripz_109270481246447459618_1753108408 +CALCULATED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +RECEIVED TOKEN: 386BBEDFFA3FBCEFCCF7F546FB4BC622 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:38:33 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108680","TransactionNo":"3434918048","Amount":"2000.00","Token":"5E397F3BCFC8DBC277E67BBE909A4C25"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE234349180482000.00tripz_109270481246447459618_1753108680 + - Merchant ID Used: UOMACV + - TransactionNo Used: 3434918048 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753108680 +CALCULATED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +RECEIVED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:38:38 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108680","TransactionNo":"3434918048","Amount":"2000.00","Token":"5E397F3BCFC8DBC277E67BBE909A4C25"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE234349180482000.00tripz_109270481246447459618_1753108680 + - Merchant ID Used: UOMACV + - TransactionNo Used: 3434918048 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753108680 +CALCULATED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +RECEIVED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:38:44 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108680","TransactionNo":"3434918048","Amount":"2000.00","Token":"5E397F3BCFC8DBC277E67BBE909A4C25"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE234349180482000.00tripz_109270481246447459618_1753108680 + - Merchant ID Used: UOMACV + - TransactionNo Used: 3434918048 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753108680 +CALCULATED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +RECEIVED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:38:49 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108680","TransactionNo":"3434918048","Amount":"2000.00","Token":"5E397F3BCFC8DBC277E67BBE909A4C25"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE234349180482000.00tripz_109270481246447459618_1753108680 + - Merchant ID Used: UOMACV + - TransactionNo Used: 3434918048 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753108680 +CALCULATED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +RECEIVED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:38:54 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753108680","TransactionNo":"3434918048","Amount":"2000.00","Token":"5E397F3BCFC8DBC277E67BBE909A4C25"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE234349180482000.00tripz_109270481246447459618_1753108680 + - Merchant ID Used: UOMACV + - TransactionNo Used: 3434918048 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753108680 +CALCULATED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +RECEIVED TOKEN: 5E397F3BCFC8DBC277E67BBE909A4C25 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'payment_id' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:43:55 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753109008","TransactionNo":"2925347460","Amount":"2000.00","Token":"16EC668D7C9A4105D464BC925D0F35B3"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE229253474602000.00tripz_109270481246447459618_1753109008 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2925347460 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753109008 +CALCULATED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +RECEIVED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:44:00 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753109008","TransactionNo":"2925347460","Amount":"2000.00","Token":"16EC668D7C9A4105D464BC925D0F35B3"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE229253474602000.00tripz_109270481246447459618_1753109008 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2925347460 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753109008 +CALCULATED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +RECEIVED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:44:06 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753109008","TransactionNo":"2925347460","Amount":"2000.00","Token":"16EC668D7C9A4105D464BC925D0F35B3"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE229253474602000.00tripz_109270481246447459618_1753109008 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2925347460 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753109008 +CALCULATED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +RECEIVED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:44:11 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753109008","TransactionNo":"2925347460","Amount":"2000.00","Token":"16EC668D7C9A4105D464BC925D0F35B3"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE229253474602000.00tripz_109270481246447459618_1753109008 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2925347460 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753109008 +CALCULATED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +RECEIVED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:44:16 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753109008","TransactionNo":"2925347460","Amount":"2000.00","Token":"16EC668D7C9A4105D464BC925D0F35B3"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE229253474602000.00tripz_109270481246447459618_1753109008 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2925347460 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753109008 +CALCULATED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +RECEIVED TOKEN: 16EC668D7C9A4105D464BC925D0F35B3 +TOKEN MATCH! Proceeding to update database. +FATAL: Database update failed: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' +--- NEW WEBHOOK --- +2025-07-21 17:51:29 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753109456","TransactionNo":"2487921821","Amount":"2000.00","Token":"1EA870532F15308A41780C06AC852C33"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE224879218212000.00tripz_109270481246447459618_1753109456 + - Merchant ID Used: UOMACV + - TransactionNo Used: 2487921821 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753109456 +CALCULATED TOKEN: 1EA870532F15308A41780C06AC852C33 +RECEIVED TOKEN: 1EA870532F15308A41780C06AC852C33 +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-21 18:54:15 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753113200","TransactionNo":"1725092256","Amount":"2000.00","Token":"983B8B9FDA5947CEE1D16D6ECC29FAF9"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE217250922562000.00tripz_109270481246447459618_1753113200 + - Merchant ID Used: UOMACV + - TransactionNo Used: 1725092256 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753113200 +CALCULATED TOKEN: 983B8B9FDA5947CEE1D16D6ECC29FAF9 +RECEIVED TOKEN: 983B8B9FDA5947CEE1D16D6ECC29FAF9 +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-21 19:06:34 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753113966","TransactionNo":"1477094275","Amount":"2000.00","Token":"01AF3E8E7C921FF72ADB09300971F2D2"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE214770942752000.00tripz_109270481246447459618_1753113966 + - Merchant ID Used: UOMACV + - TransactionNo Used: 1477094275 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753113966 +CALCULATED TOKEN: 01AF3E8E7C921FF72ADB09300971F2D2 +RECEIVED TOKEN: 01AF3E8E7C921FF72ADB09300971F2D2 +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-21 19:15:57 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753114529","TransactionNo":"746605967","Amount":"2000.00","Token":"7102931A8851540F14F4E259751EA776"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE27466059672000.00tripz_109270481246447459618_1753114529 + - Merchant ID Used: UOMACV + - TransactionNo Used: 746605967 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753114529 +CALCULATED TOKEN: 7102931A8851540F14F4E259751EA776 +RECEIVED TOKEN: 7102931A8851540F14F4E259751EA776 +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-21 19:20:54 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753114829","TransactionNo":"10119078","Amount":"2000.00","Token":"11DEB7F0AA5121F048E94CF385D5FC3D"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2101190782000.00tripz_109270481246447459618_1753114829 + - Merchant ID Used: UOMACV + - TransactionNo Used: 10119078 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753114829 +CALCULATED TOKEN: 11DEB7F0AA5121F048E94CF385D5FC3D +RECEIVED TOKEN: 11DEB7F0AA5121F048E94CF385D5FC3D +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-21 19:23:26 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_109270481246447459618_1753114985","TransactionNo":"532601241","Amount":"2000.00","Token":"18DCD7E952332EB655B036B0C76EEDC7"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE25326012412000.00tripz_109270481246447459618_1753114985 + - Merchant ID Used: UOMACV + - TransactionNo Used: 532601241 + - Amount Used: 2000.00 + - OrderRef Used: tripz_109270481246447459618_1753114985 +CALCULATED TOKEN: 18DCD7E952332EB655B036B0C76EEDC7 +RECEIVED TOKEN: 18DCD7E952332EB655B036B0C76EEDC7 +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-22 00:11:03 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_14a51b422c9972299e109c7db5f65a2c_1753132198","TransactionNo":"947634072","Amount":"200000.00","Token":"E6811EE374F921257C45DC84CCCF48DC"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE2947634072200000.00tripz_14a51b422c9972299e109c7db5f65a2c_1753132198 + - Merchant ID Used: UOMACV + - TransactionNo Used: 947634072 + - Amount Used: 200000.00 + - OrderRef Used: tripz_14a51b422c9972299e109c7db5f65a2c_1753132198 +CALCULATED TOKEN: E6811EE374F921257C45DC84CCCF48DC +RECEIVED TOKEN: E6811EE374F921257C45DC84CCCF48DC +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-22 00:17:06 - RAW BODY: {"IsSuccess":false,"Message":"OTP is not valid!","OrderRef":"tripz_14a51b422c9972299e109c7db5f65a2c_1753132598","TransactionNo":"1773754242","Amount":"200000.00","Token":"2654D3390FF25082FF5A8A1BA59D6CDA"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE21773754242200000.00tripz_14a51b422c9972299e109c7db5f65a2c_1753132598 + - Merchant ID Used: UOMACV + - TransactionNo Used: 1773754242 + - Amount Used: 200000.00 + - OrderRef Used: tripz_14a51b422c9972299e109c7db5f65a2c_1753132598 +CALCULATED TOKEN: 2654D3390FF25082FF5A8A1BA59D6CDA +RECEIVED TOKEN: 2654D3390FF25082FF5A8A1BA59D6CDA +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. +--- NEW WEBHOOK --- +2025-07-22 00:19:54 - RAW BODY: {"IsSuccess":true,"Message":null,"OrderRef":"tripz_14a51b422c9972299e109c7db5f65a2c_1753132768","TransactionNo":"1048082327","Amount":"100000.00","Token":"DCF7C2AEE0A81DB6C5F40C086E396928"} +VERIFICATION STRING: UOMACVPA8BQ8U99BRDDONSLAKW2IDSLBTCQFR776E8L55C0DLBYFB6NJJOWJ7FOLWEYQE21048082327100000.00tripz_14a51b422c9972299e109c7db5f65a2c_1753132768 + - Merchant ID Used: UOMACV + - TransactionNo Used: 1048082327 + - Amount Used: 100000.00 + - OrderRef Used: tripz_14a51b422c9972299e109c7db5f65a2c_1753132768 +CALCULATED TOKEN: DCF7C2AEE0A81DB6C5F40C086E396928 +RECEIVED TOKEN: DCF7C2AEE0A81DB6C5F40C086E396928 +TOKEN MATCH! Proceeding to update database. +SUCCESS: Database updated. diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/payment_verification.log b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/payment_verification.log new file mode 100644 index 0000000..95bc263 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/logs/payment_verification.log @@ -0,0 +1,9 @@ +[2025-07-21 17:38:50] STEP VERIFY: لم يتم تأكيد الدفع بعد عدة محاولات | Data: {"orderRef":"tripz_109270481246447459618_1753108680"} +[2025-07-21 17:38:56] STEP VERIFY: لم يتم تأكيد الدفع بعد عدة محاولات | Data: {"orderRef":"tripz_109270481246447459618_1753108680"} +[2025-07-21 17:44:13] STEP VERIFY: لم يتم تأكيد الدفع بعد عدة محاولات | Data: {"orderRef":"tripz_109270481246447459618_1753109008"} +[2025-07-21 17:51:41] STEP VERIFY: اكتملت العملية بنجاح | Data: {"orderRef":"tripz_109270481246447459618_1753109456","userId":"109270481246447459618"} +[2025-07-21 19:06:39] STEP VERIFY: اكتملت العملية بنجاح | Data: {"orderRef":"tripz_109270481246447459618_1753113966","userId":"109270481246447459618"} +[2025-07-21 19:20:58] STEP VERIFY: اكتملت العملية بنجاح | Data: {"orderRef":"tripz_109270481246447459618_1753114829","userId":"109270481246447459618"} +[2025-07-21 19:23:30] STEP VERIFY: اكتملت العملية بنجاح | Data: {"orderRef":"tripz_109270481246447459618_1753114985","userId":"109270481246447459618"} +[2025-07-22 00:11:08] STEP VERIFY: اكتملت العملية بنجاح | Data: {"orderRef":"tripz_14a51b422c9972299e109c7db5f65a2c_1753132198","userId":"14a51b422c9972299e109c7db5f65a2c"} +[2025-07-22 00:20:01] STEP VERIFY: اكتملت العملية بنجاح | Data: {"orderRef":"tripz_14a51b422c9972299e109c7db5f65a2c_1753132768","userId":"14a51b422c9972299e109c7db5f65a2c"} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_verify.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_verify.php new file mode 100755 index 0000000..fa761f9 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_verify.php @@ -0,0 +1,181 @@ + + + + + + <?= htmlspecialchars($title) ?> + + + +
+
+

+

+
+ + + prepare("SELECT * FROM `paymentsLogSyria` WHERE order_ref = :order_ref AND status = 1 LIMIT 1"); + $stmt->execute([':order_ref' => $orderRef]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + if ($payment) break; + sleep(2); +} + +if (!$payment) { + logError("VERIFY", "لم يتم تأكيد الدفع بعد عدة محاولات", ["orderRef" => $orderRef]); + showHTMLPage("error", "لم يتم تأكيد الدفع", "لم نتمكن من تأكيد دفعتك بعد. قد تستغرق العملية بضع لحظات. يرجى التحقق من رصيدك في التطبيق لاحقاً أو التواصل مع الدعم الفني."); +} + +try { + $userId = $payment['user_id']; + $amount = $payment['amount']; + $paymentMethod = $payment['payment_method'] ?? 'ecash'; + + $finalAmount = calculateBonus($amount); + + $token = generatePaymentToken($userId, $finalAmount); + if (!$token) throw new Exception("فشل إنشاء توكن محفظة الراكب"); + + $walletResult = addToPassengerWallet($userId, $finalAmount, $token); + if (!$walletResult || ($walletResult['status'] ?? 'fail') != "success") { + throw new Exception("فشل إضافة الرصيد لمحفظة الراكب"); + } + + $siroToken = generatePaymentToken($userId, $amount); + if (!$siroToken) throw new Exception("فشل إنشاء توكن محفظة سفر"); + + $siroWalletResult = addToSiroWallet($userId, $amount, $paymentMethod, $siroToken); + if (!$siroWalletResult || ($siroWalletResult['status'] ?? 'fail') != "success") { + throw new Exception("فشل إضافة الرصيد لمحفظة سفر"); + } + + logError("VERIFY", "اكتملت العملية بنجاح", ["orderRef" => $orderRef, "userId" => $userId]); + showHTMLPage("success", "تم الدفع بنجاح", "تمت إضافة الرصيد إلى محفظتك. شكرًا لاستخدامك Intaleq."); +} catch (Exception $e) { + logError("VERIFY_ERROR", $e->getMessage(), ["orderRef" => $orderRef]); + showHTMLPage("error", "حدث خطأ", "لقد تم استلام دفعتك بنجاح، ولكن حدث خطأ أثناء تحديث رصيدك. يرجى التواصل مع الدعم الفني وتزويدهم بالرقم المرجعي: " . htmlspecialchars($orderRef)); +} + +// --- دوال مساعدة --- + +function calculateBonus($amount) { + if ($amount == 200000) return 205000; + if ($amount == 400000) return 425000; + if ($amount == 1000000) return 1040000; + return $amount; +} + +function generatePaymentToken($passengerId, $amount) { + $url = BASE_URL . "/passengerWallet/addPaymentTokenPassenger.php"; + $postData = ['passengerId' => $passengerId, 'amount' => $amount]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200) return null; + $data = json_decode($response, true); + return $data['message'] ?? null; +} + +function addToPassengerWallet($passengerId, $amount, $token) { + $url = BASE_URL . "/passengerWallet/add.php"; + $postData = ['passenger_id' => $passengerId, 'balance' => $amount, 'token' => $token]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200) return null; + return json_decode($response, true); +} + +function addToSiroWallet($passengerId, $amount, $paymentMethod, $token) { + $url = BASE_URL . "/siroWallet/add.php"; + $postData = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'passengerId' => $passengerId, + 'token' => $token, + 'driverId' => 'passenger' + ]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200) return null; + return json_decode($response, true); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_webhook.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_webhook.php new file mode 100755 index 0000000..00646b0 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_webhook.php @@ -0,0 +1,91 @@ +prepare( + "UPDATE `paymentsLogSyria` SET status = :status, updated_at = NOW() WHERE order_ref = :order_ref AND status = 2" + ); + $stmt->execute([ + ':status' => $payment_status, + + ':order_ref' => $orderRef + ]); + + if ($stmt->rowCount() > 0) { + http_response_code(200); + file_put_contents($log_file, "SUCCESS: Database updated." . PHP_EOL, FILE_APPEND); + } else { + http_response_code(200); + file_put_contents($log_file, "INFO: Order not found or already processed." . PHP_EOL, FILE_APPEND); + } + +} catch (PDOException $e) { + http_response_code(500); + file_put_contents($log_file, "FATAL: Database update failed: " . $e->getMessage() . PHP_EOL, FILE_APPEND); +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/finalize_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/finalize_payment.php new file mode 100755 index 0000000..d6b43d7 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/finalize_payment.php @@ -0,0 +1,79 @@ +prepare( + "SELECT * FROM `paymentsLogSyria` + WHERE user_id = :user_id + AND status = 1 + AND updated_at >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) + ORDER BY updated_at DESC + LIMIT 1" + ); + $stmt->bindParam(':user_id', $userId, PDO::PARAM_STR); + $stmt->execute(); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + printFailure("لم يتم العثور على دفعة ناجحة حديثة."); + exit; + } + + // خطوة 2: الحصول على المبلغ (لا يحتاج للقسمة على 100) + $amount = $payment['amount']; + + // خطوة 3: حساب المكافأة + $finalAmount = calculateBonus($amount); // استخدم دالة حساب المكافآت الخاصة بك + + $passengerId = $userId; // نفترض أن معرّف المستخدم هو نفسه معرّف الراكب + + // --- هنا تضع نفس منطق إضافة الرصيد الذي كان في ملف payment_verify.php القديم --- + // (مثال) + // $token = generatePaymentToken($passengerId, $finalAmount); + // addToPassengerWallet($passengerId, $finalAmount, $token); + // ... إلخ + + // --- النجاح النهائي --- + printSuccess("تمت معالجة الدفع وتحديث الرصيد بنجاح."); + +} catch (PDOException $e) { + error_log("Finalize Payment Error: " . $e->getMessage()); + printFailure("حدث خطأ في قاعدة البيانات أثناء إتمام العملية."); +} + +// --- يمكنك وضع دوال المساعدة هنا (calculateBonus, etc.) --- +function calculateBonus($amount) { + $result = $amount; + if ($amount == 500) return 530; + if ($amount == 1000) return 1070; + if ($amount == 2000) return 2180; + if ($amount == 5000) return 5700; + return $result; +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/payWithEcash.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/payWithEcash.php new file mode 100755 index 0000000..2c38e69 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/payWithEcash.php @@ -0,0 +1,88 @@ +prepare( + "INSERT INTO `paymentsLogSyria`( `user_id`, `amount`, `status`, `order_ref`, `payment_method`, `created_at`) + VALUES (:user_id, :amount, 2, :order_ref,'ecash-passenger', NOW())" + ); + $stmt->execute([ + ':user_id' => $passengerId, + ':amount' => $amount, + ':order_ref' => $orderRef + ]); +} catch (PDOException $e) { + error_log("eCash - فشل تسجيل الدفعة المبدئية: " . $e->getMessage()); + printFailure("حدث خطأ أثناء بدء عملية الدفع. يرجى المحاولة مرة أخرى."); + exit; +} + +// --- إعادة رابط الدفع إلى تطبيق فلاتر --- +// التطبيق سيستقبل هذا الرابط ويفتحه في WebView +// نرسل الرابط داخل حقل 'message' كما يتوقع كود فلاتر +printSuccess($paymentUrl); + +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/webhook_connect.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/webhook_connect.php new file mode 100755 index 0000000..2615948 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/webhook_connect.php @@ -0,0 +1,42 @@ + false, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8" + ]; + $user = getenv('USER'); + $pass = getenv('PASS'); + $con = new PDO($dsn, $user, $pass, $options); + +} catch (PDOException $e) { + error_log("Webhook DB Connection Error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(['error' => 'Internal Server Error']); + exit; +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/payWithEcash.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/payWithEcash.php new file mode 100755 index 0000000..d2c6775 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/payWithEcash.php @@ -0,0 +1,73 @@ +user_id ?? null; +if (!$userId) { + printFailure("Authentication failed."); + exit; +} + +// 1. --- Create a unique order reference --- +$orderRef = 'INTALEQ_' . $userId . '_' . time(); + +// 2. --- Save the initial transaction to your database --- +// This step is CRITICAL for the webhook to work correctly. +// Create a table named 'ecash_transactions' with columns like: +// id, order_ref, user_id, passenger_id, amount, status, created_at, updated_at +try { + $stmt = $con->prepare( + "INSERT INTO ecash_transactions (order_ref, user_id, passenger_id, amount, status) VALUES (?, ?, ?, ?, 'pending')" + ); + $stmt->execute([$orderRef, $userId, $passengerId, $amount]); +} catch (PDOException $e) { + // Log the database error + error_log("ecash_initiate DB Error: " . $e->getMessage()); + printFailure("Failed to initiate payment transaction."); + exit; +} + +// 3. --- Generate the Verification Code (VC) --- +$stringToHash = ECASH_MERCHANT_ID . ECASH_MERCHANT_SECRET . $amount . $orderRef; +$verificationCode = strtoupper(md5($stringToHash)); + +// 4. --- Construct URLs --- +$redirectUrl = urlencode(APP_REDIRECT_URL_SUCCESS); +$callbackUrl = urlencode(APP_CALLBACK_URL); + +// 5. --- Build the Final Checkout URL --- +$checkoutUrl = sprintf( + "%s/Checkout/CardCheckout?tk=%s&mid=%s&vc=%s&c=%s&a=%s&lang=%s&or=%s&ru=%s&cu=%s", + ECASH_CHECKOUT_URL, + ECASH_TERMINAL_KEY, + ECASH_MERCHANT_ID, + $verificationCode, + ECASH_CURRENCY, + $amount, + ECASH_LANG, + $orderRef, + $redirectUrl, + $callbackUrl +); + +// 6. --- Return the URL to Flutter --- +printSuccess($checkoutUrl); + +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/ecash/webhook_ecash.php b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/webhook_ecash.php new file mode 100755 index 0000000..276aef2 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/ecash/webhook_ecash.php @@ -0,0 +1,310 @@ + + $raw_post_data]); + +$data = json_decode($raw_post_data, true); +if (!$data) { + logError("0.1", "Invalid JSON payload."); + http_response_code(400); + exit; +} + +// 2. Extract data and verify the token from ecash +$isSuccess = $data['isSuccess'] ?? null; +$orderRef = $data['orderRef'] ?? null; +$transactionNo = $data['transactionNo'] ?? null; +$amount = $data['amount'] ?? null; +$receivedToken = $data['token'] ?? ''; + +$string_to_hash = ECASH_MERCHANT_ID . ECASH_MERCHANT_SECRET . $transactionNo . $amount . $orderRef; +$expected_token = md5($string_to_hash); + +if (strcasecmp($expected_token, $receivedToken) !== 0) { + logError("1", "Token Mismatch", [ + "expected" => $expected_token, + "received" => $receivedToken, + "string" => $string_to_hash + ]); + http_response_code(401); // Unauthorized + exit; +} +logError("1", "Token Verified Successfully."); + +// 3. Check if payment was successful +if ($isSuccess !== true) { + logError("2", "Payment was not successful according to ecash.", $data); + // Optionally, update your database to mark the order as 'failed' + updateTransactionStatus($orderRef, 'failed', $transactionNo); + http_response_code(200); // Respond OK to ecash, but do nothing else + exit; +} +logError("2", "Payment reported as SUCCESS by ecash."); + +// 4. Find the original transaction in your database using the Order Reference +try { + $stmt = $con->prepare("SELECT * FROM ecash_transactions WHERE order_ref = ? LIMIT 1"); + $stmt->execute([$orderRef]); + $transaction = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$transaction) { + logError("3", "OrderRef not found in our database.", ["orderRef" => $orderRef]); + http_response_code(404); // Not Found + exit; + } + + // Security Check: Ensure this transaction hasn't already been processed + if ($transaction['status'] !== 'pending') { + logError("3.1", "Transaction already processed.", ["orderRef" => $orderRef, "status" => $transaction['status']]); + http_response_code(200); // Acknowledge receipt, but prevent double-spending + exit; + } + + $passengerId = $transaction['passenger_id']; + $paidAmount = $transaction['amount']; // Use the amount from your DB as the source of truth + logError("3", "Transaction found in DB.", ["passengerId" => $passengerId, "amount" => $paidAmount]); + + // 5. --- Start Wallet Update Logic (from your paymet_verfy.php) --- + + // Calculate bonus + $finalAmount = calculateBonus($paidAmount); + logError("4", "Bonus calculated.", ["original" => $paidAmount, "final" => $finalAmount]); + + // Add to Passenger Wallet + $passengerToken = generatePaymentToken($passengerId, $finalAmount); + if ($passengerToken) { + addToPassengerWallet($passengerId, $finalAmount, $passengerToken); + } + + // Add to Siro Wallet + $paymentMethod = 'ecash'; // Or another identifier + addToSiroWallet($passengerId, $paidAmount, $paymentMethod); + + // 6. Mark the transaction as 'success' in your database to prevent reprocessing + updateTransactionStatus($orderRef, 'success', $transactionNo); + logError("7", "Process completed successfully."); + +} catch (PDOException $e) { + logError("DB_ERROR", "Database error: " . $e->getMessage()); + http_response_code(500); + exit; +} catch (Exception $e) { + logError("GENERAL_ERROR", "General error: " . $e->getMessage()); + http_response_code(500); + exit; +} + +// 7. Respond to ecash server +http_response_code(200); +echo "Webhook processed."; + + +// --- ALL HELPER FUNCTIONS FROM paymet_verfy.php --- + +function updateTransactionStatus($orderRef, $status, $transactionNo) { + global $con; + try { + $stmt = $con->prepare( + "UPDATE ecash_transactions SET status = ?, ecash_transaction_no = ?, updated_at = NOW() WHERE order_ref = ?" + ); + $stmt->execute([$status, $transactionNo, $orderRef]); + } catch (PDOException $e) { + logError("DB_UPDATE_ERROR", "Failed to update transaction status", ["error" => $e->getMessage()]); + } +} + + + + +function generatePaymentToken($passengerId, $amount) { + $url = BASE_URL . "/passengerWallet/addPaymentTokenPassenger.php"; + + $postData = [ + 'passengerId' => $passengerId, + 'amount' => $amount + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("4.1", "cURL error in token generation", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("4.2", "HTTP error in token generation", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data || !isset($data['message'])) { + logError("4.3", "Invalid response format in token generation", [ + "response" => $response + ]); + return null; + } + + return $data['message']; // ✅ Return token +} + +// 🎯 Function to add balance to passenger's wallet with error logging +function addToPassengerWallet($passengerId, $amount, $token) { + $url = BASE_URL . "/passengerWallet/add.php"; + + $postData = [ + 'passenger_id' => $passengerId, + 'balance' => $amount, + 'token' => $token + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("5.1", "cURL error in passenger wallet update", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("5.2", "HTTP error in passenger wallet update", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data) { + logError("5.3", "Invalid response format in passenger wallet update", [ + "response" => $response + ]); + return null; + } + + return $data; // ✅ Return result +} + +// 🎯 Function to add balance to Siro wallet with error logging + + +function addToSiroWallet($passengerId, $amount, $paymentMethod) { + + + // Generate a new token specifically for the Siro wallet + $siroToken = generatePaymentToken($passengerId, $amount); + + if (!$siroToken) { + logError("6.0.1", "Failed to generate Siro token"); + return null; + } + + logError("6.0.2", "Generated new Siro token", [ + "token_length" => ($siroToken) + ]); + + $url = BASE_URL . "/siroWallet/add.php"; + + $postData = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'passengerId' => $passengerId, + 'token' => $siroToken, // Use the new Siro-specific token + 'driverId' => 'passenger' + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("6.1", "cURL error in Siro wallet update", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("6.2", "HTTP error in Siro wallet update", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data) { + logError("6.3", "Invalid response format in Siro wallet update", [ + "response" => $response + ]); + return null; + } + + return $data; // ✅ Return result +} + + +// 🎯 Function to calculate bonus +function calculateBonus($amount) { + logError("3.1", "Bonus calculation input", ["amount" => $amount]); + + $result = 0; + if ($amount == 100) $result = 100; + else if ($amount == 200) $result = 215; + else if ($amount == 400) $result = 450; + else if ($amount == 1000) $result = 1140; + + logError("3.2", "Bonus calculation result", [ + "input" => $amount, + "output" => $result + ]); + + return $result; +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/confirm_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/confirm_payment.php new file mode 100755 index 0000000..ff8aa2f --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/confirm_payment.php @@ -0,0 +1,125 @@ + intval($invoice), + 'Phone' => $phone, + 'Guid' => $guid, + 'OperationNumber' => intval($operationNumber), + 'Code' => $codeB64 +]; +$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE); + +error_log("MTN Confirm (Driver): Prepared body JSON: " . $bodyJson); + +// Generate signature +$signResult = openssl_sign($bodyJson, $sig, $privateKey, OPENSSL_ALGO_SHA256); +if (!$signResult) { + error_log("MTN Confirm (Driver): Failed to generate signature"); + printFailure("Signature error."); + exit; +} +$xSignature = base64_encode($sig); +error_log("MTN Confirm (Driver): Generated signature"); + +// Send the request +$ch = curl_init("{$baseUrl}/pos_web/payment_phone/confirm"); +curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $bodyJson, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Request-Name: pos_web/payment_phone/confirm", + "Subject: {$terminalId}", + "X-Signature: {$xSignature}" + ] +]); + +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +$curlError = curl_error($ch); +curl_close($ch); + +error_log("MTN Confirm (Driver): HTTP $httpCode - Response: $response"); +if ($curlError) { + error_log("MTN Confirm (Driver): cURL error - $curlError"); +} + +// --- SOLUTION IMPLEMENTED HERE --- +// 1. Decode the response from MTN to check its contents. +$responseData = json_decode($response, true) ?: []; + +// 2. First, check for network/gateway level failure. +if ($httpCode !== 200) { + error_log("MTN Confirm (Driver): HTTP failure for invoice {$invoice}. Code: {$httpCode}"); + // Use printFailure to send a structured error to Flutter + printFailure(['message' => 'MTN Gateway Error', 'http' => $httpCode, 'details' => $responseData]); + exit; +} + +// 3. Now, check for business-logic failure (like "Balance not enough"). +$errno = $responseData['Errno'] ?? -1; // Default to an error state if Errno is missing +if ($errno !== 0) { + $apiError = $responseData['Error'] ?? 'Unknown MTN API Error'; + error_log("MTN Confirm (Driver): Business failure for invoice {$invoice}. Errno: {$errno}, Reason: {$apiError}"); + // This now sends the specific error message in the format Flutter expects! + printFailure(['message' => $apiError, 'errno' => $errno, 'details' => $responseData]); + exit; +} + +// --- ONLY PROCEED TO DATABASE ON FULL SUCCESS (HTTP 200 AND Errno 0) --- +try { + $stmt = $con->prepare( + "UPDATE `paymentsLogSyriaDriver` SET status = 1, updated_at = NOW() + WHERE order_ref = :inv" + ); + $stmt->execute([':inv' => $invoice]); + error_log("MTN Confirm (Driver): Payment updated successfully in DB for invoice={$invoice}"); + + // The file path correction from before remains important. + include_once __DIR__ . '/finalize_wallet_payment.php'; + + // Call the wallet finalization logic + if (function_exists('finalizeWalletPayment')) { + $_GET['orderRef'] = $invoice; + finalizeWalletPayment($con); + } else { + error_log("MTN Confirm (Driver): FATAL - finalizeWalletPayment() function does not exist after include."); + } + + // On success, send a success response to Flutter + printSuccess(['message' => 'Payment confirmed successfully', 'details' => $responseData]); + +} catch (PDOException $e) { + error_log("MTN Confirm (Driver): DB update error - " . $e->getMessage()); + printFailure("Database processing error."); +} + diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/finalize_wallet_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/finalize_wallet_payment.php new file mode 100755 index 0000000..42e168d --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/finalize_wallet_payment.php @@ -0,0 +1,103 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + return $stmt->rowCount() > 0 ? $token : null; +} + +function generatePaymentID($con, $driverId, $amount, $method): ?string { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; +} + +function finalizeWalletPayment($con) { + $orderRef = $_GET['orderRef'] ?? null; + if (empty($orderRef)) { + logError("FINALIZE", "Missing orderRef"); + return; + } + + // 1. تحقق من الدفع + $stmt = $con->prepare("SELECT * FROM `paymentsLogSyriaDriver` WHERE order_ref = :order_ref AND status = 1 LIMIT 1"); + $stmt->execute([':order_ref' => $orderRef]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + logError("FINALIZE", "Payment not found or not completed", ['orderRef' => $orderRef]); + return; + } + + try { + $driverId = $payment['user_id']; + $originalAmount = floatval($payment['amount']); + $paymentMethod = $payment['payment_method'] ?? 'ecash'; + + // حساب المكافأة + $bonusAmount = match ((int)$originalAmount) { + 10000 => 10000.0, + 20000 => 21000.0, + 40000 => 45000.0, + 100000 => 110000.0, + default => $originalAmount, + }; + + // إنشاء التوكنات + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + if (!$tokenDriver) throw new Exception('Failed to generate driver token'); + + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) throw new Exception('Failed to generate siro token'); + + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + if (!$paymentID) throw new Exception('Failed to generate payment ID'); + + // driverWallet + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, + ':paymentID' => $paymentID, + ':amount' => $bonusAmount, + ':paymentMethod' => $paymentMethod + ]); + if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed'); + + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]); + + // siroWallet + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) + VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token, CURRENT_TIMESTAMP)"); + $insertSiro->execute([ + ':driverId' => $driverId, + ':passengerId' => 'driver', + ':amount' => $originalAmount, + ':paymentMethod' => $paymentMethod, + ':token' => $tokenSiro + ]); + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSiro]); + + logError("FINALIZE", "Wallets updated successfully", ['orderRef' => $orderRef]); + printSuccess("FINALIZE", "Wallets updated successfully"); + } catch (Throwable $e) { + logError("FINALIZE", "Exception during finalization: " . $e->getMessage(), ['orderRef' => $orderRef]); + } +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/generate_keys.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/generate_keys.php new file mode 100755 index 0000000..05d1fe4 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/generate_keys.php @@ -0,0 +1,47 @@ + "sha256", + "private_key_bits" => 1024, + "private_key_type" => OPENSSL_KEYTYPE_RSA, +]; + +// إنشاء زوج المفاتيح +$res = openssl_pkey_new($config); + +if (!$res) { + die('Failed to generate new private key. Error: ' . openssl_error_string()); +} + +// استخراج المفتاح الخاص +openssl_pkey_export($res, $private_key); + +// استخراج المفتاح العام +$public_key_details = openssl_pkey_get_details($res); +$public_key = $public_key_details["key"]; + +// حفظ المفاتيح في ملفات +file_put_contents('private_key.pem', $private_key); +file_put_contents('public_key.pem', $public_key); + +echo "

Keys Generated Successfully!

"; +echo "

Private Key (saved to private_key.pem):

"; +echo "
" . htmlspecialchars($private_key) . "
"; +echo "

Public Key (saved to public_key.pem):

"; +echo "
" . htmlspecialchars($public_key) . "
"; + +// --- تحضير المفتاح العام لعملية التفعيل --- +// إزالة الهيدر والفوتر والأسطر الجديدة كما هو مطلوب +$formatted_public_key = str_replace("-----BEGIN PUBLIC KEY-----", "", $public_key); +$formatted_public_key = str_replace("-----END PUBLIC KEY-----", "", $formatted_public_key); +$formatted_public_key = preg_replace("/\s+/", "", $formatted_public_key); + + +echo "

Formatted Public Key (for Terminal Activation):

"; +echo "

انسخ هذا المفتاح لاستخدامه في خطوة تفعيل الجهاز (activate_terminal.php)

"; +echo ""; + +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/initiate_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/initiate_payment.php new file mode 100755 index 0000000..15e0596 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/initiate_payment.php @@ -0,0 +1,54 @@ + intval($invoice), + 'Phone' => $phone, + 'Guid' => $guid +], JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE); + +$hash = hash('sha256', $body, true); +openssl_sign($hash, $sig, $privateKeyPem, OPENSSL_ALGO_SHA256); +$xSignature = base64_encode($sig); + +$ch = curl_init("{$baseUrl}/pos_web/payment_phone/initiate"); +curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $body, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Request-Name: pos_web/payment_phone/initiate", + "Subject: {$terminalId}", + "X-Signature: {$xSignature}" + ] +]); +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +// سجل المحاولة مع Guid +$stmt = $con->prepare( + "UPDATE `mtn_payments` + SET guid = :guid, status = 3, updated_at = NOW() + WHERE invoice = :inv" +); +$stmt->execute([':guid'=>$guid, ':inv'=>$invoice]); + +header('Content-Type: application/json'); +http_response_code($httpCode); +echo $response; \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/key.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/key.php new file mode 100755 index 0000000..eaf9c08 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/key.php @@ -0,0 +1,56 @@ + $publicKey, + "Secret" => $activationCode, + "Serial" => $serialNumber +]; +//$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES); +$bodyJson = trim(stripslashes(json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS)),'"'); +//$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); +// 1. توليد هاش SHA256 للـ JSON +//$bodyHash = hash('sha256', $bodyJson, true); + +// 2. تحميل المفتاح الخاص للتوقيع +$privateKey = openssl_pkey_get_private(file_get_contents("private_key.pem")); // تأكد من وجود هذا الملف بجانب السكربت + +// 3. توقيع الهاش +openssl_sign($bodyJson, $signature, $privateKey, OPENSSL_ALGO_SHA256); + +// 4. تحويل التوقيع إلى Base64 +$xSignature = base64_encode($signature); + +// 5. إرسال الطلب +$headers = [ + "Content-Type: application/json", + "Accept-Language: en", + "Request-Name: pos_web/pos/activate", + "Subject: $terminalId", + "X-Signature: $xSignature" +]; + +$ch = curl_init("https://cashmobile.mtnsyr.com:9000"); +curl_setopt($ch, CURLOPT_POST, true); +curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson); +curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +// ✅ النتيجة +header('Content-Type: application/json'); +echo json_encode([ + "httpCode" => $httpCode, + "response" => json_decode($response, true), + "sentBody" => $body, +]); \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/mtn_start.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/mtn_start.php new file mode 100755 index 0000000..89e007d --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/mtn_start.php @@ -0,0 +1,129 @@ + intval($amount * 100), + "Invoice" => $invoiceNumber, + "Session" => $sessionNumber, + "TTL" => $ttl +]; +error_log("📦 Create Invoice Body: " . json_encode($createInvoiceBody, JSON_UNESCAPED_UNICODE)); +$invoiceResponse = sendMtnApiRequest("pos_web/invoice/create", $terminalId, $createInvoiceBody); +error_log("📥 Create Invoice Response: " . json_encode($invoiceResponse, JSON_UNESCAPED_UNICODE)); + +if (!$invoiceResponse || isset($invoiceResponse['Errno']) && $invoiceResponse['Errno'] != 0) { + error_log("❌ Failed to create invoice. Error: " . json_encode($invoiceResponse)); + printFailure("فشل إنشاء الفاتورة عبر MTN."); + exit; +} + +// ====== 2. بدء الدفع ====== +$initiateBody = [ + "Invoice" => $invoiceNumber, + "Phone" => $phone, + "Guid" => $guid +]; +error_log("📤 body initiateBody: $initiateBody"); +error_log("📦 Initiate Payment Body: " . json_encode($initiateBody, JSON_UNESCAPED_UNICODE)); +$initiateResponse = sendMtnApiRequest("pos_web/payment_phone/initiate", $terminalId, $initiateBody); +error_log("📥 Initiate Response: " . json_encode($initiateResponse, JSON_UNESCAPED_UNICODE)); + +if (!$initiateResponse || !isset($initiateResponse['OperationNumber'])) { + error_log("❌ Failed to initiate payment."); + printFailure($initiateResponse); + exit; +} + +$operationNumber = $initiateResponse['OperationNumber']; + +// ====== 3. تسجيل العملية ====== +try { + $stmt = $con->prepare("INSERT INTO `paymentsLogSyriaDriver` + (`user_id`, `amount`, `status`, `order_ref`, `payment_method`, `created_at`) + VALUES (?, ?, 2, ?, 'mtn', NOW())"); + $stmt->execute([$passengerId, $amount, $invoiceNumber]); + error_log("✅ DB Log Inserted."); +} catch (PDOException $e) { + error_log("❌ DB ERROR: " . $e->getMessage()); + printFailure("فشل في تسجيل العملية."); + exit; +} + +// ====== 4. نجاح +error_log("✅ Payment initiation successful."); +printSuccess([ + "invoiceNumber" => $invoiceNumber, + "operationNumber" => $operationNumber, + "guid" => $guid +]); + + +// ====== دالة إرسال الطلب ===================== +function sendMtnApiRequest($requestName, $terminalId, $body) +{ + $apiUrl = "https://cashmobile.mtnsyr.com:9000"; + $privateKey = openssl_pkey_get_private(file_get_contents("private_key.pem")); + + // ✅ تحويل الـ body إلى JSON بدون فراغات أو أسطر + $bodyJson = trim(stripslashes(json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS)), '"'); +//$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + // ✅ توليد التوقيع + // $bodyHash = hash('sha256', $bodyJson, true); + error_log("📤 body before JSON: $bodyJson"); + openssl_sign($bodyJson, $signature, $privateKey, OPENSSL_ALGO_SHA256); + $xSignature = base64_encode($signature); +error_log("📤 body xSignature: $xSignature"); + // ✅ رؤوس الطلب + $headers = [ + "Content-Type: application/json", + "Accept-Language: en", + "Request-Name: $requestName", + "Subject: $terminalId", + "X-Signature: $xSignature" + ]; + + $ch = curl_init($apiUrl); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $response = curl_exec($ch); + + // ✅ لوق داخلي + error_log("🔐 Signature for $requestName: $xSignature"); + error_log("📤 Sent JSON: $bodyJson"); + + curl_close($ch); + return json_decode($response, true); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/private_key.pem b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/private_key.pem new file mode 100644 index 0000000..fead7a6 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/private_key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXwIBAAKBgQDOhVAdUyxFpVNSyjRndMWEPAN9vJEetMzLbjF9DTn2lPVuRj/M +kwq9wCNhy+tdeX2lIn4K3EkONBvYJubBhxnYOoQuMchPW5vG7VnmpLjZ7TkpM2n9 +fcMu8u1GkLatLblDI4LTfvn3851+nhpnYlUVkjw5GAhH4XnEpveIjqDhzQIDAQAB +AoGBALRcAvqJT8nHN7y+8QNFHNZ+XwIpc4egmJY1Ny0iJvPtZWaYHVG5PRE4Qu4+ +29+3oX5dYDx146tu4L5mQvLS3ULBsvxaUZt2lT/vxkQzI9pNfXw584WvIrbtxQod +ILvBcnamwQa9hEOIFZVyZ/hzkzUcMO6cAXqvsfqqPgJhm7PBAkEA+xgE9CUOLDFl +vLePQKGcHIUOsPLr16qNEgGhTW7Km3OMMqoB2f7t67xOHGqK6tnANRM4Sk6IModI +wbZuVh4jMQJBANKOVmIdDLNffZVHp90SDRG7/YdK2R5ob361CIkcUzjh927Wfs5W +A/WroB7eJ7pWiq2BMaj/xq65nYaCOldvaV0CQQDm12c+eY61DFjnDa6ykaEvCxi9 +jydJp+93vW3o/VFhZvJeZbO8EcX0MrNxJnY+gSBW6yuWDOrj4UH/bVO08pIRAkEA +lH3TiBAqo9nlTEEjrnILi4VD0IVFx/8pGnf71A6I1qXuBVn6RfQ9iKWIIBzWccCU +vrZNWn1AFntLD9CJ6p3k9QJBAMbSQ9CoXWlOLJRduV15ER1ZyE/inVd4jIvtjAgz +b7QaM62Ecxl3D8EI/LTSZV9Oa8D/62cJeMsflVa7gpavL70= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/public_key.pem b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/public_key.pem new file mode 100644 index 0000000..63a3519 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqBQZEJXWCQwPsPzBM70M3TjyU +5vwCZWoEtUomR9Qu+dEQaa0Hniz6JY8+goCxfMYuZQw6+kimctA2KqzT2pCsJufN +b92pSAMZgb0RSTl2y62oJkJd2WY7dj36AvPEyw6DxCFItvFOu7HGl3LlHQBriiw3 +jwtuS6DO7gbmAJPU8wIDAQAB +-----END PUBLIC KEY----- diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver_payout_syria.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver_payout_syria.php new file mode 100755 index 0000000..4cdb7d0 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver_payout_syria.php @@ -0,0 +1,115 @@ +prepare($sql); + + // تنفيذ الاستعلام مع تمرير البيانات + $success = $stmt->execute([ + $driver_id, + $driver_name, + $amount, + $wallet_type, + $wallet_number + ]); + + if ($success) { + // --- 4. الحصول على رقم الطلب وإرسال إشعار واتساب --- + $transaction_id = $con->lastInsertId(); // الحصول على رقم التعريف الخاص بالطلب الجديد + sendWhatsAppNotification($transaction_id, $driver_name, $amount, $wallet_type, $wallet_number); + + // إرسال استجابة نجاح إلى التطبيق + printSuccess("Withdrawal request saved and notification sent."); + + } else { + printFailure('Failed to save withdrawal request.'); + } + +} catch (PDOException $e) { + // التعامل مع أخطاء قاعدة البيانات + error_log("Database Error in request_withdrawal.php: " . $e->getMessage()); + printFailure('A database error occurred.'); +} + + +/** + * دالة لإرسال إشعار إلى خدمة العملاء عبر RaseelPlus API + */ +function sendWhatsAppNotification($transaction_id, $driver_name, $amount, $wallet_type, $wallet_number) { + + // استخدام متغيرات البيئة (Environment Variables) هو الطريقة الأكثر أماناً لإدارة المعلومات الحساسة + // بدلاً من كتابتها مباشرة في الكود. + $customer_service_number = getenv('CUSTOMER_SERVICE_WHATSAPP'); + // $customer_service_number = "9639XXXXXXXX"; // كرقم احتياطي مؤقت + + // نص الرسالة مع إضافة رقم الطلب + $messageBody = "طلب سحب جديد (رقم الطلب: #$transaction_id):\n\n" . + "اسم السائق: " . $driver_name . "\n" . + "المبلغ: " . $amount . " ل.س\n" . + "نوع المحفظة: " . $wallet_type . "\n" . + "رقم المحفظة: " . $wallet_number; + + // بيانات الطلب (Payload) للـ API + $payload = [ + "number" => $customer_service_number, + "type" => "text", + "message" => $messageBody, + "instance_id" => getenv('instance_idWhatsApp'); + "access_token" => getenv('access_tokenWhatsApp'); + ]; + + // استدعاء الـ API + // ملاحظة: لا نتحقق من استجابة الـ API هنا لأن العملية الرئيسية (حفظ الطلب) قد نجحت بالفعل. + // يمكن إضافة تسجيل للأخطاء إذا لزم الأمر. + callAPI_Withdrawal("POST", "https://raseelplus.com/api/send", json_encode($payload)); +} + + +/** + * دالة لإجراء استدعاءات API باستخدام cURL + */ +function callAPI_Withdrawal($method, $url, $data) { + $curl = curl_init(); + curl_setopt_array($curl, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => "", + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $data, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Accept: application/json" + ], + ]); + $response = curl_exec($curl); + $err = curl_error($curl); + curl_close($curl); + + if ($err) { + // تسجيل الخطأ في سجلات الخادم للمراجعة لاحقًا + error_log("[callAPI_Withdrawal] cURL Error #: " . $err); + return null; + } else { + return json_decode($response); + } +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/confirm_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/confirm_payment.php new file mode 100755 index 0000000..5e5ac72 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/confirm_payment.php @@ -0,0 +1,169 @@ + intval($invoice), + 'Phone' => $phone, + 'Guid' => $guid, + 'OperationNumber' => intval($operationNumber), + 'Code' => $codeB64 +]; +$bodyJson = trim(stripslashes(json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS)), '"'); + +error_log("MTN Confirm: Prepared body JSON: " . $bodyJson); + +// توليد التوقيع +$signResult = openssl_sign($bodyJson, $sig, $privateKey, OPENSSL_ALGO_SHA256); +if (!$signResult) { + error_log("MTN Confirm: Failed to generate signature"); + printFailure("Signature error."); + exit; +} +$xSignature = base64_encode($sig); +error_log("MTN Confirm: Generated signature"); + +// إرسال الطلب +$ch = curl_init("{$baseUrl}/pos_web/payment_phone/confirm"); +curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $bodyJson, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Request-Name: pos_web/payment_phone/confirm", + "Subject: {$terminalId}", + "X-Signature: {$xSignature}" + ] +]); + +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +$curlError = curl_error($ch); +curl_close($ch); + +error_log("MTN Confirm: HTTP $httpCode - Response: $response"); +if ($curlError) { + error_log("MTN Confirm: cURL error - $curlError"); +} + +// تحديث قاعدة البيانات في حال نجاح +if ($httpCode === 200) { + try { + $stmt = $con->prepare( + "UPDATE `paymentsLogSyria` SET status = 1, updated_at = NOW() + WHERE order_ref = :inv" + ); + $stmt->execute([':inv' => $invoice]); + error_log("MTN Confirm: Payment updated successfully in DB for invoice={$invoice}"); + + $stmt = $con->prepare("SELECT * FROM paymentsLogSyria WHERE order_ref = :order_ref LIMIT 1"); + $stmt->execute([':order_ref' => $invoice]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($payment) { + $userId = $payment['user_id']; + $amount = $payment['amount']; + $paymentMethod = $payment['payment_method'] ?? 'mtn'; + + $finalAmount = calculateBonus($amount); + $token = generatePaymentToken($userId, $finalAmount); + $walletResult = addToPassengerWallet($userId, $finalAmount, $token); + + $siroToken = generatePaymentToken($userId, $amount); + $siroWalletResult = addToSiroWallet($userId, $amount, $paymentMethod, $siroToken); + + printSuccess('MTN Confirm'); + + exit; + } + + + } catch (PDOException $e) { + error_log("MTN Confirm: DB update error - " . $e->getMessage()); + } +} else { + error_log("MTN Confirm: Payment failed with HTTP code $httpCode"); +} + +header('Content-Type: application/json'); +http_response_code($httpCode); +echo $response; + +function calculateBonus($amount) { + if ($amount == 200000) return 205000; + if ($amount == 400000) return 425000; + if ($amount == 1000000) return 1040000; + return $amount; +} + +function generatePaymentToken($passengerId, $amount) { + $url = BASE_URL . "/passengerWallet/addPaymentTokenPassenger.php"; + $postData = ['passengerId' => $passengerId, 'amount' => $amount]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200) return null; + $data = json_decode($response, true); + return $data['message'] ?? null; +} +function addToPassengerWallet($passengerId, $amount, $token) { + $url = BASE_URL . "/passengerWallet/add.php"; + $postData = ['passenger_id' => $passengerId, 'balance' => $amount, 'token' => $token]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200) return null; + return json_decode($response, true); +} + +function addToSiroWallet($passengerId, $amount, $paymentMethod, $token) { + $url = BASE_URL . "/siroWallet/add.php"; + $postData = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'passengerId' => $passengerId, + 'token' => $token, + 'driverId' => 'passenger' + ]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200) return null; + return json_decode($response, true); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/finalize_wallet_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/finalize_wallet_payment.php new file mode 100755 index 0000000..42e168d --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/finalize_wallet_payment.php @@ -0,0 +1,103 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + return $stmt->rowCount() > 0 ? $token : null; +} + +function generatePaymentID($con, $driverId, $amount, $method): ?string { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; +} + +function finalizeWalletPayment($con) { + $orderRef = $_GET['orderRef'] ?? null; + if (empty($orderRef)) { + logError("FINALIZE", "Missing orderRef"); + return; + } + + // 1. تحقق من الدفع + $stmt = $con->prepare("SELECT * FROM `paymentsLogSyriaDriver` WHERE order_ref = :order_ref AND status = 1 LIMIT 1"); + $stmt->execute([':order_ref' => $orderRef]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + logError("FINALIZE", "Payment not found or not completed", ['orderRef' => $orderRef]); + return; + } + + try { + $driverId = $payment['user_id']; + $originalAmount = floatval($payment['amount']); + $paymentMethod = $payment['payment_method'] ?? 'ecash'; + + // حساب المكافأة + $bonusAmount = match ((int)$originalAmount) { + 10000 => 10000.0, + 20000 => 21000.0, + 40000 => 45000.0, + 100000 => 110000.0, + default => $originalAmount, + }; + + // إنشاء التوكنات + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + if (!$tokenDriver) throw new Exception('Failed to generate driver token'); + + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) throw new Exception('Failed to generate siro token'); + + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + if (!$paymentID) throw new Exception('Failed to generate payment ID'); + + // driverWallet + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, + ':paymentID' => $paymentID, + ':amount' => $bonusAmount, + ':paymentMethod' => $paymentMethod + ]); + if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed'); + + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]); + + // siroWallet + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) + VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token, CURRENT_TIMESTAMP)"); + $insertSiro->execute([ + ':driverId' => $driverId, + ':passengerId' => 'driver', + ':amount' => $originalAmount, + ':paymentMethod' => $paymentMethod, + ':token' => $tokenSiro + ]); + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSiro]); + + logError("FINALIZE", "Wallets updated successfully", ['orderRef' => $orderRef]); + printSuccess("FINALIZE", "Wallets updated successfully"); + } catch (Throwable $e) { + logError("FINALIZE", "Exception during finalization: " . $e->getMessage(), ['orderRef' => $orderRef]); + } +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/generate_keys.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/generate_keys.php new file mode 100755 index 0000000..05d1fe4 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/generate_keys.php @@ -0,0 +1,47 @@ + "sha256", + "private_key_bits" => 1024, + "private_key_type" => OPENSSL_KEYTYPE_RSA, +]; + +// إنشاء زوج المفاتيح +$res = openssl_pkey_new($config); + +if (!$res) { + die('Failed to generate new private key. Error: ' . openssl_error_string()); +} + +// استخراج المفتاح الخاص +openssl_pkey_export($res, $private_key); + +// استخراج المفتاح العام +$public_key_details = openssl_pkey_get_details($res); +$public_key = $public_key_details["key"]; + +// حفظ المفاتيح في ملفات +file_put_contents('private_key.pem', $private_key); +file_put_contents('public_key.pem', $public_key); + +echo "

Keys Generated Successfully!

"; +echo "

Private Key (saved to private_key.pem):

"; +echo "
" . htmlspecialchars($private_key) . "
"; +echo "

Public Key (saved to public_key.pem):

"; +echo "
" . htmlspecialchars($public_key) . "
"; + +// --- تحضير المفتاح العام لعملية التفعيل --- +// إزالة الهيدر والفوتر والأسطر الجديدة كما هو مطلوب +$formatted_public_key = str_replace("-----BEGIN PUBLIC KEY-----", "", $public_key); +$formatted_public_key = str_replace("-----END PUBLIC KEY-----", "", $formatted_public_key); +$formatted_public_key = preg_replace("/\s+/", "", $formatted_public_key); + + +echo "

Formatted Public Key (for Terminal Activation):

"; +echo "

انسخ هذا المفتاح لاستخدامه في خطوة تفعيل الجهاز (activate_terminal.php)

"; +echo ""; + +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/initiate_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/initiate_payment.php new file mode 100755 index 0000000..15e0596 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/initiate_payment.php @@ -0,0 +1,54 @@ + intval($invoice), + 'Phone' => $phone, + 'Guid' => $guid +], JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE); + +$hash = hash('sha256', $body, true); +openssl_sign($hash, $sig, $privateKeyPem, OPENSSL_ALGO_SHA256); +$xSignature = base64_encode($sig); + +$ch = curl_init("{$baseUrl}/pos_web/payment_phone/initiate"); +curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $body, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Request-Name: pos_web/payment_phone/initiate", + "Subject: {$terminalId}", + "X-Signature: {$xSignature}" + ] +]); +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +// سجل المحاولة مع Guid +$stmt = $con->prepare( + "UPDATE `mtn_payments` + SET guid = :guid, status = 3, updated_at = NOW() + WHERE invoice = :inv" +); +$stmt->execute([':guid'=>$guid, ':inv'=>$invoice]); + +header('Content-Type: application/json'); +http_response_code($httpCode); +echo $response; \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/key.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/key.php new file mode 100755 index 0000000..eaf9c08 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/key.php @@ -0,0 +1,56 @@ + $publicKey, + "Secret" => $activationCode, + "Serial" => $serialNumber +]; +//$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES); +$bodyJson = trim(stripslashes(json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS)),'"'); +//$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); +// 1. توليد هاش SHA256 للـ JSON +//$bodyHash = hash('sha256', $bodyJson, true); + +// 2. تحميل المفتاح الخاص للتوقيع +$privateKey = openssl_pkey_get_private(file_get_contents("private_key.pem")); // تأكد من وجود هذا الملف بجانب السكربت + +// 3. توقيع الهاش +openssl_sign($bodyJson, $signature, $privateKey, OPENSSL_ALGO_SHA256); + +// 4. تحويل التوقيع إلى Base64 +$xSignature = base64_encode($signature); + +// 5. إرسال الطلب +$headers = [ + "Content-Type: application/json", + "Accept-Language: en", + "Request-Name: pos_web/pos/activate", + "Subject: $terminalId", + "X-Signature: $xSignature" +]; + +$ch = curl_init("https://cashmobile.mtnsyr.com:9000"); +curl_setopt($ch, CURLOPT_POST, true); +curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson); +curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +// ✅ النتيجة +header('Content-Type: application/json'); +echo json_encode([ + "httpCode" => $httpCode, + "response" => json_decode($response, true), + "sentBody" => $body, +]); \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_confirm.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_confirm.php new file mode 100755 index 0000000..81bfef2 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_confirm.php @@ -0,0 +1,247 @@ + (int)$invoice, + 'Phone' => $phone, + 'Guid' => $guid, + 'OperationNumber' => (int)$operationNumber, + 'Code' => $codeB64, + 'Accept-Language' => $lang + ]; + $bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE); + mlog("MTN Confirm: Prepared body JSON: " . $bodyJson); + + // توقيع الجسم + $sig = null; + $signResult = openssl_sign($bodyJson, $sig, $privateKey, OPENSSL_ALGO_SHA256); + if (!$signResult || !$sig) { + mlog("MTN Confirm: Failed to generate signature"); + printFailure("Signature error."); + exit; + } + $xSignature = base64_encode($sig); + mlog("MTN Confirm: Generated signature"); + + // إرسال الطلب إلى MTN + $ch = curl_init("{$baseUrl}/pos_web/payment_phone/confirm"); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $bodyJson, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Request-Name: pos_web/payment_phone/confirm", + "Subject: {$terminalId}", + "X-Signature: {$xSignature}" + ], + CURLOPT_TIMEOUT => 25, + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + mlog("MTN Confirm: HTTP {$httpCode} - Response: " . ($response ?? '')); + if ($curlError) { + mlog("MTN Confirm: cURL error - {$curlError}"); + } + + // فك JSON لرد MTN (حتى لو خطأ) لعرض سبب واضح + $mtn = json_decode($response ?: '{}', true); + if (!is_array($mtn)) { + $mtn = []; + } + + // 🧠 سياسة القرار: + // - إذا HTTP≠200 → فشل شبكة/بوابة + // - إذا HTTP=200 لكن Errno≠0 → خطأ من MTN (مثل Incorrect sms code) + // - فقط إذا HTTP=200 && Errno=0 → نجاح، نحدّث DB ونضيف للمحافظ + if ($httpCode !== 200) { + // لا تحدّث DB + printFailure([ + 'message' => 'MTN confirm HTTP failure', + 'http' => $httpCode, + 'mtn' => $mtn + ]); + exit; + } + + // HTTP 200 — افحص Errno + $errno = isset($mtn['Errno']) ? (int)$mtn['Errno'] : null; + if ($errno !== 0) { + // لا تحدّث DB في هذه الحالة + $errText = isset($mtn['Error']) ? $mtn['Error'] : 'Unknown MTN error'; + // اطبع لوج مشابه للمثال المطلوب + // مثال: {"Errno":662,"Error":"Incorrect sms code","Abuse":2,"Transaction":""} + mlog("MTN Confirm: Business failure from MTN - Errno={$errno}, Error=" . json_encode($mtn, JSON_UNESCAPED_UNICODE)); + printFailure([ + 'message' => $errText, + 'errno' => $errno, + 'mtn' => $mtn + ]); + exit; + } + + // ✅ نجاح كامل من MTN — تحديث DB ثم المحافظ + try { + global $con; + + $stmt = $con->prepare( + "UPDATE `paymentsLogSyria` SET status = 1, updated_at = NOW() + WHERE order_ref = :inv" + ); + $stmt->execute([':inv' => $invoice]); + mlog("MTN Confirm: Payment updated successfully in DB for invoice={$invoice}"); + + $stmt = $con->prepare("SELECT * FROM paymentsLogSyria WHERE order_ref = :order_ref LIMIT 1"); + $stmt->execute([':order_ref' => $invoice]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + mlog("MTN Confirm: Payment row not found after update"); + printFailure("Payment row not found"); + exit; + } + + $userId = $payment['user_id']; + $amount = $payment['amount']; + $paymentMethod = $payment['payment_method'] ?? 'mtn'; + + $finalAmount = calculateBonus($amount); + + $token = generatePaymentToken($userId, $finalAmount); + $walletResult = addToPassengerWallet($userId, $finalAmount, $token); + + $siroToken = generatePaymentToken($userId, $amount); + $siroWalletResult = addToSiroWallet($userId, $amount, $paymentMethod, $siroToken); + + // رجّع رد موحّد + ضمّن رد MTN + printSuccess([ + 'message' => 'MTN Confirm', + 'data' => [ + 'invoice' => $invoice, + 'finalAmount' => $finalAmount, + 'wallet' => $walletResult, + 'siroWallet' => $siroWalletResult, + 'mtn' => $mtn + ] + ]); + exit; + + } catch (PDOException $e) { + mlog("MTN Confirm: DB update error - " . $e->getMessage()); + printFailure("DB error"); + exit; + } + +} catch (Throwable $e) { + mlog("MTN Confirm: Exception - " . $e->getMessage()); + printFailure("Server error"); + exit; +} + +/** + * نفس دوال المساعدة، لكن باستعمال BASE_URL المؤمّنة أعلاه + */ +function calculateBonus($amount) { + if ($amount == 20000) return 20500; + if ($amount == 40000) return 42500; + if ($amount == 100000) return 104000; + return $amount; +} + +function generatePaymentToken($passengerId, $amount) { + $url = rtrim(BASE_URL, '/') . "/passengerWallet/addPaymentTokenPassenger.php"; + $postData = ['passengerId' => $passengerId, 'amount' => $amount]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200 || !$response) return null; + $data = json_decode($response, true); + return $data['message'] ?? null; +} + +function addToPassengerWallet($passengerId, $amount, $token) { + $url = rtrim(BASE_URL, '/') . "/passengerWallet/add.php"; + $postData = ['passenger_id' => $passengerId, 'balance' => $amount, 'token' => $token]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200 || !$response) return null; + return json_decode($response, true); +} + +function addToSiroWallet($passengerId, $amount, $paymentMethod, $token) { + $url = rtrim(BASE_URL, '/') . "/siroWallet/add.php"; + $postData = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'passengerId' => $passengerId, + 'token' => $token, + 'driverId' => 'passenger' + ]; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpCode != 200 || !$response) return null; + return json_decode($response, true); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_start.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_start.php new file mode 100755 index 0000000..89c5e4c --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_start.php @@ -0,0 +1,130 @@ + intval($amount * 100), + "Invoice" => $invoiceNumber, + "Session" => $sessionNumber, + "TTL" => $ttl +]; +error_log("📦 Create Invoice Body: " . json_encode($createInvoiceBody, JSON_UNESCAPED_UNICODE)); +$invoiceResponse = sendMtnApiRequest("pos_web/invoice/create", $terminalId, $createInvoiceBody); +error_log("📥 Create Invoice Response: " . json_encode($invoiceResponse, JSON_UNESCAPED_UNICODE)); + +if (!$invoiceResponse || isset($invoiceResponse['Errno']) && $invoiceResponse['Errno'] != 0) { + error_log("❌ Failed to create invoice. Error: " . json_encode($invoiceResponse)); + printFailure("فشل إنشاء الفاتورة عبر MTN."); + exit; +} + +// ====== 2. بدء الدفع ====== +$initiateBody = [ + "Invoice" => $invoiceNumber, + "Phone" => $phone, + "Guid" => $guid +]; +error_log("📤 body initiateBody: $initiateBody"); +error_log("📦 Initiate Payment Body: " . json_encode($initiateBody, JSON_UNESCAPED_UNICODE)); +$initiateResponse = sendMtnApiRequest("pos_web/payment_phone/initiate", $terminalId, $initiateBody); +error_log("📥 Initiate Response: " . json_encode($initiateResponse, JSON_UNESCAPED_UNICODE)); + +if (!$initiateResponse || !isset($initiateResponse['OperationNumber'])) { + error_log("❌ Failed to initiate payment."); + printFailure($initiateResponse); + exit; +} + +$operationNumber = $initiateResponse['OperationNumber']; + +// ====== 3. تسجيل العملية ====== +try { + $stmt = $con->prepare("INSERT INTO `paymentsLogSyria` + (`user_id`, `amount`, `status`, `order_ref`, `payment_method`, `created_at`) + VALUES (?, ?, 2, ?, 'mtn', NOW())"); + $stmt->execute([$passengerId, $amount, $invoiceNumber]); + error_log("✅ DB Log Inserted."); +} catch (PDOException $e) { + error_log("❌ DB ERROR: " . $e->getMessage()); + printFailure("فشل في تسجيل العملية."); + exit; +} + +// ====== 4. نجاح +error_log("✅ Payment initiation successful."); +printSuccess([ + "invoiceNumber" => $invoiceNumber, + "operationNumber" => $operationNumber, + "guid" => $guid +]); + + +// ====== دالة إرسال الطلب ===================== +function sendMtnApiRequest($requestName, $terminalId, $body) +{ + $apiUrl = "https://cashmobile.mtnsyr.com:9000"; + $privateKey = openssl_pkey_get_private(file_get_contents("private_key.pem")); + + // ✅ تحويل الـ body إلى JSON بدون فراغات أو أسطر + $bodyJson = trim(stripslashes(json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS)), '"'); +//$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + // ✅ توليد التوقيع + // $bodyHash = hash('sha256', $bodyJson, true); + error_log("📤 body before JSON: $bodyJson"); + openssl_sign($bodyJson, $signature, $privateKey, OPENSSL_ALGO_SHA256); + $xSignature = base64_encode($signature); +error_log("📤 body xSignature: $xSignature"); + // ✅ رؤوس الطلب + $headers = [ + "Content-Type: application/json", + "Accept-Language: $lang", + "Request-Name: $requestName", + "Subject: $terminalId", + "X-Signature: $xSignature" + ]; + + $ch = curl_init($apiUrl); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $response = curl_exec($ch); + + // ✅ لوق داخلي + error_log("🔐 Signature for $requestName: $xSignature"); + error_log("📤 Sent JSON: $bodyJson"); + + curl_close($ch); + return json_decode($response, true); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/private_key.pem b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/private_key.pem new file mode 100644 index 0000000..fead7a6 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/private_key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXwIBAAKBgQDOhVAdUyxFpVNSyjRndMWEPAN9vJEetMzLbjF9DTn2lPVuRj/M +kwq9wCNhy+tdeX2lIn4K3EkONBvYJubBhxnYOoQuMchPW5vG7VnmpLjZ7TkpM2n9 +fcMu8u1GkLatLblDI4LTfvn3851+nhpnYlUVkjw5GAhH4XnEpveIjqDhzQIDAQAB +AoGBALRcAvqJT8nHN7y+8QNFHNZ+XwIpc4egmJY1Ny0iJvPtZWaYHVG5PRE4Qu4+ +29+3oX5dYDx146tu4L5mQvLS3ULBsvxaUZt2lT/vxkQzI9pNfXw584WvIrbtxQod +ILvBcnamwQa9hEOIFZVyZ/hzkzUcMO6cAXqvsfqqPgJhm7PBAkEA+xgE9CUOLDFl +vLePQKGcHIUOsPLr16qNEgGhTW7Km3OMMqoB2f7t67xOHGqK6tnANRM4Sk6IModI +wbZuVh4jMQJBANKOVmIdDLNffZVHp90SDRG7/YdK2R5ob361CIkcUzjh927Wfs5W +A/WroB7eJ7pWiq2BMaj/xq65nYaCOldvaV0CQQDm12c+eY61DFjnDa6ykaEvCxi9 +jydJp+93vW3o/VFhZvJeZbO8EcX0MrNxJnY+gSBW6yuWDOrj4UH/bVO08pIRAkEA +lH3TiBAqo9nlTEEjrnILi4VD0IVFx/8pGnf71A6I1qXuBVn6RfQ9iKWIIBzWccCU +vrZNWn1AFntLD9CJ6p3k9QJBAMbSQ9CoXWlOLJRduV15ER1ZyE/inVd4jIvtjAgz +b7QaM62Ecxl3D8EI/LTSZV9Oa8D/62cJeMsflVa7gpavL70= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/public_key.pem b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/public_key.pem new file mode 100644 index 0000000..63a3519 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqBQZEJXWCQwPsPzBM70M3TjyU +5vwCZWoEtUomR9Qu+dEQaa0Hniz6JY8+goCxfMYuZQw6+kimctA2KqzT2pCsJufN +b92pSAMZgb0RSTl2y62oJkJd2WY7dj36AvPEyw6DxCFItvFOu7HGl3LlHQBriiw3 +jwtuS6DO7gbmAJPU8wIDAQAB +-----END PUBLIC KEY----- diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/mtn_new/finalize_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/mtn_new/finalize_payment.php index 7bee232..ed4c7f9 100755 --- a/walletintaleq.intaleq.xyz/v2/main/ride/mtn_new/finalize_payment.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/mtn_new/finalize_payment.php @@ -64,9 +64,9 @@ function finalizeForDriver(PDO $con, int $driverId, float $amount, string $payme if ($stmtDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed.'); // إضافة سجل محاسبي لمحفظة سفر - $stmtSefer = $con->prepare("INSERT INTO seferWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)"); - $stmtSefer->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); - if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed.'); + $stmtSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)"); + $stmtSiro->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); + if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed.'); return ['success' => true, 'message' => 'Driver wallets updated.']; } @@ -90,9 +90,9 @@ function finalizeForPassenger(PDO $con, string $passengerId, float $amount, stri if ($stmtPassenger->rowCount() === 0) throw new Exception('Update passengerWallet failed.'); // إضافة سجل محاسبي لمحفظة سفر - $stmtSefer = $con->prepare("INSERT INTO seferWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)"); - $stmtSefer->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); - if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet for passenger failed.'); + $stmtSiro = $con->prepare("INSERT INTO siroWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)"); + $stmtSiro->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); + if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet for passenger failed.'); return ['success' => true, 'message' => 'Passenger wallets updated.']; } diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/error_log b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/error_log new file mode 100644 index 0000000..e69de29 diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/payWithPayMob.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/payWithPayMob.php new file mode 100644 index 0000000..c9c4494 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/payWithPayMob.php @@ -0,0 +1,100 @@ + + $api_key]); + +$response = callAPI("POST", $auth_url, $auth_data); +// printResponse("AUTH TOKEN RESPONSE", $response); + +$auth_token = $response->token ?? null; +if (!$auth_token) { + die("❌ فشل الحصول على AUTH TOKEN!"); +} +// $amount=$amount*100; +// 2. أنشئ الطلب ORDER +$order_url = "https://accept.paymob.com/api/ecommerce/orders"; +$order_data = [ + "auth_token" => $auth_token, + "delivery_needed" => false, + "amount_cents" => $amount, + "currency" => "EGP", + "merchant_order_id" => uniqid(), + "items" => [] +]; + +$response = callAPI("POST", $order_url, json_encode($order_data)); +// printResponse("ORDER RESPONSE", $response); + +$order_id = $response->id ?? null; +if (!$order_id) { + die("❌ فشل إنشاء الطلب!"); +} +$integration_id=getenv("paymobIntegratedIdCard"); +// 3. احصل على Payment Key +$payment_key_url = "https://accept.paymob.com/api/acceptance/payment_keys"; +$payment_key_data = [ + "auth_token" => $auth_token, + "amount_cents" => $amount, + "expiration" => 3600, + "order_id" => $order_id, + "billing_data" => [ + "first_name" =>$first_name, + "last_name" => $last_name, + "email" => $email, + "phone_number" => $phone_number, + "country" => "EG", + "city" => "Cairo", + "state" => "shobra", + "street" => "Test St.", + "building" => "1", + "apartment" => "10", + "floor" => "2", + "postal_code" => "12345", + "shipping_method"=> 'card' + ], + "currency" => "EGP", + "integration_id" => $integration_id, // ضع الـ Integration ID الصحيح +]; + +$response = callAPI("POST", $payment_key_url, json_encode($payment_key_data)); +// printResponse("PAYMENT TOKEN RESPONSE", $response); + +$payment_token = $response->token ?? null; +if (!$payment_token) { + die("❌ فشل الحصول على PAYMENT TOKEN!"); +} + +// 4. إنشاء IFRAME URL +$iframe_id = "837992"; // ضع الـ Iframe ID الصحيح +$iframe_url = "https://accept.paymob.com/api/acceptance/iframes/$iframe_id?payment_token=$payment_token"; +if($payment_token){ + + printSuccess($iframe_url); +} +// دالة لطلب API عبر CURL +function callAPI($method, $url, $data) +{ + $curl = curl_init(); + + curl_setopt_array($curl, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $data, + CURLOPT_HTTPHEADER => ["Content-Type: application/json"] + ]); + + $response = curl_exec($curl); + curl_close($curl); + + return json_decode($response); +} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php new file mode 100644 index 0000000..565ea08 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php @@ -0,0 +1,358 @@ + $user_id, +// "passengerId" => $passengerId +// ]); + +// Validate user_id and passengerId +if (!$user_id || !$passengerId) { + // logError("1", "Invalid parameters", [ + // "user_id" => $user_id, + // "passengerId" => $passengerId + // ]); + printFailure("Invalid user ID or passenger ID."); + exit; +} + +try { + // Step 1: Get the latest successful payment + // logError("1", "Querying latest payment", ["user_id" => $user_id]); + + $stmt = $con->prepare("SELECT * FROM paymentsLog WHERE user_id = :user_id AND created_at >= DATE_SUB(NOW(), INTERVAL 2 MINUTE) +ORDER BY created_at DESC +LIMIT 1"); + $stmt->bindParam(':user_id', $user_id, PDO::PARAM_STR); + $stmt->execute(); + + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + logError("1", "No payment found", ["user_id" => $user_id]); + printFailure("No payment data found."); + exit; + } + + // logError("1", "Payment found", [ + // "payment_id" => $payment['id'] ?? 'unknown', + // "status" => $payment['status'], + // "amount" => $payment['amount']/100 ?? 'unknown' + // ]); + + // Step 2: Check payment status + if ($payment['status'] != 1) { + // logError("2", "Payment not successful", ["status" => $payment['status']]); + printFailure("Payment is not successful yet."); + exit; + } + + // logError("2", "Payment status verified", ["status" => $payment['status']]); + + $amount = $payment['amount']/100; // Paid amount + + // Step 3: Calculate bonus based on the paid amount + // logError("3", "Calculating bonus", ["amount" => $amount]); + $finalAmount = calculateBonus($amount); + + if ($finalAmount <= 0) { + // logError("3", "Bonus calculation failed", [ + // "original_amount" => $amount, + // "calculated_amount" => $finalAmount + // ]); + printFailure("Invalid amount for bonus calculation."); + exit; + } + + // logError("3", "Bonus calculated", [ + // "original_amount" => $amount, + // "final_amount" => $finalAmount + // ]); + + // // Step 4: Generate payment token + // logError("4", "Generating payment token", [ + // "passengerId" => $passengerId, + // "amount" => $finalAmount + // ]); + + $token = generatePaymentToken($passengerId, $finalAmount); + + if (!$token) { + // logError("4", "Token generation failed"); + printFailure("Payment verified, but failed to generate token."); + exit; + } + + // logError("4", "Token generated successfully", ["token_length" => strlen($token)]); + + // // Step 5: Add balance to passenger's wallet + // logError("5", "Adding balance to passenger wallet", [ + // "passengerId" => $passengerId, + // "amount" => $finalAmount + // ]); + + $walletResult = addToPassengerWallet($passengerId, $finalAmount, $token); + + if (!$walletResult || !isset($walletResult['status']) || $walletResult['status'] != "success") { + // logError("5", "Failed to add balance to passenger wallet", $walletResult); + printFailure("Payment verified, but failed to add balance to passenger wallet."); + exit; + } + + // logError("5", "Balance added to passenger wallet", $walletResult); + + // Step 6: Add balance to Siro wallet + // logError("6", "Adding balance to Siro wallet", [ + // "passengerId" => $passengerId, + // "amount" => $finalAmount, + // "paymentMethod" => $paymentMethod + // ]); + + $token = generatePaymentToken($passengerId, $finalAmount); + + if (!$token) { + // logError("4", "Token generation failed"); + printFailure("Payment verified, but failed to generate token."); + exit; + } + + // logError("4", "Token generated successfully", ["token_length" => strlen($token)]); + + $siroWalletResult = addToSiroWallet($passengerId, $amount, $paymentMethod); + + if (!$siroWalletResult || !isset($siroWalletResult['status']) || $siroWalletResult['status'] != "success") { + // logError("6", "Failed to add balance to Siro wallet", $siroWalletResult); + printFailure("Payment verified, but failed to add balance to Siro wallet."); + exit; + } + + // logError("6", "Balance added to Siro wallet", $siroWalletResult); + + // // Final success + // logError("7", "Process completed successfully", [ + // "payment_id" => $payment['id'] ?? 'unknown', + // "amount" => $finalAmount, + // "passengerId" => $passengerId + // ]); + + printSuccess( "Payment data saved successfully"); + +} catch (PDOException $e) { + logError("ERROR", "Database error: " . $e->getMessage()); + printFailure("Database error occurred."); +} catch (Exception $e) { + logError("ERROR", "General error: " . $e->getMessage()); + printFailure("An error occurred during payment verification."); +} + +// 🎯 Function to generate payment token with error logging +function generatePaymentToken($passengerId, $amount) { + $url = BASE_URL . "/passengerWallet/addPaymentTokenPassenger.php"; + + $postData = [ + 'passengerId' => $passengerId, + 'amount' => $amount + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("4.1", "cURL error in token generation", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("4.2", "HTTP error in token generation", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data || !isset($data['message'])) { + logError("4.3", "Invalid response format in token generation", [ + "response" => $response + ]); + return null; + } + + return $data['message']; // ✅ Return token +} + +// 🎯 Function to add balance to passenger's wallet with error logging +function addToPassengerWallet($passengerId, $amount, $token) { + $url = BASE_URL . "/passengerWallet/add.php"; + + $postData = [ + 'passenger_id' => $passengerId, + 'balance' => $amount, + 'token' => $token + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("5.1", "cURL error in passenger wallet update", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("5.2", "HTTP error in passenger wallet update", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data) { + logError("5.3", "Invalid response format in passenger wallet update", [ + "response" => $response + ]); + return null; + } + + return $data; // ✅ Return result +} + +// 🎯 Function to add balance to Siro wallet with error logging + + +function addToSiroWallet($passengerId, $amount, $paymentMethod) { + + + // Generate a new token specifically for the Siro wallet + $siroToken = generatePaymentToken($passengerId, $amount); + + if (!$siroToken) { + logError("6.0.1", "Failed to generate Siro token"); + return null; + } + + logError("6.0.2", "Generated new Siro token", [ + "token_length" => ($siroToken) + ]); + + $url = BASE_URL . "/siroWallet/add.php"; + + $postData = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'passengerId' => $passengerId, + 'token' => $siroToken, // Use the new Siro-specific token + 'driverId' => 'passenger' + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("6.1", "cURL error in Siro wallet update", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("6.2", "HTTP error in Siro wallet update", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data) { + logError("6.3", "Invalid response format in Siro wallet update", [ + "response" => $response + ]); + return null; + } + + return $data; // ✅ Return result +} + + +// 🎯 Function to calculate bonus +function calculateBonus($amount) { + logError("3.1", "Bonus calculation input", ["amount" => $amount]); + + $result = 0; + if ($amount == 100) $result = 100; + else if ($amount == 200) $result = 215; + else if ($amount == 400) $result = 450; + else if ($amount == 1000) $result = 1140; + + logError("3.2", "Bonus calculation result", [ + "input" => $amount, + "output" => $result + ]); + + return $result; +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php.zip b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php.zip new file mode 100644 index 0000000000000000000000000000000000000000..b3aa417ad28c20ddab4d06cf00a91e9751695676 GIT binary patch literal 6293 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 X!y^42F@L`x{9cB?Z;_hlkH3EacS&^* literal 0 HcmV?d00001 diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithCard.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithCard.php new file mode 100755 index 0000000..85f189a --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithCard.php @@ -0,0 +1,100 @@ + + $api_key]); + +$response = callAPI("POST", $auth_url, $auth_data); +// printResponse("AUTH TOKEN RESPONSE", $response); + +$auth_token = $response->token ?? null; +if (!$auth_token) { + die("❌ فشل الحصول على AUTH TOKEN!"); +} + $amount=$amount*100; +// 2. أنشئ الطلب ORDER +$order_url = "https://accept.paymob.com/api/ecommerce/orders"; +$order_data = [ + "auth_token" => $auth_token, + "delivery_needed" => false, + "amount_cents" => $amount, + "currency" => "EGP", + "merchant_order_id" => uniqid(), + "items" => [] +]; + +$response = callAPI("POST", $order_url, json_encode($order_data)); +// printResponse("ORDER RESPONSE", $response); + +$order_id = $response->id ?? null; +if (!$order_id) { + die("❌ فشل إنشاء الطلب!"); +} +$integration_id=getenv("paymobIntegratedIdCardDriver"); +// 3. احصل على Payment Key +$payment_key_url = "https://accept.paymob.com/api/acceptance/payment_keys"; +$payment_key_data = [ + "auth_token" => $auth_token, + "amount_cents" => $amount, + "expiration" => 3600, + "order_id" => $order_id, + "billing_data" => [ + "first_name" =>$first_name, + "last_name" => $last_name, + "email" => $email, + "phone_number" => $phone_number, + "country" => "EG", + "city" => "Cairo", + "state" => "shobra", + "street" => "Test St.", + "building" => "1", + "apartment" => "10", + "floor" => "2", + "postal_code" => "12345", + "shipping_method"=> 'card' + ], + "currency" => "EGP", + "integration_id" => $integration_id, // ضع الـ Integration ID الصحيح +]; + +$response = callAPI("POST", $payment_key_url, json_encode($payment_key_data)); +// printResponse("PAYMENT TOKEN RESPONSE", $response); + +$payment_token = $response->token ?? null; +if (!$payment_token) { + die("❌ فشل الحصول على PAYMENT TOKEN!"); +} + +// 4. إنشاء IFRAME URL +$iframe_id = "837992"; // ضع الـ Iframe ID الصحيح +$iframe_url = "https://accept.paymob.com/api/acceptance/iframes/$iframe_id?payment_token=$payment_token"; +if($payment_token){ + + printSuccess($iframe_url); +} +// دالة لطلب API عبر CURL +function callAPI($method, $url, $data) +{ + $curl = curl_init(); + + curl_setopt_array($curl, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $data, + CURLOPT_HTTPHEADER => ["Content-Type: application/json"] + ]); + + $response = curl_exec($curl); + curl_close($curl); + + return json_decode($response); +} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithWallet.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithWallet.php new file mode 100755 index 0000000..05c1c92 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithWallet.php @@ -0,0 +1,118 @@ + $api_key]); + +$response = callAPI("POST", $auth_url, $auth_data); +$auth_token = $response->token ?? null; + +if (!$auth_token) { + error_log("❌ AUTH TOKEN retrieval failed!"); + die("❌ AUTH TOKEN retrieval failed!"); +} +$amount=$amount*100; +// 2️⃣ ORDER CREATE +$order_url = "https://accept.paymob.com/api/ecommerce/orders"; +$order_data = [ + "auth_token" => $auth_token, + "delivery_needed" => false, + "amount_cents" => $amount, + "currency" => "EGP", + "merchant_order_id" => uniqid("DRV_"), + "items" => [] +]; + +$response = callAPI("POST", $order_url, json_encode($order_data)); +$order_id = $response->id ?? null; + +if (!$order_id) { + error_log("❌ Failed to create order for driver wallet!"); + die("❌ Failed to create order for driver wallet!"); +} + +// 3️⃣ PAYMENT KEY +$payment_key_url = "https://accept.paymob.com/api/acceptance/payment_keys"; +$payment_key_data = [ + "auth_token" => $auth_token, + "amount_cents" => $amount, + "expiration" => 3600, + "order_id" => $order_id, + "billing_data" => [ + "first_name" => $first_name, + "last_name" => $last_name, + "email" => $email, + "phone_number" => $phone_number, + "country" => "EG", + "city" => "Cairo", + "state" => "Nasr City", + "street" => "Driver Zone", + "building" => "5", + "apartment" => "D1", + "floor" => "1", + "postal_code" => "11765", + "shipping_method" => "driver_wallet" + ], + "currency" => "EGP", + "integration_id" => $integration_id +]; + +$response = callAPI("POST", $payment_key_url, json_encode($payment_key_data)); +$payment_token = $response->token ?? null; + +if (!$payment_token) { + error_log("❌ Failed to get PAYMENT TOKEN for driver!"); + die("❌ Failed to get PAYMENT TOKEN for driver!"); +} + +// 4️⃣ Final Step: Pay with Wallet +$redirect_url = payWithWallet($payment_token, $wallet_phone); +if ($redirect_url) { + printSuccess($redirect_url); + error_log("✅ redirect_url (driver): " . $redirect_url); +} else { + error_log("❌ Driver wallet payment failed!"); + printFailure("Payment verified, but failed to redirect."); +} + + +// 🔁 Shared helper functions +function callAPI($method, $url, $data) +{ + $curl = curl_init(); + curl_setopt_array($curl, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $data, + CURLOPT_HTTPHEADER => ["Content-Type: application/json"] + ]); + $response = curl_exec($curl); + curl_close($curl); + return json_decode($response); +} + +function payWithWallet($paymentToken, $walletPhone) +{ + $url = "https://accept.paymob.com/api/acceptance/payments/pay"; + $data = [ + "source" => [ + "identifier" => $walletPhone, + "subtype" => "WALLET" + ], + "payment_token" => $paymentToken + ]; + $response = callAPI("POST", $url, json_encode($data)); + return $response->redirect_url ?? null; +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymet_verfy.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymet_verfy.php new file mode 100755 index 0000000..e2f6a5d --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymet_verfy.php @@ -0,0 +1,146 @@ +prepare( + 'SELECT * FROM payment_log_driver + WHERE user_id = :uid + AND created_at >= DATE_SUB(NOW(), INTERVAL 2 MINUTE) + ORDER BY created_at DESC LIMIT 1' + ); + $stmt->execute([':uid' => $user_id]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment || $payment['status'] != 1) { + printFailure('No valid payment found.'); + exit; + } + + $originalAmount = floatval($payment['amount']); + $bonus = match ((int)$originalAmount) { + 80 => 80.0, + 200 => 215.0, + 400 => 450.0, + 1000 => 1140.0, + default => $originalAmount, + }; + + // 2️⃣ توكن لـ DriverWallet + $tokenDriver = generateToken($con, $driverId, $bonus); + if (!$tokenDriver) { + printFailure('Failed to generate token for driver wallet.'); + exit; + } + + // 3️⃣ توكن مستقل لـ SiroWallet + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) { + printFailure('Failed to generate token for siro wallet.'); + exit; + } + + // 4️⃣ Payment ID + $paymentID = generatePaymentID($con, $driverId, $bonus, $paymentMethod); + if (!$paymentID) { + printFailure('Failed to generate payment ID.'); + exit; + } + + // 5️⃣ Insert into driverWallet + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, + ':paymentID' => $paymentID, + ':amount' => $bonus, + ':paymentMethod' => $paymentMethod + ]); + + if ($insertDriver->rowCount() === 0) { + printFailure('Failed to insert into driverWallet.'); + exit; + } + + // 6️⃣ Update tokenDriver to isUsed = TRUE + $markTokenDriver = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token"); + $markTokenDriver->execute([':token' => $tokenDriver]); + + // 7️⃣ Insert into siroWallet + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) + VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token, CURRENT_TIMESTAMP)"); + $insertSiro->execute([ + ':driverId' => $driverId, + ':passengerId' => 'driver', + ':amount' => $originalAmount, + ':paymentMethod' => $paymentMethod, + ':token' => $tokenSiro + ]); + + // 8️⃣ Update tokenSiro to isUsed = TRUE + $markTokenSiro = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token"); + $markTokenSiro->execute([':token' => $tokenSiro]); + + // 🎉 Success response + printSuccess([ + 'message' => 'Payment verified and all wallets updated successfully.', + 'amount' => $originalAmount, + 'bonus' => $bonus, + 'paymentID' => $paymentID, + 'tokenUsed' => [ + 'driverWalletToken' => $tokenDriver, + 'siroWalletToken' => $tokenSiro + ] + ]); + +} catch (Throwable $e) { + printFailure("Server error: " . $e->getMessage()); +} + + +// ─────────────────────────── +// FUNCTIONS +// ─────────────────────────── + +function generateToken($con, $driverId, $amount): ?string { + global $secretKey; + + // نفس المنطق من سكربتك + $data = $driverId . $amount . time(); + $data .= $secretKey; + $hash = hash('sha256', $data); + $randomBytes = bin2hex(random_bytes(16)); + $token = substr($hash . $randomBytes, 0, 64); + // تخزين التوكن في قاعدة البيانات + $stmt = $con->prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) + VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([ + ':token' => $token, + ':driverID' => $driverId, + ':amount' => $amount + ]); + + return $stmt->rowCount() > 0 ? $token : null; +} + +function generatePaymentID($con, $driverId, $amount, $method): ?string { + + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) + VALUES (:amount, :method, :driverID)"); + $stmt->execute([ + ':driverID' => $driverId, + ':amount' => $amount, + ':method' => $method + ]); + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; +} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_payout.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_payout.php new file mode 100755 index 0000000..2b82766 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_payout.php @@ -0,0 +1,110 @@ + true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'], + CURLOPT_POSTFIELDS => http_build_query([ + 'grant_type' => 'password', + 'username' => $user, + 'password' => $pass, + 'client_id' => $cid, + 'client_secret' => $secret, + ]), + ]); + $resp = curl_exec($ch); + if (!$resp) return null; + $data = json_decode($resp, true); + return $data['access_token'] ?? null; +} + +$oauthToken = fetchPaymobToken($pmUser, $pmPass, $pmClientId, $pmSecret); +if (!$oauthToken) { + printFailure('Failed to retrieve Paymob token'); + exit; +} + +// 4) دوال صرف الأموال +function disburseWallet(string $token, string $amt, string $msisdn): array { + $ch = curl_init('https://payouts.paymobsolutions.com/api/secure/disburse/'); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Authorization: Bearer $token", + 'Content-Type: application/json', + ], + CURLOPT_POSTFIELDS => json_encode([ + 'amount' => $amt, + 'issuer' => 'wallet', + 'msisdn' => $msisdn, + ]), + ]); + $resp = curl_exec($ch); + return $resp ? json_decode($resp, true) : []; +} + +function disburseBank(string $token, string $amt, string $card, string $code): array { + $ch = curl_init('https://payouts.paymobsolutions.com/api/secure/disburse/'); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Authorization: Bearer $token", + 'Content-Type: application/json', + ], + CURLOPT_POSTFIELDS => json_encode([ + 'amount' => $amt, + 'issuer' => 'bank_card', + 'bank_card_number' => $card, + 'bank_code' => $code, + 'bank_transaction_type' => 'cash_transfer', + ]), + ]); + $resp = curl_exec($ch); + return $resp ? json_decode($resp, true) : []; +} + +// 5) استدعاء الدالة المناسبة وتنفيذ الصرف +if ($method === 'wallet') { + $result = disburseWallet($oauthToken, $amount, $msisdn); +} else { + $result = disburseBank($oauthToken, $amount, $bankCard, $bankCode); +} + +// 6) التحقق من نجاح الصرف وإرجاع النتيجة +if (empty($result) || ($result['disbursement_status'] ?? '') !== 'successful') { + printFailure('Disbursement failed'); + exit; +} + +// 7) إرجاع التوكن والنتيجة للعميل بدون تخزين في DB +printSuccess( $result); +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webHookWallet.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webHookWallet.php new file mode 100755 index 0000000..583c752 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webHookWallet.php @@ -0,0 +1,142 @@ + "Unauthorized – Invalid HMAC"]); + exit; + } +} +isValidHmac($data, $secret_key, $received_hmac); +// ------------------------------ +// إذا كانت HMAC صحيحة، نتابع العملية +// ------------------------------ +if ($data && isset($data['obj'])) { + $transaction = $data['obj']; + + $payment_id = $transaction['id'] ?? null; + $amount = $transaction['amount_cents'] ?? 0; + $status = $transaction['success'] ?? false; + $is_voided = $transaction['is_voided'] ?? false; + $is_refunded = $transaction['is_refunded'] ?? false; + $order_id = $transaction['order']['id'] ?? null; + $merchant_order_id = $transaction['order']['merchant_order_id'] ?? null; + $payment_method = $transaction['source_data']['type'] ?? 'unknown'; + $card_last4 = $transaction['source_data']['pan'] ?? '****'; + $transaction_type = $transaction['data']['migs_transaction']['type'] ?? 'UNKNOWN'; + $created_at = $transaction['created_at'] ?? date("Y-m-d H:i:s"); + $user_id = $transaction['order']['shipping_data']['phone_number']; + + $user_id='+2'. $user_id; + $amount=$amount/100; + + // التحقق من حالة الدفع + if (!$status) { + error_log("❌ Invalid payment status: " . $status); + echo json_encode(["error" => "Invalid payment status"]); + exit; + } + + // إضافة البيانات إلى قاعدة البيانات + $query = "INSERT INTO payment_log_driver (`payment_id`, `user_id`, `amount`, `status`) + VALUES (:payment_id, :user_id, :amount, :status)"; + + $stmt = $con->prepare($query); + $stmt->bindParam(':payment_id', $payment_id); + $stmt->bindParam(':user_id', $user_id); + $stmt->bindParam(':amount', $amount); + $stmt->bindParam(':status', $status); + + try { + $stmt->execute(); + if ($stmt->rowCount() > 0) { + http_response_code(200); + echo json_encode(["success" => true, "message" => "Payment data saved successfully"]); + error_log("Payment data saved successfully" . $status); + } else { + http_response_code(200); + echo json_encode(["success" => false, "message" => "Payment data already up to date."]); + } + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(["error" => "Failed to execute the query: " . $e->getMessage()]); + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webhook.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webhook.php new file mode 100755 index 0000000..acc6d10 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webhook.php @@ -0,0 +1,142 @@ + "Unauthorized – Invalid HMAC"]); + exit; + } +} +isValidHmac($data, $secret_key, $received_hmac); +// ------------------------------ +// إذا كانت HMAC صحيحة، نتابع العملية +// ------------------------------ +if ($data && isset($data['obj'])) { + $transaction = $data['obj']; + + $payment_id = $transaction['id'] ?? null; + $amount = $transaction['amount_cents'] ?? 0; + $status = $transaction['success'] ?? false; + $is_voided = $transaction['is_voided'] ?? false; + $is_refunded = $transaction['is_refunded'] ?? false; + $order_id = $transaction['order']['id'] ?? null; + $merchant_order_id = $transaction['order']['merchant_order_id'] ?? null; + $payment_method = $transaction['source_data']['type'] ?? 'unknown'; + $card_last4 = $transaction['source_data']['pan'] ?? '****'; + $transaction_type = $transaction['data']['migs_transaction']['type'] ?? 'UNKNOWN'; + $created_at = $transaction['created_at'] ?? date("Y-m-d H:i:s"); + $user_id = $transaction['order']['shipping_data']['phone_number']; + + $user_id='+'. $user_id; + $amount=$amount/100; + + // التحقق من حالة الدفع + if (!$status) { + error_log("❌ Invalid payment status: " . $status); + echo json_encode(["error" => "Invalid payment status"]); + exit; + } + + // إضافة البيانات إلى قاعدة البيانات + $query = "INSERT INTO payment_log_driver (`payment_id`, `user_id`, `amount`, `status`) + VALUES (:payment_id, :user_id, :amount, :status)"; + + $stmt = $con->prepare($query); + $stmt->bindParam(':payment_id', $payment_id); + $stmt->bindParam(':user_id', $user_id); + $stmt->bindParam(':amount', $amount); + $stmt->bindParam(':status', $status); + + try { + $stmt->execute(); + if ($stmt->rowCount() > 0) { + http_response_code(200); + echo json_encode(["success" => true, "message" => "Payment data saved successfully"]); + error_log("Payment data saved successfully" . $status); + } else { + http_response_code(200); + echo json_encode(["success" => false, "message" => "Payment data already up to date."]); + } + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(["error" => "Failed to execute the query: " . $e->getMessage()]); + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.log b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.log new file mode 100644 index 0000000..e3a76cb --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.log @@ -0,0 +1,33 @@ +Transaction ID: 275749381 +Amount (EGP): 25 +Order ID: 308769116 +Merchant Order ID: 67db4baf5ad92 +Payment Method: card (Last 4: 2346) +Transaction Type: PAYMENT +Success: Yes +Voided: No +Refunded: No +Created At: 2025-03-20T00:57:04.742244 +---------------------------- +Transaction ID: 275751796 +Amount (EGP): 25 +Order ID: 308771809 +Merchant Order ID: 67db4dc9f0427 +Payment Method: card (Last 4: 2346) +Transaction Type: PAYMENT +Success: Yes +Voided: No +Refunded: No +Created At: 2025-03-20T01:06:02.249734 +---------------------------- +Transaction ID: 275752145 +Amount (EGP): 25 +Order ID: 308772211 +Merchant Order ID: 67db4e263aafe +Payment Method: card (Last 4: 2346) +Transaction Type: PAYMENT +Success: Yes +Voided: No +Refunded: No +Created At: 2025-03-20T01:07:31.653223 +---------------------------- diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.php new file mode 100644 index 0000000..e2e3537 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.php @@ -0,0 +1,137 @@ + "Unauthorized – Invalid HMAC"]); + exit; + } +} +isValidHmac($data, $secret_key, $received_hmac); +// ------------------------------ +// إذا كانت HMAC صحيحة، نتابع العملية +// ------------------------------ +if ($data && isset($data['obj'])) { + $transaction = $data['obj']; + + $payment_id = $transaction['id'] ?? null; + $amount = $transaction['amount_cents'] ?? 0; + $status = $transaction['success'] ?? false; + $is_voided = $transaction['is_voided'] ?? false; + $is_refunded = $transaction['is_refunded'] ?? false; + $order_id = $transaction['order']['id'] ?? null; + $merchant_order_id = $transaction['order']['merchant_order_id'] ?? null; + $payment_method = $transaction['source_data']['type'] ?? 'unknown'; + $card_last4 = $transaction['source_data']['pan'] ?? '****'; + $transaction_type = $transaction['data']['migs_transaction']['type'] ?? 'UNKNOWN'; + $created_at = $transaction['created_at'] ?? date("Y-m-d H:i:s"); + $user_id = $transaction['order']['shipping_data']['phone_number']; + + // التحقق من حالة الدفع + if (!$status) { + error_log("❌ Invalid payment status: " . $status); + echo json_encode(["error" => "Invalid payment status"]); + exit; + } + + // إضافة البيانات إلى قاعدة البيانات + $query = "INSERT INTO paymentsLog (`payment_id`, `user_id`, `amount`, `status`) + VALUES (:payment_id, :user_id, :amount, :status)"; + + $stmt = $con->prepare($query); + $stmt->bindParam(':payment_id', $payment_id); + $stmt->bindParam(':user_id', $user_id); + $stmt->bindParam(':amount', $amount); + $stmt->bindParam(':status', $status); + + try { + $stmt->execute(); + if ($stmt->rowCount() > 0) { + http_response_code(200); + echo json_encode(["success" => true, "message" => "Payment data saved successfully"]); + } else { + http_response_code(200); + echo json_encode(["success" => false, "message" => "Payment data already up to date."]); + } + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(["error" => "Failed to execute the query: " . $e->getMessage()]); + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/error_log b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/error_log new file mode 100644 index 0000000..8dd44f5 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/error_log @@ -0,0 +1,27 @@ +[21-Mar-2025 19:37:11 Europe/Berlin] PHP Notice: Array to string conversion in /home2/seferli1/wallet.sefer.live/seferpw.shop/sefer/ride/payMob/wallet/paymob_webhook.php on line 15 +[21-Mar-2025 19:37:11 Europe/Berlin] Data: Array +[21-Mar-2025 19:37:11 Europe/Berlin] ✅ Valid HMAC signature verified. +[21-Mar-2025 19:37:11 Europe/Berlin] ❌ Invalid payment status: +[21-Mar-2025 19:37:11 Europe/Berlin] ❌ فشل الدفع عبر المحفظة! +[21-Mar-2025 19:37:11 Europe/Berlin] +[21-Mar-2025 19:38:41 Europe/Berlin] PHP Notice: Array to string conversion in /home2/seferli1/wallet.sefer.live/seferpw.shop/sefer/ride/payMob/wallet/paymob_webhook.php on line 15 +[21-Mar-2025 19:38:41 Europe/Berlin] Data: Array +[21-Mar-2025 19:38:41 Europe/Berlin] ✅ Valid HMAC signature verified. +[21-Mar-2025 19:38:41 Europe/Berlin] ❌ Invalid payment status: +[21-Mar-2025 19:38:41 Europe/Berlin] ❌ فشل الدفع عبر المحفظة! +[21-Mar-2025 19:38:41 Europe/Berlin] +[21-Mar-2025 19:39:40 Europe/Berlin] PHP Notice: Array to string conversion in /home2/seferli1/wallet.sefer.live/seferpw.shop/sefer/ride/payMob/wallet/paymob_webhook.php on line 15 +[21-Mar-2025 19:39:40 Europe/Berlin] Data: Array +[21-Mar-2025 19:39:40 Europe/Berlin] ✅ Valid HMAC signature verified. +[21-Mar-2025 19:39:40 Europe/Berlin] ❌ Invalid payment status: +[21-Mar-2025 19:39:40 Europe/Berlin] ❌ فشل الدفع عبر المحفظة! +[21-Mar-2025 19:41:14 Europe/Berlin] ✅ Valid HMAC signature verified. +[21-Mar-2025 19:41:14 Europe/Berlin] ❌ Invalid payment status: +[21-Mar-2025 19:41:14 Europe/Berlin] ❌ فشل الدفع عبر المحفظة! +[21-Mar-2025 19:41:58 Europe/Berlin] ✅ Valid HMAC signature verified. +[21-Mar-2025 19:41:58 Europe/Berlin] ❌ Invalid payment status: +[21-Mar-2025 19:41:59 Europe/Berlin] ❌ فشل الدفع عبر المحفظة! +[21-Mar-2025 19:43:19 Europe/Berlin] redirect_url ishttps://vcheckout.paymobsolutions.com/checkout/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NDI1ODI4OTksImlkIjo2MTk5MDYyNzI0fQ.KH7jKKINyVzxJMH9IT2MyiAXRK_yMHVw-f4pIzyHzj0 +[22-Mar-2025 15:38:59 Europe/Berlin] ✅ Valid HMAC signature verified. +[22-Mar-2025 15:38:59 Europe/Berlin] ❌ Invalid payment status: +[22-Mar-2025 15:39:00 Europe/Berlin] ❌ فشل الدفع عبر المحفظة! diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/payWithPayMob.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/payWithPayMob.php new file mode 100644 index 0000000..62a50f7 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/payWithPayMob.php @@ -0,0 +1,129 @@ + $api_key]); + +$response = callAPI("POST", $auth_url, $auth_data); +$auth_token = $response->token ?? null; +if (!$auth_token) { + error_log("❌ فشل الحصول على AUTH TOKEN!"); + die("❌ فشل الحصول على AUTH TOKEN!"); +} + +// 2. أنشئ الطلب ORDER +$order_url = "https://accept.paymob.com/api/ecommerce/orders"; +$order_data = [ + "auth_token" => $auth_token, + "delivery_needed" => false, + "amount_cents" => $amount, + "currency" => "EGP", + "merchant_order_id" => uniqid(), + "items" => [] +]; + +$response = callAPI("POST", $order_url, json_encode($order_data)); +$order_id = $response->id ?? null; +if (!$order_id) { + error_log("❌ فشل إنشاء الطلب!"); + die("❌ فشل إنشاء الطلب!"); +} +// error_log("orde is" .$order_id); +// 3. احصل على Payment Key + +$payment_key_url = "https://accept.paymob.com/api/acceptance/payment_keys"; +$payment_key_data = [ + "auth_token" => $auth_token, + "amount_cents" => $amount, + "expiration" => 3600, + "order_id" => $order_id, + "billing_data" => [ + "first_name" => $first_name, + "last_name" => $last_name, + "email" => $email, + "phone_number" => $phone_number, + "country" => "EG", + "city" => "Cairo", + "state" => "shobra", + "street" => "Test St.", + "building" => "1", + "apartment" => "10", + "floor" => "2", + "postal_code" => "12345", + "shipping_method" => "wallet" + ], + "currency" => "EGP", + "integration_id" => $integration_id // إذا كان مضبوط +]; +$response = callAPI("POST", $payment_key_url, json_encode($payment_key_data)); +$payment_token = $response->token ?? null; +// error_log("payment_token is" .$payment_token); +if (!$payment_token) { + error_log("❌ فشل الحصول على PAYMENT TOKEN!"); + + die("❌ فشل الحصول على PAYMENT TOKEN!"); +} +// error_log("phone wallet is ".$wallet_phone); +// 4. الدفع عبر المحفظة Wallet +$redirect_url = payWithWallet($payment_token, $wallet_phone); +if ($redirect_url) { + printSuccess($redirect_url); + error_log("redirect_url is" .$redirect_url); +} else { + error_log("❌ فشل الدفع عبر المحفظة!"); + printFailure("Payment verified, but failed to generate token."); + // die("❌ فشل الدفع عبر المحفظة!"); +} + +// دالة لطلب API عبر CURL +function callAPI($method, $url, $data) +{ + $curl = curl_init(); + + curl_setopt_array($curl, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $data, + CURLOPT_HTTPHEADER => ["Content-Type: application/json"] + ]); + + $response = curl_exec($curl); + curl_close($curl); + + return json_decode($response); +} + +// الدالة الخاصة بالدفع بالمحفظة +function payWithWallet($paymentToken, $walletPhone) +{ + $url = "https://accept.paymob.com/api/acceptance/payments/pay"; + + $data = [ + "source" => [ + "identifier" => $walletPhone, + "subtype" => "WALLET" + ], + "payment_token" => $paymentToken + ]; + + // Log the full data being sent to Paymob + // error_log("Data being sent to Paymob: " . json_encode($data)); + + $response = callAPI("POST", $url, json_encode($data)); + + // Log the full response for debugging + // error_log("Payment response: " . print_r($response, true)); + + return $response->redirect_url ?? null; +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymet_verfy.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymet_verfy.php new file mode 100644 index 0000000..5becb72 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymet_verfy.php @@ -0,0 +1,358 @@ + $user_id, +// "passengerId" => $passengerId +// ]); + +// Validate user_id and passengerId +if (!$user_id || !$passengerId) { + // logError("1", "Invalid parameters", [ + // "user_id" => $user_id, + // "passengerId" => $passengerId + // ]); + printFailure("Invalid user ID or passenger ID."); + exit; +} + +try { + // Step 1: Get the latest successful payment + // logError("1", "Querying latest payment", ["user_id" => $user_id]); + + $stmt = $con->prepare("SELECT * FROM paymentsLog WHERE user_id = :user_id AND created_at >= DATE_SUB(NOW(), INTERVAL 2 MINUTE) +ORDER BY created_at DESC +LIMIT 1"); + $stmt->bindParam(':user_id', $user_id, PDO::PARAM_STR); + $stmt->execute(); + + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + logError("1", "No payment found", ["user_id" => $user_id]); + printFailure("No payment data found."); + exit; + } + + // logError("1", "Payment found", [ + // "payment_id" => $payment['id'] ?? 'unknown', + // "status" => $payment['status'], + // "amount" => $payment['amount']/100 ?? 'unknown' + // ]); + + // Step 2: Check payment status + if ($payment['status'] != 1) { + // logError("2", "Payment not successful", ["status" => $payment['status']]); + printFailure("Payment is not successful yet."); + exit; + } + + // logError("2", "Payment status verified", ["status" => $payment['status']]); + + $amount = $payment['amount']/100; // Paid amount + + // Step 3: Calculate bonus based on the paid amount + // logError("3", "Calculating bonus", ["amount" => $amount]); + $finalAmount = calculateBonus($amount); + + if ($finalAmount <= 0) { + // logError("3", "Bonus calculation failed", [ + // "original_amount" => $amount, + // "calculated_amount" => $finalAmount + // ]); + printFailure("Invalid amount for bonus calculation."); + exit; + } + + // logError("3", "Bonus calculated", [ + // "original_amount" => $amount, + // "final_amount" => $finalAmount + // ]); + + // // Step 4: Generate payment token + // logError("4", "Generating payment token", [ + // "passengerId" => $passengerId, + // "amount" => $finalAmount + // ]); + + $token = generatePaymentToken($passengerId, $finalAmount); + + if (!$token) { + // logError("4", "Token generation failed"); + printFailure("Payment verified, but failed to generate token."); + exit; + } + + // logError("4", "Token generated successfully", ["token_length" => strlen($token)]); + + // // Step 5: Add balance to passenger's wallet + // logError("5", "Adding balance to passenger wallet", [ + // "passengerId" => $passengerId, + // "amount" => $finalAmount + // ]); + + $walletResult = addToPassengerWallet($passengerId, $finalAmount, $token); + + if (!$walletResult || !isset($walletResult['status']) || $walletResult['status'] != "success") { + // logError("5", "Failed to add balance to passenger wallet", $walletResult); + printFailure("Payment verified, but failed to add balance to passenger wallet."); + exit; + } + + // logError("5", "Balance added to passenger wallet", $walletResult); + + // Step 6: Add balance to Siro wallet + // logError("6", "Adding balance to Siro wallet", [ + // "passengerId" => $passengerId, + // "amount" => $finalAmount, + // "paymentMethod" => $paymentMethod + // ]); + + $token = generatePaymentToken($passengerId, $finalAmount); + + if (!$token) { + // logError("4", "Token generation failed"); + printFailure("Payment verified, but failed to generate token."); + exit; + } + + // logError("4", "Token generated successfully", ["token_length" => strlen($token)]); + + $siroWalletResult = addToSiroWallet($passengerId, $amount, $paymentMethod); + + if (!$siroWalletResult || !isset($siroWalletResult['status']) || $siroWalletResult['status'] != "success") { + // logError("6", "Failed to add balance to Siro wallet", $siroWalletResult); + printFailure("Payment verified, but failed to add balance to Siro wallet."); + exit; + } + + // logError("6", "Balance added to Siro wallet", $siroWalletResult); + + // // Final success + // logError("7", "Process completed successfully", [ + // "payment_id" => $payment['id'] ?? 'unknown', + // "amount" => $finalAmount, + // "passengerId" => $passengerId + // ]); + + printSuccess( "Payment data saved successfully"); + +} catch (PDOException $e) { + logError("ERROR", "Database error: " . $e->getMessage()); + printFailure("Database error occurred."); +} catch (Exception $e) { + logError("ERROR", "General error: " . $e->getMessage()); + printFailure("An error occurred during payment verification."); +} + +// 🎯 Function to generate payment token with error logging +function generatePaymentToken($passengerId, $amount) { + $url = BASE_URL . "/passengerWallet/addPaymentTokenPassenger.php"; + + $postData = [ + 'passengerId' => $passengerId, + 'amount' => $amount + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("4.1", "cURL error in token generation", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("4.2", "HTTP error in token generation", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data || !isset($data['message'])) { + logError("4.3", "Invalid response format in token generation", [ + "response" => $response + ]); + return null; + } + + return $data['message']; // ✅ Return token +} + +// 🎯 Function to add balance to passenger's wallet with error logging +function addToPassengerWallet($passengerId, $amount, $token) { + $url = BASE_URL . "/passengerWallet/add.php"; + + $postData = [ + 'passenger_id' => $passengerId, + 'balance' => $amount, + 'token' => $token + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("5.1", "cURL error in passenger wallet update", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("5.2", "HTTP error in passenger wallet update", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data) { + logError("5.3", "Invalid response format in passenger wallet update", [ + "response" => $response + ]); + return null; + } + + return $data; // ✅ Return result +} + +// 🎯 Function to add balance to Siro wallet with error logging + + +function addToSiroWallet($passengerId, $amount, $paymentMethod) { + + + // Generate a new token specifically for the Siro wallet + $siroToken = generatePaymentToken($passengerId, $amount); + + if (!$siroToken) { + logError("6.0.1", "Failed to generate Siro token"); + return null; + } + + logError("6.0.2", "Generated new Siro token", [ + "token_length" => ($siroToken) + ]); + + $url = BASE_URL . "/siroWallet/add.php"; + + $postData = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'passengerId' => $passengerId, + 'token' => $siroToken, // Use the new Siro-specific token + 'driverId' => 'passenger' + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + logError("6.1", "cURL error in Siro wallet update", [ + "error" => $curlError, + "url" => $url + ]); + return null; + } + + if ($httpCode != 200) { + logError("6.2", "HTTP error in Siro wallet update", [ + "http_code" => $httpCode, + "response" => $response + ]); + return null; + } + + $data = json_decode($response, true); + + if (!$data) { + logError("6.3", "Invalid response format in Siro wallet update", [ + "response" => $response + ]); + return null; + } + + return $data; // ✅ Return result +} + + +// 🎯 Function to calculate bonus +function calculateBonus($amount) { + logError("3.1", "Bonus calculation input", ["amount" => $amount]); + + $result = 0; + if ($amount == 100) $result = 100; + else if ($amount == 200) $result = 215; + else if ($amount == 400) $result = 450; + else if ($amount == 1000) $result = 1140; + + logError("3.2", "Bonus calculation result", [ + "input" => $amount, + "output" => $result + ]); + + return $result; +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymob_webhook.php b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymob_webhook.php new file mode 100644 index 0000000..ce0ce01 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/wallet/paymob_webhook.php @@ -0,0 +1,137 @@ + "Unauthorized – Invalid HMAC"]); + exit; + } +} +isValidHmac($data, $secret_key, $received_hmac); +// ------------------------------ +// إذا كانت HMAC صحيحة، نتابع العملية +// ------------------------------ +if ($data && isset($data['obj'])) { + $transaction = $data['obj']; + + $payment_id = $transaction['id'] ?? null; + $amount = $transaction['amount_cents'] ?? 0; + $status = $transaction['success'] ?? false; + $is_voided = $transaction['is_voided'] ?? false; + $is_refunded = $transaction['is_refunded'] ?? false; + $order_id = $transaction['order']['id'] ?? null; + $merchant_order_id = $transaction['order']['merchant_order_id'] ?? null; + $payment_method = $transaction['source_data']['type'] ?? 'unknown'; + $card_last4 = $transaction['source_data']['pan'] ?? '****'; + $transaction_type = $transaction['data']['migs_transaction']['type'] ?? 'UNKNOWN'; + $created_at = $transaction['created_at'] ?? date("Y-m-d H:i:s"); + $user_id = $transaction['order']['shipping_data']['phone_number']; + + // التحقق من حالة الدفع + if (!$status) { + error_log("❌ Invalid payment status: " . $status); + echo json_encode(["error" => "Invalid payment status"]); + exit; + } + + // إضافة البيانات إلى قاعدة البيانات + $query = "INSERT INTO paymentsLog (`payment_id`, `user_id`, `amount`, `status`) + VALUES (:payment_id, :user_id, :amount, :status)"; + + $stmt = $con->prepare($query); + $stmt->bindParam(':payment_id', $payment_id); + $stmt->bindParam(':user_id', $user_id); + $stmt->bindParam(':amount', $amount); + $stmt->bindParam(':status', $status); + + try { + $stmt->execute(); + if ($stmt->rowCount() > 0) { + http_response_code(200); + echo json_encode(["success" => true, "message" => "Payment data saved successfully"]); + } else { + http_response_code(200); + echo json_encode(["success" => false, "message" => "Payment data already up to date."]); + } + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(["error" => "Failed to execute the query: " . $e->getMessage()]); + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/check_status.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/check_status.php new file mode 100755 index 0000000..070354a --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/check_status.php @@ -0,0 +1,22 @@ +prepare("SELECT status FROM invoices_shamcash WHERE invoice_number = :inv LIMIT 1"); + $stmt->execute(['inv' => $invoice_number]); + $res = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($res) { + echo json_encode(["status" => "success", "invoice_status" => $res['status']]); + } else { + printFailure("Invoice not found"); + } +} catch (PDOException $e) { + printFailure("Error: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/create_invoice_shamcash.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/create_invoice_shamcash.php new file mode 100755 index 0000000..517ee63 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/create_invoice_shamcash.php @@ -0,0 +1,45 @@ +prepare("SELECT id, invoice_number FROM invoices_shamcash WHERE driverID = ? AND amount = ? AND status = 'pending' LIMIT 1"); + $stmt->execute([$driverID, $amount]); + $existing = $stmt->fetch(PDO::FETCH_ASSOC); + + $invoice_number = 0; + + if ($existing) { + // استخدام الفاتورة الموجودة وتحديث وقتها + $invoice_number = $existing['invoice_number']; + $con->prepare("UPDATE invoices_shamcash SET created_at=NOW() WHERE id=?")->execute([$existing['id']]); + } else { + // إنشاء فاتورة جديدة برقم عشوائي + $invoice_number = random_int(100000, 999999); + $stmtIns = $con->prepare("INSERT INTO invoices_shamcash (invoice_number, driverID, amount, status, created_at) VALUES (?, ?, ?, 'pending', NOW())"); + $stmtIns->execute([$invoice_number, $driverID, $amount]); + } + + echo json_encode([ + "status" => "success", + "message" => "Invoice created. Please use invoice_number in ShamCash Notes.", + "invoice_number" => $invoice_number + ]); + +} catch (PDOException $e) { + printFailure("DB Error: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/deposit_errors.log b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/deposit_errors.log new file mode 100644 index 0000000..07d1f21 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/deposit_errors.log @@ -0,0 +1,7 @@ +[2025-12-09 06:20:37] STEP SUCCESS: Transaction finalized for Invoice #18 +[2025-12-15 08:34:59] STEP SUCCESS: Transaction finalized for Invoice #22 +[2025-12-15 15:30:46] STEP SUCCESS: Transaction finalized for Invoice #27 +[2025-12-15 15:42:50] STEP SUCCESS: Transaction finalized for Invoice #28 +[2025-12-17 15:38:39] STEP SUCCESS: Transaction finalized for Invoice #32 +[2025-12-21 20:55:04] STEP SUCCESS: Transaction finalized for Invoice #39 +[2026-01-08 15:49:00] STEP SUCCESS: Transaction finalized for Invoice #48 diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/finalize_deposit.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/finalize_deposit.php new file mode 100755 index 0000000..2b642b4 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/finalize_deposit.php @@ -0,0 +1,120 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + return $stmt->rowCount() > 0 ? $token : null; + } +} + +if (!function_exists('generatePaymentID')) { + function generatePaymentID($con, $driverId, $amount, $method) { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; + } +} + +if (!function_exists('finalizeShamCashDeposit')) { + function finalizeShamCashDeposit(PDO $con, $invoice_id) { + + // 1. جلب بيانات الفاتورة + $stmt = $con->prepare("SELECT * FROM invoices_shamcash WHERE id = :id AND status = 'processing' LIMIT 1"); + $stmt->execute([':id' => $invoice_id]); + $invoice = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$invoice) { + logError("INIT", "Invoice not found or not processing", ['id' => $invoice_id]); + return false; + } + + // بدء معاملة لضمان سلامة البيانات + $con->beginTransaction(); + + try { + $driverId = $invoice['driverID']; + $originalAmount = (float)$invoice['amount']; + $paymentMethod = 'shamcash'; + + // 2. حساب المكافأة (Bonus Calculation) - نفس المنطق المرسل + $bonusAmount = match ((int)$originalAmount) { + 100 => 100.0, + 200 => 210.0, + 400 => 450.0, + 1000 => 1100.0, + default => $originalAmount, + }; + + // 3. إنشاء التوكنات + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + if (!$tokenDriver) throw new Exception('Failed to generate driver token'); + + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) throw new Exception('Failed to generate siro token'); + + // 4. إنشاء Payment ID + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + if (!$paymentID) throw new Exception('Failed to generate payment ID'); + + // 5. الإيداع في محفظة السائق (driverWallet) - المبلغ مع البونص + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, + ':paymentID' => $paymentID, + ':amount' => $bonusAmount, + ':paymentMethod' => $paymentMethod + ]); + if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed'); + + // حرق توكن السائق + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]); + + // 6. الإيداع في محفظة الشركة (siroWallet) - المبلغ الأصلي + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token, CURRENT_TIMESTAMP)"); + $insertSiro->execute([ + ':driverId' => $driverId, + ':passengerId' => 'driver', + ':amount' => $originalAmount, + ':paymentMethod' => $paymentMethod, + ':token' => $tokenSiro + ]); + if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed'); + + // حرق توكن الشركة + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSiro]); + + // 7. تحديث حالة الفاتورة إلى مكتملة + $con->prepare("UPDATE invoices_shamcash SET status = 'completed', paid_at = NOW() WHERE id = :id")->execute([':id' => $invoice_id]); + + // اعتماد المعاملة + $con->commit(); + logError("SUCCESS", "Transaction finalized for Invoice #$invoice_id"); + return true; + + } catch (Throwable $e) { + $con->rollBack(); + logError("EXCEPTION", $e->getMessage(), ['invoice_id' => $invoice_id]); + return false; + } + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/last_id.txt b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/last_id.txt new file mode 100644 index 0000000..e0dfa7f --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/last_id.txt @@ -0,0 +1 @@ +120840498 \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/check_status.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/check_status.php new file mode 100755 index 0000000..3bc4aa5 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/check_status.php @@ -0,0 +1,22 @@ +prepare("SELECT status FROM invoices_shamcash_passenger WHERE invoice_number = :inv LIMIT 1"); + $stmt->execute(['inv' => $invoice_number]); + $res = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($res) { + echo json_encode(["status" => "success", "invoice_status" => $res['status']]); + } else { + printFailure("Invoice not found"); + } +} catch (PDOException $e) { + printFailure("Error: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/create_invoice.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/create_invoice.php new file mode 100755 index 0000000..e64f8f8 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/create_invoice.php @@ -0,0 +1,41 @@ +prepare("SELECT id, invoice_number FROM invoices_shamcash_passenger WHERE passengerID = ? AND amount = ? AND status = 'pending' LIMIT 1"); + $stmt->execute([$passengerID, $amount]); + $existing = $stmt->fetch(PDO::FETCH_ASSOC); + + $invoice_number = 0; + + if ($existing) { + $invoice_number = $existing['invoice_number']; + $con->prepare("UPDATE invoices_shamcash_passenger SET created_at=NOW() WHERE id=?")->execute([$existing['id']]); + } else { + $invoice_number = random_int(100000, 999999); + $stmtIns = $con->prepare("INSERT INTO invoices_shamcash_passenger (invoice_number, passengerID, amount, status, created_at) VALUES (?, ?, ?, 'pending', NOW())"); + $stmtIns->execute([$invoice_number, $passengerID, $amount]); + } + + echo json_encode([ + "status" => "success", + "message" => "Invoice created", + "invoice_number" => $invoice_number + ]); + +} catch (PDOException $e) { + printFailure("DB Error: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/finalize_deposit.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/finalize_deposit.php new file mode 100755 index 0000000..ed0a9a6 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/finalize_deposit.php @@ -0,0 +1,127 @@ + 530.0, + 1000 => 1000.0, + 2000 => 2180.0, + 5000 => 5700.0, + default => (float)$amount, + }; + } +} + +if (!function_exists('generatePassengerToken')) { + function generatePassengerToken(PDO $con, $passengerId, $amount) { + // إنشاء توكن فريد + $data = $passengerId . $amount . time() . 'shamcash_passenger_secret'; + $hash = hash('sha256', $data); + $token = substr($hash . bin2hex(random_bytes(16)), 0, 64); + + // حفظ التوكن (افترضنا وجود جدول payment_tokens_passenger أو استخدام الجدول العام) + // سأستخدم الجدول العام payment_tokens مع وضع passengerId مكان driverID مؤقتاً + // أو يفضل استخدام جدول خاص للركاب لتجنب الخلط + + // الخيار الأفضل: استخدام جدول `payment_tokens` ولكن تأكد من العمود (driverID) + // سأفترض أنك ستستخدم جدول `payment_tokens_passenger` الذي اقترحته في الـ SQL السابق + + $stmt = $con->prepare("INSERT INTO payment_tokens_passenger (token, passengerID, dateCreated, amount) VALUES (:token, :id, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':id' => $passengerId, ':amount' => $amount]); + + return $stmt->rowCount() > 0 ? $token : null; + } +} + +if (!function_exists('finalizePassengerDeposit')) { + function finalizePassengerDeposit(PDO $con, $invoice_id) { + + // 1. جلب الفاتورة (يجب أن تكون في حالة processing) + $stmt = $con->prepare("SELECT * FROM invoices_shamcash_passenger WHERE id = :id AND status = 'processing' LIMIT 1"); + $stmt->execute([':id' => $invoice_id]); + $invoice = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$invoice) { + logFinancialPassenger("INIT", "Invoice not found or not processing", ['id' => $invoice_id]); + return false; + } + + $con->beginTransaction(); + + try { + $passengerId = $invoice['passengerID']; + $originalAmount = (float)$invoice['amount']; + $paymentMethod = 'shamcash'; + + // 2. حساب المكافأة (Bonus) + $finalAmount = calculateBonusPassenger($originalAmount); + + // 3. إنشاء التوكنات + $tokenPassenger = generatePassengerToken($con, $passengerId, $finalAmount); + $tokenSiro = generatePassengerToken($con, $passengerId, $originalAmount); + + if (!$tokenPassenger || !$tokenSiro) throw new Exception('Token generation failed'); + + // 4. الإيداع في محفظة الراكب (passengerWallet) + // نضيف المبلغ النهائي (مع البونص) + $stmtPassenger = $con->prepare("INSERT INTO passengerWallet (passenger_id, balance, type, create_at) VALUES (:pid, :amt, 'deposit', NOW())"); + // ملاحظة: تأكد من أسماء الأعمدة في جدول passengerWallet لديك + // في كودك القديم كان يستخدم API: /passengerWallet/add.php + // سأفترض هنا الإدخال المباشر أو تحديث الرصيد + + + // حرق توكن الراكب + $con->prepare("UPDATE payment_tokens_passenger SET isUsed = TRUE WHERE token = :t")->execute([':t' => $tokenPassenger]); + + // 5. الإيداع في محفظة الشركة (siroWallet) + // نسجل المبلغ الأصلي (بدون البونص) كإيراد + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) VALUES ('passenger', :pid, :amt, :pm, :tok, NOW())"); + $insertSiro->execute([ + ':pid' => $passengerId, + ':amt' => $originalAmount, + ':pm' => $paymentMethod, + ':tok' => $tokenSiro + ]); + + if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed'); + + // حرق توكن الشركة + $con->prepare("UPDATE payment_tokens_passenger SET isUsed = TRUE WHERE token = :t")->execute([':t' => $tokenSiro]); + + // 6. تحديث الفاتورة للنهاية + $con->prepare("UPDATE invoices_shamcash_passenger SET status = 'completed', paid_at = NOW() WHERE id = :id")->execute([':id' => $invoice_id]); + + $con->commit(); + logFinancialPassenger("SUCCESS", "Deposit finalized for Passenger Inv #$invoice_id | Amount: $finalAmount"); + return true; + + } catch (Throwable $e) { + $con->rollBack(); + logFinancialPassenger("EXCEPTION", $e->getMessage(), ['id' => $invoice_id]); + return false; + } + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions.php new file mode 100755 index 0000000..259ecc3 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions.php @@ -0,0 +1,121 @@ + "error", "msg" => "DB Failed"])); } + +if (file_exists(__DIR__ . "/finalize_deposit.php")) include_once __DIR__ . "/finalize_deposit.php"; +if (file_exists(__DIR__ . "/passenger/finalize_deposit.php")) include_once __DIR__ . "/passenger/finalize_deposit.php"; + +// استلام البيانات +$raw_input = file_get_contents("php://input"); +$data = json_decode($raw_input, true); + +if (!$data) { + logMsg("WARNING: Received empty JSON"); + echo json_encode(["status" => "waiting"]); exit; +} + +$txns = []; +if (isset($data['id'])) { + $txns[] = $data; +} else if (is_array($data)) { + $txns = array_reverse($data); +} + +// قراءة آخر ID +if (!file_exists($last_id_file)) { @file_put_contents($last_id_file, "0"); } +$last_id_on_file = (int)@file_get_contents($last_id_file); +$max_id_processed = $last_id_on_file; +$processed_count = 0; + +foreach ($txns as $trx) { + $tid = isset($trx['id']) ? (int)preg_replace('/[^0-9]/', '', $trx['id']) : 0; + $amt = (float)($trx['amount'] ?? 0); + $note = $trx['note'] ?? ''; // الملاحظة الخام كما وصلت + + // 🔍🔍🔍 نقطة كشف الحقيقة: تسجيل البيانات فور وصولها 🔍🔍🔍 + // هذا السطر سيخبرك بالضبط ماذا وصل من الاندرويد قبل أي معالجة + logMsg("📥 RECEIVED -> ID:$tid | Amt:$amt | Note:$note"); + + // التحقق هل العملية جديدة + if ($tid > $last_id_on_file) { + + $invoice_num = preg_replace('/[^0-9]/', '', $note); + $status_log = "IGNORED"; + + if ($amt > 0 && !empty($invoice_num) && strlen($invoice_num) >= 4) { + + // 1. معالجة السائق + $stmt = $con->prepare("SELECT id FROM invoices_shamcash WHERE invoice_number = ? AND amount = ? AND status = 'pending' LIMIT 1"); + $stmt->execute([$invoice_num, $amt]); + $drvInv = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($drvInv) { + $iid = $drvInv['id']; + $con->prepare("UPDATE invoices_shamcash SET status='processing', transaction_id=? WHERE id=?")->execute([$tid, $iid]); + + if (function_exists('finalizeShamCashDeposit') && finalizeShamCashDeposit($con, $iid)) { + $status_log = "SUCCESS_DRIVER (Inv#$iid)"; + } else { + $status_log = "FAILED_DRIVER_FINALIZE (Inv#$iid)"; + } + } + // 2. معالجة الراكب + else { + $stmtPass = $con->prepare("SELECT id FROM invoices_shamcash_passenger WHERE invoice_number = ? AND amount = ? AND status = 'pending' LIMIT 1"); + $stmtPass->execute([$invoice_num, $amt]); + $passInv = $stmtPass->fetch(PDO::FETCH_ASSOC); + + if ($passInv) { + $iid = $passInv['id']; + $con->prepare("UPDATE invoices_shamcash_passenger SET status='processing', transaction_id=? WHERE id=?")->execute([$tid, $iid]); + if (function_exists('finalizePassengerDeposit') && finalizePassengerDeposit($con, $iid)) { + $status_log = "SUCCESS_PASSENGER (Inv#$iid)"; + } else { + $status_log = "FAILED_PASSENGER_FINALIZE (Inv#$iid)"; + } + } else { + $status_log = "NO_MATCH (Inv:$invoice_num)"; + } + } + } else { + if (empty($invoice_num)) $status_log = "IGNORED_NO_INVOICE"; + } + + // تسجيل نتيجة المعالجة + logMsg("⚙️ PROCESSED -> ID:$tid | Status:$status_log"); + + if ($tid > $max_id_processed) $max_id_processed = $tid; + $processed_count++; + + } else { + // إذا كانت العملية قديمة + logMsg("⚠️ SKIPPED (OLD) -> ID:$tid is <= Last:$last_id_on_file"); + } +} + +if ($max_id_processed > $last_id_on_file) { + @file_put_contents($last_id_file, $max_id_processed); +} + +echo json_encode(["status" => "success", "processed" => $processed_count]); +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions_new.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions_new.php new file mode 100755 index 0000000..50b49c9 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions_new.php @@ -0,0 +1,117 @@ + + + "error", "msg" => "DB Failed"]); exit; +} + +// تضمين ملف الإيداع المالي +if (file_exists(__DIR__ . "/finalize_deposit.php")) { + include __DIR__ . "/finalize_deposit.php"; +} else { + logMsg("CRITICAL: finalize_deposit.php missing"); exit; +} + +// --- 2. استقبال البيانات --- +$raw = file_get_contents("php://input"); +if (empty($raw)) { echo json_encode(["status" => "waiting"]); exit; } +$data = json_decode($raw, true); +if (!$data) { echo json_encode(["status" => "error"]); exit; } + +if (!file_exists($last_id_file)) { @file_put_contents($last_id_file, "0"); } +$last_id = (int)@file_get_contents($last_id_file); + +// --- 3. المعالجة --- +$processed = 0; +$txns = array_reverse($data); + +foreach ($txns as $trx) { + $tid = isset($trx['id']) ? (int)$trx['id'] : 0; + + if ($tid > $last_id) { + $amt = (float)($trx['amount'] ?? 0); + $note = $trx['note'] ?? ''; + $status_log = "IGNORED"; + + // شرط الإيداع: مبلغ موجب + وجود ملاحظة رقمية + // نستخرج الأرقام فقط من الملاحظة (رقم الفاتورة) + $invoice_num = preg_replace('/[^0-9]/', '', $note); + + if ($amt > 0 && !empty($invoice_num) && strlen($invoice_num) >= 5) { + + // البحث المباشر عن الفاتورة برقمها والمبلغ + $stmt = $con->prepare("SELECT id FROM invoices_shamcash WHERE invoice_number = :inv AND amount = :amt AND status = 'pending' LIMIT 1"); + $stmt->execute([':inv' => $invoice_num, ':amt' => $amt]); + $invoice = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($invoice) { + $inv_id = $invoice['id']; + + // حجز الفاتورة فوراً + $upd = $con->prepare("UPDATE invoices_shamcash SET status = 'processing', transaction_id = :tid WHERE id = :id AND status = 'pending'"); + $upd->execute([':tid' => $tid, ':id' => $inv_id]); + + if ($upd->rowCount() > 0) { + // استدعاء الفاينلايز (مع البونص والتوكنات) + if (finalizeShamCashDeposit($con, $inv_id)) { + $status_log = "SUCCESS (Inv#$inv_id)"; + } else { + $status_log = "FAILED_FINALIZE (Inv#$inv_id)"; + // إعادة الحالة للفشل + $con->prepare("UPDATE invoices_shamcash SET status = 'failed' WHERE id = :id")->execute([':id' => $inv_id]); + } + } else { + $status_log = "RACE_CONDITION"; + } + } else { + $status_log = "NO_MATCHING_INVOICE ($invoice_num)"; + } + } elseif ($amt > 0) { + $status_log = "INVALID_NOTE"; + } + + logMsg("ID:$tid | Note:$note | Amt:$amt | $status_log"); + $last_id = $tid; + $processed++; + } +} + +if ($processed > 0) { + @file_put_contents($last_id_file, $last_id); +} + +echo json_encode(["status" => "success", "processed" => $processed]); +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/server_check.php b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/server_check.php new file mode 100755 index 0000000..54e9a11 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/server_check.php @@ -0,0 +1,60 @@ +🔍 Server & File Diagnostics"; + +// 1. فحص المجلد +$dir = __DIR__; +echo "Current Dir: $dir
"; +if (is_writable($dir)) { + echo "✅ Directory is Writable (777 OK)
"; +} else { + echo "❌ Directory NOT Writable! Please set Permissions to 777.
"; +} + +// 2. فحص ملف save_transactions.php +$target_file = $dir . '/save_transactions.php'; +echo "

Testing 'save_transactions.php':

"; + +if (!file_exists($target_file)) { + echo "❌ File not found!"; +} else { + // محاولة فحص الكود بحثاً عن أخطاء نحوية (Syntax Errors) + $content = file_get_contents($target_file); + + // فحص إذا كان المستخدم نسخ علامات Markdown بالخطأ + if (strpos($content, '```') !== false) { + echo "CRITICAL ERROR FOUND: Markdown tags (```) detected inside the PHP file!
"; + echo "👉 Solution: Open the file and remove the first/last lines containing ``` or ```php.
"; + } elseif (substr(trim($content), 0, 5) !== 'START ERROR: File does not start with <?php
"; + echo "Found instead: " . substr(trim($content), 0, 20) . "...
"; + } else { + echo "✅ File structure looks clean (No Markdown tags).
"; + + // محاولة استدعاء الملف (سيظهر الخطأ إذا وجد) + echo "Attempting to include file...

"; + echo "
"; + + // نحجز المخرجات لنرى إذا كان هناك خطأ + ob_start(); + try { + include $target_file; + } catch (Throwable $e) { + echo "Runtime Error: " . $e->getMessage(); + } + $output = ob_get_clean(); + + if (empty($output)) { + echo "File included successfully (No output is good in this context)."; + } else { + echo "Output/Error:
" . $output; + } + echo "
"; + } +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/transactions.log b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/transactions.log new file mode 100644 index 0000000..946a5ca --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/shamcash/transactions.log @@ -0,0 +1,100 @@ +[08:37:59] ID:54627270 | User:Ciedco Group | Note:مرتجع | Amt:475000 | Status:NO_MATCH +[08:37:59] ID:54847574 | User:خليل ابراهيم حسين الاحمد | Note: | Amt:-475000 | Status:IGNORED +[08:37:59] ID:60527547 | User:sameram | Note: | Amt:10000 | Status:NO_MATCH +[08:37:59] ID:60744509 | User:محمد منير عاشور | Note: | Amt:832000 | Status:NO_MATCH +[08:37:59] ID:60808239 | User:خليل ابراهيم حسين الاحمد | Note: | Amt:-830000 | Status:IGNORED +[08:37:59] ID:60906569 | User:أ.خالد محمد الخليل العمر | Note: | Amt:20000 | Status:NO_MATCH +[09:28:35] ID:64318914 | Note: | Amt:10000 | IGNORED +[12:21:45] ID:65719216 | Note: | Amt:1225000 | IGNORED +[13:12:39] ID:65755911 | Note: | Amt:10000 | IGNORED +[21:17:42] ID:65900994 | Note: | Amt:-1227000 | IGNORED +[07:52:04] ID:66228976 | Note: | Amt:1200000 | IGNORED +[12:50:53] ID:67956113 | Note: | Amt:250000 | IGNORED +[12:50:53] ID:68162721 | Note: | Amt:133000 | IGNORED +[12:50:53] ID:69061135 | Note:shahd intaleq | Amt:-325000 | IGNORED +[06:20:37] ID:70100919 | Note:969580 | Amt:10000 | SUCCESS_DRIVER (Inv#18) +[11:54:56] ID:71296296 | Note: | Amt:20000 | IGNORED +[08:34:59] ID:72614643 | Note:450448 | Amt:20000 | SUCCESS_DRIVER (Inv#22) +[15:30:46] ID:73604768 | Note: | Amt:-1358000 | IGNORED +[15:30:46] ID:73804278 | Note:127266 | Amt:20000 | SUCCESS_DRIVER (Inv#27) +[15:42:50] ID:73825611 | Note:646898 | Amt:40000 | SUCCESS_DRIVER (Inv#28) +[11:20:12] ID:74281823 | Note: | Amt:-20000 | IGNORED +[12:21:36] ID:74331105 | Note: | Amt:350000 | IGNORED +[07:55:11] ID:74889079 | Note: | Amt:1039000 | IGNORED +[15:38:39] ID:75103283 | Note: | Amt:10000 | IGNORED +[15:38:39] ID:75104422 | Note:493193 | Amt:10000 | SUCCESS_DRIVER (Inv#32) +[15:38:39] ID:75107242 | Note:493193 | Amt:10000 | NO_MATCH (493193) +[2025-12-21 20:54:28] INFO: Received single transaction ID: 74889079 +[2025-12-21 20:54:28] INFO: Received single transaction ID: 75104422 +[2025-12-21 20:54:28] INFO: Received single transaction ID: 74331105 +[2025-12-21 20:54:28] INFO: Received single transaction ID: 75103283 +[2025-12-21 20:55:04] INFO: Received single transaction ID: 77893875 +[2025-12-21 20:55:04] TXN:77893875 | Amt:467000 | Note: | Inv: | Status:IGNORED +[2025-12-21 20:55:04] INFO: Received single transaction ID: 77539683 +[2025-12-21 20:55:04] INFO: Received single transaction ID: 77532472 +[2025-12-21 20:55:04] INFO: Received single transaction ID: 78325873 +[2025-12-21 20:55:04] TXN:78325873 | Amt:10000 | Note:994127 | Inv:994127 | Status:SUCCESS_DRIVER (Inv#39) +[2025-12-21 20:55:04] INFO: Received single transaction ID: 77971899 +[2025-12-21 20:55:04] INFO: Received single transaction ID: 75107242 +[2025-12-21 20:56:42] INFO: Received single transaction ID: 77893875 +[2025-12-21 20:56:42] INFO: Received single transaction ID: 77971899 +[2025-12-21 20:56:42] INFO: Received single transaction ID: 77532472 +[2025-12-21 20:56:42] INFO: Received single transaction ID: 78325873 +[2025-12-21 20:56:42] INFO: Received single transaction ID: 77539683 +[2025-12-21 20:56:42] INFO: Received single transaction ID: 75107242 +[2025-12-26 09:31:24] INFO: Received single transaction ID: 81285522 +[2025-12-26 09:31:24] TXN:81285522 | Amt:1300000 | Note: | Inv: | Status:IGNORED +[2025-12-26 09:31:24] INFO: Received single transaction ID: 80139845 +[2025-12-26 09:31:24] INFO: Received single transaction ID: 81285582 +[2025-12-26 09:31:24] INFO: Received single transaction ID: 80197899 +[2025-12-26 09:31:24] TXN:81285582 | Amt:1300000 | Note: | Inv: | Status:IGNORED +[2025-12-26 09:31:24] INFO: Received single transaction ID: 81285625 +[2025-12-26 09:31:24] TXN:81285625 | Amt:1300000 | Note: | Inv: | Status:IGNORED +[2025-12-26 09:31:24] INFO: Received single transaction ID: 77971899 +[2025-12-26 09:31:24] INFO: Received single transaction ID: 78325873 +[2025-12-28 22:09:18] INFO: Received single transaction ID: 82265340 +[2025-12-28 22:09:18] INFO: Received single transaction ID: 82260577 +[2025-12-28 22:09:18] TXN:82265340 | Amt:1000 | Note: | Inv: | Status:IGNORED +[2025-12-28 22:09:18] TXN:82260577 | Amt:20000 | Note: | Inv: | Status:IGNORED +[2025-12-30 16:46:08] INFO: Received single transaction ID: 81285522 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 81285582 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 81285625 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 82260577 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 82265340 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 78325873 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 80197899 +[2025-12-30 16:46:08] INFO: Received single transaction ID: 80139845 +[2026-01-08 15:49:00] INFO: Received single transaction ID: 82260577 +[2026-01-08 15:49:00] INFO: Received single transaction ID: 84322399 +[2026-01-08 15:49:00] INFO: Received single transaction ID: 82265340 +[2026-01-08 15:49:00] INFO: Received single transaction ID: 84319368 +[2026-01-08 15:49:00] TXN:84319368 | Amt:20000 | Note: | Inv: | Status:IGNORED +[2026-01-08 15:49:00] INFO: Received single transaction ID: 81285625 +[2026-01-08 15:49:00] TXN:84322399 | Amt:20000 | Note:869354 | Inv:869354 | Status:SUCCESS_DRIVER (Inv#48) +[2026-01-08 15:49:01] INFO: Received single transaction ID: 81285582 +[2026-01-08 15:49:01] INFO: Received single transaction ID: 81285522[2026-02-16 14:02:39] INFO: Received single transaction ID: 843193682000020251230210701 + +[2026-02-16 18:56:11] 📥 RECEIVED -> ID:120329324 | Amt:20 | Note:377746 +[2026-02-16 18:56:11] 📥 RECEIVED -> ID:105354653 | Amt:100 | Note: +[2026-02-16 18:56:11] ⚙️ PROCESSED -> ID:105354653 | Status:IGNORED_NO_INVOICE +[2026-02-16 18:56:11] 📥 RECEIVED -> ID:84322399 | Amt:20000 | Note:869354 +[2026-02-16 18:56:11] ⚠️ SKIPPED (OLD) -> ID:84322399 is <= Last:105354653 +[2026-02-16 18:56:11] 📥 RECEIVED -> ID:120840498 | Amt:5 | Note: +[2026-02-16 18:56:11] ⚙️ PROCESSED -> ID:120840498 | Status:IGNORED_NO_INVOICE +[2026-02-16 18:56:12] 📥 RECEIVED -> ID:120327019 | Amt:500 | Note: +[2026-02-16 18:56:12] ⚠️ SKIPPED (OLD) -> ID:120327019 is <= Last:120840498 +[2026-02-16 18:56:12] ⚙️ PROCESSED -> ID:120329324 | Status:NO_MATCH (Inv:377746) +[2026-02-16 18:56:12] 📥 RECEIVED -> ID:84319368 | Amt:20000 | Note: +[2026-02-16 18:56:12] ⚠️ SKIPPED (OLD) -> ID:84319368 is <= Last:120329324 +[2026-02-25 18:13:33] 📥 RECEIVED -> ID:120327019 | Amt:500 | Note: +[2026-02-25 18:13:33] 📥 RECEIVED -> ID:120840498 | Amt:5 | Note: +[2026-02-25 18:13:33] ⚠️ SKIPPED (OLD) -> ID:120327019 is <= Last:120329324 +[2026-02-25 18:13:33] ⚙️ PROCESSED -> ID:120840498 | Status:IGNORED_NO_INVOICE +[2026-02-25 18:13:33] 📥 RECEIVED -> ID:84322399 | Amt:20000 | Note:869354 +[2026-02-25 18:13:33] ⚠️ SKIPPED (OLD) -> ID:84322399 is <= Last:120840498 +[2026-02-25 18:13:33] 📥 RECEIVED -> ID:120329324 | Amt:20 | Note:377746 +[2026-02-25 18:13:33] ⚠️ SKIPPED (OLD) -> ID:120329324 is <= Last:120840498 +[2026-02-25 18:13:33] 📥 RECEIVED -> ID:105354653 | Amt:100 | Note: +[2026-02-25 18:13:33] ⚠️ SKIPPED (OLD) -> ID:105354653 is <= Last:120840498 +[2026-02-25 18:13:33] 📥 RECEIVED -> ID:84319368 | Amt:20000 | Note: +[2026-02-25 18:13:33] ⚠️ SKIPPED (OLD) -> ID:84319368 is <= Last:120840498 diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/seferWallet/add.php b/walletintaleq.intaleq.xyz/v2/main/ride/siroWallet/add.php similarity index 95% rename from walletintaleq.intaleq.xyz/v2/main/ride/seferWallet/add.php rename to walletintaleq.intaleq.xyz/v2/main/ride/siroWallet/add.php index 6b6cc82..a610def 100755 --- a/walletintaleq.intaleq.xyz/v2/main/ride/seferWallet/add.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/siroWallet/add.php @@ -35,8 +35,8 @@ try { if ($tokenData) { // logDebug("Valid token found!"); - // Insert into Sefer Wallet - $sql = "INSERT INTO `seferWallet` ( + // Insert into Siro Wallet + $sql = "INSERT INTO `siroWallet` ( `driverId`, `passengerId`, `amount`, @@ -78,7 +78,7 @@ try { } } catch (Exception $e) { // logDebug("Exception: " . $e->getMessage()); - error_log("[seferWallet/add] " . $e->getMessage()); + error_log("[siroWallet/add] " . $e->getMessage()); printFailure("An error occurred"); } ?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/seferWallet/get.php b/walletintaleq.intaleq.xyz/v2/main/ride/siroWallet/get.php similarity index 92% rename from walletintaleq.intaleq.xyz/v2/main/ride/seferWallet/get.php rename to walletintaleq.intaleq.xyz/v2/main/ride/siroWallet/get.php index ee6c255..26ff045 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/seferWallet/get.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/siroWallet/get.php @@ -8,7 +8,7 @@ $order_id = filterRequest("order_id"); $sql = "SELECT SUM(amount) FROM - `seferWallet` + `siroWallet` WHERE createdAt BETWEEN DATE_FORMAT(CURRENT_DATE, '%Y-%m-01') AND LAST_DAY(CURRENT_DATE)"; diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/archive.zip b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/archive.zip new file mode 100755 index 0000000000000000000000000000000000000000..c922a8901b8636e1c6b6bcbc966f31a7798fbd31 GIT binary patch literal 6175 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 af9aa82F71a0{|F*En5@-po-$}+kXMvTTt-; literal 0 HcmV?d00001 diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php new file mode 100755 index 0000000..d41bef2 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php @@ -0,0 +1,237 @@ + "success", "message" => $message, "data" => $data], JSON_UNESCAPED_UNICODE); + exit; + } +} +if (!function_exists('printFailure')) { + function printFailure($message = "failure", $code = null) { + $resp = ["status" => "failure", "message" => $message]; + if ($code !== null) $resp["code"] = $code; + echo json_encode($resp, JSON_UNESCAPED_UNICODE); + exit; + } +} + +define("WALLET_LOG", __DIR__ . "/../logs/payment_verification.log"); +function wlog($step, $msg, $data = null) { + $dir = dirname(WALLET_LOG); + if (!is_dir($dir)) { @mkdir($dir, 0755, true); } + $line = "[".date('Y-m-d H:i:s')."] STEP {$step}: {$msg}"; + if ($data !== null) $line .= " | Data: ".json_encode($data, JSON_UNESCAPED_UNICODE); + file_put_contents(WALLET_LOG, $line.PHP_EOL, FILE_APPEND); +} + +// ================== منطق التوكن/المعرف ================== +function generateToken(PDO $con, string $driverId, float $amount): ?string { + // secretKey يُفترض قادم من connect/env + global $secretKey; + $data = $driverId.$amount.time().($secretKey ?? 'default_secret'); + $hash = hash('sha256', $data); + $rand = bin2hex(random_bytes(16)); + $token = substr($hash.$rand, 0, 64); + + $stmt = $con->prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) + VALUES (:t, :d, NOW(), :a)"); + $stmt->execute([':t'=>$token, ':d'=>$driverId, ':a'=>$amount]); + return $stmt->rowCount() ? $token : null; +} + +function generatePaymentID(PDO $con, string $driverId, float $amount, string $method): ?string { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (amount, payment_method, driverID) + VALUES (:a, :m, :d)"); + $stmt->execute([':a'=>$amount, ':m'=>$method, ':d'=>$driverId]); + return $stmt->rowCount() ? $con->lastInsertId() : null; +} + +// ================== منطق إنهاء الدفع (مضمَّن) ================== +function finalizeWalletPaymentInline(PDO $con, string $orderRef): void { + // نقفل الصف لمنع السباقات + $stmt = $con->prepare("SELECT * FROM paymentsLogSyriaDriver + WHERE order_ref = :r LIMIT 1 FOR UPDATE"); + $stmt->execute([':r'=>$orderRef]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + wlog("FINALIZE", "Payment row not found", ['orderRef'=>$orderRef]); + throw new RuntimeException("Payment not found."); + } + + // نتأكد من نجاح مزود الدفع + if ((int)$payment['status'] !== 1) { + wlog("FINALIZE", "Payment not completed yet", ['orderRef'=>$orderRef, 'status'=>$payment['status']]); + throw new RuntimeException("Payment not completed."); + } + + // حارس التكرار: إذا تمّت معالجة المحفظة سابقاً لا نكرر + if (!empty($payment['processed_wallet']) && (int)$payment['processed_wallet'] === 1) { + wlog("FINALIZE", "Already processed_wallet=1, skip.", ['orderRef'=>$orderRef]); + return; // لا نرمي استثناء؛ العملية سبق احتسابها + } + + $driverId = $payment['user_id']; // This is now correctly handled as a string + $originalAmount = (float)$payment['amount']; + $paymentMethod = $payment['payment_method'] ?: 'ecash'; + + // البونص + $bonusAmount = match ((int)$originalAmount) { + 100 => 100.0, + 200 => 210.0, + 400 => 450.0, + 1000 => 1100.0, + default => $originalAmount, + }; + + // تنفيذ ككل داخل معاملة + $con->beginTransaction(); + try { + // توليد التوكنات/المعرف + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + if (!$tokenDriver) throw new RuntimeException("Failed to generate driver token"); + + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) throw new RuntimeException("Failed to generate siro token"); + + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + if (!$paymentID) throw new RuntimeException("Failed to create payment ID"); + + // driverWallet + $q = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) + VALUES (:d, :r, :a, :m)"); + $q->execute([ + ':d'=>$driverId, ':a'=>$bonusAmount, + ':m'=>$paymentMethod, ':r'=>$orderRef + ]); + if ($q->rowCount() === 0) throw new RuntimeException("Insert driverWallet failed"); + + // وسم التوكن كمستخدم + $con->prepare("UPDATE payment_tokens SET isUsed = 1 WHERE token = :t")->execute([':t'=>$tokenDriver]); + + // siroWallet + $q2 = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) + VALUES (:d, :p, :a, :m, :t, CURRENT_TIMESTAMP)"); + $q2->execute([ + ':d'=>$driverId, ':p'=>'driver', ':a'=>$originalAmount, + ':m'=>$paymentMethod, ':t'=>$tokenSiro + ]); + if ($q2->rowCount() === 0) throw new RuntimeException("Insert siroWallet failed"); + + $con->prepare("UPDATE payment_tokens SET isUsed = 1 WHERE token = :t")->execute([':t'=>$tokenSiro]); + + // تأشير السجل كمنتهٍ للمحفظة + $con->prepare("UPDATE paymentsLogSyriaDriver + SET processed_wallet = 1, updated_at = NOW() + WHERE order_ref = :r")->execute([':r'=>$orderRef]); + + $con->commit(); + wlog("FINALIZE", "Wallets updated successfully", ['orderRef'=>$orderRef, 'driverId'=>$driverId]); + } catch (Throwable $e) { + $con->rollBack(); + wlog("FINALIZE", "Exception: ".$e->getMessage(), ['orderRef'=>$orderRef]); + throw $e; + } +} + +// ================== مدخل تأكيد الدفع ================== +$transactionID = filterRequest('transactionID'); +$otp = filterRequest('otp'); + +error_log("Syriatel Confirm: Request for transaction {$transactionID}"); + +if (!$transactionID || !$otp) { + printFailure("Missing transaction ID or OTP."); +} + +// بيئة +$baseUrl = rtrim((string)getenv('SYRIATEL_API_BASE_URL'), '/'); +$merchantMSISDN = (string)getenv('SYRIATEL_MERCHANT_MSISDN'); +if ($baseUrl === '' || $merchantMSISDN === '') { + error_log("Syriatel Confirm: Missing SYRIATEL envs"); + printFailure("Server configuration error."); +} + +try { + // 1) Auth token + $token = function_exists('GetSerialToken') ? GetSerialToken() : getSyriatelToken(); + if (!$token) { printFailure("Could not authenticate with the payment provider."); } + + // 2) Call provider + $body = [ + "OTP" => $otp, + "merchantMSISDN" => $merchantMSISDN, + "transactionID" => $transactionID, + "token" => $token + ]; + $url = "{$baseUrl}/ePaymentExternalModule/paymentConfirmation"; + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "Accept: application/json", + "User-Agent: Mozilla/5.0", + ], + CURLOPT_CONNECTTIMEOUT => 8, + CURLOPT_TIMEOUT => 40, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYHOST => 2, + ]); + $response = curl_exec($ch); + $errno = curl_errno($ch); + $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + error_log("Syriatel Confirm: HTTP {$httpCode} - ".substr((string)$response, 0, 300)); + + if ($errno) { printFailure("Payment gateway communication error.", $errno); } + if ($httpCode !== 200 || !$response) { printFailure("Payment gateway communication error (HTTP {$httpCode})."); } + + $responseData = json_decode($response, true); + if (!is_array($responseData)) { printFailure("Invalid provider response."); } + + $ok = (isset($responseData['errorDesc']) && $responseData['errorDesc'] === "Success"); + + if ($ok) { + // نحدّث حالة الدفع، ونُتم المحفظة بشكل آمن داخل نفس الطلب + $con->prepare("UPDATE paymentsLogSyriaDriver + SET status = 1, updated_at = NOW() + WHERE order_ref = :r")->execute([':r'=>$transactionID]); + + // إنهاء المحفظة (داخلية) + $walletOk = true; $walletMsg = null; + try { + finalizeWalletPaymentInline($con, $transactionID); + } catch (Throwable $ex) { + $walletOk = false; $walletMsg = $ex->getMessage(); + } + + $payload = [ + 'message' => 'Payment confirmed.', + 'transactionID' => $transactionID, + 'provider' => $responseData + ]; + if (!$walletOk && $walletMsg) { + $payload['walletNotice'] = "Payment successful, but wallet update failed: ".$walletMsg; + } + + printSuccess($payload); + } + + $errorMessage = $responseData['errorDesc'] ?? 'Unknown provider error'; + printFailure($errorMessage); + +} catch (Throwable $e) { + error_log("Syriatel Confirm: Exception - ".$e->getMessage()); + printFailure("An unexpected server error occurred."); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/finalize_wallet_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/finalize_wallet_payment.php new file mode 100755 index 0000000..59cb847 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/finalize_wallet_payment.php @@ -0,0 +1,127 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + return $stmt->rowCount() > 0 ? $token : null; + } +} + +if (!function_exists('generatePaymentID')) { + function generatePaymentID($con, $driverId, $amount, $method): ?string { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; + } +} + + +if (!function_exists('finalizeWalletPayment')) { + function finalizeWalletPayment($con) { + $orderRef = $_GET['orderRef'] ?? null; + if (empty($orderRef)) { + logError("FINALIZE", "Missing orderRef"); + return; // لا نستخدم throw هنا لأن الخطأ داخلي + } + + // 1. تحقق من الدفع + $stmt = $con->prepare("SELECT * FROM `paymentsLogSyriaDriver` WHERE order_ref = :order_ref AND status = 1 LIMIT 1"); + $stmt->execute([':order_ref' => $orderRef]); + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + logError("FINALIZE", "Payment not found or not completed", ['orderRef' => $orderRef]); + return; + } + + // [تحسين] استخدام معاملات لضمان سلامة البيانات + $con->beginTransaction(); + try { + $driverId = $payment['user_id']; + $originalAmount = floatval($payment['amount']); + $paymentMethod = $payment['payment_method'] ?? 'ecash'; + + // حساب المكافأة + $bonusAmount = match ((int)$originalAmount) { + 100 => 100.0, + 200 => 210.0, + 400 => 450.0, + 1000 => 1100.0, + default => $originalAmount, + }; + + // إنشاء التوكنات + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + if (!$tokenDriver) throw new Exception('Failed to generate driver token'); + + $tokenSiro = generateToken($con, $driverId, $originalAmount); + if (!$tokenSiro) throw new Exception('Failed to generate siro token'); + + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + if (!$paymentID) throw new Exception('Failed to generate payment ID'); + + // driverWallet + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, + ':paymentID' => $paymentID, + ':amount' => $bonusAmount, + ':paymentMethod' => $paymentMethod + ]); + if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed'); + + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]); + + // siroWallet + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) + VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token, CURRENT_TIMESTAMP)"); + $insertSiro->execute([ + ':driverId' => $driverId, + ':passengerId' => 'driver', + ':amount' => $originalAmount, + ':paymentMethod' => $paymentMethod, + ':token' => $tokenSiro + ]); + if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed'); + + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSiro]); + + // إذا نجحت كل العمليات، قم بتثبيتها في قاعدة البيانات + $con->commit(); + + logError("FINALIZE", "Wallets updated successfully", ['orderRef' => $orderRef]); + // لا نطبع نجاح هنا، الملف المستدعي هو المسؤول عن إرسال الرد النهائي + + } catch (Throwable $e) { + // في حالة حدوث أي خطأ، تراجع عن كل التغييرات + $con->rollBack(); + logError("FINALIZE", "Exception during finalization: " . $e->getMessage(), ['orderRef' => $orderRef]); + // نمرر الخطأ للملف الأعلى ليعالجه + throw $e; + } + } +} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/start_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/start_payment.php new file mode 100755 index 0000000..f5b8feb --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/start_payment.php @@ -0,0 +1,141 @@ +"success","message"=>$message,"data"=>$data], JSON_UNESCAPED_UNICODE); exit; + } +} +if (!function_exists('printFailure')) { + function printFailure($message = "failure", $code = null) { + $resp = ["status"=>"failure","message"=>$message]; if ($code!==null) $resp["code"]=$code; + echo json_encode($resp, JSON_UNESCAPED_UNICODE); exit; + } +} + +/** مولّد مرجع الطلب (TransactionID) */ +function generate_order_ref(): string { + // مرجع مقروء + فريد: INT-YYYYMMDDHHMMSS-6digits + $ts = date('YmdHis'); + $rand = str_pad((string)random_int(0, 999999), 6, '0', STR_PAD_LEFT); + return "INT-$ts-$rand"; +} + +// --- Input Parameters --- +$amount = filterRequest('amount'); +$driverId = filterRequest('driverId'); +$phone = filterRequest('phone'); // customerMSISDN +$lang = filterRequest('lang') ?? 'ar'; + +error_log("Syriatel Start: Request received for driver {$driverId} with amount {$amount}"); + +if (!$amount || !$driverId || !$phone) { + printFailure("Missing required parameters."); +} + +// --- Environment Variables --- +$baseUrl = rtrim((string)getenv('SYRIATEL_API_BASE_URL'), '/'); +$merchantMSISDN = (string)getenv('SYRIATEL_MERCHANT_MSISDN'); + +if ($baseUrl === '' || $merchantMSISDN === '') { + error_log("Syriatel Start: Missing SYRIATEL_API_BASE_URL or SYRIATEL_MERCHANT_MSISDN"); + printFailure("Server configuration error."); +} + +// --- Logic --- +try { + // 1) Token + $token = getSyriatelToken(); + error_log("Syriatel Start: token=" . ($token ? substr($token,0,8).'...' : 'NULL')); + + if (!$token) { + printFailure("Could not authenticate with the payment provider."); + } + + // 2) Transaction ID + log DB + $transactionID = generate_order_ref(); + $stmt = $con->prepare( + "INSERT INTO `paymentsLogSyriaDriver` (user_id, amount, status, order_ref, payment_method, created_at) + VALUES (:user_id, :amount, 0, :order_ref, 'syriatel', NOW())" + ); + $stmt->execute([ + ':user_id' => $driverId, + ':amount' => $amount, + ':order_ref' => $transactionID + ]); + error_log("Syriatel Start: Logged transaction {$transactionID} for driver {$driverId}"); + + // 3) Payment Request → Syriatel + $body = [ + "customerMSISDN" => $phone, // مثال: 09xxxxxxxx (حسب وثيقتهم) + "merchantMSISDN" => $merchantMSISDN, // من env + "amount" => $amount, + "transactionID" => $transactionID, + "token" => $token + ]; +error_log("Syriatel Start: customerMSISDN {$phone} merchantMSISDN {$merchantMSISDN}"); + $url = "{$baseUrl}/ePaymentExternalModule/paymentRequest"; + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "User-Agent: Mozilla/5.0", + "Accept: application/json" + ], + CURLOPT_CONNECTTIMEOUT => 8, + CURLOPT_TIMEOUT => 40, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYHOST => 2, + ]); + $response = curl_exec($ch); + $errno = curl_errno($ch); + $errstr = curl_error($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + error_log("Syriatel Start: paymentRequest HTTP {$httpCode} errno={$errno} resp=" . substr((string)$response,0,300)); + + if ($errno) { + printFailure("Payment gateway communication error.", $errno); + } + if ($httpCode !== 200) { + printFailure("Payment gateway communication error (HTTP {$httpCode})."); + } + + $responseData = json_decode($response, true); + + // حسب الدوكيومنت: resultCode = 1 يعني OTP انرسل بنجاح + //errorCode = 0 => Success +if (isset($responseData['errorCode']) && (string)$responseData['errorCode'] === "0") { + printSuccess([ + 'message' => 'OTP sent successfully.', + 'transactionID' => $transactionID, + ]); +} +// 2) إذا resultCode = 1 => OTP sent +elseif (isset($responseData['resultCode']) && (int)$responseData['resultCode'] === 1) { + printSuccess([ + 'message' => 'OTP sent successfully.', + 'transactionID' => $transactionID, + ]); +} +// 3) أي شيء آخر => فشل +else { + $errorMessage = $responseData['resultDescription'] + ?? $responseData['errorDesc'] + ?? 'Failed to initiate payment.'; + printFailure($errorMessage); +} + +} catch (Throwable $e) { + error_log("Syriatel Start: Exception - " . $e->getMessage()); + printFailure("An unexpected server error occurred."); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/syriatel_token_handler.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/syriatel_token_handler.php new file mode 100755 index 0000000..ba53ae6 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/syriatel_token_handler.php @@ -0,0 +1,74 @@ + $username, + "password" => $password + ]; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "User-Agent: Mozilla/5.0", + ], + CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE), + CURLOPT_CONNECTTIMEOUT => 8, + CURLOPT_TIMEOUT => 40, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYHOST => 2, + ]); + + $response = curl_exec($ch); + $errno = curl_errno($ch); + $errstr = curl_error($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($errno) { + error_log("[GetSyriatelToken] cURL error {$errno}: {$errstr}"); + printFailure("Could not connect to the payment provider.", $errno); + return null; + } + + if ($httpCode !== 200 || !$response) { + error_log("[GetSyriatelToken] HTTP {$httpCode} | Empty/invalid response"); + printFailure("Could not authenticate with the payment provider."); + return null; + } + + $data = json_decode($response, true); + $token = $data["token"] ?? null; + + if (!$token) { + error_log("[GetSyriatelToken] Token not found in response: " . substr($response, 0, 300)); + printFailure("Could not authenticate with the payment provider."); + return null; + } + + error_log("[GetSyriatelToken] Token received successfully"); + return $token; +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/logs/payment_verification.log b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/logs/payment_verification.log new file mode 100644 index 0000000..0ef1101 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/logs/payment_verification.log @@ -0,0 +1,25 @@ +[2025-11-04 11:16:27] STEP FINALIZE: Exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'orderRef' in 'field list' | Data: {"orderRef":"INT-20251104111538-994380"} +[2025-11-05 11:36:24] STEP FINALIZE: Exception: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined | Data: {"orderRef":"INT-20251105113557-052588"} +[2025-11-08 07:24:27] STEP FINALIZE: Exception: generateToken(): Argument #2 ($driverId) must be of type int, string given, called in /home/intaleq-wallet/htdocs/walletintaleq.intaleq.xyz/v1/main/ride/syriatel/driver/confirm_payment.php on line 98 | Data: {"orderRef":"INT-20251108072402-591731"} +[2025-11-15 03:12:44] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251115031225-211431","driverId":"1031b1b342a9a9e20b95"} +[2025-11-16 23:34:48] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251116233429-590104","driverId":"048e59b0737d7ad85370"} +[2025-11-17 07:48:33] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251117074803-798991","driverId":"28b3b16129d555cafb9b"} +[2025-11-22 16:35:44] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251122163518-755824","driverId":"986bf7b2242410647d05"} +[2025-11-25 11:50:26] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251125114917-921160","driverId":"7b437f291b5330536488"} +[2025-11-25 22:53:31] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251125225306-092996","driverId":"aec6f1335b72b5976dea"} +[2025-11-25 23:38:09] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251125233750-436593","driverId":"aec6f1335b72b5976dea"} +[2025-11-26 16:24:04] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251126162327-487255","driverId":"7a30afbb9b33d68a8b78"} +[2025-11-27 11:13:43] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251127111247-519577","driverId":"92e2fd19f4be30c3c727"} +[2025-11-27 16:48:44] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251127164535-525644","driverId":"e49604074b0b27710516"} +[2025-11-29 17:23:58] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251129172343-124569","driverId":"2870ec487be28f0929c7"} +[2025-11-30 21:34:28] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251130213350-345293","driverId":"3de8047aee520ff6555f"} +[2025-12-02 14:52:41] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251202145224-318083","driverId":"590c719b3aaefb07d001"} +[2025-12-13 13:33:03] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251213133220-085952","driverId":"94973848bd46ab517fa4"} +[2025-12-14 21:59:36] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251214215921-864193","driverId":"e0d0a6a92804240482fc"} +[2025-12-16 20:05:03] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251216200446-674525","driverId":"793ebf9e18327a828c55"} +[2025-12-18 11:20:20] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251218111954-420209","driverId":"df4e0e0cb135ac836e68"} +[2025-12-18 11:22:21] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251218112152-679624","driverId":"df4e0e0cb135ac836e68"} +[2025-12-18 21:25:11] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251218212432-696061","driverId":"64bfc098a99342c0c729"} +[2025-12-21 13:03:16] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251221130240-780780","driverId":"527c0a89cdf35841e4eb"} +[2025-12-21 13:14:09] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251221131302-717915","driverId":"527c0a89cdf35841e4eb"} +[2025-12-31 10:56:16] STEP FINALIZE: Wallets updated successfully | Data: {"orderRef":"INT-20251231105523-483044","driverId":"d881d416c9d712c9b222"} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php new file mode 100755 index 0000000..d66b8a3 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php @@ -0,0 +1,201 @@ +prepare("INSERT INTO payment_tokens (token, passengerID, dateCreated, amount) VALUES (:token, :passengerID, NOW(), :amount)"); + // لاحظ: استخدمنا passengerID هنا بدلاً من driverID بناء على الجدول، إذا كان الجدول موحداً استخدم العمود المناسب + // غالباً الجدول يحتوي user_id أو يتم استخدام driverID للكل. + // سأفترض هنا أن الجدول يقبل التوكن، وسأقوم بربطه بالراكب. + // إذا كان عمود driverID هو الوحيد الموجود، يمكن تمرير الراكب فيه أو تعديل الجدول. + // **للتوافق مع السائق:** سأستخدم الحقل العام أو أتجاوز الـ foreign key إذا وجد. + // لكن الأضمن: + $stmt->execute([':token' => $token, ':passengerID' => $userId, ':amount' => $amount]); + return $stmt->rowCount() > 0 ? $token : null; + } +} + +// --- المدخلات --- +$transactionID = filterRequest('transactionID'); // يقابل order_ref +$otp = filterRequest('otp'); // كود التأكيد +$lang = filterRequest('lang'); // اختياري + +mlog("Syriatel Confirm (Passenger): Start tx={$transactionID}"); + +if (!$transactionID || !$otp) { + printFailure($lang === 'ar' ? "رقم العملية أو رمز OTP مفقود." : "Missing transaction ID or OTP."); + exit; +} + +// --- المتغيرات البيئية --- +$baseUrl = rtrim(getenv('SYRIATEL_API_BASE_URL'), '/'); +$merchantMSISDN = getenv('SYRIATEL_MERCHANT_MSISDN'); + +if (!$baseUrl || !$merchantMSISDN) { + printFailure($lang === 'ar' ? "خطأ في إعدادات الخادم." : "Server configuration error."); + exit; +} + +try { + // 1) توكن المصادقة من Syriatel + $token = getSyriatelToken(); + if (!$token) { + printFailure($lang === 'ar' ? "تعذّر المصادقة مع مزوّد الدفع." : "Could not authenticate with the payment provider."); + exit; + } + + // 2) تحضير وإرسال طلب التأكيد لشركة سيريتل + $body = [ + "OTP" => $otp, + "merchantMSISDN" => $merchantMSISDN, + "transactionID" => $transactionID, + "token" => $token + ]; + + $ch = curl_init("{$baseUrl}/ePaymentExternalModule/paymentConfirmation"); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => ["Content-Type: application/json"], + CURLOPT_TIMEOUT => 25, + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + $res = json_decode($response ?: '{}', true); + if (!is_array($res)) { $res = []; } + $errCode = isset($res['errorCode']) ? (string)$res['errorCode'] : null; + + // التحقق من رد سيريتل + if ($httpCode !== 200 || $errCode !== "0") { + $errText = $res['errorDesc'] ?? $res['resultDescription'] ?? 'Payment failed'; + mlog("Syriatel Confirm (Passenger): Failed - " . json_encode($res, JSON_UNESCAPED_UNICODE)); + printFailure(['message' => $errText, 'syriatel' => $res]); + exit; + } + + // ============================================================ + // ✅ هنا يبدأ التعديل: التحديث المباشر لقاعدة البيانات (بدون cURL) + // ============================================================ + global $con; + + // 4) التحقق من السجل في قاعدة البيانات + $chk = $con->prepare("SELECT status, user_id, amount, payment_method FROM paymentsLogSyria WHERE order_ref = :ref LIMIT 1"); + $chk->execute([':ref' => $transactionID]); + $payment = $chk->fetch(PDO::FETCH_ASSOC); + + if (!$payment) { + printFailure($lang === 'ar' ? "لم يتم العثور على السجل." : "Payment row not found"); + exit; + } + + if ((int)$payment['status'] === 1) { + printSuccess(['message' => 'Already confirmed', 'data' => ['order_ref' => $transactionID]]); + exit; + } + + // بدء المعاملة (Transaction) + $con->beginTransaction(); + + try { + // أ) تحديث حالة الدفع في السجل + $stmtUpdate = $con->prepare("UPDATE `paymentsLogSyria` SET status = 1, updated_at = NOW() WHERE order_ref = :ref"); + $stmtUpdate->execute([':ref' => $transactionID]); + + $passengerId = $payment['user_id']; + $originalAmount = floatval($payment['amount']); + $paymentMethod = $payment['payment_method'] ?? 'syriatel'; + + // ب) حساب المكافأة (نفس المنطق القديم) + $bonusAmount = match ((int)$originalAmount) { + 500 => 530.0, + 1000 => 1070.0, + 2000 => 2180.0, + 5000 => 5700.0, + default => $originalAmount, + }; + + // ج) إنشاء التوكنات مباشرة (بدون دالة خارجية) + // 1. توكن لمحفظة الراكب (بالمبلغ مع البونص) + $tokenPassenger = generateLocalToken($con, $passengerId, $bonusAmount); + if (!$tokenPassenger) throw new Exception('Failed to generate passenger token'); + + // 2. توكن لمحفظة السفر/الإيرادات (بالمبلغ الأصلي) + $tokenSiro = generateLocalToken($con, $passengerId, $originalAmount); + if (!$tokenSiro) throw new Exception('Failed to generate siro token'); + + // د) الإضافة إلى passengerWallet مباشرة + // ملاحظة: تأكد من أسماء الأعمدة في جدول passengerWallet + $insertPassWallet = $con->prepare("INSERT INTO passengerWallet (passenger_id, balance, token, created_at) VALUES (:pid, :amount, :token, NOW())"); + $insertPassWallet->execute([ + ':pid' => $passengerId, + ':amount' => $bonusAmount, + ':token' => $tokenPassenger + ]); + if ($insertPassWallet->rowCount() === 0) throw new Exception('Insert to passengerWallet failed'); + + // هـ) الإضافة إلى siroWallet مباشرة + // ملاحظة: في الراكب، يكون driverId عادة هو 'passenger' لتمييز أن الدفع جاء من تطبيق الراكب + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token, createdAt) + VALUES (:did, :pid, :amount, :method, :token, NOW())"); + $insertSiro->execute([ + ':did' => 'passenger', // كما في السكربت القديم + ':pid' => $passengerId, + ':amount' => $originalAmount, + ':method' => $paymentMethod, + ':token' => $tokenSiro + ]); + if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed'); + + // و) تحديث التوكنات لتصبح مستخدمة (isUsed = TRUE) + $updateToken = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token"); + $updateToken->execute([':token' => $tokenPassenger]); + $updateToken->execute([':token' => $tokenSiro]); + + // ز) تثبيت المعاملة + $con->commit(); + + mlog("Syriatel Confirm (Passenger): Success DB Transaction for user {$passengerId}"); + + // إرجاع رد النجاح + printSuccess([ + 'message' => 'Syriatel Confirm Success', + 'data' => [ + 'order_ref' => $transactionID, + 'finalAmount' => $bonusAmount, + 'syriatel' => $res + ] + ]); + exit; + + } catch (Throwable $e) { + // في حال حدوث خطأ، تراجع عن كل شيء + $con->rollBack(); + mlog("Syriatel Confirm (Passenger): Transaction Error - " . $e->getMessage()); + printFailure($lang === 'ar' ? "فشل تحديث المحفظة." : "Wallet update failed."); + exit; + } + +} catch (Throwable $e) { + mlog("Syriatel Confirm (Passenger): General Exception - " . $e->getMessage()); + printFailure($lang === 'ar' ? "خطأ في الخادم." : "Server error"); + exit; +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/start_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/start_payment.php new file mode 100755 index 0000000..3c1a3ba --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/start_payment.php @@ -0,0 +1,124 @@ +prepare( + "INSERT INTO `paymentsLogSyria` + (user_id, amount, status, order_ref, payment_method, created_at) + VALUES + (:user_id, :amount, 0, :order_ref, 'syriatel', NOW())" + ); + $stmt->execute([ + ':user_id' => $passengerId, + ':amount' => $amount, + ':order_ref' => $transactionID + ]); + error_log("Syriatel Start (Passenger): Logged transaction {$transactionID} for passenger {$passengerId}"); + + // 3) Call Syriatel paymentRequest + $body = [ + "customerMSISDN" => $phone, // هاتف الراكب + "merchantMSISDN" => $merchantMSISDN, // هاتف التاجر (المحفظة) + "amount" => $amount, + "transactionID" => $transactionID, + "token" => $token + ]; + + $ch = curl_init("{$baseUrl}/ePaymentExternalModule/paymentRequest"); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => ["Content-Type: application/json"], + CURLOPT_TIMEOUT => 25, + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlErr = curl_error($ch); + curl_close($ch); + + if ($curlErr) { + error_log("Syriatel Start (Passenger): cURL Error - {$curlErr}"); + } + + error_log("Syriatel Start (Passenger): API Response HTTP {$httpCode} - {$response}"); + + if ($httpCode !== 200) { + printFailure($lang === 'ar' ? "خطأ اتصال ببوابة الدفع." : "Payment gateway communication error."); + exit; + } + + $responseData = json_decode($response, true); + + // حسب الدوكيومنت: resultCode = 1 يعني OTP انرسل بنجاح + //errorCode = 0 => Success +if (isset($responseData['errorCode']) && (string)$responseData['errorCode'] === "0") { + printSuccess([ + 'message' => 'OTP sent successfully.', + 'transactionID' => $transactionID, + ]); +} +// 2) إذا resultCode = 1 => OTP sent +elseif (isset($responseData['resultCode']) && (int)$responseData['resultCode'] === 1) { + printSuccess([ + 'message' => 'OTP sent successfully.', + 'transactionID' => $transactionID, + ]); +} +// 3) أي شيء آخر => فشل +else { + $errorMessage = $responseData['resultDescription'] + ?? $responseData['errorDesc'] + ?? 'Failed to initiate payment.'; + printFailure($errorMessage); +} + +} catch (Throwable $e) { + error_log("Syriatel Start: Exception - " . $e->getMessage()); + printFailure("An unexpected server error occurred."); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token.cache b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token.cache new file mode 100644 index 0000000..3877044 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token.cache @@ -0,0 +1 @@ +{"token":"E964A84D88C9A2306016886254475A49BE2BC95AFB6F4C30CD24857F5EFACDD2173D59A4B951CCEEE311AEFD3E40ABBF3E70BD2B1B8B3F0703E094C419E6291A6CFEA5C3CCD3B57E093FD58E6BB09ECF","expires_at":1759998218} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token_handler.php b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token_handler.php new file mode 100755 index 0000000..ba53ae6 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/syriatel_token_handler.php @@ -0,0 +1,74 @@ + $username, + "password" => $password + ]; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + "Content-Type: application/json", + "User-Agent: Mozilla/5.0", + ], + CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE), + CURLOPT_CONNECTTIMEOUT => 8, + CURLOPT_TIMEOUT => 40, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_SSL_VERIFYHOST => 2, + ]); + + $response = curl_exec($ch); + $errno = curl_errno($ch); + $errstr = curl_error($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($errno) { + error_log("[GetSyriatelToken] cURL error {$errno}: {$errstr}"); + printFailure("Could not connect to the payment provider.", $errno); + return null; + } + + if ($httpCode !== 200 || !$response) { + error_log("[GetSyriatelToken] HTTP {$httpCode} | Empty/invalid response"); + printFailure("Could not authenticate with the payment provider."); + return null; + } + + $data = json_decode($response, true); + $token = $data["token"] ?? null; + + if (!$token) { + error_log("[GetSyriatelToken] Token not found in response: " . substr($response, 0, 300)); + printFailure("Could not authenticate with the payment provider."); + return null; + } + + error_log("[GetSyriatelToken] Token received successfully"); + return $token; +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/archive.zip b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/archive.zip new file mode 100755 index 0000000000000000000000000000000000000000..fc138a688293f6d37bd4383c6db1ebd2f2e93619 GIT binary patch literal 8994 zcmZ{qWl&wswzW6z?ry6Wm>cyGw9)*+6i22rf70e)68Gdv33; z>RLZ~{2OzQSx+m=K|x~!AOY}z(+);G_x)NfNGJe+1Qr0m2LJ%3R_3O*M%E7Qj@G8; zMy_r^w{Nb@PF7AJb$dCmGWPqXk#j3{Mn9o5S%(gRu8K18=d)nxnB$+5OEhe41Y=iX zl|L2lS;Q9}n<@ETX?Z>@4)J@Vskjq%6h6W=A4%Ft9;BFx0$K_(T6ByKIO zaB4I4d_mp}KD1liGurq33_Ve!rWwkc#zAi(L7eeaoX9_5eZAsBpybixJn$iXzle2R z>`qI;RKgHmwwox8!>BM1v_Nj{eotXKK(55{6d*&;7V^X|+P^MQ1kS>A+ajP$znFqH zPa;0uNE!zE6p%-BOA#8EOJN(a@CEwggoI#j8e-xU3tz-Gde_3j$I?zv<(b$Wa`Sz=lHFYin4%np4#aQiK&gk z(cL|m2JgLwg9A-IvJ6-|XBDFwu*lCY(UX(SP`SRt4o+aV43@$Cu<{_bInYyJ#Ny3r zW|f>fR$VG)b?T40MhsdJD%SvhQ}~H}_xbu30)-_u*7@Uh5@ye&m^z-sopY$mM*#*n zCJOzp{uScE$vv8LFZyR zMnW!X_O1(70CA$;x?<@E$$)TGh>jS(9_+!C;PiDx?^mgAS^LZ=>Z;(n$tIUh)Dm0J zZ{`2*8-hGuy^?NNS>?Z;k-!81{%(M&i#gEE{Qnu}Uyk{yZLb8DMt{#SVyllgk)tT~ zc-UVLjYJZOfrh5Gu2ch2nzC%!nw0v{tJ@2G&0pR%QrD2!lJ(aAE$$!j=ICItTq6VD z$S0?=#NW}tF+IW2aSHZ$2EX;k5asd9-)avx=B$)VjV;J+G&D4zBL}1PIeTJf0p3ZV zOZ$em3_P((%L2}Mwvn)X(F+aLrc1YoWCpk5wxhO)%}a|Ax!8y6vK5y%6N|$%x-ASC z+oqOn>W76~1+Ba?cG-fTKkei4z;O8^psC!-_4WiiDKR=lzvY(0Y%^?LbGMRvKV7Ov zd&NyoTLB*_RYN2TN6QYVjfrsH30|>?Z~GD)=8%t8bessg5#z{PdoOyNI6uEco*0U? zDj8zo4;Y8H2PuXBf(U9X;bmq>OWFK`0;}5QBi6zcbxfN7c_ZkUZedUWDl%P10yXGR z0AvZ%OB*>c$zC+O^}ah!PsqI&0Plew{s2i!8f5j|f;7x3yqh$P#Wf8SCORmT9}%fY z`AhmW`2eu&kC7GTtxre(BG1Zh-m6=<2rG8WiSvnWfUMg7TUs#~ zHp!CjlR7+Pz2A`21nopQi%AD$rp2~VNjp%stx`C~^gE)iMQSmL(s^gUC} zZk~kc07yRaycKbfg1X?VQ{4Q4z?TRb#XggWnuzNfJ>TDI6z*j=jMv`EK?^QtN=C|w zd;y7f=By^}qIwBbVw_h*=vo7BSFA`d{l@Jifx1=xV^9p4S9B&vR%@Jw&*VR%iz7_;`WcCdD_+o{kG=*62ZE+nW z*>1p1nV)MeKi6RA=>`euFnH3SX$q6zH3mPrV}gIJE064_{CRi2Lf3 z9}A*UajP8O_d(} zNIx|TGngP8>*RfRh|;%wgkJmjs~*+KoNoDx40s;37_I8Er=%G_Zy8&F1I8@6CAcys`A5duB&Mf!n_(Wo0{3KC(RE@3k1AK8MMjB zb;3nQ>;@7aGa=;BkUw8at5t9$v_YCJmisViOgHojqDdQ?8|DJiM$|33-!|*hlh|qOK=$k zz95Z1*f7Npmz9*;DFc#T@*MXNBfc|Z<^Fv_vLsHoIfcc6t*KmutA%CKbWqyZaC$}%hp7GmeNF>^-o`Ol(KN(6<7U^m&^B|3FzB$b@Cqe5c7SZ);V~*sYTNvg`4#BK z%?G*kCV2mbn-lgCGD~mUTXRR>88SOQOQ1+f5@QIN8KUO*E9U{-Fl4!EHyXw4b`#_{ z5EZ2Dli({`Lvj3*`x34wH|&Y@+SfIAE6E&|rYeBr$bDb&Xj(u~zoi4Z1G!LjgB_Xf zt3{o%_AgZbgs@R`Ajh#P%-M*5Jbu{<=~Ro|G@G}05{>IMIW7>);}lLqGvg_GSw5E- zRxHfSa!7Fn`vosFg4&Jt3e`DbA_12-k@)DgyU0@ za*89k?FL6>e8=W)zl;zb9G>VrS{Ws>t1>WiO5~+o<8UNdK09NJgVDCV?nLerF=lZA)9i#q34s~V!u?wA!-)6RtT5ym7S###E#$c21f_$ zWm2B@nSy@p<$1+66W6{+c9>UpF#e{{k^kLJC5|q6E=rR>vrAJoDUoA8%~O`!chIl%6D4_PS32F zpJ-cQ(*4mS*e}9cgXP^O-PFIuMVFcqD}61Aim8`ocF_F|7mlf5DBfK8Dj6rZrSkIVM&Li_;5i%B~T3MX16g{wlt>3%6) zH6#=mrZ$rCx?xBOaXeltwYp*&_~;3o3>P@KOEW}Dq)sK*Mo&OeA(lmbllB<(d$}ticdJ z=~tV+ymnJVF6 zwhkegd(Y?NVC3jEMS&-@0`F{PoY&c#In~dhs0gz9c2xmO$L$vJQH+s{ zjSc8TUeY2otsa5K&)KFYf2XJVINzsqA=cjfEmfH`eO@Q120eukk&hE--O2V#m}DhbCG?Nc_-IyYtWgqT6}y$h zz21CsO$&!XnZ!@@>KphHjn`KP*&2^bx)jASyPg&@knn!I*hM4cysH5m?K%8h^DQMXJm;vja-p)6gST`ta$+jn4dMv*I#8k-mmY2e9H6rPh* zo$rfSKEm+5HWkir3vZ(4n_AaW(J%$BlrO4}oG4K46xZg-oyhSA$pSj8PLESlU&Ag++9Pdk*s zl%uY0F{sMS>sX~(-u;=&ma$N2*%K>NGFCiU^pOi#MTtI~2%(TOy3FYun~@WYDP%V! zt5%ZoYbzUpP6BU@fvdKs$68z0|u=zO|1IGf1RHm`h6?=}};wzoTyCtMg2vT0>Oh~${RR$#{8K(*-n zMSzkpZok|xBLSAN^P#*>u|&T_jQhi6b(a45L~SiOb3&XxfGgJ`kSLrE>oadFCnCt&pLtjU5}i4xGvFl&d?g8k4@LY_flA|flCSd{?i20x0}44j!( zmUv~SA-Sr@BtvjI_vOgmm1U0@t*ArF-&VRFdK1w<$Wcm5uz*0?wU1yidGG7gQn~vm z5d;q~F7f>N1AScHOuFms7AaHBkjYe3ms#=#CHX>-s!ks_6;Np$%DPZ@nDu@}g0=%9 z5%gY7AW>_GSmx~kX$4rRRd37%9<62TX7!VNber%zw=RW!Y^9%I#^`Ui_J}T- zj^|cezH53zxp9}bh-uJ9Had` z5;kjF-?Z4)_5t}%?8<9o(wner>#jir05C`Z0KC7k%gM#j)ZEq8$iv#r%E;2(-rB+X z|3)u0EFIjxv%j;v%DfB?!qM4TSZmV0SoBW)>zH|lKvhUvDJj(HMD_T44M;yK@!P1k9!oLl!A|I7c$2%mpZ5XJ z&f0YN5lTG`73gC4(JNepoOA!0nl?Z1a?5y0I(8~dF718kzo+5-W-#XXU9yluKlQoe z4T{?0w{R%Hs(rYCji)>$1M@65vAI0I1)oplpmX3I?p=;L=pms{FyJaSw@9{@v}6R0 z>=nz(lWfR%=mkPlrY~RlgKN`&u!=T%Gyh}Mzs5r7?qlFqh`kw&+$r^Zm=^v^e?gq* z^C9{={k%2bC9c+zMg93}xi7l$ z_nd-MuqXBIaN@P zth6Xz$YzJKN8Hx~gn^&0u6QZ;y~HdDuKD{39|-qZ(h)Al6o&r$Pu}l6*DGrA^!aDw zXlkZJE{CeauZDJN3EUyHRX?Ne4W7Q6=NE{zzxzIwq?i}Lx@u+N9+dD1*6iZa&~S%P z6Ay5-h>zEDw-1GmIIi4F%HfmDPx74I|61Ay_jAy!xvMpmbeXqiw#8C4 z%RBS%JSkj^nNgtATG%0tdCm(*o|_QP(71JdCOLG;`NR_j-SAs>JjeA5B!T&9{ti;y zacpfyNmD`!#;=^HZPO2Uk$Jh8Hbe0IGH7`v1Ze6syN>bLWFn0>>qK-*cJm#hIgI!F~&(|TtwIXwF#~+^`FdB z#x7&}r4!VKiN(2UA!N?eckIV7nUDse4Enk)9hw~e<2#ccsxD+3c4I%+E-Eazo4A@f zE+V`QIZ34gEm^U&dVf*C>87CxN$ax9#co`9>TunMx`vOn^*{^d5}u9_oGDR5Pu(j8 zbt*tC>N34B+m2tGamg1-ES_qxSJCkHpYq`{F;D#d6x@t%ukh^s%{lN4EbL? z8@f-3GTq3u0lo$L3tyP{7SI9;;wwRjlwVc_PwGPA6pi~_ zG9zPU-*;Z@$d+YlO73@Oc;;jKL(_VLX$aZfD({VxX5DW=P}n@Ua{9(8Ts>3mwY zX)3nepJSXhSPT+Rtn5QWG;`x)Y5>++%D--{r8K+e6crEJoZr4&SGCD{`8D$?GOC3k z1)RvkJEat^U^omn>tl%aVoaGl5|yeR6Zi4#0q1pF;5yWC4{(cho+ozfco&Li>kTkQ zjG5mPOSK)mr*y8rVOy>AfOozo5psj(SQkFCvy)4-N083*YNJVsAZIA-v1;k*W$Q-? zz&QramjRDCY&iuL&Qe7zB6W0&7?P6i7PUBChFQI1xRj+B4Nj1a!YG{{-C^U>)~x?_ zZ=J=HKkY>>S&u4u1C9c5DM(nw`r5|G!3paOLE_BuYvU5it8Uw{Cpe*~`-GnAWr82j z)MTUA_=`t$XY`aQh{01J+lT8s_Xjgk!9+n3I(zwIq#q;);`Hd#lUg7B&9TwZ>+>TVsdLZ1=ML2B~J3;K{H2vwK6wpSsWZKm+y zYs1;Bku%FQ`CC+1z&l?=O4iSv8iYDik11TW%4-m4Yi(BNyWq(xHkLy{yz?MWH=)jnq1t?Tsia<-Fajf zU{R(jG>@Q*sUh*M^;j43=B(|t0nujU7g@^)gLu;IbyjI5f&6d|H?#hI$ZV$iT~h~) zJQ8CY&IjA>Sj>+>8#yo2R6;_=TQP}G$Ur~LCdtQpY0?%{MQe8Pv#~k5a!o}{U8ZG9 zzU>?mH{6197=g@5lRmqW1_Za+A(>AUl7HL=jA=~xk9&M3zHAQ|d$yxar`8Nuc#|EF z?y|IiPxguwRq9MhYy5~~(PA9~8**X$-Z2)cJ(zG3tc(n%C#|;IPC^AVnab4`TfjIl zu|qOvuk-|x9s;3axX1PzR&6_+#HL4iX0yS}^VsJopOAuid^cG2@QGZS8X}^zaWDl6 zN_UW;!U;?BEXqyv7{45{ol2Wvp}<)-I`9(b=E}P`9gSCBumDz6ynYT$H_t=0Wv$WAAI6 zS8r>(Xg9zfR-ltd5Ij)MM93t2a7Px z7_FR!nDed1jQxUe5Js)0+Z@$HDB-npVOHM$VPkx$s720`rL~uV8tZPE(iXM!Q&_)d z=tl+KXN^QGF8?xL0S?9fq$NGs*s|0sp{>^u zq7n)f_OX)TjxMb+;W__SP{90RR-QBq1MQ#7FbKoOllmM)$MMICqYK01iyiE zS!KmJ8$OsT@?=Q{cgloGAI9%e7PHdp6E4M?>GYF$p?47#hg&pTs`^%+|5)Nx>@1YC z*)x%d5lqCJz^8Vbz9LUY%0)i`6FhUZG`W}U-KT*10AFL z=5qshTQ6jORVaYpt7$A?m_?In<`iM!NsprS7~a8jvV_Gdj-^Tv`XdWvM90 zHdr9yf?;j%gAp3fvpypA;pEFyx9Erf$tzqcV%fq+?ix$JhM0EQ_#Q+~>_)7Cu?zgo zTk@1G4siS1k{73>J@{#E+9d9AEzY7=23VV0;&_hCcG$p+s^SYtys1-6$ZQM!Y} zdX4d2?CSEQQ#w>JvHfaIS1Xj1=f8c3dc)a*=(M?B@8Bnqg5VVbe=oy6Yx>VxI!6W@dHLuktEoUWo2~ z2jZpOE#4Qh+!hZL;@Hj=x+TVCLEK|r`4jma!9vB2HuE&+tZ_G$Ejcu;IbesL$#xB| z`BD|~XdrP(RU>;2`X_W*K3(Q|#v*=p{q}Ryruhlmy%0i#q*wAy3Io)9C>=&R(@j?E z+dBtavZovwim;&AaUOR4HDk%Q&`|uKawSHIQ! zvxw?j%prb92En@!mrGR>*A2)x{X>WYCXAH!Am^KH$+YMfxM=z)KW_L`c|$y-=eaEA zIjTSJB_>{MQz~iKvQsc=IX;ZVx+Y$A1-QW=GSY>yy>HiQ00SGnI1ldJi@BxU4cfcT z+ENm6xasl)4x`eb(l^Q*!Zmqve#H zdm@n1tei+4Dti0I=o_rTiU!%P)7M9DGlnnu$+ak)`%;o^zK}n*)w*!sP|A?HHWIj{ zQK21r~QS^C;1TiS+yh`tKvrUZ+zN3rI(E_!>`jLXe z%mP9US$}dggr{PO)uY*i4w(8z;a&9bX`R$N7~ub+B08vPyqco3b`Y;G)h=k`({XKf zn>=23R~Ua{r=fd?y7WuLc7e;R?=Z@85Rk%9|N9$`zn=Z?^%(fC z<9~b6@$V}CiD>^H4FKRV@XOy~@IU$Xzu*5)MB<wg4T{t}M= nWzzn4k^fY@{t>|<{hy^wSq|oJkplo={(iC$06;&*zyAIUQkCeN literal 0 HcmV?d00001 diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status.php new file mode 100755 index 0000000..7d3aa14 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status.php @@ -0,0 +1,44 @@ +prepare($sql); + $stmt->execute([ + ':invoice_number' => $invoice_number + ]); + + // جلب نتيجة الاستعلام + $invoice = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($invoice) { + // تم العثور على الفاتورة، أرجع حالتها الحالية + echo json_encode([ + "status" => "success", + "invoice_status" => $invoice['status'] // سيكون "pending" أو "completed" + ]); + } else { + // لم يتم العثور على فاتورة بهذا الرقم + printFailure("Invoice not found."); + } + +} catch (PDOException $e) { + // في حال حدوث خطأ في قاعدة البيانات + printFailure("Database error: " . $e->getMessage()); +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status_passenger.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status_passenger.php new file mode 100755 index 0000000..3b6167d --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status_passenger.php @@ -0,0 +1,36 @@ +prepare($sql); + $stmt->execute([':invoice_number' => $invoice_number]); + + $invoice = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($invoice) { + echo json_encode([ + "status" => "success", + "invoice_status" => $invoice['status'] // "pending" أو "completed" أو "failed" + ]); + } else { + printFailure("Invoice not found."); + } + +} catch (PDOException $e) { + printFailure("Database error: " . $e->getMessage()); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice.php new file mode 100755 index 0000000..5198a37 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice.php @@ -0,0 +1,103 @@ +prepare($sql_check); + $stmt_check->execute(['driverID' => $driverID, 'user_phone' => $user_phone]); + $existing = $stmt_check->fetch(PDO::FETCH_ASSOC); + + // إنشاء رقم فاتورة جديد ومميز + $new_invoice_number = random_int(100000, 999999); + + if ($existing) { + // --- 4a. تحديث الفاتورة المعلقة الحالية --- + // error_log("[CreateInvoice] Found existing pending invoice (ID: {$existing['id']}). Updating it."); + + $sql_update = "UPDATE invoices_sms SET invoice_number = :invoice_number, amount = :amount, created_at = NOW() WHERE id = :id"; + $stmt_update = $con->prepare($sql_update); + $stmt_update->execute([ + ':invoice_number' => $new_invoice_number, + ':amount' => $amount, + ':id' => $existing['id'] + ]); + + // error_log("[CreateInvoice] Invoice updated. New invoice number: {$new_invoice_number}"); + echo json_encode([ + "status" => "success", + "message" => "Pending invoice updated.", + "invoice_number" => $new_invoice_number + ]); + + } else { + // --- 4b. إنشاء فاتورة جديدة --- + // error_log("[CreateInvoice] No pending invoice found. Creating a new one."); + + $sql_insert = "INSERT INTO invoices_sms (invoice_number, driverID, user_phone, amount, status) VALUES (:invoice_number, :driverID, :user_phone, :amount, 'pending')"; + $stmt_insert = $con->prepare($sql_insert); + $ok = $stmt_insert->execute([ + ':invoice_number' => $new_invoice_number, + ':driverID' => $driverID, + ':user_phone' => $user_phone, + ':amount' => $amount + ]); + + if ($ok) { + // error_log("[CreateInvoice] New invoice created successfully. Invoice number: {$new_invoice_number}"); + echo json_encode([ + "status" => "success", + "message" => "New invoice created.", + "invoice_number" => $new_invoice_number + ]); + } else { + // error_log("[CreateInvoice] CRITICAL: Failed to execute INSERT statement."); + printFailure("Failed to create invoice."); + } + } + +} catch (PDOException $e) { + // تسجيل أخطاء قاعدة البيانات + // error_log("[CreateInvoice] PDOException: " . $e->getMessage()); + printFailure("Database error: " . $e->getMessage()); + +} catch (Throwable $e) { + // تسجيل أي أخطاء أخرى غير متوقعة + // error_log("[CreateInvoice] Throwable Exception: " . $e->getMessage()); + printFailure("An unexpected server error occurred."); +} + +//error_log("[CreateInvoice] --- Request Ended ---"); +?> + diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice_passenger.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice_passenger.php new file mode 100755 index 0000000..cd96d6c --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice_passenger.php @@ -0,0 +1,126 @@ +prepare($sql_check); + $stmt_check->execute([ + 'passengerID' => $passengerID, + 'user_phone' => $user_phone + ]); + $existing = $stmt_check->fetch(PDO::FETCH_ASSOC); + error_log("[CreateInvoicePassenger] Checked for existing pending invoice"); + + // ------------------------------------- + // 4) توليد رقم فاتورة جديد (6 أرقام) + // ------------------------------------- + $new_invoice_number = random_int(100000, 999999); + error_log("[CreateInvoicePassenger] Generated invoice number"); + + if ($existing) { + // ------------------------------------- + // 4a) تحديث الفاتورة المعلّقة الحالية + // ------------------------------------- + error_log("[CreateInvoicePassenger] Existing pending invoice found. Updating..."); + $sql_update = " + UPDATE invoices_sms_passenger + SET invoice_number = :invoice_number, + amount = :amount, + created_at = NOW() + WHERE id = :id + "; + $stmt_update = $con->prepare($sql_update); + $stmt_update->execute([ + ':invoice_number' => $new_invoice_number, + ':amount' => $amount, + ':id' => $existing['id'] + ]); + error_log("[CreateInvoicePassenger] Invoice updated successfully"); + + echo json_encode([ + "status" => "success", + "message" => "Pending passenger invoice updated.", + "invoice_number" => $new_invoice_number + ]); + error_log("[CreateInvoicePassenger] Response sent (update)"); + } else { + // ------------------------------------- + // 4b) إنشاء فاتورة جديدة + // ------------------------------------- + error_log("[CreateInvoicePassenger] No existing invoice. Creating new one..."); + $sql_insert = " + INSERT INTO invoices_sms_passenger (invoice_number, passengerID, user_phone, amount, status) + VALUES (:invoice_number, :passengerID, :user_phone, :amount, 'pending') + "; + $stmt_insert = $con->prepare($sql_insert); + $ok = $stmt_insert->execute([ + ':invoice_number' => $new_invoice_number, + ':passengerID' => $passengerID, + ':user_phone' => $user_phone, + ':amount' => $amount + ]); + + if ($ok) { + error_log("[CreateInvoicePassenger] New invoice created successfully"); + echo json_encode([ + "status" => "success", + "message" => "New passenger invoice created.", + "invoice_number" => $new_invoice_number + ]); + error_log("[CreateInvoicePassenger] Response sent (insert)"); + } else { + error_log("[CreateInvoicePassenger] Failed to create passenger invoice (DB insert)"); + printFailure("Failed to create passenger invoice."); + } + } + +} catch (PDOException $e) { + error_log("[CreateInvoicePassenger] Database exception: " . $e->getMessage()); + printFailure("Database error: " . $e->getMessage()); + +} catch (Throwable $e) { + error_log("[CreateInvoicePassenger] Unexpected exception: " . $e->getMessage()); + printFailure("An unexpected server error occurred."); +} + +error_log("[CreateInvoicePassenger] --- Request Ended ---"); \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_payout.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_payout.php new file mode 100755 index 0000000..10fbbb7 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_payout.php @@ -0,0 +1,127 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + + return $stmt->rowCount() > 0 ? $token : null; + } +} + +if (!function_exists('generatePaymentID')) { + /** + * دالة لإنشاء سجل دفعة جديد وإرجاع الـ ID الخاص به. + * هذا السجل هو المرجع الأساسي للمعاملة. + */ + function generatePaymentID(PDO $con, $driverId, $amount, $method): ?string { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; + } +} + + +if (!function_exists('finalizePayout')) { + /** + * دالة الإتمام الرئيسية لعمليات السحب. + * تقوم بتسجيل كل المعاملات في محافظ السائق والشركة وتحديث حالة الدفعات. + */ + function finalizePayout(PDO $con, int $payoutId) { + logPayoutError("START", "Starting finalization for payout ID: {$payoutId}"); + + try { + // 1. جلب بيانات طلب السحب المكتمل + $stmt = $con->prepare("SELECT * FROM `payout_requests` WHERE id = :id AND status = 'completed' LIMIT 1"); + $stmt->execute([':id' => $payoutId]); + $payout = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$payout) { + logPayoutError("FETCH_PAYOUT", "Payout request not found or not completed.", ['payoutId' => $payoutId]); + return false; + } + + $driverId = $payout['driver_id']; + $payoutFee = 3500; + $netAmount = (float)$payout['amount']-$payoutFee; // المبلغ الصافي الذي طلبه السائق + $totalDeducted = $netAmount; // المبلغ الإجمالي الذي سيتم خصمه + + // 2. إنشاء معرف دفع رئيسي لهذه المعاملة + // نسجل المبلغ الإجمالي المخصوم بالسالب + $paymentID = generatePaymentID($con, $driverId, -$totalDeducted, 'payout'); + if (!$paymentID) throw new Exception('Failed to generate master payment ID'); + logPayoutError("GEN_PAYMENT_ID", "Master Payment ID created: {$paymentID}"); + + // 3. إنشاء التوكنات اللازمة + $tokenDriver = generateToken($con, $driverId, -$totalDeducted); + $tokenSiro = generateToken($con, $driverId, $payoutFee); + if (!$tokenDriver || !$tokenSiro) throw new Exception('Failed to generate required tokens'); + logPayoutError("GEN_TOKENS", "Driver and Siro tokens generated successfully."); + + // 4. تسجيل معاملة الخصم في محفظة السائق (driverWallet) + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, + ':paymentID' => $paymentID, + ':amount' => -$totalDeducted, // تسجيل المبلغ بالسالب + ':paymentMethod' => 'payout' + ]); + if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed'); + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]); + logPayoutError("DRIVER_WALLET", "Negative transaction of {$totalDeducted} recorded in driverWallet."); + + // 5. تسجيل معاملة الربح (العمولة) في محفظة الشركة (siroWallet) + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token) VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token)"); + $insertSiro->execute([ + ':driverId' => $driverId, + ':passengerId' => 'payout_fee', // تمييز المعاملة كعمولة سحب + ':amount' => $payoutFee, // تسجيل العمولة بالموجب + ':paymentMethod' => 'payout_fee', + ':token' => $tokenSiro + ]); + if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed'); + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSiro]); + logPayoutError("SIRO_WALLET", "Fee transaction of {$payoutFee} recorded in siroWallet."); + + // 6. تحديث حالة الدفعات التي تم سحبها في جدول 'payments' + // هذا السطر يقوم بتحديث كل الدفعات المعلقة للسائق، معتبراً أن عملية السحب تغطيها + $updatePayments = $con->prepare("UPDATE payments SET isGiven = TRUE WHERE driverID = :driverId AND isGiven = FALSE"); + $updatePayments->execute([':driverId' => $driverId]); + logPayoutError("UPDATE_PAYMENTS", "Marked pending payments as 'isGiven' for driver {$driverId}. Rows affected: " . $updatePayments->rowCount()); + + logPayoutError("SUCCESS", "Payout finalization completed successfully for payout ID: {$payoutId}"); + return true; + + } catch (Throwable $e) { + logPayoutError("EXCEPTION", "An exception occurred: " . $e->getMessage(), ['payoutId' => $payoutId]); + return false; + } + } +} +?> + diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_wallet_payment.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_wallet_payment.php new file mode 100755 index 0000000..3e0a42f --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_wallet_payment.php @@ -0,0 +1,112 @@ +prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)"); + $stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]); + + return $stmt->rowCount() > 0 ? $token : null; +} + +/** + * دالة لإنشاء سجل دفعة جديد وإرجاع الـ ID الخاص به. + */ +function generatePaymentID($con, $driverId, $amount, $method): ?string { + $stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)"); + $stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]); + + return $stmt->rowCount() > 0 ? $con->lastInsertId() : null; +} + +/** + * دالة الإتمام الرئيسية، تم تعديلها لتستقبل ID الفاتورة مباشرة + */ +function finalizeWalletPaymentByInvoice($con, $invoiceId) { + logError("FINALIZE", "Starting finalization for invoice ID: {$invoiceId}"); + + try { + // 1. جلب بيانات الفاتورة المكتملة + $stmt = $con->prepare("SELECT * FROM `invoices_sms` WHERE id = :id AND status = 'completed' LIMIT 1"); + $stmt->execute([':id' => $invoiceId]); + $invoice = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$invoice) { + logError("FINALIZE", "Invoice not found or not completed", ['invoiceId' => $invoiceId]); + return false; + } + + $driverId = $invoice['driverID']; + $originalAmount = floatval($invoice['amount']); + $paymentMethod = $invoice['sender'] ?? 'sms'; + + // حساب المكافأة + $bonusAmount = match ((int)$originalAmount) { + 10000 => 10000.0, + 20000 => 21000.0, + 40000 => 45000.0, + 100000 => 110000.0, + default => $originalAmount, + }; + + // إنشاء التوكنات ومعرف الدفع + $tokenDriver = generateToken($con, $driverId, $bonusAmount); + $tokenSiro = generateToken($con, $driverId, $originalAmount); + $paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod); + + if (!$tokenDriver || !$tokenSiro || !$paymentID) { + throw new Exception('Failed to generate required tokens or payment ID'); + } + + // --- تحديث المحافظ --- + + // driverWallet + $insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)"); + $insertDriver->execute([ + ':driverID' => $driverId, ':paymentID' => $paymentID, + ':amount' => $bonusAmount, ':paymentMethod' => $paymentMethod + ]); + if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed'); + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]); + + // siroWallet + $insertSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod, token) VALUES (:driverId, 'driver', :amount, :paymentMethod, :token)"); + $insertSiro->execute([ + ':driverId' => $driverId, ':amount' => $originalAmount, + ':paymentMethod' => $paymentMethod, ':token' => $tokenSiro + ]); + if ($insertSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed'); + $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSiro]); + + logError("FINALIZE", "SUCCESS: Wallets updated successfully for invoice ID: {$invoiceId}"); + return true; + + } catch (Throwable $e) { + logError("FINALIZE", "EXCEPTION: " . $e->getMessage(), ['invoiceId' => $invoiceId]); + return false; + } +} +?> diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_passenger_sms_payment.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_passenger_sms_payment.php new file mode 100755 index 0000000..89b0100 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_passenger_sms_payment.php @@ -0,0 +1,255 @@ +prepare(" + SELECT id, message_body, sender + FROM raw_sms_log + WHERE status = 'pending' + ORDER BY created_at ASC + LIMIT 1 + "); + $stmt->execute(); + $sms = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$sms) { + echo json_encode(["status" => "idle", "message" => "No pending messages"]); + exit; + } +} catch (PDOException $e) { + printFailure("DB fetch error: " . $e->getMessage()); + exit; +} + +$smsId = (int)$sms['id']; +$body = (string)$sms['message_body']; +$sender = (string)$sms['sender']; // نستخدمه لاشتقاق طريقة الدفع + +/* ===== Prompt لِـ Gemini ===== */ +$prompt = "Analyze the following financial SMS and return ONLY a valid JSON object: +{ + \"transaction_type\": \"income\" | \"payout\", + \"amount\": number, + \"currency\": \"SYP\" | string (3 letters), + \"phone_number\": string | null +} +SMS Text: \"$body\""; + +$payload = ['contents' => [['parts' => [['text' => $prompt]]]]]; + +$ch = curl_init($geminiApiUrl); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); +curl_setopt($ch, CURLOPT_POST, true); +curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload, JSON_UNESCAPED_UNICODE)); +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +$curlErr = curl_error($ch); +curl_close($ch); + +if ($response === false) { + printFailure("Gemini curl error: " . $curlErr); + exit; +} + +$gem = json_decode($response, true); +$gemText = $gem['candidates'][0]['content']['parts'][0]['text'] ?? null; +if ($httpCode !== 200 || !$gemText) { + printFailure("Gemini HTTP $httpCode / empty response"); + exit; +} + +/* Gemini أحيانًا يحيط الـ JSON بعلامات Markdown */ +$clean = trim(str_replace(['```json','```JSON','```'], '', $gemText)); +$data = json_decode($clean, true); +if (!is_array($data) || empty($data['transaction_type'])) { + printFailure("Failed to parse Gemini JSON"); + exit; +} + +/* ===== القيم المستخرجة ===== */ +$trxType = strtolower((string)$data['transaction_type']); +$amount = isset($data['amount']) ? floatval($data['amount']) : 0.0; +$currency = isset($data['currency']) ? strtoupper((string)$data['currency']) : ''; +$phone = isset($data['phone_number']) ? (string)$data['phone_number'] : ''; + +/* ===== طريقة الدفع من الـ sender (الآن ثابتة shamcash كما طلبت) ===== */ +$paymentMethod = 'shamcash'; // أو اشتقاق ذكي: strpos(strtolower($sender),'sham') !== false ? 'shamcash' : 'unknown'; + +/* ===== فقط INCOME: نفّذ تدفّق الراكب ===== */ +if ($trxType === 'income' && $amount > 0 && $phone !== '') { + try { + // ابحث عن فاتورة راكب حديثة متطابقة خلال 60 دقيقة + $q = $con->prepare(" + SELECT id + FROM invoices_sms_passenger + WHERE status='pending' + AND user_phone = :p + AND amount = :a + AND created_at >= (NOW() - INTERVAL 60 MINUTE) + ORDER BY created_at DESC + LIMIT 1 + "); + $q->execute([':p' => $phone, ':a' => $amount]); + $inv = $q->fetch(PDO::FETCH_ASSOC); + + if (!$inv) { + printFailure( "No matching passenger invoice"); + exit; + } + + $invoiceId = $inv['id']; + + // حدّث حالة الفاتورة + $con->prepare("UPDATE invoices_sms_passenger SET status='completed', updated_at=NOW() WHERE id=:id") + ->execute([':id' => $invoiceId]); + + // احضر بيانات الفاتورة لمعرفة passengerID والمبلغ المؤكد + $st = $con->prepare("SELECT passengerID, amount FROM invoices_sms_passenger WHERE id=:id LIMIT 1"); + $st->execute([':id' => $invoiceId]); + $row = $st->fetch(PDO::FETCH_ASSOC); + if (!$row) { + printFailure("Invoice row not found after update"); + exit; + } + + $passengerId = $row['passengerID']; + $amt = floatval($row['amount']); + + // 1) Bonus + $finalAmount = calculateBonus($amt); + + // 2) Generate payment token (للراكب) + $token = generatePaymentToken($passengerId, $finalAmount); + + // 3) Add to Passenger Wallet + $walletResult = addToPassengerWallet($passengerId, $finalAmount, $token); + + // 4) Add to Siro Wallet (محاسبي) بطريقة الدفع المستخلصة من sender + $token2 = generatePaymentToken($passengerId, $amt); + $siroWalletResult = addToSiroWallet($passengerId, $amt, $paymentMethod, $token2); + + printSuccess([ + "message" => "Passenger income processed", + "invoice_id" => $invoiceId, + "passenger_id" => $passengerId, + "amount" => $amt, + "final_amount" => $finalAmount, + "payment_method" => $paymentMethod, + "wallet" => $walletResult, + "siroWallet" => $siroWalletResult, + "sender" => $sender + ]); + exit; + + } catch (PDOException $e) { + printFailure("DB income error: " . $e->getMessage()); + exit; + } +} + +/* غير مدعوم الآن (payout أو مدخلات ناقصة) */ +printFailure([ + "status" => "ignored", + "message" => "Unsupported or incomplete transaction", + "type" => $trxType, + "sender" => $sender +]); +exit; + +/* ===== Helpers — تعتمد على BASE_URL الموجودة عندك ===== */ + +function calculateBonus($amount) { + if ($amount == 20000) return 20500; + if ($amount == 40000) return 42500; + if ($amount == 100000) return 104000; + return $amount; +} + +function generatePaymentToken($passengerId, $amount) { + if (!defined('BASE_URL')) return null; // نعتمد وجودها لديك + $url = rtrim(BASE_URL, '/') . "/passengerWallet/addPaymentTokenPassenger.php"; + $post = ['passengerId' => $passengerId, 'amount' => $amount]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post)); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($code != 200 || !$resp) return null; + $j = json_decode($resp, true); + return $j['message'] ?? null; +} + +function addToPassengerWallet($passengerId, $amount, $token) { + if (!defined('BASE_URL')) return null; + $url = rtrim(BASE_URL, '/') . "/passengerWallet/add.php"; + $post = ['passenger_id' => $passengerId, 'balance' => $amount, 'token' => $token]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post)); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($code != 200 || !$resp) return null; + return json_decode($resp, true); +} + +function addToSiroWallet($passengerId, $amount, $paymentMethod, $token) { + if (!defined('BASE_URL')) return null; + $url = rtrim(BASE_URL, '/') . "/siroWallet/add.php"; + $post = [ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, // من sender + 'passengerId' => $passengerId, + 'token' => $token, + 'driverId' => 'passenger' + ]; + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post)); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($code != 200 || !$resp) return null; + return json_decode($resp, true); +} \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_with_gemini.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_with_gemini.php new file mode 100755 index 0000000..b3de420 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_with_gemini.php @@ -0,0 +1,132 @@ +prepare("SELECT id, message_body FROM `raw_sms_log` WHERE `status` = 'pending' ORDER BY created_at ASC LIMIT 1"); +$stmt_fetch->execute(); +$sms = $stmt_fetch->fetch(PDO::FETCH_ASSOC); + +if (!$sms) { + exit("No pending messages found.\n"); +} + +$sms_id = $sms['id']; +$sms_text = $sms['message_body']; + +// 2. بناء الطلب (Prompt) الذكي إلى Gemini +$prompt = "Analyze the following financial SMS and return ONLY a valid JSON object. +- `transaction_type`: Must be 'income' (money received) or 'payout' (money sent). +- `amount`: Must be a number (float). +- `currency`: Must be a 3-letter code (e.g., SYP). +- `phone_number`: The phone number of the other party. Must be a string, or `null` if not found. + +SMS Text: \"$sms_text\""; + +$payload = ['contents' => [['parts' => [['text' => $prompt]]]]]; + +// 3. إرسال الطلب إلى Gemini API +$ch = curl_init($geminiApiUrl); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); +curl_setopt($ch, CURLOPT_POST, true); +curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); +$response = curl_exec($ch); +$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +// 4. معالجة رد Gemini +$result = json_decode($response, true); +$gemini_text_response = $result['candidates'][0]['content']['parts'][0]['text'] ?? null; + +if ($httpcode == 200 && $gemini_text_response) { + $clean_json_str = trim(str_replace(['```json', '```'], '', $gemini_text_response)); + $data = json_decode($clean_json_str, true); + + if ($data && isset($data['transaction_type'])) { + // --- نجحت المعالجة: استخراج البيانات --- + $phone_raw = $data['phone_number'] ?? null; + $amount = isset($data['amount']) ? (float)$data['amount'] : 0; + + // توحيد صيغة رقم الهاتف (مثال بسيط) + $phone_norm = $phone_raw; // يمكنك إضافة منطق أكثر تعقيداً هنا إذا لزم الأمر + + if ($data['transaction_type'] === 'income' && !empty($phone_norm) && $amount > 0) { + // البحث عن فاتورة مطابقة خلال آخر 60 دقيقة + $q = $con->prepare("SELECT id FROM invoices_sms WHERE status='pending' AND user_phone=:p AND amount=:a AND created_at >= (NOW() - INTERVAL 60 MINUTE) ORDER BY created_at DESC LIMIT 1"); + $q->execute([':p' => $phone_norm, ':a' => $amount]); + $inv = $q->fetch(PDO::FETCH_ASSOC); + + if ($inv) { + // تم العثور على فاتورة مطابقة -> قم بتحديثها وتنفيذ الإجراء النهائي + $con->prepare("UPDATE invoices_sms SET status='completed' WHERE id=:id")->execute([':id' => $inv['id']]); + + // افترض أن هذه الدالة موجودة في ملف jwtconnect.php أو ملف مساعد آخر + $ok = function_exists('finalizeWalletPaymentByInvoice') ? finalizeWalletPaymentByInvoice($con, $inv['id']) : false; + $note = $ok ? 'finalized' : 'finalize_failed'; + + $con->prepare("UPDATE raw_sms_log SET status='processed', gemini_result=:r WHERE id=:id")->execute([':r' => json_encode($data, JSON_UNESCAPED_UNICODE), ':id' => $sms_id]); + echo "Income matched -> invoice {$inv['id']} -> $note\n"; + + } else { + // لم يتم العثور على فاتورة مطابقة + $con->prepare("UPDATE raw_sms_log SET status='failed', gemini_result=:r WHERE id=:id")->execute([':r' => json_encode(['warn' => 'no pending invoice match', 'parsed' => $data], JSON_UNESCAPED_UNICODE), ':id' => $sms_id]); + echo "No matching pending invoice found.\n"; + } + + } elseif ($data['transaction_type'] === 'payout' && !empty($phone_norm) && $amount > 0) { + // --- منطق معالجة الدفعات الصادرة --- + $q = $con->prepare("SELECT id FROM payout_requests WHERE status='pending' AND driver_phone=:p AND amount=:a ORDER BY created_at DESC LIMIT 1"); + $q->execute([':p' => $phone_norm, ':a' => $amount]); + $payout = $q->fetch(PDO::FETCH_ASSOC); + + if ($payout) { + // تم العثور على طلب سحب مطابق -> قم بتحديثه واستدعاء الإتمام + $payout_id = $payout['id']; + $con->prepare("UPDATE payout_requests SET status='completed', completed_at=NOW() WHERE id=:id")->execute([':id' => $payout_id]); + + include_once __DIR__ . '/finalize_payout.php'; + if (function_exists('finalizePayout')) { + finalizePayout($con, $payout_id); + $note = "Payout request {$payout_id} finalized."; + } else { + $note = "CRITICAL: finalizePayout function not found!"; + } + + $con->prepare("UPDATE raw_sms_log SET status='processed', gemini_result=:r WHERE id=:id")->execute([':r'=>json_encode($data), ':id'=>$sms_id]); + error_log("[ProcessGemini] $note"); + + } else { + // لم يتم العثور على طلب سحب مطابق + $con->prepare("UPDATE raw_sms_log SET status='failed', gemini_result=:r WHERE id=:id")->execute([':r'=>json_encode(['warn'=>'no pending payout match', 'parsed'=>$data]), ':id'=>$sms_id]); + error_log("[ProcessGemini] No matching pending payout found for SMS ID {$sms_id}"); + } +} + + } else { + // فشل تحليل رد Gemini + $stmt_update = $con->prepare("UPDATE `raw_sms_log` SET `status` = 'failed', `gemini_result` = :result WHERE `id` = :id"); + $stmt_update->execute([':result' => json_encode(['error' => "Failed to parse Gemini's JSON response", 'response' => $gemini_text_response]), ':id' => $sms_id]); + echo "Failed to parse Gemini's JSON response for message ID $sms_id.\n"; + } +} else { + // لم يتم استلام رد من Gemini أو حدث خطأ في الطلب + $stmt_update = $con->prepare("UPDATE `raw_sms_log` SET `status` = 'failed', `gemini_result` = :result WHERE `id` = :id"); + $stmt_update->execute([':result' => json_encode(['error' => 'No valid response from Gemini API', 'http_code' => $httpcode]), ':id' => $sms_id]); + echo "No valid response from Gemini API for message ID $sms_id. HTTP Code: $httpcode\n"; +} +?> + diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/request_payout.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/request_payout.php new file mode 100755 index 0000000..8bb77ff --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/request_payout.php @@ -0,0 +1,84 @@ +prepare(" + SELECT SUM(amount) AS balance + FROM driverWallet + WHERE driverID = :id + LIMIT 1 + "); + $stmt_driver->execute([':id' => $driverId]); + $driver = $stmt_driver->fetch(PDO::FETCH_ASSOC); + + if (!$driver) { + printFailure("Driver not found."); + exit; + } + + $payout_fee = 3500.00; // عمولة السحب + $total_deduction = $amount + $payout_fee; // المبلغ المطلوب مع العمولة + + if ($driver['balance'] < $total_deduction) { + printFailure("Insufficient balance. Required: $total_deduction"); + exit; + } + + // --- 3. إنشاء طلب السحب في قاعدة البيانات --- + $sql = " + INSERT INTO payout_requests (driver_id, driver_phone, amount, wallet_type) + VALUES (:did, :phone, :amount, :wallet) + "; + $stmt = $con->prepare($sql); + $stmt->execute([ + ':did' => $driverId, + ':phone' => $phone, + ':amount'=> $amount, + ':wallet'=> $wallet_type + ]); + + if ($stmt->rowCount() > 0) { + // --- 4. إرسال إشعار لخدمة العملاء --- + $customerServicePhone = getenv('CUSTOMER_SERVICE_PHONE'); + + $message = + "⚠️ طلب دفع جديد:\n" . + "ID السائق: {$driverId}\n" . + "هاتف السائق: {$phone}\n" . + "نوع المحفظة: {$wallet_type}\n" . + "المبلغ: {$amount} SYP\n\n" . + "الرجاء من فريق خدمة العملاء تنفيذ عملية الدفع الآن."; + + // الإرسال (الفنكشن مُضمّن لديك مسبقًا) + sendWhatsAppFromServer($customerServicePhone, $message); + + error_log("[RequestPayout] Successfully created payout request for driver ID: $driverId"); + printSuccess("Payout request created successfully. It will be processed shortly."); + } else { + printFailure("Failed to create payout request."); + } + +} catch (PDOException $e) { + error_log("[RequestPayout] PDOException: " . $e->getMessage()); + printFailure("A database error occurred."); +} +?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms.php new file mode 100755 index 0000000..c949996 --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms.php @@ -0,0 +1,37 @@ +prepare($sql); + $stmt->execute([':sender' => $data['sender'], ':message' => $data['message']]); + + // --- خطوة مهمة: تفعيل سكربت المعالجة في الخلفية --- + // هذا الأمر يجعل سكربت التحليل يعمل فورًا دون أن ينتظر المستخدم + // تأكد من أن المسار صحيح تمامًا على سيرفرك + $command = "php " . __DIR__ . "/process_with_gemini.php > /dev/null 2>&1 &"; + shell_exec($command); + + http_response_code(200); + echo json_encode(['status' => 'success', 'message' => 'SMS received and scheduled for processing.']); + + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]); + } +} else { + http_response_code(400); + echo json_encode(['status' => 'error', 'message' => 'Invalid data provided.']); +} +?> + diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms_passenger.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms_passenger.php new file mode 100755 index 0000000..6b97b4d --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms_passenger.php @@ -0,0 +1,37 @@ +prepare($sql); + $stmt->execute([':sender' => $data['sender'], ':message' => $data['message']]); + + // --- خطوة مهمة: تفعيل سكربت المعالجة في الخلفية --- + // هذا الأمر يجعل سكربت التحليل يعمل فورًا دون أن ينتظر المستخدم + // تأكد من أن المسار صحيح تمامًا على سيرفرك + $command = "php " . __DIR__ . "/process_passenger_sms_payment.php > /dev/null 2>&1 &"; + shell_exec($command); + + http_response_code(200); + echo json_encode(['status' => 'success', 'message' => 'SMS received and scheduled for processing.']); + + } catch (PDOException $e) { + http_response_code(500); + echo json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]); + } +} else { + http_response_code(400); + echo json_encode(['status' => 'error', 'message' => 'Invalid data provided.']); +} +?> + diff --git a/walletintaleq.intaleq.xyz/v2/main/sms_webhook/webhook.php b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/webhook.php new file mode 100755 index 0000000..a08954c --- /dev/null +++ b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/webhook.php @@ -0,0 +1,84 @@ + "error", "message" => "Authentication failed."]); + exit; +} + +$json_data = file_get_contents('php://input'); +$data = json_decode($json_data, true); + +if ($data === null || !isset($data['sender']) || !isset($data['message'])) { + http_response_code(400); // Bad Request + echo json_encode(['status' => 'error', 'message' => 'Invalid JSON data received']); + exit(); +} + +// --- 2. استخراج البيانات --- +$sender = $data['sender']; +$message_body = $data['message']; +$received_at = date('Y-m-d H:i:s'); +$log_entry = "[$received_at] From: $sender | Message: $message_body"; + +// --- 3. تحليل الرسالة (يركز على Orange Money حالياً) --- +$pattern_orangemoney_jo = '/تم استقبال حوالة مالية من (\d+)\s+من مزود الخدمة:\s+Orange Money إلى محفظتك بمبلغ ([\d,.]+)\s+دينار/'; + +if (preg_match($pattern_orangemoney_jo, $message_body, $matches)) { + $payer_phone_raw = $matches[1]; + $amount_str = $matches[2]; + $amount = (float) str_replace(',', '', $amount_str); + + // توحيد صيغة رقم الهاتف (إزالة 0096 إذا وجدت وإضافة 0) + $payer_phone = $payer_phone_raw; + if (substr($payer_phone_raw, 0, 4) === '0096') { + $payer_phone = '0' . substr($payer_phone_raw, 4); + } + + $log_entry .= " | MATCH: Orange Money | SUCCESS: Parsed Amount = $amount, Payer Phone = $payer_phone"; + + // --- 4. منطق تحديث الفاتورة --- + try { + // البحث عن أحدث فاتورة مطابقة (نفس الرقم والمبلغ) بحالة انتظار وتحديثها + $sql = "UPDATE invoices_sms SET status = 'completed' + WHERE user_phone = :phone + AND amount = :amount + AND status = 'pending' + ORDER BY created_at DESC + LIMIT 1"; + + $stmt = $con->prepare($sql); + $stmt->execute([ + ':phone' => $payer_phone, + ':amount' => $amount + ]); + + if ($stmt->rowCount() > 0) { + $log_entry .= " | DB: SUCCESS - Invoice found and updated." . PHP_EOL; + // يمكنك هنا إضافة كود لإرسال إشعار للمستخدم + } else { + $log_entry .= " | DB: WARNING - No pending invoice found for this transaction." . PHP_EOL; + } + + } catch (PDOException $e) { + $log_entry .= " | DB: ERROR - " . $e->getMessage() . PHP_EOL; + } + +} else { + $log_entry .= " | INFO: Message did not match any known payment pattern. Ignored." . PHP_EOL; +} + +// كتابة السجل (مهم لتصحيح الأخطاء) +file_put_contents('sms_log.txt', $log_entry, FILE_APPEND); + +// إرسال رد إلى تطبيق الأندرويد +http_response_code(200); +echo json_encode(['status' => 'success', 'message' => 'Webhook processed.']); +?>