fix(medusa): Update line item adjustments upon cart discount removal (#2751)
**What** When a discount is deleted from a cart, the line item adjustments must be refreshed. Now, the cart service `removeDiscount` includes updating the adjustments. **Tests** **Add a new integration test which:** - create a cart with a discount - add a line item - validate the adjustments - remove the discount - check that the adjustments are not present anymore **Update unit tests** The actual tests cases now check that the adjustments repository is called when needed FIXES CORE-890
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(medusa): Should update the adjustments upon cart discount removal
|
||||||
@@ -520,6 +520,7 @@ describe("/store/carts", () => {
|
|||||||
|
|
||||||
let discountCart
|
let discountCart
|
||||||
let discount
|
let discount
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
discount = await simpleDiscountFactory(dbConnection, discountData, 100)
|
discount = await simpleDiscountFactory(dbConnection, discountData, 100)
|
||||||
discountCart = await simpleCartFactory(
|
discountCart = await simpleCartFactory(
|
||||||
@@ -1042,6 +1043,86 @@ describe("/store/carts", () => {
|
|||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("successfully removes adjustments upon update without discounts", async () => {
|
||||||
|
const discountData = {
|
||||||
|
code: "MEDUSA185DKK",
|
||||||
|
id: "medusa-185",
|
||||||
|
rule: {
|
||||||
|
allocation: "total",
|
||||||
|
type: "fixed",
|
||||||
|
value: 185,
|
||||||
|
},
|
||||||
|
regions: ["test-region"],
|
||||||
|
}
|
||||||
|
|
||||||
|
const cartId = "discount-cart"
|
||||||
|
|
||||||
|
const discount = await simpleDiscountFactory(dbConnection, discountData, 100)
|
||||||
|
const discountCart = await simpleCartFactory(
|
||||||
|
dbConnection,
|
||||||
|
{
|
||||||
|
id: cartId,
|
||||||
|
customer: "test-customer",
|
||||||
|
region: "test-region",
|
||||||
|
shipping_address: {
|
||||||
|
address_1: "next door",
|
||||||
|
first_name: "lebron",
|
||||||
|
last_name: "james",
|
||||||
|
country_code: "dk",
|
||||||
|
postal_code: "100",
|
||||||
|
},
|
||||||
|
shipping_methods: [
|
||||||
|
{
|
||||||
|
shipping_option: "test-option",
|
||||||
|
price: 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
100
|
||||||
|
)
|
||||||
|
await dbConnection.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.relation(Cart, "discounts")
|
||||||
|
.of(discountCart)
|
||||||
|
.add(discount)
|
||||||
|
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
let response = await api
|
||||||
|
.post(
|
||||||
|
`/store/carts/${cartId}/line-items`,
|
||||||
|
{
|
||||||
|
quantity: 1,
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.cart.items.length).toEqual(1)
|
||||||
|
expect(response.data.cart.items).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
adjustments: [
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: 185,
|
||||||
|
discount_id: "medusa-185",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.post(
|
||||||
|
`/store/carts/${cartId}`,
|
||||||
|
{
|
||||||
|
discounts: [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.cart.items.length).toEqual(1)
|
||||||
|
expect(response.data.cart.items[0].adjustments).toHaveLength(0)
|
||||||
|
})
|
||||||
|
|
||||||
it("successfully passes customer conditions with `not_in` operator and applies discount", async () => {
|
it("successfully passes customer conditions with `not_in` operator and applies discount", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
@@ -2035,17 +2116,23 @@ describe("/store/carts", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("DELETE /store/carts/:id/discounts/:code", () => {
|
describe("DELETE /store/carts/:id/discounts/:code", () => {
|
||||||
|
const discountData = {
|
||||||
|
code: "MEDUSA185DKK",
|
||||||
|
id: "medusa-185",
|
||||||
|
rule: {
|
||||||
|
allocation: "total",
|
||||||
|
type: "fixed",
|
||||||
|
value: 185,
|
||||||
|
},
|
||||||
|
regions: ["test-region"],
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
try {
|
await cartSeeder(dbConnection)
|
||||||
await cartSeeder(dbConnection)
|
await dbConnection.manager.query(
|
||||||
await dbConnection.manager.query(
|
`INSERT INTO "cart_discounts" (cart_id, discount_id)
|
||||||
`INSERT INTO "cart_discounts" (cart_id, discount_id)
|
VALUES ('test-cart', 'free-shipping')`
|
||||||
VALUES ('test-cart', 'free-shipping')`
|
)
|
||||||
)
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@@ -2073,16 +2160,74 @@ describe("/store/carts", () => {
|
|||||||
expect(response.data.cart.shipping_total).toBe(1000)
|
expect(response.data.cart.shipping_total).toBe(1000)
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("removes line item adjustments upon discount deletion", async () => {
|
||||||
|
const cartId = "discount-cart"
|
||||||
|
const discount = await simpleDiscountFactory(dbConnection, discountData, 100)
|
||||||
|
const discountCart = await simpleCartFactory(
|
||||||
|
dbConnection,
|
||||||
|
{
|
||||||
|
id: cartId,
|
||||||
|
customer: "test-customer",
|
||||||
|
region: "test-region",
|
||||||
|
shipping_address: {
|
||||||
|
address_1: "next door",
|
||||||
|
first_name: "lebron",
|
||||||
|
last_name: "james",
|
||||||
|
country_code: "dk",
|
||||||
|
postal_code: "100",
|
||||||
|
},
|
||||||
|
shipping_methods: [
|
||||||
|
{
|
||||||
|
shipping_option: "test-option",
|
||||||
|
price: 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
100
|
||||||
|
)
|
||||||
|
await dbConnection.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.relation(Cart, "discounts")
|
||||||
|
.of(discountCart)
|
||||||
|
.add(discount)
|
||||||
|
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
let response = await api
|
||||||
|
.post(
|
||||||
|
`/store/carts/${cartId}/line-items`,
|
||||||
|
{
|
||||||
|
quantity: 1,
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.cart.items.length).toEqual(1)
|
||||||
|
expect(response.data.cart.items).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
adjustments: [
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: 185,
|
||||||
|
discount_id: "medusa-185",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.delete(`/store/carts/${cartId}/discounts/${discountData.code}`)
|
||||||
|
|
||||||
|
expect(response.data.cart.items.length).toEqual(1)
|
||||||
|
expect(response.data.cart.items[0].adjustments).toHaveLength(0)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("get-cart with session customer", () => {
|
describe("get-cart with session customer", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
try {
|
await cartSeeder(dbConnection)
|
||||||
await cartSeeder(dbConnection)
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
|||||||
@@ -2281,6 +2281,10 @@ describe("CartService", () => {
|
|||||||
await cartService.update(IdMap.getId("with-d"), {
|
await cartService.update(IdMap.getId("with-d"), {
|
||||||
discounts: [],
|
discounts: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
|
||||||
|
expect(LineItemAdjustmentServiceMock.createAdjustments).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
|
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
|
||||||
expect(eventBusService.emit).toHaveBeenCalledWith(
|
expect(eventBusService.emit).toHaveBeenCalledWith(
|
||||||
"cart.updated",
|
"cart.updated",
|
||||||
@@ -2329,6 +2333,7 @@ describe("CartService", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
items: [],
|
||||||
region_id: IdMap.getId("good"),
|
region_id: IdMap.getId("good"),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -2339,6 +2344,7 @@ describe("CartService", () => {
|
|||||||
totalsService,
|
totalsService,
|
||||||
cartRepository,
|
cartRepository,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
|
lineItemAdjustmentService: LineItemAdjustmentServiceMock,
|
||||||
taxProviderService: taxProviderServiceMock,
|
taxProviderService: taxProviderServiceMock,
|
||||||
newTotalsService: newTotalsServiceMock,
|
newTotalsService: newTotalsServiceMock,
|
||||||
featureFlagRouter: new FlagRouter({}),
|
featureFlagRouter: new FlagRouter({}),
|
||||||
@@ -2351,6 +2357,9 @@ describe("CartService", () => {
|
|||||||
it("successfully removes discount", async () => {
|
it("successfully removes discount", async () => {
|
||||||
await cartService.removeDiscount(IdMap.getId("fr-cart"), "1234")
|
await cartService.removeDiscount(IdMap.getId("fr-cart"), "1234")
|
||||||
|
|
||||||
|
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
|
||||||
|
expect(LineItemAdjustmentServiceMock.createAdjustments).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
|
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
|
||||||
expect(eventBusService.emit).toHaveBeenCalledWith(
|
expect(eventBusService.emit).toHaveBeenCalledWith(
|
||||||
"cart.updated",
|
"cart.updated",
|
||||||
@@ -2361,6 +2370,7 @@ describe("CartService", () => {
|
|||||||
expect(cartRepository.save).toHaveBeenCalledWith({
|
expect(cartRepository.save).toHaveBeenCalledWith({
|
||||||
id: IdMap.getId("cart"),
|
id: IdMap.getId("cart"),
|
||||||
region_id: IdMap.getId("good"),
|
region_id: IdMap.getId("good"),
|
||||||
|
items: [],
|
||||||
discounts: [
|
discounts: [
|
||||||
{
|
{
|
||||||
code: "FS1234",
|
code: "FS1234",
|
||||||
|
|||||||
@@ -1053,7 +1053,7 @@ class CartService extends TransactionBaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDefined(data.discounts)) {
|
if (isDefined(data.discounts) && data.discounts.length) {
|
||||||
const previousDiscounts = [...cart.discounts]
|
const previousDiscounts = [...cart.discounts]
|
||||||
cart.discounts.length = 0
|
cart.discounts.length = 0
|
||||||
|
|
||||||
@@ -1081,6 +1081,9 @@ class CartService extends TransactionBaseService {
|
|||||||
if (hasFreeShipping) {
|
if (hasFreeShipping) {
|
||||||
await this.adjustFreeShipping_(cart, true)
|
await this.adjustFreeShipping_(cart, true)
|
||||||
}
|
}
|
||||||
|
} else if (isDefined(data.discounts) && !data.discounts.length) {
|
||||||
|
cart.discounts.length = 0
|
||||||
|
await this.refreshAdjustments_(cart)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("gift_cards" in data) {
|
if ("gift_cards" in data) {
|
||||||
@@ -1411,6 +1414,8 @@ class CartService extends TransactionBaseService {
|
|||||||
async (transactionManager: EntityManager) => {
|
async (transactionManager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: [
|
relations: [
|
||||||
|
"items",
|
||||||
|
"region",
|
||||||
"discounts",
|
"discounts",
|
||||||
"discounts.rule",
|
"discounts.rule",
|
||||||
"payment_sessions",
|
"payment_sessions",
|
||||||
@@ -1435,7 +1440,9 @@ class CartService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
const updatedCart = await cartRepo.save(cart)
|
const updatedCart = await cartRepo.save(cart)
|
||||||
|
|
||||||
if (updatedCart.payment_sessions?.length) {
|
await this.refreshAdjustments_(updatedCart)
|
||||||
|
|
||||||
|
if (cart.payment_sessions?.length) {
|
||||||
await this.setPaymentSessions(cartId)
|
await this.setPaymentSessions(cartId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user