149 lines
6.4 KiB
PHP
149 lines
6.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Infrastructure\Adapters\Serializers;
|
|
|
|
use Domain\Enums\ProductBrand;
|
|
use Domain\Enums\TaxRate;
|
|
use Domain\Enums\Units\OrderUnit;
|
|
use Domain\Models\Entities\Basket;
|
|
use Domain\Models\ValueObjects\BasketProduct;
|
|
use Domain\Models\ValueObjects\DiscountRate;
|
|
use Domain\Models\ValueObjects\Entities\BasketId;
|
|
use Domain\Models\ValueObjects\Entities\ProductId;
|
|
use Domain\Models\ValueObjects\IncoId;
|
|
use Illuminate\Support\Arr;
|
|
use Money\Currency;
|
|
use Money\Money;
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
class BasketSerializer
|
|
{
|
|
/** @return array<string,mixed> */
|
|
public function toArray(Basket $basket): array
|
|
{
|
|
return [
|
|
'id' => (string) $basket->id->value,
|
|
'items' => array_map(
|
|
fn (BasketProduct $item) => [
|
|
'id' => (string) $item->id->value,
|
|
'name' => $item->name,
|
|
'qty' => $item->qty,
|
|
'unitPriceHt' => $item->unitPriceHt,
|
|
'unitDiscount' => $item->unitDiscount,
|
|
'taxRate' => $item->taxRate->value,
|
|
'weightGrams' => $item->weightGrams,
|
|
'brand' => $item->brand?->value,
|
|
'incoId' => $item->incoId?->value,
|
|
'orderUnit' => $item->orderUnit->value,
|
|
'slug' => $item->slug,
|
|
'picture' => $item->picture,
|
|
'description' => $item->description,
|
|
'weightVariable' => $item->weightVariable,
|
|
'discountRateBp' => $item->discountRate->basisPoints(),
|
|
'priceKgTtc' => $item->priceKgTtc,
|
|
'options' => $item->options,
|
|
],
|
|
array_values($basket->items())
|
|
),
|
|
];
|
|
}
|
|
|
|
/** @param array<string,mixed> $data */
|
|
public function fromArray(array $data): Basket
|
|
{
|
|
$basketId = Arr::string($data, 'id');
|
|
$rawItems = Arr::array($data, 'items', []);
|
|
|
|
$hydratedItems = [];
|
|
|
|
foreach ($rawItems as $itemData) {
|
|
$itemData = Arr::wrap($itemData);
|
|
$id = Arr::string($itemData, 'id');
|
|
$name = Arr::string($itemData, 'name');
|
|
$qty = Arr::integer($itemData, 'qty');
|
|
$unitPriceHt = Arr::array($itemData, 'unitPriceHt');
|
|
$unitPriceHtCurrency = Arr::string($unitPriceHt, 'currency');
|
|
$unitDiscount = Arr::array($itemData, 'unitDiscount');
|
|
$unitDiscountCurrency = Arr::string($unitDiscount, 'currency');
|
|
$taxRate = Arr::integer($itemData, 'taxRate');
|
|
$weightGrams = Arr::integer($itemData, 'weightGrams');
|
|
$brand = Arr::get($itemData, 'brand'); // using get because it can be null
|
|
$incoId = Arr::get($itemData, 'incoId');
|
|
$orderUnit = Arr::string($itemData, 'orderUnit');
|
|
$slug = Arr::string($itemData, 'slug');
|
|
$picture = Arr::get($itemData, 'picture');
|
|
$description = Arr::get($itemData, 'description');
|
|
$weightVariable = Arr::boolean($itemData, 'weightVariable');
|
|
$discountRate = $this->hydrateDiscountRate($itemData);
|
|
$priceKgTtc = Arr::array($itemData, 'priceKgTtc');
|
|
$priceKgTtcCurrency = Arr::string($priceKgTtc, 'currency');
|
|
$options = Arr::array($itemData, 'options', []);
|
|
|
|
if (empty($unitPriceHtCurrency)) {
|
|
throw new \DomainException("Currency is required for unitPriceHt of item with id $id");
|
|
}
|
|
if (empty($unitDiscountCurrency)) {
|
|
throw new \DomainException("Currency is required for unitDiscount of item with id $id");
|
|
}
|
|
if (empty($priceKgTtcCurrency)) {
|
|
throw new \DomainException("Currency is required for priceKgTtc of item with id $id");
|
|
}
|
|
|
|
$hydratedItems[$id] = new BasketProduct(
|
|
id: new ProductId(Uuid::fromString($id)),
|
|
name: $name,
|
|
qty: $qty,
|
|
unitPriceHt: new Money(
|
|
is_scalar($a = Arr::get($unitPriceHt, 'amount', 0)) ? (int) $a : 0,
|
|
new Currency($unitPriceHtCurrency)
|
|
),
|
|
unitDiscount: new Money(
|
|
is_scalar($a = Arr::get($unitDiscount, 'amount', 0)) ? (int) $a : 0,
|
|
new Currency($unitDiscountCurrency)
|
|
),
|
|
taxRate: TaxRate::from($taxRate),
|
|
weightGrams: $weightGrams,
|
|
brand: is_string($brand) && $brand !== '' ? ProductBrand::from($brand) : null,
|
|
incoId: is_scalar($incoId) && $incoId !== 0 ? new IncoId((int) $incoId) : null,
|
|
orderUnit: OrderUnit::from($orderUnit),
|
|
slug: $slug,
|
|
picture: is_string($picture) && $picture !== '' ? $picture : null,
|
|
description: is_string($description) && $description !== '' ? $description : null,
|
|
weightVariable: $weightVariable,
|
|
discountRate: $discountRate,
|
|
priceKgTtc: new Money(
|
|
is_scalar($a = Arr::get($priceKgTtc, 'amount', 0)) ? (int) $a : 0,
|
|
new Currency($priceKgTtcCurrency)
|
|
),
|
|
options: $options
|
|
);
|
|
}
|
|
|
|
return new Basket(
|
|
id: new BasketId(Uuid::fromString($basketId)),
|
|
items: $hydratedItems
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Reads the discount rate in basis points; falls back to the legacy float ratio
|
|
* (key "discountRate") stored in sessions created before the DiscountRate value object.
|
|
*
|
|
* @param array<array-key,mixed> $itemData
|
|
*/
|
|
private function hydrateDiscountRate(array $itemData): DiscountRate
|
|
{
|
|
$basisPoints = Arr::get($itemData, 'discountRateBp');
|
|
if (is_int($basisPoints)) {
|
|
return DiscountRate::fromBasisPoints($basisPoints);
|
|
}
|
|
|
|
$legacyRatio = Arr::get($itemData, 'discountRate', 0.0);
|
|
|
|
return is_numeric($legacyRatio)
|
|
? DiscountRate::fromRatio(min(max((float) $legacyRatio, 0.0), 1.0))
|
|
: DiscountRate::zero();
|
|
}
|
|
}
|