212 lines
6.1 KiB
PHP
212 lines
6.1 KiB
PHP
<?php
|
||
|
||
namespace App\Imports;
|
||
|
||
use App\Enums\ShipmentType;
|
||
use App\Models\ShippingRate;
|
||
use App\Models\SystemSetting;
|
||
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,
|
||
'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 به IRR
|
||
$aedToIrr = (float) SystemSetting::get('aed_to_irr', 455000);
|
||
$value = $aedToIrr > 0 ? $rawValue / $aedToIrr : $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,
|
||
];
|
||
}
|
||
}
|