ifnex/04_Laravel/app/Imports/ShippingRatesImport.php
Kazem Alghasi f330d13620 refactor(import): enhance shipping rates import and refine PDF layouts
Improve the reliability and usability of the shipping rates import
process and update PDF document templates for better visual fidelity.

- Enhance `ImportShippingRates` command with `--clear` and `--dry-run`
  options to prevent accidental data loss and allow safe testing.
- Implement error handling and statistics tracking in `ShippingRatesImport`
  to capture skipped rows and import errors.
- Refactor AWB and Label PDF templates to use A4 standard dimensions
  and improved CSS layouts.
- Integrate company logo into PDF headers.
- Add a new pricing inquiry page and navigation link.
- Clean up obsolete test scripts.
2026-08-04 09:47:22 +03:30

173 lines
4.6 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;
use Illuminate\Support\Collection;
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'),
];
}
}
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 {
$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;
}
}
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;
}
$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,
];
}
}