Feat(orders,utils, cart): orders get endpoints and cart totals (#7010)
This commit is contained in:
1 parent
89143e1032
commit
cc557c8752
23 files changed
+2411
-30
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { ICartModuleService } from "@medusajs/types"
|
||||
import { BigNumber } from "@medusajs/utils"
|
||||
import { CheckConstraintViolationException } from "@mikro-orm/core"
|
||||
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
|
||||
|
||||
@@ -2341,5 +2342,409 @@ moduleIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it("should calculate totals of a cart", async () => {
|
||||
const [createdCart] = await service.create([
|
||||
{
|
||||
currency_code: "eur",
|
||||
},
|
||||
])
|
||||
|
||||
const [itemOne] = await service.addLineItems(createdCart.id, [
|
||||
{
|
||||
quantity: 1,
|
||||
unit_price: 100,
|
||||
title: "test",
|
||||
},
|
||||
])
|
||||
|
||||
const [itemTwo] = await service.addLineItems(createdCart.id, [
|
||||
{
|
||||
quantity: 2,
|
||||
unit_price: 200,
|
||||
title: "test-2",
|
||||
},
|
||||
])
|
||||
|
||||
await service.setLineItemAdjustments(createdCart.id, [
|
||||
{
|
||||
item_id: itemOne.id,
|
||||
amount: 100,
|
||||
code: "FREE",
|
||||
},
|
||||
{
|
||||
item_id: itemTwo.id,
|
||||
amount: 200,
|
||||
code: "FREE-2",
|
||||
},
|
||||
])
|
||||
|
||||
await service.addShippingMethods(createdCart.id, [
|
||||
{
|
||||
amount: 10,
|
||||
name: "Test",
|
||||
},
|
||||
])
|
||||
|
||||
const cart = await service.retrieve(createdCart.id, { select: ["total"] })
|
||||
expect(cart.total).toBeInstanceOf(BigNumber)
|
||||
|
||||
const asJson = JSON.parse(JSON.stringify(cart))
|
||||
expect(asJson).toEqual({
|
||||
id: createdCart.id,
|
||||
items: [
|
||||
{
|
||||
id: itemOne.id,
|
||||
cart_id: createdCart.id,
|
||||
title: "test",
|
||||
subtitle: null,
|
||||
thumbnail: null,
|
||||
quantity: 1,
|
||||
variant_id: null,
|
||||
product_id: null,
|
||||
product_title: null,
|
||||
product_description: null,
|
||||
product_subtitle: null,
|
||||
product_type: null,
|
||||
product_collection: null,
|
||||
product_handle: null,
|
||||
variant_sku: null,
|
||||
variant_barcode: null,
|
||||
variant_title: null,
|
||||
variant_option_values: null,
|
||||
requires_shipping: true,
|
||||
is_discountable: true,
|
||||
is_tax_inclusive: false,
|
||||
raw_compare_at_unit_price: null,
|
||||
raw_unit_price: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
metadata: null,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
tax_lines: [],
|
||||
adjustments: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
description: null,
|
||||
code: "FREE",
|
||||
raw_amount: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
provider_id: null,
|
||||
metadata: null,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
item_id: expect.any(String),
|
||||
promotion_id: null,
|
||||
deleted_at: null,
|
||||
amount: 100,
|
||||
subtotal: 100,
|
||||
total: 100,
|
||||
raw_subtotal: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
raw_total: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
},
|
||||
],
|
||||
compare_at_unit_price: null,
|
||||
unit_price: 100,
|
||||
subtotal: 100,
|
||||
total: 0,
|
||||
original_total: 100,
|
||||
discount_total: 100,
|
||||
discount_tax_total: 0,
|
||||
tax_total: 0,
|
||||
original_tax_total: 0,
|
||||
raw_subtotal: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
raw_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_total: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_total: {
|
||||
value: "100",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: itemTwo.id,
|
||||
cart_id: createdCart.id,
|
||||
title: "test-2",
|
||||
subtitle: null,
|
||||
thumbnail: null,
|
||||
quantity: 2,
|
||||
variant_id: null,
|
||||
product_id: null,
|
||||
product_title: null,
|
||||
product_description: null,
|
||||
product_subtitle: null,
|
||||
product_type: null,
|
||||
product_collection: null,
|
||||
product_handle: null,
|
||||
variant_sku: null,
|
||||
variant_barcode: null,
|
||||
variant_title: null,
|
||||
variant_option_values: null,
|
||||
requires_shipping: true,
|
||||
is_discountable: true,
|
||||
is_tax_inclusive: false,
|
||||
raw_compare_at_unit_price: null,
|
||||
raw_unit_price: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
metadata: null,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
tax_lines: [],
|
||||
adjustments: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
description: null,
|
||||
code: "FREE-2",
|
||||
raw_amount: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
provider_id: null,
|
||||
metadata: null,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
item_id: expect.any(String),
|
||||
promotion_id: null,
|
||||
deleted_at: null,
|
||||
amount: 200,
|
||||
subtotal: 200,
|
||||
total: 200,
|
||||
raw_subtotal: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
raw_total: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
},
|
||||
],
|
||||
compare_at_unit_price: null,
|
||||
unit_price: 200,
|
||||
subtotal: 400,
|
||||
total: 200,
|
||||
original_total: 400,
|
||||
discount_total: 200,
|
||||
discount_tax_total: 0,
|
||||
tax_total: 0,
|
||||
original_tax_total: 0,
|
||||
raw_subtotal: {
|
||||
value: "400",
|
||||
precision: 20,
|
||||
},
|
||||
raw_total: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_total: {
|
||||
value: "400",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_total: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
cart_id: expect.any(String),
|
||||
name: "Test",
|
||||
description: null,
|
||||
raw_amount: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
is_tax_inclusive: false,
|
||||
shipping_option_id: null,
|
||||
data: null,
|
||||
metadata: null,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
tax_lines: [],
|
||||
adjustments: [],
|
||||
amount: 10,
|
||||
subtotal: 10,
|
||||
total: 10,
|
||||
original_total: 10,
|
||||
discount_total: 0,
|
||||
discount_tax_total: 0,
|
||||
tax_total: 0,
|
||||
original_tax_total: 0,
|
||||
raw_subtotal: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
raw_total: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_total: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
},
|
||||
],
|
||||
total: 210,
|
||||
subtotal: 500,
|
||||
tax_total: 0,
|
||||
discount_total: 300,
|
||||
discount_tax_total: 0,
|
||||
original_total: 210,
|
||||
original_tax_total: 0,
|
||||
item_total: 200,
|
||||
item_subtotal: 500,
|
||||
item_tax_total: 0,
|
||||
original_item_total: 500,
|
||||
original_item_subtotal: 500,
|
||||
original_item_tax_total: 0,
|
||||
shipping_total: 10,
|
||||
shipping_subtotal: 10,
|
||||
shipping_tax_total: 0,
|
||||
original_shipping_tax_total: 0,
|
||||
original_shipping_tax_subtotal: 10,
|
||||
original_shipping_total: 10,
|
||||
raw_total: {
|
||||
value: "210",
|
||||
precision: 20,
|
||||
},
|
||||
raw_subtotal: {
|
||||
value: "500",
|
||||
precision: 20,
|
||||
},
|
||||
raw_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_total: {
|
||||
value: "300",
|
||||
precision: 20,
|
||||
},
|
||||
raw_discount_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_total: {
|
||||
value: "210",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_item_total: {
|
||||
value: "200",
|
||||
precision: 20,
|
||||
},
|
||||
raw_item_subtotal: {
|
||||
value: "500",
|
||||
precision: 20,
|
||||
},
|
||||
raw_item_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_item_total: {
|
||||
value: "500",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_item_subtotal: {
|
||||
value: "500",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_item_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_shipping_total: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
raw_shipping_subtotal: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
raw_shipping_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_shipping_tax_total: {
|
||||
value: "0",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_shipping_tax_subtotal: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
raw_original_shipping_total: {
|
||||
value: "10",
|
||||
precision: 20,
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -1,7 +1,9 @@
|
||||
import {
|
||||
CartDTO,
|
||||
CartTypes,
|
||||
Context,
|
||||
DAL,
|
||||
FindConfig,
|
||||
ICartModuleService,
|
||||
InternalModuleDeclaration,
|
||||
ModuleJoinerConfig,
|
||||
@@ -13,6 +15,9 @@ import {
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
ModulesSdkUtils,
|
||||
createRawPropertiesFromBigNumber,
|
||||
decorateCartTotals,
|
||||
deduplicate,
|
||||
isObject,
|
||||
isString,
|
||||
} from "@medusajs/utils"
|
||||
@@ -126,6 +131,125 @@ export default class CartModuleService<
|
||||
return joinerConfig
|
||||
}
|
||||
|
||||
private shouldIncludeTotals(config: FindConfig<any>): boolean {
|
||||
const totalFields = [
|
||||
"total",
|
||||
"subtotal",
|
||||
"tax_total",
|
||||
"discount_total",
|
||||
"discount_tax_total",
|
||||
"original_total",
|
||||
"original_tax_total",
|
||||
"item_total",
|
||||
"item_subtotal",
|
||||
"item_tax_total",
|
||||
"original_item_total",
|
||||
"original_item_subtotal",
|
||||
"original_item_tax_total",
|
||||
"shipping_total",
|
||||
"shipping_subtotal",
|
||||
"shipping_tax_total",
|
||||
"original_shipping_tax_total",
|
||||
"original_shipping_tax_subtotal",
|
||||
"original_shipping_total",
|
||||
]
|
||||
|
||||
const includeTotals = (config?.select ?? []).some((field) =>
|
||||
totalFields.includes(field as string)
|
||||
)
|
||||
|
||||
if (includeTotals) {
|
||||
this.addRelationsToCalculateTotals(config, totalFields)
|
||||
}
|
||||
|
||||
return includeTotals
|
||||
}
|
||||
|
||||
private addRelationsToCalculateTotals(config: FindConfig<any>, totalFields) {
|
||||
config.relations ??= []
|
||||
config.select ??= []
|
||||
|
||||
const requiredFieldsForTotals = [
|
||||
"items",
|
||||
"items.tax_lines",
|
||||
"items.adjustments",
|
||||
"shipping_methods",
|
||||
"shipping_methods.tax_lines",
|
||||
"shipping_methods.adjustments",
|
||||
]
|
||||
config.relations = deduplicate([
|
||||
...config.relations,
|
||||
...requiredFieldsForTotals,
|
||||
])
|
||||
|
||||
config.select = config.select.filter((field) => {
|
||||
return (
|
||||
!requiredFieldsForTotals.some((val) =>
|
||||
val.startsWith(field as string)
|
||||
) && !totalFields.includes(field)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async retrieve(
|
||||
id: string,
|
||||
config?: FindConfig<any> | undefined,
|
||||
sharedContext?: Context | undefined
|
||||
): Promise<CartDTO> {
|
||||
config ??= {}
|
||||
const includeTotals = this.shouldIncludeTotals(config)
|
||||
|
||||
const cart = await super.retrieve(id, config, sharedContext)
|
||||
|
||||
if (includeTotals) {
|
||||
createRawPropertiesFromBigNumber(decorateCartTotals(cart))
|
||||
}
|
||||
|
||||
return cart
|
||||
}
|
||||
|
||||
async list(
|
||||
filters?: any,
|
||||
config?: FindConfig<any> | undefined,
|
||||
sharedContext?: Context | undefined
|
||||
): Promise<CartDTO[]> {
|
||||
config ??= {}
|
||||
const includeTotals = this.shouldIncludeTotals(config)
|
||||
|
||||
const carts = await super.list(filters, config, sharedContext)
|
||||
|
||||
if (includeTotals) {
|
||||
carts.forEach((cart) => {
|
||||
createRawPropertiesFromBigNumber(decorateCartTotals(cart))
|
||||
})
|
||||
}
|
||||
|
||||
return carts
|
||||
}
|
||||
|
||||
async listAndCount(
|
||||
filters?: any,
|
||||
config?: FindConfig<any> | undefined,
|
||||
sharedContext?: Context | undefined
|
||||
): Promise<[CartDTO[], number]> {
|
||||
config ??= {}
|
||||
const includeTotals = this.shouldIncludeTotals(config)
|
||||
|
||||
const [carts, count] = await super.listAndCount(
|
||||
filters,
|
||||
config,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
if (includeTotals) {
|
||||
carts.forEach((cart) => {
|
||||
createRawPropertiesFromBigNumber(decorateCartTotals(cart))
|
||||
})
|
||||
}
|
||||
|
||||
return [carts, count]
|
||||
}
|
||||
|
||||
async create(
|
||||
data: CartTypes.CreateCartDTO[],
|
||||
sharedContext?: Context
|
||||
|
||||
Reference in new issue
Block a user