+
+
+
+
diff --git a/js/components/cart.js b/js/components/cart.js
index 063408f..b596f01 100644
--- a/js/components/cart.js
+++ b/js/components/cart.js
@@ -69,12 +69,32 @@ const CartComponent = {
if (idx > -1) {
this.cart.splice(idx, 1);
} else {
- this.cart.push({
- id: parseInt(product.id),
- name: product.name,
- price: product.price,
- isFree: false
- });
+ // Check if this product has a Y discount from active product
+ const yDiscount = this.getYProductBogoDiscount(product);
+
+ if (yDiscount) {
+ // Add with discounted price
+ const discountedPrice = this.getYProductDiscountedPrice(product);
+ const discountLabel = this.getYProductDiscountLabel(product);
+
+ this.cart.push({
+ id: parseInt(product.id),
+ name: product.name + (discountLabel ? ' (' + discountLabel + ')' : ''),
+ price: discountedPrice,
+ originalPrice: product.price,
+ isFree: false,
+ isDiscounted: true,
+ ruleId: yDiscount.rule_id
+ });
+ } else {
+ // Add with regular price
+ this.cart.push({
+ id: parseInt(product.id),
+ name: product.name,
+ price: product.price,
+ isFree: false
+ });
+ }
}
this.recalculateBogo();
},
@@ -83,7 +103,7 @@ const CartComponent = {
* Recalculate BOGO discounts based on current cart
*/
recalculateBogo() {
- // Remove existing free items from cart
+ // Remove existing auto-added free items from cart (but keep manually added discounted items)
this.cart = this.cart.filter(item => !item.isFree);
// Calculate new BOGO
@@ -93,7 +113,8 @@ const CartComponent = {
this.bogoFreeItems = bogoResult.freeItems;
this.appliedBogoRules = bogoResult.appliedRules;
- // Add free items to cart
+ // Add free items to cart (only for buy_x_get_x rules)
+ // buy_x_get_y items are NOT auto-added, user must add them manually
for (const freeItem of bogoResult.freeItems) {
this.cart.push({
id: parseInt(freeItem.id),
@@ -240,6 +261,59 @@ const CartComponent = {
return BogoService.hasBogoRules(product);
},
+ /**
+ * Get BOGO discount info for a Y product (upsell) based on active product's rules
+ * @param {Object} yProduct - The upsell product
+ * @returns {Object|null}
+ */
+ getYProductBogoDiscount(yProduct) {
+ if (!this.activeProduct) return null;
+ return BogoService.getYProductDiscount(this.activeProduct, yProduct);
+ },
+
+ /**
+ * Get discounted price for Y product
+ * @param {Object} yProduct - The upsell product
+ * @returns {string|null}
+ */
+ getYProductDiscountedPrice(yProduct) {
+ const discount = this.getYProductBogoDiscount(yProduct);
+ if (!discount) return null;
+
+ const price = parseFloat(yProduct.price);
+
+ if (discount.discount_type === 'free_product' || discount.discount_value >= 100) {
+ return '0.00';
+ } else if (discount.discount_type === 'percentage') {
+ const discountAmount = price * (discount.discount_value / 100);
+ return (price - discountAmount).toFixed(2);
+ } else if (discount.discount_type === 'flat') {
+ return Math.max(0, price - discount.discount_value).toFixed(2);
+ }
+
+ return null;
+ },
+
+ /**
+ * Get discount label for Y product
+ * @param {Object} yProduct - The upsell product
+ * @returns {string|null}
+ */
+ getYProductDiscountLabel(yProduct) {
+ const discount = this.getYProductBogoDiscount(yProduct);
+ if (!discount) return null;
+
+ if (discount.discount_type === 'free_product' || discount.discount_value >= 100) {
+ return 'GRATIS';
+ } else if (discount.discount_type === 'percentage') {
+ return discount.discount_value + '% korting';
+ } else if (discount.discount_type === 'flat') {
+ return '€' + discount.discount_value.toFixed(2) + ' korting';
+ }
+
+ return null;
+ },
+
/**
* Clear the cart
*/
@@ -270,27 +344,24 @@ const CartComponent = {
getComputed() {
return {
/**
- * Calculate subtotal (items only, no shipping, no BOGO discount)
+ * Calculate subtotal (items only, no shipping)
+ * Includes all items: full price, discounted (isFree with price > 0), and free (price = 0)
* @returns {string}
*/
subtotal() {
return this.cart
- .filter(item => !item.isFree)
.reduce((sum, item) => sum + parseFloat(item.price), 0)
.toFixed(2);
},
/**
- * Calculate total including shipping and BOGO discount
+ * Calculate total including shipping
* @returns {string}
*/
total() {
const itemsTotal = this.cart
- .filter(item => !item.isFree)
.reduce((sum, item) => sum + parseFloat(item.price), 0);
const shipping = parseFloat(this.shipping) || 0;
- // Note: BOGO discount is already applied via free items with price 0
- // So we don't subtract bogoDiscount here
return (itemsTotal + shipping).toFixed(2);
},
diff --git a/js/services/bogo.js b/js/services/bogo.js
index b5ef9fc..6e56c92 100644
--- a/js/services/bogo.js
+++ b/js/services/bogo.js
@@ -137,21 +137,28 @@ const BogoService = {
// These are handled manually via addBogoDiscountedItem() in cart.js
// The user clicks a button to add the discounted item
} else if (rule.type === 'buy_x_get_y' && rule.get_product_ids) {
- // Different product is free
+ // Different product (Y) is free or discounted
+ // For buy_x_get_y, we DON'T automatically add items to cart
+ // The user must manually add them via the upsell section
+ // We only track the discount amount for display purposes
for (const freeProductId of rule.get_product_ids) {
const freeProduct = products.find(p => p.id == freeProductId);
if (!freeProduct) continue;
+ const freeProductPrice = parseFloat(freeProduct.price);
+
if (rule.discount_type === 'free_product' || rule.discount_value >= 100) {
- result.discountAmount += freeQty * parseFloat(freeProduct.price);
- result.freeItems.push({
- id: freeProduct.id,
- name: freeProduct.name + ' (GRATIS)',
- price: '0.00',
- originalPrice: freeProduct.price,
- isFree: true,
- ruleId: rule.rule_id
- });
+ // 100% korting - product Y is gratis (but not auto-added)
+ result.discountAmount += freeQty * freeProductPrice;
+ } else if (rule.discount_type === 'percentage') {
+ // Percentage korting op product Y (but not auto-added)
+ const discountPerItem = freeProductPrice * (rule.discount_value / 100);
+ result.discountAmount += freeQty * discountPerItem;
+ } else if (rule.discount_type === 'flat') {
+ // Vaste korting op product Y (but not auto-added)
+ const discountedPrice = Math.max(0, freeProductPrice - rule.discount_value).toFixed(2);
+ const actualDiscount = freeProductPrice - parseFloat(discountedPrice);
+ result.discountAmount += freeQty * actualDiscount;
}
}
}
@@ -185,5 +192,35 @@ const BogoService = {
}
return suggestions;
+ },
+
+ /**
+ * Get BOGO discount info for a Y product based on X product's rules
+ *
+ * @param {Object} xProduct - The main product (X) with BOGO rules
+ * @param {Object} yProduct - The upsell product (Y) to check
+ * @returns {Object|null} - Discount info or null if no discount applies
+ */
+ getYProductDiscount(xProduct, yProduct) {
+ if (!xProduct || !this.hasBogoRules(xProduct)) return null;
+
+ const rule = this.getPrimaryBogoRule(xProduct);
+
+ // Only for buy_x_get_y rules
+ if (rule.type !== 'buy_x_get_y') return null;
+
+ // Check if yProduct is in the get_product_ids
+ if (!rule.get_product_ids || !rule.get_product_ids.includes(parseInt(yProduct.id))) {
+ return null;
+ }
+
+ // Return discount info
+ return {
+ rule_id: rule.rule_id,
+ discount_type: rule.discount_type,
+ discount_value: rule.discount_value,
+ label: rule.label,
+ badge_text: rule.badge_text
+ };
}
};