Sfoglia il codice sorgente

refactor(core): Update BOGOF promotion config to new schema

Michael Bromley 3 anni fa
parent
commit
5cd436e0ea

+ 7 - 7
packages/core/src/config/promotion/actions/buy-x-get-y-free-action.ts

@@ -10,18 +10,18 @@ export const buyXGetYFreeAction = new PromotionItemAction({
     description: [
         {
             languageCode: LanguageCode.en,
-            value: 'Buy { amountX } of { variantIdsX } products, get { amountY } of { variantIdsY } products free',
+            value: 'Buy X products, get Y products free',
         },
     ],
     args: {},
     conditions: [buyXGetYFreeCondition],
     execute(ctx, orderLine, args, state) {
-        const freeItemIds = state.buy_x_get_y_free.freeItemIds;
-        // TODO: fix me
-        // if (idsContainsItem(freeItemIds, orderItem)) {
-        //     const unitPrice = ctx.channel.pricesIncludeTax ? orderLine.unitPriceWithTax : orderLine.unitPrice;
-        //     return -unitPrice;
-        // }
+        const freeItemsPerLine = state.buy_x_get_y_free.freeItemsPerLine;
+        const freeQuantity = freeItemsPerLine[orderLine.id];
+        if (freeQuantity) {
+            const unitPrice = ctx.channel.pricesIncludeTax ? orderLine.unitPriceWithTax : orderLine.unitPrice;
+            return -unitPrice * (freeQuantity / orderLine.quantity);
+        }
         return 0;
     },
 });

+ 24 - 19
packages/core/src/config/promotion/conditions/buy-x-get-y-free-condition.ts

@@ -1,6 +1,7 @@
 import { LanguageCode } from '@vendure/common/lib/generated-types';
 import { ID } from '@vendure/common/lib/shared-types';
 
+import { OrderLine } from '../../../entity/order-line/order-line.entity';
 import { PromotionCondition } from '../promotion-condition';
 
 export const buyXGetYFreeCondition = new PromotionCondition({
@@ -8,7 +9,7 @@ export const buyXGetYFreeCondition = new PromotionCondition({
     description: [
         {
             languageCode: LanguageCode.en,
-            value: 'Buy { amountX } of { variantIdsX } products, get { amountY } of { variantIdsY } products free',
+            value: 'Buy X products, get Y products free',
         },
     ],
     args: {
@@ -20,7 +21,7 @@ export const buyXGetYFreeCondition = new PromotionCondition({
             type: 'ID',
             list: true,
             ui: { component: 'product-selector-form-input' },
-            label: [{ languageCode: LanguageCode.en, value: 'Product variants X' }],
+            label: [{ languageCode: LanguageCode.en, value: 'Buy amountX of these variants' }],
         },
         amountY: {
             type: 'int',
@@ -30,37 +31,41 @@ export const buyXGetYFreeCondition = new PromotionCondition({
             type: 'ID',
             list: true,
             ui: { component: 'product-selector-form-input' },
-            label: [{ languageCode: LanguageCode.en, value: 'Product variants Y' }],
+            label: [{ languageCode: LanguageCode.en, value: 'Get amountY of these variants for free' }],
         },
     },
     async check(ctx, order, args) {
         const xIds = createIdentityMap(args.variantIdsX);
         const yIds = createIdentityMap(args.variantIdsY);
         let matches = 0;
-        // TODO: fix me
-        const freeItemCandidates: any[] = [];
+        const freeItemCandidates: OrderLine[] = [];
         for (const line of order.lines) {
             const variantId = line.productVariant.id;
             if (variantId in xIds) {
                 matches += line.quantity;
             }
-            // if (variantId in yIds) {
-            //     freeItemCandidates.push(...line.items);
-            // }
+            if (variantId in yIds) {
+                freeItemCandidates.push(line);
+            }
         }
         const quantity = Math.floor(matches / args.amountX);
         if (!quantity || !freeItemCandidates.length) return false;
-        const freeItemIds = freeItemCandidates
-            .sort((a, b) => {
-                const unitPriceA = ctx.channel.pricesIncludeTax ? a.unitPriceWithTax : a.unitPrice;
-                const unitPriceB = ctx.channel.pricesIncludeTax ? b.unitPriceWithTax : b.unitPrice;
-                if (unitPriceA < unitPriceB) return -1;
-                if (unitPriceA > unitPriceB) return 1;
-                return 0;
-            })
-            .map(({ id }) => id)
-            .slice(0, quantity * args.amountY);
-        return { freeItemIds };
+        const freeLines = freeItemCandidates.sort((a, b) => {
+            const unitPriceA = ctx.channel.pricesIncludeTax ? a.unitPriceWithTax : a.unitPrice;
+            const unitPriceB = ctx.channel.pricesIncludeTax ? b.unitPriceWithTax : b.unitPrice;
+            if (unitPriceA < unitPriceB) return -1;
+            if (unitPriceA > unitPriceB) return 1;
+            return 0;
+        });
+        let placesToAllocate = args.amountY;
+        const freeItemsPerLine: { [lineId: string]: number } = {};
+        for (const freeLine of freeLines) {
+            if (placesToAllocate === 0) break;
+            const freeQuantity = Math.min(freeLine.quantity, placesToAllocate);
+            freeItemsPerLine[freeLine.id] = freeQuantity;
+            placesToAllocate -= freeQuantity;
+        }
+        return { freeItemsPerLine };
     },
 });
 

+ 2 - 2
packages/core/src/config/promotion/index.ts

@@ -31,12 +31,12 @@ export const defaultPromotionActions = [
     discountOnItemWithFacets,
     productsPercentageDiscount,
     freeShipping,
-    // buyXGetYFreeAction,
+    buyXGetYFreeAction,
 ];
 export const defaultPromotionConditions = [
     minimumOrderAmount,
     hasFacetValues,
     containsProducts,
     customerGroup,
-    // buyXGetYFreeCondition,
+    buyXGetYFreeCondition,
 ];