📄 فایل ۲: 04_Laravel/README.md (پوشه لاراول)
# 🚀 IFNEX Laravel Backend
> هسته مرکزی سیستم مدیریت لجستیک ایفنکس
| مورد | توضیحات |
| :--- | :--- |
| **نسخه لاراول** | Laravel 11.x |
| **نسخه PHP** | PHP 8.2+ |
| **پنل ادمین** | Filament 3.3.x |
| **دیتابیس** | MySQL 8+ |
| **تاریخ آخرین بهروزرسانی** | 2026-08-10 |
---
## 📋 فهرست مطالب
1. [پیشنیازها](#پیشنیازها)
2. [نصب و راهاندازی](#نصب-و-راهاندازی)
3. [ساختار پوشهها](#ساختار-پوشهها)
4. [API Endpoints](#api-endpoints)
5. [Artisan Commands](#artisan-commands)
6. [تستها](#تستها)
7. [پیکربندی](#پیکربندی)
8. [نکات امنیتی](#نکات-امنیتی)
---
## پیشنیازها
قبل از شروع، مطمئن شوید که موارد زیر روی سیستم شما نصب هستند:
| ابزار | نسخه حداقل | نصب |
|-------|-----------|-----|
| PHP | 8.2+ | [دانلود](https://www.php.net/downloads) |
| Composer | 2.x | [دانلود](https://getcomposer.org/) |
| MySQL | 8+ | [دانلود](https://dev.mysql.com/downloads/) |
| Node.js & NPM | 18+ | [دانلود](https://nodejs.org/) (اختیاری - برای WordPress tools) |
| XAMPP/WAMP | آخرین نسخه | [دانلود](https://www.apachefriends.org/) (پیشنهادی برای Windows) |
---
## نصب و راهاندازی
### ۱. کلون مخزن و ورود به پوشه لاراول
```bash
# کلون مخزن
git clone https://www.git.vernahost.ir/gitmodir110/ifnex.git
# ورود به پوشه لاراول
cd ifnex/04_Laravel
۲. نصب پکیجهای Composer
composer install
۳. کپی فایل محیط و تنظیم دیتابیس
# کپی فایل محیط
cp .env.example .env
# ویرایش فایل .env و تنظیم اطلاعات دیتابیس
nano .env # یا هر ویرایشگر دلخواه
تنظیمات مهم در فایل .env:
# دیتابیس
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ifnex_db
DB_USERNAME=root
DB_PASSWORD=
# API Key برای ترکینگ
IFNEX_API_KEY=ifnex-local-dev-key
# CORS - فقط دامنه وردپرس
CORS_ALLOWED_ORIGINS=http://localhost:8080
# Rate Limiting
IFNEX_TRACKING_RATE_LIMIT=60
# Currency API (برای فاز ۲)
CURRENCY_API_KEY=your_api_key_here
۴. تولید کلید اپلیکیشن
php artisan key:generate
۵. ایجاد دیتابیس
# ورود به MySQL
mysql -u root -p
# ایجاد دیتابیس
CREATE DATABASE ifnex_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EXIT;
۶. اجرای Migration ها
php artisan migrate --force
۷. درج دادههای اولیه (Seeders)
# این دستور ۲۳۳ کشور + تنظیمات اولیه + کاربر ادمین را ایجاد میکند
php artisan db:seed --force
اطلاعات ورود پیشفرض به پنل ادمین:
URL: http://localhost:8000/admin
Email: admin@ifnex.local
Password: password (در Seeder تنظیم شده)
۸. اجرای سرور توسعه
php artisan serve
اکنون پروژه در http://localhost:8000 قابل دسترسی است.
ساختار پوشهها
04_Laravel/
├── app/
│ ├── Models/ # مدلهای Eloquent
│ │ ├── Country.php # کشورها با ۴ زون
│ │ ├── Shipment.php # مرسولات
│ │ ├── ShipmentItem.php # اقلام گمرکی (۹ ردیف)
│ │ ├── ShippingRate.php # تعرفههای حمل
│ │ ├── ShipmentCarrierMapping.php # نگاشت کدهای ترکینگ
│ │ ├── ShipmentTrackingEvent.php # رویدادهای ترکینگ
│ │ ├── SystemSetting.php # تنظیمات سیستم
│ │ └── User.php # کاربران
│ │
│ ├── Enums/ # Enum ها
│ │ ├── ShipmentDirection.php # import/export
│ │ ├── ShipmentType.php # DOC_NORMAL/DOC_ECONOMY/PARCEL
│ │ ├── ShipmentStatus.php # ۹ وضعیت مرسوله
│ │ ├── CarrierCode.php # ۹ شرکت حمل
│ │ ├── TrackingSource.php # ۵ منبع (manual, api, import, system, customer)
│ │ ├── TransactionType.php
│ │ ├── TransactionStatus.php
│ │ ├── PaymentGateway.php # ۴ درگاه (zarinpal, wallet, manual, system)
│ │ └── UserRole.php
│ │
│ ├── Services/ # لایه سرویس (Business Logic)
│ │ ├── PriceCalculatorService.php
│ │ ├── TrackingService.php
│ │ ├── ExchangeRateService.php
│ │ ├── ZarinpalService.php
│ │ ├── MockZarinpalService.php
│ │ └── OrderPaymentService.php
│ │
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── Api/
│ │ │ │ ├── TrackController.php
│ │ │ │ ├── PricingController.php
│ │ │ │ ├── AuthController.php # ورود/خروج Sanctum
│ │ │ │ ├── BridgeAuthController.php # لاگین از پلاگین وردپرس
│ │ │ │ ├── WalletController.php
│ │ │ │ ├── PaymentController.php
│ │ │ │ ├── DiscountCodeController.php
│ │ │ │ └── Customer/
│ │ │ │ └── CustomerOrderController.php # ۶ endpoint سفارش مشتری
│ │ │ ├── OrderController.php
│ │ │ ├── PricingPageController.php
│ │ │ └── ShipmentPdfController.php
│ │ ├── Middleware/
│ │ │ └── ApiKeyMiddleware.php
│ │ └── Requests/
│ │
│ ├── Imports/ # Excel Imports
│ │ ├── ShippingRatesImport.php # واردات تعرفهها
│ │ ├── HistoricalShipmentsImport.php # واردات مرسولات تاریخی
│ │ └── RateSheetImport.php # شیتهای نرخ
│ │
│ ├── Console/Commands/ # Artisan Commands
│ │ ├── ImportShippingRates.php
│ │ ├── ImportHistoricalData.php
│ │ ├── UpdateExchangeRates.php
│ │ ├── SyncWordPressUsers.php
│ │ └── DebugImportCommand.php
│ │
│ └── Filament/ # پنل ادمین Filament
│ ├── Resources/
│ │ ├── CountryResource.php
│ │ ├── ShipmentResource.php
│ │ ├── ShippingRateResource.php
│ │ ├── ShipmentItemResource.php
│ │ ├── WalletResource.php
│ │ ├── WalletTransactionResource.php
│ │ ├── PaymentResource.php
│ │ ├── DiscountCodeResource.php
│ │ ├── ExchangeRateHistoryResource.php
│ │ ├── RoleResource.php
│ │ └── UserResource.php
│ ├── Widgets/
│ │ ├── DashboardInfoWidget.php
│ │ ├── ExchangeRateWidget.php
│ │ ├── WalletStats.php
│ │ ├── TransactionChartWidget.php
│ │ └── RecentTransactionsWidget.php
│ └── Pages/
│ ├── IfnexSettingsPage.php
│ ├── PriceTestPage.php
│ └── Reports/
│ └── FinancialReport.php
│
├── database/
│ ├── migrations/ # Migration ها
│ │ ├── 2026_08_02_000001_create_countries_table.php
│ │ ├── 2026_08_02_000002_create_shipments_table.php
│ │ ├── 2026_08_02_000003_create_shipping_rates_table.php
│ │ ├── 2026_08_02_000004_create_shipment_carrier_mappings_table.php
│ │ ├── 2026_08_02_000005_create_shipment_tracking_events_table.php
│ │ ├── 2026_08_02_000006_create_system_settings_table.php
│ │ ├── 2026_08_02_000007_update_users_table.php
│ │ ├── 2026_08_08_000001_create_shipment_items_table.php
│ │ ├── 2026_08_05_135026_create_discount_codes_table.php
│ │ ├── 2026_08_09_231738_create_exchange_rate_history_table.php
│ │ ├── 2026_08_10_080853_add_wallet_to_payment_gateway_enum.php
│ │ ├── 2026_08_10_082121_add_system_to_tracking_source_enum.php
│ │ ├── 2026_08_09_012526_create_notifications_table.php
│ │ └── 2026_08_09_220409_create_permission_tables.php
│ └── seeders/ # Seeders
│ ├── CountriesTableSeeder.php
│ ├── SystemSettingSeeder.php
│ ├── DatabaseSeeder.php
│ ├── RoleAndPermissionSeeder.php
│ └── SampleDataSeeder.php
│
├── routes/
│ ├── web.php # روتهای وب (فرمها و صفحات)
│ └── api.php # روتهای API
│
├── resources/views/
│ ├── layouts/app.blade.php # لایاوت اصلی
│ ├── orders/ # فرم ثبت سفارش
│ ├── pricing/ # صفحه استعلام قیمت
│ └── pdfs/ # قالبهای PDF
│
├── config/
│ ├── ifnex.php # تنظیمات اختصاصی IFNEX
│ └── cors.php # تنظیمات CORS
│
├── tests/
│ └── Feature/
│ └── Services/
│ └── PriceCalculatorServiceTest.php # ⭐ تستهای موتور قیمت
│
├── bootstrap/
│ └── app.php # Bootstrap لاراول ۱۱
│
├── .env.example # نمونه فایل محیط
├── composer.json # وابستگیهای Composer
└── README.md # این فایل
API Endpoints
🔓 API های عمومی (نیاز به API Key)
۱. رهگیری مرسوله
GET /api/v1/track/{awb_no}
Headers:
Authorization: Bearer {IFNEX_API_KEY}
مثال:
curl -H "Authorization: Bearer ifnex-local-dev-key" \
http://localhost:8000/api/v1/track/980100010
پاسخ موفق (200 OK):
{
"success": true,
"data": {
"awb_no": "980100010",
"status": "delivered",
"carrier_mappings": [...],
"tracking_events": [...]
}
}
۲. استعلام قیمت
POST /api/v1/calculate
Body (JSON):
{
"direction": "export",
"type": "DOC_NORMAL",
"country_iso": "US",
"weight": 2.5,
"volumetric_weight": 3.0,
"extra_service": 10.00
}
مثال:
curl -X POST http://localhost:8000/api/v1/calculate \
-H "Content-Type: application/json" \
-d '{
"direction": "export",
"type": "DOC_NORMAL",
"country_iso": "US",
"weight": 2.5,
"volumetric_weight": 3.0
}'
پاسخ موفق:
{
"base_price": 40.00,
"net_dirham": 50.00,
"net_rial": 22750000,
"total_fee": 24906510.9,
"zone": 1,
"chargeable_weight": 3.0
}
💳 API های کیف پول (فاز ۲)
۱. بررسی موجودی
GET /api/v1/wallet/balance
۲. شارژ کیف پول
POST /api/v1/wallet/charge
Body:
{
"amount": 1000000,
"description": "شارژ اولیه"
}
۳. تاریخچه تراکنشها
GET /api/v1/wallet/transactions
🎟️ API های تخفیف (فاز ۲)
۱. لیست کدهای تخفیف فعال
GET /api/v1/discount-codes/active
۲. اعتبارسنجی کد تخفیف
POST /api/v1/discount-codes/validate
Body:
{
"code": "SUMMER20",
"amount": 1000000
}
🔐 API های احراز هویت (فاز ۳)
۱. ورود و دریافت توکن Sanctum
POST /api/v1/auth/login
Body:
{
"email": "user@example.com",
"password": "password",
"token_name": "api-token"
}
۲. خروج و حذف توکن
POST /api/v1/auth/logout
Header: Authorization: Bearer {token}
🛒 API های سفارشات مشتری (فاز ۳)
۱. پروفایل و آمار کاربر
GET /api/v1/customer/profile
۲. لیست کشورها برای فرم سفارش
GET /api/v1/customer/countries
۳. لیست سفارشات کاربر
GET /api/v1/customer/orders
۴. ثبت سفارش جدید
POST /api/v1/customer/orders
Body:
{
"direction": "export",
"type": "PARCEL",
"from_country_id": 1,
"to_country_id": 2,
"weight": 2.5,
"sender_name": "نام فرستنده",
"sender_phone": "۰۹۱۲۳۴۵۶۷۸۹",
"sender_address": "آدرس",
"receiver_name": "نام گیرنده",
"receiver_phone": "۰۹۱۲۳۴۵۶۷۸۹",
"receiver_address": "آدرس",
"items": [
{
"description": "کالای گمرکی",
"hs_code": "8542390001",
"quantity": 1,
"unit_price": 100
}
]
}
۵. جزئیات یک سفارش
GET /api/v1/customer/orders/{shipment}
۶. لغو سفارش (فقط pending_payment)
POST /api/v1/customer/orders/{shipment}/cancel
۷. پرداخت از کیف پول
POST /api/v1/customer/orders/{shipment}/pay-wallet
۸. پرداخت از درگاه بانکی
POST /api/v1/customer/orders/{shipment}/pay-gateway
Body:
{
"frontend_callback": "https://your-wordpress.com/order-payment/"
}
🔗 API پل وردپرس (فاز ۳)
POST /api/v1/bridge/login
Body:
{
"bridge_api_key": "ifnex-bridge-key",
"wp_user_id": 1,
"wp_user_email": "user@wordpress.local",
"wp_user_name": "نام کاربر"
}
Artisan Commands
📥 واردات دادهها
۱. واردات تعرفههای حمل از اکسل
# واردات عادی
php artisan ifnex:import:rates storage/app/public/rates.xlsx
# پاکسازی و واردات مجدد
php artisan ifnex:import:rates storage/app/public/rates.xlsx --clear
# تست بدون ذخیره (Dry Run)
php artisan ifnex:import:rates storage/app/public/rates.xlsx --dry-run
۲. واردات مرسولات تاریخی
php artisan ifnex:import:shipments storage/app/public/historical.xlsx
💱 بهروزرسانی نرخ ارز (فاز ۲)
# بهروزرسانی دستی
php artisan ifnex:update-exchange-rates
# تنظیم Cron Job برای بهروزرسانی روزانه
# crontab -e
# 0 0 * * * cd /path/to/04_Laravel && php artisan ifnex:update-exchange-rates >> /dev/null 2>&1
🔄 سینک کاربران وردپرس (فاز ۳)
# سینک دستی کاربران بین وردپرس و لاراول
php artisan ifnex:sync-wp-users
🔑 تولید توکن API (فاز ۲)
php artisan ifnex:token --user=admin@ifnex.local --name=api-token
🧪 تستها
# اجرای همه تستها
php artisan test
# اجرای تستهای یک کلاس خاص
php artisan test --filter=PriceCalculatorServiceTest
# اجرای تست با نمایش دقیق
php artisan test --filter=it_calculates_price_correctly_for_standard_package
# گزارش پوشش تست (نیاز به Xdebug)
php artisan test --coverage
تستها
تستهای موجود
۱. PriceCalculatorServiceTest
این تست کلاس PriceCalculatorService را به طور کامل تست میکند:
php artisan test --filter=PriceCalculatorServiceTest
موارد تست شده:
✅ محاسبه صحیح قیمت برای بسته استاندارد
✅ استفاده از وزن حجمی وقتی از وزن واقعی بزرگتر است
✅ اعمال صحیح ضریب سود و VAT
✅ اعمال هزینههای جانبی
✅ اعمال کد تخفیف درصدی و ثابت
۲. WalletServiceTest (فاز ۲)
تستهای مربوط به کیف پول و تراکنشها:
php artisan test --filter=WalletServiceTest
۳. PaymentControllerTest (فاز ۲)
تستهای مربوط به درگاه پرداخت:
php artisan test --filter=PaymentControllerTest
۴. DiscountCodeControllerTest (فاز ۲)
تستهای مربوط به کدهای تخفیف:
php artisan test --filter=DiscountCodeControllerTest
نوشتن تست جدید
برای نوشتن تست جدید، از این الگو استفاده کنید:
<?php
namespace Tests\Feature\Services;
use App\Models\Country;
use App\Models\ShippingRate;
use App\Models\SystemSetting;
use App\Services\PriceCalculatorService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class PriceCalculatorServiceTest extends TestCase
{
use RefreshDatabase;
#[Test]
public function it_calculates_price_correctly()
{
// 1. تنظیم SystemSetting ها
SystemSetting::create(['key' => 'profit_margin', 'value' => 1.0]);
SystemSetting::create(['key' => 'aed_to_irr', 'value' => 1.0]);
SystemSetting::create(['key' => 'vat_rate', 'value' => 0.0]);
SystemSetting::create(['key' => 'packing_cost_default', 'value' => 0]);
// 2. ایجاد دادههای تست
$country = Country::factory()->create([...]);
ShippingRate::create([...]);
// 3. اجرای سرویس
$service = app(PriceCalculatorService::class);
$result = $service->calculate([...]);
// 4. بررسی نتیجه
$this->assertEquals(50.00, $result['total_fee']);
}
}
پیکربندی
فایل config/ifnex.php
return [
// API Key برای احراز هویت
'api_key' => env('IFNEX_API_KEY', 'default-key'),
// Rate Limiting
'tracking_rate_limit' => env('IFNEX_TRACKING_RATE_LIMIT', 60),
// Currency API
'currency_api_key' => env('CURRENCY_API_KEY'),
'currency_api_url' => env('CURRENCY_API_URL', 'https://api.freecurrencyapi.com/v1/latest'),
// Zarinpal Payment Gateway
'zarinpal' => [
'merchant_id' => env('ZARINPAL_MERCHANT_ID', 'fake-merchant-id-for-testing'),
'sandbox' => env('ZARINPAL_SANDBOX', true),
'callback_url' => env('ZARINPAL_CALLBACK_URL', 'http://localhost:8000/api/v1/payment/callback'),
],
// WordPress Bridge
'bridge_api_key' => env('IFNEX_BRIDGE_API_KEY', 'ifnex-bridge-key'),
// CORS
'cors_allowed_origins' => explode(',', env('CORS_ALLOWED_ORIGINS', '*')),
];
فایل config/cors.php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => explode(',', env('CORS_ALLOWED_ORIGINS', '*')),
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
نکات امنیتی
🚫 هرگز این کارها را نکنید
هرگز فایل .env را در Git کامیت نکنید
# بررسی کنید در .gitignore باشد
.env
.env.local
.env.production
هرگز APP_DEBUG=true را در محیط تولید بگذارید
# Production
APP_DEBUG=false
هرگز از CORS * در محیط تولید استفاده نکنید
# فقط دامنه وردپرس
CORS_ALLOWED_ORIGINS=https://your-wordpress-domain.com
هرگز API Key را در کد Hardcode نکنید
// ❌ اشتباه
$apiKey = 'secret-key-123';
// ✅ درست
$apiKey = config('ifnex.api_key');
🐛 عیبیابی
مشکل: CHECK constraint failed: direction
علت: Factory مقادیر پیشفرض اشتباه میسازد (مثلاً 'Outbound' به جای 'export')
راهحل: در تستها از ShippingRate::create() به جای ShippingRate::factory()->create() استفاده کنید:
ShippingRate::create([
'direction' => 'export', // حروف کوچک
'type' => 'DOC_NORMAL',
'weight' => 1.0,
'zone_1' => 20.00,
// ... بقیه zone ها
]);
مشکل: No rate found for the given parameters
علت: Query نمیتواند نرخ مناسبی پیدا کند
راهحل:
بررسی کنید که zone_column درست است (zone_1, zone_2, ...)
مطمئن شوید که وزن در تست بیشتر از وزنهای موجود در دیتابیس نیست
SystemSetting ها را در تست Mock کنید
📞 پشتیبانی
اگر سوالی داشتید که در این فایل یا مستندات 01_Documents پاسخ آن نبود، از کاربر (Kazem) بپرسید — حدس نزنید.
© 2026 VernaSoft Group. Internal use only.