Skip to content

Commit

Permalink
feat(core): Implement product discount promotion action
Browse files Browse the repository at this point in the history
Relates to #400
  • Loading branch information
michaelbromley committed Aug 14, 2020
1 parent f687f49 commit 7da0d46
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 3 deletions.
53 changes: 53 additions & 0 deletions packages/core/e2e/order-promotion.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
hasFacetValues,
minimumOrderAmount,
orderPercentageDiscount,
productsPercentageDiscount,
} from '@vendure/core';
import { createTestEnvironment } from '@vendure/testing';
import gql from 'graphql-tag';
Expand Down Expand Up @@ -486,6 +487,58 @@ describe('Promotions applied to Orders', () => {
await deletePromotion(promotion.id);
});

it('productsPercentageDiscount', async () => {
const item60 = getVariantBySlug('item-60');
const couponCode = '50%_off_product';
const promotion = await createPromotion({
enabled: true,
name: '50% off product',
couponCode,
conditions: [],
actions: [
{
code: productsPercentageDiscount.code,
arguments: [
{ name: 'discount', value: '50' },
{ name: 'productVariantIds', value: `["${item60.id}"]` },
],
},
],
});
const { addItemToOrder } = await shopClient.query<
AddItemToOrder.Mutation,
AddItemToOrder.Variables
>(ADD_ITEM_TO_ORDER, {
productVariantId: item60.id,
quantity: 1,
});
expect(addItemToOrder!.adjustments.length).toBe(0);
expect(addItemToOrder!.lines[0].adjustments.length).toBe(1); // 1x tax
expect(addItemToOrder!.total).toBe(6000);

const { applyCouponCode } = await shopClient.query<
ApplyCouponCode.Mutation,
ApplyCouponCode.Variables
>(APPLY_COUPON_CODE, {
couponCode,
});

expect(applyCouponCode!.total).toBe(3000);
expect(applyCouponCode!.lines[0].adjustments.length).toBe(2); // 1x tax, 1x promotion

const { removeCouponCode } = await shopClient.query<
RemoveCouponCode.Mutation,
RemoveCouponCode.Variables
>(REMOVE_COUPON_CODE, {
couponCode,
});

expect(removeCouponCode!.lines[0].adjustments.length).toBe(1); // 1x tax
expect(removeCouponCode!.total).toBe(6000);

await deletePromotion(promotion.id);
});

it('multiple promotions simultaneously', async () => {
const { facets } = await adminClient.query<GetFacetList.Query>(GET_FACET_LIST);
const saleFacetValue = facets.items[0].values[0];
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 { PromotionItemAction } from '../promotion-action';

export const productsPercentageDiscount = new PromotionItemAction({
code: 'products_percentage_discount',
description: [{ languageCode: LanguageCode.en, value: 'Discount specified products by { discount }%' }],
args: {
discount: {
type: 'int',
ui: {
component: 'number-form-input',
suffix: '%',
},
},
productVariantIds: {
type: 'ID',
list: true,
ui: { component: 'product-selector-form-input' },
label: [{ languageCode: LanguageCode.en, value: 'Product variants' }],
},
},

execute(orderItem, orderLine, args) {
if (lineContainsIds(args.productVariantIds, orderLine)) {
return -orderLine.unitPrice * (args.discount / 100);
}
return 0;
},
});

function lineContainsIds(ids: ID[], line: OrderLine): boolean {
return !!ids.find(id => idsAreEqual(id, line.productVariant.id));
}
8 changes: 7 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 { productsPercentageDiscount } from './actions/product-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 @@ -8,9 +9,14 @@ export * from './promotion-action';
export * from './promotion-condition';
export * from './actions/facet-values-discount-action';
export * from './actions/order-percentage-discount-action';
export * from './actions/product-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 defaultPromotionActions = [
orderPercentageDiscount,
discountOnItemWithFacets,
productsPercentageDiscount,
];
export const defaultPromotionConditions = [minimumOrderAmount, hasFacetValues, containsProducts];
2 changes: 1 addition & 1 deletion schema-admin.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion schema-shop.json

Large diffs are not rendered by default.

0 comments on commit 7da0d46

Please sign in to comment.