ifnex/04_Laravel/app/Services/PriceCalculatorService.php

77 lines
3.2 KiB
PHP

<?php
namespace App\Services;
use App\Models\Country;
use App\Models\ShippingRate;
use App\Models\SystemSetting;
class PriceCalculatorService
{
/**
* محاسبه قیمت ارسال
*
* @param array $data (شامل: direction, type, origin_country_id, destination_country_id, weight, length, width, height)
* @return array
*/
public function calculate(array $data): array
{
// 1. محاسبه وزن حجمی (طبق استاندارد جهانی تقسیم بر 5000)
$dimensions = ($data['length'] * $data['width'] * $data['height']) / 5000;
// 2. تعیین وزن قابل پرداخت (ماکزیموم وزن واقعی و حجمی)
$chargeableWeight = max($data['weight'], $dimensions);
// 3. استخراج زون مقصد/مبدأ بر اساس جهت ارسال
if ($data['direction'] === 'export') {
// صادرات: زون صادرات کشور مقصد مد نظر است
$country = Country::find($data['destination_country_id']);
$zone = $country->export_zone;
} else {
// واردات: زون واردات کشور مبدأ مد نظر است
$country = Country::find($data['origin_country_id']);
$zone = $country->import_zone;
}
// 4. پیدا کردن ردیف تعرفه مناسب
// منطق: باید نزدیک‌ترین وزنی که بزرگتر مساوی وزن ماست رو پیدا کنیم (مثلاً اگر 1.2 کیلو است، ردیف 1.5 را می‌گیرد)
$rateRecord = ShippingRate::where('direction', $data['direction'])
->where('type', $data['type'])
->where('weight', '>=', $chargeableWeight)
->orderBy('weight', 'asc')
->first();
// اگر وزن بالای 30 کیلو باشد یا رکوردی پیدا نشود (Spot Rate)
if (!$rateRecord) {
return [
'status' => 'error',
'message' => 'برای این وزن نرخ ثبت نشده است (نیاز به استعلام نرخ ویژه / Spot Rate).',
'chargeable_weight' => $chargeableWeight,
'volumetric_weight' => $dimensions,
];
}
// 5. استخراج قیمت پایه بر اساس زون (مثلاً ستون zone_3)
$zoneColumn = "zone_{$zone}";
$basePriceDirham = $rateRecord->$zoneColumn;
// 6. دریافت نرخ ارز و ضریب سود از تنظیمات
$settings = SystemSetting::first();
$dirhamRate = $settings->dirham_rate; // نرخ درهم به ریال
$profitPercent = $settings->profit_percent; // مثلاً 1.25
// 7. اجرای فرمول نهایی (دقیقاً مطابق اکسل)
$netDirham = $basePriceDirham * $profitPercent;
$netRial = $netDirham * $dirhamRate;
return [
'status' => 'success',
'volumetric_weight' => round($dimensions, 3),
'chargeable_weight' => round($chargeableWeight, 2),
'zone' => $zone,
'base_price_dirham' => $basePriceDirham,
'net_dirham' => round($netDirham, 2),
'net_rial' => round($netRial),
];
}
}