89 lines
2.5 KiB
PHP
89 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\ShoppingOrder;
|
|
use InvalidArgumentException;
|
|
|
|
class DhlShipmentWeightCalculator
|
|
{
|
|
public const DEFAULT_WEIGHT_KG = 1.0;
|
|
|
|
public const DEFAULT_MAX_WEIGHT_KG = 31.5;
|
|
|
|
public const PRODUCT_MAX_WEIGHTS_KG = [
|
|
'V01PAK' => 31.5,
|
|
'V53PAK' => 31.5,
|
|
'V62KP' => 1.0,
|
|
];
|
|
|
|
public function calculate(ShoppingOrder $order): float
|
|
{
|
|
$this->loadOrderItems($order);
|
|
|
|
$baseWeightGrams = max((int) ($order->weight ?? 0), 0);
|
|
$compensationWeightGrams = $this->calculateCompensationWeightGrams($order);
|
|
$totalWeightGrams = $baseWeightGrams + $compensationWeightGrams;
|
|
|
|
if ($totalWeightGrams <= 0) {
|
|
return self::DEFAULT_WEIGHT_KG;
|
|
}
|
|
|
|
return $this->roundWeightKg($totalWeightGrams / 1000);
|
|
}
|
|
|
|
public function getMaxWeightKgForProduct(?string $productCode): float
|
|
{
|
|
$productCode = strtoupper(trim((string) $productCode));
|
|
|
|
return self::PRODUCT_MAX_WEIGHTS_KG[$productCode] ?? self::DEFAULT_MAX_WEIGHT_KG;
|
|
}
|
|
|
|
public function assertWithinProductLimit(float $weightKg, ?string $productCode): void
|
|
{
|
|
$maxWeightKg = $this->getMaxWeightKgForProduct($productCode);
|
|
|
|
if ($weightKg > $maxWeightKg) {
|
|
throw new InvalidArgumentException(sprintf(
|
|
'Gewicht %.3f kg ueberschreitet das DHL-Maximalgewicht fuer %s (%.1f kg).',
|
|
$weightKg,
|
|
$productCode ?: 'das gewaehlte Produkt',
|
|
$maxWeightKg
|
|
));
|
|
}
|
|
}
|
|
|
|
private function calculateCompensationWeightGrams(ShoppingOrder $order): int
|
|
{
|
|
$items = $order->shopping_order_items ?? collect();
|
|
$weightGrams = 0;
|
|
|
|
foreach ($items as $item) {
|
|
if ((int) ($item->comp ?? 0) <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$productWeight = (int) ($item->product?->weight ?? 0);
|
|
if ($productWeight <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$quantity = max((int) ($item->qty ?? 1), 1);
|
|
$weightGrams += $productWeight * $quantity;
|
|
}
|
|
|
|
return $weightGrams;
|
|
}
|
|
|
|
private function roundWeightKg(float $weightKg): float
|
|
{
|
|
return round(max($weightKg, 0.1), 3);
|
|
}
|
|
|
|
private function loadOrderItems(ShoppingOrder $order): void
|
|
{
|
|
if ($order->exists && ! $order->relationLoaded('shopping_order_items')) {
|
|
$order->loadMissing('shopping_order_items.product');
|
|
}
|
|
}
|
|
}
|