fix: skip promotion usage limit checks on edit flows (#14176)

* fix: skip promotion usage limit checks on edit flows

* feat: add test check
This commit is contained in:
Frane Polić
2025-12-01 18:29:15 +01:00
committed by GitHub
parent 0f835381e9
commit 8ddf8b4d76
5 changed files with 35 additions and 4 deletions

View File

@@ -0,0 +1,7 @@
---
"@medusajs/promotion": patch
"@medusajs/core-flows": patch
"@medusajs/types": patch
---
fix: skip promotion usage limit checks on edit flows

View File

@@ -1437,6 +1437,16 @@ medusaIntegrationTestRunner({
adminHeaders adminHeaders
) )
const promotionModule = getContainer().resolve(Modules.PROMOTION)
// check that adjustments are computed for promotions that exceeded usage limit (we ignore usage limits on edit flows)
// @ts-ignore
await promotionModule.updatePromotions({
id: appliedPromotion.id,
limit: 1,
used: 1,
})
let result = await api.post( let result = await api.post(
"/admin/exchanges", "/admin/exchanges",
{ {

View File

@@ -29,7 +29,7 @@ export type ComputeAdjustmentsForPreviewWorkflowInput = {
/** /**
* The order's details. * The order's details.
*/ */
order: OrderDTO & { order: OrderDTO & {
/** /**
* The promotions applied to the order. * The promotions applied to the order.
*/ */
@@ -52,7 +52,7 @@ export const computeAdjustmentsForPreviewWorkflowId =
* *
* You can use this workflow within your customizations or your own custom workflows, allowing you to compute adjustments * You can use this workflow within your customizations or your own custom workflows, allowing you to compute adjustments
* in your custom flows. * in your custom flows.
* *
* @since v2.12.0 * @since v2.12.0
* *
* @example * @example
@@ -110,6 +110,9 @@ export const computeAdjustmentsForPreviewWorkflow = createWorkflow(
const actions = getActionsToComputeFromPromotionsStep({ const actions = getActionsToComputeFromPromotionsStep({
computeActionContext: actionsToComputeItemsInput, computeActionContext: actionsToComputeItemsInput,
promotionCodesToApply: orderPromotions, promotionCodesToApply: orderPromotions,
options: {
skip_usage_limit_checks: true,
},
}) })
const { lineItemAdjustmentsToCreate } = const { lineItemAdjustmentsToCreate } =

View File

@@ -295,4 +295,11 @@ export interface ComputeActionOptions {
* automatically. If not provided, the automatic promotions are applied. * automatically. If not provided, the automatic promotions are applied.
*/ */
prevent_auto_promotions?: boolean prevent_auto_promotions?: boolean
/**
* Whether to skip the usage limit checks.
* Useful when recomputing adjustment for promotions that are already applied as a part of edit/exchange flows.
*
*/
skip_usage_limit_checks?: boolean
} }

View File

@@ -634,7 +634,10 @@ export default class PromotionModuleService
options: PromotionTypes.ComputeActionOptions = {}, options: PromotionTypes.ComputeActionOptions = {},
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<PromotionTypes.ComputeActions[]> { ): Promise<PromotionTypes.ComputeActions[]> {
const { prevent_auto_promotions: preventAutoPromotions } = options const {
prevent_auto_promotions: preventAutoPromotions,
skip_usage_limit_checks: skipUsageLimitChecks,
} = options
const computedActions: PromotionTypes.ComputeActions[] = [] const computedActions: PromotionTypes.ComputeActions[] = []
const { items = [], shipping_methods: shippingMethods = [] } = const { items = [], shipping_methods: shippingMethods = [] } =
applicationContext applicationContext
@@ -806,6 +809,7 @@ export default class PromotionModuleService
} = promotion } = promotion
if ( if (
!skipUsageLimitChecks &&
promotion.campaign?.budget?.type === CampaignBudgetType.USE_BY_ATTRIBUTE promotion.campaign?.budget?.type === CampaignBudgetType.USE_BY_ATTRIBUTE
) { ) {
const attribute = promotion.campaign?.budget?.attribute! const attribute = promotion.campaign?.budget?.attribute!
@@ -847,7 +851,7 @@ export default class PromotionModuleService
} }
// Check promotion usage limit // Check promotion usage limit
if (typeof promotion.limit === "number") { if (!skipUsageLimitChecks && typeof promotion.limit === "number") {
if ((promotion.used ?? 0) >= promotion.limit) { if ((promotion.used ?? 0) >= promotion.limit) {
computedActions.push({ computedActions.push({
action: ComputedActions.PROMOTION_LIMIT_EXCEEDED, action: ComputedActions.PROMOTION_LIMIT_EXCEEDED,