From 209750e309899a28b8c3239af779a1c869595399 Mon Sep 17 00:00:00 2001 From: Marek Rzytki Date: Fri, 19 Jun 2026 10:34:19 +0200 Subject: [PATCH] Fix shipping adjustment removal to clear shipment reference --- .../Component/Core/Model/Adjustment.php | 10 +++ .../order_with_shipping_adjustment.yml | 56 ++++++++++++ ...OrderShippingAdjustmentDoubleFlushTest.php | 85 +++++++++++++++++++ .../OrderShippingAdjustmentRemovalTest.php | 50 +++++++++++ 4 files changed, 201 insertions(+) create mode 100644 tests/DataFixtures/ORM/resources/order_with_shipping_adjustment.yml create mode 100644 tests/Functional/OrderShippingAdjustmentDoubleFlushTest.php create mode 100644 tests/Model/OrderShippingAdjustmentRemovalTest.php diff --git a/src/Sylius/Component/Core/Model/Adjustment.php b/src/Sylius/Component/Core/Model/Adjustment.php index 869a23cd01..76a9663017 100644 --- a/src/Sylius/Component/Core/Model/Adjustment.php +++ b/src/Sylius/Component/Core/Model/Adjustment.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Sylius\Component\Core\Model; +use Sylius\Component\Order\Model\AdjustableInterface; use Sylius\Component\Order\Model\Adjustment as BaseAdjustment; class Adjustment extends BaseAdjustment implements AdjustmentInterface @@ -20,6 +21,15 @@ class Adjustment extends BaseAdjustment implements AdjustmentInterface /** @var ShipmentInterface|null */ protected $shipment; + public function setAdjustable(?AdjustableInterface $adjustable): void + { + parent::setAdjustable($adjustable); + + if ($adjustable === null && $this->shipment !== null) { + $this->setShipment(null); + } + } + public function getShipment(): ?ShipmentInterface { return $this->shipment; diff --git a/tests/DataFixtures/ORM/resources/order_with_shipping_adjustment.yml b/tests/DataFixtures/ORM/resources/order_with_shipping_adjustment.yml new file mode 100644 index 0000000000..2fc9dd83f1 --- /dev/null +++ b/tests/DataFixtures/ORM/resources/order_with_shipping_adjustment.yml @@ -0,0 +1,56 @@ +Sylius\Component\Currency\Model\Currency: + currency: + code: "EUR" + +Sylius\Component\Locale\Model\Locale: + locale: + code: "en_US" + +Sylius\Component\Addressing\Model\Zone: + zone: + code: "TEST_ZONE" + name: "Test Zone" + type: "country" + scope: "all" + +Sylius\Component\Core\Model\Channel: + channel: + code: "TEST" + name: "Test Channel" + hostname: "localhost" + baseCurrency: "@currency" + defaultLocale: "@locale" + enabled: true + taxCalculationStrategy: "order_items_based" + currencies: ["@currency"] + locales: ["@locale"] + +Sylius\Component\Core\Model\ShippingMethod: + shipping_method: + code: "TEST_FLAT_RATE" + enabled: true + calculator: "flat_rate" + configuration: + TEST: + amount: 1000 + zone: "@zone" + channels: ["@channel"] + +Sylius\Component\Core\Model\Adjustment: + shipping_adjustment: + type: "shipping" + amount: 1000 + label: "Shipping" + +Sylius\Component\Core\Model\Order: + order_with_shipping: + currencyCode: "EUR" + localeCode: "en_US" + channel: "@channel" + +Sylius\Component\Core\Model\Shipment: + order_shipment: + method: "@shipping_method" + order: "@order_with_shipping" + __calls: + - addAdjustment: ["@shipping_adjustment"] diff --git a/tests/Functional/OrderShippingAdjustmentDoubleFlushTest.php b/tests/Functional/OrderShippingAdjustmentDoubleFlushTest.php new file mode 100644 index 0000000000..ebaaed4ad3 --- /dev/null +++ b/tests/Functional/OrderShippingAdjustmentDoubleFlushTest.php @@ -0,0 +1,85 @@ +getContainer()->get('fidry_alice_data_fixtures.loader.doctrine'); + + $this->fixtures = $fixtureLoader->load( + [__DIR__ . '/../DataFixtures/ORM/resources/order_with_shipping_adjustment.yml'], + [], + [], + PurgeMode::createDeleteMode(), + ); + + $this->entityManager = self::$kernel->getContainer()->get('doctrine.orm.entity_manager'); + } + + #[Test] + public function it_allows_multiple_flushes_after_removing_shipping_adjustment_from_order(): void + { + /** @var Order $order */ + $order = $this->fixtures['order_with_shipping']; + + /** @var Shipment $shipment */ + $shipment = $this->fixtures['order_shipment']; + + $this->assertFalse( + $order->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT)->isEmpty(), + 'Order should have a shipping adjustment before removal', + ); + $this->assertFalse( + $shipment->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT)->isEmpty(), + 'Shipment should have a shipping adjustment before removal', + ); + + $order->removeAdjustmentsRecursively(AdjustmentInterface::SHIPPING_ADJUSTMENT); + + $this->entityManager->flush(); + $this->entityManager->flush(); + + $this->assertTrue( + $order->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT)->isEmpty(), + 'Order should have no shipping adjustments after removal', + ); + $this->assertTrue( + $shipment->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT)->isEmpty(), + 'Shipment should have no shipping adjustments after removal', + ); + } +} diff --git a/tests/Model/OrderShippingAdjustmentRemovalTest.php b/tests/Model/OrderShippingAdjustmentRemovalTest.php new file mode 100644 index 0000000000..499781f37b --- /dev/null +++ b/tests/Model/OrderShippingAdjustmentRemovalTest.php @@ -0,0 +1,50 @@ +setOrder($order); + + $adjustment = new Adjustment(); + $adjustment->setType(AdjustmentInterface::SHIPPING_ADJUSTMENT); + $adjustment->setAmount(500); + + $shipment->addAdjustment($adjustment); + + $this->assertSame($order, $adjustment->getAdjustable(), 'Adjustment should be assigned to order after addAdjustment on shipment'); + $this->assertSame($shipment, $adjustment->getShipment(), 'Adjustment should reference the shipment'); + $this->assertTrue($order->hasAdjustment($adjustment), 'Order should contain the adjustment'); + $this->assertTrue($shipment->hasAdjustment($adjustment), 'Shipment should contain the adjustment'); + + $order->removeAdjustment($adjustment); + + $this->assertNull($adjustment->getAdjustable(), 'Adjustable reference should be cleared'); + $this->assertNull($adjustment->getShipment(), 'Shipment reference should be cleared after removal from order'); + $this->assertFalse($order->hasAdjustment($adjustment), 'Order should not contain the adjustment'); + $this->assertFalse($shipment->hasAdjustment($adjustment), 'Shipment should not contain the adjustment after removal from order'); + } +}