diff --git a/packages/template-retail-react-app/app/components/product-item/index.jsx b/packages/template-retail-react-app/app/components/product-item/index.jsx
index 2cc910f4a9..847279706d 100644
--- a/packages/template-retail-react-app/app/components/product-item/index.jsx
+++ b/packages/template-retail-react-app/app/components/product-item/index.jsx
@@ -74,10 +74,14 @@ const ProductItem = ({
- {deliveryActions && {deliveryActions}}
+ {deliveryActions && !product.bonusProductLineItem && (
+ {deliveryActions}
+ )}
- {deliveryActions && {deliveryActions}}
+ {deliveryActions && !product.bonusProductLineItem && (
+ {deliveryActions}
+ )}
diff --git a/packages/template-retail-react-app/app/components/product-item/index.test.js b/packages/template-retail-react-app/app/components/product-item/index.test.js
index 15f1b8a9d9..274651c1d1 100644
--- a/packages/template-retail-react-app/app/components/product-item/index.test.js
+++ b/packages/template-retail-react-app/app/components/product-item/index.test.js
@@ -103,4 +103,41 @@ describe('ProductItem Component', () => {
expect(screen.getByText(/Quantity:/i)).toBeInTheDocument()
expect(screen.queryByRole('spinbutton')).not.toBeInTheDocument()
})
+
+ test('does not render delivery actions for bonus products', () => {
+ renderWithProviders(
+ Delivery Action}
+ />
+ )
+
+ expect(screen.queryByText(/Delivery Action/i)).not.toBeInTheDocument()
+ })
+
+ test('renders delivery actions for regular products but not bonus products', () => {
+ // Test regular product first
+ const {unmount} = renderWithProviders(
+ Delivery Action}
+ />
+ )
+
+ // Regular product should show delivery actions (appears twice - mobile and desktop)
+ expect(screen.getAllByText(/Delivery Action/i)).toHaveLength(2)
+
+ // Cleanup completely
+ unmount()
+
+ // Test bonus product with fresh render
+ renderWithProviders(
+ Delivery Action}
+ />
+ )
+
+ expect(screen.queryAllByText(/Delivery Action/i)).toHaveLength(0)
+ })
})
diff --git a/packages/template-retail-react-app/app/pages/cart/partials/cart-product-list-with-grouped-bonus-products.jsx b/packages/template-retail-react-app/app/pages/cart/partials/cart-product-list-with-grouped-bonus-products.jsx
index 941ca73e3a..ec95cfa33e 100644
--- a/packages/template-retail-react-app/app/pages/cart/partials/cart-product-list-with-grouped-bonus-products.jsx
+++ b/packages/template-retail-react-app/app/pages/cart/partials/cart-product-list-with-grouped-bonus-products.jsx
@@ -8,7 +8,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import {Stack, Box, Heading} from '@salesforce/retail-react-app/app/components/shared/ui'
import SelectBonusProductsCard from '@salesforce/retail-react-app/app/pages/cart/partials/select-bonus-products-card'
-import {getBonusProductsInCartForProduct} from '@salesforce/retail-react-app/app/utils/bonus-product/cart'
+import {getBonusProductsForSpecificCartItem} from '@salesforce/retail-react-app/app/utils/bonus-product/cart'
import {getRemainingAvailableBonusProductsForProduct} from '@salesforce/retail-react-app/app/utils/bonus-product/discovery'
import {shouldShowBonusProductSelection} from '@salesforce/retail-react-app/app/utils/bonus-product/business-logic'
@@ -76,10 +76,10 @@ const CartProductListWithGroupedBonusProducts = ({
// Enhanced rendering for eligible products
try {
- // Get bonus product data for this qualifying product
- const bonusProductsForThisProduct = getBonusProductsInCartForProduct(
+ // Get bonus products allocated specifically to this cart item
+ const bonusProductsForThisProduct = getBonusProductsForSpecificCartItem(
basket,
- qualifyingProduct.productId,
+ qualifyingProduct,
productsWithPromotions
)
const remainingBonusProductsData = getRemainingAvailableBonusProductsForProduct(
diff --git a/packages/template-retail-react-app/app/utils/bonus-product/cart.js b/packages/template-retail-react-app/app/utils/bonus-product/cart.js
index 966600e693..1c5d5a0d4c 100644
--- a/packages/template-retail-react-app/app/utils/bonus-product/cart.js
+++ b/packages/template-retail-react-app/app/utils/bonus-product/cart.js
@@ -7,6 +7,7 @@
import {getPromotionIdsForProduct} from '@salesforce/retail-react-app/app/utils/bonus-product/common'
import {findAvailableBonusDiscountLineItemIds} from '@salesforce/retail-react-app/app/utils/bonus-product/discovery'
+import {isPickupShipment} from '@salesforce/retail-react-app/app/utils/shipment-utils'
/**
* Cart state operations and product relationship utilities for bonus products.
@@ -65,6 +66,153 @@ export const getQualifyingProductIdForBonusItem = (basket, bonusDiscountLineItem
return qualifyingProductIds
}
+/**
+ * Gets bonus products allocated to a specific cart item using capacity-based sequential allocation.
+ * This function distributes available bonus products across qualifying cart items based on:
+ * - Individual item capacity (calculated from promotion rules and item quantity)
+ * - First-come-first-served allocation order (based on cart item position)
+ *
+ * @param {Object} basket - The current basket data
+ * @param {Object} targetCartItem - The specific cart item to get bonus products for
+ * @param {Object} productsWithPromotions - Products data with promotion info
+ * @returns {Array