feat: line item adjustments (#1319)
* add: crud services + model + totals * fix: enforce unique constraint on line item adjustment model and update service (#1241) * add: unique constraint on model + fix service * fix: unique constraint * fix: add cascade on delete + fix discount relation * fix: remove optional unique prop * add: tests for ensuring line item adjustment db constraints (#1279) * add: tests for ensuring db constraints * fix: use given when then * feat: adjust cart to include line item adjustments (#1242) * fix: cart service + cart tests * fix: remaining tests * fix: swap tests * fix: add relationship + fix oas * refactor: applyDiscount * fix: refactor applyDiscount and fix + add unit tests * fix: plugins tests * feat: line item adjustments draft orders (#1243) * fix: draft order tests * fix: constraint * fix: wrong variable name * fix: unique constraint * progress: add tests * fix: add cascade on delete + fix discount relation * fix: remove optional unique prop * fix: cart removeLineItem + tests * fix: cart unit tests * fix: update snapshot * remove: verbose option * rename arg Co-authored-by: Sebastian Rindom <skrindom@gmail.com> * add: create adjustments for swap additional_items * add: create adjustments for return lines * fix: unit test for creating adjustment for additional_items * fix: create adjustments only for non return items + no deletion when item is a return item * add: integration tests * refactor: use refreshAdjustments method * refactor test Co-authored-by: Sebastian Rindom <skrindom@gmail.com> Co-authored-by: Sebastian Rindom <skrindom@gmail.com> Co-authored-by: Sebastian Rindom <skrindom@gmail.com>
This commit is contained in:
co-authored by
Sebastian Rindom
parent
607a382b4e
commit
1cfeb5dbd8
@@ -16,7 +16,7 @@ const { initDb, useDb } = require("../../../helpers/use-db")
|
||||
const cartSeeder = require("../../helpers/cart-seeder")
|
||||
const productSeeder = require("../../helpers/product-seeder")
|
||||
const swapSeeder = require("../../helpers/swap-seeder")
|
||||
const { simpleCartFactory } = require("../../factories")
|
||||
const { simpleCartFactory, simpleLineItemFactory } = require("../../factories")
|
||||
const {
|
||||
simpleDiscountFactory,
|
||||
} = require("../../factories/simple-discount-factory")
|
||||
@@ -235,6 +235,131 @@ describe("/store/carts", () => {
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 1,
|
||||
adjustments: [],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("adds line item to cart containing a total fixed discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-total-fixed-discount/line-items",
|
||||
{
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-total-fixed-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 100,
|
||||
discount_id: "total-fixed-100",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("adds line item to cart containing a total percentage discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-total-percentage-discount/line-items",
|
||||
{
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-total-percentage-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 200,
|
||||
discount_id: "10Percent",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("adds line item to cart containing an item fixed discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-item-fixed-discount/line-items",
|
||||
{
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-item-fixed-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 400,
|
||||
discount_id: "item-fixed-200",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("adds line item to cart containing an item percentage discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-item-percentage-discount/line-items",
|
||||
{
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-item-percentage-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 2,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 300,
|
||||
discount_id: "item-percentage-15",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
@@ -242,7 +367,6 @@ describe("/store/carts", () => {
|
||||
it("adds line item to cart time limited sale", async () => {
|
||||
const api = useApi()
|
||||
|
||||
// Add standard line item to cart
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart/line-items",
|
||||
@@ -305,7 +429,6 @@ describe("/store/carts", () => {
|
||||
it("adds line item with quantity to cart with quantity discount", async () => {
|
||||
const api = useApi()
|
||||
|
||||
// Add standard line item to cart
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart/line-items",
|
||||
@@ -330,7 +453,6 @@ describe("/store/carts", () => {
|
||||
it("adds line item with quantity to cart with quantity discount no ceiling", async () => {
|
||||
const api = useApi()
|
||||
|
||||
// Add standard line item to cart
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart/line-items",
|
||||
@@ -351,6 +473,421 @@ describe("/store/carts", () => {
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
describe("ensures correct line item adjustment generation", () => {
|
||||
const discountData = {
|
||||
code: "MEDUSA185DKK",
|
||||
id: "medusa-185",
|
||||
rule: {
|
||||
allocation: "total",
|
||||
type: "fixed",
|
||||
value: 185,
|
||||
},
|
||||
regions: ["test-region"],
|
||||
}
|
||||
|
||||
let discountCart, discount
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
discount = await simpleDiscountFactory(
|
||||
dbConnection,
|
||||
discountData,
|
||||
100
|
||||
)
|
||||
discountCart = await simpleCartFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "discount-cart",
|
||||
customer: "test-customer",
|
||||
region: "test-region",
|
||||
shipping_address: {
|
||||
address_1: "next door",
|
||||
first_name: "lebron",
|
||||
last_name: "james",
|
||||
country_code: "dk",
|
||||
postal_code: "100",
|
||||
},
|
||||
line_items: [
|
||||
{
|
||||
id: "test-li",
|
||||
variant_id: "test-variant",
|
||||
quantity: 1,
|
||||
unit_price: 100,
|
||||
adjustments: [
|
||||
{
|
||||
amount: 185,
|
||||
description: "discount",
|
||||
discount_id: "medusa-185",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
shipping_option: "test-option",
|
||||
price: 1000,
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
await dbConnection.manager
|
||||
.createQueryBuilder()
|
||||
.relation(Cart, "discounts")
|
||||
.of(discountCart)
|
||||
.add(discount)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await doAfterEach()
|
||||
})
|
||||
|
||||
it("updates an old line item adjustment when a new line item is added to a discount cart", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/discount-cart/line-items",
|
||||
{
|
||||
quantity: 1,
|
||||
variant_id: "test-variant-quantity",
|
||||
},
|
||||
{
|
||||
withCredentials: true,
|
||||
}
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items.length).toEqual(2)
|
||||
expect(response.data.cart.items).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
item_id: "test-li",
|
||||
amount: 17,
|
||||
discount_id: "medusa-185",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 168,
|
||||
discount_id: "medusa-185",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("updates an existing item adjustment when a line item is updated", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleLineItemFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "line-item-2",
|
||||
cart_id: discountCart.id,
|
||||
variant_id: "test-variant-quantity",
|
||||
unit_price: 950,
|
||||
quantity: 1,
|
||||
adjustments: [
|
||||
{
|
||||
id: "lia-2",
|
||||
amount: 92,
|
||||
description: "discount",
|
||||
discount_id: "medusa-185",
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/discount-cart/line-items/line-item-2",
|
||||
{
|
||||
quantity: 2,
|
||||
},
|
||||
{
|
||||
withCredentials: true,
|
||||
}
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items.length).toEqual(2)
|
||||
expect(response.data.cart.items).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
item_id: "test-li",
|
||||
discount_id: "medusa-185",
|
||||
amount: 9,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
item_id: "line-item-2",
|
||||
amount: 176,
|
||||
discount_id: "medusa-185",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("updates an existing item adjustment when a line item is deleted from a discount cart", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await simpleLineItemFactory(
|
||||
dbConnection,
|
||||
{
|
||||
id: "line-item-2",
|
||||
cart_id: discountCart.id,
|
||||
variant_id: "test-variant-quantity",
|
||||
unit_price: 1000,
|
||||
quantity: 1,
|
||||
adjustments: [
|
||||
{
|
||||
id: "lia-2",
|
||||
amount: 93,
|
||||
description: "discount",
|
||||
discount_id: "medusa-185",
|
||||
},
|
||||
],
|
||||
},
|
||||
100
|
||||
)
|
||||
|
||||
const response = await api
|
||||
.delete("/store/carts/discount-cart/line-items/test-li", {
|
||||
withCredentials: true,
|
||||
})
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items.length).toEqual(1)
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
item_id: "line-item-2",
|
||||
amount: 185,
|
||||
discount_id: "medusa-185",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /store/carts/:id/line-items/:line_id", () => {
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
await cartSeeder(dbConnection)
|
||||
await swapSeeder(dbConnection)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
throw err
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await doAfterEach()
|
||||
})
|
||||
|
||||
it("updates line item of cart", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-3/line-items/test-item3/",
|
||||
{
|
||||
quantity: 3,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-3",
|
||||
unit_price: 8000,
|
||||
variant_id: "test-variant-sale-cg",
|
||||
quantity: 3,
|
||||
adjustments: [],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("updates line item of a cart containing a total fixed discount", async () => {
|
||||
const api = useApi()
|
||||
await simpleLineItemFactory(dbConnection, {
|
||||
id: "test-li-disc",
|
||||
allow_discounts: true,
|
||||
title: "Line Item Disc",
|
||||
thumbnail: "https://test.js/1234",
|
||||
unit_price: 1000,
|
||||
quantity: 1,
|
||||
variant_id: "test-variant-quantity",
|
||||
cart_id: "test-cart-w-total-fixed-discount",
|
||||
})
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
`store/carts/test-cart-w-total-fixed-discount/line-items/test-li-disc`,
|
||||
{
|
||||
quantity: 3,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-total-fixed-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 3,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 100,
|
||||
discount_id: "total-fixed-100",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("updates line item of a cart containing a total percentage discount", async () => {
|
||||
const api = useApi()
|
||||
await simpleLineItemFactory(dbConnection, {
|
||||
id: "test-li-disc",
|
||||
allow_discounts: true,
|
||||
title: "Line Item Disc",
|
||||
thumbnail: "https://test.js/1234",
|
||||
unit_price: 1000,
|
||||
quantity: 1,
|
||||
variant_id: "test-variant-quantity",
|
||||
cart_id: "test-cart-w-total-percentage-discount",
|
||||
})
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-total-percentage-discount/line-items/test-li-disc",
|
||||
{
|
||||
quantity: 10,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-total-percentage-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 10,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 1000,
|
||||
discount_id: "10Percent",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("updates line item of a cart containing an item fixed discount", async () => {
|
||||
const api = useApi()
|
||||
await simpleLineItemFactory(dbConnection, {
|
||||
id: "test-li-disc",
|
||||
allow_discounts: true,
|
||||
title: "Line Item Disc",
|
||||
thumbnail: "https://test.js/1234",
|
||||
unit_price: 1000,
|
||||
quantity: 1,
|
||||
variant_id: "test-variant-quantity",
|
||||
cart_id: "test-cart-w-item-fixed-discount",
|
||||
})
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-item-fixed-discount/line-items/test-li-disc",
|
||||
{
|
||||
quantity: 4,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-item-fixed-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 4,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 800,
|
||||
discount_id: "item-fixed-200",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("updates line item of a cart containing an item percentage discount", async () => {
|
||||
const api = useApi()
|
||||
await simpleLineItemFactory(dbConnection, {
|
||||
id: "test-li-disc",
|
||||
allow_discounts: true,
|
||||
title: "Line Item Disc",
|
||||
thumbnail: "https://test.js/1234",
|
||||
unit_price: 1000,
|
||||
quantity: 1,
|
||||
variant_id: "test-variant-quantity",
|
||||
cart_id: "test-cart-w-item-percentage-discount",
|
||||
})
|
||||
|
||||
const response = await api
|
||||
.post(
|
||||
"/store/carts/test-cart-w-item-percentage-discount/line-items/test-li-disc",
|
||||
{
|
||||
quantity: 3,
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
expect(response.data.cart.items).toEqual([
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-w-item-percentage-discount",
|
||||
unit_price: 1000,
|
||||
variant_id: "test-variant-quantity",
|
||||
quantity: 3,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 450,
|
||||
discount_id: "item-percentage-15",
|
||||
description: "discount",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /store/carts/:id", () => {
|
||||
@@ -1202,6 +1739,22 @@ describe("/store/carts", () => {
|
||||
.catch((err) => console.log(err))
|
||||
|
||||
// Ensure that the discount is only applied to the standard item
|
||||
const itemId = cartWithGiftcard.data.cart.items[0].id
|
||||
expect(cartWithGiftcard.data.cart.items).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
variant_id: "test-variant",
|
||||
quantity: 1,
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
discount_id: "10Percent",
|
||||
amount: 100,
|
||||
item_id: itemId,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
])
|
||||
)
|
||||
expect(cartWithGiftcard.data.cart.total).toBe(1900) // 1000 (giftcard) + 900 (standard item with 10% discount)
|
||||
expect(cartWithGiftcard.data.cart.discount_total).toBe(100)
|
||||
expect(cartWithGiftcard.status).toEqual(200)
|
||||
|
||||
Reference in New Issue
Block a user