refactor(shipment): update direction enums and shipment import logic

Refactor the shipment direction logic from 'outbound/inbound' to 'export/import' to align with the new database schema requirements. This includes updating the `ShippingRatesImport` logic, adjusting the Excel import sheet mappings, and removing the AED to IRR conversion during import as rates are now stored in AED.

Additionally, updated the shipment view action to open PDF documents in a new tab and updated the Phase 0 checklist with the new database schema requirements.

- docs: update Phase 0 checklist with new schema requirements
- refactor(ui): update shipment view actions to open in new tab
- refactor(import): update shipping rates import to use new direction enums and AED values
- docs: add file map and new excel document
This commit is contained in:
Kazem Alghasi 2026-08-23 21:33:56 +03:30
parent 11b524cf43
commit 48c88e9bc7
5 changed files with 607 additions and 213 deletions

Binary file not shown.

View File

@ -0,0 +1,202 @@
# 📂 نقشه فایل‌های فاز ۰ — IFNEX Laravel
> هر فایل را از پوشه `IFNEX_Laravel_Phase0/` در ریشه‌ی پروژه Laravel (مثلاً `04_Laravel/`) کپی کنید.
---
## ۱. Migrations (۸ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `database/migrations/2026_08_02_000001_create_countries_table.php` |
| 2 | `database/migrations/2026_08_02_000002_create_shipments_table.php` |
| 3 | `database/migrations/2026_08_02_000003_create_shipment_carrier_mappings_table.php` |
| 4 | `database/migrations/2026_08_02_000004_create_shipment_tracking_events_table.php` |
| 5 | `database/migrations/2026_08_02_000005_create_shipment_items_table.php` |
| 6 | `database/migrations/2026_08_02_000006_create_shipping_rates_table.php` |
| 7 | `database/migrations/2026_08_02_000007_create_system_settings_table.php` |
| 8 | `database/migrations/2026_08_02_000008_create_users_table.php` |
---
## ۲. Models (۸ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Models/Country.php` |
| 2 | `app/Models/Shipment.php` |
| 3 | `app/Models/ShipmentCarrierMapping.php` |
| 4 | `app/Models/ShipmentTrackingEvent.php` |
| 5 | `app/Models/ShipmentItem.php` |
| 6 | `app/Models/ShippingRate.php` |
| 7 | `app/Models/SystemSetting.php` |
| 8 | `app/Models/User.php` |
---
## ۳. Seeders (۳ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `database/seeders/DatabaseSeeder.php` |
| 2 | `database/seeders/CountriesTableSeeder.php` |
| 3 | `database/seeders/SystemSettingSeeder.php` |
---
## ۴. Fil> Filament Resources (۱۲ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Filament/Resources/CountryResource.php` |
| 2 | `app/Filament/Resources/CountryResource/Pages/ListCountries.php` |
| 3 | `app/Filament/Resources/CountryResource/Pages/CreateCountry.php` |
| 4 | `app/Filament/Resources/CountryResource/Pages/EditCountry.php` |
| 5 | `app/Filament/Resources/ShipmentResource.php` |
| 6 | `app/Filament/Resources/ShipmentResource/Pages/ListShipments.php` |
| 7 | `app/Filament/Resources/ShipmentResource/Pages/CreateShipment.php` |
| 8 | `app/Filament/Resources/ShipmentResource/Pages/ViewShipment.php` |
| 9 | `app/Filament/Resources/ShipmentResource/Pages/EditShipment.php` |
| 10 | `app/Filament/Resources/ShipmentResource/RelationManagers/CarrierMappingsRelationManager.php` |
| 11 | `app/Filament/Resources/ShipmentResource/RelationManagers/TrackingEventsRelationManager.php` |
| 12 | `app/Filament/Resources/ShipmentResource/RelationManagers/ItemsRelationManager.php` |
| 13 | `app/Filament/Resources/ShippingRateResource.php` |
| 14 | `app/Filament/Resources/ShippingRateResource/Pages/ListShippingRates.php` |
| 15 | `app/Filament/Resources/ShippingRateResource/Pages/CreateShippingRate.php` |
| 16 | `app/Filament/Resources/ShippingRateResource/Pages/EditShippingRate.php` |
---
## ۵. Filament Pages + Widget (۳ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Filament/Pages/SettingsPage.php` |
| 2 | `app/Filament/Pages/PriceTestPage.php` |
| 3 | `app/Filament/Widgets/ShipmentStatsWidget.php` |
---
## ۶. Filament Blade Views (۲ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `resources/views/filament/pages/settings-page.blade.php` |
| 2 | `resources/views/filament/pages/price-test-page.blade.php` |
---
## ۷. Services (۲ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Services/PriceCalculatorService.php` |
| 2 | `app/Services/TrackingService.php` |
---
## ۸. Controllers (۲ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Http/Controllers/Api/PricingController.php` |
| 2 | `app/Http/Controllers/Api/TrackController.php` |
---
## ۹. Middleware (۱ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Http/Middleware/ApiKeyAuth.php` |
---
## ۱۰. Form Requests (۲ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Http/Requests/Api/CalculatePriceRequest.php` |
| 2 | `app/Http/Requests/Api/TrackShipmentRequest.php` |
---
## ۱۱. Imports (۳ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Imports/OldShipmentsImport.php` |
| 2 | `app/Imports/ShippingRatesImport.php` |
| 3 | `app/Imports/ShippingRatesMultiSheetImport.php` |
---
## ۱۲. Provider (۱ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `app/Providers/AdminPanelProvider.php` |
> ⚠️ **مهم:** این فایل را در `bootstrap/providers.php` هم ثبت کنید:
> ```php
> return [
> App\Providers\AdminPanelProvider::class,
> ];
> ```
---
## ۱۳. Config (۲ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `config/ifnex.php` |
| 2 | `config/cors.php` |
---
## ۱۴. Routes (۱ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `routes/api.php` |
---
## ۱۵. Bootstrap (۱ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `bootstrap/app.php` |
---
## ۱۶. Environment (۱ فایل)
| # | آدرس مقصد در پروژه Laravel |
|---|---|
| 1 | `.env.example` |
---
## ⚠️ فایل‌هایی که باید حذف شوند (قدیمی)
| # | آدرس | دلیل |
|---|---|---|
| 1 | `01_Documents/PRD_v2.md` | قدیمی — فقط ۲ زون و ۲ نوع سرویس |
| 2 | `01_Documents/Project_Roadmap.md` | قدیمی — نقشه راه ۳ فازی (الان ۴ فازی) |
---
## ⚠️ فایل‌هایی که باید دستی اصلاح شوند
| # | فایل | تغییر |
|---|---|---|
| 1 | `composer.json` | `"laravel/framework": "^12.0"``"^11.0"` |
| 2 | `composer.json` | اضافه کردن `"morilog/jalali": "^5.*"` |
| 3 | `bootstrap/providers.php` | اضافه کردن `App\Providers\AdminPanelProvider::class` |
| 4 | فونت Vazirmatn | نصب: `npm install @fontsource/vazirmatn` یا CDN |
---
> مجموع: **۵۶ فایل** قابل دانلود + **۴ تغییر دستی**

View File

@ -1,257 +1,450 @@
# ✅ IFNEX Phase 0 Checklist # ✅ چک‌لیست فاز ۰IFNEX Phase 0 Checklist
> **فاز:** Phase 0 — بنیان داده + ترکینگ دستی + مهاجرت داده‌های تاریخی > **مرجع:** Phase0_Proposal.docx + EXCEL_ANALYSIS.md + STATUS.md
> **تاریخ ایجاد:** 2026-08-04 > **تاریخ:** August 2026
> **تاریخ به‌روزرسانی:** 2026-08-10 > **وضعیت:** در دست اقدام
> **وضعیت کلی:** ✅ تکمیل شده > **توسعه‌دهنده:** VernaSoft Group — Kazem Alghasi
> **مرجع اصلی:** `01_Documents/Phase0_Proposal.md`
--- ---
## پیش‌نیازها ## 🔴 بخش ۱: اصلاح اسکیمای دیتابیس (حیاتی — قبل از هر چیز)
| # | شرط | وضعیت | توضیحات | ### 1.1 بازنویسی Migration `countries`
|---|------|-------|---------| - [ ] حذف `export_zone` و `import_zone` (۲ زون قدیمی)
| P1 | Laravel 11 نصب و قابل اجرا | ✅ انجام شد | در پوشه `04_Laravel` | - [ ] اضافه کردن `export_zone_parcel` (TINYINT 1-10)
| P2 | MySQL 8+ قابل دسترس | ✅ انجام شد | دیتابیس `ifnex_db` ایجاد شده | - [ ] اضافه کردن `export_zone_doc` (TINYINT 1-10)
| P3 | Composer dependencies نصب شده | ✅ انجام شد | filament 3.3.x, maatwebsite/excel, morilog/jalali 3 | - [ ] اضافه کردن `import_zone_parcel` (TINYINT 1-10)
| P4 | فایل‌های اکسل اصلی در دسترس | ⚠️ موجود | فایل مرسولات فعلی داده‌های نمونه/قدیمی دارد — هر فایل جدید قابل import است | - [ ] اضافه کردن `import_zone_doc` (TINYINT 1-10)
- [ ] اضافه کردن `iso_code` (CHAR(2) UNIQUE)
- [ ] اضافه کردن `is_active` (BOOLEAN default true)
- [ ] اصلاح `name` — بدون کد ISO در پرانتز (مثلاً `Afghanistan` نه `Afghanistan (AF)`)
### 1.2 بازنویسی Migration `shipments`
- [ ] حذف `forwarder_track_id` (جایگزین با جدول مجزا)
- [ ] تغییر `type` از STRING به ENUM: `DOC_NORMAL`, `DOC_ECONOMY`, `PARCEL`
- [ ] تغییر `direction` از STRING به ENUM: `import`, `export` (نه Outbound/Inbound)
- [ ] تغییر `status` از STRING به ENUM (وضعیت‌های استاندارد)
- [ ] اضافه کردن `from_country_id` (FK → countries.id)
- [ ] اضافه کردن `to_country_id` (FK → countries.id)
- [ ] اضافه کردن فیلدهای مالی غایب:
- [ ] `domestic_pickup` (DECIMAL 12,2 default 0)
- [ ] `domestic_delivery` (DECIMAL 12,2 default 0)
- [ ] `warehousing_cost` (DECIMAL 12,2 default 0)
- [ ] `vat_amount` (DECIMAL 12,2 default 0)
- [ ] تبدیل فیلدهای غیرضروری فاز ۰ به `nullable`:
- [ ] `weight`, `volumetric_weight`, `chargeable_weight`, `dimensions`
- [ ] `reason_for_export`, `forwarder`
- [ ] تمام فیلدهای مالی (shipping_price, extra_service, packing_cost, discount, total_fee, net_dirham, net_rial)
- [ ] sender_company, sender_id_number, receiver_company, receiver_id_number
- [ ] حذف `user_id` از فاز ۰ (مشتریان در فاز ۲ اضافه می‌شوند) یا nullable کردن
### 1.3 ایجاد Migration `shipment_carrier_mappings` (جدول جدید)
- [ ] `id` (BIGINT PK)
- [ ] `shipment_id` (FK → shipments.id, cascadeOnDelete)
- [ ] `carrier_code` (ENUM: DHL, FEDEX, UPS, ARAMEX, NAGHEL, EMX, APSITEX, IMPEX, OTHER)
- [ ] `carrier_tracking_number` (VARCHAR 50)
- [ ] `booking_number` (VARCHAR 50 NULL)
- [ ] `direction` (ENUM: import, export)
- [ ] `delivery_status` (ENUM NULL)
- [ ] `last_synced_at` (TIMESTAMP NULL — برای فاز ۳)
- [ ] `manually_updated_at` (TIMESTAMP NULL)
- [ ] `notes` (TEXT NULL — مثلاً 100AED disposal charge)
- [ ] `created_at`, `updated_at`
### 1.4 ایجاد Migration `shipment_tracking_events` (جدول جدید)
- [ ] `id` (BIGINT PK)
- [ ] `shipment_id` (FK → shipments.id, cascadeOnDelete)
- [ ] `event_date` (DATE)
- [ ] `event_time` (TIME)
- [ ] `location` (VARCHAR 200 NULL — مثلاً DUBAI, MUSCAT)
- [ ] `event_description` (VARCHAR 500 — مثلاً Picked up by Naqel)
- [ ] `delivery_status` (ENUM NULL — اگر رویداد مرتبط با تحویل باشد)
- [ ] `source` (ENUM: manual, api_carrier, api_aggregator — فاز ۰: فقط manual)
- [ ] `carrier_mapping_id` (FK NULL — برای فاز ۳)
- [ ] `raw_payload` (JSON NULL — برای فاز ۳)
- [ ] `created_at`
### 1.5 بازنویسی Migration `system_settings`
- [ ] تغییر از ساختار ستونی به ساختار key-value:
- [ ] `key` (VARCHAR 100 UNIQUE)
- [ ] `value` (DECIMAL 15,4)
- [ ] `description` (VARCHAR 255)
- [ ] `updated_by` (FK → users.id)
- [ ] `updated_at`
### 1.6 بازنویسی Migration `users`
- [ ] اضافه کردن `phone` (VARCHAR 20 NULL)
- [ ] اضافه کردن `role` (ENUM: super_admin, tracking_operator, data_entry, customer)
- [ ] اضافه کردن `is_active` (BOOLEAN default true)
### 1.7 اصلاح Migration `shipping_rates`
- [ ] تغییر `type` از STRING به ENUM: `DOC_NORMAL`, `DOC_ECONOMY`, `PARCEL`
- [ ] تغییر `direction` از STRING به ENUM: `import`, `export`
--- ---
## بخش ۱: دیتابیس و مدل‌ها ## 🟡 بخش ۲: اصلاح و ایجاد Model ها
| # | کار | وضعیت | توضیحات | ### 2.1 بازنویسی `Country.php`
|---|-----|-------|---------| - [ ] اضافه کردن fillable: `iso_code`, `export_zone_parcel`, `export_zone_doc`, `import_zone_parcel`, `import_zone_doc`, `is_active`
| 1.1 | Migration `countries` با ۴ زون | ✅ انجام شد | iso_code + is_active اضافه شد | - [ ] حذف `export_zone`, `import_zone` از fillable
| 1.2 | Migration `shipments` مطابق Phase 0 | ✅ انجام شد | ۱۱ فیلد مالی + ۴ زون + nullable حقایل | - [ ] اضافه کردن `casts` برای `is_active` → boolean
| 1.3 | Migration `shipping_rates` با enum | ✅ انجام شد | direction + type (DOC_NORMAL/DOC_ECONOMY/PARCEL) |
| 1.4 | Migration `shipment_carrier_mappings` | ✅ انجام شد | جدول جدید برای نگاشت چند شرکت حمل |
| 1.5 | Migration `shipment_tracking_events` | ✅ انجام شد | جدول جدید برای تایم‌لاین رویدادها |
| 1.6 | Migration `system_settings` | ✅ انجام شد | جدول key-value |
| 1.7 | Migration `update_users` | ✅ انجام شد | phone, role, is_active |
| 1.8 | حل مشکل `unsignedDecimal` | ✅ انجام شد | استفاده از `decimal()->unsigned()` |
| 1.9 | حل مشکل FK constraints | ✅ انجام شد | `disableForeignKeyConstraints()` |
| 1.10 | اجرای همه migrations | ✅ انجام شد | بدون خطا |
### مدل‌ها و Enums ### 2.2 بازنویسی `Shipment.php`
- [ ] اضافه کردن `direction` cast → enum
- [ ] اضافه کردن `type` cast → enum
- [ ] اضافه کردن `status` cast → enum
- [ ] اضافه کردن fillable: `from_country_id`, `to_country_id`, `domestic_pickup`, `domestic_delivery`, `warehousing_cost`, `vat_amount`
- [ ] حذف `forwarder_track_id` از fillable
- [ ] اضافه کردن رابطه `carrierMappings()` (HasMany)
- [ ] اضافه کردن رابطه `trackingEvents()` (HasMany)
- [ ] اضافه کردن رابطه `fromCountry()` (BelongsTo)
- [ ] اضافه کردن رابطه `toCountry()` (BelongsTo)
| # | کار | وضعیت | توضیحات | ### 2.3 ایجاد `ShipmentCarrierMapping.php`
|---|-----|-------|---------| - [ ] fillable: تمام فیلدهای جدول
| 2.1 | مدل `Country.php` + روابط | ✅ انجام شد | fromShipments() + toShipments() | - [ ] casts: `direction` → enum, `last_synced_at` → datetime
| 2.2 | مدل `Shipment.php` + روالات کامل | ✅ انجام شد | items(), carrierMappings(), trackingEvents() | - [ ] رابطه `shipment()` (BelongsTo)
| 2.3 | مدل `ShippingRate.php` | ✅ انجام شد | cast برای enums |
| 2.4 | مدل `User.php` + helper methods | ✅ انجام شد | phone, role, is_active | ### 2.4 ایجاد `ShipmentTrackingEvent.php`
| 2.5 | مدل `ShipmentCarrierMapping.php` | ✅ انجام شد | | - [ ] fillable: تمام فیلدهای جدول
| 2.6 | مدل `ShipmentTrackingEvent.php` | ✅ انجام شد | | - [ ] casts: `event_date` → date, `event_time` → datetime, `source` → enum
| 2.7 | مدل `SystemSetting.php` | ✅ انجام شد | | - [ ] رابطه `shipment()` (BelongsTo)
| 2.8 | Enum `ShipmentDirection` | ✅ انجام شد | import/export |
| 2.9 | Enum `ShipmentType` | ✅ انجام شد | DOC_NORMAL/DOC_ECONOMY/PARCEL | ### 2.5 بازنویسی `SystemSetting.php`
| 2.10 | Enum `ShipmentStatus` | ✅ انجام شد | ۹ وضعیت (pending_payment, cancelled اضافه شد) | - [ ] تغییر به ساختار key-value
| 2.11 | Enum `CarrierCode` | ✅ انجام شد | ۹ شرکت حمل | - [ ] اضافه کردن متد `get($key)` — استخراج مقدار با کلید
| 2.12 | Enum `TrackingSource` | ✅ انجام شد | manual/api_carrier/api_aggregator | - [ ] اضافه کردن متد `set($key, $value)` — تنظیم مقدار
| 2.13 | Enum `UserRole` | ✅ انجام شد | ۴ نقش | - [ ] اضافه کردن رابطه `updatedBy()` (BelongsTo)
### 2.6 بازنویسی `User.php`
- [ ] اضافه کردن fillable: `phone`, `role`, `is_active`
- [ ] اضافه کردن casts: `is_active` → boolean
- [ ] اضافه کردن متد `isSuperAdmin()`, `isTrackingOperator()`, `isDataEntry()`
### 2.7 بازنویسی `ShippingRate.php`
- [ ] تغییر `type` به enum: `DOC_NORMAL`, `DOC_ECONOMY`, `PARCEL`
- [ ] تغییر `direction` به enum: `import`, `export`
--- ---
## بخش ۲: Seeders و داده‌های اولیه ## 🟡 بخش ۳: Seeders
| # | کار | وضعیت | توضیحات | ### 3.1 بازنویسی `CountriesTableSeeder.php`
|---|-----|-------|---------| - [ ] استخراج نام کشور و iso_code از فرمت `Afghanistan (AF)`
| 3.1 | Seeder ۲۳۲ کشور با ۴ زون | ✅ انجام شد | تصحیح کدهای ISO، حذف تکراری‌ها | - [ ] تنظیم ۴ زون مجزا (از شیت Zone اکسل):
| 3.2 | Seeder System Settings | ✅ انجام شد | VAT 9%, packing 100000 IRR, profit_margin 1.25 | - [ ] `export_zone_parcel` — از ستون PARCEL شیت Zone
| 3.3 | Seeder Super Admin User | ✅ انجام شد | | - [ ] `export_zone_doc` — از ستون DOCUMENT شیت Zone
| 3.4 | DatabaseSeeder ترکیبی | ✅ انجام شد | | - [ ] `import_zone_parcel` — از شیت COUNTRIES ستون IMPORT ZONES
- [ ] `import_zone_doc` — از شیت COUNTRIES (نیاز به تأیید مشتری)
- [ ] ایران (IR) را بدون زون تنظیم (مبدا/مقصد داخلی)
- [ ] تنظیم `is_active = true` برای همه
### 3.2 بازنویسی `SystemSettingSeeder.php`
- [ ] ساختار key-value:
- [ ] `('vat_rate', 0.09, 'VAT rate — 9%')`
- [ ] `('packing_cost_default', 100000, 'Default packing cost in IRR')`
- [ ] `('profit_margin', 1.25, 'Profit margin — set per company')`
- [ ] `('aed_to_irr', 455000, 'AED to IRR exchange rate')`
- [ ] `('usd_to_irr', 0, 'USD to IRR exchange rate')`
- [ ] `('cny_to_irr', 0, 'CNY to IRR exchange rate')`
- [ ] `('eur_to_irr', 0, 'EUR to IRR exchange rate')`
### 3.3 بازنویسی `DatabaseSeeder.php`
- [ ] اضافه کردن CountriesTableSeeder
- [ ] اضافه کردن SystemSettingSeeder
- [ ] ایجاد User اولیه با نقش `super_admin`
- [ ] حذف User::factory
--- ---
## بخش ۳: API ترکینگ ## 🟢 بخش ۴: API و Controller ها
| # | کار | وضعیت | توضیحات | ### 4.1 ایجاد `TrackController.php` (حیاتی — فاز ۰)
|---|-----|-------|---------| - [ ] `GET /api/track/{awb_no}` — تایم‌لاین ترکینگ
| 4.1 | ایجاد `TrackController` | ✅ انجام شد | JSON response کامل | - [ ] جستجوی shipment با awb_no
| 4.2 | ایجاد `ApiKeyMiddleware` | ✅ انجام شد | Bearer token validation | - [ ] برگرداندن رویدادهای ترکینگ مرتب‌شده (تاریخ + زمان)
| 4.3 | ثبت route `GET /api/v1/track/{awb_no}` | ✅ انجام شد | | - [ ] برگرداندن اطلاعات پایه مرسوله (direction, type, status, sender, receiver)
| 4.4 | تست با API Key صحیح | ✅ انجام شد | 200 OK | - [ ] برگرداندن نگاشت‌های شرکت حمل (carrier_mappings)
| 4.5 | تست بدون API Key | ✅ انجام شد | 401 Unauthorized | - [ ] Response در قالب JSON مرتب
| 4.6 | تست با API Key نامعتبر | ✅ انجام شد | 403 Forbidden | - [ ] اگر AWB پیدا نشد → 404 با پیام مناسب
### 4.2 اصلاح `PricingController.php`
- [ ] تغییر `type` validation به ۳ مقدار: `DOC_NORMAL`, `DOC_ECONOMY`, `PARCEL`
- [ ] اضافه کردن API Key authentication middleware
- [ ] اضافه کردن Rate Limiting (60 req/min)
- [ ] تغییر مسیر به `POST /api/calculate-price` (در فاز ۱)
### 4.3 تنظیمات امنیتی API
- [ ] ایجاد Middleware برای API Key (header: `Authorization: Bearer {key}`)
- [ ] تنظیم Rate Limiting در `RouteServiceProvider`
- [ ] تنظیم CORS در `config/cors.php` — فقط دامنه‌ی وردپرس تولیدی
- [ ] اعتبارسنجی ورودی‌ها با Form Request
### 4.4 اصلاح `routes/api.php`
- [ ] اضافه کردن `GET /api/track/{awb_no}` (فاز ۰)
- [ ] گروه‌بندی مسیرها با middleware (api_key + throttle)
- [ ] حفظ `GET /api/calculate-price` (فاز ۱)
--- ---
## بخش ۴: پنل مدیریت Filament ## 🟢 بخش ۵: Filament Admin Panel
### Resources اصلی ### 5.1 بازنویسی `CountryResource.php`
- [ ] اضافه کردن فیلدهای ۴ زون در فرم
- [ ] اضافه کردن فیلد `iso_code`
- [ ] اضافه کردن فیلد `is_active` (toggle)
- [ ] نمایش ۴ زون در جدول
| # | کار | وضعیت | توضیحات | ### 5.2 بازنویسی `ShipmentResource.php`
|---|-----|-------|---------| - [ ] حذف `forwarder_track_id` از فرم
| 5.1 | `CountryResource` | ✅ انجام شد | فرم ۴ زون + iso_code + is_active | - [ ] تغییر `type` به Select با ۳ گزینه: DOC_NORMAL, DOC_ECONOMY, PARCEL
| 5.2 | `ShipmentResource` | ✅ انجام شد | ۷ Section کامل | - [ ] تغییر `direction` به Select با ۲ گزینه: import, export
| 5.3 | `ShippingRateResource` | ✅ انجام شد | ۱۰ zone + enum | - [ ] اضافه کردن `from_country_id` و `to_country_id` (Select از کشورها)
| 5.4 | `ShipmentItemResource` | ✅ انجام شد | CRUD کامل | - [ ] اضافه کردن فیلدهای مالی غایب (domestic_pickup, domestic_delivery, warehousing_cost, vat_amount)
| 5.5 | `CarrierMappingsRelationManager` | ✅ انجام شد | برای Shipment | - [ ] تبدیل فیلدهای غیرضروری فاز ۰ به `nullable`
| 5.6 | `TrackingEventsRelationManager` | ✅ انجام شد | برای Shipment | - [ ] حذف `user_id` از فرم (یا nullable)
| 5.7 | `SettingsPage` | ✅ انجام شد | System Settings |
| 5.8 | صفحه‌های List/Create/Edit/View | ✅ انجام شد | برای همه Resources | ### 5.3 ایجاد `ShipmentCarrierMappingResource.php` (یا RelationManager)
- [ ] فرم افزودن نگاشت شرکت حمل:
- [ ] Select `carrier_code` (۸ گزینه + OTHER)
- [ ] `carrier_tracking_number`
- [ ] `booking_number` (nullable)
- [ ] `direction` (import/export)
- [ ] `notes` (nullable)
- [ ] نمایش در صفحه‌ی مرسوله به‌صورت RelationManager
### 5.4 ایجاد `ShipmentTrackingEventResource.php` (یا RelationManager) ⭐ حیاتی
- [ ] UX اختصاصی اپراتور ترکینگ:
- [ ] جستجوی سریع با کد AWB
- [ ] فرم افزودن رویداد:
- [ ] `event_date` (پیش‌فرض: امروز)
- [ ] `event_time` (پیش‌فرض: اکنون)
- [ ] `delivery_status` (Select از لیست ۸-۱۰ حالت آماده)
- [ ] `location` (متن ساده)
- [ ] `event_description` (متن ساده)
- [ ] `source` (hidden — پیش‌فرض: manual)
- [ ] دکمه «ذخیره و افزودن بعدی» — برای ثبت سریع چند رویداد
- [ ] نمایش تایم‌لاین رویدادها در صفحه‌ی مرسوله
### 5.5 بازنویسی `SettingsPage.php`
- [ ] تغییر به ساختار key-value
- [ ] فرم داینامیک: هر تنظیم یک فیلد با label از description
- [ ] اضافه کردن `vat_rate` (0.09)
- [ ] اضافه کردن `packing_cost_default` (100,000 ریال)
- [ ] ذخیره `updated_by` (کاربر فعلی)
### 5.6 بازنویسی `PriceTestPage.php`
- [ ] تغییر `type` به ۳ گزینه: DOC_NORMAL, DOC_ECONOMY, PARCEL
- [ ] نمایش زون استخراج‌شده (کدام زون استفاده شد)
- [ ] اضافه کردن محاسبه VAT و هزینه‌های جانبی
### 5.7 اصلاح `ShippingRateResource.php`
- [ ] تغییر `type` به ۳ گزینه: DOC_NORMAL, DOC_ECONOMY, PARCEL
- [ ] تغییر `direction` به: import, export
### 5.8 تنظیمات Filament
- [ ] تنظیم زبان فارسی پنل (fa)
- [ ] تنظیم navigation groups (مدیریت، ترکینگ، مالی، تنظیمات)
- [ ] تنظیم نقش‌ها و دسترسی‌ها (Filament Shield یا دستی)
--- ---
## بخش ۵: Services ## 🟢 بخش ۶: Services
| # | کار | وضعیت | توضیحات | ### 6.1 اصلاح `PriceCalculatorService.php`
|---|-----|-------|---------| - [ ] استفاده از ۴ زون مجزا (نه ۲ زون):
| 6.1 | `TrackingService` | ✅ انجام شد | getTrackingTimeline, addTrackingEvent, getShipmentWithTracking | - [ ] اگر type=PARCEL → `export_zone_parcel` / `import_zone_parcel`
| 6.2 | `PriceCalculatorService` | ✅ انجام شد | ۹ مرحله محاسبه | - [ ] اگر type=DOC_* → `export_zone_doc` / `import_zone_doc`
- [ ] پشتیبانی از ۳ نوع سرویس: DOC_NORMAL, DOC_ECONOMY, PARCEL
- [ ] اضافه کردن محاسبه VAT (9%)
- [ ] اضافه کردن هزینه‌های جانبی (domestic_pickup, packing, warehousing, delivery)
- [ ] محاسبه sub-total قبل از VAT
- [ ] خروجی کامل: base_price, net_dirham, net_rial, vat_amount, total_fee
### 6.2 ایجاد `TrackingService.php` (فاز ۰)
- [ ] متد `getTrackingTimeline($awb_no)` — دریافت تایم‌لاین
- [ ] متد `addTrackingEvent($shipment_id, $data)` — افزودن رویداد دستی
- [ ] متد `getShipmentWithTracking($awb_no)` — مرسوله + رویدادها + نگاشت‌ها
--- ---
## بخش ۶: Excel Imports ## 🔵 بخش ۷: Import و مهاجرت داده
| # | کار | وضعیت | توضیحات | ### 7.1 اصلاح `OldShipmentsImport.php`
|---|-----|-------|---------| - [ ] اصلاح ایندکس‌های ستون‌ها (مطابق EXCEL_ANALYSIS.md شیت List):
| 7.1 | `ShippingRatesImport` | ✅ انجام شد | ۴۰۴ رکورد import شد | - [ ] ستون ۱: HAWB No. (ایندکس ۰)
| 7.2 | `HistoricalShipmentsImport` | ✅ انجام شد | هر رکورد معتبر در فایل اکسل قابل import است | - [ ] ستون ۲: Date (ایندکس ۱)
| 7.3 | Artisan Command `ifnex:import:rates` | ✅ انجام شد | | - [ ] ستون ۳: Forwarder (ایندکس ۲)
| 7.4 | Artisan Command `ifnex:import:shipments` | ✅ انجام شد | | - [ ] ستون ۴-۵: From/To (ایندکس ۳-۴)
- [ ] ستون ۶: Zone (ایندکس ۵)
- [ ] ستون ۷: Service/Direction (ایندکس ۶)
- [ ] ستون ۸: Type (ایندکس ۷)
- [ ] و غیره...
- [ ] تبدیل `type` به ۳ مقدار: DOC_NORMAL, DOC_ECONOMY, PARCEL
- [ ] تبدیل `direction` به: import, export
- [ ] تبدیل نام کشورها از `Iran (IR)` به `iso_code` برای lookup
- [ ] فیلتر رکوردهای خالی
- [ ] اعتبارسنجی داده‌ها
### 7.2 اصلاح `ShippingRatesImport.php`
- [ ] پشتیبانی از ۳ نوع سرویس (نه ۲):
- [ ] شیت DocNor → type = DOC_NORMAL
- [ ] شیت DocEco → type = DOC_ECONOMY
- [ ] شیت Parcel → type = PARCEL
- [ ] پشتیبانی از فرمت Long format (شیت‌های DocNor/DocEco/Parcel)
- [ ] پشتیبانی از فرمت Wide format (شیت‌های Import/Export Rate)
### 7.3 ایجاد مهاجرت ترکینگ دستی
- [ ] اسکریپت مهاجرت شیت Sheet1 فایل `Data entry 2026-06-28.xlsx`
- [ ] نگاشت به `shipment_tracking_events` با `source = manual`
- [ ] مهاجرت شیت Refrence به `shipment_carrier_mappings`
### 7.4 تست مهاجرت
- [ ] مقایسه تعداد رکوردهای مهاجرت‌داده‌شده با اکسل
- [ ] نمونه‌گیری ۵۰ رکورد برای بررسی دقیق
- [ ] تست مهاجرت حداقل ۱۰ مرسوله با رویداد ترکینگ
--- ---
## بخش ۷: پیکربندی ## 🔵 بخش ۸: پلاگین وردپرس IFNEX Bridge
| # | کار | وضعیت | توضیحات | ### 8.1 ساختار پلاگین
|---|-----|-------|---------| - [ ] ایجاد `ifnex-bridge.php` (فایل اصلی پلاگین)
| 8.1 | `config/ifnex.php` | ✅ انجام شد | تنظیمات اختصاصی | - [ ] ایجاد `includes/api-client.php` (ارتباط با API لاراول)
| 8.2 | `config/cors.php` | ✅ انجام شد | | - [ ] ایجاد `includes/shortcodes.php` (ثبت شورت‌کدها)
| 8.3 | `.env.example` به‌روز | ✅ انجام شد | IFNEX_API_KEY, CORS_ALLOWED_ORIGINS, ... | - [ ] ایجاد `includes/tracking-form.php` (فرم رهگیری)
| 8.4 | سوییچ به Laravel 11 | ✅ انجام شد | Downgrade از v12 به v11 | - [ ] ایجاد `assets/css/ifnex-tracking.css`
| 8.5 | نصب `morilog/jalali` v3 | ✅ انجام شد | | - [ ] ایجاد `assets/js/ifnex-tracking.js`
| 8.6 | رفع خطای PSR-4 | ✅ انجام شد | SettingsPage.php |
| 8.7 | رفع خطای `MethodNotAllowedHttpException` | ✅ انجام شد | POST /admin/login | ### 8.2 شورت‌کد رهگیری مرسوله ⭐ حیاتی
- [ ] `[ifnex_tracking_form]` — فرم جستجوی کد AWB
- [ ] ارسال درخواست به `GET /api/track/{awb_no}` لاراول
- [ ] نمایش تایم‌لاین رویدادها (طراحی شبیه DHL)
- [ ] نمایش اطلاعات پایه مرسوله
- [ ] نمایش خطای «مرسوله پیدا نشد» اگر AWB معتبر نباشد
- [ ] لودینگ و UX روان
### 8.3 شورت‌کد استعلام قیمت (ساده — فاز ۰)
- [ ] `[ifnex_price_inquiry]` — فرم دریافت شماره موبایل + اطلاعات اولیه
- [ ] نمایش پیام «کارشناس ما تماس می‌گیرد»
- [ ] ذخیره اطلاعات برای پیگیری
### 8.4 امنیت پلاگین
- [ ] API Key در تنظیمات پلاگین (نه هاردکد)
- [ ] sanitize_text_field برای تمام ورودی‌ها
- [ ] esc_html و esc_attr برای خروجی‌ها
- [ ] Nonce برای فرم‌ها
--- ---
## بخش ۸: Code Review ## 🔵 بخش ۹: وب‌سایت وردپرس
| # | کار | وضعیت | توضیحات | ### 9.1 نصب و راه‌اندازی
|---|-----|-------|---------| - [ ] نصب وردپرس روی هاست مشتری
| 9.1 | بررسی `bootstrap/app.php` | ✅ انجام شد | مشکل: گروه `web` تعریف نشده | - [ ] تنظیمات امنیتی (HTTPS، فایروال، محدودیت ورود)
| 9.2 | بررسی `AdminPanelProvider.php` | ✅ انجام شد |Middlewareهای طولانی به صورت دستی | - [ ] نصب و تنظیم قالب (light mode، RTL-friendly، DHL-inspired)
| 9.3 | بررسی `composer.json` | ✅ انجام شد | صحیح است |
| 9.4 | بررسی Routes | ✅ انجام شد | کافی برای حال حاضر | ### 9.2 لندینگ پیج
| 9.5 | ارائه راه‌حل برای مشکلات | ✅ انجام شد | راه‌حل در STATUS.md ثبت شد | - [ ] بخش معرفی شرکت
- [ ] بخش خدمات (صادرات، واردات، داخلی)
- [ ] بخش «چرا ما» (مزیت رقابتی)
- [ ] فراخوان به اقدام (Call to Action)
### 9.3 صفحات ثابت
- [ ] درباره ما
- [ ] تماس با ما
- [ ] قوانین و مقررات
- [ ] سوالات متداول (FAQ)
- [ ] حریم خصوصی
### 9.4 صفحه رهگیری مرسوله
- [ ] شورت‌کد `[ifnex_tracking_form]` در صفحه
- [ ] طراحی تایم‌لاین شبیه DHL
- [ ] تست عملکرد
### 9.5 صفحه استعلام قیمت
- [ ] شورت‌کد `[ifnex_price_inquiry]` در صفحه
- [ ] فرم ساده (موبایل + مبدا + مقصد + وزن تقریبی)
- [ ] پیام «کارشناس ما تماس می‌گیرد»
### 9.6 وبلاگ سئو
- [ ] نصب بخش وبلاگ
- [ ] پست ۱: تفاوت صادرات و واردات
- [ ] پست ۲: نحوه محاسبه وزن حجمی
- [ ] پست ۳: راهنمای انتخاب شرکت حمل مناسب
### 9.7 سئو و چندزبانه
- [ ] meta tags و sitemap XML و schema markup
- [ ] ثبت در Google Search Console
- [ ] نصب Polylang (آماده برای آینده)
- [ ] تست سرعت بارگذاری (< ۳ ثانیه)
--- ---
## بخش ۹: بلاک‌های فعلی ## 🔵 بخش ۱۰: اصلاحات فنی عمومی
| # | مشکل | اولویت | وضعیت | راه‌حل | ### 10.1 `composer.json`
|---|------|--------|-------|--------| - [ ] تغییر `laravel/framework` از `^12.0` به `^11.0`
| B1 | فایل اکسل مرسولات فعلی داده‌های نمونه/قدیمی دارد | 🟡 متوسط | **بدون بلاک** | هر فایل اکسل جدید قابل import است | - [ ] اضافه کردن `morilog/jalali` (برای تبدیل تاریخ در لایه نمایش)
| B2 | گروه `web` در `bootstrap/app.php` تعریف نشده | 🔴 بالا | **بلاک** | اضافه کردن `$middleware->group('web', [...])` |
| B3 | فایل اکسل ترکینگ موجود است | 🟡 متوسط | ✅ موجود | در `01_Documents/Data entry 2026-06-28.xlsx` | ### 10.2 تنظیمات `.env.example`
| B4 | پلاگین وردپرس IFNEX Bridge ساخته نشده | 🟡 متوسط | نشده | بعد از تست کامل API | - [ ] اضافه کردن `IFNEX_API_KEY=` (برای احراز هویت وردپرس)
| B5 | تست دستی کامل Filament انجام نشده | 🟡 متوسط | pending | ورود + CRUD + RelationManagers | - [ ] اضافه کردن `CORS_ALLOWED_ORIGINS=` (فقط دامنه‌ی وردپرس)
- [ ] اضافه کردن `IFNEX_TRACKING_RATE_LIMIT=60` (درخواست در دقیقه)
### 10.3 Config اختصاصی
- [ ] ایجاد `config/ifnex.php` (تنظیمات اختصاصی پروژه)
- [ ] API Key
- [ ] CORS whitelist
- [ ] Rate limits
- [ ] Carrier codes list
- [ ] Tracking status list
### 10.4 تست‌ها
- [ ] تست Migration ها (php artisan migrate --seed)
- [ ] تست API ترکینگ (GET /api/track/{awb_no})
- [ ] تست API قیمت‌گذاری (GET /api/calculate-price)
- [ ] تست مهاجرت داده‌های تاریخی
- [ ] تست پنل Filament (CRUD + ترکینگ)
- [ ] تست پلاگین وردپرس
- [ ] تست امنیتی (CORS, Rate Limiting, API Key)
--- ---
## بخش ۱۰: کارهای باقی‌مانده فاز ۰ ## 📋 بخش ۱۱: مستندات
| # | کار | اولویت | وضعیت | یادداشت | - [ ] راهنمای نصب پروژه (Installation Guide)
|---|-----|--------|-------|---------| - [ ] راهنمای اپراتور (Operator Manual) با اسکرین‌شات
| R1 | تست دستی کامل Filament | 🔴 بالا | ✅ انجام شد | ورود + CRUD + RelationManagers + Settings | - [ ] مستندات API (مسیرها، پارامترها، نمونه پاسخ‌ها)
| R2 | مهاجرت داده‌های ترکینگ از `01_Documents/Data entry 2026-06-28.xlsx` | 🟡 متوسط | ✅ انجام شد | 98 رویداد import شد | - [ ] جلسه آموزشی ۴ ساعته برای اپراتورها
| R3 | ساخت پلاگین وردپرس IFNEX Bridge | 🟡 متوسط | ✅ انجام شد | شورت‌کدها کار می‌کنند |
| R4 | تست کامل API Track با داده‌های واقعی | 🟡 متوسط | ✅ انجام شد | AWB 980100010 و 980103619 |
| R5 | تست نهایی فاز ۰ و تحویل به مشتری | 🟢 پایین | ✅ انجام شد | همه موارد تست شدند |
--- ---
## بخش ۱۱: کارهای فاز ۱ (تکمیل شده) ## 📅 بخش ۱۲: جدول زمانی (۴ هفته)
| # | کار | اولویت | وضعیت |
|---|-----|--------|-------|
| F1.1 | تست کامل `PriceCalculatorService` با داده‌های واقعی | 🔴 بالا | ✅ انجام شد (2026-08-07) |
| F1.2 | تکمیل جدول `shipping_rates` | 🟡 متوسط | ✅ انجام شد - ۴۰۴ رکورد import شد |
| F1.3 | فرم ثبت سفارش آنلاین با ۹ ردیف کالای گمرکی | 🟡 متوسط | ✅ انجام شد |
| F1.4 | تولید PDF: AWB، INVOICE، Label | 🟡 متوسط | ✅ انجام شد |
| F1.5 | ماژول ایمپورت اکسل تعرفه‌ها | 🟢 پایین | ✅ انجام شد |
| F1.6 | صفحه استعلام قیمت واقعی | 🟢 پایین | ✅ انجام شد |
## بخش ۱۲: کارهای فاز ۲ (تکمیل شده)
| # | کار | اولویت | وضعیت |
|---|-----|--------|-------|
| F2.1 | ساخت `WalletController` با APIها | 🔴 بالا | ✅ انجام شد |
| F2.2 | ساخت `DiscountCodeController` با APIها | 🔴 بالا | ✅ انجام شد |
| F2.3 | ساخت `UpdateExchangeRates` Artisan Command | 🟡 متوسط | ✅ انجام شد |
| F2.4 | ثبت routeهای کیف پول و تخفیف | 🟡 متوسط | ✅ انجام شد |
| F2.5 | اتصال درگاه پرداخت (زرین‌پال) | 🔴 بالا | ✅ انجام شد |
| F2.6 | شارژ آنلاین کامل | 🔴 بالا | ✅ انجام شد |
| F2.7 | پنل مالی در Filament | 🟡 متوسط | ✅ انجام شد |
| F2.8 | ساخت `OrderPaymentService` | 🔴 بالا | ✅ انجام شد |
| F2.9 | ساخت `ZarinpalService` و `MockZarinpalService` | 🔴 بالا | ✅ انجام شد |
| F2.10 | ردیابی تاریخچه نرخ ارز | 🟡 متوسط | ✅ انجام شد |
| F2.11 | یکپارچگی RBAC با spatie/laravel-permission | 🟡 متوسط | ✅ انجام شد |
| F2.12 | گسترش پلاگین IFNEX Bridge (کیف پول + تراکنش) | 🟡 متوسط | ✅ انجام شد |
## بخش ۱۳: کارهای فاز ۳ (تکمیل شده)
| # | کار | اولویت | وضعیت |
|---|-----|--------|-------|
| F3.1 | ساخت `AuthController` برای Sanctum | 🔴 بالا | ✅ انجام شد |
| F3.2 | ساخت `BridgeAuthController` | 🔴 بالا | ✅ انجام شد |
| F3.3 | ساخت `CustomerOrderController` با ۶ endpoint | 🔴 بالا | ✅ انجام شد |
| F3.4 | ساخت `OrderPaymentService` | 🔴 بالا | ✅ انجام شد |
| F3.5 | توسعه پلاگین وردپرس برای پورتال مشتری | 🔴 بالا | ✅ انجام شد |
| F3.6 | توسعه پوسته سفامشی IFNEX | 🟡 متوسط | ✅ انجام شد |
| F3.7 | به‌روزرسانی وردپرس به ۷.۰.۳ | 🟡 متوسط | ✅ انجام شد |
| F3.8 | یکپارچگی Design System | 🟡 متوسط | ✅ انجام شد |
| F3.9 | خروجی CSV برای ShipmentResource و WalletTransactionResource | 🟢 پایین | ✅ انجام شد |
| هفته | زیرفاز ۰.الف (وردپرس) | زیرفاز ۰.ب (لاراول) | خروجی |
|------|------------------------|----------------------|-------|
| **هفته ۱** | نصب وردپرس + انتخاب قالب + صفحات اصلی | اصلاح Migration ها + Model ها + Seeders | محیط آماده + جداول دیتابیس |
| **هفته ۲** | لندینگ پیج + صفحات ثابت + وبلاگ | API ترکینگ + TrackController + Filament ترکینگ | صفحات آماده + API قابل تست |
| **هفته ۳** | صفحه رهگیری + شورت‌کد + فرم استعلام | پنل Filament کامل + UX اپراتور + پلاگین Bridge | ترکینگ دستی فعال |
| **هفته ۴** | سئو + Polylang + تست | مهاجرت ۳۹۵۰ رکورد + تست نهایی + رفع باگ | تحویل فاز ۰ |
--- ---
## بخش ۱۴: کارهای آینده (فاز ۴) ## 🚫 خط قرمزها — هرگز این کارها را نکن
### فاز ۴: VPS پل و ترکینگ زنده - ❌ هرگز جدول countries را به ۲ زون برگردانی
- [ ] راه‌اندازی VPS پل خارج (هلند/آلمان) - ❌ هرگز فقط ۲ نوع سرویس پیاده کن (۳ نوع الزامی است)
- [ ] اتصال به TrackingMore/17track API - ❌ هرگز ترکینگ را در وردپرس پیاده کن
- [ ] سیستم وب‌هوک - ❌ هرگز فیلدهای مالی (VAT, Packing, Warehousing) را حذف کن
- [ ] مپ کردن کدهای رهگیری - ❌ هرگز از رنگ/لوگو DHL کپی کن
- [ ] پلاگین SMS - ❌ هرگز PDF را به فارسی بسازی
- [ ] ماژول CRM - ❌ هرگز تاریخ را شمسی در DB ذخیره کنی
- [ ] اپلیکیشن موبایل - ❌ هرگز از CORS `*` استفاده کنی
- ❌ هرگز فایل .env را در Git کامیت کنی
### فاز ۲.۵: تست و بهینه‌سازی - ❌ هرگز فاز ۱ را قبل از تأیید فاز ۰ شروع کنی
- [ ] تست نهایی پلاگین وردپرس با داده‌های واقعی
- [ ] مستندسازی API
- [ ] بهینه‌سازی عملکرد (کش، query optimization)
--- ---
## Legend > © 2026 VernaSoft Group. Internal use only.
| آیکون | معنی |
|--------|------|
| ✅ | انجام شده |
| 🔄 | در حال انجام |
| ⚠️ | جزئی/ناقص/بلاک |
| ❌ | لغو شده/خراب |
| ⏸️ | متوقف/منتظر |
| 🔴 بالا | اولویت بالا |
| 🟡 متوسط | اولویت متوسط |
| 🟢 پایین | اولویت پایین |
---
## نحوه استفاده از این فایل
۱. **در ابتدای هر جلسه:** این فایل را باز کنید و موارد `pending` را بررسی کنید.
۲. **بعد از انجام هر کار:** شماره کار را پیدا کنید و وضعیت را به‌روز کنید.
۳. **اگر بلاک جدیدی ایجاد شد:** در بخش «بلاک‌های فعلی» اضافه کنید.
۴. **اگر نیاز به Code Review دارید:** بخش ۹ را بررسی کنید.
---
© 2026 VernaSoft Group. Internal use only.

View File

@ -24,13 +24,14 @@ class ViewShipment extends ViewRecord
->label('دانلود AWB') ->label('دانلود AWB')
->icon('heroicon-o-document-text') ->icon('heroicon-o-document-text')
->color('warning') ->color('warning')
->url(fn ($record) => route('shipments.pdf.awb', $record)), ->url(fn ($record) => route('shipments.pdf.awb', $record))
->openUrlInNewTab(),
Actions\Action::make('download_invoice') Actions\Action::make('download_invoice')
->label('دانلود INVOICE') ->label('دانلود INVOICE')
->icon('heroicon-o-currency-dollar') ->icon('heroicon-o-currency-dollar')
->color('info') ->color('info')
->url(fn ($record) => route('shipments.pdf.invoice', $record)), ->url(fn ($record) => route('shipments.pdf.invoice', $record))
->openUrlInNewTab(),
]; ];
} }
} }

View File

@ -4,7 +4,6 @@ namespace App\Imports;
use App\Enums\ShipmentType; use App\Enums\ShipmentType;
use App\Models\ShippingRate; use App\Models\ShippingRate;
use App\Models\SystemSetting;
use Maatwebsite\Excel\Concerns\OnEachRow; use Maatwebsite\Excel\Concerns\OnEachRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets; use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithStartRow; use Maatwebsite\Excel\Concerns\WithStartRow;
@ -16,11 +15,11 @@ class ShippingRatesImport implements WithMultipleSheets
* تعریف شیت‌های مختلف فایل اکسل و کلاس‌های پردازش‌گر مربوطه * تعریف شیت‌های مختلف فایل اکسل و کلاس‌های پردازش‌گر مربوطه
*/ */
public function sheets(): array public function sheets(): array
{ {
return [ return [
'Export Rate' => new RateSheetImport('outbound'), // تغییر به حروف کوچک 'Export Rate' => new RateSheetImport('export'),
'Import Rate' => new RateSheetImport('inbound'), // تغییر به حروف کوچک 'Import Rate' => new RateSheetImport('import'),
'DocEco' => new SimpleRateSheetImport(ShipmentType::DocEconomy, 'outbound'), // تغییر به حروف کوچک 'DocEco' => new SimpleRateSheetImport(ShipmentType::DocEconomy, 'export'),
]; ];
} }
} }
@ -72,7 +71,7 @@ class RateSheetImport implements OnEachRow, WithStartRow
// ثبت یا به‌روزرسانی نرخ در دیتابیس // ثبت یا به‌روزرسانی نرخ در دیتابیس
ShippingRate::updateOrCreate( ShippingRate::updateOrCreate(
[ [
'direction' => $this->direction, // اکنون مقدار صحیح (Outbound یا Inbound) است 'direction' => $this->direction, // export یا import
'type' => $type->value, 'type' => $type->value,
'weight' => (float) $cells[0], 'weight' => (float) $cells[0],
], ],
@ -129,7 +128,7 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
public function __construct( public function __construct(
protected ShipmentType $type, protected ShipmentType $type,
protected string $direction = 'outbound' // تغییر پیش‌فرض به حروف کوچک protected string $direction = 'export'
) {} ) {}
@ -166,9 +165,8 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
return; return;
} }
// تبدیل قیمت از AED به IRR // نرخ‌ها به صورت AED در دیتابیس ذخیره می‌شوند
$aedToIrr = (float) SystemSetting::get('aed_to_irr', 455000); $value = $rawValue;
$value = $aedToIrr > 0 ? $rawValue / $aedToIrr : $rawValue;
$zoneColumn = 'zone_' . $zoneNumber; $zoneColumn = 'zone_' . $zoneNumber;
@ -181,7 +179,7 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
// یافتن یا ایجاد رکورد و به‌روزرسانی قیمت زون // یافتن یا ایجاد رکورد و به‌روزرسانی قیمت زون
$record = ShippingRate::firstOrCreate( $record = ShippingRate::firstOrCreate(
[ [
'direction' => $this->direction, // اکنون مقدار صحیح (Outbound یا Inbound) است 'direction' => $this->direction,
'type' => $this->type->value, 'type' => $this->type->value,
'weight' => $weight, 'weight' => $weight,
], ],
@ -209,4 +207,4 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
'errors' => $this->errors, 'errors' => $this->errors,
]; ];
} }
} }