fix(medusa): Order/Cart decorate totals should assign the items totals (#2546)

**What**

If `total` or `subtotal` are selected then get the line item totals and assign them to the items.

I also had to remove the totals from the cart update service since they are not used and that by having them the items get the tax lines attached and since the update is performed by passing the entire cart, it is trying to insert the tax lines with the cart update

**Tests**

Add an integration tests to validate that the items includes the totals in the order and draft order

FIXES CORE-687
This commit is contained in:
Adrien de Peretti authored and GitHub committed 2022-11-07 13:54:41 +00:00
1 parent 15d6f92964
commit 129ad4b687
9 files changed
+318 -218

No files matched your search

@@ -785,6 +785,40 @@ describe("/admin/draft-orders", () => {
}) })
}) })
describe("GET /admin/draft-orders/:id", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
await draftOrderSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("retrieves a draft-order should include the items totals", async () => {
const api = useApi()
const order = await api.get("/admin/draft-orders/test-draft-order", {
headers: {
authorization: "Bearer test_token",
},
})
expect(order.status).toEqual(200)
expect(order.data.draft_order).toEqual(
expect.objectContaining({
id: "test-draft-order",
})
)
order.data.draft_order.cart.items.forEach((item) => {
expect(item.total).toBeDefined()
expect(item.subtotal).toBeDefined()
})
})
})
describe("DELETE /admin/draft-orders/:id", () => { describe("DELETE /admin/draft-orders/:id", () => {
beforeEach(async () => { beforeEach(async () => {
await adminSeeder(dbConnection) await adminSeeder(dbConnection)
@@ -2284,6 +2284,28 @@ describe("/admin/orders", () => {
) )
}) })
it("retrieves an order should include the items totals", async () => {
const api = useApi()
const order = await api.get("/admin/orders/test-order", {
headers: {
authorization: "Bearer test_token",
},
})
expect(order.status).toEqual(200)
expect(order.data.order).toEqual(
expect.objectContaining({
id: "test-order",
})
)
order.data.order.items.forEach((item) => {
expect(item.total).toBeDefined()
expect(item.subtotal).toBeDefined()
})
})
it("throws on invalid relation", async () => { it("throws on invalid relation", async () => {
const api = useApi() const api = useApi()
@@ -432,6 +432,7 @@ Object {
"claim_order_id": null, "claim_order_id": null,
"created_at": Any<Date>, "created_at": Any<Date>,
"description": "", "description": "",
"discount_total": 0,
"fulfilled_quantity": 2, "fulfilled_quantity": 2,
"has_shipping": null, "has_shipping": null,
"id": Any<String>, "id": Any<String>,
@@ -439,10 +440,13 @@ Object {
"is_return": false, "is_return": false,
"metadata": null, "metadata": null,
"order_id": Any<String>, "order_id": Any<String>,
"original_tax_total": 400,
"original_total": 2400,
"quantity": 2, "quantity": 2,
"returned_quantity": 1, "returned_quantity": 1,
"shipped_quantity": 2, "shipped_quantity": 2,
"should_merge": true, "should_merge": true,
"subtotal": 2000,
"swap_id": null, "swap_id": null,
"tax_lines": Array [ "tax_lines": Array [
Object { Object {
@@ -456,8 +460,10 @@ Object {
"updated_at": Any<Date>, "updated_at": Any<Date>,
}, },
], ],
"tax_total": 400,
"thumbnail": "", "thumbnail": "",
"title": "Intelligent Plastic Chips", "title": "Intelligent Plastic Chips",
"total": 2400,
"unit_price": 1000, "unit_price": 1000,
"updated_at": Any<Date>, "updated_at": Any<Date>,
"variant": Object { "variant": Object {
@@ -768,6 +774,7 @@ Object {
"claim_order_id": null, "claim_order_id": null,
"created_at": Any<Date>, "created_at": Any<Date>,
"description": "", "description": "",
"discount_total": 0,
"fulfilled_quantity": null, "fulfilled_quantity": null,
"has_shipping": null, "has_shipping": null,
"id": "test-item", "id": "test-item",
@@ -775,11 +782,14 @@ Object {
"is_return": false, "is_return": false,
"metadata": null, "metadata": null,
"order_id": Any<String>, "order_id": Any<String>,
"original_tax_total": 400,
"original_total": 2400,
"price": "10.00 USD", "price": "10.00 USD",
"quantity": 2, "quantity": 2,
"returned_quantity": null, "returned_quantity": null,
"shipped_quantity": null, "shipped_quantity": null,
"should_merge": true, "should_merge": true,
"subtotal": 2000,
"swap_id": null, "swap_id": null,
"tax_lines": Array [ "tax_lines": Array [
Object { Object {
@@ -793,8 +803,10 @@ Object {
"updated_at": Any<Date>, "updated_at": Any<Date>,
}, },
], ],
"tax_total": 400,
"thumbnail": null, "thumbnail": null,
"title": "Intelligent Plastic Chips", "title": "Intelligent Plastic Chips",
"total": 2400,
"unit_price": 1000, "unit_price": 1000,
"updated_at": Any<Date>, "updated_at": Any<Date>,
"variant": Object { "variant": Object {
@@ -991,6 +1003,7 @@ Object {
"claim_order_id": null, "claim_order_id": null,
"created_at": Any<Date>, "created_at": Any<Date>,
"description": "", "description": "",
"discount_total": 0,
"discounted_price": "12.00 USD", "discounted_price": "12.00 USD",
"fulfilled_quantity": 2, "fulfilled_quantity": 2,
"has_shipping": null, "has_shipping": null,
@@ -999,11 +1012,14 @@ Object {
"is_return": false, "is_return": false,
"metadata": null, "metadata": null,
"order_id": Any<String>, "order_id": Any<String>,
"original_tax_total": 400,
"original_total": 2400,
"price": "12.00 USD", "price": "12.00 USD",
"quantity": 2, "quantity": 2,
"returned_quantity": null, "returned_quantity": null,
"shipped_quantity": 2, "shipped_quantity": 2,
"should_merge": true, "should_merge": true,
"subtotal": 2000,
"swap_id": null, "swap_id": null,
"tax_lines": Array [ "tax_lines": Array [
Object { Object {
@@ -1017,8 +1033,10 @@ Object {
"updated_at": Any<Date>, "updated_at": Any<Date>,
}, },
], ],
"tax_total": 400,
"thumbnail": null, "thumbnail": null,
"title": "Intelligent Plastic Chips", "title": "Intelligent Plastic Chips",
"total": 2400,
"totals": Object { "totals": Object {
"discount_total": 0, "discount_total": 0,
"original_tax_total": 400, "original_tax_total": 400,
@@ -1258,6 +1276,7 @@ Object {
"claim_order_id": null, "claim_order_id": null,
"created_at": Any<Date>, "created_at": Any<Date>,
"description": "", "description": "",
"discount_total": 0,
"fulfilled_quantity": 2, "fulfilled_quantity": 2,
"has_shipping": null, "has_shipping": null,
"id": "test-item", "id": "test-item",
@@ -1265,10 +1284,13 @@ Object {
"is_return": false, "is_return": false,
"metadata": null, "metadata": null,
"order_id": Any<String>, "order_id": Any<String>,
"original_tax_total": 400,
"original_total": 2400,
"quantity": 2, "quantity": 2,
"returned_quantity": null, "returned_quantity": null,
"shipped_quantity": 2, "shipped_quantity": 2,
"should_merge": true, "should_merge": true,
"subtotal": 2000,
"swap_id": null, "swap_id": null,
"tax_lines": Array [ "tax_lines": Array [
Object { Object {
@@ -1282,8 +1304,10 @@ Object {
"updated_at": Any<Date>, "updated_at": Any<Date>,
}, },
], ],
"tax_total": 400,
"thumbnail": "", "thumbnail": "",
"title": "Intelligent Plastic Chips", "title": "Intelligent Plastic Chips",
"total": 2400,
"unit_price": 1000, "unit_price": 1000,
"updated_at": Any<Date>, "updated_at": Any<Date>,
"variant": Object { "variant": Object {
@@ -1579,6 +1603,7 @@ Object {
"claim_order_id": null, "claim_order_id": null,
"created_at": Any<Date>, "created_at": Any<Date>,
"description": "", "description": "",
"discount_total": 0,
"fulfilled_quantity": 2, "fulfilled_quantity": 2,
"has_shipping": null, "has_shipping": null,
"id": Any<String>, "id": Any<String>,
@@ -1586,10 +1611,13 @@ Object {
"is_return": false, "is_return": false,
"metadata": null, "metadata": null,
"order_id": Any<String>, "order_id": Any<String>,
"original_tax_total": 400,
"original_total": 2400,
"quantity": 2, "quantity": 2,
"returned_quantity": null, "returned_quantity": null,
"shipped_quantity": 2, "shipped_quantity": 2,
"should_merge": true, "should_merge": true,
"subtotal": 2000,
"swap_id": null, "swap_id": null,
"tax_lines": Array [ "tax_lines": Array [
Object { Object {
@@ -1603,8 +1631,10 @@ Object {
"updated_at": Any<Date>, "updated_at": Any<Date>,
}, },
], ],
"tax_total": 400,
"thumbnail": "", "thumbnail": "",
"title": "Intelligent Plastic Chips", "title": "Intelligent Plastic Chips",
"total": 2400,
"unit_price": 1000, "unit_price": 1000,
"updated_at": Any<Date>, "updated_at": Any<Date>,
"variant": Object { "variant": Object {
@@ -1,6 +1,5 @@
import { CartService, DraftOrderService } from "../../../../services" import { CartService, DraftOrderService } from "../../../../services"
import { import {
defaultAdminDraftOrdersCartFields,
defaultAdminDraftOrdersCartRelations, defaultAdminDraftOrdersCartRelations,
defaultAdminDraftOrdersFields, defaultAdminDraftOrdersFields,
defaultAdminDraftOrdersRelations, defaultAdminDraftOrdersRelations,
@@ -72,9 +71,8 @@ export default async (req, res) => {
relations: defaultAdminDraftOrdersRelations, relations: defaultAdminDraftOrdersRelations,
}) })
draftOrder.cart = await cartService.retrieve(draftOrder.cart_id, { draftOrder.cart = await cartService.retrieveWithTotals(draftOrder.cart_id, {
relations: defaultAdminDraftOrdersCartRelations, relations: defaultAdminDraftOrdersCartRelations,
select: defaultAdminDraftOrdersCartFields,
}) })
res.json({ draft_order: draftOrder }) res.json({ draft_order: draftOrder })
@@ -37,6 +37,9 @@ export const TotalsServiceMock = {
getCalculationContext: jest.fn().mockImplementation((order, lineItems) => { getCalculationContext: jest.fn().mockImplementation((order, lineItems) => {
return Promise.resolve({}) return Promise.resolve({})
}), }),
getLineItemTotals: jest.fn().mockImplementation(() => {
return Promise.resolve({})
}),
} }
const mock = jest.fn().mockImplementation(() => { const mock = jest.fn().mockImplementation(() => {
+199 -208
View File
@@ -5,6 +5,7 @@ import CartService from "../cart"
import { InventoryServiceMock } from "../__mocks__/inventory" import { InventoryServiceMock } from "../__mocks__/inventory"
import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment"
import { FlagRouter } from "../../utils/flag-router" import { FlagRouter } from "../../utils/flag-router"
import { taxProviderServiceMock } from "../__mocks__/tax-provider"
const eventBusService = { const eventBusService = {
emit: jest.fn(), emit: jest.fn(),
@@ -57,6 +58,7 @@ describe("CartService", () => {
manager: MockManager, manager: MockManager,
totalsService, totalsService,
cartRepository, cartRepository,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
result = await cartService.retrieve(IdMap.getId("emptyCart")) result = await cartService.retrieve(IdMap.getId("emptyCart"))
@@ -90,6 +92,7 @@ describe("CartService", () => {
totalsService, totalsService,
cartRepository, cartRepository,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -179,6 +182,7 @@ describe("CartService", () => {
customerService, customerService,
regionService, regionService,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -352,6 +356,7 @@ describe("CartService", () => {
inventoryService, inventoryService,
productVariantService, productVariantService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock, lineItemAdjustmentService: LineItemAdjustmentServiceMock,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -585,6 +590,7 @@ describe("CartService", () => {
inventoryService, inventoryService,
productVariantService, productVariantService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock, lineItemAdjustmentService: LineItemAdjustmentServiceMock,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({ sales_channels: true }), featureFlagRouter: new FlagRouter({ sales_channels: true }),
}) })
@@ -680,6 +686,7 @@ describe("CartService", () => {
shippingOptionService, shippingOptionService,
eventBusService, eventBusService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock, lineItemAdjustmentService: LineItemAdjustmentServiceMock,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -786,6 +793,7 @@ describe("CartService", () => {
cartRepository, cartRepository,
totalsService, totalsService,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -798,7 +806,7 @@ describe("CartService", () => {
await cartService.update("withpays", {}) await cartService.update("withpays", {})
expect(cartRepository.findOneWithRelations).toHaveBeenCalledWith( expect(cartRepository.findOneWithRelations).toHaveBeenCalledWith(
[ expect.arrayContaining([
"items", "items",
"shipping_methods", "shipping_methods",
"shipping_address", "shipping_address",
@@ -811,9 +819,7 @@ describe("CartService", () => {
"discounts", "discounts",
"discounts.rule", "discounts.rule",
"discounts.regions", "discounts.regions",
"items.tax_lines", ]),
"region.tax_rates",
],
{ {
where: { id: "withpays" }, where: { id: "withpays" },
} }
@@ -876,6 +882,7 @@ describe("CartService", () => {
eventBusService, eventBusService,
inventoryService, inventoryService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock, lineItemAdjustmentService: LineItemAdjustmentServiceMock,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -958,6 +965,7 @@ describe("CartService", () => {
cartRepository, cartRepository,
eventBusService, eventBusService,
customerService, customerService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -977,19 +985,16 @@ describe("CartService", () => {
) )
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
customer_id: IdMap.getId("existing"), expect.objectContaining({
customer: { customer_id: IdMap.getId("existing"),
id: IdMap.getId("existing"), customer: {
id: IdMap.getId("existing"),
email: "test@testdom.com",
},
email: "test@testdom.com", email: "test@testdom.com",
}, })
email: "test@testdom.com", )
discount_total: 0,
shipping_total: 0,
subtotal: 0,
tax_total: 0,
total: 0,
})
}) })
it("creates a new customer", async () => { it("creates a new customer", async () => {
@@ -1004,16 +1009,13 @@ describe("CartService", () => {
) )
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
customer_id: IdMap.getId("newCus"), expect.objectContaining({
customer: { id: IdMap.getId("newCus"), email: "no@mail.com" }, customer_id: IdMap.getId("newCus"),
email: "no@mail.com", customer: { id: IdMap.getId("newCus"), email: "no@mail.com" },
discount_total: 0, email: "no@mail.com",
shipping_total: 0, })
subtotal: 0, )
tax_total: 0,
total: 0,
})
}) })
it("throws on invalid email", async () => { it("throws on invalid email", async () => {
@@ -1039,6 +1041,7 @@ describe("CartService", () => {
cartRepository, cartRepository,
addressRepository, addressRepository,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -1074,15 +1077,12 @@ describe("CartService", () => {
country_code: "us", country_code: "us",
}) })
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
region: { countries: [{ iso_2: "us" }] }, expect.objectContaining({
discount_total: 0, region: { countries: [{ iso_2: "us" }] },
shipping_total: 0, billing_address: address,
subtotal: 0, })
tax_total: 0, )
total: 0,
billing_address: address,
})
}) })
}) })
@@ -1101,6 +1101,7 @@ describe("CartService", () => {
totalsService, totalsService,
cartRepository, cartRepository,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -1135,15 +1136,12 @@ describe("CartService", () => {
...address, ...address,
}) })
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
region: { countries: [{ iso_2: "us" }] }, expect.objectContaining({
discount_total: 0, region: { countries: [{ iso_2: "us" }] },
shipping_total: 0, shipping_address: address,
subtotal: 0, })
tax_total: 0, )
total: 0,
shipping_address: address,
})
}) })
it("throws if country not in region", async () => { it("throws if country not in region", async () => {
@@ -1256,6 +1254,7 @@ describe("CartService", () => {
eventBusService, eventBusService,
paymentSessionRepository: MockRepository(), paymentSessionRepository: MockRepository(),
priceSelectionStrategy: priceSelectionStrat, priceSelectionStrategy: priceSelectionStrat,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -1287,31 +1286,28 @@ describe("CartService", () => {
) )
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
region_id: "region", expect.objectContaining({
region: { region_id: "region",
id: "region", region: {
countries: [{ iso_2: "us" }], id: "region",
}, countries: [{ iso_2: "us" }],
shipping_address: {
country_code: "us",
},
items: [IdMap.getId("testitem")],
payment_session: null,
payment_sessions: [],
gift_cards: [],
discount_total: 0,
shipping_total: 0,
subtotal: 0,
tax_total: 0,
total: 0,
discounts: [
{
id: IdMap.getId("stays"),
regions: [{ id: IdMap.getId("region-us") }],
}, },
], shipping_address: {
}) country_code: "us",
},
items: [IdMap.getId("testitem")],
payment_session: null,
payment_sessions: [],
gift_cards: [],
discounts: [
{
id: IdMap.getId("stays"),
regions: [{ id: IdMap.getId("region-us") }],
},
],
})
)
}) })
}) })
@@ -1326,6 +1322,8 @@ describe("CartService", () => {
}, },
], ],
}, },
items: [],
shipping_methods: [],
payment_sessions: [ payment_sessions: [
{ {
id: IdMap.getId("test-session"), id: IdMap.getId("test-session"),
@@ -1344,6 +1342,7 @@ describe("CartService", () => {
totalsService, totalsService,
cartRepository, cartRepository,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -1380,6 +1379,7 @@ describe("CartService", () => {
const cart1 = { const cart1 = {
total: 100, total: 100,
items: [{ subtotal: 100 }], items: [{ subtotal: 100 }],
shipping_methods: [],
payment_sessions: [], payment_sessions: [],
region: { region: {
payment_providers: [{ id: "provider_1" }, { id: "provider_2" }], payment_providers: [{ id: "provider_1" }, { id: "provider_2" }],
@@ -1388,6 +1388,8 @@ describe("CartService", () => {
const cart2 = { const cart2 = {
total: 100, total: 100,
items: [],
shipping_methods: [],
payment_sessions: [{ provider_id: "provider_1" }], payment_sessions: [{ provider_id: "provider_1" }],
region: { region: {
payment_providers: [{ id: "provider_1" }, { id: "provider_2" }], payment_providers: [{ id: "provider_1" }, { id: "provider_2" }],
@@ -1464,6 +1466,7 @@ describe("CartService", () => {
cartRepository, cartRepository,
paymentProviderService, paymentProviderService,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -1655,6 +1658,7 @@ describe("CartService", () => {
lineItemService, lineItemService,
eventBusService, eventBusService,
customShippingOptionService, customShippingOptionService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -2010,6 +2014,7 @@ describe("CartService", () => {
discountService, discountService,
eventBusService, eventBusService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock, lineItemAdjustmentService: LineItemAdjustmentServiceMock,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -2032,37 +2037,34 @@ describe("CartService", () => {
) )
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
id: IdMap.getId("cart"), expect.objectContaining({
region_id: IdMap.getId("good"), id: IdMap.getId("cart"),
discount_total: 0, region_id: IdMap.getId("good"),
shipping_total: 0, items: [
subtotal: 0, {
tax_total: 0, id: "li1",
total: 0, quantity: 2,
items: [ unit_price: 1000,
{
id: "li1",
quantity: 2,
unit_price: 1000,
},
{
id: "li2",
quantity: 1,
unit_price: 500,
},
],
discounts: [
{
id: IdMap.getId("10off"),
code: "10%OFF",
regions: [{ id: IdMap.getId("good") }],
rule: {
type: "percentage",
}, },
}, {
], id: "li2",
}) quantity: 1,
unit_price: 500,
},
],
discounts: [
{
id: IdMap.getId("10off"),
code: "10%OFF",
regions: [{ id: IdMap.getId("good") }],
rule: {
type: "percentage",
},
},
],
})
)
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({
@@ -2085,37 +2087,34 @@ describe("CartService", () => {
}) })
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
id: IdMap.getId("cart"), expect.objectContaining({
region_id: IdMap.getId("good"), id: IdMap.getId("cart"),
discount_total: 0, region_id: IdMap.getId("good"),
shipping_total: 0, items: [
subtotal: 0, {
tax_total: 0, id: "li1",
total: 0, quantity: 2,
items: [ unit_price: 1000,
{
id: "li1",
quantity: 2,
unit_price: 1000,
},
{
id: "li2",
quantity: 1,
unit_price: 500,
},
],
discounts: [
{
id: IdMap.getId("10off"),
code: "10%OFF",
regions: [{ id: IdMap.getId("good") }],
rule: {
type: "percentage",
}, },
}, {
], id: "li2",
}) quantity: 1,
unit_price: 500,
},
],
discounts: [
{
id: IdMap.getId("10off"),
code: "10%OFF",
regions: [{ id: IdMap.getId("good") }],
rule: {
type: "percentage",
},
},
],
})
)
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({
@@ -2139,45 +2138,42 @@ describe("CartService", () => {
expect(discountService.retrieveByCode).toHaveBeenCalledTimes(2) expect(discountService.retrieveByCode).toHaveBeenCalledTimes(2)
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
id: IdMap.getId("cart"), expect.objectContaining({
discounts: [ id: IdMap.getId("cart"),
{ discounts: [
id: IdMap.getId("10off"), {
code: "10%OFF", id: IdMap.getId("10off"),
regions: [{ id: IdMap.getId("good") }], code: "10%OFF",
rule: { regions: [{ id: IdMap.getId("good") }],
type: "percentage", rule: {
type: "percentage",
},
}, },
}, {
{ id: IdMap.getId("freeship"),
id: IdMap.getId("freeship"), code: "FREESHIPPING",
code: "FREESHIPPING", regions: [{ id: IdMap.getId("good") }],
regions: [{ id: IdMap.getId("good") }], rule: {
rule: { type: "free_shipping",
type: "free_shipping", },
}, },
}, ],
], items: [
items: [ {
{ id: "li1",
id: "li1", quantity: 2,
quantity: 2, unit_price: 1000,
unit_price: 1000, },
}, {
{ id: "li2",
id: "li2", quantity: 1,
quantity: 1, unit_price: 500,
unit_price: 500, },
}, ],
], region_id: IdMap.getId("good"),
discount_total: 0, })
shipping_total: 0, )
subtotal: 0,
tax_total: 0,
total: 0,
region_id: IdMap.getId("good"),
})
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({
@@ -2209,28 +2205,25 @@ describe("CartService", () => {
) )
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
id: "with-d-and-customer", expect.objectContaining({
region_id: IdMap.getId("good"), id: "with-d-and-customer",
discount_total: 0, region_id: IdMap.getId("good"),
shipping_total: 0, discounts: [
subtotal: 0, {
tax_total: 0, id: "ApplicableForCustomer",
total: 0, code: "ApplicableForCustomer",
discounts: [ regions: [{ id: IdMap.getId("good") }],
{ rule: {
id: "ApplicableForCustomer", id: "test-rule",
code: "ApplicableForCustomer", type: "percentage",
regions: [{ id: IdMap.getId("good") }], },
rule: { starts_at: expect.any(Date),
id: "test-rule", ends_at: expect.any(Date),
type: "percentage",
}, },
starts_at: expect.any(Date), ],
ends_at: expect.any(Date), })
}, )
],
})
}) })
it("successfully remove all discounts that have been applied", async () => { it("successfully remove all discounts that have been applied", async () => {
@@ -2244,28 +2237,25 @@ describe("CartService", () => {
) )
expect(cartRepository.save).toHaveBeenCalledTimes(1) expect(cartRepository.save).toHaveBeenCalledTimes(1)
expect(cartRepository.save).toHaveBeenCalledWith({ expect(cartRepository.save).toHaveBeenCalledWith(
id: IdMap.getId("cart"), expect.objectContaining({
region_id: IdMap.getId("good"), id: IdMap.getId("cart"),
discount_total: 0, region_id: IdMap.getId("good"),
shipping_total: 0, items: [
subtotal: 0, {
tax_total: 0, id: "li1",
total: 0, quantity: 2,
items: [ unit_price: 1000,
{ },
id: "li1", {
quantity: 2, id: "li2",
unit_price: 1000, quantity: 1,
}, unit_price: 500,
{ },
id: "li2", ],
quantity: 1, discounts: [],
unit_price: 500, })
}, )
],
discounts: [],
})
}) })
}) })
@@ -2298,6 +2288,7 @@ describe("CartService", () => {
totalsService, totalsService,
cartRepository, cartRepository,
eventBusService, eventBusService,
taxProviderService: taxProviderServiceMock,
featureFlagRouter: new FlagRouter({}), featureFlagRouter: new FlagRouter({}),
}) })
@@ -8,6 +8,12 @@ describe("OrderService", () => {
withTransaction: function () { withTransaction: function () {
return this return this
}, },
getCalculationContext: jest.fn().mockImplementation((order, lineItems) => {
return Promise.resolve({})
}),
getLineItemTotals: jest.fn().mockImplementation(() => {
return Promise.resolve({})
}),
getLineItemRefund: () => {}, getLineItemRefund: () => {},
getTotal: (o) => { getTotal: (o) => {
return o.total || 0 return o.total || 0
@@ -1249,6 +1255,7 @@ describe("OrderService", () => {
{ {
order: { order: {
id: IdMap.getId("order"), id: IdMap.getId("order"),
items: [],
shipping_methods: [ shipping_methods: [
{ {
shipping_option: { shipping_option: {
@@ -1278,6 +1285,7 @@ describe("OrderService", () => {
{ {
order: { order: {
id: IdMap.getId("order"), id: IdMap.getId("order"),
items: [],
shipping_methods: [ shipping_methods: [
{ {
shipping_option: { shipping_option: {
-7
View File
@@ -920,13 +920,6 @@ class CartService extends TransactionBaseService {
} }
const cart = await this.retrieve(cartId, { const cart = await this.retrieve(cartId, {
select: [
"subtotal",
"tax_total",
"shipping_total",
"discount_total",
"total",
],
relations, relations,
}) })
+21
View File
@@ -1412,6 +1412,27 @@ class OrderService extends TransactionBaseService {
order: Order, order: Order,
totalsFields: string[] = [] totalsFields: string[] = []
): Promise<Order> { ): Promise<Order> {
if (totalsFields.some((field) => ["subtotal", "total"].includes(field))) {
const calculationContext =
await this.totalsService_.getCalculationContext(order, {
exclude_shipping: true,
})
order.items = await Promise.all(
(order.items || []).map(async (item) => {
const itemTotals = await this.totalsService_.getLineItemTotals(
item,
order,
{
include_tax: true,
calculation_context: calculationContext,
}
)
return Object.assign(item, itemTotals)
})
)
}
for (const totalField of totalsFields) { for (const totalField of totalsFields) {
switch (totalField) { switch (totalField) {
case "shipping_total": { case "shipping_total": {