diff --git a/src/Adder/DiscountAdjustmentsAdder.php b/src/Adder/DiscountAdjustmentsAdder.php
new file mode 100644
index 0000000..e4d2aa8
--- /dev/null
+++ b/src/Adder/DiscountAdjustmentsAdder.php
@@ -0,0 +1,46 @@
+integerDistributor->distribute($discount, $orderItem->getQuantity());
+ $units = $orderItem->getUnits();
+
+ /** @var int $discount */
+ foreach ($discounts as $i => $discount) {
+ /** @var AdjustmentInterface $adjustment */
+ $adjustment = $this->adjustmentFactory->createWithData(
+ $adjustmentType,
+ $label,
+ $discount,
+ );
+ $adjustment->setOriginCode($originCode);
+
+ /** @var OrderItemUnitInterface $unit */
+ $unit = $units->get($i);
+ $unit->addAdjustment($adjustment);
+ }
+ }
+}
diff --git a/src/Adder/DiscountAdjustmentsAdderInterface.php b/src/Adder/DiscountAdjustmentsAdderInterface.php
new file mode 100644
index 0000000..ea3a401
--- /dev/null
+++ b/src/Adder/DiscountAdjustmentsAdderInterface.php
@@ -0,0 +1,18 @@
+ [
'label' => false,
],
- 'getter' => function (AdjustableInterface &$adjustable): array {
- $adjustments = $adjustable->getAdjustments($this->adjustmentType)->toArray();
+ 'getter' =>
+ /** @param OrderItemInterface|OrderInterface $adjustable */
+ function (AdjustableInterface &$adjustable): array {
+ 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 {
- $adjustable->removeAdjustments($this->adjustmentType);
-
- /** @var int $discount */
- foreach ($discounts as $discount) {
- $adjustment = $this->adjustmentFactory->createWithData(
- $this->adjustmentType,
- $this->label,
- -1 * $discount,
- );
- $adjustable->addAdjustment($adjustment);
- }
+ $this->setDiscounts($adjustable, $discounts);
},
]);
}
+
+ abstract public function setDiscounts(AdjustableInterface $adjustable, array $discounts): void;
}
diff --git a/src/Form/Type/OrderDiscountCollectionType.php b/src/Form/Type/OrderDiscountCollectionType.php
index 61ed3b8..5412234 100644
--- a/src/Form/Type/OrderDiscountCollectionType.php
+++ b/src/Form/Type/OrderDiscountCollectionType.php
@@ -5,12 +5,30 @@
namespace Setono\SyliusOrderEditPlugin\Form\Type;
use Setono\SyliusOrderEditPlugin\Model\AdjustmentTypes;
+use Setono\SyliusOrderEditPlugin\Setter\OrderDiscountAdjustmentSetterInterface;
+use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Order\Factory\AdjustmentFactoryInterface;
+use Sylius\Component\Order\Model\AdjustableInterface;
+use Webmozart\Assert\Assert;
final class OrderDiscountCollectionType extends CustomDiscountCollectionType
{
- public function __construct(AdjustmentFactoryInterface $adjustmentFactory)
- {
+ public function __construct(
+ AdjustmentFactoryInterface $adjustmentFactory,
+ private readonly OrderDiscountAdjustmentSetterInterface $orderDiscountAdjustmentSetter,
+ ) {
parent::__construct($adjustmentFactory, 'Custom discount', AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT);
}
+
+ public function setDiscounts(AdjustableInterface $adjustable, array $discounts): void
+ {
+ Assert::isInstanceOf($adjustable, OrderInterface::class);
+
+ $adjustable->removeAdjustmentsRecursively($this->adjustmentType);
+
+ /** @var int $discount */
+ foreach ($discounts as $discount) {
+ $this->orderDiscountAdjustmentSetter->set($adjustable, $discount);
+ }
+ }
}
diff --git a/src/Form/Type/OrderItemDiscountCollectionType.php b/src/Form/Type/OrderItemDiscountCollectionType.php
index a6ef476..9b49205 100644
--- a/src/Form/Type/OrderItemDiscountCollectionType.php
+++ b/src/Form/Type/OrderItemDiscountCollectionType.php
@@ -4,13 +4,40 @@
namespace Setono\SyliusOrderEditPlugin\Form\Type;
+use Setono\SyliusOrderEditPlugin\Adder\DiscountAdjustmentsAdderInterface;
use Setono\SyliusOrderEditPlugin\Model\AdjustmentTypes;
+use Sylius\Component\Core\Model\OrderItemInterface;
use Sylius\Component\Order\Factory\AdjustmentFactoryInterface;
+use Sylius\Component\Order\Model\AdjustableInterface;
+use Webmozart\Assert\Assert;
final class OrderItemDiscountCollectionType extends CustomDiscountCollectionType
{
- public function __construct(AdjustmentFactoryInterface $adjustmentFactory)
- {
+ public function __construct(
+ AdjustmentFactoryInterface $adjustmentFactory,
+ private readonly DiscountAdjustmentsAdderInterface $discountAdjustmentsAdder,
+ ) {
parent::__construct($adjustmentFactory, 'Custom item discount', AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT);
}
+
+ /** @psalm-ignore-var $adjustable */
+ public function setDiscounts(AdjustableInterface $adjustable, array $discounts): void
+ {
+ Assert::isInstanceOf($adjustable, OrderItemInterface::class);
+
+ $adjustable->removeAdjustmentsRecursively($this->adjustmentType);
+ /** @var int $orderItemId */
+ $orderItemId = $adjustable->getId();
+
+ /** @var int $discount */
+ foreach ($discounts as $discount) {
+ $this->discountAdjustmentsAdder->add(
+ $adjustable,
+ $this->adjustmentType,
+ $this->adjustmentType . '_' . $orderItemId,
+ 'Custom item discount',
+ -$discount,
+ );
+ }
+ }
}
diff --git a/src/Resources/config/services/form.xml b/src/Resources/config/services/form.xml
index 460feea..f43a7d8 100644
--- a/src/Resources/config/services/form.xml
+++ b/src/Resources/config/services/form.xml
@@ -3,12 +3,13 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
-
+
%sylius.model.order_item.class%
%sylius.form.type.order_item.validation_groups%
-
@@ -17,6 +18,7 @@
class="Setono\SyliusOrderEditPlugin\Form\Type\OrderDiscountCollectionType"
>
+
@@ -25,12 +27,15 @@
class="Setono\SyliusOrderEditPlugin\Form\Type\OrderItemDiscountCollectionType"
>
+
-
+
diff --git a/src/Resources/config/services/order_processing.xml b/src/Resources/config/services/order_processing.xml
index 14e501b..9c8a21d 100644
--- a/src/Resources/config/services/order_processing.xml
+++ b/src/Resources/config/services/order_processing.xml
@@ -57,5 +57,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Setter/OrderDiscountAdjustmentSetter.php b/src/Setter/OrderDiscountAdjustmentSetter.php
new file mode 100644
index 0000000..d0f5396
--- /dev/null
+++ b/src/Setter/OrderDiscountAdjustmentSetter.php
@@ -0,0 +1,42 @@
+getItems();
+ /** @var int $orderId */
+ $orderId = $order->getId();
+
+ $distributedPrices = $this->integerDistributor->distribute($discount, $items->count());
+
+ /** @var int $distribution */
+ foreach ($distributedPrices as $i => $distribution) {
+ /** @var OrderItemInterface $item */
+ $item = $items->get($i);
+ $this->orderItemDiscountAdjustmentAdder->add(
+ $item,
+ AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT,
+ AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT . '_' . $orderId,
+ 'Custom order discount',
+ -$distribution,
+ );
+ }
+ }
+}
diff --git a/src/Setter/OrderDiscountAdjustmentSetterInterface.php b/src/Setter/OrderDiscountAdjustmentSetterInterface.php
new file mode 100644
index 0000000..579d372
--- /dev/null
+++ b/src/Setter/OrderDiscountAdjustmentSetterInterface.php
@@ -0,0 +1,12 @@
+
- {{ 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/Functional/OrderUpdateTest.php b/tests/Functional/OrderUpdateTest.php
index d7fe5d2..e9ab8cb 100644
--- a/tests/Functional/OrderUpdateTest.php
+++ b/tests/Functional/OrderUpdateTest.php
@@ -116,7 +116,7 @@ public function testItAllowsToAddAndRemoveDiscountsForTheWholeOrderMultipleTimes
/** @var EditableOrderInterface $order */
$order = $this->getOrderRepository()->findOneBy(['tokenValue' => 'TOKEN']);
self::assertSame($initialOrderTotalWithoutTaxes - 200, $this->getResultTotal($order));
- self::assertSame(-200, $order->getAdjustmentsTotal(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT));
+ self::assertSame(-200, $order->getAdjustmentsTotalRecursively(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT));
}
public function testItDoesNotAllowToExceedTheInitialOrderTotal(): void
@@ -157,10 +157,9 @@ public function testItAllowsToAddDiscountsForTheSpecificOrderItem(): void
/** @var OrderInterface $order */
$order = $this->getOrderRepository()->findOneBy(['tokenValue' => 'TOKEN']);
self::assertSame($initialOrderTotalWithoutTaxes - 100, $this->getResultTotal($order));
- self::assertSame(0, $order->getAdjustmentsTotal(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT));
self::assertSame(
-100,
- $order->getItems()->first()->getAdjustmentsTotal(AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT),
+ $order->getItems()->first()->getAdjustmentsTotalRecursively(AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT),
);
}
@@ -183,10 +182,9 @@ public function testItAllowsToAddAndRemoveDiscountsForTheOrderItemMultipleTimes(
/** @var EditableOrderInterface $order */
$order = $this->getOrderRepository()->findOneBy(['tokenValue' => 'TOKEN']);
self::assertSame($initialOrderTotalWithoutTaxes - 200, $this->getResultTotal($order));
- self::assertSame(0, $order->getAdjustmentsTotal(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT));
self::assertSame(
-200,
- $order->getItems()->first()->getAdjustmentsTotal(AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT),
+ $order->getItems()->first()->getAdjustmentsTotalRecursively(AdjustmentTypes::SETONO_ADMIN_ORDER_ITEM_DISCOUNT),
);
}
diff --git a/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php b/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php
new file mode 100644
index 0000000..a9c1ae8
--- /dev/null
+++ b/tests/Unit/Adder/DiscountAdjustmentsAdderTest.php
@@ -0,0 +1,67 @@
+prophesize(IntegerDistributorInterface::class);
+ $adjustmentFactory = $this->prophesize(AdjustmentFactoryInterface::class);
+
+ $item = $this->prophesize(OrderItemInterface::class);
+ $firstUnit = $this->prophesize(OrderItemUnitInterface::class);
+ $secondUnit = $this->prophesize(OrderItemUnitInterface::class);
+ $thirdUnit = $this->prophesize(OrderItemUnitInterface::class);
+
+ $adder = new DiscountAdjustmentsAdder(
+ $integerDistributor->reveal(),
+ $adjustmentFactory->reveal(),
+ );
+
+ $item->getQuantity()->willReturn(3);
+ $item->getUnits()->willReturn(new ArrayCollection(
+ [$firstUnit->reveal(), $secondUnit->reveal(), $thirdUnit->reveal()],
+ ));
+
+ $integerDistributor->distribute(-1000, 3)->willReturn([-333, -333, -334]);
+
+ $firstAdjustment = $this->prophesize(AdjustmentInterface::class);
+ $secondAdjustment = $this->prophesize(AdjustmentInterface::class);
+ $thirdAdjustment = $this->prophesize(AdjustmentInterface::class);
+
+ $adjustmentFactory
+ ->createWithData(AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, 'Label', -333)
+ ->willReturn($firstAdjustment->reveal(), $secondAdjustment->reveal())
+ ;
+ $adjustmentFactory
+ ->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, 'ORIGIN_CODE', 'Label', -1000);
+ }
+}
diff --git a/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php b/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php
new file mode 100644
index 0000000..74deb92
--- /dev/null
+++ b/tests/Unit/Setter/OrderDiscountAdjustmentSetterTest.php
@@ -0,0 +1,54 @@
+prophesize(IntegerDistributorInterface::class);
+ $orderItemDiscountAdjustmentAdder = $this->prophesize(DiscountAdjustmentsAdderInterface::class);
+
+ $setter = new OrderDiscountAdjustmentSetter(
+ $integerDistributor->reveal(),
+ $orderItemDiscountAdjustmentAdder->reveal(),
+ );
+
+ $order = $this->prophesize(EditableOrderInterface::class);
+ $firstItem = $this->prophesize(OrderItemInterface::class);
+ $secondItem = $this->prophesize(OrderItemInterface::class);
+ $order->getItems()->willReturn(new ArrayCollection([$firstItem->reveal(), $secondItem->reveal()]));
+ $order->getId()->willReturn(100);
+
+ $integerDistributor
+ ->distribute(1000, 2)
+ ->willReturn([500, 500])
+ ;
+
+ $orderItemDiscountAdjustmentAdder
+ ->add($firstItem->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT . '_100', 'Custom order discount', -500)
+ ->shouldBeCalled()
+ ;
+
+ $orderItemDiscountAdjustmentAdder
+ ->add($secondItem->reveal(), AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT, AdjustmentTypes::SETONO_ADMIN_ORDER_DISCOUNT . '_100', 'Custom order discount', -500)
+ ->shouldBeCalled()
+ ;
+
+ $setter->set($order->reveal(), 1000);
+ }
+}