205 lines
8.2 KiB
PHP
205 lines
8.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
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 Infrastructure\Adapters\Serializers\BasketSerializer;
|
|
use Money\Currency;
|
|
use Money\Money;
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
it('serializes and deserializes basket correctly', function () {
|
|
describe('BasketSerializer', function () {
|
|
// GIVEN
|
|
$serializer = new BasketSerializer();
|
|
|
|
$basketIdStr = \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
|
|
$productIdStr = \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
|
|
|
|
$basketProduct = new BasketProduct(
|
|
id: new ProductId(Uuid::fromString($productIdStr)),
|
|
name: 'Product 1',
|
|
qty: 2,
|
|
unitPriceHt: new Money(1000, new Currency('EUR')),
|
|
unitDiscount: new Money(100, new Currency('EUR')),
|
|
taxRate: TaxRate::TVA_20,
|
|
weightGrams: 500,
|
|
brand: ProductBrand::loue,
|
|
incoId: new IncoId(12345),
|
|
orderUnit: OrderUnit::PCE,
|
|
slug: 'product-1',
|
|
picture: 'pic.png',
|
|
description: 'desc',
|
|
weightVariable: true,
|
|
discountRate: DiscountRate::fromRatio(0.1),
|
|
priceKgTtc: new Money(2000, new Currency('EUR')),
|
|
options: ['color' => 'red']
|
|
);
|
|
|
|
$basket = new Basket(
|
|
id: new BasketId(Uuid::fromString($basketIdStr)),
|
|
items: [$productIdStr => $basketProduct]
|
|
);
|
|
|
|
// WHEN
|
|
$array = $serializer->toArray($basket);
|
|
$array = json_decode(json_encode($array), true);
|
|
$deserializedBasket = $serializer->fromArray($array);
|
|
|
|
// THEN
|
|
expect($array)->toBeArray()
|
|
->and($array['id'])->toBe($basketIdStr)
|
|
->and($array['items'][0]['id'])->toBe($productIdStr)
|
|
->and($array['items'][0]['name'])->toBe('Product 1')
|
|
->and($array['items'][0]['taxRate'])->toBe(TaxRate::TVA_20->value)
|
|
->and($deserializedBasket->id->value->toString())->toBe($basketIdStr)
|
|
->and($deserializedBasket->items())->toHaveCount(1)
|
|
->and($deserializedBasket->items()[$productIdStr]->name)->toBe('Product 1')
|
|
->and($deserializedBasket->items()[$productIdStr]->weightVariable)->toBeTrue()
|
|
->and($deserializedBasket->items()[$productIdStr]->options)->toBe(['color' => 'red'])
|
|
->and($array['items'][0]['discountRateBp'])->toBe(1000)
|
|
->and($deserializedBasket->items()[$productIdStr]->discountRate->basisPoints())->toBe(1000);
|
|
});
|
|
|
|
it('hydrates the discount rate from the legacy float ratio stored in older sessions', function (float $legacyRatio, int $expectedBasisPoints) {
|
|
// GIVEN
|
|
$serializer = new BasketSerializer();
|
|
$productIdStr = \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
|
|
$data = [
|
|
'id' => \Symfony\Component\Uid\Uuid::v7()->toRfc4122(),
|
|
'items' => [
|
|
[
|
|
'id' => $productIdStr,
|
|
'name' => 'Test',
|
|
'qty' => 1,
|
|
'unitPriceHt' => ['amount' => 1000, 'currency' => 'EUR'],
|
|
'unitDiscount' => ['amount' => 100, 'currency' => 'EUR'],
|
|
'taxRate' => TaxRate::TVA_20->value,
|
|
'weightGrams' => 500,
|
|
'orderUnit' => OrderUnit::PCE->value,
|
|
'slug' => 'test',
|
|
'weightVariable' => false,
|
|
'discountRate' => $legacyRatio,
|
|
'priceKgTtc' => ['amount' => 2000, 'currency' => 'EUR'],
|
|
],
|
|
],
|
|
];
|
|
|
|
// WHEN
|
|
$basket = $serializer->fromArray($data);
|
|
|
|
// THEN
|
|
expect($basket->items()[$productIdStr]->discountRate->basisPoints())->toBe($expectedBasisPoints);
|
|
})->with([
|
|
'regular ratio' => [0.15, 1500],
|
|
'no discount' => [0.0, 0],
|
|
'out of range value is clamped' => [20.0, 10000],
|
|
]);
|
|
|
|
it('throws exception if currency is missing during deserialization', function () {
|
|
// GIVEN
|
|
$serializer = new BasketSerializer();
|
|
$productIdStr = \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
|
|
$data = [
|
|
'id' => \Symfony\Component\Uid\Uuid::v7()->toRfc4122(),
|
|
'items' => [
|
|
[
|
|
'id' => $productIdStr,
|
|
'name' => 'Test',
|
|
'qty' => 1,
|
|
'unitPriceHt' => ['amount' => 1000, 'currency' => ''],
|
|
'unitDiscount' => ['amount' => 100, 'currency' => 'EUR'],
|
|
'taxRate' => TaxRate::TVA_20->value,
|
|
'weightGrams' => 500,
|
|
'orderUnit' => OrderUnit::PCE->value,
|
|
'slug' => 'test',
|
|
'weightVariable' => false,
|
|
'priceKgTtc' => ['amount' => 2000, 'currency' => 'EUR'],
|
|
],
|
|
],
|
|
];
|
|
|
|
// WHEN
|
|
$action = fn () => $serializer->fromArray($data);
|
|
|
|
// THEN
|
|
expect($action)->toThrow(
|
|
\DomainException::class,
|
|
'Currency is required for unitPriceHt of item with id ' . $productIdStr
|
|
);
|
|
});
|
|
|
|
it('throws exception if currency is missing for unitDiscount', function () {
|
|
// GIVEN
|
|
$serializer = new BasketSerializer();
|
|
$productIdStr = \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
|
|
$data = [
|
|
'id' => \Symfony\Component\Uid\Uuid::v7()->toRfc4122(),
|
|
'items' => [
|
|
[
|
|
'id' => $productIdStr,
|
|
'name' => 'Test',
|
|
'qty' => 1,
|
|
'unitPriceHt' => ['amount' => 1000, 'currency' => 'EUR'],
|
|
'unitDiscount' => ['amount' => 100, 'currency' => ''],
|
|
'taxRate' => TaxRate::TVA_20->value,
|
|
'weightGrams' => 500,
|
|
'orderUnit' => OrderUnit::PCE->value,
|
|
'slug' => 'test',
|
|
'weightVariable' => false,
|
|
'priceKgTtc' => ['amount' => 2000, 'currency' => 'EUR'],
|
|
],
|
|
],
|
|
];
|
|
|
|
// WHEN
|
|
$action = fn () => $serializer->fromArray($data);
|
|
|
|
// THEN
|
|
expect($action)->toThrow(
|
|
\DomainException::class,
|
|
'Currency is required for unitDiscount of item with id ' . $productIdStr
|
|
);
|
|
});
|
|
|
|
it('throws exception if currency is missing for priceKgTtc', function () {
|
|
// GIVEN
|
|
$serializer = new BasketSerializer();
|
|
$productIdStr = \Symfony\Component\Uid\Uuid::v7()->toRfc4122();
|
|
$data = [
|
|
'id' => \Symfony\Component\Uid\Uuid::v7()->toRfc4122(),
|
|
'items' => [
|
|
[
|
|
'id' => $productIdStr,
|
|
'name' => 'Test',
|
|
'qty' => 1,
|
|
'unitPriceHt' => ['amount' => 1000, 'currency' => 'EUR'],
|
|
'unitDiscount' => ['amount' => 100, 'currency' => 'EUR'],
|
|
'taxRate' => TaxRate::TVA_20->value,
|
|
'weightGrams' => 500,
|
|
'orderUnit' => OrderUnit::PCE->value,
|
|
'slug' => 'test',
|
|
'weightVariable' => false,
|
|
'priceKgTtc' => ['amount' => 2000, 'currency' => ''],
|
|
],
|
|
],
|
|
];
|
|
|
|
// WHEN
|
|
$action = fn () => $serializer->fromArray($data);
|
|
|
|
// THEN
|
|
expect($action)->toThrow(
|
|
\DomainException::class,
|
|
'Currency is required for priceKgTtc of item with id ' . $productIdStr
|
|
);
|
|
});
|
|
});
|