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, }; // 3. یافتن نرخ پایه $baseRate = $this->lookupRate($direction, $type, $chargeableWeight, $zone); // 4. محاسبات مالی (تبدیل ارز، سود، مالیات) $financials = $this->calculateFinancials($baseRate); // 5. جمع‌آوری هزینه‌های جانبی $extraCosts = $this->calculateExtraCosts($data); // 6. محاسبه قیمت قبل از تخفیف $subtotal = $financials['net_rial'] + array_sum($extraCosts); // 7. اعمال کد تخفیف $discountResult = $this->applyDiscount($subtotal, $data['discount_code'] ?? null); if ($discountResult['success']) { // افزایش شمارنده استفاده از کد تخفیف DiscountCode::where('code', $discountResult['discount_code'])->increment('used_count'); } // 8. محاسبه مالیات و قیمت نهایی $vatRate = (float) SystemSetting::get('vat_rate', 0.09); $finalPrice = $discountResult['final_price']; $vatAmount = $finalPrice * $vatRate; $totalFee = $finalPrice + $vatAmount; // 9. بازگرداندن نتیجه نهایی return [ 'base_price' => $baseRate, 'net_dirham' => $financials['net_dirham'], 'net_rial' => $financials['net_rial'], 'extra_service' => $extraCosts['extra_service'], 'packing_cost' => $extraCosts['packing_cost'], 'domestic_pickup' => $extraCosts['domestic_pickup'], 'domestic_delivery' => $extraCosts['domestic_delivery'], 'warehousing_cost' => $extraCosts['warehousing_cost'], 'discount_applied' => $discountResult['success'], 'discount_amount' => $discountResult['discount_amount'], 'discount_message' => $discountResult['message'], 'vat_amount' => $vatAmount, 'total_fee' => $totalFee, 'zone' => $zone, 'chargeable_weight' => $chargeableWeight, ]; } /** * محاسبه ارزش مالی نرخ پایه (با اعمال حاشیه سود و تبدیل ارز) * * @param float $baseRate نرخ پایه به درهم * @return array ['net_dirham' => float, 'net_rial' => float] */ private function calculateFinancials(float $baseRate): array { $profitMargin = (float) SystemSetting::get('profit_margin', 1.25); $aedToIrr = (float) SystemSetting::get('aed_to_irr', 455000); $netDirham = $baseRate * $profitMargin; $netRial = $netDirham * $aedToIrr; return [ 'net_dirham' => $netDirham, 'net_rial' => $netRial, ]; } /** * محاسبه مجموع هزینه‌های جانبی * * @param array $data داده‌های ورودی * @return array آرایه‌ای شامل هزینه‌های جانبی */ private function calculateExtraCosts(array $data): array { $packingCostDefault = (float) SystemSetting::get('packing_cost_default', 100000); return [ 'extra_service' => (float) ($data['extra_service'] ?? 0), 'packing_cost' => (float) ($data['packing_cost'] ?? $packingCostDefault), 'domestic_pickup' => (float) ($data['domestic_pickup'] ?? 0), 'domestic_delivery' => (float) ($data['domestic_delivery'] ?? 0), 'warehousing_cost' => (float) ($data['warehousing_cost'] ?? 0), ]; } /** * اعمال کد تخفیف روی قیمت نهایی * * @param float $totalPrice قیمت کل قبل از تخفیف * @param string|null $code کد تخفیف وارد شده توسط کاربر * @return array ['success' => bool, 'message' => string, 'discount_amount' => float, 'final_price' => float] */ public function applyDiscount(float $totalPrice, ?string $code): array { if (empty($code)) { return [ 'success' => false, 'message' => 'کد تخفیف وارد نشده است.', 'discount_amount' => 0, 'final_price' => $totalPrice, ]; } $discount = DiscountCode::where('code', $code)->first(); // 1. بررسی وجود کد if (!$discount) { return [ 'success' => false, 'message' => 'کد تخفیف نامعتبر است.', 'discount_amount' => 0, 'final_price' => $totalPrice, ]; } // 2. بررسی فعال بودن کد if (!$discount->is_active) { return [ 'success' => false, 'message' => 'این کد تخفیف غیرفعال شده است.', 'discount_amount' => 0, 'final_price' => $totalPrice, ]; } // 3. بررسی تاریخ انقضا if ($discount->expires_at && $discount->expires_at->isPast()) { return [ 'success' => false, 'message' => 'این کد تخفیف منقضی شده است.', 'discount_amount' => 0, 'final_price' => $totalPrice, ]; } // 4. بررسی حداقل مبلغ سفارش if ($discount->min_order_amount > 0 && $totalPrice < $discount->min_order_amount) { return [ 'success' => false, 'message' => "حداقل مبلغ سفارش برای استفاده از این کد " . number_format($discount->min_order_amount) . " ریال است.", 'discount_amount' => 0, 'final_price' => $totalPrice, ]; } // 5. بررسی محدودیت استفاده if ($discount->usage_limit && $discount->used_count >= $discount->usage_limit) { return [ 'success' => false, 'message' => 'ظرفیت استفاده از این کد تخفیف به پایان رسیده است.', 'discount_amount' => 0, 'final_price' => $totalPrice, ]; } // محاسبه مبلغ تخفیف $discountAmount = 0; if ($discount->type === 'percentage') { $discountAmount = ($totalPrice * $discount->value) / 100; } elseif ($discount->type === 'fixed') { $discountAmount = $discount->value; } // اطمینان از اینکه تخفیف بیشتر از مبلغ کل نشود $discountAmount = min($discountAmount, $totalPrice); $finalPrice = $totalPrice - $discountAmount; return [ 'success' => true, 'message' => 'کد تخفیف با موفقیت اعمال شد.', 'discount_amount' => $discountAmount, 'final_price' => $finalPrice, 'discount_code' => $discount->code, // برای ذخیره در سفارش ]; } /** * جستجوی نرخ حمل و نقل در دیتابیس * * @param string $direction جهت ارسال (export/import) * @param ShipmentType $type نوع سرویس * @param float $weight وزن قابل پرداخت * @param int $zone شماره زون * @return float نرخ پیدا شده * * @throws InvalidArgumentException اگر نرخی یافت نشود */ 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; } }