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 — بنیان داده + ترکینگ دستی + مهاجرت داده‌های تاریخی
> **تاریخ ایجاد:** 2026-08-04
> **تاریخ به‌روزرسانی:** 2026-08-10
> **وضعیت کلی:** ✅ تکمیل شده
> **مرجع اصلی:** `01_Documents/Phase0_Proposal.md`
> **مرجع:** Phase0_Proposal.docx + EXCEL_ANALYSIS.md + STATUS.md
> **تاریخ:** August 2026
> **وضعیت:** در دست اقدام
> **توسعه‌دهنده:** VernaSoft Group — Kazem Alghasi
---
## پیش‌نیازها
## 🔴 بخش ۱: اصلاح اسکیمای دیتابیس (حیاتی — قبل از هر چیز)
| # | شرط | وضعیت | توضیحات |
|---|------|-------|---------|
| P1 | Laravel 11 نصب و قابل اجرا | ✅ انجام شد | در پوشه `04_Laravel` |
| P2 | MySQL 8+ قابل دسترس | ✅ انجام شد | دیتابیس `ifnex_db` ایجاد شده |
| P3 | Composer dependencies نصب شده | ✅ انجام شد | filament 3.3.x, maatwebsite/excel, morilog/jalali 3 |
| P4 | فایل‌های اکسل اصلی در دسترس | ⚠️ موجود | فایل مرسولات فعلی داده‌های نمونه/قدیمی دارد — هر فایل جدید قابل import است |
### 1.1 بازنویسی Migration `countries`
- [ ] حذف `export_zone` و `import_zone` (۲ زون قدیمی)
- [ ] اضافه کردن `export_zone_parcel` (TINYINT 1-10)
- [ ] اضافه کردن `export_zone_doc` (TINYINT 1-10)
- [ ] اضافه کردن `import_zone_parcel` (TINYINT 1-10)
- [ ] اضافه کردن `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 ها
| # | کار | وضعیت | توضیحات |
|---|-----|-------|---------|
| 1.1 | Migration `countries` با ۴ زون | ✅ انجام شد | iso_code + is_active اضافه شد |
| 1.2 | Migration `shipments` مطابق Phase 0 | ✅ انجام شد | ۱۱ فیلد مالی + ۴ زون + nullable حقایل |
| 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 | ✅ انجام شد | بدون خطا |
### 2.1 بازنویسی `Country.php`
- [ ] اضافه کردن fillable: `iso_code`, `export_zone_parcel`, `export_zone_doc`, `import_zone_parcel`, `import_zone_doc`, `is_active`
- [ ] حذف `export_zone`, `import_zone` از fillable
- [ ] اضافه کردن `casts` برای `is_active` → boolean
### مدل‌ها و 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.1 | مدل `Country.php` + روابط | ✅ انجام شد | fromShipments() + toShipments() |
| 2.2 | مدل `Shipment.php` + روالات کامل | ✅ انجام شد | items(), carrierMappings(), trackingEvents() |
| 2.3 | مدل `ShippingRate.php` | ✅ انجام شد | cast برای enums |
| 2.4 | مدل `User.php` + helper methods | ✅ انجام شد | phone, role, is_active |
| 2.5 | مدل `ShipmentCarrierMapping.php` | ✅ انجام شد | |
| 2.6 | مدل `ShipmentTrackingEvent.php` | ✅ انجام شد | |
| 2.7 | مدل `SystemSetting.php` | ✅ انجام شد | |
| 2.8 | Enum `ShipmentDirection` | ✅ انجام شد | import/export |
| 2.9 | Enum `ShipmentType` | ✅ انجام شد | DOC_NORMAL/DOC_ECONOMY/PARCEL |
| 2.10 | Enum `ShipmentStatus` | ✅ انجام شد | ۹ وضعیت (pending_payment, cancelled اضافه شد) |
| 2.11 | Enum `CarrierCode` | ✅ انجام شد | ۹ شرکت حمل |
| 2.12 | Enum `TrackingSource` | ✅ انجام شد | manual/api_carrier/api_aggregator |
| 2.13 | Enum `UserRole` | ✅ انجام شد | ۴ نقش |
### 2.3 ایجاد `ShipmentCarrierMapping.php`
- [ ] fillable: تمام فیلدهای جدول
- [ ] casts: `direction` → enum, `last_synced_at` → datetime
- [ ] رابطه `shipment()` (BelongsTo)
### 2.4 ایجاد `ShipmentTrackingEvent.php`
- [ ] fillable: تمام فیلدهای جدول
- [ ] casts: `event_date` → date, `event_time` → datetime, `source` → enum
- [ ] رابطه `shipment()` (BelongsTo)
### 2.5 بازنویسی `SystemSetting.php`
- [ ] تغییر به ساختار key-value
- [ ] اضافه کردن متد `get($key)` — استخراج مقدار با کلید
- [ ] اضافه کردن متد `set($key, $value)` — تنظیم مقدار
- [ ] اضافه کردن رابطه `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 | Seeder ۲۳۲ کشور با ۴ زون | ✅ انجام شد | تصحیح کدهای ISO، حذف تکراری‌ها |
| 3.2 | Seeder System Settings | ✅ انجام شد | VAT 9%, packing 100000 IRR, profit_margin 1.25 |
| 3.3 | Seeder Super Admin User | ✅ انجام شد | |
| 3.4 | DatabaseSeeder ترکیبی | ✅ انجام شد | |
### 3.1 بازنویسی `CountriesTableSeeder.php`
- [ ] استخراج نام کشور و iso_code از فرمت `Afghanistan (AF)`
- [ ] تنظیم ۴ زون مجزا (از شیت Zone اکسل):
- [ ] `export_zone_parcel` — از ستون PARCEL شیت Zone
- [ ] `export_zone_doc` — از ستون DOCUMENT شیت Zone
- [ ] `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` | ✅ انجام شد | JSON response کامل |
| 4.2 | ایجاد `ApiKeyMiddleware` | ✅ انجام شد | Bearer token validation |
| 4.3 | ثبت route `GET /api/v1/track/{awb_no}` | ✅ انجام شد | |
| 4.4 | تست با API Key صحیح | ✅ انجام شد | 200 OK |
| 4.5 | تست بدون API Key | ✅ انجام شد | 401 Unauthorized |
| 4.6 | تست با API Key نامعتبر | ✅ انجام شد | 403 Forbidden |
### 4.1 ایجاد `TrackController.php` (حیاتی — فاز ۰)
- [ ] `GET /api/track/{awb_no}` — تایم‌لاین ترکینگ
- [ ] جستجوی shipment با awb_no
- [ ] برگرداندن رویدادهای ترکینگ مرتب‌شده (تاریخ + زمان)
- [ ] برگرداندن اطلاعات پایه مرسوله (direction, type, status, sender, receiver)
- [ ] برگرداندن نگاشت‌های شرکت حمل (carrier_mappings)
- [ ] Response در قالب JSON مرتب
- [ ] اگر 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.1 | `CountryResource` | ✅ انجام شد | فرم ۴ زون + iso_code + is_active |
| 5.2 | `ShipmentResource` | ✅ انجام شد | ۷ Section کامل |
| 5.3 | `ShippingRateResource` | ✅ انجام شد | ۱۰ zone + enum |
| 5.4 | `ShipmentItemResource` | ✅ انجام شد | CRUD کامل |
| 5.5 | `CarrierMappingsRelationManager` | ✅ انجام شد | برای Shipment |
| 5.6 | `TrackingEventsRelationManager` | ✅ انجام شد | برای Shipment |
| 5.7 | `SettingsPage` | ✅ انجام شد | System Settings |
| 5.8 | صفحه‌های List/Create/Edit/View | ✅ انجام شد | برای همه Resources |
### 5.2 بازنویسی `ShipmentResource.php`
- [ ] حذف `forwarder_track_id` از فرم
- [ ] تغییر `type` به Select با ۳ گزینه: DOC_NORMAL, DOC_ECONOMY, PARCEL
- [ ] تغییر `direction` به Select با ۲ گزینه: import, export
- [ ] اضافه کردن `from_country_id` و `to_country_id` (Select از کشورها)
- [ ] اضافه کردن فیلدهای مالی غایب (domestic_pickup, domestic_delivery, warehousing_cost, vat_amount)
- [ ] تبدیل فیلدهای غیرضروری فاز ۰ به `nullable`
- [ ] حذف `user_id` از فرم (یا nullable)
### 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 | `TrackingService` | ✅ انجام شد | getTrackingTimeline, addTrackingEvent, getShipmentWithTracking |
| 6.2 | `PriceCalculatorService` | ✅ انجام شد | ۹ مرحله محاسبه |
### 6.1 اصلاح `PriceCalculatorService.php`
- [ ] استفاده از ۴ زون مجزا (نه ۲ زون):
- [ ] اگر type=PARCEL → `export_zone_parcel` / `import_zone_parcel`
- [ ] اگر 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 | `ShippingRatesImport` | ✅ انجام شد | ۴۰۴ رکورد import شد |
| 7.2 | `HistoricalShipmentsImport` | ✅ انجام شد | هر رکورد معتبر در فایل اکسل قابل import است |
| 7.3 | Artisan Command `ifnex:import:rates` | ✅ انجام شد | |
| 7.4 | Artisan Command `ifnex:import:shipments` | ✅ انجام شد | |
### 7.1 اصلاح `OldShipmentsImport.php`
- [ ] اصلاح ایندکس‌های ستون‌ها (مطابق EXCEL_ANALYSIS.md شیت List):
- [ ] ستون ۱: HAWB No. (ایندکس ۰)
- [ ] ستون ۲: Date (ایندکس ۱)
- [ ] ستون ۳: Forwarder (ایندکس ۲)
- [ ] ستون ۴-۵: 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 | `config/ifnex.php` | ✅ انجام شد | تنظیمات اختصاصی |
| 8.2 | `config/cors.php` | ✅ انجام شد | |
| 8.3 | `.env.example` به‌روز | ✅ انجام شد | IFNEX_API_KEY, CORS_ALLOWED_ORIGINS, ... |
| 8.4 | سوییچ به Laravel 11 | ✅ انجام شد | Downgrade از v12 به v11 |
| 8.5 | نصب `morilog/jalali` v3 | ✅ انجام شد | |
| 8.6 | رفع خطای PSR-4 | ✅ انجام شد | SettingsPage.php |
| 8.7 | رفع خطای `MethodNotAllowedHttpException` | ✅ انجام شد | POST /admin/login |
### 8.1 ساختار پلاگین
- [ ] ایجاد `ifnex-bridge.php` (فایل اصلی پلاگین)
- [ ] ایجاد `includes/api-client.php` (ارتباط با API لاراول)
- [ ] ایجاد `includes/shortcodes.php` (ثبت شورت‌کدها)
- [ ] ایجاد `includes/tracking-form.php` (فرم رهگیری)
- [ ] ایجاد `assets/css/ifnex-tracking.css`
- [ ] ایجاد `assets/js/ifnex-tracking.js`
### 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 | بررسی `bootstrap/app.php` | ✅ انجام شد | مشکل: گروه `web` تعریف نشده |
| 9.2 | بررسی `AdminPanelProvider.php` | ✅ انجام شد |Middlewareهای طولانی به صورت دستی |
| 9.3 | بررسی `composer.json` | ✅ انجام شد | صحیح است |
| 9.4 | بررسی Routes | ✅ انجام شد | کافی برای حال حاضر |
| 9.5 | ارائه راه‌حل برای مشکلات | ✅ انجام شد | راه‌حل در STATUS.md ثبت شد |
### 9.1 نصب و راه‌اندازی
- [ ] نصب وردپرس روی هاست مشتری
- [ ] تنظیمات امنیتی (HTTPS، فایروال، محدودیت ورود)
- [ ] نصب و تنظیم قالب (light mode، RTL-friendly، DHL-inspired)
### 9.2 لندینگ پیج
- [ ] بخش معرفی شرکت
- [ ] بخش خدمات (صادرات، واردات، داخلی)
- [ ] بخش «چرا ما» (مزیت رقابتی)
- [ ] فراخوان به اقدام (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 (آماده برای آینده)
- [ ] تست سرعت بارگذاری (< ۳ ثانیه)
---
## بخش ۹: بلاک‌های فعلی
## 🔵 بخش ۱۰: اصلاحات فنی عمومی
| # | مشکل | اولویت | وضعیت | راه‌حل |
|---|------|--------|-------|--------|
| B1 | فایل اکسل مرسولات فعلی داده‌های نمونه/قدیمی دارد | 🟡 متوسط | **بدون بلاک** | هر فایل اکسل جدید قابل import است |
| B2 | گروه `web` در `bootstrap/app.php` تعریف نشده | 🔴 بالا | **بلاک** | اضافه کردن `$middleware->group('web', [...])` |
| B3 | فایل اکسل ترکینگ موجود است | 🟡 متوسط | ✅ موجود | در `01_Documents/Data entry 2026-06-28.xlsx` |
| B4 | پلاگین وردپرس IFNEX Bridge ساخته نشده | 🟡 متوسط | نشده | بعد از تست کامل API |
| B5 | تست دستی کامل Filament انجام نشده | 🟡 متوسط | pending | ورود + CRUD + RelationManagers |
### 10.1 `composer.json`
- [ ] تغییر `laravel/framework` از `^12.0` به `^11.0`
- [ ] اضافه کردن `morilog/jalali` (برای تبدیل تاریخ در لایه نمایش)
### 10.2 تنظیمات `.env.example`
- [ ] اضافه کردن `IFNEX_API_KEY=` (برای احراز هویت وردپرس)
- [ ] اضافه کردن `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)
---
## بخش ۱۰: کارهای باقی‌مانده فاز ۰
## 📋 بخش ۱۱: مستندات
| # | کار | اولویت | وضعیت | یادداشت |
|---|-----|--------|-------|---------|
| R1 | تست دستی کامل Filament | 🔴 بالا | ✅ انجام شد | ورود + CRUD + RelationManagers + Settings |
| R2 | مهاجرت داده‌های ترکینگ از `01_Documents/Data entry 2026-06-28.xlsx` | 🟡 متوسط | ✅ انجام شد | 98 رویداد import شد |
| R3 | ساخت پلاگین وردپرس IFNEX Bridge | 🟡 متوسط | ✅ انجام شد | شورت‌کدها کار می‌کنند |
| R4 | تست کامل API Track با داده‌های واقعی | 🟡 متوسط | ✅ انجام شد | AWB 980100010 و 980103619 |
| R5 | تست نهایی فاز ۰ و تحویل به مشتری | 🟢 پایین | ✅ انجام شد | همه موارد تست شدند |
- [ ] راهنمای نصب پروژه (Installation Guide)
- [ ] راهنمای اپراتور (Operator Manual) با اسکرین‌شات
- [ ] مستندات API (مسیرها، پارامترها، نمونه پاسخ‌ها)
- [ ] جلسه آموزشی ۴ ساعته برای اپراتورها
---
## بخش ۱۱: کارهای فاز ۱ (تکمیل شده)
| # | کار | اولویت | وضعیت |
|---|-----|--------|-------|
| 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 پل و ترکینگ زنده
- [ ] راه‌اندازی VPS پل خارج (هلند/آلمان)
- [ ] اتصال به TrackingMore/17track API
- [ ] سیستم وب‌هوک
- [ ] مپ کردن کدهای رهگیری
- [ ] پلاگین SMS
- [ ] ماژول CRM
- [ ] اپلیکیشن موبایل
### فاز ۲.۵: تست و بهینه‌سازی
- [ ] تست نهایی پلاگین وردپرس با داده‌های واقعی
- [ ] مستندسازی API
- [ ] بهینه‌سازی عملکرد (کش، query optimization)
- ❌ هرگز جدول countries را به ۲ زون برگردانی
- ❌ هرگز فقط ۲ نوع سرویس پیاده کن (۳ نوع الزامی است)
- ❌ هرگز ترکینگ را در وردپرس پیاده کن
- ❌ هرگز فیلدهای مالی (VAT, Packing, Warehousing) را حذف کن
- ❌ هرگز از رنگ/لوگو DHL کپی کن
- ❌ هرگز PDF را به فارسی بسازی
- ❌ هرگز تاریخ را شمسی در DB ذخیره کنی
- ❌ هرگز از CORS `*` استفاده کنی
- ❌ هرگز فایل .env را در Git کامیت کنی
- ❌ هرگز فاز ۱ را قبل از تأیید فاز ۰ شروع کنی
---
## Legend
| آیکون | معنی |
|--------|------|
| ✅ | انجام شده |
| 🔄 | در حال انجام |
| ⚠️ | جزئی/ناقص/بلاک |
| ❌ | لغو شده/خراب |
| ⏸️ | متوقف/منتظر |
| 🔴 بالا | اولویت بالا |
| 🟡 متوسط | اولویت متوسط |
| 🟢 پایین | اولویت پایین |
---
## نحوه استفاده از این فایل
۱. **در ابتدای هر جلسه:** این فایل را باز کنید و موارد `pending` را بررسی کنید.
۲. **بعد از انجام هر کار:** شماره کار را پیدا کنید و وضعیت را به‌روز کنید.
۳. **اگر بلاک جدیدی ایجاد شد:** در بخش «بلاک‌های فعلی» اضافه کنید.
۴. **اگر نیاز به Code Review دارید:** بخش ۹ را بررسی کنید.
---
© 2026 VernaSoft Group. Internal use only.
> © 2026 VernaSoft Group. Internal use only.

View File

@ -24,13 +24,14 @@ class ViewShipment extends ViewRecord
->label('دانلود AWB')
->icon('heroicon-o-document-text')
->color('warning')
->url(fn ($record) => route('shipments.pdf.awb', $record)),
->url(fn ($record) => route('shipments.pdf.awb', $record))
->openUrlInNewTab(),
Actions\Action::make('download_invoice')
->label('دانلود INVOICE')
->icon('heroicon-o-currency-dollar')
->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\Models\ShippingRate;
use App\Models\SystemSetting;
use Maatwebsite\Excel\Concerns\OnEachRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithStartRow;
@ -16,11 +15,11 @@ class ShippingRatesImport implements WithMultipleSheets
* تعریف شیت‌های مختلف فایل اکسل و کلاس‌های پردازش‌گر مربوطه
*/
public function sheets(): array
{
{
return [
'Export Rate' => new RateSheetImport('outbound'), // تغییر به حروف کوچک
'Import Rate' => new RateSheetImport('inbound'), // تغییر به حروف کوچک
'DocEco' => new SimpleRateSheetImport(ShipmentType::DocEconomy, 'outbound'), // تغییر به حروف کوچک
'Export Rate' => new RateSheetImport('export'),
'Import Rate' => new RateSheetImport('import'),
'DocEco' => new SimpleRateSheetImport(ShipmentType::DocEconomy, 'export'),
];
}
}
@ -72,7 +71,7 @@ class RateSheetImport implements OnEachRow, WithStartRow
// ثبت یا به‌روزرسانی نرخ در دیتابیس
ShippingRate::updateOrCreate(
[
'direction' => $this->direction, // اکنون مقدار صحیح (Outbound یا Inbound) است
'direction' => $this->direction, // export یا import
'type' => $type->value,
'weight' => (float) $cells[0],
],
@ -129,7 +128,7 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
public function __construct(
protected ShipmentType $type,
protected string $direction = 'outbound' // تغییر پیش‌فرض به حروف کوچک
protected string $direction = 'export'
) {}
@ -166,9 +165,8 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
return;
}
// تبدیل قیمت از AED به IRR
$aedToIrr = (float) SystemSetting::get('aed_to_irr', 455000);
$value = $aedToIrr > 0 ? $rawValue / $aedToIrr : $rawValue;
// نرخ‌ها به صورت AED در دیتابیس ذخیره می‌شوند
$value = $rawValue;
$zoneColumn = 'zone_' . $zoneNumber;
@ -181,7 +179,7 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
// یافتن یا ایجاد رکورد و به‌روزرسانی قیمت زون
$record = ShippingRate::firstOrCreate(
[
'direction' => $this->direction, // اکنون مقدار صحیح (Outbound یا Inbound) است
'direction' => $this->direction,
'type' => $this->type->value,
'weight' => $weight,
],
@ -209,4 +207,4 @@ class SimpleRateSheetImport implements OnEachRow, WithStartRow
'errors' => $this->errors,
];
}
}
}