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 0000000..b3aa417 Binary files /dev/null and b/walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php.zip differ 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 0000000..c922a89 Binary files /dev/null and b/walletintaleq.intaleq.xyz/v2/main/ride/syriatel/archive.zip differ 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 0000000..fc138a6 Binary files /dev/null and b/walletintaleq.intaleq.xyz/v2/main/sms_webhook/archive.zip differ 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.']); +?>