From acf6bbc2ec1d90e3b0100c86f56e96b38fa7c67a Mon Sep 17 00:00:00 2001 From: William Bouchard <46496014+willbouch@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:01:41 -0400 Subject: [PATCH] chore(core-flows): throw error on invalid promo code (#13140) * chore(core-flows): throw error on invalid promo code * add changelog * better error handling in test --------- Co-authored-by: william bouchard Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com> --- .changeset/ninety-kangaroos-grin.md | 5 +++ .../http/__tests__/cart/store/cart.spec.ts | 18 ++++++++ .../steps/get-promotion-codes-to-apply.ts | 45 ++++++++++++++----- 3 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 .changeset/ninety-kangaroos-grin.md diff --git a/.changeset/ninety-kangaroos-grin.md b/.changeset/ninety-kangaroos-grin.md new file mode 100644 index 0000000000..3e87bedb27 --- /dev/null +++ b/.changeset/ninety-kangaroos-grin.md @@ -0,0 +1,5 @@ +--- +"@medusajs/core-flows": minor +--- + +chore(code-flows): throw error on invalid promo code diff --git a/integration-tests/http/__tests__/cart/store/cart.spec.ts b/integration-tests/http/__tests__/cart/store/cart.spec.ts index 297b382197..cc58729ebd 100644 --- a/integration-tests/http/__tests__/cart/store/cart.spec.ts +++ b/integration-tests/http/__tests__/cart/store/cart.spec.ts @@ -2815,6 +2815,24 @@ medusaIntegrationTestRunner({ ) }) + it("should throw an error when adding a promotion that does not exist", async () => { + const invalidPromoCode = "SOME_INVALID_PROMO_CODE" + + const { response } = await api + .post( + `/store/carts/${cart.id}/promotions`, + { promo_codes: [invalidPromoCode] }, + storeHeaders + ) + .catch((e) => e) + + expect(response.status).toEqual(400) + expect(response.data.type).toEqual("invalid_data") + expect(response.data.message).toEqual( + `The promotion code ${invalidPromoCode} is invalid` + ) + }) + it("should remove promotion adjustments when promotion is deleted", async () => { let cartBeforeRemovingPromotion = ( await api.get(`/store/carts/${cart.id}`, storeHeaders) diff --git a/packages/core/core-flows/src/cart/steps/get-promotion-codes-to-apply.ts b/packages/core/core-flows/src/cart/steps/get-promotion-codes-to-apply.ts index 4de4ab53fb..9b554e707d 100644 --- a/packages/core/core-flows/src/cart/steps/get-promotion-codes-to-apply.ts +++ b/packages/core/core-flows/src/cart/steps/get-promotion-codes-to-apply.ts @@ -1,6 +1,10 @@ import { IPromotionModuleService } from "@medusajs/framework/types" -import { Modules, PromotionActions } from "@medusajs/framework/utils" -import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk" +import { + MedusaError, + Modules, + PromotionActions, +} from "@medusajs/framework/utils" +import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk" /** * The details of the promotion codes to apply on a cart. @@ -68,14 +72,12 @@ export const getPromotionCodesToApply = createStep( async (data: GetPromotionCodesToApplyStepInput, { container }) => { const { promo_codes = [], cart, action = PromotionActions.ADD } = data const { items = [], shipping_methods = [] } = cart - const adjustmentCodes: string[] = [] const promotionService = container.resolve( Modules.PROMOTION ) - const objects = items.concat(shipping_methods) - - objects.forEach((object) => { + const adjustmentCodes: string[] = [] + items.concat(shipping_methods).forEach((object) => { object.adjustments?.forEach((adjustment) => { if (adjustment.code && !adjustmentCodes.includes(adjustment.code)) { adjustmentCodes.push(adjustment.code) @@ -94,17 +96,38 @@ export const getPromotionCodesToApply = createStep( : [] ) - if (action === PromotionActions.ADD) { - promo_codes.forEach((code) => promotionCodesToApply.add(code)) - } - if (action === PromotionActions.REMOVE) { promo_codes.forEach((code) => promotionCodesToApply.delete(code)) } if (action === PromotionActions.REPLACE) { promotionCodesToApply.clear() - promo_codes.forEach((code) => promotionCodesToApply.add(code)) + } + + if ( + action === PromotionActions.ADD || + action === PromotionActions.REPLACE + ) { + const validPromoCodes: Set = new Set( + promo_codes.length + ? ( + await promotionService.listPromotions( + { code: promo_codes }, + { select: ["code"] } + ) + ).map((p) => p.code!) + : [] + ) + + promo_codes.forEach((code) => { + if (!validPromoCodes.has(code)) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `The promotion code ${code} is invalid` + ) + } + promotionCodesToApply.add(code) + }) } return new StepResponse(