diff --git a/modules/order/src/OrderRefresh.php b/modules/order/src/OrderRefresh.php index d5cbd937..6c47b039 100644 --- a/modules/order/src/OrderRefresh.php +++ b/modules/order/src/OrderRefresh.php @@ -170,6 +170,7 @@ class OrderRefresh implements OrderRefreshInterface { // Remove order items which had their quantities set to 0. if (Calculator::compare($order_item->getQuantity(), '0') === 0) { $order->removeItem($order_item); + $order_item->delete(); } else { // Remove the order that was set above, to avoid diff --git a/modules/promotion/src/EarlyOrderProcessor.php b/modules/promotion/src/EarlyOrderProcessor.php index 2bb5420d..d1dae197 100644 --- a/modules/promotion/src/EarlyOrderProcessor.php +++ b/modules/promotion/src/EarlyOrderProcessor.php @@ -7,7 +7,7 @@ use Drupal\commerce_order\OrderProcessorInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; /** - * Clear promotions to orders during the order refresh process. + * Allows promotions to clear their changes during the order refresh process. */ class EarlyOrderProcessor implements OrderProcessorInterface { diff --git a/modules/promotion/src/Entity/Promotion.php b/modules/promotion/src/Entity/Promotion.php index 242b54a1..9f8c885c 100644 --- a/modules/promotion/src/Entity/Promotion.php +++ b/modules/promotion/src/Entity/Promotion.php @@ -563,12 +563,10 @@ class Promotion extends CommerceContentEntityBase implements PromotionInterface */ public function apply(OrderInterface $order) { $offer = $this->getOffer(); - $order_items = $order->getItems(); - if ($offer instanceof OrderItemPromotionOfferInterface) { $offer_conditions = new ConditionGroup($offer->getConditions(), $offer->getConditionOperator()); // Apply the offer to order items that pass the conditions. - foreach ($order_items as $order_item) { + foreach ($order->getItems() as $order_item) { if ($offer_conditions->evaluate($order_item)) { $offer->apply($order_item, $this); } diff --git a/modules/promotion/src/Entity/PromotionInterface.php b/modules/promotion/src/Entity/PromotionInterface.php index e6ae90ba..936f6f4e 100644 --- a/modules/promotion/src/Entity/PromotionInterface.php +++ b/modules/promotion/src/Entity/PromotionInterface.php @@ -422,7 +422,7 @@ interface PromotionInterface extends ContentEntityInterface, EntityStoresInterfa public function apply(OrderInterface $order); /** - * Allows a promotion to clean up any modifications done to the given entity. + * Allows a promotion to clean up any modifications done to the given order. * * @param \Drupal\commerce_order\Entity\OrderInterface $order * The order. diff --git a/modules/promotion/src/Plugin/Commerce/PromotionOffer/BuyXGetY.php b/modules/promotion/src/Plugin/Commerce/PromotionOffer/BuyXGetY.php index b1ca9ca7..eec2a3e6 100644 --- a/modules/promotion/src/Plugin/Commerce/PromotionOffer/BuyXGetY.php +++ b/modules/promotion/src/Plugin/Commerce/PromotionOffer/BuyXGetY.php @@ -344,20 +344,6 @@ class BuyXGetY extends OrderPromotionOfferBase { $order = $entity; $order_items = $order->getItems(); - // Check if we have any order item whose quantity has been changed by this - // promotion, and subtract that amount. If the promotion still applies, the - // necessary quantity will be added back below. If the order item will have - // no quantity left, it will be removed. - if ($this->configuration['get_auto_add']) { - $auto_add_order_items = array_filter($order_items, function (OrderItemInterface $order_item) use ($promotion) { - return $order_item->getData("promotion:{$promotion->id()}:auto_add_quantity"); - }); - foreach ($auto_add_order_items as $order_item) { - $new_quantity = Calculator::subtract($order_item->getQuantity(), $order_item->getData("promotion:{$promotion->id()}:auto_add_quantity")); - $order_item->setQuantity($new_quantity); - } - } - $buy_conditions = $this->buildConditionGroup($this->configuration['buy_conditions']); $buy_order_items = $this->selectOrderItems($order_items, $buy_conditions, 'DESC'); $buy_quantities = array_map(function (OrderItemInterface $order_item) { @@ -470,15 +456,17 @@ class BuyXGetY extends OrderPromotionOfferBase { $this->assertEntity($entity); /** @var \Drupal\commerce_order\Entity\OrderInterface $order */ $order = $entity; - $order_items = $order->getItems(); - // Remove any leftover order items that were auto-added. - foreach ($order_items as $order_item) { - $order_item->setAdjustments(array_filter($order_item->getAdjustments(), function (Adjustment $adjustment) use ($promotion) { - return $adjustment->getSourceId() !== $promotion->id(); - })); - - if ($order_item->getData("promotion:{$promotion->id()}:auto_add_quantity")) { + // Check if we have any order item whose quantity has been changed by this + // promotion, and subtract that amount. If the promotion still applies, the + // necessary quantity will be added back in ::apply(). Order items that will + // end up with a quantity of 0 will be removed from the order by + // \Drupal\commerce_order\OrderRefresh::refresh(). + if ($this->configuration['get_auto_add']) { + $auto_add_order_items = array_filter($order->getItems(), function (OrderItemInterface $order_item) use ($promotion) { + return $order_item->getData("promotion:{$promotion->id()}:auto_add_quantity"); + }); + foreach ($auto_add_order_items as $order_item) { $new_quantity = Calculator::subtract($order_item->getQuantity(), $order_item->getData("promotion:{$promotion->id()}:auto_add_quantity")); $order_item->setQuantity($new_quantity); } @@ -547,13 +535,13 @@ class BuyXGetY extends OrderPromotionOfferBase { } /** - * Find the configured purchasable entity amongst the given conditions. + * Finds the configured purchasable entity amongst the given conditions. * * @param \Drupal\commerce\ConditionGroup $conditions * The condition group. * * @return \Drupal\commerce\PurchasableEntityInterface|null - * The purchasable entity, NULL if not found in the conditions. + * The purchasable entity, or NULL if not found in the conditions. */ protected function findSinglePurchasableEntity(ConditionGroup $conditions) { foreach ($conditions->getConditions() as $condition) { @@ -697,7 +685,7 @@ class BuyXGetY extends OrderPromotionOfferBase { * @return array * The quantity list slice. */ - protected function sliceQuantities(array &$quantities, string $total_quantity) { + protected function sliceQuantities(array &$quantities, $total_quantity) { $remaining_quantity = $total_quantity; $slice = []; foreach ($quantities as $order_item_id => $quantity) { @@ -786,7 +774,7 @@ class BuyXGetY extends OrderPromotionOfferBase { * @return \Drupal\commerce_price\Price * The adjustment amount. */ - protected function buildAdjustmentAmount(OrderItemInterface $order_item, string $quantity) { + protected function buildAdjustmentAmount(OrderItemInterface $order_item, $quantity) { if ($this->configuration['offer_type'] == 'percentage') { $percentage = (string) $this->configuration['offer_percentage']; $total_price = $order_item->getTotalPrice(); @@ -807,7 +795,7 @@ class BuyXGetY extends OrderPromotionOfferBase { } /** - * Get the purchasable entity condition plugin definitions. + * Gets the purchasable entity condition plugin definitions. * * @return array * The purchasable entity condition plugin definitions.