diff --git a/spec/Provider/OrderItemNonNeutralTaxesProviderSpec.php b/spec/Provider/OrderItemNonNeutralTaxesProviderSpec.php deleted file mode 100644 index 89d14d3d..00000000 --- a/spec/Provider/OrderItemNonNeutralTaxesProviderSpec.php +++ /dev/null @@ -1,45 +0,0 @@ -getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) - ->willReturn(new ArrayCollection([$adjustment->getWrappedObject()])); - - $adjustment->isNeutral()->willReturn(true); - $adjustment->getAmount()->shouldNotBeCalled(); - - $orderItem->getUnits()->willReturn(new ArrayCollection([$orderItemUnit->getWrappedObject()])); - $orderItemUnit->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) - ->willReturn(new ArrayCollection([$unitAdjustment->getWrappedObject()])); - - $unitAdjustment->isNeutral()->willReturn(false); - $unitAdjustment->getAmount()->willReturn(20); - - $this->provide($orderItem)->shouldReturn([20]); - } -} diff --git a/spec/Provider/OrderItemTaxesProviderSpec.php b/spec/Provider/OrderItemTaxesProviderSpec.php new file mode 100644 index 00000000..57089fbf --- /dev/null +++ b/spec/Provider/OrderItemTaxesProviderSpec.php @@ -0,0 +1,259 @@ +getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$neutralAdjustment->getWrappedObject()])) + ; + $orderItem->getQuantity()->shouldBeCalled()->willReturn(3); + + $neutralAdjustment->isNeutral()->willReturn(true); + $neutralAdjustment->getAmount()->willReturn(332); + + $orderItem + ->getUnits() + ->willReturn(new ArrayCollection([ + $firstOrderItemUnit->getWrappedObject(), + $secondOrderItemUnit->getWrappedObject(), + $thirdOrderItemUnit->getWrappedObject(), + ])) + ; + + $firstOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->willReturn(new ArrayCollection([])) + ; + $firstOrderItemUnit->getId()->shouldBeCalled()->willReturn(100); + + $secondOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->willReturn(new ArrayCollection([])) + ; + $secondOrderItemUnit->getId()->shouldBeCalled()->willReturn(101); + + $thirdOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->willReturn(new ArrayCollection([])) + ; + $thirdOrderItemUnit->getId()->shouldBeCalled()->willReturn(102); + + $this->provide($orderItem)->shouldReturn([ + 'total' => 332, + 'itemTaxes' => [ + '100' => [0 => 0, 1 => 111], + '101' => [0 => 0, 1 => 111], + '102' => [0 => 0, 1 => 110], + ], + ]); + } + + function it_allocates_non_neutral_order_item_taxes_to_the_units( + OrderItemInterface $orderItem, + AdjustmentInterface $nonNeutralAdjustment, + OrderItemUnitInterface $firstOrderItemUnit, + OrderItemUnitInterface $secondOrderItemUnit, + OrderItemUnitInterface $thirdOrderItemUnit, + ): void { + $orderItem + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$nonNeutralAdjustment->getWrappedObject()])) + ; + $orderItem->getQuantity()->shouldBeCalled()->willReturn(3); + + $nonNeutralAdjustment->isNeutral()->willReturn(false); + $nonNeutralAdjustment->getAmount()->willReturn(557); + + $orderItem + ->getUnits() + ->willReturn(new ArrayCollection([ + $firstOrderItemUnit->getWrappedObject(), + $secondOrderItemUnit->getWrappedObject(), + $thirdOrderItemUnit->getWrappedObject(), + ])) + ; + + $firstOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->willReturn(new ArrayCollection([])) + ; + $firstOrderItemUnit->getId()->shouldBeCalled()->willReturn(100); + + $secondOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->willReturn(new ArrayCollection([])) + ; + $secondOrderItemUnit->getId()->shouldBeCalled()->willReturn(101); + + $thirdOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->willReturn(new ArrayCollection([])) + ; + $thirdOrderItemUnit->getId()->shouldBeCalled()->willReturn(102); + + $this->provide($orderItem)->shouldReturn([ + 'total' => 557, + 'itemTaxes' => [ + '100' => [0 => 186, 1 => 0], + '101' => [0 => 186, 1 => 0], + '102' => [0 => 185, 1 => 0], + ], + ]); + } + + function it_provides_non_neutral_tax_based_on_given_order_item( + OrderItemInterface $orderItem, + OrderItemUnitInterface $firstOrderItemUnit, + OrderItemUnitInterface $secondOrderItemUnit, + OrderItemUnitInterface $thirdOrderItemUnit, + AdjustmentInterface $firstNonNeutralAdjustment, + AdjustmentInterface $secondNonNeutralAdjustment, + AdjustmentInterface $thirdNonNeutralAdjustment, + ): void { + $orderItem + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([])) + ; + $orderItem->getQuantity()->shouldBeCalled()->willReturn(3); + $orderItem + ->getUnits() + ->willReturn(new ArrayCollection([ + $firstOrderItemUnit->getWrappedObject(), + $secondOrderItemUnit->getWrappedObject(), + $thirdOrderItemUnit->getWrappedObject(), + ])) + ; + + $firstOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$firstNonNeutralAdjustment->getWrappedObject()])) + ; + $firstOrderItemUnit->getId()->shouldBeCalled()->willReturn(100); + + $secondOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$secondNonNeutralAdjustment->getWrappedObject()])) + ; + $secondOrderItemUnit->getId()->shouldBeCalled()->willReturn(101); + + $thirdOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$thirdNonNeutralAdjustment->getWrappedObject()])) + ; + $thirdOrderItemUnit->getId()->shouldBeCalled()->willReturn(102); + + $firstNonNeutralAdjustment->isNeutral()->shouldBeCalled()->willReturn(false); + $firstNonNeutralAdjustment->getAmount()->shouldBeCalled()->willReturn(20); + + $secondNonNeutralAdjustment->isNeutral()->shouldBeCalled()->willReturn(false); + $secondNonNeutralAdjustment->getAmount()->shouldBeCalled()->willReturn(20); + + $thirdNonNeutralAdjustment->isNeutral()->shouldBeCalled()->willReturn(false); + $thirdNonNeutralAdjustment->getAmount()->shouldBeCalled()->willReturn(19); + + $this->provide($orderItem)->shouldReturn([ + 'total' => 59, + 'itemTaxes' => [ + '100' => [0 => 20, 1 => 0], + '101' => [0 => 20, 1 => 0], + '102' => [0 => 19, 1 => 0], + ], + ]); + } + + function it_provides_neutral_tax_based_on_given_order_item( + OrderItemInterface $orderItem, + OrderItemUnitInterface $firstOrderItemUnit, + OrderItemUnitInterface $secondOrderItemUnit, + OrderItemUnitInterface $thirdOrderItemUnit, + AdjustmentInterface $firstNeutralAdjustment, + AdjustmentInterface $secondNeutralAdjustment, + AdjustmentInterface $thirdNeutralAdjustment, + ): void { + $orderItem + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([])) + ; + $orderItem->getQuantity()->shouldBeCalled()->willReturn(3); + $orderItem + ->getUnits() + ->willReturn(new ArrayCollection([ + $firstOrderItemUnit->getWrappedObject(), + $secondOrderItemUnit->getWrappedObject(), + $thirdOrderItemUnit->getWrappedObject(), + ])) + ; + + $firstOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$firstNeutralAdjustment->getWrappedObject()])) + ; + $firstOrderItemUnit->getId()->shouldBeCalled()->willReturn(100); + + $secondOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$secondNeutralAdjustment->getWrappedObject()])) + ; + $secondOrderItemUnit->getId()->shouldBeCalled()->willReturn(101); + + $thirdOrderItemUnit + ->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) + ->shouldBeCalled() + ->willReturn(new ArrayCollection([$thirdNeutralAdjustment->getWrappedObject()])) + ; + $thirdOrderItemUnit->getId()->shouldBeCalled()->willReturn(102); + + $firstNeutralAdjustment->isNeutral()->shouldBeCalled()->willReturn(true); + $firstNeutralAdjustment->getAmount()->shouldBeCalled()->willReturn(30); + + $secondNeutralAdjustment->isNeutral()->shouldBeCalled()->willReturn(true); + $secondNeutralAdjustment->getAmount()->shouldBeCalled()->willReturn(29); + + $thirdNeutralAdjustment->isNeutral()->shouldBeCalled()->willReturn(true); + $thirdNeutralAdjustment->getAmount()->shouldBeCalled()->willReturn(29); + + $this->provide($orderItem)->shouldReturn([ + 'total' => 88, + 'itemTaxes' => [ + '100' => [0 => 0, 1 => 30], + '101' => [0 => 0, 1 => 29], + '102' => [0 => 0, 1 => 29], + ], + ]); + } +} diff --git a/spec/Provider/PayPalItemDataProviderSpec.php b/spec/Provider/PayPalItemDataProviderSpec.php index cfa26423..ea39fcf8 100644 --- a/spec/Provider/PayPalItemDataProviderSpec.php +++ b/spec/Provider/PayPalItemDataProviderSpec.php @@ -17,19 +17,19 @@ use PhpSpec\ObjectBehavior; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\OrderItemInterface; -use Sylius\PayPalPlugin\Provider\OrderItemNonNeutralTaxesProviderInterface; +use Sylius\PayPalPlugin\Provider\OrderItemTaxesProviderInterface; final class PayPalItemDataProviderSpec extends ObjectBehavior { - function let(OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider): void + function let(OrderItemTaxesProviderInterface $orderItemTaxesProvider): void { - $this->beConstructedWith($orderItemNonNeutralTaxesProvider); + $this->beConstructedWith($orderItemTaxesProvider); } - function it_returns_array_of_items_with_tax( + function it_returns_array_of_items_with_non_neutral_tax( OrderInterface $order, OrderItemInterface $orderItem, - OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, ): void { $order->getItems()->willReturn(new ArrayCollection([$orderItem->getWrappedObject()])); $orderItem->getProductName()->willReturn('PRODUCT_ONE'); @@ -38,7 +38,10 @@ function it_returns_array_of_items_with_tax( $orderItem->getUnitPrice()->willReturn(2000); $orderItem->getQuantity()->willReturn(1); - $orderItemNonNeutralTaxesProvider->provide($orderItem)->willReturn([200]); + $orderItemTaxesProvider->provide($orderItem)->willReturn([ + 'total' => 200, + 'itemTaxes' => [1 => [0 => 200, 1 => 0]], + ]); $this->provide($order)->shouldReturn( [ @@ -62,10 +65,49 @@ function it_returns_array_of_items_with_tax( ); } - function it_returns_array_of_items_with_different_quantities_with_tax( + function it_returns_array_of_items_with_neutral_tax( OrderInterface $order, OrderItemInterface $orderItem, - OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, + ): void { + $order->getItems()->willReturn(new ArrayCollection([$orderItem->getWrappedObject()])); + $orderItem->getProductName()->willReturn('PRODUCT_ONE'); + $order->getCurrencyCode()->willReturn('PLN'); + + $orderItem->getUnitPrice()->willReturn(2000); + $orderItem->getQuantity()->willReturn(1); + + $orderItemTaxesProvider->provide($orderItem)->willReturn([ + 'total' => 200, + 'itemTaxes' => [1 => [0 => 0, 1 => 200]], + ]); + + $this->provide($order)->shouldReturn( + [ + 'items' => [ + [ + 'name' => 'PRODUCT_ONE', + 'unit_amount' => [ + 'value' => '18.00', + 'currency_code' => 'PLN', + ], + 'quantity' => 1, + 'tax' => [ + 'value' => '2.00', + 'currency_code' => 'PLN', + ], + ], + ], + 'total_item_value' => '18.00', + 'total_tax' => '2.00', + ], + ); + } + + function it_returns_array_of_items_with_different_quantities_with_non_neutral_tax( + OrderInterface $order, + OrderItemInterface $orderItem, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, ): void { $order->getItems()->willReturn(new ArrayCollection([$orderItem->getWrappedObject()])); $orderItem->getProductName()->willReturn('PRODUCT_ONE'); @@ -74,7 +116,14 @@ function it_returns_array_of_items_with_different_quantities_with_tax( $orderItem->getUnitPrice()->willReturn(2000); $orderItem->getQuantity()->willReturn(3); - $orderItemNonNeutralTaxesProvider->provide($orderItem)->willReturn([200, 200, 200]); + $orderItemTaxesProvider->provide($orderItem)->willReturn([ + 'total' => 600, + 'itemTaxes' => [ + 1 => [0 => 200, 1 => 0], + 2 => [0 => 200, 1 => 0], + 3 => [0 => 200, 1 => 0], + ], + ]); $this->provide($order)->shouldReturn( [ @@ -122,10 +171,77 @@ function it_returns_array_of_items_with_different_quantities_with_tax( ); } + function it_returns_array_of_items_with_different_quantities_with_neutral_tax( + OrderInterface $order, + OrderItemInterface $orderItem, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, + ): void { + $order->getItems()->willReturn(new ArrayCollection([$orderItem->getWrappedObject()])); + $orderItem->getProductName()->willReturn('PRODUCT_ONE'); + $order->getCurrencyCode()->willReturn('PLN'); + + $orderItem->getUnitPrice()->willReturn(2000); + $orderItem->getQuantity()->willReturn(3); + + $orderItemTaxesProvider->provide($orderItem)->willReturn([ + 'total' => 600, + 'itemTaxes' => [ + 1 => [0 => 0, 1 => 200], + 2 => [0 => 0, 1 => 200], + 3 => [0 => 0, 1 => 200], + ], + ]); + + $this->provide($order)->shouldReturn( + [ + 'items' => [ + [ + 'name' => 'PRODUCT_ONE', + 'unit_amount' => [ + 'value' => '18.00', + 'currency_code' => 'PLN', + ], + 'quantity' => 1, + 'tax' => [ + 'value' => '2.00', + 'currency_code' => 'PLN', + ], + ], + [ + 'name' => 'PRODUCT_ONE', + 'unit_amount' => [ + 'value' => '18.00', + 'currency_code' => 'PLN', + ], + 'quantity' => 1, + 'tax' => [ + 'value' => '2.00', + 'currency_code' => 'PLN', + ], + ], + [ + 'name' => 'PRODUCT_ONE', + 'unit_amount' => [ + 'value' => '18.00', + 'currency_code' => 'PLN', + ], + 'quantity' => 1, + 'tax' => [ + 'value' => '2.00', + 'currency_code' => 'PLN', + ], + ], + ], + 'total_item_value' => '54.00', + 'total_tax' => '6.00', + ], + ); + } + function it_returns_array_of_items_with_different_quantities_without_tax( OrderInterface $order, OrderItemInterface $orderItem, - OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, ): void { $order->getItems()->willReturn(new ArrayCollection([$orderItem->getWrappedObject()])); $orderItem->getProductName()->willReturn('PRODUCT_ONE'); @@ -134,7 +250,7 @@ function it_returns_array_of_items_with_different_quantities_without_tax( $orderItem->getUnitPrice()->willReturn(2000); $orderItem->getQuantity()->willReturn(3); - $orderItemNonNeutralTaxesProvider->provide($orderItem)->willReturn([0]); + $orderItemTaxesProvider->provide($orderItem)->willReturn(['total' => 0]); $this->provide($order)->shouldReturn( [ @@ -162,7 +278,7 @@ function it_returns_array_of_different_items_with_different_quantities_without_t OrderInterface $order, OrderItemInterface $orderItemOne, OrderItemInterface $orderItemTwo, - OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, ): void { $order->getItems() ->willReturn(new ArrayCollection([$orderItemOne->getWrappedObject(), $orderItemTwo->getWrappedObject()])); @@ -176,8 +292,8 @@ function it_returns_array_of_different_items_with_different_quantities_without_t $order->getCurrencyCode()->willReturn('PLN'); - $orderItemNonNeutralTaxesProvider->provide($orderItemOne)->willReturn([0]); - $orderItemNonNeutralTaxesProvider->provide($orderItemTwo)->willReturn([0]); + $orderItemTaxesProvider->provide($orderItemOne)->willReturn(['total' => 0]); + $orderItemTaxesProvider->provide($orderItemTwo)->willReturn(['total' => 0]); $this->provide($order)->shouldReturn( [ @@ -213,11 +329,11 @@ function it_returns_array_of_different_items_with_different_quantities_without_t ); } - function it_returns_array_of_different_items_with_different_quantities_with_tax( + function it_returns_array_of_different_items_with_different_quantities_with_different_taxes( OrderInterface $order, OrderItemInterface $orderItemOne, OrderItemInterface $orderItemTwo, - OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider, + OrderItemTaxesProviderInterface $orderItemTaxesProvider, ): void { $order->getItems()->willReturn(new ArrayCollection([$orderItemOne->getWrappedObject(), $orderItemTwo->getWrappedObject()])); $orderItemOne->getProductName()->willReturn('PRODUCT_ONE'); @@ -230,8 +346,21 @@ function it_returns_array_of_different_items_with_different_quantities_with_tax( $order->getCurrencyCode()->willReturn('PLN'); - $orderItemNonNeutralTaxesProvider->provide($orderItemOne)->willReturn([100, 100, 100]); - $orderItemNonNeutralTaxesProvider->provide($orderItemTwo)->willReturn([200, 100]); + $orderItemTaxesProvider->provide($orderItemOne)->willReturn([ + 'total' => 300, + 'itemTaxes' => [ + 1 => [0 => 100, 1 => 0], + 2 => [0 => 100, 1 => 0], + 3 => [0 => 100, 1 => 0], + ], + ]); + $orderItemTaxesProvider->provide($orderItemTwo)->willReturn([ + 'total' => 200, + 'itemTaxes' => [ + 1 => [0 => 0, 1 => 100], + 2 => [0 => 0, 1 => 100], + ], + ]); $this->provide($order)->shouldReturn( [ @@ -275,19 +404,19 @@ function it_returns_array_of_different_items_with_different_quantities_with_tax( [ 'name' => 'PRODUCT_TWO', 'unit_amount' => [ - 'value' => '10.00', + 'value' => '9.00', 'currency_code' => 'PLN', ], 'quantity' => 1, 'tax' => [ - 'value' => '2.00', + 'value' => '1.00', 'currency_code' => 'PLN', ], ], [ 'name' => 'PRODUCT_TWO', 'unit_amount' => [ - 'value' => '10.00', + 'value' => '9.00', 'currency_code' => 'PLN', ], 'quantity' => 1, @@ -297,8 +426,8 @@ function it_returns_array_of_different_items_with_different_quantities_with_tax( ], ], ], - 'total_item_value' => '80.00', - 'total_tax' => '6.00', + 'total_item_value' => '78.00', + 'total_tax' => '5.00', ], ); } diff --git a/src/Provider/OrderItemNonNeutralTaxesProvider.php b/src/Provider/OrderItemNonNeutralTaxesProvider.php deleted file mode 100644 index ee3ddb43..00000000 --- a/src/Provider/OrderItemNonNeutralTaxesProvider.php +++ /dev/null @@ -1,51 +0,0 @@ - $orderItemTaxAdjustments */ - $orderItemTaxAdjustments = $orderItem->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT); - foreach ($orderItemTaxAdjustments as $taxAdjustment) { - if (!$taxAdjustment->isNeutral()) { - $taxes[] = $taxAdjustment->getAmount(); - } - } - - /** @var Collection $orderItemUnits */ - $orderItemUnits = $orderItem->getUnits(); - - foreach ($orderItemUnits as $unit) { - /** @var Collection $unitAdjustments */ - $unitAdjustments = $unit->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT); - - foreach ($unitAdjustments as $taxAdjustment) { - if (!$taxAdjustment->isNeutral()) { - $taxes[] = $taxAdjustment->getAmount(); - } - } - } - - return (empty($taxes)) ? [0] : $taxes; - } -} diff --git a/src/Provider/OrderItemTaxesProvider.php b/src/Provider/OrderItemTaxesProvider.php new file mode 100644 index 00000000..838eb9f2 --- /dev/null +++ b/src/Provider/OrderItemTaxesProvider.php @@ -0,0 +1,58 @@ + 0, 1 => 0]; + foreach ($orderItem->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) as $taxAdjustment) { + $orderItemTaxes[(int) $taxAdjustment->isNeutral()] += $taxAdjustment->getAmount(); + } + + [0 => $nonNeutralItemTaxes, 1 => $neutralItemTaxes] = $orderItemTaxes; + + $totalTaxes = ['total' => 0, 'itemTaxes' => []]; + $unitCount = $orderItem->getQuantity(); + + foreach ($orderItem->getUnits() as $unit) { + $unitId = (string) $unit->getId(); + + $nonNeutralTaxAllocation = (int) ceil($nonNeutralItemTaxes / $unitCount); + $neutralTaxAllocation = (int) ceil($neutralItemTaxes / $unitCount); + + $totalTaxes['itemTaxes'][$unitId][0] = $nonNeutralTaxAllocation; + $totalTaxes['itemTaxes'][$unitId][1] = $neutralTaxAllocation; + + $totalTaxes['total'] += $nonNeutralTaxAllocation; + $totalTaxes['total'] += $neutralTaxAllocation; + + $nonNeutralItemTaxes -= $nonNeutralTaxAllocation; + $neutralItemTaxes -= $neutralTaxAllocation; + + --$unitCount; + + foreach ($unit->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) as $taxAdjustment) { + $totalTaxes['itemTaxes'][$unitId][(int) $taxAdjustment->isNeutral()] += $taxAdjustment->getAmount(); + $totalTaxes['total'] += $taxAdjustment->getAmount(); + } + } + + return $totalTaxes; + } +} diff --git a/src/Provider/OrderItemNonNeutralTaxesProviderInterface.php b/src/Provider/OrderItemTaxesProviderInterface.php similarity index 58% rename from src/Provider/OrderItemNonNeutralTaxesProviderInterface.php rename to src/Provider/OrderItemTaxesProviderInterface.php index ad3b4918..b9de6e64 100644 --- a/src/Provider/OrderItemNonNeutralTaxesProviderInterface.php +++ b/src/Provider/OrderItemTaxesProviderInterface.php @@ -15,8 +15,13 @@ use Sylius\Component\Core\Model\OrderItemInterface; -interface OrderItemNonNeutralTaxesProviderInterface +interface OrderItemTaxesProviderInterface { - /** @return array|int[] */ - public function provide(OrderItemInterface $orderItem): iterable; + /** + * @return array{ + * total: int, + * itemTaxes: array + * } + */ + public function provide(OrderItemInterface $orderItem): array; } diff --git a/src/Provider/PayPalItemDataProvider.php b/src/Provider/PayPalItemDataProvider.php index 4b1d4dc9..fefbb97e 100644 --- a/src/Provider/PayPalItemDataProvider.php +++ b/src/Provider/PayPalItemDataProvider.php @@ -13,17 +13,12 @@ namespace Sylius\PayPalPlugin\Provider; -use Doctrine\Common\Collections\Collection; use Sylius\Component\Core\Model\OrderInterface; -use Sylius\Component\Core\Model\OrderItemInterface; final class PayPalItemDataProvider implements PayPalItemDataProviderInterface { - private OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider; - - public function __construct(OrderItemNonNeutralTaxesProviderInterface $orderItemNonNeutralTaxesProvider) + public function __construct(private readonly OrderItemTaxesProviderInterface $orderItemTaxesProvider) { - $this->orderItemNonNeutralTaxesProvider = $orderItemNonNeutralTaxesProvider; } public function provide(OrderInterface $order): array @@ -34,36 +29,60 @@ public function provide(OrderInterface $order): array 'total_tax' => 0, ]; - /** @var Collection $orderItems */ - $orderItems = $order->getItems(); - - foreach ($orderItems as $orderItem) { - $nonNeutralTaxes = $this->orderItemNonNeutralTaxesProvider->provide($orderItem); - /** @var int $nonNeutralTax */ - foreach ($nonNeutralTaxes as $nonNeutralTax) { - $displayQuantity = $nonNeutralTaxes === [0] ? $orderItem->getQuantity() : 1; - $itemValue = $orderItem->getUnitPrice(); - $itemData['total_item_value'] += ($itemValue * $displayQuantity) / 100; - $itemData['total_tax'] += ($nonNeutralTax * $displayQuantity) / 100; - - $itemData['items'][] = [ - 'name' => $orderItem->getProductName(), - 'unit_amount' => [ - 'value' => number_format($itemValue / 100, 2, '.', ''), - 'currency_code' => $order->getCurrencyCode(), - ], - 'quantity' => $displayQuantity, - 'tax' => [ - 'value' => number_format($nonNeutralTax / 100, 2, '.', ''), - 'currency_code' => $order->getCurrencyCode(), - ], - ]; + $currencyCode = (string) $order->getCurrencyCode(); + + foreach ($order->getItems() as $orderItem) { + $productName = (string) $orderItem->getProductName(); + $itemValue = $orderItem->getUnitPrice(); + + $taxes = $this->orderItemTaxesProvider->provide($orderItem); + + if ($taxes['total'] === 0) { + $this->addItem($itemData, $productName, $orderItem->getQuantity(), $itemValue, 0, $currencyCode); + + continue; + } + + foreach ($taxes['itemTaxes'] as $itemTaxes) { + $this->addItem( + $itemData, + $productName, + 1, + $itemValue - $itemTaxes[1], + array_sum($itemTaxes), + $currencyCode, + ); } } - $itemData['total_item_value'] = number_format($itemData['total_item_value'], 2, '.', ''); - $itemData['total_tax'] = number_format($itemData['total_tax'], 2, '.', ''); + $itemData['total_item_value'] = number_format($itemData['total_item_value'] / 100, 2, '.', ''); + $itemData['total_tax'] = number_format($itemData['total_tax'] / 100, 2, '.', ''); return $itemData; } + + private function addItem( + array &$itemData, + string $productName, + int $quantity, + int $itemValue, + int $tax, + string $currencyCode, + ): void { + $itemData['total_item_value'] += $itemValue * $quantity; + $itemData['total_tax'] += $tax * $quantity; + + $itemData['items'][] = [ + 'name' => $productName, + 'unit_amount' => [ + 'value' => number_format($itemValue / 100, 2, '.', ''), + 'currency_code' => $currencyCode, + ], + 'quantity' => $quantity, + 'tax' => [ + 'value' => number_format($tax / 100, 2, '.', ''), + 'currency_code' => $currencyCode, + ], + ]; + } } diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 8385cf0b..18414f2a 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -65,15 +65,15 @@ - +