Introduce a comprehensive address management system allowing users to
save, manage, and reuse sender and receiver addresses during the
ordering process. This feature bridges the WordPress frontend with the
Laravel backend API.
Key changes:
- Backend (Laravel):
- Added `AddressBookEntry` model and migration for storing addresses
with role (sender/receiver), usage tracking, and default status.
- Implemented `AddressBookController` with full CRUD functionality
secured via Sanctum and ownership validation.
- Integrated address usage tracking and upsert logic into the
`CustomerOrderController` to prevent duplicate entries.
- Added 18 new feature tests covering ownership, limits, and
validation.
- Frontend (WordPress):
- Added a new "Address Book" tab in the user dashboard with card-based
UI, filtering, and SweetAlert2 integration.
- Enhanced the order form with dropdown selectors for saved addresses
and "save this address" checkboxes for both sender and receiver.
- Implemented secure AJAX proxies in `user-bridge.php` with nonce
and sanitization.
- Documentation:
- Updated `AGENT.md` and `CLIENT_DELIVERY.md` to reflect phase 3.9
completion and updated the project roadmap.
- Removed obsolete `README-INSTALL.md`.
41 KiB
راهنمای ایجنت — پروژهٔ IFNEX Logistics
تاریخ: ۲۰۲۶-۱۰-۳۱ نسخه: ۱.۵ تهیهکننده: VernaSoft Group — Kazem Alghasi
۱. خلاصهٔ پروژه
سیستم مدیریت لجستیک بینالمللی با معماری Headless: Laravel 11 بهعنوان بکاند، WordPress بهعنوان فرانتاند و Filament 3.3 بهعنوان پنل مدیریت. این سیستم جایگزین فرآیندهای دستی مبتنی بر اکسل شده و از Multi-Package، فاکتور گمرکی، کیف پول دیجیتال، درگاه پرداخت Zarinpal، تولید PDF با بارکد، فلوی تأیید سفارش، تعهدنامه، SMS کاوهنگار، سیستم اعتبار چندارزی، رهگیری پیشرفته، سیستم ۴-رُبعی نرخها و فاکتورهای دستی مدیر پشتیبانی میکند.
وضعیت فعلی
فازهای ۰، ۱، ۲، ۳، ۳.۵، ۳.۶ و ۳.۷ تکمیل شدهاند. فاز ۳.۷ (اصلاحات ارزی و فاکتور دستی) تکمیل شد:
- فلوی کامل سفارش (ثبت ← تأیید ← تعهدنامه ← پرداخت) — تست 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) همچنان به زمان دیپلوی موکول است.
معماری ارزی (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_Phase0_Checklist.md # چکلیست تکمیل فازها
│ ├── IFNEX_ADR.md # تصمیمات معماری (ADR-001 تا 009)
│ ├── EXCEL_ANALYSIS.md # تحلیل دادههای تاریخی
│ ├── IFNEX_I18N_Strategy.md # استراتژی چندزبانه
│ └── IFNEX_Commercial_Model.md # مدل تجاری
│
├── 03_WordPress/ # فرانتاند وردپرس
│ └── wp-content/
│ ├── themes/ifnex/ # قالب سفارشی
│ └── plugins/ifnex-bridge/ # پلاگین ارتباط با لاراول
│ ├── includes/ # api-client، user-bridge، shortcodes، tracking-form
│ └── assets/ # CSS و JS فرم سفارش
│
├── 04_Laravel/ # بکاند لاراول (هستهٔ اصلی)
│ ├── app/
│ │ ├── Enums/ # ShipmentStatus، ShipmentDirection، ShipmentType، PaymentGateway، TransactionStatus
│ │ ├── Filament/ # ۱۷ Resource + Pages + Widgets
│ │ ├── Http/
│ │ │ ├── Controllers/Api/ # Track، Pricing، Auth، Bridge، Customer، Wallet، Payment، Staff، CommitmentForm
│ │ │ └── Middleware/ # ApiKeyMiddleware
│ │ ├── Models/ # ۲۶ مدل Eloquent
│ │ ├── Notifications/ # DB notifications + SMS
│ │ ├── Observers/ # ShipmentObserver
│ │ ├── Services/ # PriceCalculator، Pdf، Tracking، OrderPayment، Wallet، Zarinpal، KavenegarSms
│ │ ├── Traits/ # Auditable
│ │ ├── Imports/ # OldShipments، ShippingRates
│ │ └── Exports/ # ShippingRatesTemplateExport
│ ├── database/migrations/ # ۵۲ migration
│ ├── resources/views/pdfs/ # awb، invoice، label، import-invoice
│ └── routes/api.php # ۴۰+ endpoint
│
├── AGENT.md # همین سند
├── CLIENT_DELIVERY.md # چکلیست وضعیت تحویل مشتری (منبع اصلی)
├── DEPLOYMENT.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 باشند، یک کلید معتبر محسوب میشود. - 🔐 هرگز کلید واقعی را در این فایل، در
DEPLOYMENT.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}
# بهروزرسانی نرخ ارز (کرون)
php artisan ifnex:update-rates --source=ecb
# تولید 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 + کارهای موکولشده به آینده
| # | کار | وضعیت | اولویت |
|---|---|---|---|
| ۱ | دیپلوی روی سرور Production (pull + migrate + .env سرور + ایمپورت نرخ واقعی + E2E) | ⏳ قدم بعدی | بالا |
| ۲ | چندزبانه (i18n) | ⏳ موکول به زمان دیپلوی | متوسط |
| ۳ | سند پیشنهادی سیستم مالی (درخواست ۱۳ کارفرما) | ⏳ موکول به آینده | پایین |
| ۴ | پلاگین SMS (بهصورت ماژول قابل فعالسازی) | ⏳ منتظر پنل SMS مشتری | متوسط |
| ۵ | لاین واردات از چین (ماژول مجزا) | ⏳ مطالعاتاتی | پایین |
| ۶ | ارز مرجع قابل تنظیم (نسخه Pro) | 📋 مطرحشده — 01_Documents/IFNEX_Pro_Backlog.md |
پایین (نسخه Pro) |
| ۷ | سیستم بروزرسانی + لایسنس (Domain Lock) | 📋 مطرحشده — 01_Documents/IFNEX_Pro_Backlog.md |
پایین (نسخه Pro) |
۱۰. مستندات مرجع
| فایل | محتوا |
|---|---|
01_Documents/EXCEL_ANALYSIS.md |
تحلیل کامل فایلهای اکسل (۳۹۵۰ رکورد، فرمولها، زونها) |
01_Documents/IFNEX_Phase0_Checklist.md |
چکلیست کامل فازها (۰ تا ۳.۵) |
01_Documents/IFNEX_Roadmap.md |
نقشهٔ راه فازی (تا فاز ۳.۶) |
01_Documents/IFNEX_File_Map.md |
نقشهٔ ۱۰۰+ فایل پروژه |
01_Documents/IFNEX_I18N_Strategy.md |
استراتژی چندزبانه (برای زمان دیپلوی) |
01_Documents/IFNEX_Commercial_Model.md |
مدل تجاری و پلنهای فروش |
01_Documents/IFNEX_Pro_Backlog.md |
فیچرهای نسخه Pro (ارز مرجع قابل تنظیم، لایسنس، آپدیت) |
01_Documents/DESIGN_SYSTEM.md |
رنگها، تایپوگرافی، فاصلهگذاری |
DEPLOYMENT.md |
راهنمای ایمپورت نرخها (سیستم ۴-رُبعی) |
DEPLOYMENT_HANDOFF.md |
تحویل استقرار به تیم IT کارفرما |
04_Laravel/README.md |
راهنمای بکاند |
CLIENT_DELIVERY.md |
چکلیست وضعیت تحویل مشتری (منبع اصلی وضعیت تحویل) |