diff --git a/.changeset/cozy-meals-rush.md b/.changeset/cozy-meals-rush.md new file mode 100644 index 00000000..d776cb97 --- /dev/null +++ b/.changeset/cozy-meals-rush.md @@ -0,0 +1,5 @@ +--- +"@labdigital/commercetools-mock": minor +--- + +Add basic support for discount codes in the cart repository diff --git a/src/repositories/cart/actions.ts b/src/repositories/cart/actions.ts index 4fc62c33..6f818f16 100644 --- a/src/repositories/cart/actions.ts +++ b/src/repositories/cart/actions.ts @@ -42,6 +42,7 @@ import type { ProductVariant, } from "@commercetools/platform-sdk"; import type { + CartAddDiscountCodeAction, CustomLineItem, DirectDiscount, } from "@commercetools/platform-sdk/dist/declarations/src/generated/models/cart"; @@ -61,6 +62,7 @@ import { calculateCartTotalPrice, calculateLineItemTotalPrice, createCustomLineItemFromDraft, + createDiscountCodeInfoFromCode, selectPrice, } from "./helpers.ts"; import type { CartRepository } from "./index.ts"; @@ -280,6 +282,25 @@ export class CartUpdateHandler // and prices on related Products have changed in the meanwhile. } + addDiscountCode( + context: RepositoryContext, + resource: Writable, + { code }: CartAddDiscountCodeAction, + ) { + const info = createDiscountCodeInfoFromCode( + context.projectKey, + this._storage, + code, + ); + if ( + !resource.discountCodes + .map((dc) => dc.discountCode.id) + .includes(info.discountCode.id) + ) { + resource.discountCodes.push(info); + } + } + removeDiscountCode( context: RepositoryContext, resource: Writable, diff --git a/src/repositories/cart/helpers.ts b/src/repositories/cart/helpers.ts index d96a036b..5722a9ae 100644 --- a/src/repositories/cart/helpers.ts +++ b/src/repositories/cart/helpers.ts @@ -2,12 +2,15 @@ import type { Cart, CustomLineItem, CustomLineItemDraft, + DiscountCodeInfo, + DiscountCodeNonApplicableError, LineItem, Price, TaxCategory, TaxCategoryReference, } from "@commercetools/platform-sdk"; import { v4 as uuidv4 } from "uuid"; +import { CommercetoolsError } from "#src/exceptions.ts"; import { calculateTaxedPrice } from "#src/lib/tax.ts"; import type { AbstractStorage } from "#src/storage/abstract.ts"; import { @@ -121,3 +124,29 @@ export const createCustomLineItemFromDraft = ( taxedPricePortions: [], }; }; + +export const createDiscountCodeInfoFromCode = ( + projectKey: string, + storage: AbstractStorage, + code: string, +): DiscountCodeInfo => { + const discountCodes = storage.query(projectKey, "discount-code", { + where: `code="${code}"`, + }); + // Does not validate anything besides existence of the DiscountCode object + if (discountCodes.count === 0) { + throw new CommercetoolsError({ + code: "DiscountCodeNonApplicable", + message: `The discount code '${code}' was not found.`, + reason: "DoesNotExist", + discountCode: "nonexistent", + }); + } + return { + discountCode: { + typeId: "discount-code", + id: discountCodes.results[0].id, + }, + state: "MatchesCart", + }; +}; diff --git a/src/repositories/cart/index.test.ts b/src/repositories/cart/index.test.ts index 9a65cdd9..8e752828 100644 --- a/src/repositories/cart/index.test.ts +++ b/src/repositories/cart/index.test.ts @@ -716,4 +716,36 @@ describe("createShippingInfo", () => { expect(result.taxedPrice!.totalGross.centAmount).toBe(1204); expect(result.taxedPrice!.totalNet.centAmount).toBe(995); }); + + test("create cart with discount code", async () => { + const code = storage.add("dummy", "discount-code", { + ...getBaseResourceProperties(), + code: "test-1234", + cartDiscounts: [], + isActive: true, + references: [], + groups: [], + }); + + const cart: CartDraft = { + country: "NL", + currency: "EUR", + discountCodes: ["test-1234"], + }; + + const ctx = { projectKey: "dummy", storeKey: "dummyStore" }; + + const result = repository.create(ctx, cart); + expect(result.id).toBeDefined(); + + expect(result.discountCodes).toEqual([ + { + discountCode: { + typeId: "discount-code", + id: code.id, + }, + state: "MatchesCart", + }, + ]); + }); }); diff --git a/src/repositories/cart/index.ts b/src/repositories/cart/index.ts index 75208c43..afbf99e4 100644 --- a/src/repositories/cart/index.ts +++ b/src/repositories/cart/index.ts @@ -2,6 +2,7 @@ import type { BusinessUnit, Cart, CartDraft, + DiscountCodeInfo, GeneralError, InvalidOperationError, LineItem, @@ -29,6 +30,7 @@ import { CartUpdateHandler } from "./actions.ts"; import { calculateCartTotalPrice, createCustomLineItemFromDraft, + createDiscountCodeInfoFromCode, selectPrice, } from "./helpers.ts"; @@ -87,6 +89,20 @@ export class CartRepository extends AbstractResourceRepository<"cart"> { ), ) ?? []; + // Validate that discount codes exist + const discountCodeInfo: DiscountCodeInfo[] = []; + if (draft.discountCodes?.length) { + draft.discountCodes.forEach((code) => { + discountCodeInfo.push( + createDiscountCodeInfoFromCode( + context.projectKey, + this._storage, + code, + ), + ); + }); + } + const resource: Writable = { ...getBaseResourceProperties(), anonymousId: draft.anonymousId, @@ -106,7 +122,7 @@ export class CartRepository extends AbstractResourceRepository<"cart"> { customerEmail: draft.customerEmail, customLineItems, directDiscounts: [], - discountCodes: [], + discountCodes: discountCodeInfo, inventoryMode: "None", itemShippingAddresses: [], lineItems,