Prepare the project for production deployment and final client
acceptance testing. Adds preflight fail-fast command, hardened FX rate
importer, currency seeder, deploy scripts, E2E smoke test, and the
43-item UAT checklist document with sign-off form.
Key changes:
- Phase 3.9.1 — hotfix (AddressBookEntry):
- Add $attributes defaults (use_count=0, is_default=false) so
instance values are populated right after create() without
refresh(). Resolves the red test
`it_increments_use_count_and_sets_last_used_at`.
- Phase 3.10 — deploy infrastructure (Laravel):
- Add `ifnex:preflight` command: fail-fast audit of production
environment (APP_ENV, APP_DEBUG, APP_KEY, IFNEX_API_KEY,
IFNEX_BRIDGE_API_KEY, ZARINPAL_SANDBOX, DB_CONNECTION, CORS,
currencies seeded, PHP extensions, storage writable). Exits 1
if any check fails; supports --skip-db for pre-migrate runs.
- Add `ifnex:import-fx-rates` command: replacement for
`ifnex:update-rates`. Fetches USD/AED from Exir.io + EUR/CNY
from FreeCurrencyAPI. Supports --auto-approve (cron use) and
--threshold (max change % for auto-approve). Logs critical on
HTTP failure. URL configurable via EXIR_API_URL env.
- Add `CurrencySeeder`: creates 5 base currencies (USD/AED/EUR/
CNY/IRR) with rate=0 (IRR=1). Idempotent — does not overwrite
real rates already set by admin or cron.
- Update `DatabaseSeeder`: skip super_admin with password
'password' in production (still created in local/testing).
- Fix `bootstrap/app.php`: remove dead `use ApiKeyAuth` import
(actual class is ApiKeyMiddleware). Latent fatal if api_key
alias was used.
- Add `config/ifnex.php` exir block + preflight config.
- Harden `.env.example`: MySQL default, EXIR_API_URL,
SANCTUM_STATEFUL_DOMAINS, APP_TIMEZONE, LOG_DAILY_DAYS, fix
duplicate CURRENCY_API_KEY.
- Phase 3.10 — deploy scripts (Linux):
- Add `scripts/deploy.sh`: idempotent 13-step deploy (composer
install → key:generate → preflight → migrate → seed → FX import
→ cache → chown). Fail-fast with set -e.
- Add `scripts/cron-exir-rates.sh`: daily cron wrapper for
`ifnex:import-fx-rates --source=all --auto-approve`.
- Phase 3.10.1 — preflight hotfix:
- Make expected DB connection configurable
(ifnex.preflight.expected_db_connection) instead of hardcoded
'mysql'. Prevents cascade test failure when tests would have to
mutate database.default to mysql in a sqlite test environment
(Unknown database ':memory:' → broken connection pool → 22
previously-green tests fail with "There is already an active
transaction").
- Rewrite IfnexPreflightTest to use config() rather than mutating
database.default.
- Phase 3.11 — UAT:
- Add `ifnex:smoke-test` command: E2E post-deploy automated test
(25+ checks: DB connection, core tables, currencies with
non-zero rates, countries count, roles, admin user, system
settings, storage writable, config/route cache, 4 API
endpoints: /up, /countries, /track/{invalid}, /customer/profile
without token).
- Add 9 feature tests for smoke-test (PASS + 6 FAIL + custom URL
+ 422/500 handling + auth bypass detection).
- Add `UAT-3.11.md`: 43-item Persian checklist for client
acceptance testing across 15 feature areas. Includes sign-off
form for both parties (client + VernaSoft).
- Update `CLIENT_DELIVERY.md` to record phases 3.10 and 3.11.
Tests:
- Total: 51 → 82 tests, 150 → 220+ assertions, all green.
- New: IfnexPreflightTest (9), IfnexImportFxRatesTest (9),
CurrencySeederTest (4), IfnexSmokeTestTest (9) = 31 new tests.
Documentation:
- DEPLOYMENT_HANDOFF.md §2.4: add CurrencySeeder + import-fx-rates.
- DEPLOYMENT_HANDOFF.md §2.8: update cron to use cron-exir-rates.sh.
- UAT-3.11.md: new 43-item client acceptance checklist + sign-off.
- CLIENT_DELIVERY.md: record phases 3.10 and 3.11 completion.
205 lines
9.6 KiB
PHP
205 lines
9.6 KiB
PHP
<?php
|
||
|
||
return [
|
||
|
||
'bridge_api_key' => env('IFNEX_BRIDGE_API_KEY', 'change-this-secret-key'), // This is the API key that you get from the IFNEX Bridge
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| IFNEX API Settings
|
||
|--------------------------------------------------------------------------
|
||
| تنظیمات عمومی API سیستم ایفنکس
|
||
*/
|
||
'api_key' => env('IFNEX_API_KEY', 'change-me'),
|
||
|
||
'cors_allowed_origins' => explode(',', env('CORS_ALLOWED_ORIGINS', 'http://localhost,http://127.0.0.1')),
|
||
|
||
'tracking_rate_limit' => env('IFNEX_TRACKING_RATE_LIMIT', 60),
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Carrier Codes (کدهای شرکتهای حملونقل)
|
||
|--------------------------------------------------------------------------
|
||
| لیست شرکتهای حملونقل فعال در سیستم
|
||
*/
|
||
'carrier_codes' => [
|
||
'DHL',
|
||
'FEDEX',
|
||
'UPS',
|
||
'ARAMEX',
|
||
'NAGHEL',
|
||
'EMX',
|
||
'APSITEX',
|
||
'IMPEX',
|
||
'OTHER',
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Tracking Statuses (وضعیتهای رهگیری مرسوله)
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
'tracking_statuses' => [
|
||
'processed',
|
||
'picked_up',
|
||
'in_transit',
|
||
'out_for_delivery',
|
||
'failed',
|
||
'delivered',
|
||
'returned',
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Currency API (بهروزرسانی نرخ ارز)
|
||
|--------------------------------------------------------------------------
|
||
| FreeCurrencyAPI برای EUR و CNY (Exir.io این دو را ندارد).
|
||
| USD و AED از Exir.io میآیند (دقیقتر در بازار ایران).
|
||
*/
|
||
'currency' => [
|
||
'api_key' => env('CURRENCY_API_KEY'),
|
||
'api_url' => env('CURRENCY_API_URL', 'https://api.freecurrencyapi.com/v1/latest'),
|
||
'base_currency' => 'USD',
|
||
'target_currencies' => ['IRR', 'AED', 'EUR', 'CNY'],
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Exir.io (نرخ ارز بازار ایران)
|
||
|--------------------------------------------------------------------------
|
||
| منبع نرخ USD و AED — نیازی به API key ندارد.
|
||
| برای دریافت EUR/CNY از FreeCurrencyAPI استفاده میشود.
|
||
*/
|
||
'exir' => [
|
||
'api_url' => env('EXIR_API_URL', 'https://api.exir.io/v2/minicharts'),
|
||
'timeout' => (int) env('EXIR_API_TIMEOUT', 15),
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Preflight (بررسی پیشاز-دیپلوی)
|
||
|--------------------------------------------------------------------------
|
||
| اگر در محیط تست یا staging میخواهید preflight سبز شود
|
||
| بدون اینکه واقعاً به MySQL وصل شوید، این متغیر را روی sqlite بگذارید.
|
||
| در Production همیشه mysql باید باشد.
|
||
*/
|
||
'preflight' => [
|
||
'expected_db_connection' => env('IFNEX_PREFLIGHT_DB', 'mysql'),
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Zarinpal Payment Gateway (درگاه پرداخت زرینپال)
|
||
|--------------------------------------------------------------------------
|
||
| تنظیمات اتصال به درگاه زرینپال برای شارژ کیف پول
|
||
*/
|
||
'zarinpal' => [
|
||
// شناسه پذیرنده (Merchant ID) از پنل زرینپال
|
||
'merchant_id' => env('ZARINPAL_MERCHANT_ID', 'fake-merchant-id-for-testing'),
|
||
|
||
// محیط Sandbox برای تست (true) یا Production (false)
|
||
'sandbox' => env('ZARINPAL_SANDBOX', true),
|
||
|
||
// URL Callback که زرینپال بعد از پرداخت کاربر را به آن redirect میکند
|
||
'callback_url' => env('ZARINPAL_CALLBACK_URL', null),
|
||
// اگر null باشد، از url('/api/v1/payment/callback') استفاده میشود
|
||
|
||
// URL فرانتاند برای redirect بعد از پرداخت موفق
|
||
'frontend_success_url' => env('ZARINPAL_FRONTEND_SUCCESS_URL', '/payment/success'),
|
||
|
||
// URL فرانتاند برای redirect بعد از پرداخت ناموفق
|
||
'frontend_failure_url' => env('ZARINPAL_FRONTEND_FAILURE_URL', '/payment/failed'),
|
||
|
||
// زمان انقضای تراکنشهای pending (به دقیقه)
|
||
'transaction_expiry_minutes' => env('ZARINPAL_EXPIRY_MINUTES', 30),
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Wallet Settings (تنظیمات کیف پول)
|
||
|--------------------------------------------------------------------------
|
||
| قوانین و محدودیتهای کیف پول کاربران
|
||
*/
|
||
'wallet' => [
|
||
// حداقل مبلغ شارژ آنلاین (ریال) - معمولاً ۱۰,۰۰۰ ریال
|
||
'min_deposit_amount' => env('WALLET_MIN_DEPOSIT', 10000),
|
||
|
||
// حداکثر مبلغ شارژ در هر تراکنش (ریال) - معمولاً ۵۰۰ میلیون ریال
|
||
'max_deposit_amount' => env('WALLET_MAX_DEPOSIT', 500000000),
|
||
|
||
// حداقل موجودی لازم برای پرداخت سفارش از کیف پول (ریال)
|
||
'min_balance_for_payment' => env('WALLET_MIN_BALANCE', 1000),
|
||
|
||
// کارمزد شارژ کیف پول (درصد) - معمولاً ۰٪
|
||
'deposit_fee_percent' => env('WALLET_DEPOSIT_FEE', 0),
|
||
|
||
// آیا کیف پول بهصورت پیشفرض هنگام ثبتنام کاربر ساخته شود؟
|
||
'auto_create_on_register' => env('WALLET_AUTO_CREATE', true),
|
||
|
||
// آیا کاربران عادی اجازه برداشت (cash out) دارند؟
|
||
'allow_withdrawal' => env('WALLET_ALLOW_WITHDRAWAL', false),
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Financial Defaults (پیشفرضهای مالی)
|
||
|--------------------------------------------------------------------------
|
||
| این مقادیر فقط fallback هستند — مقادیر واقعی از جدول system_settings خوانده میشوند
|
||
*/
|
||
'financial_defaults' => [
|
||
'vat_rate' => 0.09, // ۹٪ مالیات بر ارزش افزوده
|
||
'profit_margin' => 1.25, // ۲۵٪ حاشیه سود
|
||
'packing_cost' => 100000, // ۱۰۰,۰۰۰ ریال هزینه بستهبندی پیشفرض
|
||
// ⚠️ نرخهای ارز فقط از جدول currencies خوانده میشوند (هیچ fallback عددی نداریم).
|
||
// اگه ارز در دیتابیس نباشد، ExchangeRateService خطا میدهد و مدیر باید آن را تنظیم کند.
|
||
// این عدد فقط برای جلوگیری از Fatal Error در تستهای قدیمی نگه داشته شده — نباید به آن اعتماد کرد.
|
||
'aed_to_irr' => 7419700, // [Deprecated — فقط تست] 7,419,700 ریال/درهم (اکتبر ۲۰۲۶)
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Notification Settings (تنظیمات اعلانها)
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
'notifications' => [
|
||
// آیا هنگام شارژ موفق به کاربر ایمیل/پیامک زده شود؟
|
||
'notify_on_deposit' => env('NOTIFY_ON_DEPOSIT', true),
|
||
|
||
// آیا هنگام شارژ دستی توسط ادمین به کاربر اطلاع داده شود؟
|
||
'notify_on_manual_adjustment' => env('NOTIFY_ON_MANUAL_ADJUSTMENT', true),
|
||
|
||
// آیا هنگام رسیدن موجودی به آستانه هشدار، اطلاع داده شود؟
|
||
'low_balance_threshold' => env('LOW_BALANCE_THRESHOLD', 500000), // ۵۰۰,۰۰۰ ریال
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Kavenegar SMS Gateway (درگاه پیامک کاوهنگار)
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
'kavenegar' => [
|
||
'api_key' => env('KAVENEGAR_API_KEY', ''),
|
||
'sender' => env('KAVENEGAR_SENDER', '10008566'),
|
||
'send_shipment_approved' => env('KAVENEGAR_SEND_SHIPMENT_APPROVED', true),
|
||
'send_shipment_rejected' => env('KAVENEGAR_SEND_SHIPMENT_REJECTED', true),
|
||
'send_payment_success' => env('KAVENEGAR_SEND_PAYMENT_SUCCESS', true),
|
||
'send_tracking_update' => env('KAVENEGAR_SEND_TRACKING_UPDATE', false),
|
||
],
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Audit & Logging (ثبت فعالیتها و لاگ)
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
'audit' => [
|
||
// آیا تمام عملیات مالی لاگ شوند؟ (توصیه میشود همیشه true باشد)
|
||
'log_financial_operations' => true,
|
||
|
||
// آیا IP و User Agent کاربر در تراکنشها ذخیره شود؟
|
||
'track_client_info' => true,
|
||
|
||
// تعداد روز نگهداری لاگهای قدیمی (برای پاکسازی خودکار)
|
||
'log_retention_days' => env('AUDIT_LOG_RETENTION_DAYS', 365),
|
||
],
|
||
|
||
]; |