diff --git a/packages/core/src/config/promotion/promotion-action.ts b/packages/core/src/config/promotion/promotion-action.ts index 5bc31358a4..e4f9911ba1 100644 --- a/packages/core/src/config/promotion/promotion-action.ts +++ b/packages/core/src/config/promotion/promotion-action.ts @@ -199,6 +199,14 @@ export interface PromotionItemActionConfig; + + /** + * @description + * The maximum discount amount that can be applied to this action. + * + * @default 0 + */ + maxDiscountAmount?: ExecutePromotionItemActionFn; } /** @@ -321,10 +329,15 @@ export class PromotionItemAction< T extends ConfigArgs = ConfigArgs, U extends Array> = [], > extends PromotionAction { + /** @internal */ private readonly executeFn: ExecutePromotionItemActionFn; + /** @internal */ + private readonly maxDiscountAmountFn: ExecutePromotionItemActionFn; + constructor(config: PromotionItemActionConfig) { super(config); this.executeFn = config.execute; + this.maxDiscountAmountFn = config.maxDiscountAmount || (() => 0); } /** @internal */ @@ -349,6 +362,34 @@ export class PromotionItemAction< promotion, ); } + + /** + * @description + * The maximum discount amount that can be applied to this action. + * + * @default 0 + */ + maxDiscountAmount( + ctx: RequestContext, + orderLine: OrderLine, + args: ConfigArg[], + state: PromotionState, + promotion: Promotion, + ) { + const actionState = this.conditions + ? pick( + state, + this.conditions.map(c => c.code), + ) + : {}; + return this.maxDiscountAmountFn( + ctx, + orderLine, + this.argsArrayToHash(args), + actionState as ConditionState, + promotion, + ); + } } /** diff --git a/packages/core/src/entity/promotion/promotion.entity.ts b/packages/core/src/entity/promotion/promotion.entity.ts index d7a44f2a8d..5644ee28ec 100644 --- a/packages/core/src/entity/promotion/promotion.entity.ts +++ b/packages/core/src/entity/promotion/promotion.entity.ts @@ -150,9 +150,17 @@ export class Promotion if (promotionAction instanceof PromotionItemAction) { if (this.isOrderItemArg(args)) { const { orderLine } = args; - amount += roundMoney( + const discountAmount = roundMoney( await promotionAction.execute(ctx, orderLine, action.args, state, this), - ); + ) * orderLine.quantity; + const maxDiscountAmount = + roundMoney( + await promotionAction.maxDiscountAmount(ctx, orderLine, action.args, state, this), + ); + amount += + maxDiscountAmount && maxDiscountAmount > discountAmount + ? maxDiscountAmount + : discountAmount; } } else if (promotionAction instanceof PromotionOrderAction) { if (this.isOrderArg(args)) { diff --git a/packages/core/src/service/helpers/order-calculator/order-calculator.ts b/packages/core/src/service/helpers/order-calculator/order-calculator.ts index b8ee2609c7..05eef9ff54 100644 --- a/packages/core/src/service/helpers/order-calculator/order-calculator.ts +++ b/packages/core/src/service/helpers/order-calculator/order-calculator.ts @@ -199,7 +199,6 @@ export class OrderCalculator { // for (const item of line.items) { const adjustment = await promotion.apply(ctx, { orderLine: line }, state); if (adjustment) { - adjustment.amount = adjustment.amount * line.quantity; line.addAdjustment(adjustment); priceAdjusted = true; }