we some broken carts reported with products added to cart automatically with promotion buyXgetY

we have a product X and with promotion if this product is added to cart 20 other products are added with a discount of 100%.
this works fine most of the time. but sometimes the carts break with a WSCOD.

DivisionByZeroError: Division by zero in bcdiv() (Zeile 96 in /web/modules/contrib/commerce/modules/price/src/Calculator.php).

#0 /web/modules/contrib/commerce/modules/price/src/Calculator.php(96): bcdiv()
#1 /web/modules/contrib/commerce/modules/price/src/Price.php(169): Drupal\commerce_price\Calculator::divide()
#2 /web/modules/contrib/commerce/modules/order/src/Entity/OrderItem.php(271): Drupal\commerce_price\Price->divide()
#3 /web/modules/contrib/commerce/modules/promotion/src/Plugin/Commerce/PromotionOffer/BuyXGetY.php(425): Drupal\commerce_order\Entity\OrderItem->getAdjustedUnitPrice()
#4 /web/modules/contrib/commerce/modules/promotion/src/Plugin/Commerce/PromotionOffer/CombinationOffer.php(257): Drupal\commerce_promotion\Plugin\Commerce\PromotionOffer\BuyXGetY->apply()
#5 /web/modules/contrib/commerce/modules/promotion/src/Entity/Promotion.php(624): Drupal\commerce_promotion\Plugin\Commerce\PromotionOffer\CombinationOffer->apply()
#6 /web/modules/contrib/commerce/modules/promotion/src/PromotionOrderProcessor.php(126): Drupal\commerce_promotion\Entity\Promotion->apply()
#7 /web/modules/contrib/commerce/modules/order/src/OrderRefresh.php(209): Drupal\commerce_promotion\PromotionOrderProcessor->process()
#8 /web/modules/contrib/commerce/modules/order/src/OrderStorage.php(127): Drupal\commerce_order\OrderRefresh->refresh()
#9 /web/modules/contrib/commerce/modules/order/src/OrderStorage.php(90): Drupal\commerce_order\OrderStorage->doOrderPreSave()
#10 /web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(529): Drupal\commerce_order\OrderStorage->invokeHook()
#11 /web/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php(753): Drupal\Core\Entity\EntityStorageBase->doPreSave()
#12 /web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(483): Drupal\Core\Entity\ContentEntityStorageBase->doPreSave()
#13 /web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(806): Drupal\Core\Entity\EntityStorageBase->save()
#14 /web/modules/contrib/commerce/modules/order/src/OrderStorage.php(173): Drupal\Core\Entity\Sql\SqlContentEntityStorage->save()
#15 /web/core/lib/Drupal/Core/Entity/EntityBase.php(354): Drupal\commerce_order\OrderStorage->save()
#16 /web/modules/contrib/commerce/modules/order/src/OrderStorage.php(160): Drupal\Core\Entity\EntityBase->save()
#17 /web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(319): Drupal\commerce_order\OrderStorage->postLoad()
#18 /web/modules/contrib/commerce/modules/cart/src/CartProvider.php(213): Drupal\Core\Entity\EntityStorageBase->loadMultiple()
#19 /web/modules/contrib/commerce/modules/cart/src/CartProvider.php(130): Drupal\commerce_cart\CartProvider->loadCartData()
#20 /web/modules/contrib/commerce/modules/cart/src/CartProvider.php(117): Drupal\commerce_cart\CartProvider->getCartId()
#21 /web/modules/contrib/commerce/modules/cart/src/Form/AddToCartForm.php(254): Drupal\commerce_cart\CartProvider->getCart()
#22 /web/modules/contrib/commerce/modules/cart/src/Form/AddToCartForm.php(232): Drupal\commerce_cart\Form\AddToCartForm->prepareOrderItem()
#23 /web/core/lib/Drupal/Core/Entity/ContentEntityForm.php(186): Drupal\commerce_cart\Form\AddToCartForm->buildEntity()
#24 [internal function]: Drupal\Core\Entity\ContentEntityForm->validateForm()
#25 /web/core/lib/Drupal/Core/Form/FormValidator.php(82): call_user_func_array()
#26 /web/core/lib/Drupal/Core/Form/FormValidator.php(274): Drupal\Core\Form\FormValidator->executeValidateHandlers()
#27 /web/core/lib/Drupal/Core/Form/FormValidator.php(118): Drupal\Core\Form\FormValidator->doValidateForm()
#28 /web/core/lib/Drupal/Core/Form/FormBuilder.php(593): Drupal\Core\Form\FormValidator->validateForm()
#29 /web/core/lib/Drupal/Core/Form/FormBuilder.php(326): Drupal\Core\Form\FormBuilder->processForm()
#30 /web/modules/contrib/commerce/modules/product/src/ProductLazyBuilders.php(77): Drupal\Core\Form\FormBuilder->buildForm()
#31 [internal function]: Drupal\commerce_product\ProductLazyBuilders->addToCartForm()
#32 /web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php(113): call_user_func_array()
#33 /web/core/lib/Drupal/Core/Render/Renderer.php(875): Drupal\Core\Render\Renderer->doTrustedCallback()
#34 /web/core/lib/Drupal/Core/Render/Renderer.php(411): Drupal\Core\Render\Renderer->doCallback()
#35 /web/core/lib/Drupal/Core/Render/Renderer.php(504): Drupal\Core\Render\Renderer->doRender()
#36 /web/core/lib/Drupal/Core/Render/Renderer.php(248): Drupal\Core\Render\Renderer->doRender()
#37 /web/core/modules/views/src/Plugin/views/field/EntityField.php(974): Drupal\Core\Render\Renderer->render()
#38 /web/modules/contrib/search_api/src/Plugin/views/field/SearchApiEntityField.php(259): Drupal\views\Plugin\views\field\EntityField->render_item()
#39 /web/core/modules/views/src/Plugin/views/field/FieldPluginBase.php(1214): Drupal\search_api\Plugin\views\field\SearchApiEntityField->render_item()
#40 /web/core/modules/views/views.theme.inc(238): Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender()
#41 [internal function]: template_preprocess_views_view_field()
#42 /web/core/lib/Drupal/Core/Theme/ThemeManager.php(261): call_user_func_array()
#43 /web/core/lib/Drupal/Core/Render/Renderer.php(491): Drupal\Core\Theme\ThemeManager->render()
#44 /web/core/lib/Drupal/Core/Render/Renderer.php(248): Drupal\Core\Render\Renderer->doRender()
#45 /web/core/modules/views/src/Plugin/views/field/FieldPluginBase.php(1796): Drupal\Core\Render\Renderer->render()
#46 /web/core/modules/views/src/Plugin/views/style/StylePluginBase.php(769): Drupal\views\Plugin\views\field\FieldPluginBase->theme()
#47 [internal function]: Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow()
#48 /web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php(113): call_user_func_array()
#49 /web/core/lib/Drupal/Core/Render/Renderer.php(875): Drupal\Core\Render\Renderer->doTrustedCallback()
#50 /web/core/lib/Drupal/Core/Render/Renderer.php(432): Drupal\Core\Render\Renderer->doCallback()
#51 /web/core/lib/Drupal/Core/Render/Renderer.php(248): Drupal\Core\Render\Renderer->doRender()
#52 /web/core/modules/views/src/Plugin/views/style/StylePluginBase.php(708): Drupal\Core\Render\Renderer->render()
#53 /web/core/modules/views/src/Plugin/views/style/StylePluginBase.php(574): Drupal\views\Plugin\views\style\StylePluginBase->renderFields()
#54 /web/core/modules/views/src/Plugin/views/style/StylePluginBase.php(462): Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping()
#55 /web/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php(2177): Drupal\views\Plugin\views\style\StylePluginBase->render()
#56 /web/core/modules/views/src/ViewExecutable.php(1593): Drupal\views\Plugin\views\display\DisplayPluginBase->render()
#57 /web/core/modules/views/src/Plugin/views/display/Page.php(201): Drupal\views\ViewExecutable->render()
#58 /web/core/modules/views/src/ViewExecutable.php(1690): Drupal\views\Plugin\views\display\Page->execute()
#59 /web/core/modules/views/src/Element/View.php(81): Drupal\views\ViewExecutable->executeDisplay()
#60 [internal function]: Drupal\views\Element\View::preRenderViewElement()
#61 /web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php(113): call_user_func_array()
#62 /web/core/lib/Drupal/Core/Render/Renderer.php(875): Drupal\Core\Render\Renderer->doTrustedCallback()
#63 /web/core/lib/Drupal/Core/Render/Renderer.php(432): Drupal\Core\Render\Renderer->doCallback()
#64 /web/core/lib/Drupal/Core/Render/Renderer.php(248): Drupal\Core\Render\Renderer->doRender()
#65 /web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(238): Drupal\Core\Render\Renderer->render()
#66 /web/core/lib/Drupal/Core/Render/Renderer.php(638): Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}()
#67 /web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(231): Drupal\Core\Render\Renderer->executeInRenderContext()
#68 /web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(128): Drupal\Core\Render\MainContent\HtmlRenderer->prepare()
#69 /web/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php(90): Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse()
#70 [internal function]: Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray()
#71 /web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
#72 /vendor/symfony/http-kernel/HttpKernel.php(186): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
#73 /vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
#74 /web/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle()
#75 /web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
#76 /web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
#77 /web/core/modules/big_pipe/src/StackMiddleware/ContentLength.php(32): Drupal\Core\StackMiddleware\ContentLength->handle()
#78 /web/core/modules/page_cache/src/StackMiddleware/PageCache.php(116): Drupal\big_pipe\StackMiddleware\ContentLength->handle()
#79 /web/core/modules/page_cache/src/StackMiddleware/PageCache.php(90): Drupal\page_cache\StackMiddleware\PageCache->pass()
#80 /web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle()
#81 /web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#82 /web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#83 /web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle()
#84 /web/core/lib/Drupal/Core/DrupalKernel.php(741): Drupal\Core\StackMiddleware\StackedHttpKernel->handle()
#85 /web/index.php(19): Drupal\Core\DrupalKernel->handle()
#86 {main}

we can not reproduce it.
But some debugging showed, that $quantity is 0.
at

  $order_item = $get_order_items[$order_item_id];
      $adjusted_unit_price = $order_item->getAdjustedUnitPrice(['promotion']);

a simple if before fixes the broken carts at in DEV. But is this ok for prod?

if ($order_item->getQuantity() <= 0) {
        // Wenn die Menge Null ist, diesen Bestellposten überspringen, 
        // um die Division durch Null zu vermeiden.
   //     \Drupal::logger('commerce_promotion')->warning('BXGY offer skipped for item @id due to zero quantity.', ['@id' => $order_item->id()]);
   //     continue; 
    //  }

Issue fork commerce-3562915

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

nojj created an issue. See original summary.

ivnish’s picture

Version: 3.1.0 » 3.x-dev
nojj’s picture

@ivnish we are using commerce 3.1 so I selected this.

anybody’s picture

jsacksick made their first commit to this issue’s fork.

jsacksick’s picture

Status: Active » Needs review

@anybody, @nojj: Made a change to the MR which seemed incorrect and wasn't respecting coding standards.
Is there anyway either of you could confirm the fix?

anybody’s picture

@jsacksick LGTM but I'd vote to add a comment like "Prevent division by zero:" to make the purpose clearer.

jsacksick’s picture

@anybody: Done. Considering this is a blind fix, I'd appreciate some feedback / help with testing :).

anybody’s picture

Status: Needs review » Reviewed & tested by the community

Thanks, yes of course. I played around, because this isn't a regular issue in our project, just happens from time to time. Results were positive, RTBC.

Can we also fix the related #3156089: Price calculation fails with a fatal error on zero quantity order items that have adjustments maybe? It has tests and test-only. Now that we're in that context...
Thanks!

  • jsacksick committed 6bcea123 on 3.x authored by nojj
    fix: #3562915 DivisionByZeroError: Division by zero in bcdiv() with...
jsacksick’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

jsacksick’s picture

@anybody: There is no MR there.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.