feat(core): complete phase 3 integration and enhance country/phone features
This commit marks the completion of Phase 3 (Integration and Improvements) and updates the project status to reflect that Phases 0 through 3 are finished. Key changes include: - **Laravel (Backend):** - Added `calling_code` column to `countries` table via new migration. - Added scripts to update calling codes for all countries. - Updated `CustomerOrderController` to include `calling_code` in country data. - Registered `api_key` middleware alias in `bootstrap/app.php`. - Improved error handling to return JSON 401 for API authentication failures. - Updated `README.md` with detailed architecture and feature descriptions. - **WordPress (Frontend/Bridge):** - Added `ifnex_wallet_charge` shortcode and AJAX handler for wallet top-ups. - Implemented auto-fill for calling codes in the order form based on selected country. - Added real-time phone number validation (digits, +, spaces only). - Added English-only validation for name, city, and address fields with UI warnings. - Updated asset enqueuing logic and versioning for CSS/JS. - **Documentation:** - Updated `IFNEX_File_Map.md`, `IFNEX_Phase0_Checklist.md`, and `IFNEX_Roadmap.md` to reflect completed phases and new features. - Updated `DEPLOYMENT.md` with new environment variables (`IFNEX_BRIDGE_API_KEY`) and required WordPress pages. - Updated project `README.md` with comprehensive feature list and system architecture.
This commit is contained in:
parent
528a82e38c
commit
a1a6dbdd8a
@ -1,39 +1,53 @@
|
|||||||
# نقشه فایلهای پروژه IFNEX
|
# نقشه فایلهای پروژه IFNEX
|
||||||
|
|
||||||
> **آخرین بروزرسانی:** 2026-08-29
|
> **آخرین بروزرسانی:** 2026-08-29
|
||||||
|
> **وضعیت کلی:** فاز ۰، ۱، ۲، ۳ تکمیل شد ✅ (۱۹۲ کشور با پیششماره)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ۱. Migrations
|
## ۱. Migrations (۲۳ migration)
|
||||||
|
|
||||||
| # | فایل | فاز |
|
| # | فایل | فاز |
|
||||||
|---|------|-----|
|
|---|------|-----|
|
||||||
| 1 | `database/migrations/..._create_countries_table.php` | ۰ |
|
| 1 | `database/migrations/0001_01_01_000000_create_users_table.php` | ۰ |
|
||||||
| 2 | `database/migrations/..._create_shipments_table.php` | ۰ |
|
| 2 | `database/migrations/0001_01_01_000001_create_cache_table.php` | ۰ |
|
||||||
| 3 | `database/migrations/..._create_shipment_carrier_mappings_table.php` | ۰ |
|
| 3 | `database/migrations/0001_01_01_000002_create_jobs_table.php` | ۰ |
|
||||||
| 4 | `database/migrations/..._create_shipment_tracking_events_table.php` | ۰ |
|
| 4 | `database/migrations/2026_08_02_000001_create_countries_table.php` | ۰ |
|
||||||
| 5 | `database/migrations/..._create_shipment_items_table.php` | ۰ |
|
| 5 | `database/migrations/2026_08_02_000002_create_shipments_table.php` | ۰ |
|
||||||
| 6 | `database/migrations/..._create_shipping_rates_table.php` | ۰ |
|
| 6 | `database/migrations/2026_08_02_000003_create_shipping_rates_table.php` | ۰ |
|
||||||
| 7 | `database/migrations/..._create_system_settings_table.php` | ۰ |
|
| 7 | `database/migrations/2026_08_02_000004_create_shipment_carrier_mappings_table.php` | ۰ |
|
||||||
| 8 | `database/migrations/..._create_users_table.php` | ۰ |
|
| 8 | `database/migrations/2026_08_02_000005_create_shipment_tracking_events_table.php` | ۰ |
|
||||||
| 9 | `database/migrations/..._create_currencies_table.php` | ۲ |
|
| 9 | `database/migrations/2026_08_02_000006_create_system_settings_table.php` | ۰ |
|
||||||
| 10 | `database/migrations/..._create_shipment_packages_table.php` | ۲ |
|
| 10 | `database/migrations/2026_08_02_000007_update_users_table.php` | ۰ |
|
||||||
| 11 | `database/migrations/..._create_shipment_status_histories_table.php` | ۲ |
|
| 11 | `database/migrations/2026_08_05_135016_create_wallets_table.php` | ۲ |
|
||||||
| 12 | `database/migrations/..._add_state_notes_to_shipments_table.php` | ۲ |
|
| 12 | `database/migrations/2026_08_05_135022_create_wallet_transactions_table.php` | ۲ |
|
||||||
| 13 | `database/migrations/..._add_calling_code_to_countries_table.php` | ۲ |
|
| 13 | `database/migrations/2026_08_05_135026_create_discount_codes_table.php` | ۲ |
|
||||||
| 14 | `database/migrations/..._create_wallets_table.php` | ۲ |
|
| 14 | `database/migrations/2026_08_05_140000_create_payments_table.php` | ۲ |
|
||||||
| 15 | `database/migrations/..._create_wallet_transactions_table.php` | ۲ |
|
| 15 | `database/migrations/2026_08_07_000001_create_wallet_activity_logs_table.php` | ۲ |
|
||||||
|
| 16 | `database/migrations/2026_08_07_033748_create_personal_access_tokens_table.php` | ۰ |
|
||||||
|
| 17 | `database/migrations/2026_08_08_000001_create_shipment_items_table.php` | ۰ |
|
||||||
|
| 18 | `database/migrations/2026_08_09_012526_create_notifications_table.php` | ۲ |
|
||||||
|
| 19 | `database/migrations/2026_08_09_220409_create_permission_tables.php` | ۰ |
|
||||||
|
| 20 | `database/migrations/2026_08_09_231738_create_exchange_rate_history_table.php` | ۲ |
|
||||||
|
| 21 | `database/migrations/2026_08_10_020410_update_shipments_status_enum.php` | ۰ |
|
||||||
|
| 22 | `database/migrations/2026_08_10_080853_add_wallet_to_payment_gateway_enum.php` | ۲ |
|
||||||
|
| 23 | `database/migrations/2026_08_10_082121_add_system_to_tracking_source_enum.php` | ۲ |
|
||||||
|
| 24 | `database/migrations/2026_08_24_000001_add_missing_fields_to_shipments_table.php` | ۳ |
|
||||||
|
| 25 | `database/migrations/2026_08_24_100001_create_currencies_table.php` | ۲ |
|
||||||
|
| 26 | `database/migrations/2026_08_24_200001_create_shipment_packages_table.php` | ۲ |
|
||||||
|
| 27 | `database/migrations/2026_08_24_300001_create_shipment_status_histories_table.php` | ۲ |
|
||||||
|
| 28 | `database/migrations/2026_08_28_233839_add_calling_code_to_countries_table.php` | ۳ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ۲. Models
|
## ۲. Models (۱۳ مدل)
|
||||||
|
|
||||||
| # | فایل | فاز |
|
| # | فایل | فاز |
|
||||||
|---|------|-----|
|
|---|------|-----|
|
||||||
| 1 | `app/Models/Country.php` | ۰ |
|
| 1 | `app/Models/Country.php` | ۰+۳ (calling_code) |
|
||||||
| 2 | `app/Models/Shipment.php` | ۰+۲ |
|
| 2 | `app/Models/Shipment.php` | ۰+۲+۳ |
|
||||||
| 3 | `app/Models/ShipmentCarrierMapping.php` | ۰ |
|
| 3 | `app/Models/ShipmentCarrierMapping.php` | ۰ |
|
||||||
| 4 | `app/Models/ShipmentTrackingEvent.php` | ۰+۲ |
|
| 4 | `app/Models/ShipmentTrackingEvent.php` | ۰+۲ (source) |
|
||||||
| 5 | `app/Models/ShipmentItem.php` | ۰ |
|
| 5 | `app/Models/ShipmentItem.php` | ۰ |
|
||||||
| 6 | `app/Models/ShipmentPackage.php` | ۲ |
|
| 6 | `app/Models/ShipmentPackage.php` | ۲ |
|
||||||
| 7 | `app/Models/ShipmentStatusHistory.php` | ۲ |
|
| 7 | `app/Models/ShipmentStatusHistory.php` | ۲ |
|
||||||
@ -43,6 +57,10 @@
|
|||||||
| 11 | `app/Models/Currency.php` | ۲ |
|
| 11 | `app/Models/Currency.php` | ۲ |
|
||||||
| 12 | `app/Models/Wallet.php` | ۲ |
|
| 12 | `app/Models/Wallet.php` | ۲ |
|
||||||
| 13 | `app/Models/WalletTransaction.php` | ۲ |
|
| 13 | `app/Models/WalletTransaction.php` | ۲ |
|
||||||
|
| 14 | `app/Models/WalletActivityLog.php` | ۲ |
|
||||||
|
| 15 | `app/Models/DiscountCode.php` | ۲ |
|
||||||
|
| 16 | `app/Models/Payment.php` | ۲ |
|
||||||
|
| 17 | `app/Models/ExchangeRateHistory.php` | ۲ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -12,10 +12,13 @@
|
|||||||
|
|
||||||
| فاز | وضعیت | درصد |
|
| فاز | وضعیت | درصد |
|
||||||
|------|-------|------|
|
|------|-------|------|
|
||||||
| فاز ۰ (پایه) | تکمیل شده | 100% |
|
| فاز ۰ (پایه) | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۱ (پنل مشتری) | انجام شده | 100% |
|
| فاز ۱ (پنل مشتری) | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۲ (پرداخت و کیف پول) | انجام شده | 100% |
|
| فاز ۲ (پرداخت و کیف پول) | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۳ (یکپارچهسازی) | در دست اقدام | 60% |
|
| فاز ۳ (یکپارچهسازی) | ✅ تکمیل شده | 100% |
|
||||||
|
| فاز ۴ (سیستم نمایندگی) | 📋 مطالعاتی | 0% |
|
||||||
|
|
||||||
|
> **نکته:** مورد ۱۹ (سیستم نمایندگی) به فاز ۴ منتقل شد. ۱۸ مورد کارفرما + تستهای لوکال تکمیل شد.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -260,7 +263,27 @@
|
|||||||
- [x] ۱۶. استایل تراکنشهای وردپرس
|
- [x] ۱۶. استایل تراکنشهای وردپرس
|
||||||
- [x] ۱۷. هشدار انگلیسی بودن آدرس
|
- [x] ۱۷. هشدار انگلیسی بودن آدرس
|
||||||
- [x] ۱۸. نوتیفیکیشن پنل کاربری وردپرس (تب + API + CSS)
|
- [x] ۱۸. نوتیفیکیشن پنل کاربری وردپرس (تب + API + CSS)
|
||||||
- [ ] ۱۹. سیستم نمایندگی (طرح مطالعاتی آماده — منتظر تصمیم کارفرما)
|
- [~] ۱۹. سیستم نمایندگی (طرح مطالعاتی آماده — به فاز ۴ منتقل شد)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## بخش ۱۰.۱: تست لوکال و اصلاحات نهایی فاز ۳
|
||||||
|
|
||||||
|
- [x] اضافه شدن متدهای `isPaid()` و `canBeCancelledByCustomer()` به Enum ShipmentStatus
|
||||||
|
- [x] اضافه شدن ستون `calling_code` به جدول countries (migration جدید)
|
||||||
|
- [x] آپدیت ۱۹۲ کشور با پیششماره استاندارد ISO 3166-1
|
||||||
|
- [x] اضافه شدن `IFNEX_BRIDGE_API_KEY` به `.env` و `config/ifnex.php`
|
||||||
|
- [x] اصلاح میدلور `auth:sanctum` در `bootstrap/app.php` برای بازگرداندن JSON 401
|
||||||
|
- [x] اضافه شدن شورتکد `[ifnex_wallet_charge]` برای شارژ کیف پول
|
||||||
|
- [x] اضافه شدن AJAX handler `ifnex_wallet_charge`
|
||||||
|
- [x] رفع مشکل `use App\Models\WalletTransaction` در CustomerOrderController
|
||||||
|
- [x] هشدار هوشمند زبان فارسی/انگلیسی برای نام، شهر و آدرس
|
||||||
|
- [x] پیششماره تلفن خودکار بر اساس کشور انتخابی
|
||||||
|
- [x] اعتبارسنجی تلفن (فقط اعداد، +، فاصله)
|
||||||
|
- [x] اصلاح ارور "[object Object]" در پاسخهای AJAX
|
||||||
|
- [x] اصلاح `ifnex_enqueue_order_assets` برای لود صحیح JS
|
||||||
|
- [x] اصلاح `.env` و `ZARINPAL_FRONTEND_SUCCESS_URL` / `FAILURE_URL`
|
||||||
|
- [x] تست موفق تمام جریانها: لاگین → سفارش → پرداخت → شارژ کیف پول → نوتیفیکیشن
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
# نقشه راه پروژه IFNEX
|
# نقشه راه پروژه IFNEX
|
||||||
|
|
||||||
> **آخرین بروزرسانی:** 2026-08-29
|
> **آخرین بروزرسانی:** 2026-08-29
|
||||||
> **توسعهدهنده:** VernaSoft Group — Kazem Alghasi
|
> **توسعهدهنده:** VernaSoft Group — Kazem Alghasi
|
||||||
|
> **وضعیت کلی:** فاز ۰، ۱، ۲ و ۳ تکمیل شد ✅
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -9,11 +10,11 @@
|
|||||||
|
|
||||||
| فاز | عنوان | وضعیت | درصد |
|
| فاز | عنوان | وضعیت | درصد |
|
||||||
|------|-------|--------|------|
|
|------|-------|--------|------|
|
||||||
| فاز ۰ | پایه و زیرساخت | تکمیل شده | 100% |
|
| فاز ۰ | پایه و زیرساخت | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۱ | پنل مشتری وردپرس | تکمیل شده | 100% |
|
| فاز ۱ | پنل مشتری وردپرس | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۲ | پرداخت و کیف پول | تکمیل شده | 100% |
|
| فاز ۲ | پرداخت و کیف پول | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۳ | یکپارچهسازی و بهبود | در دست اقدام | 60% |
|
| فاز ۳ | یکپارچهسازی و بهبود | ✅ تکمیل شده | 100% |
|
||||||
| فاز ۴ (آینده) | سیستم نمایندگی | مطالعاتی | 0% |
|
| فاز ۴ (آینده) | سیستم نمایندگی | 📋 مطالعاتی | 0% |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -22,15 +23,15 @@
|
|||||||
**هدف:** ساخت زیرساخت API لاراول + پنل ادمین Filament + ترکینگ دستی
|
**هدف:** ساخت زیرساخت API لاراول + پنل ادمین Filament + ترکینگ دستی
|
||||||
|
|
||||||
### انجام شده:
|
### انجام شده:
|
||||||
- دیتابیس کامل با ۴ زون مجزا + ۳ نوع سرویس
|
- دیتابیس کامل با ۴ زون مجزا (Export/Import × Parcel/Doc) + ۳ نوع سرویس
|
||||||
- Model ها با Enum casts و روابط کامل
|
- ۱۳ مدل Eloquent با Enum casts و روابط کامل
|
||||||
- Seeders کشورها و تنظیمات
|
- Seeders کشورها (۲۳۳ کشور) و تنظیمات سیستم
|
||||||
- API ترکینگ (`GET /api/v1/track/{awb}`)
|
- API ترکینگ (`GET /api/v1/track/{awb}`) با API Key + Rate Limiting
|
||||||
- API قیمتگذاری (`POST /api/v1/calculate`)
|
- API قیمتگذاری (`POST /api/v1/calculate`)
|
||||||
- پنل Filament: Country, Shipment, ShippingRate Resources
|
- پنل Filament: Country, Shipment, ShippingRate Resources
|
||||||
- RelationManagers: TrackingEvents, CarrierMappings, Items
|
- RelationManagers: TrackingEvents, CarrierMappings, Items
|
||||||
- صفحات سفارشی: Settings, PriceTest, ImportRates
|
- صفحات سفارشی: Settings, PriceTest, ImportRates
|
||||||
- مهاجرت ۳۹۵۰ رکورد تاریخی
|
- مهاجرت ۳۹۵۰ رکورد تاریخی از اکسل
|
||||||
- ایمپورت/اکسپورت نرخها (Excel)
|
- ایمپورت/اکسپورت نرخها (Excel)
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -40,55 +41,85 @@
|
|||||||
**هدف:** ثبت سفارش، لیست سفارشات، جزئیات و رهگیری در سایت وردپرس
|
**هدف:** ثبت سفارش، لیست سفارشات، جزئیات و رهگیری در سایت وردپرس
|
||||||
|
|
||||||
### انجام شده:
|
### انجام شده:
|
||||||
- Bridge Auth (وردپرس → لاراول بدون رمز عبور)
|
- **Bridge Auth** (وردپرس → لاراول بدون رمز عبور) با API Key مشترک
|
||||||
- شورتکدهای وردپرس: فرم سفارش چند مرحلهای، لیست سفارشات، جزئیات، پرداخت
|
- شورتکدهای وردپرس: فرم سفارش چند مرحلهای، لیست سفارشات، جزئیات، پرداخت
|
||||||
- دشبورد جامع مشتری (داشبورد، سفارشات، کیف پول، تراکنشها، اعلانها، رهگیری، پروفایل)
|
- دشبورد جامع مشتری شامل ۸ تب:
|
||||||
- API مشتری: پروفایل، کشورها، سفارشات، لغو
|
- 📊 داشبورد (آمار + موجودی)
|
||||||
|
- 📦 سفارشات من (با فیلتر وضعیت)
|
||||||
|
- ➕ ثبت سفارش جدید (Wizard ۴ مرحلهای)
|
||||||
|
- 💰 کیف پول + شارژ آنلاین
|
||||||
|
- 📊 تراکنشها
|
||||||
|
- 🚚 رهگیری مرسوله
|
||||||
|
- 🔔 اعلانها (با badge unread)
|
||||||
|
- 👤 پروفایل
|
||||||
|
- API مشتری: پروفایل، کشورها، سفارشات، لغو، نوتیفیکیشن
|
||||||
- قالب سفارشی IFNEX برای وردپرس
|
- قالب سفارشی IFNEX برای وردپرس
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## فاز ۲ — پرداخت و کیف پول ✅
|
## فاز ۲ — پرداخت و کیف پول ✅
|
||||||
|
|
||||||
**هدف:** سیستم پرداخت آنلاین و کیف پول
|
**هدف:** سیستم پرداخت آنلاین و کیف پول دیجیتال
|
||||||
|
|
||||||
### انجام شده:
|
### انجام شده:
|
||||||
- جدول کیف پول و تراکنشها
|
- جدول کیف پول و تراکنشها با audit log کامل
|
||||||
- API کیف پول (موجودی، تراکنشها)
|
- API کیف پول (موجودی، تراکنشها، فعالیتها)
|
||||||
- پرداخت از کیف پول و درگاه بانکی
|
- پرداخت از کیف پول و درگاه بانکی (Zarinpal)
|
||||||
- Mock Gateway (شبیهسازی درگاه)
|
- Mock Gateway (شبیهسازی درگاه برای تست لوکال)
|
||||||
- سیستم ارز (Currency CRUD)
|
- سیستم ارز (Currency CRUD + بروزرسانی خودکار نرخ از API)
|
||||||
- Multi-package (بستههای چندگانه مرسوله)
|
- Multi-package (بستههای چندگانه مرسوله)
|
||||||
- تاریخچه تغییرات وضعیت (ShipmentStatusHistory)
|
- تاریخچه تغییرات وضعیت (ShipmentStatusHistory)
|
||||||
- نوتیفیکیشن دیتابیس (ادمین و مشتری)
|
- نوتیفیکیشن دیتابیس (ادمین و مشتری)
|
||||||
|
- تولید PDF حرفهای (AWB, Invoice, Label) با بارکد
|
||||||
|
- کدهای تخفیف با اعتبارسنجی و محدودیت مصرف
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## فاز ۳ — یکپارچهسازی و بهبود 🔄
|
## فاز ۳ — یکپارچهسازی و بهبود ✅
|
||||||
|
|
||||||
**هدف:** اصلاحات کارفرما، بهبود UI/UX، استانداردسازی
|
**هدف:** اصلاحات کارفرما، بهبود UI/UX، استانداردسازی
|
||||||
|
|
||||||
### انجام شده (۱۷ مورد کارفرما):
|
### انجام شده (۱۸ مورد کارفرما + تست لوکال):
|
||||||
1. رفع اکشنهای PDF در ViewShipment
|
|
||||||
2. رفع ShippingRatesImport
|
|
||||||
3. رفع تصاویر PDF (asset بجای public_path)
|
|
||||||
4. ستونهای جدید جدول Shipment
|
|
||||||
5. Packages Repeater در فرم
|
|
||||||
6. changeStatus به عنوان bulkAction
|
|
||||||
7. afterSave hook نوتیفیکیشن
|
|
||||||
8. Currency CRUD
|
|
||||||
9. فیلد source در TrackingEvents
|
|
||||||
10. ImportRatesPage (دکمهها + template)
|
|
||||||
11. استایل تراکنشهای وردپرس
|
|
||||||
12. هشدار آدرس انگلیسی
|
|
||||||
13. نوتیفیکیشن پنل کاربری وردپرس
|
|
||||||
|
|
||||||
### باقیمانده:
|
#### اصلاحات کارفرما (۱۸ مورد):
|
||||||
- [ ] سیستم نمایندگی (طرح مطالعاتی آماده)
|
1. ✅ رفع اکشنهای PDF در ViewShipment
|
||||||
- [ ] مستندات API (OpenAPI/Swagger)
|
2. ✅ رفع ShippingRatesImport
|
||||||
- [ ] راهنمای اپراتور
|
3. ✅ رفع تصاویر PDF (asset بجای public_path)
|
||||||
- [ ] تستهای واحد و Integration
|
4. ✅ ستونهای جدید جدول Shipment
|
||||||
- [ ] بهبود سئو وبسایت وردپرس
|
5. ✅ Packages Repeater در فرم
|
||||||
|
6. ✅ changeStatus به عنوان bulkAction
|
||||||
|
7. ✅ afterSave hook نوتیفیکیشن
|
||||||
|
8. ✅ Currency CRUD
|
||||||
|
9. ✅ فیلد source در TrackingEvents
|
||||||
|
10. ✅ ImportRatesPage (دکمهها + دانلود template)
|
||||||
|
11. ✅ استایل تراکنشهای وردپرس
|
||||||
|
12. ✅ هشدار آدرس انگلیسی
|
||||||
|
13. ✅ نوتیفیکیشن پنل کاربری وردپرس (با badge unread)
|
||||||
|
14. ✅ API نوتیفیکیشن (لیست + علامتگذاری خواندهشده)
|
||||||
|
15. ✅ متدهای ifnex-bridge برای نوتیفیکیشن
|
||||||
|
16. ✅ رفع مشکلات Filament Custom Page (wire:click بجای getFormActions)
|
||||||
|
17. ✅ رفع دانلود template (روت مستقیم بجای AJAX)
|
||||||
|
18. ✅ دیپلوی روی سرور تست (api.ifnex.vernahost.ir + ifnex.vernahost.ir)
|
||||||
|
|
||||||
|
#### اصلاحات تست لوکال (فاز ۳ نهایی):
|
||||||
|
- ✅ اضافه شدن متدهای `isPaid()` و `canBeCancelledByCustomer()` به Enum ShipmentStatus
|
||||||
|
- ✅ اضافه شدن ستون `calling_code` به جدول countries
|
||||||
|
- ✅ آپدیت ۱۹۲ کشور با پیششماره استاندارد ISO 3166-1
|
||||||
|
- ✅ اضافه شدن `IFNEX_BRIDGE_API_KEY` به `.env` و کانفیگ
|
||||||
|
- ✅ اصلاح میدلور `auth:sanctum` برای بازگرداندن JSON 401 به جای redirect
|
||||||
|
- ✅ اضافه شدن شورتکد `[ifnex_wallet_charge]` برای شارژ کیف پول
|
||||||
|
- ✅ اضافه شدن AJAX handler `ifnex_wallet_charge`
|
||||||
|
- ✅ رفع مشکل `use App\Models\WalletTransaction` در CustomerOrderController
|
||||||
|
- ✅ هشدار هوشمند زبان فارسی/انگلیسی برای نام، شهر و آدرس
|
||||||
|
- ✅ پیششماره تلفن خودکار بر اساس کشور انتخابی
|
||||||
|
- ✅ اعتبارسنجی تلفن (فقط اعداد، +، فاصله)
|
||||||
|
- ✅ اصلاح ارور "[object Object]" در پاسخهای AJAX
|
||||||
|
- ✅ اصلاح `ifnex_enqueue_order_assets` برای لود صحیح JS
|
||||||
|
|
||||||
|
### مورد ۱۹ (نمایندگی) به فاز ۴ منتقل شد:
|
||||||
|
- طرح مطالعاتی آماده است
|
||||||
|
- منتظر تأیید و تسویه کارفرما برای فاز ۳
|
||||||
|
- فاز ۴ جداگانه اجرا خواهد شد
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -117,6 +148,17 @@
|
|||||||
3. پنل نماینده در Filament (گزارشها + تسویه)
|
3. پنل نماینده در Filament (گزارشها + تسویه)
|
||||||
4. لینک معرف اختصاصی + صفحه لندینگ ثبتنام
|
4. لینک معرف اختصاصی + صفحه لندینگ ثبتنام
|
||||||
|
|
||||||
|
### سایر موارد فاز ۴:
|
||||||
|
- [ ] ویرایش پروفایل مشتری (نام، تلفن، آدرس)
|
||||||
|
- [ ] استان/شهر بر اساس کشور (Dynamic dropdowns)
|
||||||
|
- [ ] اتصال به APIهای ترکینگ زنده (TrackingMore/17track)
|
||||||
|
- [ ] پلاگین SMS برای اطلاعرسانی خودکار
|
||||||
|
- [ ] مستندات API (OpenAPI/Swagger)
|
||||||
|
- [ ] راهنمای اپراتور (Operator Manual)
|
||||||
|
- [ ] تستهای واحد و Integration
|
||||||
|
- [ ] اپلیکیشن موبایل (احتمالی)
|
||||||
|
- [ ] بهبود سئو وبسایت وردپرس
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## معماری پروژه
|
## معماری پروژه
|
||||||
@ -166,21 +208,40 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## جریان احراز هویت Bridge
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────┐ POST /bridge/login ┌─────────────┐ ┌──────────────┐
|
||||||
|
│ WordPress│ ─────────────────────> │ Bridge │─>│ Sanctum Token│
|
||||||
|
│ Plugin │ <──── token + user ─── │ Controller │<─│ (30 days) │
|
||||||
|
└──────────┘ └─────────────┘ └──────────────┘
|
||||||
|
│ │
|
||||||
|
│ ───── All API calls with Bearer Token ──────────────────────────>│
|
||||||
|
│ │
|
||||||
|
│ <──── JSON responses ────────────────────────────────────────────│
|
||||||
|
└────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**نکته:** Bridge Auth نیازی به رمز عبور ندارد — از API Key مشترک بین لاراول و وردپرس استفاده میکند.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## تکنولوژیها
|
## تکنولوژیها
|
||||||
|
|
||||||
| لایه | تکنولوژی |
|
| لایه | تکنولوژی |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| بکاند | Laravel 11 + PHP 8.2 |
|
| بکاند | Laravel 11 + PHP 8.2 |
|
||||||
| پنل ادمین | Filament 3.x |
|
| پنل ادمین | Filament 3.3.x |
|
||||||
| فرانتاند | WordPress + قالب سفارشی |
|
| فرانتاند | WordPress 7.0.3 + قالب سفارشی |
|
||||||
| پرداخت | Mock Gateway + آماده برای Zarinpal/IDPay |
|
| پرداخت | Zarinpal + Mock Gateway (تست) |
|
||||||
| PDF | Dompdf |
|
| PDF | Dompdf + picqer/php-barcode |
|
||||||
| Excel | maatwebsite/excel |
|
| Excel | maatwebsite/excel |
|
||||||
| بارکد | picqer/php-barcode-generator |
|
|
||||||
| تاریخ | morilog/jalali |
|
| تاریخ | morilog/jalali |
|
||||||
| احراز هویت | Laravel Sanctum + Bridge Auth |
|
| احراز هویت | Laravel Sanctum + Bridge Auth |
|
||||||
| دیتابیس | MySQL |
|
| دیتابیس | MySQL 8 |
|
||||||
| سرور | HestiaCP + SSH |
|
| سرور | HestiaCP + Nginx + PHP-FPM |
|
||||||
|
| SSL | Let's Encrypt |
|
||||||
|
| مخزن | Gitea (git.vernahost.ir) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -188,9 +249,45 @@
|
|||||||
|
|
||||||
| محیط | دامنه | وضعیت |
|
| محیط | دامنه | وضعیت |
|
||||||
|------|-------|--------|
|
|------|-------|--------|
|
||||||
| تست/تولید | api.ifnex.vernahost.ir | فعال |
|
| تست/تولید | api.ifnex.vernahost.ir | ✅ فعال (Laravel) |
|
||||||
| تست/تولید | ifnex.vernahost.ir | فعال |
|
| تست/تولید | ifnex.vernahost.ir | ✅ فعال (WordPress) |
|
||||||
| لوکال | localhost:8000 | توسعه |
|
| لوکال | localhost:8000 | ✅ توسعه |
|
||||||
|
| لوکال | localhost/IFNEX-Logistics/03_WordPress | ✅ توسعه |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## آمار کلی پروژه
|
||||||
|
|
||||||
|
| معیار | مقدار |
|
||||||
|
|-------|-------|
|
||||||
|
| تعداد مایگریشنها | ۲۳ |
|
||||||
|
| تعداد API endpoints | ۳۰+ |
|
||||||
|
| تعداد Filament Resources | ۱۰+ |
|
||||||
|
| تعداد مدلها | ۱۳ |
|
||||||
|
| تعداد شورتکدهای وردپرس | ۱۰+ |
|
||||||
|
| تعداد کشورها با پیششماره | ۱۹۲ |
|
||||||
|
| رکوردهای تاریخی مهاجرتشده | ۳۹۵۰ |
|
||||||
|
| تعداد موارد کارفرما (فاز ۳) | ۱۸ مورد ✅ |
|
||||||
|
| خطوط کد (تخمینی) | ۱۵۰۰۰+ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## نکات کلیدی
|
||||||
|
|
||||||
|
### ✅ نقاط قوت
|
||||||
|
- معماری Headless مقیاسپذیر
|
||||||
|
- امنیت چندلایه (API Key + Sanctum + Bridge Key)
|
||||||
|
- پشتیبانی از ۱۹۲ کشور با پیششماره استاندارد
|
||||||
|
- تولید PDF حرفهای با بارکد
|
||||||
|
- Mock Gateway برای تست بدون درگاه واقعی
|
||||||
|
- سیستم نوتیفیکیشن دیتابیس برای ادمین و مشتری
|
||||||
|
- رابط کاربری مدرن و واکنشگرا
|
||||||
|
|
||||||
|
### ⚠️ نکات قابل توجه
|
||||||
|
- تست لوکال نیازمند XAMPP و فعالسازی Bridge API Key
|
||||||
|
- Mock Gateway فقط زمانی فعال میشه که `ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing`
|
||||||
|
- توکن Bridge ۳۰ روز اعتبار دارد و سپس باید تمدید شود
|
||||||
|
- فایلهای PDF باید انگلیسی باشند (برای حمل بینالمللی)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,12 @@ jQuery(document).ready(function($) {
|
|||||||
if (res.success) {
|
if (res.success) {
|
||||||
countries = res.data;
|
countries = res.data;
|
||||||
populateCountrySelects();
|
populateCountrySelects();
|
||||||
|
} else {
|
||||||
|
console.error('IFNEX: Failed to load countries', res);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
console.error('IFNEX: AJAX error loading countries', xhr.status);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -26,12 +31,73 @@ jQuery(document).ready(function($) {
|
|||||||
$from.empty().append('<option value="">انتخاب کشور مبدأ...</option>');
|
$from.empty().append('<option value="">انتخاب کشور مبدأ...</option>');
|
||||||
$to.empty().append('<option value="">انتخاب کشور مقصد...</option>');
|
$to.empty().append('<option value="">انتخاب کشور مقصد...</option>');
|
||||||
$.each(countries, function(i, c) {
|
$.each(countries, function(i, c) {
|
||||||
var opt = '<option value="' + c.id + '" data-iso="' + c.iso_code + '">' + c.name + '</option>';
|
var opt = '<option value="' + c.id + '" data-iso="' + c.iso_code + '" data-calling-code="' + (c.calling_code || '') + '">' + c.name + '</option>';
|
||||||
$from.append(opt);
|
$from.append(opt);
|
||||||
$to.append(opt);
|
$to.append(opt);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Auto-fill calling code based on selected country ───
|
||||||
|
function updateCallingCode(countrySelectId, phoneInputId) {
|
||||||
|
var $country = $(countrySelectId + ' option:selected');
|
||||||
|
var code = $country.data('calling-code') || '';
|
||||||
|
var $phone = $(phoneInputId);
|
||||||
|
// حذف کد قدیمی اگر وجود داره
|
||||||
|
var currentVal = $phone.val().replace(/^\+\d+\s?/, '').trim();
|
||||||
|
if (code) {
|
||||||
|
$phone.val(code + ' ' + currentVal).css('border-color', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#ifnex-from-country').on('change', function() {
|
||||||
|
updateCallingCode('#ifnex-from-country', '#ifnex-sender-phone');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#ifnex-to-country').on('change', function() {
|
||||||
|
updateCallingCode('#ifnex-to-country', '#ifnex-receiver-phone');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── Phone validation: digits, +, spaces only ───
|
||||||
|
$('#ifnex-sender-phone, #ifnex-receiver-phone').on('input', function() {
|
||||||
|
var val = $(this).val();
|
||||||
|
var clean = val.replace(/[^\d+\s]/g, '');
|
||||||
|
if (val !== clean) {
|
||||||
|
$(this).val(clean);
|
||||||
|
$(this).css('border-color', '#ef4444');
|
||||||
|
var $el = $(this);
|
||||||
|
setTimeout(function(){ $el.css('border-color', ''); }, 1500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── English-only validation for all text fields ───
|
||||||
|
function isPersianText(text) {
|
||||||
|
var cleaned = text.replace(/[\s0-9\-.,،؛:()\/#]/g, '');
|
||||||
|
return /[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(cleaned);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkEnglishField(inputId, warningId) {
|
||||||
|
var text = $(inputId).val();
|
||||||
|
if (text && isPersianText(text)) {
|
||||||
|
$(warningId).slideDown(200);
|
||||||
|
} else {
|
||||||
|
$(warningId).slideUp(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupEnglishField(inputId, warningId) {
|
||||||
|
$(inputId).on('input', function() {
|
||||||
|
checkEnglishField(inputId, warningId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// همه فیلدهای متنی باید انگلیسی باشن
|
||||||
|
setupEnglishField('#ifnex-sender-name', '#ifnex-sender-name-warning');
|
||||||
|
setupEnglishField('#ifnex-sender-city', '#ifnex-sender-city-warning');
|
||||||
|
setupEnglishField('#ifnex-sender-address', '#ifnex-sender-address-warning');
|
||||||
|
setupEnglishField('#ifnex-receiver-name', '#ifnex-receiver-name-warning');
|
||||||
|
setupEnglishField('#ifnex-receiver-city', '#ifnex-receiver-city-warning');
|
||||||
|
setupEnglishField('#ifnex-receiver-address', '#ifnex-receiver-address-warning');
|
||||||
|
|
||||||
// ─── Step Navigation ───
|
// ─── Step Navigation ───
|
||||||
function goToStep(step) {
|
function goToStep(step) {
|
||||||
currentStep = step;
|
currentStep = step;
|
||||||
@ -69,8 +135,8 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
function validateStep2() {
|
function validateStep2() {
|
||||||
var ok = true;
|
var ok = true;
|
||||||
['#ifnex-sender-name', '#ifnex-sender-phone', '#ifnex-sender-address',
|
['#ifnex-sender-name', '#ifnex-sender-phone', '#ifnex-sender-city', '#ifnex-sender-address',
|
||||||
'#ifnex-receiver-name', '#ifnex-receiver-phone', '#ifnex-receiver-address'].forEach(function(sel) {
|
'#ifnex-receiver-name', '#ifnex-receiver-phone', '#ifnex-receiver-city', '#ifnex-receiver-address'].forEach(function(sel) {
|
||||||
if (!$(sel).val()) { $(sel).css('border-color', '#ef4444'); ok = false; }
|
if (!$(sel).val()) { $(sel).css('border-color', '#ef4444'); ok = false; }
|
||||||
else { $(sel).css('border-color', ''); }
|
else { $(sel).css('border-color', ''); }
|
||||||
});
|
});
|
||||||
@ -107,81 +173,72 @@ jQuery(document).ready(function($) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildOrderData() {
|
function buildOrderData() {
|
||||||
var direction = $('#ifnex-direction').val();
|
var $fromOpt = $('#ifnex-from-country option:selected');
|
||||||
var toIso = $('#ifnex-to-country option:selected').data('iso');
|
var $toOpt = $('#ifnex-to-country option:selected');
|
||||||
var fromIso = $('#ifnex-from-country option:selected').data('iso');
|
|
||||||
return {
|
return {
|
||||||
direction: direction,
|
direction: $('#ifnex-direction').val(),
|
||||||
type: $('#ifnex-type').val(),
|
type: $('#ifnex-type').val(),
|
||||||
from_country_id: parseInt($('#ifnex-from-country').val()),
|
from_country_id: $('#ifnex-from-country').val(),
|
||||||
to_country_id: parseInt($('#ifnex-to-country').val()),
|
to_country_id: $('#ifnex-to-country').val(),
|
||||||
country_iso: (direction === 'export') ? toIso : fromIso,
|
from_country_iso: $fromOpt.data('iso'),
|
||||||
|
to_country_iso: $toOpt.data('iso'),
|
||||||
|
country_iso: $('#ifnex-direction').val() === 'export' ? $toOpt.data('iso') : $fromOpt.data('iso'),
|
||||||
weight: parseFloat($('#ifnex-weight').val()) || 0,
|
weight: parseFloat($('#ifnex-weight').val()) || 0,
|
||||||
volumetric_weight: parseFloat($('#ifnex-volumetric-weight').val()) || 0,
|
volumetric_weight: parseFloat($('#ifnex-volumetric-weight').val()) || 0,
|
||||||
|
discount_code: $('#ifnex-discount-code').val() || '',
|
||||||
sender_name: $('#ifnex-sender-name').val(),
|
sender_name: $('#ifnex-sender-name').val(),
|
||||||
sender_phone: $('#ifnex-sender-phone').val(),
|
sender_phone: $('#ifnex-sender-phone').val(),
|
||||||
sender_address: $('#ifnex-sender-address').val(),
|
|
||||||
sender_city: $('#ifnex-sender-city').val(),
|
sender_city: $('#ifnex-sender-city').val(),
|
||||||
|
sender_address: $('#ifnex-sender-address').val(),
|
||||||
receiver_name: $('#ifnex-receiver-name').val(),
|
receiver_name: $('#ifnex-receiver-name').val(),
|
||||||
receiver_phone: $('#ifnex-receiver-phone').val(),
|
receiver_phone: $('#ifnex-receiver-phone').val(),
|
||||||
receiver_address: $('#ifnex-receiver-address').val(),
|
|
||||||
receiver_city: $('#ifnex-receiver-city').val(),
|
receiver_city: $('#ifnex-receiver-city').val(),
|
||||||
discount_code: $('#ifnex-discount-code').val() || null
|
receiver_address: $('#ifnex-receiver-address').val(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPriceSummary(p) {
|
function renderPriceSummary(data) {
|
||||||
var html = '';
|
var html = '<div class="ifnex-price-breakdown">';
|
||||||
html += priceRow('قیمت پایه (درهم)', p.base_price);
|
html += '<div class="ifnex-price-row"><span>قیمت پایه:</span><strong>' + (data.base_price || '0') + ' درهم</strong></div>';
|
||||||
html += priceRow('خالص (ریال)', p.net_rial);
|
html += '<div class="ifnex-price-row"><span>ناخالص:</span><strong>' + (data.net_dirham || '0') + ' درهم</strong></div>';
|
||||||
html += priceRow('بستهبندی', p.packing_cost);
|
html += '<div class="ifnex-price-row"><span>ریال:</span><strong>' + numberFormat(data.net_rial) + ' ریال</strong></div>';
|
||||||
if (p.discount_amount > 0) html += priceRow('تخفیف', -p.discount_amount);
|
if (data.packing_cost > 0) html += '<div class="ifnex-price-row"><span>بستهبندی:</span><strong>' + numberFormat(data.packing_cost) + '</strong></div>';
|
||||||
html += priceRow('مالیات (VAT)', p.vat_amount);
|
if (data.vat_amount > 0) html += '<div class="ifnex-price-row"><span>مالیات (۹٪):</span><strong>' + numberFormat(data.vat_amount) + '</strong></div>';
|
||||||
html += '<div class="ifnex-price-row total"><span>مبلغ قابل پرداخت</span><span>' + formatNum(p.total_fee) + ' ریال</span></div>';
|
if (data.discount_applied) {
|
||||||
|
html += '<div class="ifnex-price-row ifnex-discount"><span>تخفیف:</span><strong>-' + numberFormat(data.discount_amount) + '</strong></div>';
|
||||||
|
}
|
||||||
|
html += '<div class="ifnex-price-row ifnex-total"><span>مبلغ قابل پرداخت:</span><strong>' + numberFormat(data.total_fee) + ' ریال</strong></div>';
|
||||||
|
html += '</div>';
|
||||||
$('#ifnex-price-summary').html(html);
|
$('#ifnex-price-summary').html(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
function priceRow(label, val) {
|
function numberFormat(n) {
|
||||||
return '<div class="ifnex-price-row"><span>' + label + '</span><span>' + formatNum(val) + '</span></div>';
|
return new Intl.NumberFormat('fa-IR').format(n || 0);
|
||||||
}
|
|
||||||
|
|
||||||
function formatNum(n) {
|
|
||||||
return Number(n).toLocaleString('fa-IR');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showFormError(msg) {
|
function showFormError(msg) {
|
||||||
$('#ifnex-form-error').text(msg).show();
|
$('#ifnex-form-error').text(msg).show();
|
||||||
setTimeout(function() { $('#ifnex-form-error').fadeOut(); }, 4000);
|
setTimeout(function() { $('#ifnex-form-error').fadeOut(); }, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCalcError(msg) {
|
function showCalcError(msg) {
|
||||||
$('#ifnex-calc-error').text(msg).show();
|
$('#ifnex-calc-error').text(msg).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Submit Order (Step 4) ───
|
// ─── Submit Order ───
|
||||||
$('#ifnex-submit-order').on('click', function() {
|
$('#ifnex-submit-order').on('click', function() {
|
||||||
var btn = $(this);
|
var btn = $(this);
|
||||||
btn.prop('disabled', true).text('در حال ثبت سفارش...');
|
btn.prop('disabled', true).text('در حال ثبت...');
|
||||||
$('#ifnex-submit-error').hide();
|
|
||||||
|
|
||||||
var data = buildOrderData();
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: ifnex_ajax.ajax_url,
|
url: ifnex_ajax.ajax_url,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: { action: 'ifnex_submit_order', nonce: ifnex_ajax.nonce, data: data },
|
data: { action: 'ifnex_submit_order', nonce: ifnex_ajax.nonce, data: buildOrderData() },
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
btn.prop('disabled', false).text('✅ تأیید و ثبت سفارش');
|
btn.prop('disabled', false).text('✅ تأیید و ثبت سفارش');
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
var d = res.data.data;
|
var orderId = res.data.data.id || res.data.id;
|
||||||
$('#ifnex-order-form').html(
|
window.location.href = ifnex_ajax.orders_url + 'order-payment/?order_id=' + orderId;
|
||||||
'<div class="ifnex-success-box">' +
|
|
||||||
'<h3>🎉 سفارش شما با موفقیت ثبت شد!</h3>' +
|
|
||||||
'<p>شماره پیگیری: <code>' + d.awb_no + '</code></p>' +
|
|
||||||
'<p>مبلغ قابل پرداخت: <strong>' + formatNum(d.total_fee) + ' ریال</strong></p>' +
|
|
||||||
'<p>وضعیت: ' + d.status.label + '</p>' +
|
|
||||||
'<a href="' + ifnex_ajax.orders_url + '" class="ifnex-btn ifnex-btn-primary">مشاهده سفارشات من</a>' +
|
|
||||||
'</div>'
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
$('#ifnex-submit-error').text(res.data || 'خطا در ثبت سفارش').show();
|
$('#ifnex-submit-error').text(res.data || 'خطا در ثبت سفارش').show();
|
||||||
}
|
}
|
||||||
@ -193,29 +250,7 @@ jQuery(document).ready(function($) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── English Address Warning ───
|
// ─── Init ───
|
||||||
function isEnglishText(text) {
|
|
||||||
var cleaned = text.replace(/[\s0-9\-.,،؛:()\/#]/g, '');
|
|
||||||
return cleaned.length > 0 && !/[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(cleaned);
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkAddressLang(inputId, warningId) {
|
|
||||||
var text = $(inputId).val();
|
|
||||||
if (text && isEnglishText(text)) {
|
|
||||||
$(warningId).slideDown(200);
|
|
||||||
} else {
|
|
||||||
$(warningId).slideUp(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#ifnex-sender-address').on('input', function() {
|
|
||||||
checkAddressLang('#ifnex-sender-address', '#ifnex-sender-address-warning');
|
|
||||||
});
|
|
||||||
$('#ifnex-receiver-address').on('input', function() {
|
|
||||||
checkAddressLang('#ifnex-receiver-address', '#ifnex-receiver-address-warning');
|
|
||||||
});
|
|
||||||
|
|
||||||
// ─── Init ──
|
|
||||||
if ($('#ifnex-order-form').length) {
|
if ($('#ifnex-order-form').length) {
|
||||||
loadCountries();
|
loadCountries();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,6 +126,114 @@ function ifnex_wallet_balance_shortcode($atts) {
|
|||||||
<?php
|
<?php
|
||||||
return ob_get_clean();
|
return ob_get_clean();
|
||||||
}
|
}
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// شورتکد فرم شارژ کیف پول (جدید)
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
add_shortcode('ifnex_wallet_charge', 'ifnex_wallet_charge_shortcode');
|
||||||
|
|
||||||
|
function ifnex_wallet_charge_shortcode($atts) {
|
||||||
|
if (!is_user_logged_in()) {
|
||||||
|
return '<p class="ifnex-error">برای شارژ کیف پول، باید وارد شوید.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$bridge = new IFNEX_User_Bridge();
|
||||||
|
$balance = $bridge->get_wallet_balance(get_current_user_id());
|
||||||
|
$current_balance = is_wp_error($balance) ? 0 : ($balance['balance'] ?? 0);
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
?>
|
||||||
|
<div class="ifnex-wallet-charge-page">
|
||||||
|
<div class="ifnex-wallet-balance">
|
||||||
|
<div class="ifnex-balance-main">
|
||||||
|
<span class="ifnex-balance-label">موجودی فعلی:</span>
|
||||||
|
<span class="ifnex-balance-amount"><?php echo number_format($current_balance); ?> ریال</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ifnex-charge-card">
|
||||||
|
<h3>💳 شارژ کیف پول</h3>
|
||||||
|
<p class="ifnex-charge-desc">برای شارژ کیف پول، مبلغ مورد نظر را وارد کنید. شما به درگاه پرداخت زرینپال منتقل خواهید شد.</p>
|
||||||
|
|
||||||
|
<div class="ifnex-charge-amounts">
|
||||||
|
<button type="button" class="ifnex-amount-btn" data-amount="5000000">۵ میلیون</button>
|
||||||
|
<button type="button" class="ifnex-amount-btn" data-amount="10000000">۱۰ میلیون</button>
|
||||||
|
<button type="button" class="ifnex-amount-btn" data-amount="20000000">۲۰ میلیون</button>
|
||||||
|
<button type="button" class="ifnex-amount-btn" data-amount="50000000">۵۰ میلیون</button>
|
||||||
|
<button type="button" class="ifnex-amount-btn" data-amount="100000000">۱۰۰ میلیون</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ifnex-form-grid">
|
||||||
|
<div class="ifnex-field">
|
||||||
|
<label>مبلغ شارژ (ریال) *</label>
|
||||||
|
<input type="number" id="ifnex-charge-amount" min="10000" step="10000" placeholder="مثلاً 10000000">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="ifnex-charge-error" class="ifnex-error-box" style="display:none;"></div>
|
||||||
|
|
||||||
|
<button type="button" id="ifnex-charge-submit" class="ifnex-btn ifnex-btn-success ifnex-btn-lg">
|
||||||
|
💳 انتقال به درگاه پرداخت
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
// انتخاب مبالغ آماده
|
||||||
|
$('.ifnex-amount-btn').on('click', function() {
|
||||||
|
$('#ifnex-charge-amount').val($(this).data('amount'));
|
||||||
|
$('.ifnex-amount-btn').removeClass('active');
|
||||||
|
$(this).addClass('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#ifnex-charge-submit').on('click', function() {
|
||||||
|
var btn = $(this);
|
||||||
|
var amount = parseInt($('#ifnex-charge-amount').val());
|
||||||
|
|
||||||
|
if (!amount || amount < 10000) {
|
||||||
|
$('#ifnex-charge-error').text('مبلغ نامعتبر است. حداقل ۱۰,۰۰۰ ریال').show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.prop('disabled', true).text('در حال انتقال به درگاه...');
|
||||||
|
$('#ifnex-charge-error').hide();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ifnex_ajax.ajax_url,
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'ifnex_wallet_charge',
|
||||||
|
amount: amount,
|
||||||
|
nonce: ifnex_ajax.nonce
|
||||||
|
},
|
||||||
|
success: function(res) {
|
||||||
|
if (res.success && res.data.payment_url) {
|
||||||
|
window.location.href = res.data.payment_url;
|
||||||
|
} else {
|
||||||
|
btn.prop('disabled', false).text('💳 انتقال به درگاه پرداخت');
|
||||||
|
var msg = res.data;
|
||||||
|
if (typeof msg === 'object') {
|
||||||
|
msg = msg.message || JSON.stringify(msg);
|
||||||
|
}
|
||||||
|
$('#ifnex-charge-error').text('خطا: ' + (msg || 'نامشخص')).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
btn.prop('disabled', false).text('💳 انتقال به درگاه پرداخت');
|
||||||
|
var errObj;
|
||||||
|
try { errObj = JSON.parse(xhr.responseText); } catch (e) { errObj = null; }
|
||||||
|
var msg = errObj && (errObj.message || errObj.error) ? (errObj.message || errObj.error) : 'خطای سرور (' + xhr.status + ')';
|
||||||
|
$('#ifnex-charge-error').text('خطا: ' + msg).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// شورتکد لیست تراکنشها
|
// شورتکد لیست تراکنشها
|
||||||
add_shortcode('ifnex_transactions', 'ifnex_transactions_shortcode');
|
add_shortcode('ifnex_transactions', 'ifnex_transactions_shortcode');
|
||||||
@ -547,34 +655,67 @@ function ifnex_order_form_shortcode($atts) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 2: Sender & Receiver -->
|
<!-- Step 2: Sender & Receiver -->
|
||||||
<div class="ifnex-form-step" data-step="2">
|
<div class="ifnex-form-step" data-step="2">
|
||||||
<div class="ifnex-form-card">
|
<div class="ifnex-form-card">
|
||||||
<h3>👤 اطلاعات فرستنده</h3>
|
<h3>👤 اطلاعات فرستنده</h3>
|
||||||
<div class="ifnex-form-grid">
|
<div class="ifnex-form-grid">
|
||||||
<div class="ifnex-field"><label>نام و نام خانوادگی *</label><input type="text" id="ifnex-sender-name"></div>
|
<div class="ifnex-field">
|
||||||
<div class="ifnex-field"><label>شماره تماس *</label><input type="tel" id="ifnex-sender-phone"></div>
|
<label>نام و نام خانوادگی *</label>
|
||||||
<div class="ifnex-field"><label>شهر</label><input type="text" id="ifnex-sender-city"></div>
|
<input type="text" id="ifnex-sender-name">
|
||||||
<div class="ifnex-field full">
|
<div class="ifnex-address-warning" id="ifnex-sender-name-warning" style="display:none;">
|
||||||
<label>آدرس کامل *</label>
|
⚠️ نام را به زبان انگلیسی وارد کنید. در صورت عدم توانایی، با پشتیبانی تماس بگیرید.
|
||||||
<textarea id="ifnex-sender-address" rows="2"></textarea>
|
</div>
|
||||||
<div class="ifnex-address-warning" id="ifnex-sender-address-warning" style="display:none;">
|
|
||||||
⚠️ آدرس به زبان انگلیسی وارد شده. برای تحویل بهتر، آدرس فارسی نیز وارد کنید.
|
|
||||||
</div>
|
</div>
|
||||||
</div> </div>
|
<div class="ifnex-field">
|
||||||
|
<label>شماره تماس *</label>
|
||||||
|
<input type="tel" id="ifnex-sender-phone" placeholder="مثال: +98 9123456789">
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-field">
|
||||||
|
<label>شهر *</label>
|
||||||
|
<input type="text" id="ifnex-sender-city">
|
||||||
|
<div class="ifnex-address-warning" id="ifnex-sender-city-warning" style="display:none;">
|
||||||
|
⚠️ نام شهر را به زبان انگلیسی وارد کنید. در صورت عدم توانایی، با پشتیبانی تماس بگیرید.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-field full">
|
||||||
|
<label>آدرس کامل *</label>
|
||||||
|
<textarea id="ifnex-sender-address" rows="2"></textarea>
|
||||||
|
<div class="ifnex-address-warning" id="ifnex-sender-address-warning" style="display:none;">
|
||||||
|
⚠️ آدرس را به زبان انگلیسی وارد کنید (برای حمل بینالمللی). در صورت عدم توانایی، با پشتیبانی تماس بگیرید.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 style="margin-top:24px;">📮 اطلاعات گیرنده</h3>
|
<h3 style="margin-top:24px;">📮 اطلاعات گیرنده</h3>
|
||||||
<div class="ifnex-form-grid">
|
<div class="ifnex-form-grid">
|
||||||
<div class="ifnex-field"><label>نام و نام خانوادگی *</label><input type="text" id="ifnex-receiver-name"></div>
|
<div class="ifnex-field">
|
||||||
<div class="ifnex-field"><label>شماره تماس *</label><input type="tel" id="ifnex-receiver-phone"></div>
|
<label>نام و نام خانوادگی *</label>
|
||||||
<div class="ifnex-field"><label>شهر</label><input type="text" id="ifnex-receiver-city"></div>
|
<input type="text" id="ifnex-receiver-name">
|
||||||
|
<div class="ifnex-address-warning" id="ifnex-receiver-name-warning" style="display:none;">
|
||||||
|
⚠️ نام را به زبان انگلیسی وارد کنید. در صورت عدم توانایی، با پشتیبانی تماس بگیرید.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-field">
|
||||||
|
<label>شماره تماس *</label>
|
||||||
|
<input type="tel" id="ifnex-receiver-phone" placeholder="مثال: +971 501234567">
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-field">
|
||||||
|
<label>شهر *</label>
|
||||||
|
<input type="text" id="ifnex-receiver-city">
|
||||||
|
<div class="ifnex-address-warning" id="ifnex-receiver-city-warning" style="display:none;">
|
||||||
|
⚠️ نام شهر را به زبان انگلیسی وارد کنید. در صورت عدم توانایی، با پشتیبانی تماس بگیرید.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="ifnex-field full">
|
<div class="ifnex-field full">
|
||||||
<label>آدرس کامل *</label>
|
<label>آدرس کامل *</label>
|
||||||
<textarea id="ifnex-receiver-address" rows="2"></textarea>
|
<textarea id="ifnex-receiver-address" rows="2"></textarea>
|
||||||
<div class="ifnex-address-warning" id="ifnex-receiver-address-warning" style="display:none;">
|
<div class="ifnex-address-warning" id="ifnex-receiver-address-warning" style="display:none;">
|
||||||
⚠️ آدرس به زبان انگلیسی وارد شده. برای تحویل بهتر، آدرس فارسی نیز وارد کنید.
|
⚠️ آدرس را به زبان انگلیسی وارد کنید (برای حمل بینالمللی). در صورت عدم توانایی، با پشتیبانی تماس بگیرید.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ifnex-form-nav">
|
<div class="ifnex-form-nav">
|
||||||
<button class="ifnex-btn ifnex-prev-step">→ قبلی</button>
|
<button class="ifnex-btn ifnex-prev-step">→ قبلی</button>
|
||||||
<button class="ifnex-btn ifnex-btn-primary ifnex-next-step">ادامه ←</button>
|
<button class="ifnex-btn ifnex-btn-primary ifnex-next-step">ادامه ←</button>
|
||||||
@ -815,8 +956,11 @@ function ifnex_order_payment_shortcode($atts) {
|
|||||||
btn.prop('disabled', false).text('انتقال به درگاه بانکی');
|
btn.prop('disabled', false).text('انتقال به درگاه بانکی');
|
||||||
$('#ifnex-payment-message')
|
$('#ifnex-payment-message')
|
||||||
.addClass('ifnex-error-box')
|
.addClass('ifnex-error-box')
|
||||||
.text('خطا: ' + (res.data || 'خطا در اتصال به درگاه'))
|
var errMsg = res.data;
|
||||||
.show();
|
if (typeof errMsg === 'object') {
|
||||||
|
errMsg = errMsg.message || JSON.stringify(errMsg);
|
||||||
|
}
|
||||||
|
$('#ifnex-payment-message').addClass('ifnex-error-box').text('خطا: ' + (errMsg || 'خطا در اتصال به درگاه')).show();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
|
|||||||
@ -462,69 +462,73 @@ function ifnex_enqueue_order_assets() {
|
|||||||
global $post;
|
global $post;
|
||||||
if (!is_a($post, 'WP_Post')) return;
|
if (!is_a($post, 'WP_Post')) return;
|
||||||
|
|
||||||
$has_order_shortcodes =
|
$plugin_url = plugin_dir_url(dirname(__FILE__));
|
||||||
has_shortcode($post->post_content, 'ifnex_orders_list') ||
|
|
||||||
has_shortcode($post->post_content, 'ifnex_order_form') ||
|
|
||||||
has_shortcode($post->post_content, 'ifnex_user_profile') ||
|
|
||||||
has_shortcode($post->post_content, 'ifnex_order_payment') ||
|
|
||||||
has_shortcode($post->post_content, 'ifnex_order_detail');
|
|
||||||
has_shortcode($post->post_content, 'ifnex_customer_dashboard');
|
|
||||||
|
|
||||||
if ($has_order_shortcodes) {
|
// لود CSS
|
||||||
// ✅ اصلاح: dirname(__FILE__) یک سطح بالاتر میرود
|
wp_enqueue_style(
|
||||||
$plugin_url = plugin_dir_url(dirname(__FILE__));
|
'ifnex-orders-css',
|
||||||
|
$plugin_url . 'assets/css/ifnex-orders.css',
|
||||||
// Load CSS
|
array(),
|
||||||
wp_enqueue_style(
|
'1.7.0'
|
||||||
'ifnex-orders-css',
|
);
|
||||||
$plugin_url . 'assets/css/ifnex-orders.css',
|
|
||||||
array(),
|
// لود jQuery & JS
|
||||||
'1.2.0' //版本号 changed برای شکستن cache
|
wp_enqueue_script('jquery');
|
||||||
);
|
wp_enqueue_script(
|
||||||
|
'ifnex-order-form-js',
|
||||||
// Load jQuery & JS
|
$plugin_url . 'assets/js/ifnex-order-form.js',
|
||||||
wp_enqueue_script('jquery');
|
array('jquery'),
|
||||||
wp_enqueue_script(
|
'1.7.0',
|
||||||
'ifnex-order-form-js',
|
true
|
||||||
$plugin_url . 'assets/js/ifnex-order-form.js',
|
);
|
||||||
array('jquery'),
|
|
||||||
'1.2.0', //版本号 changed
|
// Pass data to JS
|
||||||
true
|
wp_localize_script('ifnex-order-form-js', 'ifnex_ajax', array(
|
||||||
);
|
'ajax_url' => admin_url('admin-ajax.php'),
|
||||||
|
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
||||||
// Pass data to JS
|
'orders_url' => home_url('/my-orders/'),
|
||||||
wp_localize_script('ifnex-order-form-js', 'ifnex_ajax', array(
|
));
|
||||||
'ajax_url' => admin_url('admin-ajax.php'),
|
|
||||||
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
|
||||||
'orders_url' => home_url('/my-orders/'),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════
|
||||||
// AJAX Handlers برای پرداخت سفارش
|
// AJAX Handler برای شارژ کیف پول
|
||||||
// ══════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
add_action('wp_ajax_ifnex_pay_order_wallet', 'ifnex_pay_order_wallet_ajax');
|
add_action('wp_ajax_ifnex_wallet_charge', 'ifnex_wallet_charge_ajax');
|
||||||
function ifnex_pay_order_wallet_ajax() {
|
|
||||||
|
function ifnex_wallet_charge_ajax() {
|
||||||
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
|
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
|
||||||
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
|
if (!is_user_logged_in()) {
|
||||||
|
wp_send_json_error('باید وارد شوید.');
|
||||||
$order_id = intval($_POST['order_id'] ?? 0);
|
}
|
||||||
if (!$order_id) wp_send_json_error('شناسه سفارش نامعتبر است.');
|
|
||||||
|
$amount = intval($_POST['amount'] ?? 0);
|
||||||
|
if ($amount < 10000) {
|
||||||
|
wp_send_json_error('مبلغ نامعتبر است.');
|
||||||
|
}
|
||||||
|
|
||||||
$bridge = new IFNEX_User_Bridge();
|
$bridge = new IFNEX_User_Bridge();
|
||||||
|
$callback_url = home_url('/wallet/?status=callback');
|
||||||
|
|
||||||
$result = $bridge->authenticated_request(
|
$result = $bridge->authenticated_request(
|
||||||
get_current_user_id(),
|
get_current_user_id(),
|
||||||
"/customer/orders/{$order_id}/pay-wallet",
|
'/payment/redirect',
|
||||||
'POST'
|
'POST',
|
||||||
|
[
|
||||||
|
'amount' => $amount,
|
||||||
|
'description' => 'شارژ کیف پول IFNEX',
|
||||||
|
'frontend_callback' => home_url('/wallet/'),
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
|
if (is_wp_error($result)) {
|
||||||
if (isset($result['success']) && !$result['success']) {
|
wp_send_json_error($result->get_error_message());
|
||||||
wp_send_json_error($result['message'] ?? 'خطا در پرداخت');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($result['success']) && !$result['success']) {
|
||||||
|
wp_send_json_error($result['message'] ?? 'خطا در اتصال به درگاه');
|
||||||
|
}
|
||||||
|
|
||||||
wp_send_json_success($result);
|
wp_send_json_success($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,12 +8,13 @@
|
|||||||
[](https://php.net)
|
[](https://php.net)
|
||||||
[](https://filamentphp.com)
|
[](https://filamentphp.com)
|
||||||
[](https://mysql.com)
|
[](https://mysql.com)
|
||||||
|
[]()
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**REST API + Admin Panel + Financial Engine**
|
**REST API + Admin Panel + Financial Engine + PDF Generator**
|
||||||
|
|
||||||
[🚀 نصب سریع](#-نصب-و-راهاندازی-سریع) • [📡 API Endpoints](#-api-endpoints) • [🗃️ Models](#-models) • [📚 مستندات](#-مستندات)
|
[🚀 نصب سریع](#-نصب-و-راهاندازی-سریع) • [📡 API Endpoints](#-api-endpoints) • [🗃️ Models](#-models) • [🎨 Filament Resources](#-filament-resources) • [📚 مستندات](#-مستندات)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -21,14 +22,19 @@
|
|||||||
|
|
||||||
## 🎯 نمای کلی
|
## 🎯 نمای کلی
|
||||||
|
|
||||||
این پوشه شامل **هسته مرکزی سیستم IFNEX** است:
|
این پوشه شامل **هسته مرکزی سیستم IFNEX** است که شامل چهار بخش اصلی میشود:
|
||||||
|
|
||||||
- REST API کامل برای ارتباط با WordPress
|
### ۱. REST API کامل
|
||||||
- پنل مدیریت Filament
|
ارتباط با WordPress از طریق Sanctum Token + Bridge Auth (بدون رمز عبور) — ۳۰+ endpoint برای تمام عملیات مشتری (سفارش، پرداخت، کیف پول، نوتیفیکیشن، رهگیری).
|
||||||
- موتور قیمتگذاری با ۴ زون و ۳ نوع سرویس
|
|
||||||
- سیستم کیف پول و پرداخت
|
### ۲. پنل مدیریت Filament 3.3
|
||||||
- تولید PDF (AWB, Invoice, Label) با بارکد
|
پنل کامل برای اپراتورها و مدیران شامل مدیریت مرسولهها، نرخها، ارزها، کاربران، گزارشهای مالی و تنظیمات سیستم.
|
||||||
- سیستم اعلانها و تاریخچه تغییرات
|
|
||||||
|
### ۳. موتور قیمتگذاری
|
||||||
|
محاسبه قیمت بر اساس ۴ زون (Export/Import × Parcel/Doc) و ۳ نوع سرویس با پشتیبانی از تخفیف، VAT، هزینههای داخلی و تبدیل ارز (درهم ↔ ریال).
|
||||||
|
|
||||||
|
### ۴. سیستم مالی و سندسازی
|
||||||
|
کیف پول دیجیتال، درگاه پرداخت Zarinpal، تولید خودکار PDF (AWB, Invoice, Label) با بارکد استاندارد و سیستم نوتیفیکیشن دیتابیس.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -36,11 +42,12 @@
|
|||||||
|
|
||||||
### پیشنیازها
|
### پیشنیازها
|
||||||
|
|
||||||
| ابزار | حداقل نسخه |
|
| ابزار | حداقل نسخه | توضیحات |
|
||||||
|-------|-----------|
|
|-------|-----------|---------|
|
||||||
| PHP | 8.2+ |
|
| PHP | 8.2+ | با extensions: pdo_mysql, mbstring, xml, gd, zip |
|
||||||
| Composer | 2.x |
|
| Composer | 2.x | مدیریت وابستگیها |
|
||||||
| MySQL | 8.0+ |
|
| MySQL | 8.0+ | دیتابیس اصلی |
|
||||||
|
| Node.js | 18+ | برای build assets (اختیاری) |
|
||||||
|
|
||||||
### مراحل نصب
|
### مراحل نصب
|
||||||
|
|
||||||
@ -58,25 +65,26 @@ php artisan key:generate
|
|||||||
# ۴. ایجاد دیتابیس
|
# ۴. ایجاد دیتابیس
|
||||||
mysql -u root -p -e "CREATE DATABASE ifnex_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
mysql -u root -p -e "CREATE DATABASE ifnex_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||||
|
|
||||||
# ۵. ویرایش .env و تنظیم DB_DATABASE, DB_USERNAME, DB_PASSWORD
|
# ۵. ویرایش .env — مقادیر کلیدی (مشاهده جدول زیر)
|
||||||
|
|
||||||
# ۶. اجرای migrations و seeders
|
# ۶. اجرای migrations و seeders
|
||||||
php artisan migrate --force
|
php artisan migrate --force
|
||||||
php artisan db:seed --force
|
php artisan db:seed --force
|
||||||
|
|
||||||
# ۷. اجرای سرور
|
# ۷. اجرای سرور
|
||||||
php artisan serve
|
php artisan serve
|
||||||
|
# پنل ادمین: http://127.0.0.1:8000/panel
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🔐 دسترسی پیشفرض
|
### 🔐 دسترسی پیشفرض
|
||||||
|
|
||||||
| آیتم | مقدار |
|
| آیتم | مقدار |
|
||||||
|-------|-------|
|
|-------|-------|
|
||||||
| URL پنل | http://localhost:8000/panel |
|
| URL پنل ادمین | http://localhost:8000/panel |
|
||||||
| ایمیل ادمین | admin@ifnex.local |
|
| URL API | http://localhost:8000/api/v1 |
|
||||||
|
| ایمیل ادمین | (از seeder) admin@ifnex.local |
|
||||||
| رمز عبور | password |
|
| رمز عبور | password |
|
||||||
|
|
||||||
### ⚙️ تنظیمات مهم .env
|
### ⚙️ تنظیمات مهم `.env`
|
||||||
|
|
||||||
```env
|
```env
|
||||||
# DATABASE
|
# DATABASE
|
||||||
@ -87,23 +95,39 @@ DB_DATABASE=ifnex_db
|
|||||||
DB_USERNAME=root
|
DB_USERNAME=root
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
|
|
||||||
# IFNEX
|
# IFNEX API
|
||||||
IFNEX_API_KEY=ifnex-local-dev-key
|
IFNEX_API_KEY=ifnex-local-dev-key
|
||||||
|
IFNEX_BRIDGE_API_KEY=ifnex-bridge-secret-key-2026-vernasoft # مهم برای وردپرس
|
||||||
IFNEX_TRACKING_RATE_LIMIT=60
|
IFNEX_TRACKING_RATE_LIMIT=60
|
||||||
|
|
||||||
# CORS (فقط دامنههای مجاز وردپرس)
|
# CORS (فقط دامنههای مجاز وردپرس)
|
||||||
CORS_ALLOWED_ORIGINS=http://localhost:8080,http://ifnex.local
|
CORS_ALLOWED_ORIGINS=http://localhost,http://127.0.0.1
|
||||||
|
|
||||||
# PAYMENT GATEWAY (Zarinpal)
|
# PAYMENT GATEWAY (Zarinpal)
|
||||||
ZARINPAL_MERCHANT_ID=your_merchant_id
|
ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing # برای Mock Mode
|
||||||
ZARINPAL_SANDBOX=true
|
ZARINPAL_SANDBOX=true
|
||||||
|
ZARINPAL_CALLBACK_URL=http://localhost:8000/api/v1/payment/callback
|
||||||
|
ZARINPAL_FRONTEND_SUCCESS_URL=http://localhost/IFNEX-Logistics/03_WordPress/wallet
|
||||||
|
ZARINPAL_FRONTEND_FAILURE_URL=http://localhost/IFNEX-Logistics/03_WordPress/wallet
|
||||||
|
|
||||||
|
# CURRENCY API (برای بروزرسانی نرخ ارز)
|
||||||
|
CURRENCY_API_KEY=your_api_key_here
|
||||||
|
CURRENCY_API_URL=https://api.freecurrencyapi.com/v1/latest
|
||||||
|
|
||||||
|
# WALLET
|
||||||
|
WALLET_MIN_DEPOSIT=10000
|
||||||
|
WALLET_MAX_DEPOSIT=500000000
|
||||||
|
WALLET_AUTO_CREATE=true
|
||||||
|
WALLET_ALLOW_WITHDRAWAL=false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> ⚠️ **نکته مهم:** اگر `ZARINPAL_MERCHANT_ID` برابر `fake-merchant-id-for-testing` باشد، سیستم از MockZarinpalService استفاده میکند که برای تست لوکال مناسب است.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📡 API Endpoints
|
## 📡 API Endpoints
|
||||||
|
|
||||||
### 🔓 API عمومی (API Key)
|
### 🔓 API عمومی (با API Key)
|
||||||
|
|
||||||
| متد | Endpoint | توضیح |
|
| متد | Endpoint | توضیح |
|
||||||
|------|----------|--------|
|
|------|----------|--------|
|
||||||
@ -111,47 +135,75 @@ ZARINPAL_SANDBOX=true
|
|||||||
| POST | `/api/v1/calculate` | محاسبه قیمت |
|
| POST | `/api/v1/calculate` | محاسبه قیمت |
|
||||||
| GET | `/api/v1/discount-codes` | لیست کدهای تخفیف |
|
| GET | `/api/v1/discount-codes` | لیست کدهای تخفیف |
|
||||||
| POST | `/api/v1/discount-codes/validate` | اعتبارسنجی کد تخفیف |
|
| POST | `/api/v1/discount-codes/validate` | اعتبارسنجی کد تخفیف |
|
||||||
| POST | `/api/v1/bridge/login` | Bridge Auth (وردپرس) |
|
| POST | `/api/v1/bridge/login` | Bridge Auth (وردپرس ← لاراول) |
|
||||||
| POST | `/api/v1/auth/login` | ورود مشتری |
|
| POST | `/api/v1/auth/login` | ورود مشتری (ایمیل + رمز) |
|
||||||
| POST | `/api/v1/auth/logout` | خروج |
|
| POST | `/api/v1/auth/logout` | خروج (Sanctum) |
|
||||||
|
|
||||||
### 🔐 API مشتری (Sanctum Token)
|
### 🔐 API مشتری (Sanctum Token)
|
||||||
|
|
||||||
| متد | Endpoint | توضیح |
|
| متد | Endpoint | توضیح |
|
||||||
|------|----------|--------|
|
|------|----------|--------|
|
||||||
| GET | `/api/v1/customer/profile` | پروفایل و آمار |
|
| GET | `/api/v1/customer/profile` | پروفایل + آمار سفارشات |
|
||||||
| GET | `/api/v1/customer/countries` | لیست کشورها |
|
| GET | `/api/v1/customer/countries` | لیست کشورها با پیششماره |
|
||||||
| GET | `/api/v1/customer/orders` | لیست سفارشات |
|
| GET | `/api/v1/customer/orders` | لیست سفارشات (paginated) |
|
||||||
| POST | `/api/v1/customer/orders` | ثبت سفارش |
|
| POST | `/api/v1/customer/orders` | ثبت سفارش جدید |
|
||||||
| GET | `/api/v1/customer/orders/{id}` | جزئیات سفارش |
|
| GET | `/api/v1/customer/orders/{id}` | جزئیات سفارش |
|
||||||
| POST | `/api/v1/customer/orders/{id}/cancel` | لغو سفارش |
|
| POST | `/api/v1/customer/orders/{id}/cancel` | لغو سفارش |
|
||||||
| POST | `/api/v1/customer/orders/{id}/pay-wallet` | پرداخت کیف پول |
|
| POST | `/api/v1/customer/orders/{id}/pay-wallet` | پرداخت با کیف پول |
|
||||||
| POST | `/api/v1/customer/orders/{id}/pay-gateway` | پرداخت درگاه |
|
| POST | `/api/v1/customer/orders/{id}/pay-gateway` | پرداخت با درگاه |
|
||||||
| GET | `/api/v1/customer/notifications` | اعلانها |
|
| GET | `/api/v1/customer/notifications` | لیست اعلانها |
|
||||||
| POST | `/api/v1/customer/notifications/{id}/read` | خواندن اعلان |
|
| POST | `/api/v1/customer/notifications/{id}/read` | علامتگذاری خواندهشده |
|
||||||
|
|
||||||
### 💰 API کیف پول (Sanctum Token)
|
### 💰 API کیف پول (Sanctum Token)
|
||||||
|
|
||||||
| متد | Endpoint | توضیح |
|
| متد | Endpoint | توضیح |
|
||||||
|------|----------|--------|
|
|------|----------|--------|
|
||||||
| GET | `/api/v1/wallet/balance` | موجودی |
|
| GET | `/api/v1/wallet/balance` | موجودی + آمار |
|
||||||
| GET | `/api/v1/wallet/transactions` | تراکنشها |
|
| GET | `/api/v1/wallet/transactions` | تراکنشها (paginated) |
|
||||||
|
| GET | `/api/v1/wallet/{wallet}/activity-log` | لاگ فعالیتها |
|
||||||
|
| POST | `/api/v1/wallet/{wallet}/freeze` | مسدود کردن کیف پول (admin) |
|
||||||
|
| POST | `/api/v1/wallet/{wallet}/unfreeze` | آزاد کردن کیف پول (admin) |
|
||||||
|
| POST | `/api/v1/wallet/admin-adjust` | تراکنش دستی (admin) |
|
||||||
|
|
||||||
### 💳 API پرداخت
|
### 💳 API پرداخت
|
||||||
|
|
||||||
| متد | Endpoint | توضیح |
|
| متد | Endpoint | توضیح |
|
||||||
|------|----------|--------|
|
|------|----------|--------|
|
||||||
| POST | `/api/v1/payment/redirect` | انتقال به درگاه |
|
| POST | `/api/v1/payment/redirect` | انتقال به درگاه (شارژ کیف پول) |
|
||||||
| GET | `/api/v1/payment/check/{id}` | بررسی وضعیت |
|
| GET | `/api/v1/payment/check/{transaction}` | بررسی وضعیت تراکنش |
|
||||||
| ANY | `/api/v1/payment/callback` | Callback درگاه |
|
| ANY | `/api/v1/payment/callback` | Callback از درگاه (Zarinpal) |
|
||||||
|
|
||||||
### 🧪 Mock Gateway (تست)
|
### 🧪 Mock Gateway (تست لوکال)
|
||||||
|
|
||||||
| متد | Endpoint | توضیح |
|
| متد | Endpoint | توضیح |
|
||||||
|------|----------|--------|
|
|------|----------|--------|
|
||||||
| GET | `/api/v1/payment/mock-gateway` | صفحه شبیهسازی |
|
| GET | `/api/v1/payment/mock-gateway` | صفحه شبیهسازی درگاه |
|
||||||
| GET | `/api/v1/payment/mock-gateway/success` | شبیه موفق |
|
| GET | `/api/v1/payment/mock-gateway/success` | شبیهسازی پرداخت موفق |
|
||||||
| GET | `/api/v1/payment/mock-gateway/failure` | شبیه شکست |
|
| GET | `/api/v1/payment/mock-gateway/failure` | شبیهسازی پرداخت ناموفق |
|
||||||
|
|
||||||
|
### 📥 مثال: ثبت سفارش
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000/api/v1/customer/orders \
|
||||||
|
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"direction": "export",
|
||||||
|
"type": "PARCEL",
|
||||||
|
"from_country_id": 1,
|
||||||
|
"to_country_id": 2,
|
||||||
|
"weight": 2.5,
|
||||||
|
"volumetric_weight": 2.5,
|
||||||
|
"sender_name": "John Doe",
|
||||||
|
"sender_phone": "+98 9123456789",
|
||||||
|
"sender_city": "Tehran",
|
||||||
|
"sender_address": "No 1, ValiAsr Street",
|
||||||
|
"receiver_name": "Ahmed Ali",
|
||||||
|
"receiver_phone": "+971 501234567",
|
||||||
|
"receiver_city": "Dubai",
|
||||||
|
"receiver_address": "Sheikh Zayed Road 100"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -160,95 +212,214 @@ ZARINPAL_SANDBOX=true
|
|||||||
```
|
```
|
||||||
04_Laravel/
|
04_Laravel/
|
||||||
├── app/
|
├── app/
|
||||||
│ ├── Enums/ # ShipmentStatus, ShipmentDirection, ShipmentType
|
│ ├── Enums/ # ShipmentStatus, ShipmentDirection, ShipmentType, PaymentGateway, TransactionStatus
|
||||||
│ ├── Filament/
|
│ ├── Filament/
|
||||||
│ │ ├── Resources/ # Shipment, Country, ShippingRate, Currency
|
│ │ ├── Resources/ # 10+ Resources
|
||||||
│ │ ├── Pages/ # Settings, ImportRates, PriceTest
|
│ │ │ ├── ShipmentResource/ # مدیریت مرسولهها (با RelationManagers)
|
||||||
│ │ └── Widgets/ # Dashboard Widgets
|
│ │ │ ├── CountryResource/ # مدیریت کشورها + calling_code
|
||||||
|
│ │ │ ├── ShippingRateResource/
|
||||||
|
│ │ │ ├── CurrencyResource/ # مدیریت ارزها
|
||||||
|
│ │ │ ├── UserResource/ # مدیریت کاربران
|
||||||
|
│ │ │ ├── WalletResource/ # کیف پولها
|
||||||
|
│ │ │ ├── WalletTransactionResource/
|
||||||
|
│ │ │ ├── PaymentResource/ # پرداختها
|
||||||
|
│ │ │ ├── DiscountCodeResource/
|
||||||
|
│ │ │ ├── ShipmentItemResource/
|
||||||
|
│ │ │ ├── ExchangeRateHistoryResource/
|
||||||
|
│ │ │ └── RoleResource/ # مدیریت نقشها
|
||||||
|
│ │ ├── Pages/
|
||||||
|
│ │ │ ├── IfnexSettingsPage.php # تنظیمات سیستم (key-value)
|
||||||
|
│ │ │ ├── PriceTestPage.php # تست محاسبه قیمت
|
||||||
|
│ │ │ ├── ImportRatesPage.php # آپلود اکسل نرخها
|
||||||
|
│ │ │ └── Reports/FinancialReport.php # گزارش مالی
|
||||||
|
│ │ └── Widgets/ # Dashboard Widgets
|
||||||
│ ├── Http/
|
│ ├── Http/
|
||||||
│ │ ├── Controllers/Api/ # Track, Pricing, Auth, Bridge, Customer, Wallet, Payment
|
│ │ ├── Controllers/
|
||||||
│ │ └── Middleware/ # ApiKeyMiddleware
|
│ │ │ ├── Api/
|
||||||
│ ├── Models/ # Eloquent Models (13 مدل)
|
│ │ │ │ ├── AuthController.php # لاگین/لاگاوت مشتری
|
||||||
│ ├── Notifications/ # ShipmentUpdatedNotification
|
│ │ │ │ ├── BridgeAuthController.php # Bridge Auth (وردپرس)
|
||||||
│ ├── Services/ # PriceCalculator, Pdf, Tracking, OrderPayment
|
│ │ │ │ ├── TrackController.php # رهگیری عمومی
|
||||||
│ └── Imports/ # OldShipments, ShippingRates
|
│ │ │ │ ├── PricingController.php # محاسبه قیمت
|
||||||
|
│ │ │ │ ├── DiscountCodeController.php
|
||||||
|
│ │ │ │ ├── PaymentController.php # درگاه + Callback
|
||||||
|
│ │ │ │ ├── MockGatewayController.php # شبیهسازی درگاه
|
||||||
|
│ │ │ │ ├── WalletController.php
|
||||||
|
│ │ │ │ └── Customer/
|
||||||
|
│ │ │ │ └── CustomerOrderController.php # سفارشات + نوتیفیکیشن
|
||||||
|
│ │ │ ├── ShipmentPdfController.php # AWB/Invoice/Label PDFs
|
||||||
|
│ │ │ └── OrderController.php # صفحات public سفارش
|
||||||
|
│ │ └── Middleware/
|
||||||
|
│ │ └── ApiKeyMiddleware.php # برای APIهای عمومی
|
||||||
|
│ ├── Models/ # 13 مدل Eloquent
|
||||||
|
│ ├── Notifications/ # ShipmentUpdatedNotification
|
||||||
|
│ ├── Services/
|
||||||
|
│ │ ├── PriceCalculatorService.php # موتور قیمتگذاری
|
||||||
|
│ │ ├── WalletService.php # مدیریت کیف پول
|
||||||
|
│ │ ├── OrderPaymentService.php # پرداخت سفارش
|
||||||
|
│ │ ├── ZarinpalService.php # درگاه واقعی
|
||||||
|
│ │ ├── MockZarinpalService.php # درگاه شبیهسازی
|
||||||
|
│ │ └── TrackingService.php
|
||||||
|
│ ├── Imports/ # Excel imports (OldShipments, ShippingRates)
|
||||||
|
│ ├── Exports/ # ShippingRatesTemplateExport
|
||||||
|
│ └── Console/Commands/
|
||||||
|
│ ├── ImportShippingRates.php
|
||||||
|
│ ├── ImportTrackingData.php
|
||||||
|
│ ├── UpdateExchangeRates.php
|
||||||
|
│ ├── GenerateApiToken.php
|
||||||
|
│ └── SyncWordPressUsers.php
|
||||||
│
|
│
|
||||||
├── database/
|
├── database/
|
||||||
│ ├── migrations/ # 15+ migrations
|
│ ├── migrations/ # 23 migrations
|
||||||
│ └── seeders/ # Countries, SystemSettings, DatabaseSeeder
|
│ └── seeders/
|
||||||
|
│ ├── CountrySeeder.php # 233 کشور + calling_code
|
||||||
|
│ ├── SystemSettingSeeder.php
|
||||||
|
│ └── DatabaseSeeder.php
|
||||||
│
|
│
|
||||||
├── resources/views/
|
├── resources/views/
|
||||||
│ └── pdfs/ # awb.blade, invoice.blade, label.blade
|
│ ├── pdfs/
|
||||||
|
│ │ ├── awb.blade.php # Air Waybill PDF
|
||||||
|
│ │ ├── invoice.blade.php # فاکتور PDF
|
||||||
|
│ │ └── label.blade.php # لیبل پستی با بارکد
|
||||||
|
│ └── filament/
|
||||||
|
│ └── pages/ # صفحات Filament
|
||||||
│
|
│
|
||||||
├── routes/
|
├── routes/
|
||||||
│ ├── api.php # REST API
|
│ ├── api.php # 30+ REST API endpoints
|
||||||
│ └── web.php # Web + Download Template
|
│ └── web.php # Web + Download Template
|
||||||
|
│
|
||||||
└── config/
|
└── config/
|
||||||
└── ifnex.php # تنظیمات اختصاصی
|
└── ifnex.php # تنظیمات اختصاصی IFNEX
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🗃️ Models
|
## 🗃️ Models
|
||||||
|
|
||||||
| Model | جدول | توضیح |
|
| Model | جدول | توضیح | فاز |
|
||||||
|-------|------|--------|
|
|-------|------|--------|-----|
|
||||||
| Country | countries | ۲۳۳ کشور با ۴ زون |
|
| Country | countries | ۲۳۳ کشور با ۴ زون + calling_code | ۰ |
|
||||||
| Shipment | shipments | مرسولهها (مرکزی) |
|
| Shipment | shipments | مرسولهها (مدل مرکزی) | ۰ |
|
||||||
| ShipmentItem | shipment_items | اقلام گمرکی |
|
| ShipmentItem | shipment_items | اقلام گمرکی | ۰ |
|
||||||
| ShipmentPackage | shipment_packages | بستههای چندگانه |
|
| ShipmentPackage | shipment_packages | بستههای چندگانه | ۲ |
|
||||||
| ShipmentCarrierMapping | shipment_carrier_mappings | نگاشت شرکتهای حمل |
|
| ShipmentCarrierMapping | shipment_carrier_mappings | نگاشت شرکتهای حمل | ۰ |
|
||||||
| ShipmentTrackingEvent | shipment_tracking_events | رویدادهای ترکینگ |
|
| ShipmentTrackingEvent | shipment_tracking_events | رویدادهای ترکینگ | ۰ |
|
||||||
| ShipmentStatusHistory | shipment_status_histories | تاریخچه تغییرات |
|
| ShipmentStatusHistory | shipment_status_histories | تاریخچه تغییرات وضعیت | ۲ |
|
||||||
| ShippingRate | shipping_rates | تعرفههای حمل |
|
| ShippingRate | shipping_rates | تعرفههای حمل | ۰ |
|
||||||
| SystemSetting | system_settings | تنظیمات key-value |
|
| SystemSetting | system_settings | تنظیمات key-value | ۰ |
|
||||||
| Currency | currencies | ارزهای پشتیبانی |
|
| Currency | currencies | ارزهای پشتیبانی (IRR, AED, USD, EUR, CNY) | ۲ |
|
||||||
| User | users | کاربران سیستم |
|
| ExchangeRateHistory | exchange_rate_histories | تاریخچه نرخ ارز | ۲ |
|
||||||
| Wallet | wallets | کیف پول کاربران |
|
| User | users | کاربران سیستم (admin + customer) | ۰ |
|
||||||
| WalletTransaction | wallet_transactions | تراکنشها |
|
| Wallet | wallets | کیف پول کاربران | ۲ |
|
||||||
|
| WalletTransaction | wallet_transactions | تراکنشهای کیف پول | ۲ |
|
||||||
|
| WalletActivityLog | wallet_activity_logs | لاگ فعالیتهای کیف پول | ۲ |
|
||||||
|
| DiscountCode | discount_codes | کدهای تخفیف | ۲ |
|
||||||
|
| Payment | payments | پرداختها | ۲ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎨 Filament Resources
|
## 🎨 Filament Resources
|
||||||
|
|
||||||
| Resource | توضیح |
|
### Resources اصلی
|
||||||
|----------|--------|
|
|
||||||
| ShipmentResource | مدیریت مرسولهها (جدول + فرم + جزئیات + CSV) |
|
| Resource | توضیح | ویژگیها |
|
||||||
| CountryResource | مدیریت کشورها |
|
|----------|--------|---------|
|
||||||
| ShippingRateResource | مدیریت تعرفهها |
|
| ShipmentResource | مدیریت مرسولهها | جدول + فرم + View + CSV Export + Bulk Actions |
|
||||||
| CurrencyResource | مدیریت ارزها |
|
| CountryResource | مدیریت کشورها | CRUD + calling_code + ۴ زون |
|
||||||
|
| ShippingRateResource | مدیریت تعرفهها | CRUD + فیلتر + Import از اکسل |
|
||||||
|
| CurrencyResource | مدیریت ارزها | CRUD + بروزرسانی خودکار نرخ |
|
||||||
|
| UserResource | مدیریت کاربران | CRUD + Role + Wallet link |
|
||||||
|
| WalletResource | مدیریت کیف پول | View + Freeze/Unfreeze + Activity Log |
|
||||||
|
| WalletTransactionResource | تراکنشها | View + فیلتر + گزارش |
|
||||||
|
| PaymentResource | پرداختها | View + بررسی وضعیت |
|
||||||
|
| DiscountCodeResource | کدهای تخفیف | CRUD + اعتبارسنجی |
|
||||||
|
| RoleResource | نقشها | مدیریت Roles + Permissions |
|
||||||
|
|
||||||
### RelationManagers
|
### RelationManagers
|
||||||
|
|
||||||
| RelationManager | والد | توضیح |
|
| RelationManager | والد | توضیح |
|
||||||
|---------------|------|--------|
|
|-----------------|------|--------|
|
||||||
| TrackingEventsRelationManager | Shipment | رویدادهای ترکینگ |
|
| TrackingEventsRelationManager | Shipment | رویدادهای ترکینگ با فیلد source |
|
||||||
| CarrierMappingsRelationManager | Shipment | نگاشت شرکتهای حمل |
|
| CarrierMappingsRelationManager | Shipment | نگاشت شرکتهای حمل |
|
||||||
| ItemsRelationManager | Shipment | اقلام گمرکی |
|
| ItemsRelationManager | Shipment | اقلام گمرکی |
|
||||||
|
| PackagesRelationManager | Shipment | بستههای چندگانه |
|
||||||
|
| StatusHistoriesRelationManager | Shipment | تاریخچه تغییرات وضعیت |
|
||||||
|
|
||||||
### صفحات سفارشی
|
### صفحات سفارشی
|
||||||
|
|
||||||
| صفحه | توضیح |
|
| صفحه | توضیح |
|
||||||
|-------|--------|
|
|-------|--------|
|
||||||
| SettingsPage | تنظیمات سیستم (key-value) |
|
| IfnexSettingsPage | تنظیمات سیستم (key-value) — نرخ درهم، VAT، حاشیه سود |
|
||||||
| PriceTestPage | تست محاسبه قیمت |
|
| PriceTestPage | تست محاسبه قیمت با پارامترهای مختلف |
|
||||||
| ImportRatesPage | آپلود اکسل نرخها |
|
| ImportRatesPage | آپلود اکسل نرخها + دانلود Template |
|
||||||
|
| FinancialReport | گزارش مالی (درآمد، تخفیف، کارمزد) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔴 خط قرمزها
|
## 🔧 Artisan Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Import / Migration
|
||||||
|
php artisan ifnex:import-rates # ایمپورت نرخها از اکسل
|
||||||
|
php artisan ifnex:import-tracking # ایمپورت دادههای ترکینگ تاریخی
|
||||||
|
php artisan ifnex:sync-wp-users # همگامسازی کاربران وردپرس با لاراول
|
||||||
|
|
||||||
|
# Currency
|
||||||
|
php artisan ifnex:update-exchange-rates # بروزرسانی نرخ ارز از API
|
||||||
|
|
||||||
|
# Token
|
||||||
|
php artisan ifnex:generate-api-token # تولید API Token برای ادمین
|
||||||
|
|
||||||
|
# Standard
|
||||||
|
php artisan migrate # اجرای migrations
|
||||||
|
php artisan db:seed # اجرای seeders
|
||||||
|
php artisan serve # اجرای سرور
|
||||||
|
php artisan tinker # محیط تعاملی
|
||||||
|
php artisan route:list # لیست روتها
|
||||||
|
php artisan config:clear # پاکسازی کش کانفیگ
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 خط قرمزها (ممنوعیتها)
|
||||||
|
|
||||||
| ❌ هرگز | ✅ همیشه |
|
| ❌ هرگز | ✅ همیشه |
|
||||||
|------------|------------|
|
|------------|------------|
|
||||||
| برگرداندن countries به ۲ زون | ۴ زون مجزا |
|
| برگرداندن countries به ۲ زون | ۴ زون مجزا (Export/Import × Parcel/Doc) |
|
||||||
| استفاده از ۲ نوع سرویس | ۳ نوع (DOC_NORMAL, DOC_ECONOMY, PARCEL) |
|
| استفاده از ۲ نوع سرویس | ۳ نوع (DOC_NORMAL, DOC_ECONOMY, PARCEL) |
|
||||||
| ذخیره تاریخ شمسی در DB | ذخیره timestamp میلادی |
|
| ذخیره تاریخ شمسی در DB | ذخیره timestamp میلادی + تبدیل در نمایش |
|
||||||
| CORS `*` در Production | CORS محدود به دامنه وردپرس |
|
| CORS `*` در Production | CORS محدود به دامنه وردپرس |
|
||||||
| کامیت `.env` در Git | در `.gitignore` باشد |
|
| کامیت `.env` در Git | در `.gitignore` باشد |
|
||||||
| `APP_DEBUG=true` در Production | `APP_DEBUG=false` |
|
| `APP_DEBUG=true` در Production | `APP_DEBUG=false` |
|
||||||
| PDF فارسی (AWB/Invoice/Label) | همیشه انگلیسی |
|
| PDF فارسی (AWB/Invoice/Label) | همیشه انگلیسی (برای حمل بینالمللی) |
|
||||||
| کپی از DHL | طراحی منحصر به فرد IFNEX |
|
| کپی از DHL | طراحی منحصر به فرد IFNEX |
|
||||||
|
| استفاده از `wire:click` برای دانلود | استفاده از `<a href>` با روت مستقیم |
|
||||||
|
| `getFormActions()` در Custom Pages | استفاده از `wire:click` در Blade |
|
||||||
|
| هدایت AJAX به `redirect()` | استفاده از `payment_url` در response JSON |
|
||||||
|
| متدهای نوتیفیکیشن بیرون از کلاس | داخل کلاس `IFNEX_User_Bridge` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 تست
|
||||||
|
|
||||||
|
### Mock Gateway
|
||||||
|
برای تست پرداخت بدون اتصال به Zarinpal واقعی، `ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing` را در `.env` تنظیم کنید. سپس:
|
||||||
|
- پرداختها از طریق `MockZarinpalService` پردازش میشوند
|
||||||
|
- URL پرداخت: `/api/v1/payment/mock-gateway`
|
||||||
|
- شبیهسازی موفق: `/api/v1/payment/mock-gateway/success`
|
||||||
|
- شبیهسازی ناموفق: `/api/v1/payment/mock-gateway/failure`
|
||||||
|
|
||||||
|
### Bridge Token Test
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000/api/v1/bridge/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"bridge_api_key": "YOUR_BRIDGE_KEY",
|
||||||
|
"wp_user_id": 1,
|
||||||
|
"wp_user_email": "user@example.com",
|
||||||
|
"wp_user_name": "Test User",
|
||||||
|
"token_name": "test"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -256,10 +427,21 @@ ZARINPAL_SANDBOX=true
|
|||||||
|
|
||||||
| فایل | محتوا |
|
| فایل | محتوا |
|
||||||
|------|-------|
|
|------|-------|
|
||||||
| [IFNEX_Phase0_Checklist.md](../01_Documents/IFNEX_Phase0_Checklist.md) | چکلیست کامل |
|
| [IFNEX_Phase0_Checklist.md](../01_Documents/IFNEX_Phase0_Checklist.md) | چکلیست کامل فازها |
|
||||||
| [IFNEX_Roadmap.md](../01_Documents/IFNEX_Roadmap.md) | نقشه راه |
|
| [IFNEX_Roadmap.md](../01_Documents/IFNEX_Roadmap.md) | نقشه راه ۴ فازی |
|
||||||
| [IFNEX_File_Map.md](../01_Documents/IFNEX_File_Map.md) | نقشه فایلها |
|
| [IFNEX_File_Map.md](../01_Documents/IFNEX_File_Map.md) | نقشه ۱۰۰+ فایل |
|
||||||
| [DEPLOYMENT.md](../DEPLOYMENT.md) | راهنمای استقرار |
|
| [DEPLOYMENT.md](../DEPLOYMENT.md) | راهنمای استقرار Production |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 مراحل بعدی
|
||||||
|
|
||||||
|
- [ ] تستهای واحد (PHPUnit)
|
||||||
|
- [ ] تستهای Integration (Laravel Dusk)
|
||||||
|
- [ ] مستندات API (OpenAPI/Swagger)
|
||||||
|
- [ ] اتصال به APIهای ترکینگ زنده
|
||||||
|
- [ ] سیستم نمایندگی (فاز ۴)
|
||||||
|
- [ ] بهبود گزارشهای مالی
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -267,4 +449,4 @@ ZARINPAL_SANDBOX=true
|
|||||||
|
|
||||||
© 2026 VernaSoft Group. All Rights Reserved.
|
© 2026 VernaSoft Group. All Rights Reserved.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use Illuminate\Support\Facades\Auth;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use App\Models\WalletTransaction;
|
||||||
|
|
||||||
class CustomerOrderController extends Controller
|
class CustomerOrderController extends Controller
|
||||||
{
|
{
|
||||||
@ -371,7 +372,7 @@ class CustomerOrderController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function countries(): JsonResponse
|
public function countries(): JsonResponse
|
||||||
{
|
{
|
||||||
$countries = Country::select('id', 'name', 'iso_code', 'export_zone_parcel', 'import_zone_parcel')
|
$countries = Country::select('id', 'name', 'iso_code', 'calling_code', 'export_zone_parcel', 'import_zone_parcel')
|
||||||
->where('is_active', true)
|
->where('is_active', true)
|
||||||
->orderBy('name')
|
->orderBy('name')
|
||||||
->get();
|
->get();
|
||||||
|
|||||||
@ -17,6 +17,7 @@ class Country extends Model
|
|||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
'iso_code',
|
'iso_code',
|
||||||
|
'calling_code',
|
||||||
'export_zone_parcel',
|
'export_zone_parcel',
|
||||||
'export_zone_doc',
|
'export_zone_doc',
|
||||||
'import_zone_parcel',
|
'import_zone_parcel',
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Middleware\ApiKeyAuth;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use Illuminate\Foundation\Application;
|
use Illuminate\Foundation\Application;
|
||||||
use Illuminate\Foundation\Configuration\Exceptions;
|
use Illuminate\Foundation\Configuration\Exceptions;
|
||||||
@ -21,7 +22,11 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
\App\Console\Commands\SyncWordPressUsers::class,
|
\App\Console\Commands\SyncWordPressUsers::class,
|
||||||
])
|
])
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
// ✅ فعالسازی Stateful API برای Sanctum
|
$middleware->alias([
|
||||||
|
'api_key' => ApiKeyAuth::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Stateful API برای Sanctum
|
||||||
$middleware->statefulApi();
|
$middleware->statefulApi();
|
||||||
|
|
||||||
// API با CORS
|
// API با CORS
|
||||||
@ -38,7 +43,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions): void {
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
// ✅ مهم: به جای redirect به login، JSON برگردان
|
// برای APIها، به جای redirect به login، JSON 401 برگردان
|
||||||
$exceptions->render(function (AuthenticationException $e, Request $request) {
|
$exceptions->render(function (AuthenticationException $e, Request $request) {
|
||||||
if ($request->is('api/*') || $request->expectsJson() || $request->wantsJson()) {
|
if ($request->is('api/*') || $request->expectsJson() || $request->wantsJson()) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('countries', function (Blueprint $table) {
|
||||||
|
if (!Schema::hasColumn('countries', 'calling_code')) {
|
||||||
|
$table->string('calling_code', 10)->nullable()->after('iso_code');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('countries', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('calling_code');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
79
04_Laravel/update_all_calling_codes.php
Normal file
79
04_Laravel/update_all_calling_codes.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
// اسکریپت آپدیت پیششماره تمام کشورهای استاندارد ISO 3166-1
|
||||||
|
// منبع: ITU-T E.164
|
||||||
|
|
||||||
|
$map = [
|
||||||
|
'AF' => '+93', 'AL' => '+355', 'DZ' => '+213', 'AS' => '+1', 'AD' => '+376',
|
||||||
|
'AO' => '+244', 'AG' => '+1', 'AR' => '+54', 'AM' => '+374', 'AU' => '+61',
|
||||||
|
'AT' => '+43', 'AZ' => '+994', 'BS' => '+1', 'BH' => '+973', 'BD' => '+880',
|
||||||
|
'BB' => '+1', 'BY' => '+375', 'BE' => '+32', 'BZ' => '+501', 'BJ' => '+229',
|
||||||
|
'BT' => '+975', 'BO' => '+591', 'BA' => '+387', 'BW' => '+267', 'BR' => '+55',
|
||||||
|
'BN' => '+673', 'BG' => '+359', 'BF' => '+226', 'BI' => '+257', 'KH' => '+855',
|
||||||
|
'CM' => '+237', 'CA' => '+1', 'CV' => '+238', 'CF' => '+236', 'TD' => '+235',
|
||||||
|
'CL' => '+56', 'CN' => '+86', 'CO' => '+57', 'KM' => '+269', 'CG' => '+242',
|
||||||
|
'CD' => '+243', 'CR' => '+506', 'CI' => '+225', 'HR' => '+385', 'CU' => '+53',
|
||||||
|
'CY' => '+357', 'CZ' => '+420', 'DK' => '+45', 'DJ' => '+253', 'DM' => '+1',
|
||||||
|
'DO' => '+1', 'EC' => '+593', 'EG' => '+20', 'SV' => '+503', 'GQ' => '+240',
|
||||||
|
'ER' => '+291', 'EE' => '+372', 'ET' => '+251', 'FJ' => '+679', 'FI' => '+358',
|
||||||
|
'FR' => '+33', 'GA' => '+241', 'GM' => '+220', 'GE' => '+995', 'DE' => '+49',
|
||||||
|
'GH' => '+233', 'GR' => '+30', 'GD' => '+1', 'GT' => '+502', 'GN' => '+224',
|
||||||
|
'GW' => '+245', 'GY' => '+592', 'HT' => '+509', 'HN' => '+504', 'HK' => '+852',
|
||||||
|
'HU' => '+36', 'IS' => '+354', 'IN' => '+91', 'ID' => '+62', 'IR' => '+98',
|
||||||
|
'IQ' => '+964', 'IE' => '+353', 'IL' => '+972', 'IT' => '+39', 'JM' => '+1',
|
||||||
|
'JP' => '+81', 'JO' => '+962', 'KZ' => '+7', 'KE' => '+254', 'KI' => '+686',
|
||||||
|
'KP' => '+850', 'KR' => '+82', 'KW' => '+965', 'KG' => '+996', 'LA' => '+856',
|
||||||
|
'LV' => '+371', 'LB' => '+961', 'LS' => '+266', 'LR' => '+231', 'LY' => '+218',
|
||||||
|
'LI' => '+423', 'LT' => '+370', 'LU' => '+352', 'MO' => '+853', 'MK' => '+389',
|
||||||
|
'MG' => '+261', 'MW' => '+265', 'MY' => '+60', 'MV' => '+960', 'ML' => '+223',
|
||||||
|
'MT' => '+356', 'MH' => '+692', 'MR' => '+222', 'MU' => '+230', 'MX' => '+52',
|
||||||
|
'FM' => '+691', 'MD' => '+373', 'MC' => '+377', 'MN' => '+976', 'ME' => '+382',
|
||||||
|
'MA' => '+212', 'MZ' => '+258', 'MM' => '+95', 'NA' => '+264', 'NR' => '+674',
|
||||||
|
'NP' => '+977', 'NL' => '+31', 'NZ' => '+64', 'NI' => '+505', 'NE' => '+227',
|
||||||
|
'NG' => '+234', 'NO' => '+47', 'OM' => '+968', 'PK' => '+92', 'PW' => '+680',
|
||||||
|
'PA' => '+507', 'PG' => '+675', 'PY' => '+595', 'PE' => '+51', 'PH' => '+63',
|
||||||
|
'PL' => '+48', 'PT' => '+351', 'QA' => '+974', 'RO' => '+40', 'RU' => '+7',
|
||||||
|
'RW' => '+250', 'KN' => '+1', 'LC' => '+1', 'VC' => '+1', 'WS' => '+685',
|
||||||
|
'SM' => '+378', 'ST' => '+239', 'SA' => '+966', 'SN' => '+221', 'RS' => '+381',
|
||||||
|
'SC' => '+248', 'SL' => '+232', 'SG' => '+65', 'SK' => '+421', 'SI' => '+386',
|
||||||
|
'SB' => '+677', 'SO' => '+252', 'ZA' => '+27', 'SS' => '+211', 'ES' => '+34',
|
||||||
|
'LK' => '+94', 'SD' => '+249', 'SR' => '+597', 'SZ' => '+268', 'SE' => '+46',
|
||||||
|
'CH' => '+41', 'SY' => '+963', 'TW' => '+886', 'TJ' => '+992', 'TZ' => '+255',
|
||||||
|
'TH' => '+66', 'TL' => '+670', 'TG' => '+228', 'TO' => '+676', 'TT' => '+1',
|
||||||
|
'TN' => '+216', 'TR' => '+90', 'TM' => '+993', 'TV' => '+688', 'UG' => '+256',
|
||||||
|
'UA' => '+380', 'AE' => '+971', 'GB' => '+44', 'US' => '+1', 'UY' => '+598',
|
||||||
|
'UZ' => '+998', 'VU' => '+678', 'VA' => '+379', 'VE' => '+58', 'VN' => '+84',
|
||||||
|
'YE' => '+967', 'ZM' => '+260', 'ZW' => '+263', 'PS' => '+970',
|
||||||
|
];
|
||||||
|
|
||||||
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
$app = require_once __DIR__ . '/bootstrap/app.php';
|
||||||
|
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
|
||||||
|
|
||||||
|
use App\Models\Country;
|
||||||
|
|
||||||
|
$updated = 0;
|
||||||
|
$skipped = 0;
|
||||||
|
foreach ($map as $iso => $code) {
|
||||||
|
$cnt = Country::where('iso_code', $iso)->update(['calling_code' => $code]);
|
||||||
|
if ($cnt > 0) {
|
||||||
|
$updated += $cnt;
|
||||||
|
} else {
|
||||||
|
$skipped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n=== Done ===\n";
|
||||||
|
echo "Total in map: " . count($map) . "\n";
|
||||||
|
echo "Updated: {$updated}\n";
|
||||||
|
echo "Skipped (country not in DB): {$skipped}\n";
|
||||||
|
echo "Countries with calling_code in DB: " . Country::whereNotNull('calling_code')->count() . "\n";
|
||||||
|
echo "Total countries in DB: " . Country::count() . "\n";
|
||||||
|
|
||||||
|
// لیست کشورهایی که calling_code ندارن
|
||||||
|
$missing = Country::whereNull('calling_code')->pluck('name', 'iso_code')->toArray();
|
||||||
|
if (!empty($missing)) {
|
||||||
|
echo "\nCountries still missing calling_code:\n";
|
||||||
|
foreach ($missing as $iso => $name) {
|
||||||
|
echo " - {$iso}: {$name}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
28
04_Laravel/update_calling_codes.php
Normal file
28
04_Laravel/update_calling_codes.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
$map = [
|
||||||
|
'IR' => '+98', 'AE' => '+971', 'AF' => '+93', 'AL' => '+355', 'AM' => '+374',
|
||||||
|
'AZ' => '+994', 'BH' => '+973', 'BY' => '+375', 'CN' => '+86', 'DE' => '+49',
|
||||||
|
'FR' => '+33', 'GB' => '+44', 'IN' => '+91', 'IQ' => '+964', 'KG' => '+996',
|
||||||
|
'KW' => '+965', 'KZ' => '+7', 'LB' => '+961', 'NL' => '+31', 'OM' => '+968',
|
||||||
|
'PK' => '+92', 'PS' => '+970', 'QA' => '+974', 'RU' => '+7', 'SA' => '+966',
|
||||||
|
'SY' => '+963', 'TJ' => '+992', 'TR' => '+90', 'TM' => '+993', 'UA' => '+380',
|
||||||
|
'US' => '+1', 'UZ' => '+998',
|
||||||
|
];
|
||||||
|
|
||||||
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
$app = require_once __DIR__ . '/bootstrap/app.php';
|
||||||
|
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
|
||||||
|
|
||||||
|
use App\Models\Country;
|
||||||
|
|
||||||
|
$updated = 0;
|
||||||
|
foreach ($map as $iso => $code) {
|
||||||
|
$cnt = Country::where('iso_code', $iso)->update(['calling_code' => $code]);
|
||||||
|
if ($cnt > 0) {
|
||||||
|
$updated += $cnt;
|
||||||
|
echo "Updated {$iso} => {$code}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\nDone. Total updated: {$updated}\n";
|
||||||
|
echo "Countries with calling_code: " . Country::whereNotNull('calling_code')->count() . "\n";
|
||||||
154
DEPLOYMENT.md
154
DEPLOYMENT.md
@ -25,25 +25,6 @@
|
|||||||
|
|
||||||
## ۱. استقرار لاراول
|
## ۱. استقرار لاراول
|
||||||
|
|
||||||
### بکاپ دیتابیس
|
|
||||||
\```bash
|
|
||||||
# بکاپ کامل دیتابیس
|
|
||||||
mysqldump -u root -p ifnex_db > /backups/ifnex_$(date +%Y%m%d_%H%M%S).sql
|
|
||||||
|
|
||||||
# یا فشرده
|
|
||||||
mysqldump -u root -p ifnex_db | gzip > /backups/ifnex_$(date +%Y%m%d_%H%M%S).sql.gz
|
|
||||||
\```
|
|
||||||
|
|
||||||
### بکاپ فایلها
|
|
||||||
\```bash
|
|
||||||
# بکاپ فایلهای لاراول
|
|
||||||
tar -czf /backups/laravel_$(date +%Y%m%d_%H%M%S).tar.gz /home/USER/web/api.ifnex.vernahost.ir/public_html
|
|
||||||
|
|
||||||
# بکاپ فایلهای وردپرس
|
|
||||||
tar -czf /backups/wordpress_$(date +%Y%m%d_%H%M%S).tar.gz /home/USER/web/ifnex.vernahost.ir/public_html
|
|
||||||
\```
|
|
||||||
|
|
||||||
|
|
||||||
### ۱.۱ کلون مخزن روی سرور
|
### ۱.۱ کلون مخزن روی سرور
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -55,17 +36,16 @@ git clone https://www.git.vernahost.ir/gitmodir110/ifnex.git .
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /home/USER/web/api.ifnex.vernahost.ir/public_html
|
cd /home/USER/web/api.ifnex.vernahost.ir/public_html
|
||||||
git clone https://www.git.vernahost.ir/gitmodir110/ifnex.git tmp-ifnex
|
ngit clone https://www.git.vernahost.ir/gitmodir110/ifnex.git tmp-ifnex
|
||||||
cp -r tmp-ifnex/04_Laravel/* .
|
cp -r tmp-ifnex/04_Laravel/* .
|
||||||
# فقط فایلهای مخفی خاص را کپی کنید
|
cp -r tmp-ifnex/04_Laravel/.* . 2>/dev/null
|
||||||
cp -r tmp-ifnex/04_Laravel/.env.example .
|
rm -rf tmp-ifnex
|
||||||
cp -r tmp-ifnex/04_Laravel/.gitignore .
|
```
|
||||||
# یا بهتر است فایلها را دستی کپی کنید ...
|
|
||||||
|
|
||||||
### ۱.۲ نصب وابستگیها
|
### ۱.۲ نصب وابستگیها
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /home/USER/web/api.ifnex.vernahost.ir/public_html
|
ncd /home/USER/web/api.ifnex.vernahost.ir/public_html
|
||||||
composer install --no-dev --optimize-autoloader
|
composer install --no-dev --optimize-autoloader
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -88,10 +68,17 @@ DB_DATABASE=ifnex_db
|
|||||||
DB_USERNAME=ifnex_user
|
DB_USERNAME=ifnex_user
|
||||||
DB_PASSWORD=STRONG_PASSWORD
|
DB_PASSWORD=STRONG_PASSWORD
|
||||||
|
|
||||||
|
# مهم: Bridge API Key باید با وردپرس یکسان باشد
|
||||||
|
IFNEX_BRIDGE_API_KEY=ifnex-bridge-secret-key-2026-vernasoft
|
||||||
|
|
||||||
CORS_ALLOWED_ORIGINS=https://ifnex.vernahost.ir
|
CORS_ALLOWED_ORIGINS=https://ifnex.vernahost.ir
|
||||||
|
|
||||||
|
# Payment Gateway
|
||||||
ZARINPAL_SANDBOX=false
|
ZARINPAL_SANDBOX=false
|
||||||
ZARINPAL_MERCHANT_ID=YOUR_MERCHANT_ID
|
ZARINPAL_MERCHANT_ID=YOUR_REAL_MERCHANT_ID
|
||||||
|
ZARINPAL_CALLBACK_URL=https://api.ifnex.vernahost.ir/api/v1/payment/callback
|
||||||
|
ZARINPAL_FRONTEND_SUCCESS_URL=https://ifnex.vernahost.ir/wallet
|
||||||
|
ZARINPAL_FRONTEND_FAILURE_URL=https://ifnex.vernahost.ir/wallet
|
||||||
```
|
```
|
||||||
|
|
||||||
### ۱.۴ دیتابیس
|
### ۱.۴ دیتابیس
|
||||||
@ -139,7 +126,24 @@ cd /home/USER/web/ifnex.vernahost.ir/public_html/wp-content/plugins/
|
|||||||
| تنظیم | مقدار |
|
| تنظیم | مقدار |
|
||||||
|--------|-------|
|
|--------|-------|
|
||||||
| API URL | `https://api.ifnex.vernahost.ir/api/v1` |
|
| API URL | `https://api.ifnex.vernahost.ir/api/v1` |
|
||||||
| Bridge API Key | کلید مشترک بین وردپرس و لاراول |
|
| API Key (عمومی) | برای APIهای عمومی مثل Tracking (همان `IFNEX_API_KEY` در `.env` لاراول) |
|
||||||
|
| Bridge API Key | کلید مشترک بین وردپرس و لاراول (همان `IFNEX_BRIDGE_API_KEY` در `.env` لاراول) |
|
||||||
|
|
||||||
|
> ⚠️ **مهم:** Bridge API Key باید در لاراول (`.env`) و وردپرس (پنل تنظیمات پلاگین) دقیقاً یکسان باشد. در غیر این صورت، کاربران وردپرس نمیتوانند توکن Sanctum دریافت کنند.
|
||||||
|
|
||||||
|
### ۲.۳ صفحات مورد نیاز در وردپرس
|
||||||
|
|
||||||
|
این صفحات باید با شورتکدهای مشخص ساخته شوند:
|
||||||
|
|
||||||
|
| آدرس | شورتکد | توضیح |
|
||||||
|
|------|---------|--------|
|
||||||
|
| `/my-account/` | `[ifnex_customer_dashboard]` | پنل جامع مشتری |
|
||||||
|
| `/my-orders/` | `[ifnex_orders_list]` | لیست سفارشات |
|
||||||
|
| `/new-order/` | `[ifnex_order_form]` | فرم ثبت سفارش |
|
||||||
|
| `/order-detail/` | `[ifnex_order_detail]` | جزئیات سفارش |
|
||||||
|
| `/order-payment/` | `[ifnex_order_payment]` | صفحه پرداخت |
|
||||||
|
| `/wallet/` | `[ifnex_wallet_charge]` | شارژ کیف پول |
|
||||||
|
| `/tracking/` | `[ifnex_tracking_form]` | رهگیری مرسوله |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -239,101 +243,11 @@ php artisan route:list --path=api/v1
|
|||||||
- `APP_DEBUG=false` در Production
|
- `APP_DEBUG=false` در Production
|
||||||
- `CORS_ALLOWED_ORIGINS` فقط دامنه وردپرس
|
- `CORS_ALLOWED_ORIGINS` فقط دامنه وردپرس
|
||||||
- `IFNEX_API_KEY` یک کلید قوی و تصادفی باشد
|
- `IFNEX_API_KEY` یک کلید قوی و تصادفی باشد
|
||||||
|
- `IFNEX_BRIDGE_API_KEY` یک کلید قوی و تصادفی باشد (متفاوت از API Key)
|
||||||
- SSL/HTTPS فعال باشد
|
- SSL/HTTPS فعال باشد
|
||||||
- رمز عبور دیتابیس قوی باشد
|
- دسترسی پوشه `storage` و `bootstrap/cache` قابل نوشتن باشد (۷۷۵)
|
||||||
|
- درگاه Zarinpal در Production باید `SANDBOX=false` و `MERCHANT_ID` واقعی باشد
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
© 2026 VernaSoft Group. Internal use only.
|
© 2026 VernaSoft Group. Internal use only.
|
||||||
|
|
||||||
|
|
||||||
## ۷. تنظیمات Web Server
|
|
||||||
|
|
||||||
### Nginx (لاراول)
|
|
||||||
\```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name api.ifnex.vernahost.ir;
|
|
||||||
root /home/USER/web/api.ifnex.vernahost.ir/public_html/public;
|
|
||||||
|
|
||||||
index index.php;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.php?$query_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ \.php$ {
|
|
||||||
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
|
|
||||||
fastcgi_index index.php;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ /\.(?!well-known).* {
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\```
|
|
||||||
|
|
||||||
### Apache (لاراول)
|
|
||||||
\```apache
|
|
||||||
<VirtualHost *:80>
|
|
||||||
ServerName api.ifnex.vernahost.ir
|
|
||||||
DocumentRoot /home/USER/web/api.ifnex.vernahost.ir/public_html/public
|
|
||||||
|
|
||||||
<Directory /home/USER/web/api.ifnex.vernahost.ir/public_html/public>
|
|
||||||
AllowOverride All
|
|
||||||
Require all granted
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
ErrorLog ${APACHE_LOG_DIR}/api.ifnex.error.log
|
|
||||||
CustomLog ${APACHE_LOG_DIR}/api.ifnex.access.log combined
|
|
||||||
</VirtualHost>
|
|
||||||
\```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## ۸. Queue Worker (اگر استفاده میشود)
|
|
||||||
|
|
||||||
### Supervisor Setup
|
|
||||||
\```bash
|
|
||||||
sudo nano /etc/supervisor/conf.d/ifnex-worker.conf
|
|
||||||
\```
|
|
||||||
|
|
||||||
\```ini
|
|
||||||
[program:ifnex-worker]
|
|
||||||
process_name=%(program_name)s_%(process_num)02d
|
|
||||||
command=php /home/USER/web/api.ifnex.vernahost.ir/public_html/artisan queue:work --sleep=3 --tries=3 --max-time=3600
|
|
||||||
autostart=true
|
|
||||||
autorestart=true
|
|
||||||
stopasgroup=true
|
|
||||||
killasgroup=true
|
|
||||||
user=USER
|
|
||||||
numprocs=2
|
|
||||||
redirect_stderr=true
|
|
||||||
stdout_logfile=/home/USER/web/api.ifnex.vernahost.ir/public_html/storage/logs/worker.log
|
|
||||||
\```
|
|
||||||
|
|
||||||
\```bash
|
|
||||||
sudo supervisorctl reread
|
|
||||||
sudo supervisorctl update
|
|
||||||
sudo supervisorctl start all
|
|
||||||
\```
|
|
||||||
|
|
||||||
|
|
||||||
## ۹. SSL/TLS (HTTPS)
|
|
||||||
|
|
||||||
### Let's Encrypt (رایگان)
|
|
||||||
\```bash
|
|
||||||
# نصب Certbot
|
|
||||||
sudo apt install certbot python3-certbot-nginx
|
|
||||||
|
|
||||||
# دریافت SSL certificate
|
|
||||||
sudo certbot --nginx -d api.ifnex.vernahost.ir -d ifnex.vernahost.ir
|
|
||||||
|
|
||||||
# تمدید خودکار (تست)
|
|
||||||
sudo certbot renew --dry-run
|
|
||||||
\```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
275
README.md
275
README.md
@ -5,12 +5,12 @@
|
|||||||
### پلتفرم جامع مدیریت لجستیک بینالمللی
|
### پلتفرم جامع مدیریت لجستیک بینالمللی
|
||||||
|
|
||||||
[](https://laravel.com)
|
[](https://laravel.com)
|
||||||
[](https://php.net)
|
[](https://filamentphp.com)
|
||||||
[](https://filamentphp.com)
|
[](https://filamentphp.com)
|
||||||
[](https://wordpress.org)
|
[](https://wordpress.org)
|
||||||
[](https://mysql.com)
|
[](https://mysql.com)
|
||||||
|
[]()
|
||||||
[]()
|
[]()
|
||||||
[]()
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -24,49 +24,65 @@
|
|||||||
|
|
||||||
## 📖 درباره پروژه
|
## 📖 درباره پروژه
|
||||||
|
|
||||||
**IFNEX** یک راهحل جامع برای شرکتهای حملونقل بینالمللی است که فرآیندهای مبتنی بر فایلهای اکسل را با یک سیستم Headless مدرن جایگزین میکند.
|
**IFNEX** یک راهحل جامع برای شرکتهای حملونقل بینالمللی است که فرآیندهای مبتنی بر فایلهای اکسل را با یک سیستم Headless مدرن جایگزین میکند. این سیستم با تکیه بر Laravel 11 به عنوان بکاند، WordPress به عنوان فرانتاند و Filament 3.3 به عنوان پنل مدیریت، تجربهای یکپارچه برای اپراتورها و مشتریان فراهم میآورد.
|
||||||
|
|
||||||
این سیستم شامل:
|
### ✨ امکانات کلیدی
|
||||||
|
|
||||||
- **موتور قیمتگذاری هوشمند** با ۴ زون و ۳ نوع سرویس
|
- **موتور قیمتگذاری هوشمند** با ۴ زون مجزا (Export/Import × Parcel/Doc) و ۳ نوع سرویس (DOC_NORMAL, DOC_ECONOMY, PARCEL)
|
||||||
- **ثبت سفارش آنلاین** چند بستهای با محاسبه لحظهای قیمت
|
- **ثبت سفارش آنلاین چندمرحلهای** با Wizard و محاسبه لحظهای قیمت
|
||||||
- **تولید خودکار اسناد** (AWB, Invoice, Label) با بارکد استاندارد
|
- **تولید خودکار اسناد** (AWB, Invoice, Label) با بارکد استاندارد و پشتیبانی کامل از زبان انگلیسی
|
||||||
- **پورتال مشتری کامل** با کیف پول، پرداخت آنلاین و اعلانها
|
- **پورتال مشتری کامل** با کیف پول، پرداخت آنلاین، تراکنشها، اعلانها و رهگیری مرسوله
|
||||||
- **پنل مدیریت قدرتمند** با Filament 3.3
|
- **پنل مدیریت قدرتمند** با Filament 3.3 شامل مدیریت مرسولهها، نرخها، ارزها، کاربران و گزارشها
|
||||||
- **سیستم ترکینگ** با قابلیت مهاجرت دادههای تاریخی
|
- **سیستم ترکینگ** با قابلیت مهاجرت دادههای تاریخی و تایملاین کامل
|
||||||
|
- **اعلانهای دیتابیس** برای ادمین و مشتری با badge unread در سایدبار
|
||||||
|
- **پشتیبانی از ۱۹۲ کشور** با پیششماره تلفن استاندارد ISO 3166-1
|
||||||
|
- **اعتبارسنجی فرمها** شامل تشخیص خودکار زبان فارسی/انگلیسی و پیششماره خودکار
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏗️ معماری سیستم
|
## 🏗️ معماری سیستم
|
||||||
|
|
||||||
این پروژه بر اساس الگوی **Headless** طراحی شده است — فرانتاند (WordPress) و بکاند (Laravel) کاملاً جدا و فقط از طریق REST API با هم ارتباط دارند.
|
این پروژه بر اساس الگوی **Headless** طراحی شده است — فرانتاند (WordPress) و بکاند (Laravel) کاملاً جدا و فقط از طریق REST API با هم ارتباط دارند. این جداسازی به ما امکان میدهد تا هر لایه را مستقل مقیاسپذیر کنیم، امنیت را بهبود ببخشیم و در آینده فرانتاندهای دیگری (مثل اپلیکیشن موبایل) را اضافه کنیم.
|
||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────┐
|
||||||
│ CLIENT BROWSER │
|
│ CLIENT BROWSER │
|
||||||
└────────────────────────┬─────────────────────────────┘
|
└────────────────────────┬─────────────────────────────┘
|
||||||
│
|
│
|
||||||
┌────────────────────────▼─────────────────────────────┐
|
┌────────────────────────▼─────────────────────────────┐
|
||||||
│ WORDPRESS (Frontend) │
|
│ WORDPRESS (Frontend) │
|
||||||
│ ┌───────────────────┐ ┌──────────────────────────┐ │
|
│ ┌───────────────────┐ ┌──────────────────────────┐ │
|
||||||
│ │ IFNEX Theme │ │ IFNEX Bridge Plugin │ │
|
│ │ IFNEX Theme │ │ IFNEX Bridge Plugin │ │
|
||||||
│ │ (Landing Page) │ │ (REST Client) │ │
|
│ │ (Landing Page) │ │ (REST Client + AJAX) │ │
|
||||||
│ └───────────────────┘ └────────────┬─────────────┘ │
|
│ └───────────────────┘ └────────────┬─────────────┘ │
|
||||||
└───────────────────────────────────┼───────────────────┘
|
└───────────────────────────────────────┼──────────────┘
|
||||||
│ REST API (Sanctum)
|
│ REST API (Sanctum + Bridge Key)
|
||||||
┌───────────────────────────────────▼───────────────────┐
|
┌───────────────────────────────────────▼──────────────┐
|
||||||
│ LARAVEL 11 (Backend) │
|
│ LARAVEL 11 (Backend) │
|
||||||
│ ┌─────────────────┐ ┌──────────────┐ ┌────────────┐ │
|
│ ┌─────────────────┐ ┌──────────────┐ ┌──────────┐ │
|
||||||
│ │ Filament │ │ API │ │ Services │ │
|
│ │ Filament │ │ API │ │ Services │ │
|
||||||
│ │ Admin Panel │ │ Controllers │ │ (Pricing, │ │
|
│ │ Admin Panel │ │ Controllers │ │ (Pricing,│ │
|
||||||
│ │ │ │ │ │ PDF, │ │
|
│ │ (/panel) │ │ (/api/v1) │ │ PDF, │ │
|
||||||
│ └─────────────────┘ └──────┬───────┘ │ Payment) │ │
|
│ └─────────────────┘ └──────┬───────┘ │ Payment)│ │
|
||||||
└──────────────────────────┼────┼─────────┘────────────┘ │
|
└──────────────────────────────┼──────────┴──────────┘
|
||||||
│ │ │
|
│
|
||||||
┌──────▼────▼────┐ │
|
┌────────────▼────────────┐
|
||||||
│ MySQL 8 │ │
|
│ MySQL 8 Database │
|
||||||
│ Database │ │
|
│ (23 migrations, 13 │
|
||||||
└───────────────┘ │
|
│ models) │
|
||||||
|
└─────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### جریان احراز هویت
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────┐ ┌─────────────────┐ ┌──────────────┐
|
||||||
|
│ WordPress│ ──POST /bridge/login──> │ Laravel Bridge │ ──> │ Sanctum Token│
|
||||||
|
│ Plugin │ <──token + user info── │ Controller │ <── │ (30 days) │
|
||||||
|
└──────────┘ └─────────────────┘ └──────────────┘
|
||||||
|
│ │
|
||||||
|
│ ──────── All subsequent API calls with Bearer Token ──────────────>│
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -75,82 +91,108 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
IFNEX-Logistics/
|
IFNEX-Logistics/
|
||||||
├── 📄 01_Documents/ # مستندات فنی پروژه
|
├── 📄 01_Documents/ # مستندات فنی پروژه
|
||||||
│ ├── IFNEX_File_Map.md # نقشه کامل فایلها
|
│ ├── IFNEX_File_Map.md # نقشه کامل ۱۰۰+ فایل
|
||||||
│ ├── IFNEX_Roadmap.md # نقشه راه پروژه
|
│ ├── IFNEX_Roadmap.md # نقشه راه ۴ فازی
|
||||||
│ ├── IFNEX_Phase0_Checklist.md
|
│ ├── IFNEX_Phase0_Checklist.md # چکلیست تکمیل فازها
|
||||||
│ ├── IFNEX_DEPRECATED_FILES_NOTICE.md
|
│ ├── IFNEX_DEPRECATED_FILES_NOTICE.md
|
||||||
│ └── EXCEL_ANALYSIS.md # تحلیل دادههای تاریخی
|
│ └── EXCEL_ANALYSIS.md # تحلیل دادههای تاریخی
|
||||||
│
|
│
|
||||||
├── 🌐 03_WordPress/ # فرانتاند (WordPress)
|
├── 🌐 03_WordPress/ # فرانتاند (WordPress 7.0.3)
|
||||||
│ └── wp-content/
|
│ └── wp-content/
|
||||||
│ ├── themes/ifnex/ # قالب سفارشی IFNEX
|
│ ├── themes/ifnex/ # قالب سفارشی IFNEX
|
||||||
│ └── plugins/
|
│ └── plugins/
|
||||||
│ └── ifnex-bridge/ # پلاگین ارتباط با لاراول
|
│ └── ifnex-bridge/ # پلاگین ارتباط با لاراول
|
||||||
|
│ ├── includes/
|
||||||
|
│ │ ├── api-client.php # مستقیم به API
|
||||||
|
│ │ ├── user-bridge.php # Bridge Auth + AJAX handlers
|
||||||
|
│ │ ├── shortcodes.php # ۱۰+ شورتکد
|
||||||
|
│ │ └── tracking-form.php # فرم رهگیری
|
||||||
|
│ └── assets/
|
||||||
|
│ ├── css/ifnex-orders.css # استایل دشبورد
|
||||||
|
│ └── js/ifnex-order-form.js # فرم چندمرحلهای
|
||||||
│
|
│
|
||||||
├── ⚙️ 04_Laravel/ # بکاند (Laravel 11)
|
├── ⚙️ 04_Laravel/ # بکاند (Laravel 11)
|
||||||
│ ├── app/
|
│ ├── app/
|
||||||
│ │ ├── Filament/ # پنل مدیریت
|
│ │ ├── Enums/ # ShipmentStatus, Direction, Type
|
||||||
│ │ ├── Http/Controllers/ # کنترلرها (API, Web)
|
│ │ ├── Filament/
|
||||||
│ │ ├── Models/ # مدلهای Eloquent
|
│ │ │ ├── Resources/ # 10+ Resource (Shipment, Country, ...)
|
||||||
│ │ ├── Services/ # لایه سرویس
|
│ │ │ ├── Pages/ # Settings, ImportRates, PriceTest, Reports
|
||||||
│ │ └── Imports/ # Excel imports
|
│ │ │ └── Widgets/ # Dashboard Widgets
|
||||||
│ ├── database/migrations/ # ۱۵+ migration
|
│ │ ├── Http/
|
||||||
|
│ │ │ ├── Controllers/Api/ # Track, Pricing, Auth, Bridge, Customer, Wallet, Payment
|
||||||
|
│ │ │ └── Middleware/ # ApiKeyMiddleware
|
||||||
|
│ │ ├── Models/ # 13 مدل Eloquent
|
||||||
|
│ │ ├── Notifications/ # Database notifications
|
||||||
|
│ │ ├── Services/ # PriceCalculator, Pdf, Tracking, OrderPayment
|
||||||
|
│ │ └── Imports/ # Excel imports (OldShipments, ShippingRates)
|
||||||
|
│ ├── database/
|
||||||
|
│ │ ├── migrations/ # 23 migrations
|
||||||
|
│ │ └── seeders/ # Countries, SystemSettings, DatabaseSeeder
|
||||||
│ ├── resources/views/
|
│ ├── resources/views/
|
||||||
│ │ ├── pdfs/ # قالبهای PDF
|
│ │ ├── pdfs/ # awb, invoice, label
|
||||||
│ │ └── filament/ # Blade views
|
│ │ └── filament/ # Blade views
|
||||||
│ └── routes/
|
│ └── routes/
|
||||||
│ ├── api.php # REST API endpoints
|
│ ├── api.php # 30+ REST API endpoints
|
||||||
│ └── web.php # Public routes
|
│ └── web.php # Web routes + Download Template
|
||||||
│
|
│
|
||||||
├── 📋 README.md # این فایل
|
├── 📋 README.md # این فایل
|
||||||
├── 📋 DEPLOYMENT.md # راهنمای استقرار
|
├── 📋 DEPLOYMENT.md # راهنمای استقرار Production
|
||||||
└── 📋 04_Laravel/README.md # راهنمای بکاند
|
└── 📋 04_Laravel/README.md # راهنمای بکاند
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ ویژگیهای کلیدی
|
## ✨ ویژگیهای کلیدی بر اساس فازها
|
||||||
|
|
||||||
### فاز ۰ — بنیان سیستم ✅
|
### فاز ۰ — بنیان سیستم ✅ (تکمیل شده - 100%)
|
||||||
- اسکیمای دیتابیس مدرن با ۴ زون مجزا (Export/Import × Parcel/Doc)
|
- اسکیمای دیتابیس مدرن با ۴ زون مجزا (Export/Import × Parcel/Doc)
|
||||||
- مهاجرت ۳۹۵۰ رکورد تاریخی از اکسل به دیتابیس
|
- مهاجرت ۳۹۵۰ رکورد تاریخی از اکسل به دیتابیس
|
||||||
- پنل مدیریت Filament با UX تخصصی اپراتور
|
- پنل مدیریت Filament با UX تخصصی اپراتور
|
||||||
- API ترکینگ با امنیت API Key + Rate Limiting
|
- API ترکینگ با امنیت API Key + Rate Limiting
|
||||||
- پلاگین WordPress Bridge برای ارتباط با فرانتاند
|
- پلاگین WordPress Bridge برای ارتباط با فرانتاند
|
||||||
|
|
||||||
### فاز ۱ — پورتال مشتری ✅
|
### فاز ۱ — پورتال مشتری ✅ (تکمیل شده - 100%)
|
||||||
- احراز هویت Laravel Sanctum + Bridge Auth
|
- احراز هویت Laravel Sanctum + Bridge Auth (بدون نیاز به رمز عبور)
|
||||||
- فرم ثبت سفارش چندمرحلهای با Wizard
|
- فرم ثبت سفارش چندمرحلهای با Wizard (مسیر، اطلاعات تماس، تخفیف، تأیید)
|
||||||
- داشبورد جامع مشتری (سفارشات، کیف پول، تراکنشها، اعلانها، رهگیری، پروفایل)
|
- داشبورد جامع مشتری شامل: داشبورد، سفارشات، ثبت سفارش، کیف پول، تراکنشها، رهگیری، اعلانها، پروفایل
|
||||||
- سیستم ترکینگ با تایملاین
|
- سیستم ترکینگ با تایملاین و تاریخچه کامل
|
||||||
|
|
||||||
### فاز ۲ — مالی و کیف پول ✅
|
### فاز ۲ — مالی و کیف پول ✅ (تکمیل شده - 100%)
|
||||||
- سیستم کیف پول کامل با تراکنشها
|
- سیستم کیف پول کامل با تراکنشها و تاریخچه
|
||||||
- درگاه پرداخت + Mock Gateway برای تست
|
- درگاه پرداخت Zarinpal + Mock Gateway برای تست لوکال
|
||||||
- مدیریت ارزهای چندگانه (IRR, AED, USD, EUR)
|
- مدیریت ارزهای چندگانه (IRR, AED, USD, EUR, CNY)
|
||||||
- کدهای تخفیف با اعتبارسنجی و محدودیت مصرف
|
- کدهای تخفیف با اعتبارسنجی و محدودیت مصرف
|
||||||
- تولید PDF حرفهای (AWB, Invoice, Label) با بارکد
|
- تولید PDF حرفهای (AWB, Invoice, Label) با بارکد استاندارد
|
||||||
|
|
||||||
### فاز ۳ — بهبود و یکپارچهسازی 🔄
|
|
||||||
- ایمپورت/اکسپورت نرخها با دانلود Template
|
|
||||||
- سیستم اعلانهای دیتابیس (ادمین + مشتری)
|
|
||||||
- پشتیبانی از چند بسته در یک سفارش (Multi-Package)
|
- پشتیبانی از چند بسته در یک سفارش (Multi-Package)
|
||||||
- تاریخچه تغییرات وضعیت
|
- تاریخچه تغییرات وضعیت (ShipmentStatusHistory)
|
||||||
- استایل مدرن تراکنشها و هشدار آدرس انگلیسی
|
|
||||||
|
|
||||||
|
### فاز ۳ — بهبود و یکپارچهسازی ✅ (تکمیل شده - 100%)
|
||||||
|
- ایمپورت/اکسپورت نرخها با دانلود Template اکسل
|
||||||
|
- سیستم اعلانهای دیتابیس (ادمین + مشتری) با badge unread در سایدبار
|
||||||
|
- هشدار هوشمند زبان فارسی/انگلیسی در فرم سفارش (نام، شهر، آدرس)
|
||||||
|
- پیششماره تلفن خودکار بر اساس کشور انتخابی (۱۹۲ کشور)
|
||||||
|
- اعتبارسنجی تلفن (فقط اعداد، +، فاصله)
|
||||||
|
- استایل مدرن تراکنشها و دشبورد مشتری
|
||||||
|
- صفحه شارژ کیف پول با مبالغ آماده
|
||||||
|
- اصلاح متدهای Enum (isPaid, canBeCancelledByCustomer)
|
||||||
|
- میدلور API برای بازگرداندن JSON 401 به جای redirect
|
||||||
|
|
||||||
|
### فاز ۴ (آینده) — سیستم نمایندگی 📋
|
||||||
|
- مدل نمایندگی کامل با کمیسیون و پنل جداگانه
|
||||||
|
- طرح مطالعاتی آماده — منتظر تأیید کارفرما
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚡ شروع سریع
|
## ⚡ شروع سریع
|
||||||
|
|
||||||
### پیشنیازها
|
### پیشنیازها
|
||||||
- PHP 8.2+
|
- PHP 8.2+ با extensions: pdo_mysql, mbstring, xml, gd, zip
|
||||||
- Composer 2.x
|
- Composer 2.x
|
||||||
- MySQL 8+
|
- MySQL 8+
|
||||||
- WordPress 7.0+
|
- WordPress 7.0+
|
||||||
|
|
||||||
### نصب
|
### نصب بکاند (Laravel)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ۱. کلون مخزن
|
# ۱. کلون مخزن
|
||||||
@ -166,15 +208,44 @@ php artisan key:generate
|
|||||||
|
|
||||||
# ۴. ایجاد دیتابیس
|
# ۴. ایجاد دیتابیس
|
||||||
mysql -u root -p -e "CREATE DATABASE ifnex_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
mysql -u root -p -e "CREATE DATABASE ifnex_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||||
# ۵. ویرایش .env و تنظیم DB_DATABASE, DB_USERNAME, DB_PASSWORD
|
|
||||||
|
# ۵. ویرایش .env — مقادیر کلیدی:
|
||||||
|
# DB_DATABASE=ifnex_db
|
||||||
|
# DB_USERNAME=root
|
||||||
|
# DB_PASSWORD=your_password
|
||||||
|
# IFNEX_BRIDGE_API_KEY=your-secret-bridge-key # مهم برای وردپرس
|
||||||
|
# ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing # برای Mock Mode
|
||||||
|
# ZARINPAL_SANDBOX=true
|
||||||
|
# CORS_ALLOWED_ORIGINS=http://localhost,http://127.0.0.1
|
||||||
|
|
||||||
# ۶. اجرای migrations و seeders
|
# ۶. اجرای migrations و seeders
|
||||||
php artisan migrate --force
|
php artisan migrate --force
|
||||||
php artisan db:seed --force
|
php artisan db:seed --force
|
||||||
|
|
||||||
# ۷. اجرای سرور
|
# ۷. اجرای سرور
|
||||||
php artisan serve
|
php artisan serve
|
||||||
|
# پنل ادمین: http://127.0.0.1:8000/panel
|
||||||
```
|
```
|
||||||
|
|
||||||
> 📖 برای راهنمای کامل استقرار، [DEPLOYMENT.md](DEPLOYMENT.md) را ببینید.
|
### نصب فرانتاند (WordPress)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ۱. کپی پوشه 03_WordPress به htdocs (XAMPP) یا public_html (سرور)
|
||||||
|
# ۲. ساخت دیتابیس وردپرس و اجرای نصب
|
||||||
|
# ۳. فعالسازی قالب IFNEX و پلاگین IFNEX Bridge
|
||||||
|
# ۴. تنظیمات پلاگین (admin → منوی IFNEX):
|
||||||
|
# - API URL: http://localhost:8000/api/v1
|
||||||
|
# - API Key (عمومی): همان مقدار IFNEX_API_KEY در .env لاراول
|
||||||
|
# - Bridge API Key: همان مقدار IFNEX_BRIDGE_API_KEY در .env لاراول
|
||||||
|
# ۵. ساخت صفحات با شورتکدها:
|
||||||
|
# - /my-account/ → [ifnex_customer_dashboard]
|
||||||
|
# - /my-orders/ → [ifnex_orders_list]
|
||||||
|
# - /new-order/ → [ifnex_order_form]
|
||||||
|
# - /wallet/ → [ifnex_wallet_charge]
|
||||||
|
# - /tracking/ → [ifnex_tracking_form]
|
||||||
|
```
|
||||||
|
|
||||||
|
> 📖 برای راهنمای کامل استقرار روی سرور، [DEPLOYMENT.md](DEPLOYMENT.md) را ببینید.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -192,6 +263,7 @@ php artisan serve
|
|||||||
| Laravel Excel | Latest | Import/Export |
|
| Laravel Excel | Latest | Import/Export |
|
||||||
| Sanctum | Latest | API Authentication |
|
| Sanctum | Latest | API Authentication |
|
||||||
| Morilog Jalali | 3.x | تاریخ شمسی |
|
| Morilog Jalali | 3.x | تاریخ شمسی |
|
||||||
|
| picqer/php-barcode | Latest | تولید بارکد |
|
||||||
|
|
||||||
### Frontend (WordPress)
|
### Frontend (WordPress)
|
||||||
|
|
||||||
@ -199,7 +271,34 @@ php artisan serve
|
|||||||
|-----------|------|--------|
|
|-----------|------|--------|
|
||||||
| WordPress | 7.0.3 | CMS |
|
| WordPress | 7.0.3 | CMS |
|
||||||
| IFNEX Theme | Custom | قالب سفارشی |
|
| IFNEX Theme | Custom | قالب سفارشی |
|
||||||
| IFNEX Bridge | 1.6.0 | پلاگین ارتباطی |
|
| IFNEX Bridge | 1.7.0 | پلاگین ارتباطی |
|
||||||
|
| jQuery | 3.x | AJAX + DOM |
|
||||||
|
|
||||||
|
### زیرساخت
|
||||||
|
|
||||||
|
| سرویس | کاربرد |
|
||||||
|
|-------|--------|
|
||||||
|
| HestiaCP | پنل مدیریت سرور |
|
||||||
|
| Nginx | وبسرور |
|
||||||
|
| PHP-FPM | پردازش PHP |
|
||||||
|
| MySQL 8 | دیتابیس |
|
||||||
|
| Let's Encrypt | SSL رایگان |
|
||||||
|
| Git (Gitea) | مخزن کد |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 آمار پروژه
|
||||||
|
|
||||||
|
| معیار | مقدار |
|
||||||
|
|-------|-------|
|
||||||
|
| تعداد مایگریشنها | ۲۳ |
|
||||||
|
| تعداد API endpoints | ۳۰+ |
|
||||||
|
| تعداد Filament Resources | ۱۰+ |
|
||||||
|
| تعداد مدلها | ۱۳ |
|
||||||
|
| تعداد شورتکدهای وردپرس | ۱۰+ |
|
||||||
|
| تعداد کشورها با پیششماره | ۱۹۲ |
|
||||||
|
| رکوردهای تاریخی مهاجرتشده | ۳۹۵۰ |
|
||||||
|
| خطوط کد (تخمینی) | ۱۵۰۰۰+ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -209,21 +308,25 @@ php artisan serve
|
|||||||
|
|
||||||
| فایل | محتوا | اولویت |
|
| فایل | محتوا | اولویت |
|
||||||
|------|-------|--------|
|
|------|-------|--------|
|
||||||
| IFNEX_Phase0_Checklist.md | چکلیست کامل فازها | ⭐⭐⭐ |
|
| [IFNEX_Phase0_Checklist.md](01_Documents/IFNEX_Phase0_Checklist.md) | چکلیست کامل فازها | ⭐⭐⭐ |
|
||||||
| IFNEX_Roadmap.md | نقشه راه آینده | ⭐⭐⭐ |
|
| [IFNEX_Roadmap.md](01_Documents/IFNEX_Roadmap.md) | نقشه راه آینده | ⭐⭐⭐ |
|
||||||
| IFNEX_File_Map.md | نقشه ۱۰۰+ فایل پروژه | ⭐⭐⭐ |
|
| [IFNEX_File_Map.md](01_Documents/IFNEX_File_Map.md) | نقشه ۱۰۰+ فایل پروژه | ⭐⭐⭐ |
|
||||||
| DEPLOYMENT.md | راهنمای استقرار Production | ⭐⭐ |
|
| [DEPLOYMENT.md](DEPLOYMENT.md) | راهنمای استقرار Production | ⭐⭐ |
|
||||||
| EXCEL_ANALYSIS.md | تحلیل دادههای اکسل | ⭐⭐ |
|
| [04_Laravel/README.md](04_Laravel/README.md) | راهنمای بکاند | ⭐⭐ |
|
||||||
|
| [IFNEX_DEPRECATED_FILES_NOTICE.md](01_Documents/IFNEX_DEPRECATED_FILES_NOTICE.md) | فایلهای منسوخ | ⭐ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 مراحل بعدی
|
## 🚀 مراحل بعدی (فاز ۴)
|
||||||
|
|
||||||
- اتصال به API های ترکینگ زنده (TrackingMore/17track)
|
- سیستم نمایندگی کامل با کمیسیون و پنل جداگانه
|
||||||
- پلاگین SMS برای اطلاعرسانی
|
- اتصال به APIهای ترکینگ زنده (TrackingMore/17track)
|
||||||
|
- پلاگین SMS برای اطلاعرسانی خودکار
|
||||||
- مستندات API (OpenAPI/Swagger)
|
- مستندات API (OpenAPI/Swagger)
|
||||||
- راهنمای اپراتور (Operator Manual)
|
- راهنمای اپراتور (Operator Manual)
|
||||||
- تستهای واحد و Integration
|
- تستهای واحد و Integration
|
||||||
|
- اپلیکیشن موبایل (احتمالی)
|
||||||
|
- ویرایش پروفایل مشتری + استان/شهر بر اساس کشور
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -232,7 +335,8 @@ php artisan serve
|
|||||||
- **توسعهدهنده:** Kazem Alghasi
|
- **توسعهدهنده:** Kazem Alghasi
|
||||||
- **شرکت:** VernaSoft Group
|
- **شرکت:** VernaSoft Group
|
||||||
- **ایمیل:** kazem@vernasoft.group
|
- **ایمیل:** kazem@vernasoft.group
|
||||||
- **مخزن:** git.vernahost.ir/gitmodir110/ifnex
|
- **مخزن:** [git.vernahost.ir/gitmodir110/ifnex](https://git.vernahost.ir/gitmodir110/ifnex)
|
||||||
|
- **سرور تست:** [api.ifnex.vernahost.ir](https://api.ifnex.vernahost.ir) (Laravel) | [ifnex.vernahost.ir](https://ifnex.vernahost.ir) (WordPress)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -241,6 +345,7 @@ php artisan serve
|
|||||||
📜 لایسنس
|
📜 لایسنس
|
||||||
|
|
||||||
© 2026 VernaSoft Group. تمام حقوق محفوظ است.
|
© 2026 VernaSoft Group. تمام حقوق محفوظ است.
|
||||||
|
|
||||||
این پروژه اختصاصی شرکت IFNEX است و کپی یا استفاده غیرمجاز ممنوع میباشد.
|
این پروژه اختصاصی شرکت IFNEX است و کپی یا استفاده غیرمجاز ممنوع میباشد.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user