ifnex/04_Laravel/app/Filament/Pages/PriceTestPage.php
Kazem Alghasi 563f89495c fix(pricing): restore array-based calculate() and harden pricing API
Restore the array-based signature of PriceCalculatorService::calculate()
to fix the TypeError thrown when PricingController and CustomerOrderController
called it with an array (the previous commit had switched to 4 separate
string params without updating the callers).

- PriceCalculatorService: support multiple input formats for direction
  (export|import|Outbound|Inbound) and type (DOC_NORMAL|DOC_ECONOMY|PARCEL|
  DOCUMENT|NON DOC) for backward compatibility with admin and customer flows.
- ExchangeRateService: add convertToIrr() for explicit AED→IRR conversion
  (was missing but referenced by the calculator).
- PricingController: expand validation rules to accept new shipment types
  and a discount_code string (was 'discount' numeric). Add 3-layer exception
  handling (422 validation / 400 business / 500 server).
- PriceTestPage: compute volumetric weight from dimensions (IATA: L×W×H/5000),
  resolve destination country by direction, and show errors as Filament
  notifications instead of crashing.
2026-10-29 14:40:58 +03:30

125 lines
5.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Filament\Pages;
use App\Services\PriceCalculatorService;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Section;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use App\Models\Country;
class PriceTestPage extends Page
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-calculator';
protected static string $view = 'filament.pages.price-test-page';
protected static ?string $navigationLabel = 'تست محاسبه قیمت';
protected static ?string $navigationGroup = 'ابزارها';
protected static ?int $navigationSort = 1;
protected static bool $shouldRegisterNavigation = true;
public ?array $data = [];
public ?array $result = null;
public function mount(): void
{
$this->form->fill();
}
public function form(Form $form): Form
{
return $form
->schema([
Section::make('اطلاعات ارسال')
->schema([
Select::make('direction')
->label('جهت ارسال')
->options(['export' => 'صادرات (خروج از ایران)', 'import' => 'واردات (ورود به ایران)'])
->required()
->reactive()
->afterStateUpdated(fn ($state) => $this->result = null),
Select::make('type')
->label('نوع محموله')
->options(['DOCUMENT' => 'مدارک (DOCUMENT)', 'NON DOC' => 'غیر مدارک (NON DOC)'])
->required()
->afterStateUpdated(fn () => $this->result = null),
])->columns(2),
Section::make('مبدا و مقصد')
->schema([
Select::make('origin_country_id')
->label('کشور مبدا')
->options(Country::all()->pluck('name', 'id'))
->searchable()
->required()
->afterStateUpdated(fn () => $this->result = null),
Select::make('destination_country_id')
->label('کشور مقصد')
->options(Country::all()->pluck('name', 'id'))
->searchable()
->required()
->afterStateUpdated(fn () => $this->result = null),
])->columns(2),
Section::make('ابعاد و وزن')
->schema([
TextInput::make('weight')->label('وزن واقعی (کیلوگرم)')->numeric()->required()->afterStateUpdated(fn () => $this->result = null),
TextInput::make('length')->label('طول (سانتی‌متر)')->numeric()->required()->afterStateUpdated(fn () => $this->result = null),
TextInput::make('width')->label('عرض (سانتی‌متر)')->numeric()->required()->afterStateUpdated(fn () => $this->result = null),
TextInput::make('height')->label('ارتفاع (سانتی‌متر)')->numeric()->required()->afterStateUpdated(fn () => $this->result = null),
])->columns(4),
])
->statePath('data');
}
public function calculate()
{
$data = $this->form->getState();
// تعیین کشور مقصد (برای صادرات = مقصد، برای واردات = مبدا)
$destinationId = ($data['direction'] === 'export')
? ($data['destination_country_id'] ?? null)
: ($data['origin_country_id'] ?? null);
$country = Country::find($destinationId);
if (! $country) {
\Filament\Notifications\Notification::make()
->title('خطا')
->body('کشور مقصد یافت نشد.')
->danger()
->send();
return;
}
// محاسبه وزن حجمی از ابعاد (فرمول IATA: L×W×H/5000)
$length = (float) ($data['length'] ?? 0);
$width = (float) ($data['width'] ?? 0);
$height = (float) ($data['height'] ?? 0);
$volumetricWeight = ($length * $width * $height) / 5000;
$service = app(PriceCalculatorService::class);
try {
$this->result = $service->calculate([
'direction' => $data['direction'], // 'export' | 'import'
'type' => $data['type'], // 'DOCUMENT' | 'NON DOC'
'country_iso' => $country->iso_code,
'weight' => (float) $data['weight'],
'volumetric_weight' => $volumetricWeight,
]);
} catch (\Exception $e) {
\Filament\Notifications\Notification::make()
->title('خطا در محاسبه قیمت')
->body($e->getMessage())
->danger()
->send();
$this->result = null;
}
}
}