Summary
When a product bundle contains products that have variations (configurable products with child variation products), the bundle’s cart discount is never applied. The promotion validation silently fails because the onHowManyBundlesCanBeInCartBeforeGettingProductAmounts hook incorrectly inflates the required product amount by summing all child variation link entries.
Bundles with simple products (no variations) work correctly.
Root Cause
File: app/addons/product_bundles/src/HookHandlers/ProductBundlesHookHandler.php
Method: onHowManyBundlesCanBeInCartBeforeGettingProductAmounts (line ~303)
When a bundle is saved with any_variation = Y, the onUpdateLinks hook creates entries in cscart_product_bundle_product_links for the parent product AND each child variation — all with amount = 1.
For example, a bundle with 2 products:
- Product A (parent, 23 child variations) → 24 link entries (1 parent + 23 children), each
amount = 1 - Product B (parent, 6 child variations) → 7 link entries (1 parent + 6 children), each
amount = 1
The howManyBundlesCanBeInCart method loads these link entries into $bundle_products. Then the hook consolidates child entries to the parent:
// Line ~310 — THE BUG
$bundle_products[$parent_id]['amount'] += $bundle_products[$product_id]['amount'];
unset($bundle_products[$product_id]);
This sums ALL child amounts to the parent:
- Product A:
1 (parent) + 23 × 1 (children) = 24 - Product B:
1 (parent) + 6 × 1 (children) = 7
Later, the validation checks:
$is_bundle_complete = $cart_product_amounts[$product_id] >= $bundle_product['amount'];
The cart has 1 of each product, but the required amount is 24 and 7. The check fails (1 >= 24 → false), and the bundle is never considered complete. The promotion is not applied.
Steps to Reproduce
-
Create two configurable products with variations:
- Product A: a product with at least 2 child variations (e.g., different colors)
- Product B: a product with at least 2 child variations
-
Create a product bundle:
- Add Product A with
any_variation = Y, amount = 1, any discount type - Add Product B with
any_variation = Y, amount = 1, any discount type - Save the bundle
- Add Product A with
-
Verify the links table:
SELECT product_id, amount, all_variants FROM cscart_product_bundle_product_links WHERE bundle_id = <your_bundle_id>;You’ll see entries for the parent AND each child variation, all with
amount = 1. -
Add products to cart on the storefront:
- Add any variation of Product A (quantity 1)
- Add any variation of Product B (quantity 1)
-
Go to checkout / cart page
Expected: Bundle discount is applied to the order total.
Actual: No discount applied. The bundle promotion is silently skipped.
- For comparison, create a bundle with simple products (no variations, no
any_variation). The same discount type and values. Add those products to cart.
Result: Discount IS applied correctly for simple products.
Fix
In app/addons/product_bundles/src/HookHandlers/ProductBundlesHookHandler.php, method onHowManyBundlesCanBeInCartBeforeGettingProductAmounts, the child link consolidation should NOT sum amounts to the parent. The child entries should simply be removed:
Before (broken):
foreach (array_keys($bundle_products) as $product_id) {
if (
$product_id_map->isChildProduct($product_id)
&& isset($bundle_products[$product_id_map->getParentProductId($product_id)])
&& YesNo::toBool($bundle_products[$product_id_map->getParentProductId($product_id)]['all_variants'])
) {
$bundle_products[$product_id_map->getParentProductId($product_id)]['amount'] += $bundle_products[$product_id]['amount'];
unset($bundle_products[$product_id]);
}
}
After (fixed):
foreach (array_keys($bundle_products) as $product_id) {
if (
$product_id_map->isChildProduct($product_id)
&& isset($bundle_products[$product_id_map->getParentProductId($product_id)])
&& YesNo::toBool($bundle_products[$product_id_map->getParentProductId($product_id)]['all_variants'])
) {
unset($bundle_products[$product_id]);
}
}
The child link entries exist in the links table solely for product-to-bundle lookup (finding which bundles contain a given product). They should not inflate the parent’s required amount during the cart completeness check. The parent entry already has the correct amount value from the bundle configuration.
Impact
- Any product bundle using
any_variation = Ywith configurable products that have child variations will fail to apply the cart discount - The more child variations a product has, the higher the falsely inflated required amount
- The bundle displays correctly on the product page (storefront display is unaffected)
- Only the cart/checkout discount application is broken
- Bundles with simple products (no variations) are not affected