Update: 2026-06-16 22:44:11
This commit is contained in:
460
INFRASTRUCTURE_REPORT.md
Normal file
460
INFRASTRUCTURE_REPORT.md
Normal file
@@ -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 للمدفوعات
|
||||||
|
---
|
||||||
289
scratch/payment_simulation.py
Normal file
289
scratch/payment_simulation.py
Normal file
@@ -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()
|
||||||
File diff suppressed because one or more lines are too long
970
walletintaleq.intaleq.xyz/WalletDB.sql
Normal file
970
walletintaleq.intaleq.xyz/WalletDB.sql
Normal file
@@ -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 */;
|
||||||
@@ -1,4 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* jwtconnect.php — Unified Authentication Gateway (بوابة المصادقة الموحدة)
|
||||||
|
*
|
||||||
|
* ═══════════════════════════════════════════════════════════════
|
||||||
|
* SECURITY UPGRADE: هذا الملف أصبح بوابة مصادقة إجبارية.
|
||||||
|
* كل طلب يجب أن يمر بأحد المسارات التالية:
|
||||||
|
*
|
||||||
|
* Path 1: S2S API Key → X-S2S-Api-Key header
|
||||||
|
* Path 2: Payment Key → PAYMENT_KEY header
|
||||||
|
* Path 3: Webhook Token → X-Auth-Token header
|
||||||
|
* Path 4: Cron Key / CLI → X-Cron-Key header أو CLI execution
|
||||||
|
* Path 5: JWT (default) → Authorization: Bearer <token>
|
||||||
|
*
|
||||||
|
* أي طلب بدون أي مصادقة → يُرفض تلقائياً من authenticateJWT()
|
||||||
|
* ═══════════════════════════════════════════════════════════════
|
||||||
|
*/
|
||||||
|
|
||||||
// Load environment variables from .env file
|
// Load environment variables from .env file
|
||||||
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
||||||
require_once 'load_env.php';
|
require_once 'load_env.php';
|
||||||
@@ -10,7 +27,7 @@ $secretKey = getenv('SECRET_KEY'); // Only need the secret key now
|
|||||||
|
|
||||||
// --- CORS Headers ---
|
// --- CORS Headers ---
|
||||||
$allowedOrigins = [
|
$allowedOrigins = [
|
||||||
'https://walletintaleq.intaleq.xyz',
|
|
||||||
'https://wallet.siromove.com',
|
'https://wallet.siromove.com',
|
||||||
'https://wallet-syria.siromove.com',
|
'https://wallet-syria.siromove.com',
|
||||||
'https://wallet-egypt.siromove.com',
|
'https://wallet-egypt.siromove.com',
|
||||||
@@ -22,17 +39,19 @@ if (in_array($origin, $allowedOrigins)) {
|
|||||||
} else {
|
} else {
|
||||||
header("Access-Control-Allow-Origin: https://walletintaleq.intaleq.xyz");
|
header("Access-Control-Allow-Origin: https://walletintaleq.intaleq.xyz");
|
||||||
}
|
}
|
||||||
header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // Adjust as needed
|
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
|
||||||
header("Access-Control-Allow-Headers: Content-Type, Authorization");
|
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'); // Set content type to JSON
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
// Handle preflight requests (OPTIONS)
|
// Handle preflight requests (OPTIONS)
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
||||||
http_response_code(200);
|
http_response_code(200);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
$dbname = getenv('dbname');
|
|
||||||
// --- Database Connection (Still needed for your application logic) ---
|
$dbname = getenv('dbname');
|
||||||
|
|
||||||
|
// --- Database Connection ---
|
||||||
try {
|
try {
|
||||||
$dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4";
|
$dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4";
|
||||||
$options = [
|
$options = [
|
||||||
@@ -41,19 +60,75 @@ try {
|
|||||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8"
|
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8"
|
||||||
];
|
];
|
||||||
$user = getenv('USER'); // Still used for DB connection
|
$user = getenv('USER');
|
||||||
$pass = getenv('PASS'); // Still used for DB connection
|
$pass = getenv('PASS');
|
||||||
$con = new PDO($dsn, $user, $pass, $options);
|
$con = new PDO($dsn, $user, $pass, $options);
|
||||||
|
|
||||||
// --- JWT Authentication ---
|
// --- Load Functions ---
|
||||||
include "functions.php"; // Include the functions file
|
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) {
|
} catch (PDOException $e) {
|
||||||
error_log($e->getMessage());
|
error_log($e->getMessage());
|
||||||
http_response_code(500); // Internal Server Error
|
http_response_code(500);
|
||||||
echo json_encode(['error' => 'A database error occurred.']);
|
echo json_encode(['error' => 'A database error occurred.']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.');
|
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)");
|
$stmtSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)");
|
||||||
$stmtSefer->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
$stmtSiro->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
||||||
if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed.');
|
if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed.');
|
||||||
|
|
||||||
return ['success' => true, 'message' => 'Driver wallets updated.'];
|
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.');
|
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)");
|
$stmtSiro = $con->prepare("INSERT INTO siroWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)");
|
||||||
$stmtSefer->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
$stmtSiro->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
||||||
if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet for passenger failed.');
|
if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet for passenger failed.');
|
||||||
|
|
||||||
return ['success' => true, 'message' => 'Passenger wallets updated.'];
|
return ['success' => true, 'message' => 'Passenger wallets updated.'];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,104 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* driverWallet/add.php — إضافة رصيد لمحفظة السائق
|
||||||
|
*
|
||||||
|
* ═══════════════════════════════════════════════════════════════
|
||||||
|
* SECURITY FIX:
|
||||||
|
* - إضافة التحقق من ملكية الحساب (driverID == JWT user_id)
|
||||||
|
* - لف العملية في Transaction ذرية
|
||||||
|
* - استخدام FOR UPDATE لمنع Race Condition على التوكن
|
||||||
|
* - التحقق من صحة المبلغ
|
||||||
|
* ═══════════════════════════════════════════════════════════════
|
||||||
|
*/
|
||||||
|
|
||||||
// Include the database connection file
|
// Include the database connection file (calls authenticateJWT)
|
||||||
include "../../connect.php";
|
include "../../connect.php";
|
||||||
//ride/driverWallet/add.php
|
|
||||||
// Get the request parameters
|
// ── 1. استخراج user_id من JWT المصادق ──────────────────────────
|
||||||
$driverID = filterRequest("driverID");
|
$jwtUserId = $decodedToken->user_id ?? $decodedToken->sub ?? null;
|
||||||
$paymentID = filterRequest("paymentID");
|
|
||||||
$amount = filterRequest("amount");
|
// ── 2. استخراج والتحقق من البيانات ──────────────────────────
|
||||||
|
$driverID = filterRequest("driverID");
|
||||||
|
$paymentID = filterRequest("paymentID");
|
||||||
|
$amount = filterRequest("amount");
|
||||||
$paymentMethod = filterRequest("paymentMethod");
|
$paymentMethod = filterRequest("paymentMethod");
|
||||||
$token = filterRequest("token");
|
$token = filterRequest("token");
|
||||||
|
|
||||||
// Retrieve token details from the database
|
if (empty($driverID) || !isset($amount) || empty($paymentMethod) || empty($token)) {
|
||||||
$stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE");
|
printFailure("Missing required parameters");
|
||||||
$stmt->execute(array(
|
exit;
|
||||||
':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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,67 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* addFromAdmin.php — إضافة رصيد من المسؤول (Admin Only)
|
||||||
|
*
|
||||||
|
* ═══════════════════════════════════════════════════════════════
|
||||||
|
* SECURITY FIX: كان هذا الملف بدون أي مصادقة! ❌
|
||||||
|
* الآن يتطلب:
|
||||||
|
* 1. JWT مصادق (عبر authenticateJWT)
|
||||||
|
* 2. التحقق من دور المسؤول (admin role)
|
||||||
|
* 3. التحقق من المبلغ (حد أقصى)
|
||||||
|
* 4. تسجيل تدقيق لكل عملية (audit log)
|
||||||
|
* ═══════════════════════════════════════════════════════════════
|
||||||
|
*/
|
||||||
|
|
||||||
// Include the database connection file
|
// Include the database connection WITH JWT authentication
|
||||||
include "../../jwtconnect.php";
|
include "../../connect.php";
|
||||||
//ride/driverWallet/add.php
|
// connect.php calls authenticateJWT() → 5-layer security check ✅
|
||||||
// Get the request parameters
|
|
||||||
$driverID = filterRequest("driverID");
|
// ── 1. استخراج user_id من JWT المصادق ──────────────────────────
|
||||||
$paymentID = filterRequest("paymentID");
|
$adminUserId = $decodedToken->user_id ?? $decodedToken->sub ?? null;
|
||||||
$amount = filterRequest("amount");
|
$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");
|
$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` (
|
$sql = "INSERT INTO `driverWallet` (
|
||||||
`driverID`,
|
`driverID`,
|
||||||
`paymentID`,
|
`paymentID`,
|
||||||
@@ -25,27 +75,51 @@ $phone = filterRequest("phone");
|
|||||||
);";
|
);";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->execute(array(
|
$stmt->execute([
|
||||||
':driverID' => $driverID,
|
':driverID' => $driverID,
|
||||||
':paymentID' => $paymentID,
|
':paymentID' => $paymentID ?? ('admin_' . time() . '_' . bin2hex(random_bytes(4))),
|
||||||
':amount' => $amount,
|
':amount' => $amount,
|
||||||
':paymentMethod' => $paymentMethod
|
':paymentMethod' => $paymentMethod
|
||||||
));
|
]);
|
||||||
|
|
||||||
if ($stmt->rowCount() > 0) {
|
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");
|
printSuccess("Record saved successfully");
|
||||||
$messageBody = "تم إضافة رصيد بقيمة $amount إلى محفظتك بنجاح."; // "Balance of $amount added successfully."
|
|
||||||
|
|
||||||
sendWhatsAppFromServer($phone, $messageBody);
|
// إرسال إشعار واتساب للسائق
|
||||||
|
if (!empty($phone)) {
|
||||||
// Mark the token as used in the database
|
$messageBody = "تم إضافة رصيد بقيمة $amount إلى محفظتك بنجاح.";
|
||||||
/* $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID");
|
sendWhatsAppFromServer($phone, $messageBody);
|
||||||
$stmt->execute(array(
|
}
|
||||||
':tokenID' => $tokenData['id']
|
|
||||||
));*/
|
|
||||||
} else {
|
} else {
|
||||||
// Print a failure message
|
$con->rollBack();
|
||||||
printFailure("Failed to save record");
|
printFailure("Failed to save record");
|
||||||
}
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if ($con->inTransaction()) {
|
||||||
|
$con->rollBack();
|
||||||
|
}
|
||||||
|
error_log("[addFromAdmin] Error: " . $e->getMessage());
|
||||||
|
printFailure("An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,28 +91,28 @@ if ($language === 'ar') {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<img src='https://lh3.googleusercontent.com/a/ACg8ocLe5TgvmTjoFx7KjIoWGxX0G2ryKBTzUZi2-mBYb9DI1dsKQ0WEYh5ZPdnA3WeFbp9VnaTNzJuA0w8S4RiQ7042AKrOwXo3=s576-c-no' alt='SEFER App Logo' style='width: 150px; margin: 20px auto; display: block;'>
|
<img src='https://lh3.googleusercontent.com/a/ACg8ocLe5TgvmTjoFx7KjIoWGxX0G2ryKBTzUZi2-mBYb9DI1dsKQ0WEYh5ZPdnA3WeFbp9VnaTNzJuA0w8S4RiQ7042AKrOwXo3=s576-c-no' alt='SIRO App Logo' style='width: 150px; margin: 20px auto; display: block;'>
|
||||||
|
|
||||||
<h1>Your SEFER Transfer Details</h1>
|
<h1>Your SIRO Transfer Details</h1>
|
||||||
<p>Thank you for using our service. We hope you have a great day!</p>
|
<p>Thank you for using our service. We hope you have a great day!</p>
|
||||||
<p>We want to inform you that an amount of $amount has been transferred from your account to the new driver: $newDriverName (Phone: $driverPhone).</p>
|
<p>We want to inform you that an amount of $amount has been transferred from your account to the new driver: $newDriverName (Phone: $driverPhone).</p>
|
||||||
<p>Regards,<br> SEFER Team</p>
|
<p>Regards,<br> SIRO Team</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>";
|
</html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Email headers
|
// Email headers
|
||||||
$supportEmail = 'seferteam@sefer.live';
|
$supportEmail = 'siroteam@siro.live';
|
||||||
$headers = "MIME-Version: 1.0\r\n";
|
$headers = "MIME-Version: 1.0\r\n";
|
||||||
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
|
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
|
||||||
$headers .= "From: $supportEmail\r\n";
|
$headers .= "From: $supportEmail\r\n";
|
||||||
|
|
||||||
// Send email
|
// Send email
|
||||||
if (!empty($driverEmail)) {
|
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.";
|
echo "Email sent successfully.";
|
||||||
} else {
|
} else {
|
||||||
echo "Email sending failed.";
|
echo "Email sending failed.";
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ try {
|
|||||||
$paymentID2 = "transfer_recv_" . time() . bin2hex(random_bytes(4));
|
$paymentID2 = "transfer_recv_" . time() . bin2hex(random_bytes(4));
|
||||||
$token1 = bin2hex(random_bytes(32));
|
$token1 = bin2hex(random_bytes(32));
|
||||||
$token2 = 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)
|
// 4. Deduct from Sender (payments table)
|
||||||
$deductAmount = -$amount;
|
$deductAmount = -$amount;
|
||||||
@@ -108,12 +108,12 @@ try {
|
|||||||
':token' => $token2
|
':token' => $token2
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 6. Add Fee to Sefer Wallet
|
// 6. Add Fee to Siro Wallet
|
||||||
$stmt = $con->prepare("INSERT INTO seferWallet (amount, paymentMethod, passengerId, token, driverId)
|
$stmt = $con->prepare("INSERT INTO siroWallet (amount, paymentMethod, passengerId, token, driverId)
|
||||||
VALUES (:fee, 'payout fee', 'driver', :token, :senderID)");
|
VALUES (:fee, 'payout fee', 'driver', :token, :senderID)");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
':fee' => $fee,
|
':fee' => $fee,
|
||||||
':token' => $seferToken,
|
':token' => $siroToken,
|
||||||
':senderID' => $senderID
|
':senderID' => $senderID
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
148
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_verify.php
Executable file
148
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_verify.php
Executable file
@@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// هذا الملف هو نقطة النهاية بعد الدفع، ويقوم بكل عمليات التحقق وإضافة الرصيد
|
||||||
|
// This file is the final endpoint after payment, handling all verification and balance updates.
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
// دوال مساعدة لإنشاء التوكنات ومعرفات الدفع
|
||||||
|
// Helper functions for creating tokens and payment IDs
|
||||||
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* إنشاء توكن فريد لعملية المحفظة وتخزينه في قاعدة البيانات
|
||||||
|
* Creates a unique token for a wallet transaction and stores it in the database.
|
||||||
|
*/
|
||||||
|
define("BASE_URL", "https://wl.tripz-egypt.com/v1/main/ride"); // تأكد من صحة هذا الرابط
|
||||||
|
define("LOG_FILE", "../logs/payment_verification.log");
|
||||||
|
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateToken($con, $driverId, $amount): ?string
|
||||||
|
{
|
||||||
|
global $secretKey; // يفترض أن هذا المتغير متاح من ملف الاتصال
|
||||||
|
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret');
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* تسجيل دفعة في جدول النقاط وإعادة المعرف الخاص بها
|
||||||
|
* 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 "<h1>خطأ: الرقم المرجعي للطلب مفقود.</h1>";
|
||||||
|
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 "<h1>خطأ في تأكيد الدفع</h1><p>لم نتمكن من تأكيد دفعتك. قد تستغرق العملية بضع لحظات. يرجى التحقق من رصيدك في التطبيق لاحقاً أو التواصل مع الدعم الفني.</p>";
|
||||||
|
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 "<h1>تمت العملية بنجاح</h1><p>تمت إضافة الرصيد إلى محفظتك. يمكنك الآن العودة إلى التطبيق.</p>";
|
||||||
|
|
||||||
|
} 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 "<h1>حدث خطأ</h1><p>لقد تم استلام دفعتك بنجاح، ولكن حدث خطأ أثناء تحديث رصيدك. يرجى التواصل مع الدعم الفني وتزويدهم بالرقم المرجعي: " . htmlspecialchars($orderRef) . "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
91
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_webhook.php
Executable file
91
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/ecash_webhook.php
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
// استخدام ملف اتصال خاص بالـ Webhook لا يحتوي على أي تحقق من الهوية
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ملف Webhook النهائي الخاص بـ eCash (مع تسجيل إضافي للتصحيح)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- الإعدادات ---
|
||||||
|
$ecash_merchant_id = getenv('ECASH_MERCHANT_ID');
|
||||||
|
$ecash_merchant_secret = getenv('ECASH_MERCHANT_SECRET');
|
||||||
|
|
||||||
|
// --- إعداد ملف اللوج (Log File) ---
|
||||||
|
$log_dir = __DIR__ . '/../logs';
|
||||||
|
$log_file = $log_dir . '/ecash_production.log';
|
||||||
|
|
||||||
|
if (!is_dir($log_dir)) {
|
||||||
|
mkdir($log_dir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- قراءة البيانات القادمة من eCash ---
|
||||||
|
$raw_body = file_get_contents("php://input");
|
||||||
|
$data = json_decode($raw_body, true);
|
||||||
|
|
||||||
|
// --- تسجيل الـ Callback كاملاً لأغراض المراقبة ---
|
||||||
|
file_put_contents($log_file, "--- NEW WEBHOOK ---\n" . date('Y-m-d H:i:s') . " - RAW BODY: " . $raw_body . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
if (!$data || !isset($data['Token'])) {
|
||||||
|
http_response_code(400);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- استخراج البيانات ---
|
||||||
|
$isSuccess = $data['IsSuccess'] ?? false;
|
||||||
|
$transactionNo = $data['TransactionNo'] ?? '';
|
||||||
|
$amount = $data['Amount'] ?? '';
|
||||||
|
$orderRef = $data['OrderRef'] ?? '';
|
||||||
|
$receivedToken = $data['Token'];
|
||||||
|
|
||||||
|
// --- **تصحيح الأخطاء: بناء وتسجيل سلسلة التحقق** ---
|
||||||
|
$verification_string = $ecash_merchant_id . $ecash_merchant_secret . $transactionNo . $amount . $orderRef;
|
||||||
|
$expectedToken = strtoupper(md5($verification_string));
|
||||||
|
|
||||||
|
// تسجيل السلسلة المستخدمة في التوقيع والقيم الفردية
|
||||||
|
$debug_log = "VERIFICATION STRING: " . $verification_string . PHP_EOL;
|
||||||
|
$debug_log .= " - Merchant ID Used: " . $ecash_merchant_id . PHP_EOL;
|
||||||
|
$debug_log .= " - TransactionNo Used: " . $transactionNo . PHP_EOL;
|
||||||
|
$debug_log .= " - Amount Used: " . $amount . PHP_EOL;
|
||||||
|
$debug_log .= " - OrderRef Used: " . $orderRef . PHP_EOL;
|
||||||
|
$debug_log .= "CALCULATED TOKEN: " . $expectedToken . PHP_EOL;
|
||||||
|
$debug_log .= "RECEIVED TOKEN: " . $receivedToken . PHP_EOL;
|
||||||
|
|
||||||
|
file_put_contents($log_file, $debug_log, FILE_APPEND);
|
||||||
|
|
||||||
|
|
||||||
|
// --- التحقق من صحة الـ Token ---
|
||||||
|
if (!hash_equals($expectedToken, $receivedToken)) {
|
||||||
|
http_response_code(401);
|
||||||
|
file_put_contents($log_file, "TOKEN MISMATCH! Process stopped." . PHP_EOL, FILE_APPEND);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- تحديث حالة الدفعة في قاعدة البيانات ---
|
||||||
|
file_put_contents($log_file, "TOKEN MATCH! Proceeding to update database." . PHP_EOL, FILE_APPEND);
|
||||||
|
$payment_status = $isSuccess ? 1 : 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $con->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);
|
||||||
|
}
|
||||||
|
?>
|
||||||
79
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/finalize_payment.php
Executable file
79
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/finalize_payment.php
Executable file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
// هذا الملف يجب أن يستخدم ملف الاتصال الذي يتحقق من الهوية
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
// يجب استدعاء دالة التحقق هنا لضمان أن الطلب قادم من تطبيقك فقط
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ملف إتمام الدفع النهائي
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| هذا الملف مسؤول عن:
|
||||||
|
| 1. استقبال طلب من تطبيق فلاتر بعد عودة المستخدم.
|
||||||
|
| 2. التحقق من وجود دفعة ناجحة حديثة للمستخدم في قاعدة البيانات.
|
||||||
|
| 3. حساب المكافآت.
|
||||||
|
| 4. استدعاء واجهات API داخلية لإضافة الرصيد إلى المحافظ.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- استقبال البيانات من تطبيق فلاتر ---
|
||||||
|
$userId = filterRequest("userId"); // أو driverId
|
||||||
|
$paymentMethod = filterRequest("paymentMethod") ?? 'ecash';
|
||||||
|
|
||||||
|
if (empty($userId)) {
|
||||||
|
printFailure("معرّف المستخدم غير صالح.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// خطوة 1: البحث عن آخر دفعة ناجحة للمستخدم (تم تحديثها بواسطة الـ Webhook)
|
||||||
|
$stmt = $con->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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
88
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/payWithEcash.php
Executable file
88
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/payWithEcash.php
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php"; // تأكد من أن هذا الملف يحتوي على الاتصال بقاعدة البيانات ودوال المساعدة
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ملف بدء الدفع مع eCash
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| هذا الملف مسؤول عن:
|
||||||
|
| 1. استقبال طلب الدفع من تطبيق فلاتر (المبلغ ومعرّف المستخدم/السائق).
|
||||||
|
| 2. إنشاء رابط دفع فريد وخاص ببوابة eCash.
|
||||||
|
| 3. حساب رمز التحقق (Verification Code) المطلوب من eCash.
|
||||||
|
| 4. تسجيل محاولة الدفع في قاعدة البيانات بحالة "قيد الانتظار".
|
||||||
|
| 5. إعادة رابط الدفع إلى التطبيق ليتم عرضه في WebView.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- الإعدادات الرئيسية - يجب تخزينها كمتغيرات بيئة (Environment Variables) ---
|
||||||
|
$ecash_merchant_id = getenv('ECASH_MERCHANT_ID'); // معرّف التاجر الخاص بك من eCash
|
||||||
|
$ecash_merchant_secret = getenv('ECASH_MERCHANT_SECRET'); // المفتاح السري الخاص بك من eCash
|
||||||
|
$ecash_terminal_key = getenv('ECASH_TERMINAL_KEY'); // مفتاح المحطة الطرفية (Terminal Key) من eCash
|
||||||
|
$ecash_checkout_url = 'https://checkout.ecash-pay.com/'; //
|
||||||
|
$ecash_checkout_url_stage = 'https://checkout.ecash-pay.co/';//رابط بوابة الدفع
|
||||||
|
$base_app_url = getenv('APP_BASE_URL'); // الرابط الأساسي لواجهة API الخاصة بك
|
||||||
|
|
||||||
|
// --- استقبال البيانات من تطبيق فلاتر ---
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
$driverId = filterRequest("driverId"); // معرّف السائق أو المستخدم
|
||||||
|
|
||||||
|
// --- التحقق من صحة البيانات المدخلة ---
|
||||||
|
if (empty($amount) || empty($driverId) || !is_numeric($amount) || $amount <= 0) {
|
||||||
|
printFailure("المبلغ أو معرّف المستخدم غير صالح.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- إعداد متغيرات الدفع ---
|
||||||
|
$currency = "SYP"; // العملة حسب متطلبات eCash
|
||||||
|
$lang = "AR"; // لغة واجهة الدفع (AR أو EN)
|
||||||
|
//$orderRef = uniqid($driverId . "_"); // إنشاء رقم مرجعي فريد للطلب لربطه بالمستخدم
|
||||||
|
$orderRef = "tripz_" . $driverId . "_" . time();
|
||||||
|
// --- إنشاء رمز التحقق (Verification Code) ---
|
||||||
|
// هو عبارة عن MD5 لمجموعة من الحقول ويجب أن يكون بأحرف كبيرة
|
||||||
|
$verification_string = $ecash_merchant_id . $ecash_merchant_secret . $amount . $orderRef;
|
||||||
|
$verificationCode = strtoupper(md5($verification_string));
|
||||||
|
|
||||||
|
// --- تحديد روابط إعادة التوجيه والاستدعاء (Redirect & Callback) ---
|
||||||
|
// الرابط الذي يتم توجيه المستخدم إليه بعد إتمام الدفع
|
||||||
|
$redirectUrl = urlencode($base_app_url . "/driver/ecash_verify.php?orderRef=" . $orderRef);
|
||||||
|
// الرابط الذي تستدعيه eCash لإبلاغ سيرفرك بنتيجة العملية (Webhook)
|
||||||
|
$callbackUrl = urlencode($base_app_url . "/driver/ecash_webhook.php");
|
||||||
|
|
||||||
|
// --- بناء رابط الدفع النهائي الخاص بـ eCash ---
|
||||||
|
$paymentUrl = "{$ecash_checkout_url}Checkout/CardCheckout" .
|
||||||
|
"?tk=" . urlencode($ecash_terminal_key) .
|
||||||
|
"&mid=" . urlencode($ecash_merchant_id) .
|
||||||
|
"&vc=" . urlencode($verificationCode) .
|
||||||
|
"&c=" . urlencode($currency) .
|
||||||
|
"&a=" . urlencode($amount) .
|
||||||
|
"&lang=" . urlencode($lang) .
|
||||||
|
"&or=" . urlencode($orderRef) .
|
||||||
|
"&ru=" . $redirectUrl .
|
||||||
|
"&cu=" . $callbackUrl;
|
||||||
|
|
||||||
|
// --- تسجيل العملية المبدئية في قاعدة البيانات ---
|
||||||
|
// هذا يساعد على تتبع الطلب وربطه بالـ callback القادم من eCash
|
||||||
|
// نفترض أن حقل status يقبل القيم: 0=فشل، 1=نجاح، 2=قيد الانتظار
|
||||||
|
try {
|
||||||
|
$stmt = $con->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);
|
||||||
|
|
||||||
|
?>
|
||||||
42
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/webhook_connect.php
Executable file
42
walletintaleq.intaleq.xyz/v2/main/ride/ecash/driver/webhook_connect.php
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
// Load environment variables from .env file
|
||||||
|
// **FIX:** Corrected the path to go up three levels to find the 'vendor' directory
|
||||||
|
require_once realpath(__DIR__ . '/../../../vendor/autoload.php');
|
||||||
|
// **FIX:** Corrected the path to go up two levels to find 'load_env.php'
|
||||||
|
require_once realpath(__DIR__ . '/../../load_env.php');
|
||||||
|
|
||||||
|
$env_file = '/home/tripz-egypt-wl/env/.env';
|
||||||
|
loadEnvironment($env_file);
|
||||||
|
|
||||||
|
// --- CORS Headers ---
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Allow-Methods: POST, OPTIONS");
|
||||||
|
header("Access-Control-Allow-Headers: Content-Type");
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
||||||
|
http_response_code(200);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbname = getenv('dbname');
|
||||||
|
// --- Database Connection ONLY ---
|
||||||
|
try {
|
||||||
|
$dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4";
|
||||||
|
$options = [
|
||||||
|
PDO::ATTR_EMULATE_PREPARES => 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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
44
walletintaleq.intaleq.xyz/v2/main/ride/ecash/ecash_config.php
Executable file
44
walletintaleq.intaleq.xyz/v2/main/ride/ecash/ecash_config.php
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
// --- ecash_config.php ---
|
||||||
|
// Central configuration file for ecash, loading from a .env file.
|
||||||
|
|
||||||
|
// This assumes you have a function or a library (like Dotenv) to load the .env file.
|
||||||
|
|
||||||
|
|
||||||
|
// --- IMPORTANT ---
|
||||||
|
// Define the path to your .env file. Adjust if necessary.
|
||||||
|
//$env_file_path = '/home/tripz-egypt-wl/env/.env'; // Or use realpath(__DIR__ . '/../.env');
|
||||||
|
//loadEnvironment($env_file_path);
|
||||||
|
require "../../jwtconnect.php";
|
||||||
|
// --- Load ecash Credentials from Environment Variables ---
|
||||||
|
define('ECASH_MERCHANT_ID', getenv('ECASH_MERCHANT_ID'));
|
||||||
|
define('ECASH_MERCHANT_SECRET', getenv('ECASH_MERCHANT_SECRET'));
|
||||||
|
define('ECASH_TERMINAL_KEY', getenv('ECASH_TERMINAL_KEY'));
|
||||||
|
|
||||||
|
// --- Set Mode (Staging/Live) from Environment Variable ---
|
||||||
|
// Add ECASH_STAGING_MODE=true to your .env for testing
|
||||||
|
$is_staging = getenv('ECASH_STAGING_MODE') === 'false';
|
||||||
|
define('ECASH_STAGING_MODE', $is_staging);
|
||||||
|
|
||||||
|
// --- URLs (Automatically switch based on mode) ---
|
||||||
|
$checkout_base_url = ECASH_STAGING_MODE ? 'https://checkout.ecash-pay.co' : 'https://checkout.ecash-pay.com';
|
||||||
|
define('ECASH_CHECKOUT_URL', $checkout_base_url);
|
||||||
|
|
||||||
|
// --- Your Application URLs (Load from .env or define here) ---
|
||||||
|
// It's best practice to also put these in your .env file.
|
||||||
|
define('APP_BASE_URL', getenv('APP_BASE_URL')); // e.g., https://yourdomain.com/api
|
||||||
|
define('APP_REDIRECT_URL_SUCCESS', APP_BASE_URL . '/success.php');
|
||||||
|
define('APP_CALLBACK_URL', APP_BASE_URL . '/webhook_ecash.php'); // Use a specific webhook for ecash
|
||||||
|
|
||||||
|
// --- Other Settings ---
|
||||||
|
define('ECASH_CURRENCY', 'SYP');
|
||||||
|
define('ECASH_LANG', 'EN'); // 'EN' for English, 'AR' for Arabic
|
||||||
|
|
||||||
|
// --- Basic Validation ---
|
||||||
|
if (!ECASH_MERCHANT_ID || !ECASH_MERCHANT_SECRET || !ECASH_TERMINAL_KEY) {
|
||||||
|
http_response_code(500);
|
||||||
|
error_log("ecash config: Missing one or more required ecash environment variables.");
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'Payment gateway not configured correctly.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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.
|
||||||
@@ -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"}
|
||||||
181
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_verify.php
Executable file
181
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_verify.php
Executable file
@@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
// هذا الملف هو نقطة النهاية بعد الدفع، ويقوم بكل عمليات التحقق وإضافة الرصيد
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
define("BASE_URL", "https://wl.tripz-egypt.com/v1/main/ride");
|
||||||
|
define("LOG_FILE", "../logs/payment_verification.log");
|
||||||
|
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showHTMLPage($type, $title, $message) {
|
||||||
|
$color = $type === 'success' ? '#28a745' : '#dc3545';
|
||||||
|
$icon = $type === 'success' ? '✔' : '✖';
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ar" dir="rtl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title><?= htmlspecialchars($title) ?></title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #f4f6f9;
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 100px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: #fff;
|
||||||
|
padding: 40px 30px;
|
||||||
|
margin: auto;
|
||||||
|
max-width: 450px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
|
||||||
|
animation: fadeIn 1s ease-out;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
font-size: 64px;
|
||||||
|
color: <?= $color ?>;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
color: <?= $color ?>;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(-20px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="icon"><?= $icon ?></div>
|
||||||
|
<h1><?= htmlspecialchars($title) ?></h1>
|
||||||
|
<p><?= htmlspecialchars($message) ?></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<?php
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$orderRef = $_GET['orderRef'] ?? null;
|
||||||
|
if (empty($orderRef)) {
|
||||||
|
showHTMLPage("error", "خطأ في الرابط", "الرقم المرجعي للطلب غير موجود.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment = null;
|
||||||
|
$max_attempts = 5;
|
||||||
|
for ($attempts = 0; $attempts < $max_attempts; $attempts++) {
|
||||||
|
$stmt = $con->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);
|
||||||
|
}
|
||||||
|
?>
|
||||||
91
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_webhook.php
Executable file
91
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/ecash_webhook.php
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
// استخدام ملف اتصال خاص بالـ Webhook لا يحتوي على أي تحقق من الهوية
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ملف Webhook النهائي الخاص بـ eCash (مع تسجيل إضافي للتصحيح)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- الإعدادات ---
|
||||||
|
$ecash_merchant_id = getenv('ECASH_MERCHANT_ID');
|
||||||
|
$ecash_merchant_secret = getenv('ECASH_MERCHANT_SECRET');
|
||||||
|
|
||||||
|
// --- إعداد ملف اللوج (Log File) ---
|
||||||
|
$log_dir = __DIR__ . '/../logs';
|
||||||
|
$log_file = $log_dir . '/ecash_production.log';
|
||||||
|
|
||||||
|
if (!is_dir($log_dir)) {
|
||||||
|
mkdir($log_dir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- قراءة البيانات القادمة من eCash ---
|
||||||
|
$raw_body = file_get_contents("php://input");
|
||||||
|
$data = json_decode($raw_body, true);
|
||||||
|
|
||||||
|
// --- تسجيل الـ Callback كاملاً لأغراض المراقبة ---
|
||||||
|
file_put_contents($log_file, "--- NEW WEBHOOK ---\n" . date('Y-m-d H:i:s') . " - RAW BODY: " . $raw_body . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
if (!$data || !isset($data['Token'])) {
|
||||||
|
http_response_code(400);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- استخراج البيانات ---
|
||||||
|
$isSuccess = $data['IsSuccess'] ?? false;
|
||||||
|
$transactionNo = $data['TransactionNo'] ?? '';
|
||||||
|
$amount = $data['Amount'] ?? '';
|
||||||
|
$orderRef = $data['OrderRef'] ?? '';
|
||||||
|
$receivedToken = $data['Token'];
|
||||||
|
|
||||||
|
// --- **تصحيح الأخطاء: بناء وتسجيل سلسلة التحقق** ---
|
||||||
|
$verification_string = $ecash_merchant_id . $ecash_merchant_secret . $transactionNo . $amount . $orderRef;
|
||||||
|
$expectedToken = strtoupper(md5($verification_string));
|
||||||
|
|
||||||
|
// تسجيل السلسلة المستخدمة في التوقيع والقيم الفردية
|
||||||
|
$debug_log = "VERIFICATION STRING: " . $verification_string . PHP_EOL;
|
||||||
|
$debug_log .= " - Merchant ID Used: " . $ecash_merchant_id . PHP_EOL;
|
||||||
|
$debug_log .= " - TransactionNo Used: " . $transactionNo . PHP_EOL;
|
||||||
|
$debug_log .= " - Amount Used: " . $amount . PHP_EOL;
|
||||||
|
$debug_log .= " - OrderRef Used: " . $orderRef . PHP_EOL;
|
||||||
|
$debug_log .= "CALCULATED TOKEN: " . $expectedToken . PHP_EOL;
|
||||||
|
$debug_log .= "RECEIVED TOKEN: " . $receivedToken . PHP_EOL;
|
||||||
|
|
||||||
|
file_put_contents($log_file, $debug_log, FILE_APPEND);
|
||||||
|
|
||||||
|
|
||||||
|
// --- التحقق من صحة الـ Token ---
|
||||||
|
if (!hash_equals($expectedToken, $receivedToken)) {
|
||||||
|
http_response_code(401);
|
||||||
|
file_put_contents($log_file, "TOKEN MISMATCH! Process stopped." . PHP_EOL, FILE_APPEND);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- تحديث حالة الدفعة في قاعدة البيانات ---
|
||||||
|
file_put_contents($log_file, "TOKEN MATCH! Proceeding to update database." . PHP_EOL, FILE_APPEND);
|
||||||
|
$payment_status = $isSuccess ? 1 : 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $con->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);
|
||||||
|
}
|
||||||
|
?>
|
||||||
79
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/finalize_payment.php
Executable file
79
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/finalize_payment.php
Executable file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
// هذا الملف يجب أن يستخدم ملف الاتصال الذي يتحقق من الهوية
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
// يجب استدعاء دالة التحقق هنا لضمان أن الطلب قادم من تطبيقك فقط
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ملف إتمام الدفع النهائي
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| هذا الملف مسؤول عن:
|
||||||
|
| 1. استقبال طلب من تطبيق فلاتر بعد عودة المستخدم.
|
||||||
|
| 2. التحقق من وجود دفعة ناجحة حديثة للمستخدم في قاعدة البيانات.
|
||||||
|
| 3. حساب المكافآت.
|
||||||
|
| 4. استدعاء واجهات API داخلية لإضافة الرصيد إلى المحافظ.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- استقبال البيانات من تطبيق فلاتر ---
|
||||||
|
$userId = filterRequest("userId"); // أو driverId
|
||||||
|
$paymentMethod = filterRequest("paymentMethod") ?? 'ecash';
|
||||||
|
|
||||||
|
if (empty($userId)) {
|
||||||
|
printFailure("معرّف المستخدم غير صالح.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// خطوة 1: البحث عن آخر دفعة ناجحة للمستخدم (تم تحديثها بواسطة الـ Webhook)
|
||||||
|
$stmt = $con->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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
88
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/payWithEcash.php
Executable file
88
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/payWithEcash.php
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php"; // تأكد من أن هذا الملف يحتوي على الاتصال بقاعدة البيانات ودوال المساعدة
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ملف بدء الدفع مع eCash
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| هذا الملف مسؤول عن:
|
||||||
|
| 1. استقبال طلب الدفع من تطبيق فلاتر (المبلغ ومعرّف المستخدم/السائق).
|
||||||
|
| 2. إنشاء رابط دفع فريد وخاص ببوابة eCash.
|
||||||
|
| 3. حساب رمز التحقق (Verification Code) المطلوب من eCash.
|
||||||
|
| 4. تسجيل محاولة الدفع في قاعدة البيانات بحالة "قيد الانتظار".
|
||||||
|
| 5. إعادة رابط الدفع إلى التطبيق ليتم عرضه في WebView.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// --- الإعدادات الرئيسية - يجب تخزينها كمتغيرات بيئة (Environment Variables) ---
|
||||||
|
$ecash_merchant_id = getenv('ECASH_MERCHANT_ID'); // معرّف التاجر الخاص بك من eCash
|
||||||
|
$ecash_merchant_secret = getenv('ECASH_MERCHANT_SECRET'); // المفتاح السري الخاص بك من eCash
|
||||||
|
$ecash_terminal_key = getenv('ECASH_TERMINAL_KEY'); // مفتاح المحطة الطرفية (Terminal Key) من eCash
|
||||||
|
$ecash_checkout_url = 'https://checkout.ecash-pay.com/'; //
|
||||||
|
$ecash_checkout_url_stage = 'https://checkout.ecash-pay.co/';//رابط بوابة الدفع
|
||||||
|
$base_app_url = getenv('APP_BASE_URL'); // الرابط الأساسي لواجهة API الخاصة بك
|
||||||
|
|
||||||
|
// --- استقبال البيانات من تطبيق فلاتر ---
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
$passengerId = filterRequest("passengerId"); // معرّف السائق أو المستخدم
|
||||||
|
|
||||||
|
// --- التحقق من صحة البيانات المدخلة ---
|
||||||
|
if (empty($amount) || empty($passengerId) || !is_numeric($amount) || $amount <= 0) {
|
||||||
|
printFailure("المبلغ أو معرّف المستخدم غير صالح.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- إعداد متغيرات الدفع ---
|
||||||
|
$currency = "SYP"; // العملة حسب متطلبات eCash
|
||||||
|
$lang = "AR"; // لغة واجهة الدفع (AR أو EN)
|
||||||
|
//$orderRef = uniqid($passengerId . "_"); // إنشاء رقم مرجعي فريد للطلب لربطه بالمستخدم
|
||||||
|
$orderRef = "tripz_" . $passengerId . "_" . time();
|
||||||
|
// --- إنشاء رمز التحقق (Verification Code) ---
|
||||||
|
// هو عبارة عن MD5 لمجموعة من الحقول ويجب أن يكون بأحرف كبيرة
|
||||||
|
$verification_string = $ecash_merchant_id . $ecash_merchant_secret . $amount . $orderRef;
|
||||||
|
$verificationCode = strtoupper(md5($verification_string));
|
||||||
|
|
||||||
|
// --- تحديد روابط إعادة التوجيه والاستدعاء (Redirect & Callback) ---
|
||||||
|
// الرابط الذي يتم توجيه المستخدم إليه بعد إتمام الدفع
|
||||||
|
$redirectUrl = urlencode($base_app_url . "/passenger/ecash_verify.php?orderRef=" . $orderRef);
|
||||||
|
// الرابط الذي تستدعيه eCash لإبلاغ سيرفرك بنتيجة العملية (Webhook)
|
||||||
|
$callbackUrl = urlencode($base_app_url . "/passenger/ecash_webhook.php");
|
||||||
|
|
||||||
|
// --- بناء رابط الدفع النهائي الخاص بـ eCash ---
|
||||||
|
$paymentUrl = "{$ecash_checkout_url}Checkout/CardCheckout" .
|
||||||
|
"?tk=" . urlencode($ecash_terminal_key) .
|
||||||
|
"&mid=" . urlencode($ecash_merchant_id) .
|
||||||
|
"&vc=" . urlencode($verificationCode) .
|
||||||
|
"&c=" . urlencode($currency) .
|
||||||
|
"&a=" . urlencode($amount) .
|
||||||
|
"&lang=" . urlencode($lang) .
|
||||||
|
"&or=" . urlencode($orderRef) .
|
||||||
|
"&ru=" . $redirectUrl .
|
||||||
|
"&cu=" . $callbackUrl;
|
||||||
|
//error_log("eCash - فشل تسجيل الدفعة المبدئية: " . $paymentUrl);
|
||||||
|
// --- تسجيل العملية المبدئية في قاعدة البيانات ---
|
||||||
|
// هذا يساعد على تتبع الطلب وربطه بالـ callback القادم من eCash
|
||||||
|
// نفترض أن حقل status يقبل القيم: 0=فشل، 1=نجاح، 2=قيد الانتظار
|
||||||
|
try {
|
||||||
|
$stmt = $con->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);
|
||||||
|
|
||||||
|
?>
|
||||||
42
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/webhook_connect.php
Executable file
42
walletintaleq.intaleq.xyz/v2/main/ride/ecash/passenger/webhook_connect.php
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
// Load environment variables from .env file
|
||||||
|
// **FIX:** Corrected the path to go up three levels to find the 'vendor' directory
|
||||||
|
require_once realpath(__DIR__ . '/../../../vendor/autoload.php');
|
||||||
|
// **FIX:** Corrected the path to go up two levels to find 'load_env.php'
|
||||||
|
require_once realpath(__DIR__ . '/../../load_env.php');
|
||||||
|
|
||||||
|
$env_file = '/home/tripz-egypt-wl/env/.env';
|
||||||
|
loadEnvironment($env_file);
|
||||||
|
|
||||||
|
// --- CORS Headers ---
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Allow-Methods: POST, OPTIONS");
|
||||||
|
header("Access-Control-Allow-Headers: Content-Type");
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
||||||
|
http_response_code(200);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbname = getenv('dbname');
|
||||||
|
// --- Database Connection ONLY ---
|
||||||
|
try {
|
||||||
|
$dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4";
|
||||||
|
$options = [
|
||||||
|
PDO::ATTR_EMULATE_PREPARES => 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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
73
walletintaleq.intaleq.xyz/v2/main/ride/ecash/payWithEcash.php
Executable file
73
walletintaleq.intaleq.xyz/v2/main/ride/ecash/payWithEcash.php
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
// --- payWithEcash.php (Updated) ---
|
||||||
|
// This script now saves transaction details before generating the payment link.
|
||||||
|
|
||||||
|
require "../../jwtconnect.php"; // Your existing connection/auth script
|
||||||
|
require_once "ecash_config.php"; // The ecash config file
|
||||||
|
|
||||||
|
// --- Get Input Data ---
|
||||||
|
$amount = filterRequest("amount", "numeric");
|
||||||
|
$passengerId = filterRequest("passengerId"); // Get passengerId from the request
|
||||||
|
|
||||||
|
if (!$amount || $amount <= 0) {
|
||||||
|
printFailure("Invalid or missing amount.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (!$passengerId) {
|
||||||
|
printFailure("Passenger ID is required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user ID from your JWT authentication in jwtconnect.php
|
||||||
|
$userId = $decodedToken->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);
|
||||||
|
|
||||||
|
?>
|
||||||
310
walletintaleq.intaleq.xyz/v2/main/ride/ecash/webhook_ecash.php
Executable file
310
walletintaleq.intaleq.xyz/v2/main/ride/ecash/webhook_ecash.php
Executable file
@@ -0,0 +1,310 @@
|
|||||||
|
|
||||||
|
<?php
|
||||||
|
// --- webhook_ecash.php ---
|
||||||
|
// This script securely handles the callback from ecash and updates user wallets.
|
||||||
|
|
||||||
|
// Include necessary files
|
||||||
|
require_once "../../jwtconnect.php"; // Adjust path as needed
|
||||||
|
require_once "ecash_config.php"; // Adjust path as needed
|
||||||
|
|
||||||
|
define("BASE_URL", "https://wl.tripz-egypt.com/v1/main/ride");
|
||||||
|
define("LOG_FILE", "../logs/ecash_webhook.log");
|
||||||
|
|
||||||
|
// --- Start Webhook Processing ---
|
||||||
|
|
||||||
|
// 1. Log the raw incoming data from ecash
|
||||||
|
$raw_post_data = file_get_contents('php://input');
|
||||||
|
logError("0", "Webhook received", ["payload" => $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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
125
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/confirm_payment.php
Executable file
125
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/confirm_payment.php
Executable file
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/mtn/driver/confirm_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// It's better to use __DIR__ for reliable file path resolution.
|
||||||
|
// Assuming your private_key.pem is in the same directory as this script.
|
||||||
|
$privateKeyPath = __DIR__ . "/private_key.pem";
|
||||||
|
|
||||||
|
$baseUrl = rtrim(getenv('MTN_API_BASE_URL'), '/');
|
||||||
|
$terminalId = getenv('MTN_TERMINAL_ID');
|
||||||
|
$privateKey = openssl_pkey_get_private(file_get_contents($privateKeyPath));
|
||||||
|
|
||||||
|
$invoice = filterRequest('invoiceNumber');
|
||||||
|
$phone = filterRequest('phone');
|
||||||
|
$guid = filterRequest('guid');
|
||||||
|
$operationNumber = filterRequest('operationNumber');
|
||||||
|
$code = filterRequest('otp'); // The OTP
|
||||||
|
|
||||||
|
error_log("MTN Confirm (Driver): Start request for invoice={$invoice}, phone={$phone}, guid={$guid}, opNum={$operationNumber}");
|
||||||
|
|
||||||
|
if (!$invoice || !$phone || !$guid || !$operationNumber || !$code) {
|
||||||
|
error_log("MTN Confirm (Driver): Missing parameters");
|
||||||
|
printFailure("Missing parameters.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the code
|
||||||
|
$hashBin = hash('sha256', $code, true);
|
||||||
|
$codeB64 = base64_encode($hashBin);
|
||||||
|
|
||||||
|
$body = [
|
||||||
|
'Invoice' => 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.");
|
||||||
|
}
|
||||||
|
|
||||||
103
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/finalize_wallet_payment.php
Executable file
103
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/finalize_wallet_payment.php
Executable file
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
// wallet/finalize_wallet_payment.php
|
||||||
|
include_once "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
define("LOG_FILE", "../logs/payment_verification.log");
|
||||||
|
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateToken($con, $driverId, $amount): ?string {
|
||||||
|
global $secretKey;
|
||||||
|
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret');
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/generate_keys.php
Executable file
47
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/generate_keys.php
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
// File: generate_keys.php
|
||||||
|
// الوظيفة: إنشاء زوج المفاتيح (العام والخاص) لمرة واحدة فقط
|
||||||
|
|
||||||
|
// إعدادات لتوليد المفتاح
|
||||||
|
$config = [
|
||||||
|
"digest_alg" => "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 "<h1>Keys Generated Successfully!</h1>";
|
||||||
|
echo "<h2>Private Key (saved to private_key.pem):</h2>";
|
||||||
|
echo "<pre>" . htmlspecialchars($private_key) . "</pre>";
|
||||||
|
echo "<h2>Public Key (saved to public_key.pem):</h2>";
|
||||||
|
echo "<pre>" . htmlspecialchars($public_key) . "</pre>";
|
||||||
|
|
||||||
|
// --- تحضير المفتاح العام لعملية التفعيل ---
|
||||||
|
// إزالة الهيدر والفوتر والأسطر الجديدة كما هو مطلوب
|
||||||
|
$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 "<h2>Formatted Public Key (for Terminal Activation):</h2>";
|
||||||
|
echo "<p><strong>انسخ هذا المفتاح لاستخدامه في خطوة تفعيل الجهاز (activate_terminal.php)</strong></p>";
|
||||||
|
echo "<textarea rows='5' cols='80' readonly>" . htmlspecialchars($formatted_public_key) . "</textarea>";
|
||||||
|
|
||||||
|
?>
|
||||||
54
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/initiate_payment.php
Executable file
54
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/initiate_payment.php
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/mtn/passenger/initiate_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
$baseUrl = rtrim(getenv('MTN_API_BASE_URL'), '/');
|
||||||
|
$terminalId = getenv('MTN_TERMINAL_ID');
|
||||||
|
$privateKeyPem = getenv('MTN_PRIVATE_KEY');
|
||||||
|
|
||||||
|
$invoice = filterRequest('invoice'); // رقم الفاتورة
|
||||||
|
$phone = filterRequest('phone'); // رقم الزبون
|
||||||
|
$guid = uniqid('mtn_');
|
||||||
|
|
||||||
|
if (!$invoice || !$phone) {
|
||||||
|
printFailure("Missing invoice or phone.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = json_encode([
|
||||||
|
'Invoice' => 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;
|
||||||
56
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/key.php
Executable file
56
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/key.php
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
// بيانات التفعيل
|
||||||
|
$terminalId = "9001000000060863";
|
||||||
|
$activationCode = "26164711";
|
||||||
|
$serialNumber = "INTALEQ-001"; // يمكنك تغييره
|
||||||
|
|
||||||
|
// المفتاح العام على سطر واحد — بدون BEGIN/END وبدون أسطر جديدة
|
||||||
|
//$publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNxFbepx2OrpyrNG4+/aAaH3Rjc8dGw6B6vMAfsZzzm4wzoSkrtsr6jfuaMTZRLwxS5h8k1ztLG1HrOmL/NDsiE/7yxaKLAIZyWB/rR9byvPeOCC8QnCd/08kmxNl/l7Akn6qlPwsVpKUUNsr0SkU9lShMAw4OBgQq399jsbkFSwIDAQAB";
|
||||||
|
$publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOhVAdUyxFpVNSyjRndMWEPAN9vJEetMzLbjF9DTn2lPVuRj/Mkwq9wCNhy+tdeX2lIn4K3EkONBvYJubBhxnYOoQuMchPW5vG7VnmpLjZ7TkpM2n9fcMu8u1GkLatLblDI4LTfvn3851+nhpnYlUVkjw5GAhH4XnEpveIjqDhzQIDAQAB";
|
||||||
|
// جسم الطلب
|
||||||
|
$body = [
|
||||||
|
"Key" => $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,
|
||||||
|
]);
|
||||||
129
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/mtn_start.php
Executable file
129
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver/mtn_start.php
Executable file
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
date_default_timezone_set("Asia/Damascus");
|
||||||
|
|
||||||
|
// ========== إعدادات MTN ==========
|
||||||
|
$terminalId = "9001000000060863";
|
||||||
|
$currencyCode = 760;
|
||||||
|
$sessionNumber = 0;
|
||||||
|
$ttl = 15;
|
||||||
|
|
||||||
|
// ====== استقبال البيانات من فلاتر ======
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
$passengerId = filterRequest("passengerId");
|
||||||
|
$phone = filterRequest("phone");
|
||||||
|
|
||||||
|
// ✅ Log مبدئي
|
||||||
|
error_log("🚦 START | passengerId: $passengerId | phone: $phone | amount: $amount");
|
||||||
|
|
||||||
|
// تحقق من المدخلات
|
||||||
|
if (empty($amount) || empty($passengerId) || empty($phone) || $amount <= 0) {
|
||||||
|
error_log("❌ Invalid input: amount=$amount, passengerId=$passengerId, phone=$phone");
|
||||||
|
printFailure("بيانات الدفع غير كاملة أو غير صالحة.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== توليد invoiceNumber و GUID ======
|
||||||
|
$invoiceNumber = mt_rand(10000000000, 99999999999);
|
||||||
|
//$invoiceNumber = "MTN_" . $passengerId . "_" . time();
|
||||||
|
$guid = uniqid("mtn_");
|
||||||
|
error_log("🧾 Generated Invoice: $invoiceNumber");
|
||||||
|
error_log("🧭 Generated GUID: $guid");
|
||||||
|
|
||||||
|
// ====== 1. إنشاء الفاتورة ======
|
||||||
|
$createInvoiceBody = [
|
||||||
|
"Amount" => 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);
|
||||||
|
}
|
||||||
@@ -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-----
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqBQZEJXWCQwPsPzBM70M3TjyU
|
||||||
|
5vwCZWoEtUomR9Qu+dEQaa0Hniz6JY8+goCxfMYuZQw6+kimctA2KqzT2pCsJufN
|
||||||
|
b92pSAMZgb0RSTl2y62oJkJd2WY7dj36AvPEyw6DxCFItvFOu7HGl3LlHQBriiw3
|
||||||
|
jwtuS6DO7gbmAJPU8wIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
115
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver_payout_syria.php
Executable file
115
walletintaleq.intaleq.xyz/v2/main/ride/mtn/driver_payout_syria.php
Executable file
@@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
include "../../jwtconnect.php";
|
||||||
|
|
||||||
|
// --- 2. استقبال البيانات من الطلب ---
|
||||||
|
$driver_id = filterRequest("driver_id");
|
||||||
|
$driver_name = filterRequest("driver_name");
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
$wallet_type = filterRequest("wallet_type");
|
||||||
|
$wallet_number = filterRequest("wallet_number");
|
||||||
|
|
||||||
|
// التحقق من أن البيانات الأساسية موجودة
|
||||||
|
if (empty($driver_id) || empty($driver_name) || empty($amount) || empty($wallet_type) || empty($wallet_number)) {
|
||||||
|
printFailure('Missing required fields.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3. إدراج الطلب في قاعدة البيانات ---
|
||||||
|
try {
|
||||||
|
$sql = "INSERT INTO driver_withdrawal_requests (driver_id, driver_name, amount, wallet_type, wallet_number) VALUES (?, ?, ?, ?, ?)";
|
||||||
|
$stmt = $con->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
169
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/confirm_payment.php
Executable file
169
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/confirm_payment.php
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/mtn/passenger/confirm_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
$baseUrl = rtrim(getenv('MTN_API_BASE_URL'), '/');
|
||||||
|
$terminalId = getenv('MTN_TERMINAL_ID');
|
||||||
|
$privateKeyPem = getenv('MTN_PRIVATE_KEY');
|
||||||
|
$privateKey = openssl_pkey_get_private(file_get_contents("private_key.pem"));
|
||||||
|
$invoice = filterRequest('invoiceNumber');
|
||||||
|
$phone = filterRequest('phone');
|
||||||
|
$guid = filterRequest('guid');
|
||||||
|
$operationNumber = filterRequest('operationNumber');
|
||||||
|
$code = filterRequest('otp'); // الـ OTP
|
||||||
|
|
||||||
|
error_log("MTN Confirm: Start request for invoice={$invoice}, phone={$phone}, guid={$guid}, opNum={$operationNumber}");
|
||||||
|
|
||||||
|
if (!$invoice || !$phone || !$guid || !$operationNumber || !$code) {
|
||||||
|
error_log("MTN Confirm: Missing parameters");
|
||||||
|
printFailure("Missing parameters.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// تشفير الكود
|
||||||
|
$hashBin = hash('sha256', $code, true);
|
||||||
|
$codeB64 = base64_encode($hashBin);
|
||||||
|
|
||||||
|
$body = [
|
||||||
|
'Invoice' => 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);
|
||||||
|
}
|
||||||
|
?>
|
||||||
103
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/finalize_wallet_payment.php
Executable file
103
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/finalize_wallet_payment.php
Executable file
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
// wallet/finalize_wallet_payment.php
|
||||||
|
include_once "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
define("LOG_FILE", "../logs/payment_verification.log");
|
||||||
|
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateToken($con, $driverId, $amount): ?string {
|
||||||
|
global $secretKey;
|
||||||
|
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret');
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/generate_keys.php
Executable file
47
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/generate_keys.php
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
// File: generate_keys.php
|
||||||
|
// الوظيفة: إنشاء زوج المفاتيح (العام والخاص) لمرة واحدة فقط
|
||||||
|
|
||||||
|
// إعدادات لتوليد المفتاح
|
||||||
|
$config = [
|
||||||
|
"digest_alg" => "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 "<h1>Keys Generated Successfully!</h1>";
|
||||||
|
echo "<h2>Private Key (saved to private_key.pem):</h2>";
|
||||||
|
echo "<pre>" . htmlspecialchars($private_key) . "</pre>";
|
||||||
|
echo "<h2>Public Key (saved to public_key.pem):</h2>";
|
||||||
|
echo "<pre>" . htmlspecialchars($public_key) . "</pre>";
|
||||||
|
|
||||||
|
// --- تحضير المفتاح العام لعملية التفعيل ---
|
||||||
|
// إزالة الهيدر والفوتر والأسطر الجديدة كما هو مطلوب
|
||||||
|
$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 "<h2>Formatted Public Key (for Terminal Activation):</h2>";
|
||||||
|
echo "<p><strong>انسخ هذا المفتاح لاستخدامه في خطوة تفعيل الجهاز (activate_terminal.php)</strong></p>";
|
||||||
|
echo "<textarea rows='5' cols='80' readonly>" . htmlspecialchars($formatted_public_key) . "</textarea>";
|
||||||
|
|
||||||
|
?>
|
||||||
54
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/initiate_payment.php
Executable file
54
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/initiate_payment.php
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/mtn/passenger/initiate_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
$baseUrl = rtrim(getenv('MTN_API_BASE_URL'), '/');
|
||||||
|
$terminalId = getenv('MTN_TERMINAL_ID');
|
||||||
|
$privateKeyPem = getenv('MTN_PRIVATE_KEY');
|
||||||
|
|
||||||
|
$invoice = filterRequest('invoice'); // رقم الفاتورة
|
||||||
|
$phone = filterRequest('phone'); // رقم الزبون
|
||||||
|
$guid = uniqid('mtn_');
|
||||||
|
|
||||||
|
if (!$invoice || !$phone) {
|
||||||
|
printFailure("Missing invoice or phone.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = json_encode([
|
||||||
|
'Invoice' => 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;
|
||||||
56
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/key.php
Executable file
56
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/key.php
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
// بيانات التفعيل
|
||||||
|
$terminalId = "9001000000060863";
|
||||||
|
$activationCode = "26164711";
|
||||||
|
$serialNumber = "INTALEQ-001"; // يمكنك تغييره
|
||||||
|
|
||||||
|
// المفتاح العام على سطر واحد — بدون BEGIN/END وبدون أسطر جديدة
|
||||||
|
//$publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNxFbepx2OrpyrNG4+/aAaH3Rjc8dGw6B6vMAfsZzzm4wzoSkrtsr6jfuaMTZRLwxS5h8k1ztLG1HrOmL/NDsiE/7yxaKLAIZyWB/rR9byvPeOCC8QnCd/08kmxNl/l7Akn6qlPwsVpKUUNsr0SkU9lShMAw4OBgQq399jsbkFSwIDAQAB";
|
||||||
|
$publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOhVAdUyxFpVNSyjRndMWEPAN9vJEetMzLbjF9DTn2lPVuRj/Mkwq9wCNhy+tdeX2lIn4K3EkONBvYJubBhxnYOoQuMchPW5vG7VnmpLjZ7TkpM2n9fcMu8u1GkLatLblDI4LTfvn3851+nhpnYlUVkjw5GAhH4XnEpveIjqDhzQIDAQAB";
|
||||||
|
// جسم الطلب
|
||||||
|
$body = [
|
||||||
|
"Key" => $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,
|
||||||
|
]);
|
||||||
247
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_confirm.php
Executable file
247
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_confirm.php
Executable file
@@ -0,0 +1,247 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/mtn/passenger/confirm_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
function mlog(string $msg) { error_log($msg); } // timestamp يضاف تلقائياً من PHP
|
||||||
|
|
||||||
|
// قاعدة URL للتطبيق (لمعالجة BASE_URL غير المعروفة)
|
||||||
|
if (!defined('BASE_URL')) {
|
||||||
|
$APP_BASE_URL = rtrim(getenv('APP_BASE_URL') ?: '', '/');
|
||||||
|
if ($APP_BASE_URL === '') {
|
||||||
|
$scheme = isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : 'https';
|
||||||
|
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
||||||
|
define('BASE_URL', $scheme . '://' . $host);
|
||||||
|
} else {
|
||||||
|
define('BASE_URL', $APP_BASE_URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$baseUrl = rtrim(getenv('MTN_API_BASE_URL'), '/');
|
||||||
|
$terminalId = getenv('MTN_TERMINAL_ID');
|
||||||
|
$privateKeyPem = getenv('MTN_PRIVATE_KEY');
|
||||||
|
$privateKey = openssl_pkey_get_private(file_get_contents("private_key.pem"));
|
||||||
|
$invoice = filterRequest('invoiceNumber');
|
||||||
|
$phone = filterRequest('phone');
|
||||||
|
$guid = filterRequest('guid');
|
||||||
|
$operationNumber = filterRequest('operationNumber');
|
||||||
|
$code = filterRequest('otp'); // الـ OTP
|
||||||
|
$lang = filterRequest("lang");
|
||||||
|
|
||||||
|
mlog("MTN Confirm: Start request for invoice={$invoice}, phone={$phone}, guid={$guid}, opNum={$operationNumber}");
|
||||||
|
|
||||||
|
if (!$invoice || !$phone || !$guid || !$operationNumber || !$code) {
|
||||||
|
mlog("MTN Confirm: Missing parameters");
|
||||||
|
printFailure("Missing parameters.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// تشفير الكود (SHA256 ثم Base64)
|
||||||
|
$hashBin = hash('sha256', $code, true);
|
||||||
|
$codeB64 = base64_encode($hashBin);
|
||||||
|
|
||||||
|
// جسم الطلب نحو MTN
|
||||||
|
$body = [
|
||||||
|
'Invoice' => (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);
|
||||||
|
}
|
||||||
130
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_start.php
Executable file
130
walletintaleq.intaleq.xyz/v2/main/ride/mtn/passenger/mtn_start.php
Executable file
@@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
date_default_timezone_set("Asia/Damascus");
|
||||||
|
|
||||||
|
// ========== إعدادات MTN ==========
|
||||||
|
$terminalId = "9001000000060863";
|
||||||
|
$currencyCode = 760;
|
||||||
|
$sessionNumber = 0;
|
||||||
|
$ttl = 15;
|
||||||
|
|
||||||
|
// ====== استقبال البيانات من فلاتر ======
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
$passengerId = filterRequest("passengerId");
|
||||||
|
$phone = filterRequest("phone");
|
||||||
|
$lang = filterRequest("lang");
|
||||||
|
|
||||||
|
// ✅ Log مبدئي
|
||||||
|
error_log("🚦 START | passengerId: $passengerId | phone: $phone | amount: $amount");
|
||||||
|
|
||||||
|
// تحقق من المدخلات
|
||||||
|
if (empty($amount) || empty($passengerId) || empty($phone) || $amount <= 0) {
|
||||||
|
error_log("❌ Invalid input: amount=$amount, passengerId=$passengerId, phone=$phone");
|
||||||
|
printFailure("بيانات الدفع غير كاملة أو غير صالحة.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== توليد invoiceNumber و GUID ======
|
||||||
|
$invoiceNumber = mt_rand(10000000000, 99999999999);
|
||||||
|
//$invoiceNumber = "MTN_" . $passengerId . "_" . time();
|
||||||
|
$guid = uniqid("mtn_");
|
||||||
|
error_log("🧾 Generated Invoice: $invoiceNumber");
|
||||||
|
error_log("🧭 Generated GUID: $guid");
|
||||||
|
|
||||||
|
// ====== 1. إنشاء الفاتورة ======
|
||||||
|
$createInvoiceBody = [
|
||||||
|
"Amount" => 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);
|
||||||
|
}
|
||||||
@@ -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-----
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqBQZEJXWCQwPsPzBM70M3TjyU
|
||||||
|
5vwCZWoEtUomR9Qu+dEQaa0Hniz6JY8+goCxfMYuZQw6+kimctA2KqzT2pCsJufN
|
||||||
|
b92pSAMZgb0RSTl2y62oJkJd2WY7dj36AvPEyw6DxCFItvFOu7HGl3LlHQBriiw3
|
||||||
|
jwtuS6DO7gbmAJPU8wIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
@@ -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.');
|
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)");
|
$stmtSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)");
|
||||||
$stmtSefer->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
$stmtSiro->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
||||||
if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed.');
|
if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed.');
|
||||||
|
|
||||||
return ['success' => true, 'message' => 'Driver wallets updated.'];
|
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.');
|
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)");
|
$stmtSiro = $con->prepare("INSERT INTO siroWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)");
|
||||||
$stmtSefer->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
$stmtSiro->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]);
|
||||||
if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet for passenger failed.');
|
if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet for passenger failed.');
|
||||||
|
|
||||||
return ['success' => true, 'message' => 'Passenger wallets updated.'];
|
return ['success' => true, 'message' => 'Passenger wallets updated.'];
|
||||||
}
|
}
|
||||||
|
|||||||
100
walletintaleq.intaleq.xyz/v2/main/ride/payMob/payWithPayMob.php
Normal file
100
walletintaleq.intaleq.xyz/v2/main/ride/payMob/payWithPayMob.php
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
<?php
|
||||||
|
include "../../jwtconnect.php";
|
||||||
|
// 1. احصل على AUTH TOKEN
|
||||||
|
$api_key = getenv("payMobApiKey1"); // ضع API Key الخاص بك هنا
|
||||||
|
$email= filterRequest("amount");
|
||||||
|
$first_name= filterRequest("first_name");
|
||||||
|
$last_name= filterRequest("last_name");
|
||||||
|
$phone_number= filterRequest("phone_number");
|
||||||
|
$amount= filterRequest("amount");
|
||||||
|
|
||||||
|
$auth_url = "https://accept.paymob.com/api/auth/tokens";
|
||||||
|
$auth_data = json_encode(["api_key" => $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);
|
||||||
|
}
|
||||||
358
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php
Normal file
358
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymet_verfy.php
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
<?php
|
||||||
|
include "../../jwtconnect.php";
|
||||||
|
|
||||||
|
define("BASE_URL", "https://wl.tripz-egypt.com/v1/main/ride");
|
||||||
|
define("LOG_FILE", "../logs/payment_verification.log"); // Define log file path
|
||||||
|
|
||||||
|
// Function to write to error log
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
$logEntry = "[{$timestamp}] STEP {$step}: {$message}";
|
||||||
|
|
||||||
|
if ($data !== null) {
|
||||||
|
$logEntry .= " | Data: " . json_encode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure log directory exists
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) {
|
||||||
|
mkdir($logDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to log file
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Also log to PHP error log for server monitoring
|
||||||
|
// error_log("PAYMENT_VERIFICATION: {$logEntry}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive parameters from GET request
|
||||||
|
$user_id = filterRequest("user_id");
|
||||||
|
$passengerId = filterRequest("passengerId");
|
||||||
|
$paymentMethod = filterRequest("paymentMethod");
|
||||||
|
|
||||||
|
// Log initial request
|
||||||
|
// logError("0", "Request received", [
|
||||||
|
// "user_id" => $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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
Binary file not shown.
100
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithCard.php
Executable file
100
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithCard.php
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
// 1. احصل على AUTH TOKEN
|
||||||
|
$api_key = getenv("payMobApiKey1"); // ضع API Key الخاص بك هنا
|
||||||
|
$email= filterRequest("amount");
|
||||||
|
$first_name= filterRequest("first_name");
|
||||||
|
$last_name= filterRequest("last_name");
|
||||||
|
$phone_number= filterRequest("phone_number");
|
||||||
|
$amount= filterRequest("amount");
|
||||||
|
|
||||||
|
$auth_url = "https://accept.paymob.com/api/auth/tokens";
|
||||||
|
$auth_data = json_encode(["api_key" => $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);
|
||||||
|
}
|
||||||
118
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithWallet.php
Executable file
118
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/payWithWallet.php
Executable file
@@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// 1️⃣ AUTH TOKEN
|
||||||
|
$api_key = getenv("payMobApiKey1");
|
||||||
|
$integration_id = getenv("paymobIntegratedIdDriverWallet"); // 🔁 تأكد أنه خاص بالسائق
|
||||||
|
|
||||||
|
$email = filterRequest("email");
|
||||||
|
$first_name = filterRequest("first_name");
|
||||||
|
$last_name = filterRequest("last_name");
|
||||||
|
$phone_number = filterRequest("phone_number"); // هاتف السائق
|
||||||
|
$wallet_phone = '+2'.$phone_number;
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
|
||||||
|
$auth_url = "https://accept.paymob.com/api/auth/tokens";
|
||||||
|
$auth_data = json_encode(["api_key" => $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;
|
||||||
|
}
|
||||||
146
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymet_verfy.php
Executable file
146
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymet_verfy.php
Executable file
@@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
define('BASE_URL', 'https://wl.tripz-egypt.com/v1/main/ride');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$driverId = filterRequest('driverID');
|
||||||
|
$user_id = filterRequest('user_id');
|
||||||
|
$paymentMethod = filterRequest('paymentMethod');
|
||||||
|
|
||||||
|
if (empty($user_id) || empty($driverId)) {
|
||||||
|
printFailure('Missing user_id or driverID.');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1️⃣ تحقق من سجل الدفع خلال آخر دقيقتين
|
||||||
|
$stmt = $con->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;
|
||||||
|
}
|
||||||
110
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_payout.php
Executable file
110
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_payout.php
Executable file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
// paymob_payout.php
|
||||||
|
// سكريبت بي ات بي لمعاملات Paymob Payout (محفظة وبنك) بدون تخزين في قاعدة البيانات
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
include '../../../jwtconnect.php'; // يعطيك $con، filterRequest(), printSuccess(), printFailure()
|
||||||
|
|
||||||
|
// 1) جلب باراميترات الطلب عبر filterRequest
|
||||||
|
$driverId = filterRequest('driverID');
|
||||||
|
$amount = filterRequest('amount');
|
||||||
|
$method = filterRequest('method'); // 'wallet' أو 'bank'
|
||||||
|
$msisdn = filterRequest('msisdn');
|
||||||
|
$bankCard = filterRequest('bankCard'); // يُستعمل عند method == 'bank'
|
||||||
|
$bankCode = filterRequest('bankCode'); // يُستعمل عند method == 'bank'
|
||||||
|
|
||||||
|
if (empty($driverId) || empty($amount) || empty($method)) {
|
||||||
|
printFailure('Missing parameters');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) جلب بيانات Paymob من البيئة (Environment Variables)
|
||||||
|
$pmUser = getenv('payMobOutUserName');
|
||||||
|
$pmPass = getenv('payMobOutPassword');
|
||||||
|
$pmClientId = getenv('PAYMOBOUTCLIENT_ID'); // من static const pmobid
|
||||||
|
$pmSecret = getenv('PAYMOBOUTCLIENTSECRET'); // من static const pmobsec
|
||||||
|
|
||||||
|
// 3) دالة للحصول على OAuth Token من Paymob
|
||||||
|
function fetchPaymobToken(string $user, string $pass, string $cid, string $secret): ?string {
|
||||||
|
$ch = curl_init('https://payouts.paymobsolutions.com/api/secure/o/token/');
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_POST => 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);
|
||||||
|
?>
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة HMAC من الهيدر أو من الـ query
|
||||||
|
// ------------------------------
|
||||||
|
$received_hmac = $_SERVER['HTTP_HMAC'] ?? ($_GET['hmac'] ?? '');
|
||||||
|
$received_hmac = trim($received_hmac);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة البيانات القادمة من Paymob
|
||||||
|
// ------------------------------
|
||||||
|
$raw_body = file_get_contents("php://input");
|
||||||
|
$data = json_decode($raw_body, true);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// المفتاح السري
|
||||||
|
// ------------------------------
|
||||||
|
$secret_key = getenv('hmacPaymob');
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// دالة لتحويل القيم إلى النصوص
|
||||||
|
// ------------------------------
|
||||||
|
function normalize($value) {
|
||||||
|
if ($value === true) return 'true';
|
||||||
|
if ($value === false) return 'false';
|
||||||
|
if (is_null($value)) return '';
|
||||||
|
return (string)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// التحقق من صحة HMAC
|
||||||
|
// ------------------------------
|
||||||
|
function isValidHmac($data, $secret_key, $received_hmac) {
|
||||||
|
if (!isset($data['obj'])) return false;
|
||||||
|
|
||||||
|
$obj = $data['obj'];
|
||||||
|
|
||||||
|
// دمج جميع الحقول بشكل متسلسل
|
||||||
|
$fields = [
|
||||||
|
normalize($obj['amount_cents'] ?? ''),
|
||||||
|
normalize($obj['created_at'] ?? ''),
|
||||||
|
normalize($obj['currency'] ?? ''),
|
||||||
|
normalize($obj['error_occured'] ?? false),
|
||||||
|
normalize($obj['has_parent_transaction'] ?? false),
|
||||||
|
normalize($obj['id'] ?? ''),
|
||||||
|
normalize($obj['integration_id'] ?? ''),
|
||||||
|
normalize($obj['is_3d_secure'] ?? false),
|
||||||
|
normalize($obj['is_auth'] ?? false),
|
||||||
|
normalize($obj['is_capture'] ?? false),
|
||||||
|
normalize($obj['is_refunded'] ?? false),
|
||||||
|
normalize($obj['is_standalone_payment'] ?? false),
|
||||||
|
normalize($obj['is_voided'] ?? false),
|
||||||
|
normalize($obj['order']['id'] ?? ''),
|
||||||
|
normalize($obj['owner'] ?? ''),
|
||||||
|
normalize($obj['pending'] ?? false),
|
||||||
|
normalize($obj['source_data']['pan'] ?? ''),
|
||||||
|
normalize($obj['source_data']['sub_type'] ?? ''),
|
||||||
|
normalize($obj['source_data']['type'] ?? ''),
|
||||||
|
normalize($obj['success'] ?? false)
|
||||||
|
];
|
||||||
|
|
||||||
|
// دمج الحقول في رسالة واحدة
|
||||||
|
$message = implode('', $fields);
|
||||||
|
|
||||||
|
// حساب HMAC باستخدام المفتاح السري
|
||||||
|
$calculated_hmac = hash_hmac('sha512', $message, $secret_key);
|
||||||
|
|
||||||
|
//
|
||||||
|
/*طباعة الرسائل لأغراض التصحيح
|
||||||
|
error_log("🔐 Message used for HMAC: " . $message);
|
||||||
|
error_log("🔐 Calculated HMAC: " . $calculated_hmac);
|
||||||
|
error_log("📩 Received HMAC: " . $received_hmac);
|
||||||
|
error_log("Calculated HMAC length: " . strlen($calculated_hmac));
|
||||||
|
error_log("Received HMAC length: " . strlen($received_hmac));
|
||||||
|
*/
|
||||||
|
// التحقق من تطابق HMAC
|
||||||
|
if (hash_equals($calculated_hmac, $received_hmac)) {
|
||||||
|
error_log("✅ Valid HMAC signature verified.");
|
||||||
|
return $calculated_hmac;
|
||||||
|
} else {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "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()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
142
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webhook.php
Executable file
142
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_driver/paymob_webhook.php
Executable file
@@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة HMAC من الهيدر أو من الـ query
|
||||||
|
// ------------------------------
|
||||||
|
$received_hmac = $_SERVER['HTTP_HMAC'] ?? ($_GET['hmac'] ?? '');
|
||||||
|
$received_hmac = trim($received_hmac);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة البيانات القادمة من Paymob
|
||||||
|
// ------------------------------
|
||||||
|
$raw_body = file_get_contents("php://input");
|
||||||
|
$data = json_decode($raw_body, true);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// المفتاح السري
|
||||||
|
// ------------------------------
|
||||||
|
$secret_key = getenv('hmacPaymob');
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// دالة لتحويل القيم إلى النصوص
|
||||||
|
// ------------------------------
|
||||||
|
function normalize($value) {
|
||||||
|
if ($value === true) return 'true';
|
||||||
|
if ($value === false) return 'false';
|
||||||
|
if (is_null($value)) return '';
|
||||||
|
return (string)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// التحقق من صحة HMAC
|
||||||
|
// ------------------------------
|
||||||
|
function isValidHmac($data, $secret_key, $received_hmac) {
|
||||||
|
if (!isset($data['obj'])) return false;
|
||||||
|
|
||||||
|
$obj = $data['obj'];
|
||||||
|
|
||||||
|
// دمج جميع الحقول بشكل متسلسل
|
||||||
|
$fields = [
|
||||||
|
normalize($obj['amount_cents'] ?? ''),
|
||||||
|
normalize($obj['created_at'] ?? ''),
|
||||||
|
normalize($obj['currency'] ?? ''),
|
||||||
|
normalize($obj['error_occured'] ?? false),
|
||||||
|
normalize($obj['has_parent_transaction'] ?? false),
|
||||||
|
normalize($obj['id'] ?? ''),
|
||||||
|
normalize($obj['integration_id'] ?? ''),
|
||||||
|
normalize($obj['is_3d_secure'] ?? false),
|
||||||
|
normalize($obj['is_auth'] ?? false),
|
||||||
|
normalize($obj['is_capture'] ?? false),
|
||||||
|
normalize($obj['is_refunded'] ?? false),
|
||||||
|
normalize($obj['is_standalone_payment'] ?? false),
|
||||||
|
normalize($obj['is_voided'] ?? false),
|
||||||
|
normalize($obj['order']['id'] ?? ''),
|
||||||
|
normalize($obj['owner'] ?? ''),
|
||||||
|
normalize($obj['pending'] ?? false),
|
||||||
|
normalize($obj['source_data']['pan'] ?? ''),
|
||||||
|
normalize($obj['source_data']['sub_type'] ?? ''),
|
||||||
|
normalize($obj['source_data']['type'] ?? ''),
|
||||||
|
normalize($obj['success'] ?? false)
|
||||||
|
];
|
||||||
|
|
||||||
|
// دمج الحقول في رسالة واحدة
|
||||||
|
$message = implode('', $fields);
|
||||||
|
|
||||||
|
// حساب HMAC باستخدام المفتاح السري
|
||||||
|
$calculated_hmac = hash_hmac('sha512', $message, $secret_key);
|
||||||
|
|
||||||
|
//
|
||||||
|
/*طباعة الرسائل لأغراض التصحيح
|
||||||
|
error_log("🔐 Message used for HMAC: " . $message);
|
||||||
|
error_log("🔐 Calculated HMAC: " . $calculated_hmac);
|
||||||
|
error_log("📩 Received HMAC: " . $received_hmac);
|
||||||
|
error_log("Calculated HMAC length: " . strlen($calculated_hmac));
|
||||||
|
error_log("Received HMAC length: " . strlen($received_hmac));
|
||||||
|
*/
|
||||||
|
// التحقق من تطابق HMAC
|
||||||
|
if (hash_equals($calculated_hmac, $received_hmac)) {
|
||||||
|
error_log("✅ Valid HMAC signature verified.");
|
||||||
|
return $calculated_hmac;
|
||||||
|
} else {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "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()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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
|
||||||
|
----------------------------
|
||||||
137
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.php
Normal file
137
walletintaleq.intaleq.xyz/v2/main/ride/payMob/paymob_webhook.php
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
include "../../jwtconnect.php";
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة HMAC من الهيدر أو من الـ query
|
||||||
|
// ------------------------------
|
||||||
|
$received_hmac = $_SERVER['HTTP_HMAC'] ?? ($_GET['hmac'] ?? '');
|
||||||
|
$received_hmac = trim($received_hmac);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة البيانات القادمة من Paymob
|
||||||
|
// ------------------------------
|
||||||
|
$raw_body = file_get_contents("php://input");
|
||||||
|
$data = json_decode($raw_body, true);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// المفتاح السري
|
||||||
|
// ------------------------------
|
||||||
|
$secret_key = getenv('hmacPaymob');
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// دالة لتحويل القيم إلى النصوص
|
||||||
|
// ------------------------------
|
||||||
|
function normalize($value) {
|
||||||
|
if ($value === true) return 'true';
|
||||||
|
if ($value === false) return 'false';
|
||||||
|
if (is_null($value)) return '';
|
||||||
|
return (string)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// التحقق من صحة HMAC
|
||||||
|
// ------------------------------
|
||||||
|
function isValidHmac($data, $secret_key, $received_hmac) {
|
||||||
|
if (!isset($data['obj'])) return false;
|
||||||
|
|
||||||
|
$obj = $data['obj'];
|
||||||
|
|
||||||
|
// دمج جميع الحقول بشكل متسلسل
|
||||||
|
$fields = [
|
||||||
|
normalize($obj['amount_cents'] ?? ''),
|
||||||
|
normalize($obj['created_at'] ?? ''),
|
||||||
|
normalize($obj['currency'] ?? ''),
|
||||||
|
normalize($obj['error_occured'] ?? false),
|
||||||
|
normalize($obj['has_parent_transaction'] ?? false),
|
||||||
|
normalize($obj['id'] ?? ''),
|
||||||
|
normalize($obj['integration_id'] ?? ''),
|
||||||
|
normalize($obj['is_3d_secure'] ?? false),
|
||||||
|
normalize($obj['is_auth'] ?? false),
|
||||||
|
normalize($obj['is_capture'] ?? false),
|
||||||
|
normalize($obj['is_refunded'] ?? false),
|
||||||
|
normalize($obj['is_standalone_payment'] ?? false),
|
||||||
|
normalize($obj['is_voided'] ?? false),
|
||||||
|
normalize($obj['order']['id'] ?? ''),
|
||||||
|
normalize($obj['owner'] ?? ''),
|
||||||
|
normalize($obj['pending'] ?? false),
|
||||||
|
normalize($obj['source_data']['pan'] ?? ''),
|
||||||
|
normalize($obj['source_data']['sub_type'] ?? ''),
|
||||||
|
normalize($obj['source_data']['type'] ?? ''),
|
||||||
|
normalize($obj['success'] ?? false)
|
||||||
|
];
|
||||||
|
|
||||||
|
// دمج الحقول في رسالة واحدة
|
||||||
|
$message = implode('', $fields);
|
||||||
|
|
||||||
|
// حساب HMAC باستخدام المفتاح السري
|
||||||
|
$calculated_hmac = hash_hmac('sha512', $message, $secret_key);
|
||||||
|
|
||||||
|
// طباعة الرسائل لأغراض التصحيح
|
||||||
|
// error_log("🔐 Message used for HMAC: " . $message);
|
||||||
|
// error_log("🔐 Calculated HMAC: " . $calculated_hmac);
|
||||||
|
// error_log("📩 Received HMAC: " . $received_hmac);
|
||||||
|
// error_log("Calculated HMAC length: " . strlen($calculated_hmac));
|
||||||
|
// error_log("Received HMAC length: " . strlen($received_hmac));
|
||||||
|
|
||||||
|
// التحقق من تطابق HMAC
|
||||||
|
if (hash_equals($calculated_hmac, $received_hmac)) {
|
||||||
|
error_log("✅ Valid HMAC signature verified.");
|
||||||
|
return $calculated_hmac;
|
||||||
|
} else {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "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()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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] ❌ فشل الدفع عبر المحفظة!
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// 1. احصل على AUTH TOKEN
|
||||||
|
$api_key = getenv("payMobApiKey1");
|
||||||
|
$integration_id = getenv("paymobIntegratedIdWallet");
|
||||||
|
$email = filterRequest("email");
|
||||||
|
$first_name = filterRequest("first_name");
|
||||||
|
$last_name = filterRequest("last_name");
|
||||||
|
$phone_number = filterRequest("phone_number");
|
||||||
|
$wallet_phone = filterRequest("phone_number");
|
||||||
|
$amount = filterRequest("amount");
|
||||||
|
|
||||||
|
$auth_url = "https://accept.paymob.com/api/auth/tokens";
|
||||||
|
$auth_data = json_encode(["api_key" => $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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,358 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
define("BASE_URL", "https://wl.tripz-egypt.com/v1/main/ride");
|
||||||
|
define("LOG_FILE", "../logs/payment_verification.log"); // Define log file path
|
||||||
|
|
||||||
|
// Function to write to error log
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
$logEntry = "[{$timestamp}] STEP {$step}: {$message}";
|
||||||
|
|
||||||
|
if ($data !== null) {
|
||||||
|
$logEntry .= " | Data: " . json_encode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure log directory exists
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) {
|
||||||
|
mkdir($logDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to log file
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Also log to PHP error log for server monitoring
|
||||||
|
// error_log("PAYMENT_VERIFICATION: {$logEntry}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive parameters from GET request
|
||||||
|
$user_id = filterRequest("user_id");
|
||||||
|
$passengerId = filterRequest("passengerId");
|
||||||
|
$paymentMethod = filterRequest("paymentMethod");
|
||||||
|
|
||||||
|
// Log initial request
|
||||||
|
// logError("0", "Request received", [
|
||||||
|
// "user_id" => $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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة HMAC من الهيدر أو من الـ query
|
||||||
|
// ------------------------------
|
||||||
|
$received_hmac = $_SERVER['HTTP_HMAC'] ?? ($_GET['hmac'] ?? '');
|
||||||
|
$received_hmac = trim($received_hmac);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// قراءة البيانات القادمة من Paymob
|
||||||
|
// ------------------------------
|
||||||
|
$raw_body = file_get_contents("php://input");
|
||||||
|
$data = json_decode($raw_body, true);
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// المفتاح السري
|
||||||
|
// ------------------------------
|
||||||
|
$secret_key = getenv('hmacPaymob');
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// دالة لتحويل القيم إلى النصوص
|
||||||
|
// ------------------------------
|
||||||
|
function normalize($value) {
|
||||||
|
if ($value === true) return 'true';
|
||||||
|
if ($value === false) return 'false';
|
||||||
|
if (is_null($value)) return '';
|
||||||
|
return (string)$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// التحقق من صحة HMAC
|
||||||
|
// ------------------------------
|
||||||
|
function isValidHmac($data, $secret_key, $received_hmac) {
|
||||||
|
if (!isset($data['obj'])) return false;
|
||||||
|
|
||||||
|
$obj = $data['obj'];
|
||||||
|
|
||||||
|
// دمج جميع الحقول بشكل متسلسل
|
||||||
|
$fields = [
|
||||||
|
normalize($obj['amount_cents'] ?? ''),
|
||||||
|
normalize($obj['created_at'] ?? ''),
|
||||||
|
normalize($obj['currency'] ?? ''),
|
||||||
|
normalize($obj['error_occured'] ?? false),
|
||||||
|
normalize($obj['has_parent_transaction'] ?? false),
|
||||||
|
normalize($obj['id'] ?? ''),
|
||||||
|
normalize($obj['integration_id'] ?? ''),
|
||||||
|
normalize($obj['is_3d_secure'] ?? false),
|
||||||
|
normalize($obj['is_auth'] ?? false),
|
||||||
|
normalize($obj['is_capture'] ?? false),
|
||||||
|
normalize($obj['is_refunded'] ?? false),
|
||||||
|
normalize($obj['is_standalone_payment'] ?? false),
|
||||||
|
normalize($obj['is_voided'] ?? false),
|
||||||
|
normalize($obj['order']['id'] ?? ''),
|
||||||
|
normalize($obj['owner'] ?? ''),
|
||||||
|
normalize($obj['pending'] ?? false),
|
||||||
|
normalize($obj['source_data']['pan'] ?? ''),
|
||||||
|
normalize($obj['source_data']['sub_type'] ?? ''),
|
||||||
|
normalize($obj['source_data']['type'] ?? ''),
|
||||||
|
normalize($obj['success'] ?? false)
|
||||||
|
];
|
||||||
|
|
||||||
|
// دمج الحقول في رسالة واحدة
|
||||||
|
$message = implode('', $fields);
|
||||||
|
|
||||||
|
// حساب HMAC باستخدام المفتاح السري
|
||||||
|
$calculated_hmac = hash_hmac('sha512', $message, $secret_key);
|
||||||
|
|
||||||
|
// طباعة الرسائل لأغراض التصحيح
|
||||||
|
// error_log("🔐 Message used for HMAC: " . $message);
|
||||||
|
// error_log("🔐 Calculated HMAC: " . $calculated_hmac);
|
||||||
|
// error_log("📩 Received HMAC: " . $received_hmac);
|
||||||
|
// error_log("Calculated HMAC length: " . strlen($calculated_hmac));
|
||||||
|
// error_log("Received HMAC length: " . strlen($received_hmac));
|
||||||
|
|
||||||
|
// التحقق من تطابق HMAC
|
||||||
|
if (hash_equals($calculated_hmac, $received_hmac)) {
|
||||||
|
error_log("✅ Valid HMAC signature verified.");
|
||||||
|
return $calculated_hmac;
|
||||||
|
} else {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "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()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
22
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/check_status.php
Executable file
22
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/check_status.php
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/check_status.php
|
||||||
|
include "../../jwtconnect.php";
|
||||||
|
|
||||||
|
$invoice_number = filterRequest("invoice_number");
|
||||||
|
|
||||||
|
if (empty($invoice_number)) { printFailure("invoice_number required"); exit; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $con->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());
|
||||||
|
}
|
||||||
|
?>
|
||||||
45
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/create_invoice_shamcash.php
Executable file
45
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/create_invoice_shamcash.php
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/create_invoice_shamcash.php
|
||||||
|
// ينشئ الفاتورة ويعيد رقمها للسائق ليكتبه في الملاحظات
|
||||||
|
|
||||||
|
include "../../jwtconnect.php";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$driverID = filterRequest("driverID");
|
||||||
|
$amount_raw = filterRequest("amount");
|
||||||
|
|
||||||
|
$amount = is_numeric($amount_raw) ? (float) $amount_raw : 0.0;
|
||||||
|
|
||||||
|
if (empty($driverID) || $amount <= 0) {
|
||||||
|
printFailure("Required: driverID, amount");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// البحث عن فاتورة معلقة لنفس السائق والمبلغ (لتجنب التكرار)
|
||||||
|
$stmt = $con->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());
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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
|
||||||
120
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/finalize_deposit.php
Executable file
120
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/finalize_deposit.php
Executable file
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/finalize_deposit.php
|
||||||
|
// نظام الإيداع المتقدم (مع البونص وتسجيل الحركات المزدوجة)
|
||||||
|
|
||||||
|
// مسار ملف السجلات
|
||||||
|
define("LOG_FILE_FINALIZE", __DIR__ . "/deposit_errors.log");
|
||||||
|
|
||||||
|
if (!function_exists('logError')) {
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents(LOG_FILE_FINALIZE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('generateToken')) {
|
||||||
|
function generateToken($con, $driverId, $amount) {
|
||||||
|
$data = $driverId . $amount . time() . 'shamcash_secret';
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
120840498
|
||||||
22
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/check_status.php
Executable file
22
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/check_status.php
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/passenger/check_status.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
$invoice_number = filterRequest("invoice_number");
|
||||||
|
|
||||||
|
if (empty($invoice_number)) { printFailure("invoice_number required"); exit; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $con->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());
|
||||||
|
}
|
||||||
|
?>
|
||||||
41
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/create_invoice.php
Executable file
41
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/create_invoice.php
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/passenger/create_invoice.php
|
||||||
|
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$passengerID = filterRequest("passengerID");
|
||||||
|
$amount_raw = filterRequest("amount");
|
||||||
|
$amount = is_numeric($amount_raw) ? (float) $amount_raw : 0.0;
|
||||||
|
|
||||||
|
if (empty($passengerID) || $amount <= 0) {
|
||||||
|
printFailure("Required: passengerID and valid amount");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// البحث عن فاتورة معلقة لنفس الراكب
|
||||||
|
$stmt = $con->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());
|
||||||
|
}
|
||||||
|
?>
|
||||||
127
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/finalize_deposit.php
Executable file
127
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/passenger/finalize_deposit.php
Executable file
@@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/passenger/finalize_deposit.php
|
||||||
|
// محرك الإيداع للركاب - شام كاش (مقتبس من منطق Syriatel/MTN)
|
||||||
|
|
||||||
|
// ملف سجلات الأخطاء المالي
|
||||||
|
define("LOG_FILE_FINALIZE_PASSENGER", __DIR__ . "/deposit_financial_passenger.log");
|
||||||
|
|
||||||
|
if (!function_exists('logFinancialPassenger')) {
|
||||||
|
function logFinancialPassenger($step, $message, $data = null) {
|
||||||
|
$logDir = dirname(LOG_FILE_FINALIZE_PASSENGER);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
|
||||||
|
$entry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data) $entry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
|
file_put_contents(LOG_FILE_FINALIZE_PASSENGER, $entry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// دوال مساعدة (Helpers) - تحاكي دوال الـ API الموجودة في كودك القديم
|
||||||
|
// في بيئة الإنتاج، يفضل استدعاء ملفات الـ API الموجودة لديك بالفعل لضمان التوافق
|
||||||
|
// لكن هنا سنكتب المنطق المباشر لقاعدة البيانات للسرعة والوضوح
|
||||||
|
|
||||||
|
if (!function_exists('calculateBonusPassenger')) {
|
||||||
|
function calculateBonusPassenger($amount) {
|
||||||
|
// نفس منطق البونص الذي أرسلته
|
||||||
|
return match ((int)$amount) {
|
||||||
|
|
||||||
|
500 => 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
121
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions.php
Executable file
121
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions.php
Executable file
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/save_transactions.php (Debug Edition)
|
||||||
|
|
||||||
|
ini_set('display_errors', 0);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
|
$log_file = __DIR__ . '/transactions.log';
|
||||||
|
$last_id_file = __DIR__ . '/last_id.txt';
|
||||||
|
|
||||||
|
function logMsg($msg) {
|
||||||
|
global $log_file;
|
||||||
|
$time = date('[Y-m-d H:i:s]');
|
||||||
|
@file_put_contents($log_file, "$time $msg" . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
|
||||||
|
|
||||||
|
// الاتصال بقاعدة البيانات
|
||||||
|
$paths = [__DIR__.'/../jwtconnect.php', __DIR__.'/../../jwtconnect.php', __DIR__.'/../../../jwtconnect.php'];
|
||||||
|
foreach ($paths as $p) { if (file_exists($p)) { include $p; if(isset($con)) break; } }
|
||||||
|
if (!isset($con)) { logMsg("CRITICAL: DB Connection Failed"); exit(json_encode(["status" => "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]);
|
||||||
|
?>
|
||||||
117
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions_new.php
Executable file
117
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/save_transactions_new.php
Executable file
@@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// shamcash/save_transactions.php
|
||||||
|
// يعتمد حصرياً على Note (Invoice Number)
|
||||||
|
|
||||||
|
ini_set('display_errors', 0);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
header("Access-Control-Allow-Methods: POST, OPTIONS");
|
||||||
|
header("Access-Control-Allow-Headers: Content-Type");
|
||||||
|
|
||||||
|
$log_file = __DIR__ . '/transactions.log';
|
||||||
|
$last_id_file = __DIR__ . '/last_id.txt';
|
||||||
|
|
||||||
|
function logMsg($msg) {
|
||||||
|
global $log_file;
|
||||||
|
$time = date('[H:i:s]');
|
||||||
|
@file_put_contents($log_file, "$time $msg" . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
|
http_response_code(200); exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 1. الاتصال بقاعدة البيانات ---
|
||||||
|
// البحث عن jwtconnect.php في المجلدات العلوية
|
||||||
|
$possible_paths = [__DIR__ . '/../jwtconnect.php', __DIR__ . '/../../jwtconnect.php'];
|
||||||
|
$db_connected = false;
|
||||||
|
foreach ($possible_paths as $path) {
|
||||||
|
if (file_exists($path)) { include $path; if(isset($con)){ $db_connected = true; break; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$db_connected) {
|
||||||
|
logMsg("CRITICAL: DB Connection Failed.");
|
||||||
|
echo json_encode(["status" => "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]);
|
||||||
|
?>
|
||||||
60
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/server_check.php
Executable file
60
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/server_check.php
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
// shamcash/server_check.php - V2 (The Doctor)
|
||||||
|
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
header("Content-Type: text/html; charset=utf-8");
|
||||||
|
|
||||||
|
echo "<h2>🔍 Server & File Diagnostics</h2>";
|
||||||
|
|
||||||
|
// 1. فحص المجلد
|
||||||
|
$dir = __DIR__;
|
||||||
|
echo "<strong>Current Dir:</strong> $dir <br>";
|
||||||
|
if (is_writable($dir)) {
|
||||||
|
echo "<span style='color:green'>✅ Directory is Writable (777 OK)</span><br>";
|
||||||
|
} else {
|
||||||
|
echo "<span style='color:red'>❌ Directory NOT Writable! Please set Permissions to 777.</span><br>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. فحص ملف save_transactions.php
|
||||||
|
$target_file = $dir . '/save_transactions.php';
|
||||||
|
echo "<hr><h3>Testing 'save_transactions.php':</h3>";
|
||||||
|
|
||||||
|
if (!file_exists($target_file)) {
|
||||||
|
echo "<span style='color:red'>❌ File not found!</span>";
|
||||||
|
} else {
|
||||||
|
// محاولة فحص الكود بحثاً عن أخطاء نحوية (Syntax Errors)
|
||||||
|
$content = file_get_contents($target_file);
|
||||||
|
|
||||||
|
// فحص إذا كان المستخدم نسخ علامات Markdown بالخطأ
|
||||||
|
if (strpos($content, '```') !== false) {
|
||||||
|
echo "<span style='color:red'>❌ <b>CRITICAL ERROR FOUND:</b></span> Markdown tags (```) detected inside the PHP file!<br>";
|
||||||
|
echo "👉 <b>Solution:</b> Open the file and remove the first/last lines containing ``` or ```php.<br>";
|
||||||
|
} elseif (substr(trim($content), 0, 5) !== '<?php') {
|
||||||
|
echo "<span style='color:red'>❌ <b>START ERROR:</b></span> File does not start with <?php<br>";
|
||||||
|
echo "Found instead: " . substr(trim($content), 0, 20) . "...<br>";
|
||||||
|
} else {
|
||||||
|
echo "<span style='color:green'>✅ File structure looks clean (No Markdown tags).</span><br>";
|
||||||
|
|
||||||
|
// محاولة استدعاء الملف (سيظهر الخطأ إذا وجد)
|
||||||
|
echo "<b>Attempting to include file...</b><br><br>";
|
||||||
|
echo "<div style='background:#f0f0f0; padding:10px; border:1px solid #ccc;'>";
|
||||||
|
|
||||||
|
// نحجز المخرجات لنرى إذا كان هناك خطأ
|
||||||
|
ob_start();
|
||||||
|
try {
|
||||||
|
include $target_file;
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo "<strong style='color:red'>Runtime Error:</strong> " . $e->getMessage();
|
||||||
|
}
|
||||||
|
$output = ob_get_clean();
|
||||||
|
|
||||||
|
if (empty($output)) {
|
||||||
|
echo "File included successfully (No output is good in this context).";
|
||||||
|
} else {
|
||||||
|
echo "<strong>Output/Error:</strong><br>" . $output;
|
||||||
|
}
|
||||||
|
echo "</div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
100
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/transactions.log
Normal file
100
walletintaleq.intaleq.xyz/v2/main/ride/shamcash/transactions.log
Normal file
@@ -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
|
||||||
@@ -35,8 +35,8 @@ try {
|
|||||||
if ($tokenData) {
|
if ($tokenData) {
|
||||||
// logDebug("Valid token found!");
|
// logDebug("Valid token found!");
|
||||||
|
|
||||||
// Insert into Sefer Wallet
|
// Insert into Siro Wallet
|
||||||
$sql = "INSERT INTO `seferWallet` (
|
$sql = "INSERT INTO `siroWallet` (
|
||||||
`driverId`,
|
`driverId`,
|
||||||
`passengerId`,
|
`passengerId`,
|
||||||
`amount`,
|
`amount`,
|
||||||
@@ -78,7 +78,7 @@ try {
|
|||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// logDebug("Exception: " . $e->getMessage());
|
// logDebug("Exception: " . $e->getMessage());
|
||||||
error_log("[seferWallet/add] " . $e->getMessage());
|
error_log("[siroWallet/add] " . $e->getMessage());
|
||||||
printFailure("An error occurred");
|
printFailure("An error occurred");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -8,7 +8,7 @@ $order_id = filterRequest("order_id");
|
|||||||
$sql = "SELECT
|
$sql = "SELECT
|
||||||
SUM(amount)
|
SUM(amount)
|
||||||
FROM
|
FROM
|
||||||
`seferWallet`
|
`siroWallet`
|
||||||
WHERE
|
WHERE
|
||||||
createdAt BETWEEN DATE_FORMAT(CURRENT_DATE, '%Y-%m-01') AND LAST_DAY(CURRENT_DATE)";
|
createdAt BETWEEN DATE_FORMAT(CURRENT_DATE, '%Y-%m-01') AND LAST_DAY(CURRENT_DATE)";
|
||||||
|
|
||||||
BIN
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/archive.zip
Executable file
BIN
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/archive.zip
Executable file
Binary file not shown.
237
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php
Executable file
237
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/confirm_payment.php
Executable file
@@ -0,0 +1,237 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/syriatel/driver/confirm_payment.php
|
||||||
|
// يعتمد على jwtconnect.php و syriatel_token_handler.php فقط
|
||||||
|
include_once "../../../jwtconnect.php";
|
||||||
|
include_once "./syriatel_token_handler.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// ================== Helpers (طباعة/لوج) ==================
|
||||||
|
if (!function_exists('printSuccess')) {
|
||||||
|
function printSuccess($data = null, $message = "success") {
|
||||||
|
echo json_encode(["status" => "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.");
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
// wallet/finalize_wallet_payment.php
|
||||||
|
|
||||||
|
// تم حذف include_once من هنا لأنه يُفترض أن ملف الاتصال قد تم تحميله بالفعل
|
||||||
|
// بواسطة الملف الذي يستدعي هذه الدالة (confirm_payment.php).
|
||||||
|
// include_once "../../../jwtconnect.php";
|
||||||
|
|
||||||
|
define("LOG_FILE", __DIR__ . "/../logs/payment_verification.log");
|
||||||
|
|
||||||
|
if (!function_exists('logError')) {
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logDir = dirname(LOG_FILE);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents(LOG_FILE, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('generateToken')) {
|
||||||
|
function generateToken($con, $driverId, $amount): ?string {
|
||||||
|
global $secretKey;
|
||||||
|
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret');
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
141
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/start_payment.php
Executable file
141
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/driver/start_payment.php
Executable file
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/syriatel/driver/start_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
include_once "./syriatel_token_handler.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
/** دوال الطباعة (لو موجودة أصلاً في jwtconnect.php تجاهل هذه) */
|
||||||
|
if (!function_exists('printSuccess')) {
|
||||||
|
function printSuccess($data = null, $message = "success") {
|
||||||
|
echo json_encode(["status"=>"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.");
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php // syriatel_token_handler
|
||||||
|
function getSyriatelToken(): ?string {
|
||||||
|
// اضبط البيئة: prod أو stage (افتراضي prod)
|
||||||
|
$env = getenv("SYRIATEL_ENV") ?: "prod";
|
||||||
|
|
||||||
|
// Base URLs من Postman
|
||||||
|
$baseStage = "https://merchants.syriatel.sy:1443/ePayment_external_Json_test/rs/ePaymentExternalModule";
|
||||||
|
$baseProd = "https://merchants.syriatel.sy:1443/ePayment_external_Json/rs/ePaymentExternalModule";
|
||||||
|
|
||||||
|
$baseUrl = ($env === "stage") ? $baseStage : $baseProd;
|
||||||
|
$url = $baseUrl . "/getToken";
|
||||||
|
|
||||||
|
// ⚠️ لا تضع قيم افتراضية حساسة Hardcoded
|
||||||
|
$username = getenv("SYRIATEL_USERNAME");
|
||||||
|
$password = getenv("SYRIATEL_PASSWORD");
|
||||||
|
|
||||||
|
if (!$username || !$password) {
|
||||||
|
error_log("[GetSyriatelToken] Missing credentials in ENV");
|
||||||
|
printFailure("Payment provider credentials are missing.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("[GetSyriatelToken] Env={$env} | URL={$url} | user={$username}");
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
"username" => $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;
|
||||||
|
}
|
||||||
@@ -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"}
|
||||||
201
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php
Executable file
201
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/confirm_payment.php
Executable file
@@ -0,0 +1,201 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/syriatel/passenger/confirm_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
include_once __DIR__ . "/syriatel_token_handler.php";
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
/** Helpers **/
|
||||||
|
function mlog(string $msg) { error_log($msg); }
|
||||||
|
|
||||||
|
// تعريف دالة توليد التوكن محلياً (نفس منطق السائق ولكن للراكب)
|
||||||
|
if (!function_exists('generateLocalToken')) {
|
||||||
|
function generateLocalToken($con, $userId, $amount) {
|
||||||
|
// مفتاح سري بسيط للتشفير (يمكنك تغييره أو جلبه من ملف الإعدادات)
|
||||||
|
$secretKey = 'Tripz_Passenger_Secret_Key';
|
||||||
|
$data = $userId . $amount . time() . $secretKey;
|
||||||
|
$hash = hash('sha256', $data);
|
||||||
|
$randomBytes = bin2hex(random_bytes(16));
|
||||||
|
$token = substr($hash . $randomBytes, 0, 64);
|
||||||
|
|
||||||
|
$stmt = $con->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;
|
||||||
|
}
|
||||||
|
?>
|
||||||
124
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/start_payment.php
Executable file
124
walletintaleq.intaleq.xyz/v2/main/ride/syriatel/passenger/start_payment.php
Executable file
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
// /v1/main/ride/syriatel/passenger/start_payment.php
|
||||||
|
include "../../../jwtconnect.php";
|
||||||
|
include_once "./syriatel_token_handler.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// --- Input Parameters ---
|
||||||
|
$amount = filterRequest('amount');
|
||||||
|
$passengerId = filterRequest('passengerId'); // بدل driverId
|
||||||
|
$phone = filterRequest('phone'); // رقم الراكب (customerMSISDN)
|
||||||
|
$lang = filterRequest('lang') ?? 'ar';
|
||||||
|
|
||||||
|
error_log("Syriatel Start (Passenger): Request received for passenger {$passengerId} with amount {$amount}");
|
||||||
|
|
||||||
|
if (!$amount || !$passengerId || !$phone) {
|
||||||
|
printFailure($lang === 'ar' ? "بيانات ناقصة." : "Missing required parameters.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Environment Variables ---
|
||||||
|
$baseUrl = rtrim(getenv('SYRIATEL_API_BASE_URL'), '/');
|
||||||
|
$merchantMSISDN = getenv('SYRIATEL_MERCHANT_MSISDN');
|
||||||
|
|
||||||
|
if (!$baseUrl || !$merchantMSISDN) {
|
||||||
|
error_log("Syriatel Start (Passenger): Missing SYRIATEL_API_BASE_URL or SYRIATEL_MERCHANT_MSISDN env variables.");
|
||||||
|
printFailure($lang === 'ar' ? "خطأ إعدادات الخادم." : "Server configuration error.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1) Get Authentication Token
|
||||||
|
$token = getSyriatelToken();
|
||||||
|
error_log("Syriatel Start (Passenger):token= .$token");
|
||||||
|
if (!$token) {
|
||||||
|
printFailure($lang === 'ar' ? "تعذّر المصادقة مع مزوّد الدفع." : "Could not authenticate with the payment provider.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Generate transaction ID + log
|
||||||
|
$transactionID = generate_order_ref(); // موجود لديك مسبقًا
|
||||||
|
// ملاحظة: استخدم جدول منفصل للركاب، أو وحّد الجدول مع حقل user_type. هنا نفترض جدول خاص بالراكب.
|
||||||
|
$stmt = $con->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.");
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"token":"E964A84D88C9A2306016886254475A49BE2BC95AFB6F4C30CD24857F5EFACDD2173D59A4B951CCEEE311AEFD3E40ABBF3E70BD2B1B8B3F0703E094C419E6291A6CFEA5C3CCD3B57E093FD58E6BB09ECF","expires_at":1759998218}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php // syriatel_token_handler
|
||||||
|
function getSyriatelToken(): ?string {
|
||||||
|
// اضبط البيئة: prod أو stage (افتراضي prod)
|
||||||
|
$env = getenv("SYRIATEL_ENV") ?: "prod";
|
||||||
|
|
||||||
|
// Base URLs من Postman
|
||||||
|
$baseStage = "https://merchants.syriatel.sy:1443/ePayment_external_Json_test/rs/ePaymentExternalModule";
|
||||||
|
$baseProd = "https://merchants.syriatel.sy:1443/ePayment_external_Json/rs/ePaymentExternalModule";
|
||||||
|
|
||||||
|
$baseUrl = ($env === "stage") ? $baseStage : $baseProd;
|
||||||
|
$url = $baseUrl . "/getToken";
|
||||||
|
|
||||||
|
// ⚠️ لا تضع قيم افتراضية حساسة Hardcoded
|
||||||
|
$username = getenv("SYRIATEL_USERNAME");
|
||||||
|
$password = getenv("SYRIATEL_PASSWORD");
|
||||||
|
|
||||||
|
if (!$username || !$password) {
|
||||||
|
error_log("[GetSyriatelToken] Missing credentials in ENV");
|
||||||
|
printFailure("Payment provider credentials are missing.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("[GetSyriatelToken] Env={$env} | URL={$url} | user={$username}");
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
"username" => $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;
|
||||||
|
}
|
||||||
BIN
walletintaleq.intaleq.xyz/v2/main/sms_webhook/archive.zip
Executable file
BIN
walletintaleq.intaleq.xyz/v2/main/sms_webhook/archive.zip
Executable file
Binary file not shown.
44
walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status.php
Executable file
44
walletintaleq.intaleq.xyz/v2/main/sms_webhook/check_invoice_status.php
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
//check_invoice_status.php
|
||||||
|
// تضمين ملف الاتصال والإعدادات الخاص بك
|
||||||
|
// يفترض أن هذا الملف يقوم بالاتصال بقاعدة البيانات ($con)
|
||||||
|
include "../jwtconnect.php";
|
||||||
|
|
||||||
|
// --- 1. استقبال البيانات من تطبيق فلاتر ---
|
||||||
|
$invoice_number = filterRequest("invoice_number");
|
||||||
|
|
||||||
|
// التحقق من أن رقم القسيمة قد تم إرساله
|
||||||
|
if (empty($invoice_number)) {
|
||||||
|
printFailure("invoice_number is required.");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2. البحث عن الفاتورة في قاعدة البيانات ---
|
||||||
|
try {
|
||||||
|
// إعداد الاستعلام للبحث عن حالة الفاتورة
|
||||||
|
$sql = "SELECT status FROM `invoices_sms` WHERE invoice_number = :invoice_number LIMIT 1";
|
||||||
|
|
||||||
|
$stmt = $con->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());
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
// check_invoice_status_passenger.php
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// تضمين الاتصال بقاعدة البيانات ($con)
|
||||||
|
include "../jwtconnect.php";
|
||||||
|
|
||||||
|
// 1) استقبال رقم الفاتورة
|
||||||
|
$invoice_number = filterRequest("invoice_number");
|
||||||
|
|
||||||
|
// التحقق من المدخلات
|
||||||
|
if (empty($invoice_number)) {
|
||||||
|
printFailure("invoice_number is required.");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2) البحث عن حالة الفاتورة في جدول الركّاب
|
||||||
|
$sql = "SELECT status FROM `invoices_sms_passenger` WHERE invoice_number = :invoice_number LIMIT 1";
|
||||||
|
$stmt = $con->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());
|
||||||
|
}
|
||||||
103
walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice.php
Executable file
103
walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice.php
Executable file
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
// create_invoice.php
|
||||||
|
|
||||||
|
// --- بداية التسجيل: تأكيد بدء تشغيل السكربت ---
|
||||||
|
//error_log("[CreateInvoice] --- Request Started ---");
|
||||||
|
|
||||||
|
// تضمين ملف الاتصال والإعدادات الخاص بك
|
||||||
|
// تأكد من أن هذا الملف لا يحتوي على أخطاء قد تسبب مشكلة Parse
|
||||||
|
include "../jwtconnect.php";
|
||||||
|
//error_log("[CreateInvoice] Included 'jwtconnect.php'");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// --- 1. تسجيل واستقبال المدخلات ---
|
||||||
|
// تسجيل البيانات الخام القادمة من الطلب لمعرفة ما يصل بالضبط
|
||||||
|
// error_log("[CreateInvoice] Raw POST data: " . json_encode($_POST));
|
||||||
|
|
||||||
|
$driverID = filterRequest("driverID");
|
||||||
|
$user_phone = filterRequest("user_phone");
|
||||||
|
$amount_raw = filterRequest("amount");
|
||||||
|
|
||||||
|
// تسجيل البيانات بعد الفلترة
|
||||||
|
//error_log("[CreateInvoice] Filtered Input: driverID={$driverID}, user_phone={$user_phone}, amount_raw={$amount_raw}");
|
||||||
|
|
||||||
|
// تأكيد المبلغ كرقم
|
||||||
|
$amount = is_numeric($amount_raw) ? (float) $amount_raw : 0.0;
|
||||||
|
|
||||||
|
// --- 2. التحقق الأساسي من المدخلات ---
|
||||||
|
if (empty($driverID) || empty($user_phone) || $amount <= 0) {
|
||||||
|
error_log("[CreateInvoice] Validation Failed: Missing or invalid required parameters.");
|
||||||
|
printFailure("driverID, user_phone and a valid amount are required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// error_log("[CreateInvoice] Input validation passed.");
|
||||||
|
|
||||||
|
// --- 3. التحقق من وجود فاتورة معلقة ---
|
||||||
|
// error_log("[CreateInvoice] Checking for existing pending invoice for driverID: {$driverID}");
|
||||||
|
$sql_check = "SELECT id, invoice_number FROM invoices_sms WHERE driverID = :driverID AND user_phone = :user_phone AND status = 'pending' ORDER BY created_at DESC LIMIT 1";
|
||||||
|
$stmt_check = $con->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 ---");
|
||||||
|
?>
|
||||||
|
|
||||||
126
walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice_passenger.php
Executable file
126
walletintaleq.intaleq.xyz/v2/main/sms_webhook/create_invoice_passenger.php
Executable file
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
// create_invoice_passenger.php
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// تضمين الاتصال
|
||||||
|
// -------------------------------------
|
||||||
|
include "../jwtconnect.php";
|
||||||
|
error_log("[CreateInvoicePassenger] Included 'jwtconnect.php'");
|
||||||
|
|
||||||
|
error_log("[CreateInvoicePassenger] --- Request Started ---");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// -------------------------------------
|
||||||
|
// 1) قراءة المدخلات
|
||||||
|
// -------------------------------------
|
||||||
|
$passengerID = filterRequest("passengerID");
|
||||||
|
$user_phone = filterRequest("user_phone");
|
||||||
|
$amount_raw = filterRequest("amount");
|
||||||
|
error_log("[CreateInvoicePassenger] Read inputs (passengerID, user_phone, amount)");
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// 2) تحويل/التحقق من المبلغ
|
||||||
|
// -------------------------------------
|
||||||
|
$amount = is_numeric($amount_raw) ? (float)$amount_raw : 0.0;
|
||||||
|
if (empty($passengerID) || empty($user_phone) || $amount <= 0) {
|
||||||
|
error_log("[CreateInvoicePassenger] Validation failed: missing/invalid parameters");
|
||||||
|
printFailure("passengerID, user_phone and a valid amount are required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
error_log("[CreateInvoicePassenger] Input validation passed");
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// 3) التحقق من وجود فاتورة معلّقة لنفس الراكب ونفس الهاتف
|
||||||
|
// -------------------------------------
|
||||||
|
$sql_check = "
|
||||||
|
SELECT id, invoice_number
|
||||||
|
FROM invoices_sms_passenger
|
||||||
|
WHERE passengerID = :passengerID
|
||||||
|
AND user_phone = :user_phone
|
||||||
|
AND status = 'pending'
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT 1
|
||||||
|
";
|
||||||
|
$stmt_check = $con->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 ---");
|
||||||
127
walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_payout.php
Executable file
127
walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_payout.php
Executable file
@@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
// finalize_payout.php
|
||||||
|
|
||||||
|
if (!function_exists('logPayoutError')) {
|
||||||
|
/**
|
||||||
|
* دالة مخصصة لتسجيل الأخطاء والخطوات في ملف سجل خاص بعمليات السحب.
|
||||||
|
*/
|
||||||
|
function logPayoutError($step, $message, $data = null) {
|
||||||
|
$logFile = __DIR__ . "/../logs/payout_finalization.log";
|
||||||
|
$logDir = dirname($logFile);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents($logFile, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('generateToken')) {
|
||||||
|
/**
|
||||||
|
* دالة لإنشاء توكن دفع فريد وحفظه في قاعدة البيانات.
|
||||||
|
*/
|
||||||
|
function generateToken(PDO $con, $driverId, $amount): ?string {
|
||||||
|
global $secretKey;
|
||||||
|
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret_for_token');
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
112
walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_wallet_payment.php
Executable file
112
walletintaleq.intaleq.xyz/v2/main/sms_webhook/finalize_wallet_payment.php
Executable file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
// wallet/finalize_wallet_payment.php
|
||||||
|
|
||||||
|
// لم نعد بحاجة لـ jwtconnect.php هنا لأن الاتصال يتم تمريره من السكربت الرئيسي
|
||||||
|
|
||||||
|
if (!function_exists('logError')) {
|
||||||
|
function logError($step, $message, $data = null) {
|
||||||
|
$logFile = __DIR__ . "/../logs/finalization.log";
|
||||||
|
$logDir = dirname($logFile);
|
||||||
|
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
|
||||||
|
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
|
||||||
|
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
|
||||||
|
file_put_contents($logFile, $logEntry . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* دالة لإنشاء توكن دفع فريد وحفظه في قاعدة البيانات.
|
||||||
|
*/
|
||||||
|
function generateToken($con, $driverId, $amount): ?string {
|
||||||
|
// افترض أن secretKey تم تعريفه في ملف jwtconnect.php
|
||||||
|
global $secretKey;
|
||||||
|
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret_for_token');
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* دالة لإنشاء سجل دفعة جديد وإرجاع الـ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
255
walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_passenger_sms_payment.php
Executable file
255
walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_passenger_sms_payment.php
Executable file
@@ -0,0 +1,255 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* process_passenger_sms_payment.php
|
||||||
|
* - يستخدم BASE_URL الموجودة مسبقًا (لا يُعرّف بديل).
|
||||||
|
* - يستخدم Gemini 2.5 Flash Lite.
|
||||||
|
* - لا يحدّث raw_sms_log الآن (لا mark processed/failed).
|
||||||
|
* - الدفع للراكب فقط: invoices_sms_passenger → bonus → generate token → add to wallets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
include_once __DIR__ . '/../../jwtconnect.php';
|
||||||
|
|
||||||
|
if (!defined('BASE_URL')) {
|
||||||
|
$APP_BASE_URL = rtrim(getenv('APP_BASE_URL') ?: '', '/');
|
||||||
|
if ($APP_BASE_URL === '') {
|
||||||
|
$scheme = isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : 'https';
|
||||||
|
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
||||||
|
define('BASE_URL', $scheme . '://' . $host);
|
||||||
|
} else {
|
||||||
|
define('BASE_URL', $APP_BASE_URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Gemini: Flash Lite ===== */
|
||||||
|
$geminiModel = 'gemini-2.5-flash-lite';
|
||||||
|
$geminiApiKey = getenv('GEMINI_API_KEY');
|
||||||
|
if (!$geminiApiKey) {
|
||||||
|
printFailure("Missing GEMINI_API_KEY");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$geminiApiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$geminiModel}:generateContent?key={$geminiApiKey}";
|
||||||
|
|
||||||
|
/* ===== اجلب رسالة واحدة pending (مع sender) ===== */
|
||||||
|
try {
|
||||||
|
$stmt = $con->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);
|
||||||
|
}
|
||||||
132
walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_with_gemini.php
Executable file
132
walletintaleq.intaleq.xyz/v2/main/sms_webhook/process_with_gemini.php
Executable file
@@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
// تأكد من أن هذا السكربت لا يمكن الوصول إليه مباشرة من الويب (للحماية)
|
||||||
|
// يمكنك وضع ملف .htaccess في المجلد لمنع الوصول المباشر
|
||||||
|
|
||||||
|
// المسار الصحيح لملف الاتصال
|
||||||
|
// هذه الطريقة تضمن أن المسار صحيح دائمًا بغض النظر عن كيفية استدعاء السكربت
|
||||||
|
include_once __DIR__ . '/../../jwtconnect.php';
|
||||||
|
|
||||||
|
// يمكنك هنا تضمين أي ملفات مساعدة أخرى
|
||||||
|
// استخدام __DIR__ هنا أيضًا يضمن إيجاد الملف في نفس المجلد الحالي
|
||||||
|
include_once __DIR__ . '/finalize_wallet_payment.php';
|
||||||
|
// --- إعدادات Gemini API ---
|
||||||
|
// من الأفضل قراءة مفتاح API من متغيرات البيئة لزيادة الأمان
|
||||||
|
$geminiApiKey = getenv('GEMINI_API_KEY');
|
||||||
|
|
||||||
|
$geminiApiUrl = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=" . $geminiApiKey;
|
||||||
|
|
||||||
|
// 1. جلب رسالة واحدة بحالة "pending" لمعالجتها
|
||||||
|
$stmt_fetch = $con->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";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
84
walletintaleq.intaleq.xyz/v2/main/sms_webhook/request_payout.php
Executable file
84
walletintaleq.intaleq.xyz/v2/main/sms_webhook/request_payout.php
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
// request_payout.php
|
||||||
|
include "../jwtconnect.php"; // ملف الاتصال الذي يتحقق من JWT
|
||||||
|
|
||||||
|
error_log("[RequestPayout] --- Request Started ---");
|
||||||
|
|
||||||
|
// --- 1. استقبال المدخلات ---
|
||||||
|
$driverId = filterRequest("driverId");
|
||||||
|
$amount_raw = filterRequest("amount");
|
||||||
|
$wallet_type = filterRequest("wallet_type") ?? 'Sham Cash'; // قيمة افتراضية
|
||||||
|
$phone = filterRequest("phone");
|
||||||
|
|
||||||
|
// تأكيد المبلغ كرقم
|
||||||
|
$amount = is_numeric($amount_raw) ? (float)$amount_raw : 0.0;
|
||||||
|
|
||||||
|
// تحقق أساسي
|
||||||
|
if (empty($driverId) || $amount <= 0) {
|
||||||
|
printFailure("driverId and a valid amount are required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// --- 2. التحقق من بيانات السائق ورصيده ---
|
||||||
|
$stmt_driver = $con->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.");
|
||||||
|
}
|
||||||
|
?>
|
||||||
37
walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms.php
Executable file
37
walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms.php
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
//save_raw_sms.php
|
||||||
|
// تضمين ملف الاتصال والإعدادات الرئيسي
|
||||||
|
// تأكد من أن هذا الملف يقوم بالتحقق من صحة JWT و HMAC القادم في الهيدرز
|
||||||
|
include __DIR__ . "/../jwtconnect.php";
|
||||||
|
|
||||||
|
// استقبال الرسالة الخام من تطبيق الأندرويد
|
||||||
|
$json_data = file_get_contents('php://input');
|
||||||
|
$data = json_decode($json_data, true);
|
||||||
|
|
||||||
|
// التحقق من وجود البيانات المطلوبة
|
||||||
|
if ($data && isset($data['sender']) && isset($data['message'])) {
|
||||||
|
try {
|
||||||
|
// حفظ الرسالة في جدول السجل الخام مع حالة "pending"
|
||||||
|
$sql = "INSERT INTO `raw_sms_log` (sender, message_body, status) VALUES (:sender, :message, 'pending')";
|
||||||
|
$stmt = $con->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.']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
37
walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms_passenger.php
Executable file
37
walletintaleq.intaleq.xyz/v2/main/sms_webhook/save_raw_sms_passenger.php
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
//save_raw_sms.php
|
||||||
|
// تضمين ملف الاتصال والإعدادات الرئيسي
|
||||||
|
// تأكد من أن هذا الملف يقوم بالتحقق من صحة JWT و HMAC القادم في الهيدرز
|
||||||
|
include __DIR__ . "/../jwtconnect.php";
|
||||||
|
|
||||||
|
// استقبال الرسالة الخام من تطبيق الأندرويد
|
||||||
|
$json_data = file_get_contents('php://input');
|
||||||
|
$data = json_decode($json_data, true);
|
||||||
|
|
||||||
|
// التحقق من وجود البيانات المطلوبة
|
||||||
|
if ($data && isset($data['sender']) && isset($data['message'])) {
|
||||||
|
try {
|
||||||
|
// حفظ الرسالة في جدول السجل الخام مع حالة "pending"
|
||||||
|
$sql = "INSERT INTO `raw_sms_log` (sender, message_body, status) VALUES (:sender, :message, 'pending')";
|
||||||
|
$stmt = $con->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.']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
84
walletintaleq.intaleq.xyz/v2/main/sms_webhook/webhook.php
Executable file
84
walletintaleq.intaleq.xyz/v2/main/sms_webhook/webhook.php
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
//webhook.php
|
||||||
|
// تضمين ملف الاتصال الذي يتحقق أيضاً من توكن JWT
|
||||||
|
include "../jwtconnect.php";
|
||||||
|
|
||||||
|
// --- 1. قراءة البيانات المرسلة ---
|
||||||
|
$expectedToken = trim(file_get_contents('/home/intaleq-wallet/.webhookKey') ?: 'secret'); // Replace with actual key
|
||||||
|
$receivedToken = $_SERVER['HTTP_X_AUTH_TOKEN'] ?? '';
|
||||||
|
|
||||||
|
if (!hash_equals($expectedToken, $receivedToken)) {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["status" => "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.']);
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user