Skip to content

Commit

Permalink
Merge branch 'master' into minor
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Sep 29, 2023
2 parents 53bb605 + 9b51f4e commit 2407ee6
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 62 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## <small>2.0.9 (2023-09-29)</small>


#### Fixes

* **core** Fix discount calculation error edge-case ([7549aad](https://github.com/vendure-ecommerce/vendure/commit/7549aad)), closes [#2385](https://github.com/vendure-ecommerce/vendure/issues/2385)

## <small>2.0.8 (2023-09-27)</small>


Expand Down
203 changes: 143 additions & 60 deletions packages/core/e2e/order-promotion.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ describe('Promotions applied to Orders', () => {
describe('discountOnItemWithFacets', () => {
const couponCode = '50%_off_sale_items';
let promotion: Codegen.PromotionFragment;

function getItemSale1Line<
T extends Array<
| CodegenShop.UpdatedOrderFragment['lines'][number]
Expand Down Expand Up @@ -1943,78 +1944,160 @@ describe('Promotions applied to Orders', () => {
});

// https://github.com/vendure-ecommerce/vendure/issues/2385
it('prevents negative line price', async () => {
await shopClient.asAnonymousUser();
const item1000 = getVariantBySlug('item-1000')!;
describe('prevents negative line price', () => {
const TAX_INCLUDED_CHANNEL_TOKEN_2 = 'tax_included_channel_2';
const couponCode1 = '100%_off';
const couponCode2 = '100%_off';
await createPromotion({
enabled: true,
name: '100% discount ',
couponCode: couponCode1,
conditions: [],
actions: [
{
code: productsPercentageDiscount.code,
arguments: [
{ name: 'discount', value: '100' },
{
name: 'productVariantIds',
value: `["${item1000.id}"]`,
},
],
let taxIncludedChannel: Codegen.ChannelFragment;

beforeAll(async () => {
// Create a channel where the prices include tax, so we can ensure
// that PromotionActions are working as expected when taxes are included
const { createChannel } = await adminClient.query<
Codegen.CreateChannelMutation,
Codegen.CreateChannelMutationVariables
>(CREATE_CHANNEL, {
input: {
code: 'tax-included-channel-2',
currencyCode: CurrencyCode.GBP,
pricesIncludeTax: true,
defaultTaxZoneId: 'T_1',
defaultShippingZoneId: 'T_1',
defaultLanguageCode: LanguageCode.en,
token: TAX_INCLUDED_CHANNEL_TOKEN_2,
},
],
});
await createPromotion({
enabled: true,
name: '20% discount ',
couponCode: couponCode2,
conditions: [],
actions: [
{
code: productsPercentageDiscount.code,
arguments: [
{ name: 'discount', value: '20' },
{
name: 'productVariantIds',
value: `["${item1000.id}"]`,
},
],
});
taxIncludedChannel = createChannel as Codegen.ChannelFragment;
await adminClient.query<
Codegen.AssignProductsToChannelMutation,
Codegen.AssignProductsToChannelMutationVariables
>(ASSIGN_PRODUCT_TO_CHANNEL, {
input: {
channelId: taxIncludedChannel.id,
priceFactor: 1,
productIds: products.map(p => p.id),
},
],
});
const item1000 = getVariantBySlug('item-1000')!;
const promo100 = await createPromotion({
enabled: true,
name: '100% discount ',
couponCode: couponCode1,
conditions: [],
actions: [
{
code: productsPercentageDiscount.code,
arguments: [
{ name: 'discount', value: '100' },
{
name: 'productVariantIds',
value: `["${item1000.id}"]`,
},
],
},
],
});
const promo20 = await createPromotion({
enabled: true,
name: '20% discount ',
couponCode: couponCode2,
conditions: [],
actions: [
{
code: productsPercentageDiscount.code,
arguments: [
{ name: 'discount', value: '20' },
{
name: 'productVariantIds',
value: `["${item1000.id}"]`,
},
],
},
],
});
await adminClient.query<
Codegen.AssignPromotionToChannelMutation,
Codegen.AssignPromotionToChannelMutationVariables
>(ASSIGN_PROMOTIONS_TO_CHANNEL, {
input: {
promotionIds: [promo100.id, promo20.id],
channelId: taxIncludedChannel.id,
},
});
});

await shopClient.query<
CodegenShop.ApplyCouponCodeMutation,
CodegenShop.ApplyCouponCodeMutationVariables
>(APPLY_COUPON_CODE, { couponCode: couponCode1 });
it('prices exclude tax', async () => {
await shopClient.asAnonymousUser();
const item1000 = getVariantBySlug('item-1000')!;

await shopClient.query<
CodegenShop.AddItemToOrderMutation,
CodegenShop.AddItemToOrderMutationVariables
>(ADD_ITEM_TO_ORDER, {
productVariantId: item1000.id,
quantity: 1,
await shopClient.query<
CodegenShop.ApplyCouponCodeMutation,
CodegenShop.ApplyCouponCodeMutationVariables
>(APPLY_COUPON_CODE, { couponCode: couponCode1 });

await shopClient.query<
CodegenShop.AddItemToOrderMutation,
CodegenShop.AddItemToOrderMutationVariables
>(ADD_ITEM_TO_ORDER, {
productVariantId: item1000.id,
quantity: 1,
});

const { activeOrder: check1 } = await shopClient.query<CodegenShop.GetActiveOrderQuery>(
GET_ACTIVE_ORDER,
);

expect(check1!.lines[0].discountedUnitPriceWithTax).toBe(0);
expect(check1!.totalWithTax).toBe(0);

await shopClient.query<
CodegenShop.ApplyCouponCodeMutation,
CodegenShop.ApplyCouponCodeMutationVariables
>(APPLY_COUPON_CODE, { couponCode: couponCode2 });

const { activeOrder: check2 } = await shopClient.query<CodegenShop.GetActiveOrderQuery>(
GET_ACTIVE_ORDER,
);
expect(check2!.lines[0].discountedUnitPriceWithTax).toBe(0);
expect(check2!.totalWithTax).toBe(0);
});

const { activeOrder: check1 } = await shopClient.query<CodegenShop.GetActiveOrderQuery>(
GET_ACTIVE_ORDER,
);
it('prices include tax', async () => {
shopClient.setChannelToken(TAX_INCLUDED_CHANNEL_TOKEN_2);
await shopClient.asAnonymousUser();
const item1000 = getVariantBySlug('item-1000')!;

expect(check1!.lines[0].discountedUnitPriceWithTax).toBe(0);
expect(check1!.totalWithTax).toBe(0);
await shopClient.query<
CodegenShop.ApplyCouponCodeMutation,
CodegenShop.ApplyCouponCodeMutationVariables
>(APPLY_COUPON_CODE, { couponCode: couponCode1 });

await shopClient.query<
CodegenShop.ApplyCouponCodeMutation,
CodegenShop.ApplyCouponCodeMutationVariables
>(APPLY_COUPON_CODE, { couponCode: couponCode2 });
await shopClient.query<
CodegenShop.AddItemToOrderMutation,
CodegenShop.AddItemToOrderMutationVariables
>(ADD_ITEM_TO_ORDER, {
productVariantId: item1000.id,
quantity: 1,
});

const { activeOrder: check2 } = await shopClient.query<CodegenShop.GetActiveOrderQuery>(
GET_ACTIVE_ORDER,
);
expect(check2!.lines[0].discountedUnitPriceWithTax).toBe(0);
expect(check2!.totalWithTax).toBe(0);
const { activeOrder: check1 } = await shopClient.query<CodegenShop.GetActiveOrderQuery>(
GET_ACTIVE_ORDER,
);

expect(check1!.lines[0].discountedUnitPriceWithTax).toBe(0);
expect(check1!.totalWithTax).toBe(0);

await shopClient.query<
CodegenShop.ApplyCouponCodeMutation,
CodegenShop.ApplyCouponCodeMutationVariables
>(APPLY_COUPON_CODE, { couponCode: couponCode2 });

const { activeOrder: check2 } = await shopClient.query<CodegenShop.GetActiveOrderQuery>(
GET_ACTIVE_ORDER,
);
expect(check2!.lines[0].discountedUnitPriceWithTax).toBe(0);
expect(check2!.totalWithTax).toBe(0);
});
});

async function getProducts() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const productsPercentageDiscount = new PromotionItemAction({
label: [{ languageCode: LanguageCode.en, value: 'Product variants' }],
},
},

execute(ctx, orderLine, args) {
if (lineContainsIds(args.productVariantIds, orderLine)) {
const unitPrice = ctx.channel.pricesIncludeTax ? orderLine.unitPriceWithTax : orderLine.unitPrice;
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/entity/order-line/order-line.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ export class OrderLine extends VendureEntity implements HasCustomFields {
addAdjustment(adjustment: Adjustment) {
// We should not allow adding adjustments which would
// result in a negative unit price
const maxDiscount = this.proratedLinePrice * -1;
const maxDiscount =
(this.listPriceIncludesTax ? this.proratedLinePriceWithTax : this.proratedLinePrice) * -1;
const limitedAdjustment: Adjustment = {
...adjustment,
amount: Math.max(maxDiscount, adjustment.amount),
Expand Down

0 comments on commit 2407ee6

Please sign in to comment.