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.
125 lines
5.2 KiB
PHP
125 lines
5.2 KiB
PHP
<?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;
|
||
}
|
||
}
|
||
} |