-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(workflows-sdk,core-flows,medusa,types): add workflow to update p…
…romotions to cart (#6474) what: - adds API + workflow to add/remove promotions in a cart - minor fixes in promotions module - minor type fixes in cart module - typing fix in workflows-sdk (Thanks @adrien2p) - fix step result in workflows-sdk (Thanks @adrien2p) RESOLVES CORE-1768 Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
- Loading branch information
Showing
30 changed files
with
1,187 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
"@medusajs/workflows-sdk": patch | ||
"@medusajs/core-flows": patch | ||
"@medusajs/medusa": patch | ||
"@medusajs/types": patch | ||
--- | ||
|
||
feat(workflows-sdk,core-flows,medusa,types): add workflow to add promotions to cart |
309 changes: 309 additions & 0 deletions
309
integration-tests/plugins/__tests__/cart/store/add-promotions-to-cart.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,309 @@ | ||
import { ModuleRegistrationName } from "@medusajs/modules-sdk" | ||
import { ICartModuleService, IPromotionModuleService } from "@medusajs/types" | ||
import { PromotionType } from "@medusajs/utils" | ||
import path from "path" | ||
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" | ||
import { useApi } from "../../../../environment-helpers/use-api" | ||
import { getContainer } from "../../../../environment-helpers/use-container" | ||
import { initDb, useDb } from "../../../../environment-helpers/use-db" | ||
import adminSeeder from "../../../../helpers/admin-seeder" | ||
|
||
jest.setTimeout(50000) | ||
|
||
const env = { MEDUSA_FF_MEDUSA_V2: true } | ||
|
||
describe("Store Carts API: Add promotions to cart", () => { | ||
let dbConnection | ||
let appContainer | ||
let shutdownServer | ||
let cartModuleService: ICartModuleService | ||
let promotionModuleService: IPromotionModuleService | ||
|
||
beforeAll(async () => { | ||
const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) | ||
dbConnection = await initDb({ cwd, env } as any) | ||
shutdownServer = await startBootstrapApp({ cwd, env }) | ||
appContainer = getContainer() | ||
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART) | ||
promotionModuleService = appContainer.resolve( | ||
ModuleRegistrationName.PROMOTION | ||
) | ||
}) | ||
|
||
afterAll(async () => { | ||
const db = useDb() | ||
await db.shutdown() | ||
await shutdownServer() | ||
}) | ||
|
||
beforeEach(async () => { | ||
await adminSeeder(dbConnection) | ||
}) | ||
|
||
afterEach(async () => { | ||
const db = useDb() | ||
await db.teardown() | ||
}) | ||
|
||
describe("POST /store/carts/:id/promotions", () => { | ||
it("should add line item adjustments to a cart based on promotions", async () => { | ||
const appliedPromotion = await promotionModuleService.create({ | ||
code: "PROMOTION_APPLIED", | ||
type: PromotionType.STANDARD, | ||
application_method: { | ||
type: "fixed", | ||
target_type: "items", | ||
allocation: "each", | ||
value: "300", | ||
apply_to_quantity: 1, | ||
max_quantity: 1, | ||
target_rules: [ | ||
{ | ||
attribute: "product_id", | ||
operator: "eq", | ||
values: "prod_tshirt", | ||
}, | ||
], | ||
}, | ||
}) | ||
|
||
const createdPromotion = await promotionModuleService.create({ | ||
code: "PROMOTION_TEST", | ||
type: PromotionType.STANDARD, | ||
application_method: { | ||
type: "fixed", | ||
target_type: "items", | ||
allocation: "across", | ||
value: "1000", | ||
apply_to_quantity: 1, | ||
target_rules: [ | ||
{ | ||
attribute: "product_id", | ||
operator: "eq", | ||
values: "prod_mat", | ||
}, | ||
], | ||
}, | ||
}) | ||
|
||
const cart = await cartModuleService.create({ | ||
currency_code: "usd", | ||
items: [ | ||
// Adjustment to add | ||
{ | ||
id: "item-1", | ||
unit_price: 2000, | ||
quantity: 1, | ||
title: "Test item", | ||
product_id: "prod_mat", | ||
} as any, | ||
// This adjustment will be removed and recreated | ||
{ | ||
id: "item-2", | ||
unit_price: 1000, | ||
quantity: 1, | ||
title: "Test item", | ||
product_id: "prod_tshirt", | ||
} as any, | ||
], | ||
}) | ||
|
||
// Adjustment to keep | ||
const [lineItemAdjustment] = | ||
await cartModuleService.addLineItemAdjustments([ | ||
{ | ||
code: appliedPromotion.code!, | ||
amount: 300, | ||
item_id: "item-2", | ||
promotion_id: appliedPromotion.id, | ||
}, | ||
]) | ||
|
||
const api = useApi() as any | ||
|
||
const created = await api.post(`/store/carts/${cart.id}/promotions`, { | ||
promo_codes: [createdPromotion.code], | ||
}) | ||
|
||
expect(created.status).toEqual(200) | ||
expect(created.data.cart).toEqual( | ||
expect.objectContaining({ | ||
id: expect.any(String), | ||
items: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
id: "item-1", | ||
adjustments: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
promotion_id: createdPromotion.id, | ||
code: createdPromotion.code, | ||
amount: 1000, | ||
}), | ||
]), | ||
}), | ||
expect.objectContaining({ | ||
adjustments: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
id: expect.not.stringContaining(lineItemAdjustment.id), | ||
promotion_id: appliedPromotion.id, | ||
code: appliedPromotion.code, | ||
amount: 300, | ||
}), | ||
]), | ||
}), | ||
]), | ||
}) | ||
) | ||
}) | ||
|
||
it("should add shipping method adjustments to a cart based on promotions", async () => { | ||
const [appliedPromotion] = await promotionModuleService.create([ | ||
{ | ||
code: "PROMOTION_APPLIED", | ||
type: PromotionType.STANDARD, | ||
rules: [ | ||
{ | ||
attribute: "customer_id", | ||
operator: "in", | ||
values: ["cus_test"], | ||
}, | ||
{ | ||
attribute: "currency_code", | ||
operator: "in", | ||
values: ["eur"], | ||
}, | ||
], | ||
application_method: { | ||
type: "fixed", | ||
target_type: "shipping_methods", | ||
allocation: "each", | ||
value: "100", | ||
max_quantity: 1, | ||
target_rules: [ | ||
{ | ||
attribute: "name", | ||
operator: "in", | ||
values: ["express"], | ||
}, | ||
], | ||
}, | ||
}, | ||
]) | ||
|
||
const [newPromotion] = await promotionModuleService.create([ | ||
{ | ||
code: "PROMOTION_NEW", | ||
type: PromotionType.STANDARD, | ||
rules: [ | ||
{ | ||
attribute: "customer_id", | ||
operator: "in", | ||
values: ["cus_test"], | ||
}, | ||
{ | ||
attribute: "currency_code", | ||
operator: "in", | ||
values: ["eur"], | ||
}, | ||
], | ||
application_method: { | ||
type: "fixed", | ||
target_type: "shipping_methods", | ||
allocation: "each", | ||
value: "200", | ||
max_quantity: 1, | ||
target_rules: [ | ||
{ | ||
attribute: "name", | ||
operator: "in", | ||
values: ["express", "standard"], | ||
}, | ||
], | ||
}, | ||
}, | ||
]) | ||
|
||
const cart = await cartModuleService.create({ | ||
currency_code: "eur", | ||
customer_id: "cus_test", | ||
items: [ | ||
{ | ||
unit_price: 2000, | ||
quantity: 1, | ||
title: "Test item", | ||
product_id: "prod_mat", | ||
} as any, | ||
], | ||
}) | ||
|
||
const [express, standard] = await cartModuleService.addShippingMethods( | ||
cart.id, | ||
[ | ||
{ | ||
amount: 500, | ||
name: "express", | ||
}, | ||
{ | ||
amount: 500, | ||
name: "standard", | ||
}, | ||
] | ||
) | ||
|
||
const [adjustment] = await cartModuleService.addShippingMethodAdjustments( | ||
cart.id, | ||
[ | ||
{ | ||
shipping_method_id: express.id, | ||
amount: 100, | ||
code: appliedPromotion.code!, | ||
}, | ||
] | ||
) | ||
|
||
const api = useApi() as any | ||
|
||
const created = await api.post(`/store/carts/${cart.id}/promotions`, { | ||
promo_codes: [newPromotion.code], | ||
}) | ||
|
||
expect(created.status).toEqual(200) | ||
expect(created.data.cart).toEqual( | ||
expect.objectContaining({ | ||
id: expect.any(String), | ||
items: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
id: expect.any(String), | ||
}), | ||
]), | ||
shipping_methods: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
id: express.id, | ||
adjustments: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
id: expect.any(String), | ||
amount: 200, | ||
code: newPromotion.code, | ||
}), | ||
expect.objectContaining({ | ||
id: expect.not.stringContaining(adjustment.id), | ||
amount: 100, | ||
code: appliedPromotion.code, | ||
}), | ||
]), | ||
}), | ||
expect.objectContaining({ | ||
id: standard.id, | ||
adjustments: [ | ||
expect.objectContaining({ | ||
id: expect.any(String), | ||
amount: 200, | ||
code: newPromotion.code, | ||
}), | ||
], | ||
}), | ||
]), | ||
}) | ||
) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.