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:
Adrien de Peretti
2022-12-12 10:53:40 +01:00
committed by GitHub
parent 72f70bc789
commit d68e81fb3d
4 changed files with 185 additions and 18 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
fix(medusa): Should update the adjustments upon cart discount removal

View File

@@ -520,6 +520,7 @@ describe("/store/carts", () => {
let discountCart
let discount
beforeEach(async () => {
discount = await simpleDiscountFactory(dbConnection, discountData, 100)
discountCart = await simpleCartFactory(
@@ -1042,6 +1043,86 @@ describe("/store/carts", () => {
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 () => {
const api = useApi()
@@ -2035,17 +2116,23 @@ describe("/store/carts", () => {
})
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 () => {
try {
await cartSeeder(dbConnection)
await dbConnection.manager.query(
`INSERT INTO "cart_discounts" (cart_id, discount_id)
VALUES ('test-cart', 'free-shipping')`
)
} catch (err) {
console.log(err)
throw err
}
await cartSeeder(dbConnection)
await dbConnection.manager.query(
`INSERT INTO "cart_discounts" (cart_id, discount_id)
VALUES ('test-cart', 'free-shipping')`
)
})
afterEach(async () => {
@@ -2073,16 +2160,74 @@ describe("/store/carts", () => {
expect(response.data.cart.shipping_total).toBe(1000)
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", () => {
beforeEach(async () => {
try {
await cartSeeder(dbConnection)
} catch (err) {
console.log(err)
throw err
}
await cartSeeder(dbConnection)
})
afterEach(async () => {

View File

@@ -2281,6 +2281,10 @@ describe("CartService", () => {
await cartService.update(IdMap.getId("with-d"), {
discounts: [],
})
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
expect(LineItemAdjustmentServiceMock.createAdjustments).toHaveBeenCalledTimes(1)
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
expect(eventBusService.emit).toHaveBeenCalledWith(
"cart.updated",
@@ -2329,6 +2333,7 @@ describe("CartService", () => {
},
},
],
items: [],
region_id: IdMap.getId("good"),
})
},
@@ -2339,6 +2344,7 @@ describe("CartService", () => {
totalsService,
cartRepository,
eventBusService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock,
taxProviderService: taxProviderServiceMock,
newTotalsService: newTotalsServiceMock,
featureFlagRouter: new FlagRouter({}),
@@ -2351,6 +2357,9 @@ describe("CartService", () => {
it("successfully removes discount", async () => {
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).toHaveBeenCalledWith(
"cart.updated",
@@ -2361,6 +2370,7 @@ describe("CartService", () => {
expect(cartRepository.save).toHaveBeenCalledWith({
id: IdMap.getId("cart"),
region_id: IdMap.getId("good"),
items: [],
discounts: [
{
code: "FS1234",

View File

@@ -1053,7 +1053,7 @@ class CartService extends TransactionBaseService {
}
}
if (isDefined(data.discounts)) {
if (isDefined(data.discounts) && data.discounts.length) {
const previousDiscounts = [...cart.discounts]
cart.discounts.length = 0
@@ -1081,6 +1081,9 @@ class CartService extends TransactionBaseService {
if (hasFreeShipping) {
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) {
@@ -1411,6 +1414,8 @@ class CartService extends TransactionBaseService {
async (transactionManager: EntityManager) => {
const cart = await this.retrieve(cartId, {
relations: [
"items",
"region",
"discounts",
"discounts.rule",
"payment_sessions",
@@ -1435,7 +1440,9 @@ class CartService extends TransactionBaseService {
)
const updatedCart = await cartRepo.save(cart)
if (updatedCart.payment_sessions?.length) {
await this.refreshAdjustments_(updatedCart)
if (cart.payment_sessions?.length) {
await this.setPaymentSessions(cartId)
}