fix(medusa): Discount allocation precision issues (#3244)

This commit is contained in:
Adrien de Peretti
2023-02-13 17:22:18 +01:00
committed by GitHub
parent bbbb3d8882
commit 4cb44a3a2e
10 changed files with 306 additions and 40 deletions

View File

@@ -2569,15 +2569,13 @@ describe("/admin/order-edits", () => {
]),
}),
]),
// rounding issue since we are allocating 1/3 of the discount to one item and 2/3 to the other item where both cost 10
// resulting in adjustment amounts like: 1333...
discount_total: 2001,
total: 1099,
discount_total: 2000,
gift_card_total: 0,
gift_card_tax_total: 0,
shipping_total: 0,
subtotal: 3000,
tax_total: 100,
total: 1100,
})
)

View File

@@ -2210,16 +2210,18 @@ describe("/admin/products", () => {
expect(deleteRegionPriceResponse.status).toEqual(200)
expect(finalPriceArray).toHaveLength(2)
expect(finalPriceArray).toEqual([
expect.objectContaining({
amount: 1000,
currency_code: "usd",
}),
expect.objectContaining({
amount: 900,
currency_code: "eur",
}),
])
expect(finalPriceArray).toEqual(
expect.arrayContaining([
expect.objectContaining({
amount: 1000,
currency_code: "usd",
}),
expect.objectContaining({
amount: 900,
currency_code: "eur",
}),
])
)
})
it("successfully updates a variants prices by deleting both a currency and region price", async () => {

View File

@@ -10,7 +10,13 @@ const {
simpleOrderFactory,
simpleProductFactory,
simpleShippingOptionFactory,
simpleRegionFactory,
} = require("../../factories")
const {
simpleDiscountFactory,
} = require("../../factories/simple-discount-factory")
jest.setTimeout(30000)
describe("/admin/orders", () => {
let medusaProcess
@@ -236,6 +242,157 @@ describe("/admin/orders", () => {
)
})
test("creates a return w. fixed discount on the total and return the total with the right precision", async () => {
await adminSeeder(dbConnection)
const variant1Price = 4452600
const product1 = await simpleProductFactory(dbConnection, {
variants: [
{
id: "test-variant",
prices: [
{
amount: variant1Price,
currency: "usd",
variant_id: "test-variant",
},
],
},
],
})
const variant2Price = 482200
const product2 = await simpleProductFactory(dbConnection, {
variants: [
{
id: "test-variant-2",
prices: [
{
amount: variant2Price,
currency: "usd",
variant_id: "test-variant-2",
},
],
},
],
})
const region = await simpleRegionFactory(dbConnection, {
id: "test-region",
tax_rate: 12.5,
})
const discountAmount = 10000
const discount = await simpleDiscountFactory(dbConnection, {
id: "test-discount",
code: "TEST-2",
regions: [region.id],
rule: {
type: "fixed",
value: discountAmount,
allocation: "total",
},
})
const item1Id = "test-item"
const item2Id = "test-item-2"
const order = await simpleOrderFactory(dbConnection, {
email: "test@testson.com",
region: region.id,
currency_code: "usd",
line_items: [
{
id: item1Id,
variant_id: product1.variants[0].id,
quantity: 2,
fulfilled_quantity: 2,
shipped_quantity: 2,
unit_price: variant1Price,
adjustments: [
{
amount: 9023,
discount_code: discount.code,
description: "discount",
item_id: "test-item",
},
],
tax_lines: [
{
name: "default",
code: "default",
rate: 20,
},
],
},
{
id: item2Id,
variant_id: product2.variants[0].id,
quantity: 2,
fulfilled_quantity: 2,
shipped_quantity: 2,
unit_price: variant2Price,
adjustments: [
{
amount: 977,
discount_code: discount.code,
description: "discount",
item_id: "test-item",
},
],
tax_lines: [
{
name: "default",
code: "default",
rate: 20,
},
],
},
],
})
const api = useApi()
const response = await api.post(
`/admin/orders/${order.id}/return`,
{
items: [
{
item_id: item1Id,
quantity: 1,
note: "TOO SMALL",
},
],
},
{
headers: {
authorization: "Bearer test_token",
},
}
)
expect(response.status).toEqual(200)
/*
* Region has default tax rate 12.5 but line item has tax rate 20
* total item 1 amount (4452600 * 2 - 9023) * 1.2 = 10675412
* therefore refund amount should be (4452600 - 9023 / 2) * 1.2 = 5337706
* therefore if the second item gets refunded 5337706.2 * 2 = 10675412 which is the expected total amount
*/
expect(response.data.order.returns[0].refund_amount).toEqual(5337706)
expect(response.data.order.returns[0].items).toHaveLength(1)
expect(response.data.order.returns[0].items).toEqual(
expect.arrayContaining([
expect.objectContaining({
item_id: "test-item",
quantity: 1,
note: "TOO SMALL",
}),
])
)
})
test("receives a return with a claimed line item", async () => {
await adminSeeder(dbConnection)

View File

@@ -1466,18 +1466,97 @@ describe("/store/carts", () => {
it("Applies dynamic discount to cart correctly", async () => {
const api = useApi()
const cart = await api.post(
"/store/carts/test-cart",
{
discounts: [{ code: "DYN_DISC" }],
},
{ withCredentials: true }
)
const cart = await api.post("/store/carts/test-cart", {
discounts: [{ code: "DYN_DISC" }],
})
expect(cart.data.cart.shipping_total).toBe(1000)
expect(cart.status).toEqual(200)
})
it("successfully apply a fixed discount with total allocation and return the total with the right precision", async () => {
const api = useApi()
const cartId = "test-cart"
const quantity = 2
const variant1Price = 4452600
const product1 = await simpleProductFactory(dbConnection, {
variants: [
{
id: "test-variant-1-fixed-discount-total",
prices: [
{
amount: variant1Price,
currency: "usd",
variant_id: "test-variant-1-fixed-discount-total",
},
],
},
],
})
await api.post(`/store/carts/${cartId}/line-items`, {
variant_id: product1.variants[0].id,
quantity,
})
const variant2Price = 482200
const product2 = await simpleProductFactory(dbConnection, {
variants: [
{
id: "test-variant-2-fixed-discount-total",
prices: [
{
amount: variant2Price,
currency: "usd",
variant_id: "test-variant-2-fixed-discount-total",
},
],
},
],
})
await api.post(`/store/carts/${cartId}/line-items`, {
variant_id: product2.variants[0].id,
quantity,
})
const discountAmount = 10000
const discount = await simpleDiscountFactory(dbConnection, {
id: "test-discount",
code: "TEST",
regions: ["test-region"],
rule: {
type: "fixed",
value: discountAmount,
allocation: "total",
},
})
const response = await api.post(`/store/carts/${cartId}`, {
discounts: [{ code: discount.code }],
})
expect(response.status).toBe(200)
const cart = response.data.cart
const shippingAmount = 1000
const expectedTotal =
quantity * variant1Price +
quantity * variant2Price +
shippingAmount -
discountAmount
const expectedSubtotal = expectedTotal + discountAmount - shippingAmount
expect(cart.total).toBe(expectedTotal)
expect(cart.subtotal).toBe(expectedSubtotal)
expect(cart.discount_total).toBe(discountAmount)
expect(cart.shipping_total).toBe(1000)
})
it("updates cart customer id", async () => {
const api = useApi()