From 78ff64e7837f6506c641a3c97ffdfa6ee17419ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frane=20Poli=C4=87?= <16856471+fPolic@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:16:18 +0200 Subject: [PATCH] fix(medusa): validate customer for group discount (#3797) * fix: validate customer for group discount * fix: remove logger * fix: add generated desc * fix: add an integration test case * refactor: update error message * fix: typo * refactor: move condition --------- Co-authored-by: fPolic --- .changeset/calm-needles-change.md | 5 ++ .../api/__tests__/store/cart/cart.js | 57 +++++++++++++++++++ .../src/lib/models/StorePostCartsCartReq.ts | 2 +- .../src/api/routes/store/carts/update-cart.ts | 2 +- packages/medusa/src/services/cart.ts | 4 +- packages/medusa/src/services/discount.ts | 21 ++++++- 6 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 .changeset/calm-needles-change.md diff --git a/.changeset/calm-needles-change.md b/.changeset/calm-needles-change.md new file mode 100644 index 0000000000..9e9faa1723 --- /dev/null +++ b/.changeset/calm-needles-change.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +fix(medusa); validate customer id when applying a customer group discount diff --git a/integration-tests/api/__tests__/store/cart/cart.js b/integration-tests/api/__tests__/store/cart/cart.js index a28dfbf06c..3d83b677f9 100644 --- a/integration-tests/api/__tests__/store/cart/cart.js +++ b/integration-tests/api/__tests__/store/cart/cart.js @@ -1083,6 +1083,63 @@ describe("/store/carts", () => { expect(response.status).toEqual(200) }) + it("throws if no customer is associated with the cart while applying a customer groups discount", async () => { + const api = useApi() + + await simpleCustomerGroupFactory(dbConnection, { + id: "customer-group-2", + name: "Loyal", + }) + + await simpleCartFactory( + dbConnection, + { + id: "test-customer-discount", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12, + }, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + await simpleDiscountFactory(dbConnection, { + id: "test-discount", + code: "TEST", + regions: ["test-region"], + rule: { + type: "percentage", + value: "10", + allocation: "total", + conditions: [ + { + type: "customer_groups", + operator: "in", + customer_groups: ["customer-group-2"], + }, + ], + }, + }) + + try { + await api.post("/store/carts/test-customer-discount", { + discounts: [{ code: "TEST" }], + }) + } catch (error) { + expect(error.response.status).toEqual(400) + expect(error.response.data.message).toEqual( + "Discount TEST is only valid for specific customer" + ) + } + }) + it("successfully removes adjustments upon update without discounts", async () => { const discountData = { code: "MEDUSA185DKK", diff --git a/packages/generated/client-types/src/lib/models/StorePostCartsCartReq.ts b/packages/generated/client-types/src/lib/models/StorePostCartsCartReq.ts index 29d3bd5d49..41c6d1dd42 100644 --- a/packages/generated/client-types/src/lib/models/StorePostCartsCartReq.ts +++ b/packages/generated/client-types/src/lib/models/StorePostCartsCartReq.ts @@ -44,7 +44,7 @@ export interface StorePostCartsCartReq { */ discounts?: Array<{ /** - * The code that a Discount is identifed by. + * The code that a Discount is identified by. */ code: string }> diff --git a/packages/medusa/src/api/routes/store/carts/update-cart.ts b/packages/medusa/src/api/routes/store/carts/update-cart.ts index e397901ea8..04abb99f40 100644 --- a/packages/medusa/src/api/routes/store/carts/update-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/update-cart.ts @@ -168,7 +168,7 @@ class Discount { * - code * properties: * code: - * description: "The code that a Discount is identifed by." + * description: "The code that a Discount is identified by." * type: string * customer_id: * description: "The ID of the Customer to associate the Cart with." diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index 39250ac7b6..de1174cea9 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -1443,7 +1443,9 @@ class CartService extends TransactionBaseService { async (transactionManager: EntityManager) => { const discounts = await this.discountService_ .withTransaction(transactionManager) - .listByCodes(discountCodes, { relations: ["rule", "regions"] }) + .listByCodes(discountCodes, { + relations: ["rule", "rule.conditions", "regions"], + }) await this.discountService_ .withTransaction(transactionManager) diff --git a/packages/medusa/src/services/discount.ts b/packages/medusa/src/services/discount.ts index 1cf6e75e68..0f27454b9c 100644 --- a/packages/medusa/src/services/discount.ts +++ b/packages/medusa/src/services/discount.ts @@ -16,7 +16,13 @@ import { } from "." import { TransactionBaseService } from "../interfaces" import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { Cart, Discount, LineItem, Region } from "../models" +import { + Cart, + Discount, + DiscountConditionType, + LineItem, + Region, +} from "../models" import { AllocationType as DiscountAllocation, DiscountRule, @@ -705,6 +711,13 @@ class DiscountService extends TransactionBaseService { ) } + if (!cart.customer_id && this.hasCustomersGroupCondition(disc)) { + throw new MedusaError( + MedusaError.Types.NOT_ALLOWED, + `Discount ${disc.code} is only valid for specific customer` + ) + } + const isValidForRegion = await this.isValidForRegion( disc, cart.region_id @@ -734,6 +747,12 @@ class DiscountService extends TransactionBaseService { }) } + hasCustomersGroupCondition(discount: Discount): boolean { + return discount.rule.conditions.some( + (cond) => cond.type === DiscountConditionType.CUSTOMER_GROUPS + ) + } + hasReachedLimit(discount: Discount): boolean { const count = discount.usage_count || 0 const limit = discount.usage_limit