diff --git a/composer.json b/composer.json index 592249a..bc23749 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "php": ">=8.1", "doctrine/orm": "^2.0 || ^3.0", "doctrine/persistence": "^2.0 || ^3.0", + "ramsey/uuid": "^4.7", "sylius/admin-bundle": "^1.0", "sylius/core": "^1.0", "sylius/core-bundle": "^1.0", diff --git a/psalm.xml b/psalm.xml index ab9fc1c..b21e566 100644 --- a/psalm.xml +++ b/psalm.xml @@ -29,4 +29,11 @@ + + + + + + + diff --git a/src/Adder/DiscountAdjustmentsAdder.php b/src/Adder/DiscountAdjustmentsAdder.php index f7bac55..e4d2aa8 100644 --- a/src/Adder/DiscountAdjustmentsAdder.php +++ b/src/Adder/DiscountAdjustmentsAdder.php @@ -18,8 +18,13 @@ public function __construct( ) { } - public function add(OrderItemInterface $orderItem, string $adjustmentType, int $discount): void - { + public function add( + OrderItemInterface $orderItem, + string $adjustmentType, + string $originCode, + string $label, + int $discount, + ): void { $discounts = $this->integerDistributor->distribute($discount, $orderItem->getQuantity()); $units = $orderItem->getUnits(); @@ -28,9 +33,10 @@ public function add(OrderItemInterface $orderItem, string $adjustmentType, int $ /** @var AdjustmentInterface $adjustment */ $adjustment = $this->adjustmentFactory->createWithData( $adjustmentType, - 'Custom discount', + $label, $discount, ); + $adjustment->setOriginCode($originCode); /** @var OrderItemUnitInterface $unit */ $unit = $units->get($i); diff --git a/src/Adder/DiscountAdjustmentsAdderInterface.php b/src/Adder/DiscountAdjustmentsAdderInterface.php index 4ad906d..ea3a401 100644 --- a/src/Adder/DiscountAdjustmentsAdderInterface.php +++ b/src/Adder/DiscountAdjustmentsAdderInterface.php @@ -8,5 +8,11 @@ interface DiscountAdjustmentsAdderInterface { - public function add(OrderItemInterface $orderItem, string $adjustmentType, int $discount): void; + public function add( + OrderItemInterface $orderItem, + string $adjustmentType, + string $originCode, + string $label, + int $discount, + ): void; } diff --git a/src/Form/Type/CustomDiscountCollectionType.php b/src/Form/Type/CustomDiscountCollectionType.php index f13bcee..25d6c0c 100644 --- a/src/Form/Type/CustomDiscountCollectionType.php +++ b/src/Form/Type/CustomDiscountCollectionType.php @@ -4,12 +4,16 @@ namespace Setono\SyliusOrderEditPlugin\Form\Type; +use Doctrine\Common\Collections\Collection; +use Sylius\Component\Core\Model\OrderInterface; +use Sylius\Component\Core\Model\OrderItemInterface; use Sylius\Component\Order\Factory\AdjustmentFactoryInterface; use Sylius\Component\Order\Model\AdjustableInterface; use Sylius\Component\Order\Model\AdjustmentInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\OptionsResolver\OptionsResolver; +use Webmozart\Assert\Assert; abstract class CustomDiscountCollectionType extends AbstractType { @@ -37,11 +41,26 @@ public function configureOptions(OptionsResolver $resolver): void 'label' => false, ], 'getter' => function (AdjustableInterface &$adjustable): array { - $adjustments = $adjustable->getAdjustments($this->adjustmentType)->toArray(); + Assert::isInstanceOfAny($adjustable, [OrderInterface::class, OrderItemInterface::class]); + /** @var Collection $adjustments */ + $adjustments = $adjustable->getAdjustmentsRecursively($this->adjustmentType); - return array_map(function (AdjustmentInterface $adjustment): int { - return -1 * $adjustment->getAmount(); - }, $adjustments); + $notDistributedAdjustments = []; + /** @var AdjustmentInterface $adjustment */ + foreach ($adjustments as $adjustment) { + /** @var string $originCode */ + $originCode = $adjustment->getOriginCode(); + + if (isset($notDistributedAdjustments[$originCode])) { + $notDistributedAdjustments[$originCode] += ($adjustment->getAmount()) * -1; + + continue; + } + + $notDistributedAdjustments[$originCode] = ($adjustment->getAmount()) * -1; + } + + return $notDistributedAdjustments; }, 'setter' => function (AdjustableInterface &$adjustable, array $discounts): void { $this->setDiscounts($adjustable, $discounts); diff --git a/src/Form/Type/OrderItemDiscountCollectionType.php b/src/Form/Type/OrderItemDiscountCollectionType.php index f1325c5..1089b25 100644 --- a/src/Form/Type/OrderItemDiscountCollectionType.php +++ b/src/Form/Type/OrderItemDiscountCollectionType.php @@ -4,6 +4,7 @@ namespace Setono\SyliusOrderEditPlugin\Form\Type; +use Ramsey\Uuid\Uuid; use Setono\SyliusOrderEditPlugin\Adder\DiscountAdjustmentsAdderInterface; use Setono\SyliusOrderEditPlugin\Model\AdjustmentTypes; use Sylius\Component\Core\Model\OrderItemInterface; @@ -26,9 +27,11 @@ public function setDiscounts(AdjustableInterface $adjustable, array $discounts): $adjustable->removeAdjustmentsRecursively($this->adjustmentType); + $originCode = Uuid::uuid4()->toString(); + /** @var int $discount */ foreach ($discounts as $discount) { - $this->discountAdjustmentsAdder->add($adjustable, $this->adjustmentType, -$discount); + $this->discountAdjustmentsAdder->add($adjustable, $this->adjustmentType, $originCode, 'Custom item discount', -$discount); } } } diff --git a/src/Setter/OrderDiscountAdjustmentSetter.php b/src/Setter/OrderDiscountAdjustmentSetter.php index e70c369..9ea2fab 100644 --- a/src/Setter/OrderDiscountAdjustmentSetter.php +++ b/src/Setter/OrderDiscountAdjustmentSetter.php @@ -4,6 +4,7 @@ namespace Setono\SyliusOrderEditPlugin\Setter; +use Ramsey\Uuid\Uuid; use Setono\SyliusOrderEditPlugin\Adder\DiscountAdjustmentsAdderInterface; use Setono\SyliusOrderEditPlugin\Model\AdjustmentTypes; use Sylius\Component\Core\Distributor\MinimumPriceDistributorInterface; @@ -27,6 +28,8 @@ public function set(OrderInterface $order, int $discount): void $distributedPrices = $this->minimumPriceDistributor->distribute($items->toArray(), $discount, $channel, true); + $originCode = Uuid::uuid4()->toString(); + /** @var int $distribution */ foreach ($distributedPrices as $i => $distribution) { /** @var OrderItemInterface $item */ @@ -34,6 +37,8 @@ public function set(OrderInterface $order, int $discount): void $this->orderItemDiscountAdjustmentAdder->add( $item, AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, + $originCode, + 'Custom order discount', -$distribution, ); } diff --git a/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_item.html.twig b/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_item.html.twig index daf5aa7..74d6efb 100644 --- a/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_item.html.twig +++ b/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_item.html.twig @@ -2,6 +2,7 @@ {% set orderPromotionAdjustment = constant('Sylius\\Component\\Core\\Model\\AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT') %} {% set unitPromotionAdjustment = constant('Sylius\\Component\\Core\\Model\\AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT') %} +{% set adminOrderDiscountAdjustment = constant('Setono\\SyliusOrderEditPlugin\\Model\\AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT') %} {% set adminOrderItemDiscountAdjustment = constant('Setono\\SyliusOrderEditPlugin\\Model\\AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT') %} {% set shippingAdjustment = constant('Sylius\\Component\\Core\\Model\\AdjustmentInterface::SHIPPING_ADJUSTMENT') %} {% set taxAdjustment = constant('Sylius\\Component\\Core\\Model\\AdjustmentInterface::TAX_ADJUSTMENT') %} @@ -23,13 +24,22 @@ {{ money.format(item.unitPrice, order.currencyCode) }} - {{ money.format(item.units.first.adjustmentsTotal(unitPromotionAdjustment), order.currencyCode) }} + {{ money.format( + item.units.first.adjustmentsTotal(unitPromotionAdjustment) + item.units.first.adjustmentsTotal(adminOrderItemDiscountAdjustment), + order.currencyCode + ) }} - ~ {{ money.format(item.units.first.adjustmentsTotal(orderPromotionAdjustment), order.currencyCode) }} + ~ {{ money.format( + item.units.first.adjustmentsTotal(orderPromotionAdjustment) + item.units.first.adjustmentsTotal(adminOrderDiscountAdjustment), + order.currencyCode + ) }} - {{ money.format(item.fullDiscountedUnitPrice, order.currencyCode) }} + {{ money.format( + item.fullDiscountedUnitPrice + item.units.first.adjustmentsTotal(adminOrderItemDiscountAdjustment) + item.units.first.adjustmentsTotal(adminOrderDiscountAdjustment), + order.currencyCode + ) }} {{ item.quantity }} @@ -49,14 +59,3 @@ {{ money.format(item.total, order.currencyCode) }} -{% set discounts = item.getAdjustments(adminOrderItemDiscountAdjustment) %} -{% if discounts is not empty %} - - - {{ 'setono_sylius_order_edit.ui.discounts'|trans }}: - {% for discount in discounts %} - {{ money.format(discount.amount, order.currencyCode) }}{% if not loop.last %}, {% endif %} - {% endfor %} - - -{% endif %} diff --git a/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_totalsPromotions.html.twig b/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_totalsPromotions.html.twig index 46db361..969d063 100644 --- a/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_totalsPromotions.html.twig +++ b/tests/Application/templates/bundles/SyliusAdminBundle/Order/Show/Summary/_totalsPromotions.html.twig @@ -3,12 +3,14 @@ {% set orderPromotionAdjustment = constant('Sylius\\Component\\Core\\Model\\AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT') %} {% set unitPromotionAdjustment = constant('Sylius\\Component\\Core\\Model\\AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT') %} {% set adminOrderDiscountAdjustment = constant('Setono\\SyliusOrderEditPlugin\\Model\\AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT') %} +{% set adminOrderItemDiscountAdjustment = constant('Setono\\SyliusOrderEditPlugin\\Model\\AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT') %} {% set orderPromotionAdjustments = sylius_aggregate_adjustments(order.getAdjustmentsRecursively(orderPromotionAdjustment)) %} {% set unitPromotionAdjustments = sylius_aggregate_adjustments(order.getAdjustmentsRecursively(unitPromotionAdjustment)) %} {% set adminOrderDiscountAdjustments = sylius_aggregate_adjustments(order.getAdjustmentsRecursively(adminOrderDiscountAdjustment)) %} + {% set adminOrderItemDiscountAdjustments = sylius_aggregate_adjustments(order.getAdjustmentsRecursively(adminOrderItemDiscountAdjustment)) %} {% set promotionAdjustments = orderPromotionAdjustments|merge(unitPromotionAdjustments)|merge(adminOrderDiscountAdjustments) %} {% if not promotionAdjustments is empty %}
@@ -28,7 +30,8 @@ {% set orderPromotionTotal = order.getAdjustmentsTotalRecursively(orderPromotionAdjustment) %} {% set unitPromotionTotal = order.getAdjustmentsTotalRecursively(unitPromotionAdjustment) %} {% set adminOrderDiscountTotal = order.getAdjustmentsTotalRecursively(adminOrderDiscountAdjustment) %} + {% set adminOrderItemDiscountTotal = order.getAdjustmentsTotalRecursively(adminOrderItemDiscountAdjustment) %} {{ 'sylius.ui.promotion_total'|trans }}: - {{ money.format(orderPromotionTotal + unitPromotionTotal + adminOrderDiscountTotal, order.currencyCode) }} + {{ money.format(orderPromotionTotal + unitPromotionTotal + adminOrderDiscountTotal + adminOrderItemDiscountTotal, order.currencyCode) }} diff --git a/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php b/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php index c7e5a1c..a9c1ae8 100644 --- a/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php +++ b/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php @@ -46,18 +46,22 @@ public function testItAddsDiscountAdjustmentsOnOrderItemUnits(): void $thirdAdjustment = $this->prophesize(AdjustmentInterface::class); $adjustmentFactory - ->createWithData(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, 'Custom discount', -333) + ->createWithData(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, 'Label', -333) ->willReturn($firstAdjustment->reveal(), $secondAdjustment->reveal()) ; $adjustmentFactory - ->createWithData(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, 'Custom discount', -334, ) + ->createWithData(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, 'Label', -334, ) ->willReturn($thirdAdjustment->reveal()) ; + $firstAdjustment->setOriginCode('ORIGIN_CODE')->shouldBeCalled(); + $secondAdjustment->setOriginCode('ORIGIN_CODE')->shouldBeCalled(); + $thirdAdjustment->setOriginCode('ORIGIN_CODE')->shouldBeCalled(); + $firstUnit->addAdjustment($firstAdjustment->reveal())->shouldBeCalled(); $secondUnit->addAdjustment($secondAdjustment->reveal())->shouldBeCalled(); $thirdUnit->addAdjustment($thirdAdjustment->reveal())->shouldBeCalled(); - $adder->add($item->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, -1000); + $adder->add($item->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, 'ORIGIN_CODE', 'Label', -1000); } } diff --git a/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php b/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php index 7cef13e..ca751f5 100644 --- a/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php +++ b/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php @@ -6,6 +6,7 @@ use Doctrine\Common\Collections\ArrayCollection; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Setono\SyliusOrderEditPlugin\Adder\DiscountAdjustmentsAdderInterface; use Setono\SyliusOrderEditPlugin\Entity\EditableOrderInterface; @@ -42,12 +43,12 @@ public function testItDistributesDiscountsOnOrderItemUnits(): void ; $orderItemDiscountAdjustmentAdder - ->add($firstItem->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, -400) + ->add($firstItem->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, Argument::type('string'), 'Custom order discount', -400) ->shouldBeCalled() ; $orderItemDiscountAdjustmentAdder - ->add($secondItem->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, -600) + ->add($secondItem->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, Argument::type('string'), 'Custom order discount', -600) ->shouldBeCalled() ;