This commit marks the completion of phase 3.11 (UAT Ready) and includes significant updates to deployment automation, testing, and documentation. Key changes: - Implement `ifnex:smoke-test` command for E2E post-deployment validation - Implement `ifnex:preflight` command for environment audit before migration - Implement `ifnex:import-fx-rates` for automated multi-source currency rate imports (Exir.io and FreeCurrencyAPI) - Update `CurrencySeeder` to support base currencies (USD, AED, EUR, CNY, IRR) - Enhance `IfnexSmokeTest` with improved environment-aware checks and robust HTTP mocking in tests - Update project documentation (Roadmap, README, AGENT, Handoff) to reflect completed phases 3.7 through 3.11 - Add UAT checklist and installation guides for recent hotfixes - Update project statistics (models, migrations, endpoints, and test counts)
45 KiB
راهنمای ایجنت — پروژهٔ IFNEX Logistics
تاریخ: ۲۰۲۶-۱۱-۰۱ نسخه: ۱.۶ (بهروزرسانی فاز ۳.۱۱) تهیهکننده: VernaSoft Group — Kazem Alghasi
۱. خلاصهٔ پروژه
سیستم مدیریت لجستیک بینالمللی با معماری Headless: Laravel 11 بهعنوان بکاند، WordPress 7.1 بهعنوان فرانتاند و Filament 3.3 بهعنوان پنل مدیریت. این سیستم جایگزین فرآیندهای دستی مبتنی بر اکسل شده و از Multi-Package، فاکتور گمرکی، کیف پول دیجیتال، درگاه پرداخت Zarinpal، تولید PDF با بارکد، فلوی تأیید سفارش، تعهدنامه، SMS کاوهنگار، سیستم اعتبار چندارزی، رهگیری پیشرفته، سیستم ۴-رُبعی نرخها، فاکتورهای دستی مدیر، دفترچه آدرس مشتری و دستورات خودکار استقرار پشتیبانی میکند.
وضعیت فعلی
فازهای ۰، ۱، ۲، ۳، ۳.۵، ۳.۶، ۳.۷، ۳.۸، ۳.۸.۱، ۳.۹، ۳.۱۰، ۳.۱۰.۱ و ۳.۱۱ تکمیل شدهاند. فاز ۳.۱۱ (UAT نهایی) تکمیل شد. سیستم آمادهٔ دیپلوی روی سرور Production و UAT توسط کارفرماست.
- فلوی کامل سفارش (ثبت ← تأیید ← تعهدنامه ← پرداخت) — تست End-to-End
- بازطراحی داشبورد و Login پنل Filament (هویت بصری navy + amber)
- بازطراحی PDFهای AWB، Invoice و Label (dompdf، چیدمان جدولی)
- صفحهٔ «وضعیت مالی مشتری» در پنل ادمین (۴ KPI + بدهیهای ارزی + سفارشها و تراکنشها)
- سیستم اعتبار چندارزی کامل (درخواست ۹) — بدهی به همان ارز، تسویه با نرخ روز
- ویجت هشدار بدهیهای ارزی تسویهنشده + badge روی منو
- Rate Limiting روی همهٔ APIها (۶ لایه throttle: auth / sms / public / customer / wallet / staff)
- چکلیست خودکار کارمند پس از تأیید سفارش (درخواست ۵)
- نمایش بدهی ارزی در پورتال مشتری وردپرس
- استایلدهی صفحهٔ پروفایل مشتری در وردپرس
- پاکسازی کد (حذف فایلهای تستی، تأیید تمیزی
opcache_reset/dd/dump) - سیستم ۴-رُبعی نرخها (Export/Import × Doc/Parcel) با ایمپورت از اکسل
- معماری IRR-only — ارز مبنا = ریال ایران؛ تبدیل ارز در زمان ایمپورت
- فاکتورهای دستی مدیر — صدور، پرداخت از کیف پول، اعلان خودکار به مشتری
فاز ۳.۸ (کارهای سریع ظاهری / برندینگ) نیز تکمیل شد:
- Favicon حرفهای IFNEX — ico چندسایزی + svg وکتور + apple-touch-icon + PWA icons + webmanifest + لینک در head پنل
- صفحهٔ
/برندشده — جایگزین welcome پیشفرض لاراول - جمعشدن کارت لاگین فیلمنت — ۳۸۰px، فشردهتر
- SweetAlert2 برای خطاهای فرم سفارش وردپرس (باندل محلی)
فاز ۳.۸.۱ (سختسازی Production) نیز تکمیل شد (۲۰۲۶-۱۰-۳۱):
- P0 — باگ کد تخفیف: متد
consumeDiscountCode()فراخوانی میشد ولی وجود نداشت (ثبت سفارش را میشکست). سرویس جدیدDiscountCodeServiceبا جدولdiscount_code_usages(Audit + Idempotency + قفل رقابتی) جایگزین شد؛ مصرف فقط در ثبت اولیه، ارسال مجدد دوباره مصرف نمیکند - گارد ظرفیت کد تخفیف در قیمتگذاری — کدهای پرشده در
calculate()هم اعمال نمیشوند - گارد Mock Gateway در Production — اگر
APP_ENV=productionو درگاه تستی باشد، پردازش باRuntimeException+Log::criticalمسدود میشود (قبلاً پیشفرضsandbox=trueخطرناک بود) - حذف هکهای دیباگ وردپرس —
opcache_reset()+header('Cache-Control')از ۵ فایل پلاگین حذف شد - نسخهبندی سالم assetها — cache-buster
'2.0.0-' . time()(هر ریکوئست کش را میشکند) باifnex_asset_version()مبتنی برfilemtime+ ثابتIFNEX_BRIDGE_VERSION(2.1.0) جایگزین شد (۶ نقطه) - سختسازی آپلود تعهدنامه —
mimetypes:application/pdf,image/jpeg,image/png(بررسی محتوا، نه فقط پسوند) - خروج
wp-config.phpاز گیت — saltهای واقعی لورفته فرض میشوند؛ فایل در.gitignoreو فقطwp-config-sample.phpدر مخزن است .env.exampleبروز — بلوک Production (لاگ روزانه، APP_DEBUG=false، کشها) +IFNEX_BRIDGE_API_KEY+ راهنمای چرخش کلید- سند استقرار — بخش ۴.۴ «چکلیست امنیتی سختسازی» در
DEPLOYMENT_HANDOFF.md - تستها: ۷ تست شکستهٔ قدیمی (auth کد تخفیف + معماری قدیمی محاسبهگر) تعمیر شد؛ ۷ تست جدید برای سرویس مصرف + ۲ تست برای ظرفیت/تخفیف — ۳۳ تست پاس، ۱۰۱ assertion
فاز ۳.۹ (دفترچه آدرس) نیز تکمیل شد (۲۰۲۶-۱۱-۰۱):
- مدل + جدول
address_book_entries— نقش (sender/receiver)، برچسب، فیلدهای تماس عیناً مطابق ستونهای sender_/receiver_ در shipments، پیشفرض، شمارندهٔ استفاده +last_used_at، سقف ۵۰ رکورد per-user - CRUD API با Sanctum —
GET/POST/PUT/DELETE /api/v1/addresses+POST /addresses/{id}/default؛ Ownership در همهٔ اکشنها؛ دتکت رکورد تکراری (نقش + تلفن + آدرس → بروزرسانی بهجای ساخت دوباره)؛ فیلتر role/search - اتصال به ثبت سفارش — چکباکس «ذخیره این آدرس» (upsert بدون رکورد تکراری) + شمارش استفاده از آدرس انتخابشده؛ عملیات غیرحیاتی (هر خطا فقط Log — سفارش rollback نمیشود)
- فرم سفارش وردپرس — dropdown «آدرسهای ذخیرهشده» بالای بخش فرستنده/گیرنده (پر شدن یککلیکی ۷ فیلد) + چکباکس ذخیره برای هر نقش
- تب «دفترچه آدرس» در پنل کاربری — کارتهای آدرس با فیلتر همه/فرستنده/گیرنده، فرم افزودن/ویرایش، حذف با تأیید SweetAlert، تنظیم پیشفرض، حالت خالی راهنما
- پروکسی AJAX امن — ۴ هندلر جدید (get/save/delete/set-default) با nonce + sanitize + توکن Sanctum کاربر
- تستها: ۱۸ تست جدید (
AddressBookControllerTest) — لیست/فیلتر/ساخت/ویرایش/حذف/مالکیت/سقف/تکراری/پیشفرض/markUsed/formFields
چندزبانه (i18n) همچنان به زمان دیپلوی موکول است.
فاز ۳.۱۰ (استقرار Production) و فاز ۳.۱۰.۱ (هاتفیکس preflight) و فاز ۳.۱۱ (UAT نهایی) نیز تکمیل شدند (۲۰۲۶-۱۱-۰۱):
- دستور
ifnex:preflight— fail-fast ممیزی محیط Production پیش از migrate (APP_ENV, APP_DEBUG, APP_KEY, IFNEX_API_KEY, IFNEX_BRIDGE_API_KEY, ZARINPAL_SANDBOX, DB_CONNECTION, CORS, currencies، اکستنشنهای PHP، دسترسی storage) - دستور
ifnex:import-fx-rates— جایگزینifnex:update-ratesبا پشتیبانی از EUR/CNY از FreeCurrencyAPI (بهعلاوه USD/AED از Exir.io)، پرچم--auto-approveبرای کرون،Log::criticalدر شکست HTTP، URL اکسیر از env CurrencySeeder— پنج ارز پایه (USD/AED/EUR/CNY/IRR) با نرخ صفر (IRR=1)؛ idempotent — نرخهای واقعی را overwrite نمیکند- اسکریپت
scripts/deploy.sh— استقرار خودکار ۱۳ مرحلهای با fail-fast (set -e) - اسکریپت
scripts/cron-exir-rates.sh— wrapper کرون روزانه برایifnex:import-fx-rates --source=all --auto-approve - سختسازی
.env.example— MySQL پیشفرض، EXIR_API_URL، SANCTUM_STATEFUL_DOMAINS، APP_TIMEZONE، LOG_DAILY_DAYS، رفع تکرار CURRENCY_API_KEY - رفع باگ latent در
bootstrap/app.php— حذفuse ApiKeyAuthکه کلاس وجود نداشت (کی向着 fatal) - بهبود
DatabaseSeeder— حساب super_admin با رمزpasswordدر Production ساخته نمیشود - دستور
ifnex:smoke-test— E2E خودکار Post-Deploy (۲۵+ بررسی: DB، دادهها، ۴ endpoint API) - سند
UAT-3.11.md— چکلیست ۴۳ موردی فارسی برای کارفرما + فرم امضای تحویل - تستها: ۳۱ تست جدید (IfnexPreflight ۹، IfnexImportFxRates ۹، CurrencySeeder ۴، IfnexSmokeTest ۹) — ۸۲ تست پاس، ۲۲۰+ assertion
معماری ارزی (Currency Architecture)
قاعده طلایی: ارز مبنا در کل سیستم = ریال ایران (IRR). هیچ واحد دیگری (تومان، درهم، دلار، یورو) در نمایش قیمتهای داخلی یا ذخیرهسازی استفاده نمیشود.
| نوع داده | ارز ذخیره | تبدیل |
|---|---|---|
نرخهای حمل (rate_entries) |
IRR | در زمان ایمپورت با نرخ روز |
فاکتورهای دستی (manual_invoices) |
IRR | مستقیم |
تراکنشهای کیف پول (wallet_transactions) |
IRR | مستقیم |
بدهیهای ارزی مشتری (customer_credits) |
ارز خارجی | در زمان تسویه با نرخ روز |
نرخهای ارز از جدول currencies خوانده میشوند. مدیر بهصورت دستی یا از API (Exir.io، موقتاً غیرفعال) نرخ را بهروز میکند. API نرخها با وضعیت pending ذخیره میشوند و مدیر باید تأیید کند (approved).
تفاوت نرخهای حمل و بدهی ارزی:
- نرخهای حمل به IRR ذخیره میشوند (در زمان ایمپورت با نرخ روز تبدیل میشوند) — تغییرات نرخ روز روی نرخهای ذخیرهشده اثر ندارد.
- بدهی ارزی به ارز خارجی ذخیره میشود — در زمان تسویه با نرخ روز محاسبه میشود.
فیچر فاکتورهای دستی مدیر (Manual Invoices)
مدیر میتواند برای هر مشتری فاکتور صادر کند (برای خدمات خارج از سفارش: انبارداری، مشاوره تلفنی، هزینههای جانبی و...).
- پنل ادمین:
Manual invoices(گروه «مالی») - مدل:
ManualInvoice+ManualInvoiceService+CustomerInvoiceController - جریان:
- مدیر فاکتور صادر میکند →
status = 'pending_payment' - اعلان خودکار به مشتری ارسال میشود (
ManualInvoiceCreatedNotification) - مشتری در پورتال وردپرس فاکتور را میبیند (تب «فاکتورهای دستی»)
- با کلیک روی «پرداخت از کیف پول»، مبلغ از کیف پول کسر میشود
- تراکنش با نوع
invoice_paymentدرwallet_transactionsثبت میشود
- مدیر فاکتور صادر میکند →
- شماره فاکتور: فرمت
INV-YYYY-NNNNNN(مثلاًINV-2026-000001) - وضعیتها:
pending_payment/paid/cancelled/expired - اعلام در پورتال: badge قرمز در منوی سایدبار + اعلان در تب اعلانها + ویجت داشبورد + تفکیک در وضعیت مالی
خط قرمزهای معماری ارزی
| ❌ هرگز | ✅ همیشه |
|---|---|
| ذخیره نرخها به AED/USD | ذخیره به IRR |
| نمایش قیمت به «درهم» در فرم/پورتال | نمایش به «ریال» |
| تبدیل در زمان محاسبه قیمت | تبدیل در زمان ایمپورت |
| وجود fallback عددی برای نرخ ارز | خطای واضح اگه نرخ تنظیم نشده |
| استفاده از «تومان» در کد/UI | فقط «ریال» |
۲. تکنولوژیها و نسخهها
| لایه | تکنولوژی | نسخه / توضیح |
|---|---|---|
| Backend | Laravel | 11.x |
| زبان | PHP | ^8.2 (۸.۳ نیز پشتیبانی میشود) |
| پنل مدیریت | Filament | 3.3.x |
| فرانتاند | WordPress | 7.x + قالب سفارشی IFNEX |
| احراز هویت | Laravel Sanctum + Bridge Auth | بدون رمز عبور (کلید API مشترک) |
| پرداخت | Zarinpal + Mock Gateway (تست) | کلید sandbox برای تست لوکال |
| PDF و بارکد | Dompdf + picqer/php-barcode-generator | AWB، Invoice، Label، فاکتور واردات |
| پیامک | Kavenegar | تأیید موبایل + اعلان وضعیت سفارش |
| اکسل | maatwebsite/excel + PhpSpreadsheet | Import / Export نرخها و دادههای تاریخی |
| تاریخ و زمان | morilog/jalali + Carbon | تاریخ شمسی در نمایش، میلادی در DB |
| دیتابیس | MySQL | 8.0+ (تستها با SQLite) |
| صف | Redis (ترجیحی) / Database | برای پردازشهای سنگین |
| سرور | HestiaCP + Nginx + PHP-FPM | تولید (api.ifnex.vernahost.ir) |
۳. ساختار دایرکتوری
IFNEX-Logistics/
├── 01_Documents/ # مستندات فنی
│ ├── IFNEX_File_Map.md # نقشهٔ فایلهای پروژه
│ ├── IFNEX_Roadmap.md # نقشهٔ راه فازی (۰ تا ۳.۱۱ + آینده ۴/۵)
│ ├── IFNEX_ADR.md # تصمیمات معماری (ADR-001 تا 009)
│ ├── IFNEX_Commercial_Model.md # مدل تجاری (آینده — فاز ۵)
│ ├── IFNEX_Pro_Backlog.md # فیچرهای نسخه Pro
│ ├── IFNEX_I18N_Strategy.md # استراتژی چندزبانه
│ ├── DESIGN_SYSTEM.md # سیستم طراحی
│ ├── EXCEL_ANALYSIS.md # تحلیل دادههای تاریخی
│ └── archives/ # اسناد منسوخشده (PRD_v2، Project_Roadmap قدیم)
│
├── 03_WordPress/ # فرانتاند وردپرس 7.1
│ └── wp-content/
│ ├── themes/ifnex/ # قالب سفارشی
│ └── plugins/ifnex-bridge/ # پلاگین ارتباط با لاراول (v2.1.0)
│ ├── includes/ # api-client، user-bridge، shortcodes، tracking-form
│ └── assets/ # CSS و JS فرم سفارش + دفترچه آدرس
│
├── 04_Laravel/ # بکاند لاراول (هستهٔ اصلی)
│ ├── app/
│ │ ├── Console/Commands/ # ifnex:preflight، import-fx-rates، smoke-test + ۶ دستور قدیمی
│ │ ├── Enums/ # ShipmentStatus، ShipmentDirection، ShipmentType، PaymentGateway، TransactionStatus
│ │ ├── Filament/ # ۱۹ Resource + Pages + Widgets
│ │ ├── Http/
│ │ │ ├── Controllers/Api/ # Track، Pricing، Auth، Bridge، Customer، Wallet، Payment، Staff، CommitmentForm، AddressBook
│ │ │ └── Middleware/ # ApiKeyMiddleware، StaffApiMiddleware، SetCspHeaders
│ │ ├── Models/ # ۳۱ مدل Eloquent
│ │ ├── Notifications/ # DB notifications + SMS
│ │ ├── Observers/ # ShipmentObserver
│ │ ├── Services/ # PriceCalculator، Pdf، Tracking، OrderPayment، Wallet، Zarinpal، KavenegarSms، DiscountCode، CustomerCredit، AddressBook
│ │ ├── Traits/ # Auditable
│ │ ├── Imports/ # OldShipments، ShippingRates
│ │ └── Exports/ # ShippingRatesTemplateExport
│ ├── database/
│ │ ├── migrations/ # ۶۲ migration
│ │ └── seeders/ # Countries، SystemSettings، Currency (جدید)، RoleAndPermission، DatabaseSeeder
│ ├── scripts/ # deploy.sh + cron-exir-rates.sh + one-off/
│ ├── resources/views/pdfs/ # awb، invoice، label، import-invoice
│ └── routes/api.php # ۵۰+ endpoint
│
├── AGENT.md # همین سند
├── CLIENT_DELIVERY.md # چکلیست وضعیت تحویل مشتری (منبع اصلی وضعیت)
├── UAT-3.11.md # چکلیست ۴۳ موردی UAT نهایی کارفرما (فاز ۳.۱۱)
├── RATE_IMPORTER.md # راهنمای ایمپورت نرخها (سیستم ۴-رُبعی)
├── DEPLOYMENT_HANDOFF.md # تحویل استقرار به تیم IT کارفرما
└── README.md # معرفی کلی پروژه
۴. مفاهیم کلیدی بیزینس
۴.۱ مرسوله (Shipment)
| مورد | مقدار |
|---|---|
انواع (Type) |
DOC_NORMAL، DOC_ECONOMY، PARCEL |
جهت (Direction) |
export (صادرات) و import (واردات) |
وضعیت (Status) |
pending_approval ← approved ← processed ← picked_up ← in_transit ← out_for_delivery ← delivered / failed / returned / cancelled (بههمراه pending_payment legacy و archived) |
هر مرسوله دارای چند بسته (packages)، اقلام گمرکی (items — فقط برای PARCEL)، تاریخچهٔ تغییرات وضعیت (statusHistories)، شرکتهای حمل (carrierMappings)، رویدادهای رهگیری (trackingEvents) و تعهدنامهها (commitmentForms) است.
۴.۲ بسته (Package)
- هر مرسوله میتواند چندین بسته داشته باشد (جدول
shipment_packages). - وزن حجمی =
(Length × Width × Height) / 5000(استاندارد IATA). - وزن قابل پرداخت =
max(وزن واقعی، وزن حجمی).
۴.۳ فاکتور گمرکی (Invoice)
- فقط برای مرسولههای نوع
PARCELصادر میشود. - حداکثر ۹ قلم کالا (شرح، HS Code، تعداد، قیمت واحد، مجموع به USD).
- مجموع کل فاکتور در
shipments.invoice_total_usdذخیره میشود. - فاکتور واردات (Import Invoice): فیلدهای brand_fee، report_fee، customs_clearance_cost، order_registration_fee و… بههمراه قالب PDF مطابق شیت ENG Invoice.
۴.۴ کیف پول (Wallet)
- هر کاربر یک کیف پول دارد.
- تراکنشها (
WalletTransaction) با نوعdeposit،order_payment،refund،withdrawalبهصورت polymorphic به Payment یا سفارش متصل هستند. - پرداخت از کیف پول یا درگاه Zarinpal (با Mock برای تست)، بههمراه freeze / unfreeze و activity log کامل.
۴.۵ احراز هویت Bridge
- کاربران وردپرس بدون نیاز به رمز عبور از طریق
POST /api/v1/bridge/loginبا ارسالbridge_api_keyوwp_user_idوارد لاراول میشوند. - پاسخ شامل توکن Sanctum (معتبر ۳۰ روز) و اطلاعات کاربر است.
- کلید
IFNEX_BRIDGE_API_KEYباید در هر دو طرف (.envلاراول و تنظیمات پلاگین وردپرس) یکسان باشد. - توکن در usermeta کاربر وردپرس (
ifnex_laravel_token) ذخیره میشود و روی ۴۰۱ خودکار باطل و تجدید میشود. - کلید
IFNEX_API_KEYکلید عمومی بخش رهگیری است وApiKeyMiddlewareآن را با!==مقایسه میکند؛ اگر خالی بماند، درخواست با توکن خالی از guard عبور میکند. - ⚠️
BridgeAuthControllerفقط مقدارchange-this-secret-keyرا رد میکند. این مقدار عمداً غیرکارکردی است تا جایگزینیاش فراموش نشود — هر مقدار دیگری، حتی مواردی که شبیه placeholder باشند، یک کلید معتبر محسوب میشود. - 🔐 هرگز کلید واقعی را در این فایل، در
RATE_IMPORTER.mdیا در04_Laravel/README.mdننویس. مقادیری که قبلاً در این مخزن ثبت شدهاند را لورفته فرض کن و چرخش بده.
۴.۶ رهگیری (Tracking)
- کاربر با شمارهٔ AWB جستجو میکند.
- سیستم رویدادهای رهگیری را از جدول
shipment_tracking_eventsبا فیلدsource(manual، api، import، system، customer) نمایش میدهد. - ایمپورت گروهی وضعیت ترکینگ با CSV از پنل (صفحهٔ BulkTrackingImport) انجام میشود.
۴.۷ قیمتگذاری (Pricing)
- بر اساس ۴ زون مجزا (Export/Import × Parcel/Doc) و ۳ نوع سرویس.
- فرمول: قیمت پایه (AED) × ضریب سود × نرخ تبدیل به ریال + هزینههای جانبی (Packing، Domestic Pickup، …) + مالیات بر ارزش افزوده (۹٪).
- محمولههای بالای ۳۰ کیلوگرم مشمول نرخ ویژه (Spot Rate) هستند و محاسبهٔ آنلاین ندارند.
۴.۸ فلوی تأیید سفارش (Approval Flow)
- مشتری بعد از ثبت سفارش مستقیم به درگاه نمیرود؛ سفارش با وضعیت
pending_approvalثبت میشود. - کارمند یا مدیر از پنل فیلمنت (اکشن تأیید در
ShipmentResource) یا از API (/staff/orders/{id}/approve|reject) تأیید میکند. - فقط پس از
approved، گزینههای پرداخت (کیف پول / درگاه) در وردپرس باز میشود. پرداخت موفق سفارش راprocessedمیکند (PaymentControllerدر callback باis_order_paymentدر metadata). - سفارشهای
approvedپرداختنشده روی مانده حساب کاربر (account_balanceدر پروفایل) اثر میگذارند.
۴.۹ تعهدنامه و اسناد سفارش (Commitment Forms)
- مدیر فرمهای تعهدنامه را در فیلمنت (
CommitmentFormResource) با direction (export / import / both) آپلود میکند. - مشتری در جزئیات سفارش وردپرس لیست تعهدنامهها را میبیند ← دانلود / چاپ / امضا ← آپلود فایل امضاشده (
POST /orders/{shipment}/commitment-forms/{form}/upload) که در جدولshipment_commitment_formsثبت میشود. - دانلود AWB، Invoice و Label نیز از همین بخش (
/orders/{shipment}/pdf/*) انجام میشود. - ✅ چک مالکیت اعمال شده:
ShipmentPolicy+ بررسیuser_idدر کنترلرهای PDF و تعهدنامه (کامیت8cf4075). - دانلود قالب تعهدنامه از route محافظتشده با auth (جایگزین asset عمومی) و دانلود ادمین از دیسک secure از طریق روتهای
admin.commitment-forms.*انجام میشود.
۴.۱۰ اعلانها و SMS کاوهنگار
- تنظیمات از
SystemSettingخوانده میشود (kavenegar_api_keyبههمراه سوییچ هر نوع پیام، مانندkavenegar_send_shipment_approved). - نوتیفیکیشنها:
ShipmentApprovedSms،ShipmentRejectedSms،PaymentSuccessSms،TrackingUpdatedSmsبههمراه کانالSmsChannel. - تریگر اصلی:
ShipmentObserver(روی تغییر وضعیت Shipment) وPaymentController(پرداخت موفق). تأیید موبایل:MobileVerificationController. - در
.envلوکال کلید کاوهنگار خالی است؛ تا وقتی تنظیم نشود SMS ارسال نمیشود (فقط DB notification).
۴.۱۱ اعتبار مشتری (Credit) — چندارزی
- سیستم کامل با
CustomerCreditService(متدهایgrantCredit()،settle()،getCustomerDebtsByCurrency()) و جدولهایcustomer_creditsوcredit_settlementsپیادهسازی شده است. - بدهی به همان ارز ثبت میشود و تسویه با نرخ روز انجام میگیرد. race condition در
settle()باlockForUpdate()و بررسی مجدد مانده اصلاح شد. - فقط
super_adminمجاز به اعطای اعتبار است (Policy).
۴.۱۲ Audit Log
- trait
App\Traits\Auditableروی مدلهای اصلی (User، Shipment، Wallet و…) اعمال شده و درAuditLogResourceقابل مشاهده است. ShipmentStatusHistoryدارای ستونهایfrom_status/to_status/reasonبههمراه نام کاربر تغییردهنده است.
۴.۱۳ معماری کیفپولمحور (Wallet-Centric Architecture)
سیستم مالی IFNEX بر مبنای کیف پول مشتری کار میکند. همه پرداختها از کیف پول عبور میکنند.
ساختار کیف پول:
- هر کاربر یک کیف پول دارد (
walletstable) - موجودی کیف پول به ریال (IRR) است
- تراکنشها در
wallet_transactionsثبت میشوند با نوعهای:deposit— شارژ کیف پول (از درگاه یا دستی توسط ادمین)withdrawal— برداشت/کسرorder_payment— پرداخت سفارشrefund— بازگشت وجهcredit_settlement— تسویه بدهی ارزی (با نرخ روز)invoice_payment— پرداخت فاکتور دستی
جریان پرداخت (همه از کیف پول میگذرند):
| سناریو | مسیر |
|---|---|
| شارژ کیف پول | درگاه Zarinpal → walletService->completeDeposit() → افزایش موجودی |
| پرداخت سفارش | OrderPaymentService->payFromWallet() → کسر از کیف پول + ثبت order_payment |
| پرداخت فاکتور دستی | ManualInvoiceService->payFromWallet() → کسر از کیف پول + ثبت invoice_payment |
| تسویه بدهی ارزی | CustomerCreditService->settle() (with $fromWallet=true) → کسر از کیف پول + ثبت credit_settlement |
مزایای این معماری:
- ✅ همه پرداختها در یک جدول (
wallet_transactions) ثبت میشوند — تاریخچه واحد - ✅ موجودی کیف پول منهای بدهیها = مانده حساب واقعی مشتری
- ✅ مدیر میتواند موجودی را بهصورت دستی تنظیم کند (
manualDeposit/manualWithdrawal) - ✅ قفل کیف پول (
freeze) در همه پرداختها اعمال میشود - ✅ Race condition با
lockForUpdate()در پرداختهای همزمان مدیریت میشود
ویژگیهای کلیدی مدل Wallet:
$wallet->balance // موجودی فعلی (ریال)
$wallet->isFrozen() // آیا مسدود است؟
$wallet->hasSufficientBalance($amount) // آیا موجودی کافی است؟
$wallet->freeze($reason, $admin) // مسدود کردن توسط ادمین
$wallet->unfreeze($admin) // رفع مسدودیت
قاعده طلایی:
هیچ پرداختی بدون عبور از کیف پول ثبت نمیشود. اگه در آینده درگاه جدیدی اضافه شود (مثلاً Stripe)، باید مبلغ ابتدا به کیف پول واریز شود (
deposit) و سپس از کیف پول کسر شود (order_payment/invoice_payment).
۴.۱۴ فاکتورهای دستی مدیر (Manual Invoices)
مدیر میتواند برای هر مشتری فاکتور صادر کند (خدمات خارج از سفارش). مشتری در پورتالش فاکتور را میبیند و از کیف پول پرداخت میکند.
- مدل:
ManualInvoice+ManualInvoiceService+CustomerInvoiceController - پنل ادمین:
ManualInvoiceResourceدر گروه «مالی» - پورتال وردپرس: تب «فاکتورهای دستی» با badge قرمز برای فاکتورهای pending
- شماره فاکتور:
INV-YYYY-NNNNNN(مثلاًINV-2026-000001) - وضعیتها:
pending_payment/paid/cancelled/expired - اعلان خودکار:
ManualInvoiceCreatedNotificationبه مشتری ارسال میشود - پرداخت: از کیف پول مشتری (کسر + ثبت تراکنش
invoice_payment)
۴.۱۵ نرخهای حمل و سیستم ۴-رُبعی
نرخهای حمل در جدول rate_entries بهصورت ۴-رُبعی ذخیره میشوند:
- جهت:
import/export - نوع سرویس:
document/parcel - وزن × زون: ماتریس
نگاشت زونها در country_zones (هر کشور میتواند زون متفاوت برای Doc و Parcel داشته باشد).
نکته مهم:
DOC_ECONOMYفعلاً به همان نرخDOC_NORMALمحاسبه میشود. برای تفکیک کامل، بایدservice_typeدرrate_entriesبه ۳ مقدار گسترش پیدا کند.
۵. دستورات روزمره
# نصب وابستگیها
composer install
# تنظیم محیط
cp .env.example .env
php artisan key:generate
# دیتابیس (ابتدا باید ایجاد شود)
php artisan migrate --force
php artisan db:seed --force
# اجرای سرور توسعه
php artisan serve
# اجرای صف (پردازشهای سنگین)
php artisan queue:work
# تستها
php artisan test
# پاکسازی و بازسازی کش
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan filament:clear-cached-components
# ایمپورت / اکسپورت نرخها
php artisan ifnex:import:rates {path}
php artisan ifnex:import:shipments {path}
php artisan ifnex:import:tracking {path}
# بهروزرسانی نرخ ارز (کرون) — فاز ۳.۱۰
# دستور جدید: USD/AED از Exir.io + EUR/CNY از FreeCurrencyAPI + auto-approve
php artisan ifnex:import-fx-rates --source=all --auto-approve
# دستور قدیمی ifnex:update-rates هنوز موجود است ولی فقط USD/AED را پشتیبانی میکند
# پیشاز-دیپلوی (fail-fast) — فاز ۳.۱۰
php artisan ifnex:preflight # بررسی سختسازی محیط قبل از migrate
php artisan ifnex:preflight --skip-db # قبل از migrate، currencies را چک نکن
# تست E2E Post-Deploy — فاز ۳.۱۱
php artisan ifnex:smoke-test # ۲۵+ بررسی: DB، دادهها، ۴ endpoint API
# تولید API Token برای ادمین
php artisan ifnex:token
۶. متغیرهای محیطی کلیدی (.env)
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:8000
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ifnex_db
DB_USERNAME=root
DB_PASSWORD=
# IFNEX اختصاصی — پیش از استقرار با رشتهٔ تصادفی جایگزین کن
# مقدار change-this-secret-key عمداً غیرکارکردی است تا جایگزینی فراموش نشود
IFNEX_API_KEY=change-this-secret-key
IFNEX_BRIDGE_API_KEY=change-this-secret-key # باید عیناً با وردپرس یکی باشد
IFNEX_TRACKING_RATE_LIMIT=60
# CORS (فقط دامنههای مجاز وردپرس)
CORS_ALLOWED_ORIGINS=http://localhost,http://127.0.0.1
# Zarinpal (برای تست از Mock استفاده کن)
ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing # اگر fake باشد، MockGateway فعال میشود
ZARINPAL_SANDBOX=true
ZARINPAL_CALLBACK_URL=http://localhost:8000/api/v1/payment/callback
ZARINPAL_FRONTEND_FAILURE_URL=http://localhost/IFNEX-Logistics/03_WordPress/wallet
# نکته: ZARINPAL_FRONTEND_SUCCESS_URL در کد خوانده نمیشود؛ ریدایرکت موفق
# از frontend_callback ارسالی وردپرس تعیین میشود.
# Kavenegar SMS (خالی = فقط DB notification)
KAVENEGAR_API_KEY=
KAVENEGAR_SENDER=10008566
# Wallet
WALLET_MIN_DEPOSIT=10000
WALLET_MAX_DEPOSIT=500000000
WALLET_AUTO_CREATE=true
۷. خط قرمزها (ممنوعیتهای مطلق)
| ❌ هرگز | ✅ همیشه |
|---|---|
| برگرداندن کشورها به ۲ زون | ۴ زون مجزا (Export/Import × Parcel/Doc) |
| استفاده از ۲ نوع سرویس | ۳ نوع (DOC_NORMAL، DOC_ECONOMY، PARCEL) |
| ذخیرهٔ تاریخ شمسی در DB | ذخیرهٔ timestamp میلادی + تبدیل در نمایش |
CORS * در Production |
CORS محدود به دامنهٔ وردپرس |
کامیت .env در Git |
قرار دادن .env در .gitignore |
APP_DEBUG=true در Production |
APP_DEBUG=false |
| PDF فارسی (AWB / Invoice / Label) | همیشه انگلیسی (برای حمل بینالمللی) |
| کپی از DHL | طراحی منحصر به فرد IFNEX |
استفاده از wire:click برای دانلود |
استفاده از <a href> با روت مستقیم |
getFormActions() در Custom Pages |
استفاده از wire:click در Blade |
هدایت AJAX به redirect() |
استفاده از payment_url در response JSON |
| متدهای نوتیفیکیشن بیرون از کلاس | داخل کلاس IFNEX_User_Bridge |
| روت staff/admin بدون چک نقش | چک نقش یا مالکیت در middleware یا ابتدای کنترلر |
| هدایت مستقیم سفارش به درگاه پس از ثبت | فلوی pending_approval ← approved ← پرداخت |
| ذخیره نرخها به AED/USD | ذخیره به IRR (تبدیل در ایمپورت) |
| نمایش قیمت به «درهم» در UI | نمایش به «ریال» |
| استفاده از «تومان» در کد/UI | فقط «ریال» |
| fallback عددی برای نرخ ارز | خطای واضح اگه نرخ تنظیم نشده |
تغییر customer_credits به IRR |
بدهی ارزی به ارز خارجی، تسویه با نرخ روز |
۸. نکات ویژه برای ایجنت
اصول کلی
- هنگام تولید کد جدید، حتماً از Enumها بهجای رشتههای سختکدشده استفاده کن.
- برای هر مدل جدید، migration، مدل و در صورت نیاز کنترلر یا Resource فیلمنت بساز.
- هنگام استفاده از هر Model در فایل جدید، حتماً
use App\Models\...را import کن. (باگ اخیر نبودِ import برایSystemSettingدرPaymentController/ShipmentObserver/TrackingService، فلوی تأیید و پرداخت را میشکست — کامیت2737e26). - مدیریت تاریخ همیشه با Carbon انجام میشود و ذخیره بهصورت
Y-m-d H:i:sدر DB است. - برای کوئریهای سنگین از
chunk()یاcursor()استفاده کن تا حافظه مصرف نشود.
خطاهای رایج
- نبودِ فیلد
deleted_atدر کوئریها (در صورت استفاده از SoftDeletes). - فراموشی
fillableیاcastsدر مدلها. - فراموشی
$withبرای بارگذاری روابط در Resourceها. - استفاده از
redirect()در کنترلرهای API (باید JSON برگردانند).
قواعد حوزهٔ کار
- برای تغییر وضعیت مرسوله، حتماً تاریخچه را بهروز کن (
ShipmentStatusHistoryباfrom_status/to_status/reason). - در فرم سفارش مشتری، مرحلهٔ Invoice فقط برای نوع PARCEL نمایش داده میشود.
- تولید PDF با بارکد بهصورت base64 embed انجام میشود.
- Bridge Auth نیازی به رمز عبور ندارد و فقط از
IFNEX_BRIDGE_API_KEYاستفاده میکند. - تست لوکال پرداخت: از
ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testingبرای فعالسازی Mock Gateway استفاده کن.
هشدارهای تاریخی
- مارکآپ شورتکدهای وردپرس: باز و بسته بودن
divها را متوازن نگه دار. باگ «مرحلهٔ ۲ فرم سفارش لود نمیشود» ریشهاش یکdivبستهنشده درshortcodes.phpبود که مراحل را داخل هم nest میکرد. هکهای MutationObserver و setInterval هیچکدام مشکل را حل نکردند و حذف شدند. - هکهای موقت دیباگ:
opcache_reset()وheader()در بالای فایلهای پلاگین و cache-buster باtime()فقط برای کار لوکال هستند و باید پیش از دیپلوی حذف شوند.
۹. کارهای باقیمانده
فاز ۳.۶ (اصلاحات جلسه کارفرما) — ✅ تکمیل (۲۰۲۶-۱۰-۰۴)
| # | کار | وضعیت |
|---|---|---|
| ۱ | تست انتهای فلوی سفارش: آپلود تعهدنامه ← تأیید کارمند ← پرداخت کیف پول یا درگاه | ✅ |
| ۲ | امنیت: چک نقش /staff/*، چک مالکیت PDF و تعهدنامه، محدودسازی discount-codes، rate limiting |
✅ |
| ۳ | بازطراحی سیستم اعتبار چندارزی + نمایش در پورتال مشتری + ویجت هشدار داشبورد | ✅ |
| ۴ | چکلیست خودکار کارمند پس از تأیید سفارش | ✅ (instantiateChecklist() در approve()) |
| ۶ | پاکسازی: فایلهای تستی، cache-busterها، !importantها |
✅ |
| ۷ | نمایش وزن واقعی و حجمی در خلاصهٔ قیمت وردپرس | ✅ (در API موجود است) |
فاز ۳.۷ (اصلاحات ارزی و فاکتور دستی) — ✅ تکمیل (۲۰۲۶-۱۰-۳۰)
| # | کار | وضعیت |
|---|---|---|
| ۱ | سیستم ۴-رُبعی نرخها (Export/Import × Doc/Parcel) با ایمپورت از اکسل | ✅ |
| ۲ | معماری IRR-only — ارز مبنا = ریال ایران، حذف جفتارز | ✅ |
| ۳ | ایمپورت فایل اکسل اصلی مشتری + قالب جدید IFNEX_Rate_Template.xlsx |
✅ |
| ۴ | حذف تمام «تومان» و «درهم» از نمایش قیمتهای داخلی | ✅ |
| ۵ | فاکتورهای دستی مدیر (صدور + پرداخت از کیف پول + اعلان خودکار) | ✅ |
| ۶ | تب «فاکتورهای دستی» در پورتال وردپرس (لیست + جزئیات + پرداخت) | ✅ |
| ۷ | اضافه شدن فاکتورها به وضعیت مالی و داشبورد مشتری | ✅ |
| ۸ | فرمت هزارگان در فیلدهای عددی فرم فاکتور ادمین | ✅ |
فاز ۳.۸ (کارهای سریع ظاهری) — ✅ تکمیل (۲۰۲۶-۱۰-۳۱)
| # | کار | وضعیت |
|---|---|---|
| ۱ | Favicon IFNEX (هواپیمای کاغذی کهربایی روی سرمهای — هماهنگ با هویت لاگین) در public/favicon.ico + public/images/favicon.svg + apple-touch-icon + icon-192/512 + site.webmanifest + لینک در filament/hooks/head |
✅ |
| ۲ | صفحهٔ / برندشده (RTL، وزیرمتن، کارتهای «پنل مدیریت / استعلام نرخ / ثبت سفارش»، چیپهای وضعیت سیستم) جایگزین welcome پیشفرض |
✅ |
| ۳ | جمعکردن کارت لاگین فیلمنت (max-width ۴۴۰←۳۸۰px، padding ۲.۵rem←۱.۷۵rem، فاصلههای فشرده) | ✅ |
| ۴ | SweetAlert2 (v11.14.5 باندل محلی در پلاگین bridge) برای خطاهای فرم سفارش: اعتبارسنجی مراحل، خطای ثبت، خطای ارتباط + جایگزینی هر ۳ alert() بومی با پاپآپ برند |
✅ |
| ۵ | سازگارسازی migration فاکتور دستی با SQLite (تستها طبق همین سند با SQLite اجرا میشوند) | ✅ |
فاز ۳.۹ (دفترچه آدرس) — ✅ تکمیل (۲۰۲۶-۱۱-۰۱)
| # | کار | وضعیت |
|---|---|---|
| ۱ | مایگریشن + مدل AddressBookEntry (سقف ۵۰ رکورد، upsert ضدتکرار، آمار استفاده) |
✅ |
| ۲ | CRUD API /api/v1/addresses + default-set (Sanctum + Ownership) |
✅ |
| ۳ | اتصال به POST /customer/orders (save flags + address_id usage) |
✅ |
| ۴ | dropdown آدرس ذخیرهشده + چکباکس «ذخیره این آدرس» در فرم سفارش وردپرس | ✅ |
| ۵ | تب «دفترچه آدرس» در پنل کاربری (کارتها + فیلتر + فرم + حذف/پیشفرض) | ✅ |
| ۶ | ۴ پروکسی AJAX جدید با nonce/sanitize | ✅ |
| ۷ | ۱۸ تست Feature جدید | ✅ |
فاز ۳.۱۰ و ۳.۱۱ — ✅ تکمیل شد
فاز ۳.۱۰ (استقرار Production) و فاز ۳.۱۱ (UAT نهایی) تکمیل شدند. سیستم آمادهٔ دیپلوی روی سرور Production است.
باقیماندهٔ واقعی (post-3.11)
| # | کار | وضعیت | اولویت |
|---|---|---|---|
| ۱ | دیپلوی روی سرور Production (pull + bash scripts/deploy.sh + ifnex:smoke-test) |
⏳ قدم بعدی | بالا |
| ۲ | UAT نهایی کارفرما — چکلیست ۴۳ موردی UAT-3.11.md + فرم امضا |
⏳ بعد از دیپلوی | بالا |
| ۳ | چندزبانه (i18n) | ⏳ موکول به زمان دیپلوی | متوسط |
| ۴ | سند پیشنهادی سیستم مالی (درخواست ۱۳ کارفرما) | ⏳ موکول به آینده | پایین |
| ۵ | پلاگین SMS (بهصورت ماژول قابل فعالسازی) | ⏳ منتظر پنل SMS مشتری | متوسط |
| ۶ | لاین واردات از چین (ماژول مجزا) | ⏳ مطالعاتاتی | پایین |
| ۷ | ارز مرجع قابل تنظیم (نسخه Pro) | 📋 مطرحشده — 01_Documents/IFNEX_Pro_Backlog.md |
پایین (نسخه Pro) |
| ۸ | سیستم بروزرسانی + لایسنس (Domain Lock) | 📋 مطرحشده — 01_Documents/IFNEX_Pro_Backlog.md |
پایین (نسخه Pro) |
۱۰. مستندات مرجع
| فایل | محتوا |
|---|---|
CLIENT_DELIVERY.md |
چکلیست وضعیت تحویل مشتری (منبع اصلی وضعیت) |
UAT-3.11.md |
چکلیست ۴۳ موردی UAT نهایی کارفرما (فاز ۳.۱۱) + فرم امضا |
DEPLOYMENT_HANDOFF.md |
راهنمای استقرار برای تیم IT کارفرما |
RATE_IMPORTER.md |
راهنمای ایمپورت نرخها (سیستم ۴-رُبعی) |
04_Laravel/README.md |
راهنمای بکاند |
01_Documents/IFNEX_Roadmap.md |
نقشهٔ راه فازی (۰ تا ۳.۱۱ + آینده ۴/۵) |
01_Documents/IFNEX_File_Map.md |
نقشهٔ فایلهای پروژه |
01_Documents/IFNEX_Pro_Backlog.md |
فیچرهای نسخه Pro (ارز مرجع قابل تنظیم، لایسنس، آپدیت) |
01_Documents/IFNEX_Commercial_Model.md |
مدل تجاری و پلنهای فروش (آینده — فاز ۵) |
01_Documents/IFNEX_ADR.md |
تصمیمات معماری (ADR-001 تا 009) |
01_Documents/IFNEX_I18N_Strategy.md |
استراتژی چندزبانه (موکول به زمان دیپلوی) |
01_Documents/DESIGN_SYSTEM.md |
رنگها، تایپوگرافی، فاصلهگذاری |
01_Documents/EXCEL_ANALYSIS.md |
تحلیل کامل فایلهای اکسل (۳۹۵۰ رکورد، فرمولها، زونها) |