diff --git a/01_Documents/4_5989927490271846355.xlsx b/01_Documents/4_5989927490271846355.xlsx new file mode 100644 index 0000000..3b1c9e6 Binary files /dev/null and b/01_Documents/4_5989927490271846355.xlsx differ diff --git a/01_Documents/IFNEX_File_Map.md b/01_Documents/IFNEX_File_Map.md new file mode 100644 index 0000000..a958be5 --- /dev/null +++ b/01_Documents/IFNEX_File_Map.md @@ -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 | + +--- + +> مجموع: **۵۶ فایل** قابل دانلود + **۴ تغییر دستی** diff --git a/01_Documents/IFNEX_Phase0_Checklist.md b/01_Documents/IFNEX_Phase0_Checklist.md index 2ef230c..360f49a 100644 --- a/01_Documents/IFNEX_Phase0_Checklist.md +++ b/01_Documents/IFNEX_Phase0_Checklist.md @@ -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. diff --git a/04_Laravel/app/Filament/Resources/ShipmentResource/Pages/ViewShipment.php b/04_Laravel/app/Filament/Resources/ShipmentResource/Pages/ViewShipment.php index 6ceaf7a..9f837bc 100644 --- a/04_Laravel/app/Filament/Resources/ShipmentResource/Pages/ViewShipment.php +++ b/04_Laravel/app/Filament/Resources/ShipmentResource/Pages/ViewShipment.php @@ -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(), ]; } } diff --git a/04_Laravel/app/Imports/ShippingRatesImport.php b/04_Laravel/app/Imports/ShippingRatesImport.php index a2110c9..61c7730 100644 --- a/04_Laravel/app/Imports/ShippingRatesImport.php +++ b/04_Laravel/app/Imports/ShippingRatesImport.php @@ -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, ]; } -} +} \ No newline at end of file