Refactor the shipment direction logic from 'outbound/inbound' to 'export/import' to align with the new database schema requirements. This includes updating the `ShippingRatesImport` logic, adjusting the Excel import sheet mappings, and removing the AED to IRR conversion during import as rates are now stored in AED. Additionally, updated the shipment view action to open PDF documents in a new tab and updated the Phase 0 checklist with the new database schema requirements. - docs: update Phase 0 checklist with new schema requirements - refactor(ui): update shipment view actions to open in new tab - refactor(import): update shipping rates import to use new direction enums and AED values - docs: add file map and new excel document
210 lines
6.1 KiB
PHP
210 lines
6.1 KiB
PHP
<?php
|
||
|
||
namespace App\Imports;
|
||
|
||
use App\Enums\ShipmentType;
|
||
use App\Models\ShippingRate;
|
||
use Maatwebsite\Excel\Concerns\OnEachRow;
|
||
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
|
||
use Maatwebsite\Excel\Concerns\WithStartRow;
|
||
use Maatwebsite\Excel\Row;
|
||
|
||
class ShippingRatesImport implements WithMultipleSheets
|
||
{
|
||
/**
|
||
* تعریف شیتهای مختلف فایل اکسل و کلاسهای پردازشگر مربوطه
|
||
*/
|
||
public function sheets(): array
|
||
{
|
||
return [
|
||
'Export Rate' => new RateSheetImport('export'),
|
||
'Import Rate' => new RateSheetImport('import'),
|
||
'DocEco' => new SimpleRateSheetImport(ShipmentType::DocEconomy, 'export'),
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* کلاس برای پردازش شیتهای استاندارد نرخها (Export Rate و Import Rate)
|
||
*/
|
||
class RateSheetImport implements OnEachRow, WithStartRow
|
||
{
|
||
protected int $imported = 0;
|
||
protected int $skipped = 0;
|
||
protected array $errors = [];
|
||
|
||
public function __construct(protected string $direction) {}
|
||
|
||
/**
|
||
* شروع خواندن از ردیف ۵ (۴ ردیف اول هدر هستند)
|
||
*/
|
||
public function startRow(): int
|
||
{
|
||
return 5;
|
||
}
|
||
|
||
/**
|
||
* پردازش هر ردیف از شیت
|
||
*/
|
||
public function onRow(Row $row)
|
||
{
|
||
$rowIndex = $row->getIndex();
|
||
$cells = $row->toArray();
|
||
|
||
// بررسی اعتبار ستون وزن (ستون اول)
|
||
if (empty($cells[0]) || !is_numeric($cells[0])) {
|
||
$this->skipped++;
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// تشخیص نوع سرویس (Doc یا Parcel)
|
||
$type = $this->resolveType($rowIndex, $cells);
|
||
|
||
// استخراج و نرمالسازی قیمتهای ۱۰ زون
|
||
$zones = [];
|
||
for ($i = 1; $i <= 10; $i++) {
|
||
$val = str_replace([',', ' '], '', (string) ($cells[$i] ?? 0));
|
||
$zones['zone_' . $i] = is_numeric($val) ? (float) $val : 0;
|
||
}
|
||
|
||
// ثبت یا بهروزرسانی نرخ در دیتابیس
|
||
ShippingRate::updateOrCreate(
|
||
[
|
||
'direction' => $this->direction, // export یا import
|
||
'type' => $type->value,
|
||
'weight' => (float) $cells[0],
|
||
],
|
||
$zones
|
||
);
|
||
|
||
$this->imported++;
|
||
} catch (\Throwable $e) {
|
||
$this->errors[] = "Row $rowIndex: " . $e->getMessage();
|
||
$this->skipped++;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* دریافت آمار عملیات ایمپورت
|
||
*/
|
||
public function getStats(): array
|
||
{
|
||
return [
|
||
'imported' => $this->imported,
|
||
'skipped' => $this->skipped,
|
||
'errors' => $this->errors,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* تشخیص نوع سرویس بر اساس محتوای ردیف
|
||
*/
|
||
private function resolveType(int $rowIndex, array $cells): ShipmentType
|
||
{
|
||
$header = strtoupper((string) ($cells[3] ?? ''));
|
||
|
||
if (str_contains($header, 'DOCUMENT') || str_contains($header, 'DOC')) {
|
||
return ShipmentType::DocNormal;
|
||
}
|
||
|
||
if (str_contains($header, 'NON') || str_contains($header, 'PARCEL')) {
|
||
return ShipmentType::Parcel;
|
||
}
|
||
|
||
// اگر نوع مشخص نبود، بر اساس شماره ردیف حدس میزنیم
|
||
return $rowIndex < 10 ? ShipmentType::DocNormal : ShipmentType::Parcel;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* کلاس برای پردازش شیت سادهتر نرخها (DocEco)
|
||
*/
|
||
class SimpleRateSheetImport implements OnEachRow, WithStartRow
|
||
{
|
||
protected int $imported = 0;
|
||
protected int $skipped = 0;
|
||
protected array $errors = [];
|
||
|
||
public function __construct(
|
||
protected ShipmentType $type,
|
||
protected string $direction = 'export'
|
||
) {}
|
||
|
||
|
||
/**
|
||
* شروع خواندن از ردیف ۲ (۱ ردیف اول هدر است)
|
||
*/
|
||
public function startRow(): int
|
||
{
|
||
return 2;
|
||
}
|
||
|
||
/**
|
||
* پردازش هر ردیف از شیت
|
||
*/
|
||
public function onRow(Row $row)
|
||
{
|
||
$cells = $row->toArray();
|
||
|
||
// بررسی اعتبار ستون وزن (ستون اول)
|
||
if (empty($cells[0]) || !is_numeric($cells[0])) {
|
||
$this->skipped++;
|
||
return;
|
||
}
|
||
|
||
try {
|
||
$weight = (float) $cells[0];
|
||
$zoneNumber = (int) $cells[1];
|
||
$rawValue = str_replace([',', ' '], '', (string) ($cells[2] ?? 0));
|
||
$rawValue = is_numeric($rawValue) ? (float) $rawValue : 0;
|
||
|
||
// بررسی اعتبار شماره زون و قیمت
|
||
if ($zoneNumber < 1 || $zoneNumber > 10 || $rawValue <= 0) {
|
||
$this->skipped++;
|
||
return;
|
||
}
|
||
|
||
// نرخها به صورت AED در دیتابیس ذخیره میشوند
|
||
$value = $rawValue;
|
||
|
||
$zoneColumn = 'zone_' . $zoneNumber;
|
||
|
||
// ایجاد مقادیر پیشفرض برای زونها
|
||
$defaults = [];
|
||
for ($i = 1; $i <= 10; $i++) {
|
||
$defaults['zone_' . $i] = 0;
|
||
}
|
||
|
||
// یافتن یا ایجاد رکورد و بهروزرسانی قیمت زون
|
||
$record = ShippingRate::firstOrCreate(
|
||
[
|
||
'direction' => $this->direction,
|
||
'type' => $this->type->value,
|
||
'weight' => $weight,
|
||
],
|
||
$defaults
|
||
);
|
||
|
||
$record->{$zoneColumn} = $value;
|
||
$record->save();
|
||
|
||
$this->imported++;
|
||
} catch (\Throwable $e) {
|
||
$this->errors[] = "Row " . $row->getIndex() . ": " . $e->getMessage();
|
||
$this->skipped++;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* دریافت آمار عملیات ایمپورت
|
||
*/
|
||
public function getStats(): array
|
||
{
|
||
return [
|
||
'imported' => $this->imported,
|
||
'skipped' => $this->skipped,
|
||
'errors' => $this->errors,
|
||
];
|
||
}
|
||
} |