Skip to content

Commit

Permalink
feat(core): Implement "containsProducts" PromotionCondition
Browse files Browse the repository at this point in the history
Relates to #400
  • Loading branch information
michaelbromley committed Aug 13, 2020
1 parent 72b6ccd commit 688d304
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/common/src/shared-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export type DefaultFormComponentId =
| 'facet-value-form-input'
| 'number-form-input'
| 'select-form-input'
| 'product-selector-form-input'
| 'text-form-input';

/**
Expand All @@ -132,6 +133,7 @@ type DefaultFormConfigHash = {
'boolean-form-input': {};
'currency-form-input': {};
'facet-value-form-input': {};
'product-selector-form-input': {};
'text-form-input': {};
};

Expand Down
48 changes: 48 additions & 0 deletions packages/core/e2e/order-promotion.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { omit } from '@vendure/common/lib/omit';
import { pick } from '@vendure/common/lib/pick';
import {
containsProducts,
discountOnItemWithFacets,
hasFacetValues,
minimumOrderAmount,
Expand Down Expand Up @@ -327,6 +328,53 @@ describe('Promotions applied to Orders', () => {

await deletePromotion(promotion.id);
});

it('containsProducts', async () => {
const item60 = getVariantBySlug('item-60');
const item12 = getVariantBySlug('item-12');
const promotion = await createPromotion({
enabled: true,
name: 'Free if buying 3 or more offer products',
conditions: [
{
code: containsProducts.code,
arguments: [
{ name: 'minimum', value: '3' },
{ name: 'productVariantIds', value: JSON.stringify([item60.id, item12.id]) },
],
},
],
actions: [freeOrderAction],
});
await shopClient.query<AddItemToOrder.Mutation, AddItemToOrder.Variables>(ADD_ITEM_TO_ORDER, {
productVariantId: item60.id,
quantity: 1,
});
const { addItemToOrder } = await shopClient.query<
AddItemToOrder.Mutation,
AddItemToOrder.Variables
>(ADD_ITEM_TO_ORDER, {
productVariantId: item12.id,
quantity: 1,
});
expect(addItemToOrder!.total).toBe(7200);
expect(addItemToOrder!.adjustments.length).toBe(0);

const { adjustOrderLine } = await shopClient.query<
AdjustItemQuantity.Mutation,
AdjustItemQuantity.Variables
>(ADJUST_ITEM_QUANTITY, {
orderLineId: addItemToOrder!.lines[0].id,
quantity: 2,
});
expect(adjustOrderLine!.total).toBe(0);
expect(adjustOrderLine!.adjustments[0].description).toBe(
'Free if buying 3 or more offer products',
);
expect(adjustOrderLine!.adjustments[0].amount).toBe(-13200);

await deletePromotion(promotion.id);
});
});

describe('default PromotionActions', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { LanguageCode } from '@vendure/common/lib/generated-types';
import { ID } from '@vendure/common/lib/shared-types';

import { idsAreEqual } from '../../../common/utils';
import { OrderLine } from '../../../entity/order-line/order-line.entity';
import { Order } from '../../../entity/order/order.entity';
import { PromotionCondition } from '../promotion-condition';

export const containsProducts = new PromotionCondition({
code: 'contains_products',
description: [
{ languageCode: LanguageCode.en, value: 'Buy at least { minimum } of the specified products' },
],
args: {
minimum: { type: 'int' },
productVariantIds: {
type: 'ID',
list: true,
ui: { component: 'product-selector-form-input' },
label: [{ languageCode: LanguageCode.en, value: 'Product variants' }],
},
},
async check(order: Order, args) {
const ids = args.productVariantIds;
let matches = 0;
for (const line of order.lines) {
if (lineContainsIds(ids, line)) {
matches += line.quantity;
}
}
return args.minimum <= matches;
},
});

function lineContainsIds(ids: ID[], line: OrderLine): boolean {
return !!ids.find(id => idsAreEqual(id, line.productVariant.id));
}
4 changes: 3 additions & 1 deletion packages/core/src/config/promotion/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { discountOnItemWithFacets } from './actions/facet-values-discount-action';
import { orderPercentageDiscount } from './actions/order-percentage-discount-action';
import { containsProducts } from './conditions/contains-products-condition';
import { hasFacetValues } from './conditions/has-facet-values-condition';
import { minimumOrderAmount } from './conditions/min-order-amount-condition';

Expand All @@ -9,6 +10,7 @@ export * from './actions/facet-values-discount-action';
export * from './actions/order-percentage-discount-action';
export * from './conditions/has-facet-values-condition';
export * from './conditions/min-order-amount-condition';
export * from './conditions/contains-products-condition';

export const defaultPromotionActions = [orderPercentageDiscount, discountOnItemWithFacets];
export const defaultPromotionConditions = [minimumOrderAmount, hasFacetValues];
export const defaultPromotionConditions = [minimumOrderAmount, hasFacetValues, containsProducts];

0 comments on commit 688d304

Please sign in to comment.