Refactor the shipping rate import process to support bidirectional data handling (import/export) and implement currency conversion using system settings. Update the price calculator to ensure valid zone data is retrieved. - Update `ShippingRatesImport` to handle both import and export directions via `SimpleRateSheetImport`. - Implement AED to IRR conversion during rate importation using `SystemSetting`. - Add validation for zone numbers and rate values during import. - Enhance `PriceCalculatorService` to filter for non-zero zone values. - Add various debug and testing scripts for pricing and data structure verification.
85 lines
3.2 KiB
PHP
85 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Enums\ShipmentType;
|
|
use App\Models\Country;
|
|
use App\Models\Shipment;
|
|
use App\Models\SystemSetting;
|
|
use InvalidArgumentException;
|
|
|
|
class PriceCalculatorService
|
|
{
|
|
public function calculate(array $data): array
|
|
{
|
|
$type = ShipmentType::from($data['type']);
|
|
$direction = $data['direction'] === 'Outbound' ? 'export' : 'import';
|
|
$chargeableWeight = max($data['weight'], $data['volumetric_weight']);
|
|
|
|
$country = Country::where('iso_code', $data['country_iso'])->firstOrFail();
|
|
|
|
$zone = match (true) {
|
|
$type === ShipmentType::Parcel && $direction === 'export' => $country->export_zone_parcel,
|
|
$type === ShipmentType::Parcel && $direction === 'import' => $country->import_zone_parcel,
|
|
$type !== ShipmentType::Parcel && $direction === 'export' => $country->export_zone_doc,
|
|
$type !== ShipmentType::Parcel && $direction === 'import' => $country->import_zone_doc,
|
|
};
|
|
|
|
$rate = $this->lookupRate($direction, $type, $chargeableWeight, $zone);
|
|
|
|
$profitMargin = (float) SystemSetting::get('profit_margin', 1.25);
|
|
$aedToIrr = (float) SystemSetting::get('aed_to_irr', 455000);
|
|
$vatRate = (float) SystemSetting::get('vat_rate', 0.09);
|
|
$packingCostDefault = (float) SystemSetting::get('packing_cost_default', 100000);
|
|
|
|
$netDirham = $rate * $profitMargin;
|
|
$netRial = $netDirham * $aedToIrr;
|
|
|
|
$extraService = (float) ($data['extra_service'] ?? 0);
|
|
$packingCost = (float) ($data['packing_cost'] ?? $packingCostDefault);
|
|
$domesticPickup = (float) ($data['domestic_pickup'] ?? 0);
|
|
$domesticDelivery = (float) ($data['domestic_delivery'] ?? 0);
|
|
$warehousingCost = (float) ($data['warehousing_cost'] ?? 0);
|
|
$discount = (float) ($data['discount'] ?? 0);
|
|
|
|
$subtotal = $netRial + $extraService + $packingCost + $domesticPickup + $domesticDelivery + $warehousingCost - $discount;
|
|
$totalFee = $subtotal * (1 + $vatRate);
|
|
$vatAmount = $totalFee - $subtotal;
|
|
|
|
return [
|
|
'base_price' => $rate,
|
|
'net_dirham' => $netDirham,
|
|
'net_rial' => $netRial,
|
|
'extra_service' => $extraService,
|
|
'packing_cost' => $packingCost,
|
|
'domestic_pickup' => $domesticPickup,
|
|
'domestic_delivery' => $domesticDelivery,
|
|
'warehousing_cost' => $warehousingCost,
|
|
'discount' => $discount,
|
|
'vat_amount' => $vatAmount,
|
|
'total_fee' => $totalFee,
|
|
'zone' => $zone,
|
|
'chargeable_weight' => $chargeableWeight,
|
|
];
|
|
}
|
|
|
|
private function lookupRate(string $direction, ShipmentType $type, float $weight, int $zone): float
|
|
{
|
|
$zoneColumn = 'zone_' . $zone;
|
|
|
|
$rate = \App\Models\ShippingRate::query()
|
|
->where('direction', $direction)
|
|
->where('type', $type->value)
|
|
->where('weight', '<=', $weight)
|
|
->where($zoneColumn, '>', 0)
|
|
->orderByDesc('weight')
|
|
->value($zoneColumn);
|
|
|
|
if ($rate === null) {
|
|
throw new InvalidArgumentException('No rate found for the given parameters.');
|
|
}
|
|
|
|
return (float) $rate;
|
|
}
|
|
}
|