Implement the core logic for applying discount codes during price calculation and introduce the WalletService. This includes updating the PriceCalculatorService to validate and apply discounts, incrementing usage counts, and adding a Filament resource for managing discount codes via the admin panel. Additionally, refactor TrackingDataImport to use OnEachRow for better memory management during large Excel imports.
218 lines
6.9 KiB
PHP
218 lines
6.9 KiB
PHP
<?php
|
|
|
|
namespace App\Imports;
|
|
|
|
use App\Models\Shipment;
|
|
use App\Models\ShipmentTrackingEvent;
|
|
use App\Models\Country;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Maatwebsite\Excel\Concerns\OnEachRow;
|
|
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
|
use Maatwebsite\Excel\Row;
|
|
|
|
class TrackingDataImport implements OnEachRow, WithHeadingRow
|
|
{
|
|
protected $importedEvents = 0;
|
|
protected $skippedEvents = 0;
|
|
protected $errors = [];
|
|
protected $createdShipments = 0;
|
|
|
|
public function onRow(Row $row)
|
|
{
|
|
$rowIndex = $row->getIndex();
|
|
$rowArray = $row->toArray();
|
|
|
|
try {
|
|
// استخراج و نرمالسازی دادهها از ردیف اکسل
|
|
$awbNo = $this->normalizeAwb($rowArray['awb'] ?? null);
|
|
$eventDate = $this->normalizeDate($rowArray['date'] ?? null);
|
|
$eventTime = $this->normalizeTime($rowArray['time'] ?? null);
|
|
$eventDescription = $this->normalizeDescription($rowArray['state'] ?? null);
|
|
$location = $this->normalizeLocation($rowArray['country'] ?? null);
|
|
$deliveryStatus = $this->normalizeDeliveryStatus($rowArray['last_state'] ?? null);
|
|
|
|
// بررسی اعتبار دادههای ضروری
|
|
if (!$awbNo || !$eventDate || !$eventDescription) {
|
|
$this->skippedEvents++;
|
|
return;
|
|
}
|
|
|
|
// جستجوی مرسوله بر اساس AWB
|
|
$shipment = Shipment::where('awb_no', $awbNo)->first();
|
|
|
|
// اگر مرسوله وجود نداشت، آن را ایجاد کن
|
|
if (!$shipment) {
|
|
$shipment = $this->createShipmentFromTrackingRow($rowArray, $awbNo, $location);
|
|
$this->createdShipments++;
|
|
}
|
|
|
|
// ثبت رویداد ترکینگ
|
|
ShipmentTrackingEvent::create([
|
|
'shipment_id' => $shipment->id,
|
|
'event_date' => $eventDate,
|
|
'event_time' => $eventTime,
|
|
'location' => $location,
|
|
'event_description' => $eventDescription,
|
|
'delivery_status' => $deliveryStatus,
|
|
'source' => 'manual',
|
|
]);
|
|
|
|
$this->importedEvents++;
|
|
} catch (\Throwable $e) {
|
|
$this->skippedEvents++;
|
|
$this->errors[] = "Row {$rowIndex}: " . $e->getMessage();
|
|
Log::error('Tracking import error', ['row' => $rowIndex, 'error' => $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
protected function createShipmentFromTrackingRow(array $row, string $awbNo, ?string $location): Shipment
|
|
{
|
|
// استخراج نام کشور از لوکیشن
|
|
$countryName = $location ? explode(' - ', $location)[0] : null;
|
|
$country = Country::where('name', 'like', "%{$countryName}%")->first();
|
|
|
|
// تعیین وضعیت مرسوله بر اساس آخرین وضعیت
|
|
$lastState = strtolower($row['last_state'] ?? '');
|
|
$status = 'processed';
|
|
|
|
if (str_contains($lastState, 'delivered')) $status = 'delivered';
|
|
elseif (str_contains($lastState, 'in transit')) $status = 'in_transit';
|
|
elseif (str_contains($lastState, 'picked')) $status = 'picked_up';
|
|
elseif (str_contains($lastState, 'out for delivery')) $status = 'out_for_delivery';
|
|
elseif (str_contains($lastState, 'failed')) $status = 'failed';
|
|
|
|
// ایجاد مرسوله جدید با مقادیر پیشفرض
|
|
return Shipment::create([
|
|
'awb_no' => $awbNo,
|
|
'direction' => 'export',
|
|
'type' => 'PARCEL',
|
|
'status' => $status,
|
|
'weight' => 0,
|
|
'volumetric_weight' => 0,
|
|
'chargeable_weight' => 0,
|
|
'shipping_price' => 0,
|
|
'extra_service' => 0,
|
|
'packing_cost' => 0,
|
|
'domestic_pickup' => 0,
|
|
'domestic_delivery' => 0,
|
|
'warehousing_cost' => 0,
|
|
'vat_amount' => 0,
|
|
'discount' => 0,
|
|
'total_fee' => 0,
|
|
'net_dirham' => 0,
|
|
'net_rial' => 0,
|
|
'from_country_id' => Country::where('name', 'Iran')->first()?->id,
|
|
'to_country_id' => $country?->id,
|
|
'sender_name' => 'Unknown',
|
|
'receiver_name' => 'Unknown',
|
|
]);
|
|
}
|
|
|
|
// --- متدهای کمکی برای نرمالسازی دادهها ---
|
|
|
|
protected function normalizeAwb($value): ?string
|
|
{
|
|
if (!$value) return null;
|
|
$value = trim($value);
|
|
return $value === '' || $value === '0' ? null : $value;
|
|
}
|
|
|
|
protected function normalizeDate($value): ?string
|
|
{
|
|
if (!$value) return null;
|
|
|
|
if ($value instanceof \DateTime) {
|
|
return $value->format('Y-m-d');
|
|
}
|
|
|
|
$value = trim($value);
|
|
if ($value === '' || $value === '1899-12-31') return null;
|
|
|
|
try {
|
|
return date('Y-m-d', strtotime($value));
|
|
} catch (\Throwable $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
protected function normalizeTime($value): ?string
|
|
{
|
|
if (!$value) return null;
|
|
|
|
if ($value instanceof \DateTime) {
|
|
return $value->format('H:i:s');
|
|
}
|
|
|
|
$value = trim($value);
|
|
if ($value === '' || $value === '1899-12-31') return null;
|
|
|
|
try {
|
|
return date('H:i:s', strtotime($value));
|
|
} catch (\Throwable $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
protected function normalizeDescription($value): ?string
|
|
{
|
|
if (!$value) return null;
|
|
$value = trim($value);
|
|
return $value === '' ? null : $value;
|
|
}
|
|
|
|
protected function normalizeLocation($value): ?string
|
|
{
|
|
if (!$value) return null;
|
|
$value = trim($value);
|
|
return $value === '' || $value === '.' ? null : $value;
|
|
}
|
|
|
|
protected function normalizeDeliveryStatus($value): ?string
|
|
{
|
|
if (!$value) return null;
|
|
$value = trim($value);
|
|
if ($value === '') return null;
|
|
|
|
$statuses = [
|
|
'processed' => 'processed',
|
|
'picked up' => 'picked_up',
|
|
'in transit' => 'in_transit',
|
|
'out for delivery' => 'out_for_delivery',
|
|
'failed' => 'failed',
|
|
'delivered' => 'delivered',
|
|
'returned' => 'returned',
|
|
];
|
|
|
|
$lower = strtolower($value);
|
|
foreach ($statuses as $key => $status) {
|
|
if (str_contains($lower, $key)) {
|
|
return $status;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// --- متدهای دریافت آمار ---
|
|
|
|
public function getImportedEvents(): int
|
|
{
|
|
return $this->importedEvents;
|
|
}
|
|
|
|
public function getSkippedEvents(): int
|
|
{
|
|
return $this->skippedEvents;
|
|
}
|
|
|
|
public function getErrors(): array
|
|
{
|
|
return $this->errors;
|
|
}
|
|
|
|
public function getCreatedShipments(): int
|
|
{
|
|
return $this->createdShipments;
|
|
}
|
|
}
|