fix: Cart operation should calculate item prices accounting for quantity (#13251)
* fix(): Cart operation should calculate item prices accounting for quantity * fix(): Cart operation should calculate item prices accounting for quantity * fix(): Cart operation should calculate item prices accounting for quantity * fix when call warning * fix tests and remove unnecessary object copy * Create warm-dancers-allow.md * fix update line item in cart workflow * fix changeset * update order flows * fix cart spec integration tests * improve create order workflow * fixes and tests adjustments/improvements * configurable useQueryGraphStep return type * revert nullable take * cleanup useQueryGraphStep
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
IRegionModuleService,
|
||||
ISalesChannelModuleService,
|
||||
IStockLocationService,
|
||||
PricingContext,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
@@ -759,11 +760,23 @@ medusaIntegrationTestRunner({
|
||||
* Tried jest, but for some reasons it is not able to provide
|
||||
* correct arguments passed to the function
|
||||
*/
|
||||
let pricingContext: any
|
||||
const originalFn = pricingModule.listPriceSets.bind(pricingModule)
|
||||
pricingModule.listPriceSets = function () {
|
||||
pricingContext = { ...arguments[0].context }
|
||||
return originalFn.bind(pricingModule)(...arguments)
|
||||
let calculatePricesHasBeenCalled = false
|
||||
|
||||
const originalFn = pricingModule.calculatePrices.bind(pricingModule)
|
||||
pricingModule.calculatePrices = function (...args) {
|
||||
calculatePricesHasBeenCalled = true
|
||||
|
||||
const pricingContext = args[1]!.context
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
unit_price: 100,
|
||||
region_id: region.id,
|
||||
currency_code: "usd",
|
||||
})
|
||||
)
|
||||
|
||||
return originalFn.bind(pricingModule)(...args)
|
||||
}
|
||||
|
||||
const { result } = await createCartWorkflow(appContainer).run({
|
||||
@@ -782,15 +795,9 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
setPricingContextHook = undefined
|
||||
pricingModule.listPriceSets = originalFn
|
||||
pricingModule.calculatePrices = originalFn
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
unit_price: 100,
|
||||
region_id: region.id,
|
||||
currency_code: "usd",
|
||||
})
|
||||
)
|
||||
expect(calculatePricesHasBeenCalled).toBe(true)
|
||||
|
||||
const cart = await cartModuleService.retrieveCart(result.id, {
|
||||
relations: ["items"],
|
||||
@@ -924,11 +931,25 @@ medusaIntegrationTestRunner({
|
||||
* Tried jest, but for some reasons it is not able to provide
|
||||
* correct arguments passed to the function
|
||||
*/
|
||||
let pricingContext: any
|
||||
const originalFn = pricingModule.listPriceSets.bind(pricingModule)
|
||||
pricingModule.listPriceSets = function () {
|
||||
pricingContext = { ...arguments[0].context }
|
||||
return originalFn.bind(pricingModule)(...arguments)
|
||||
let calculatePricesHasBeenCalled = false
|
||||
|
||||
const originalFn = pricingModule.calculatePrices.bind(pricingModule)
|
||||
pricingModule.calculatePrices = function (...args) {
|
||||
calculatePricesHasBeenCalled = true
|
||||
|
||||
const pricingContext = args[1]!.context
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
unit_price: 200,
|
||||
region_id: region.id,
|
||||
currency_code: "usd",
|
||||
})
|
||||
)
|
||||
expect(pricingContext?.customer_id).toBeDefined()
|
||||
expect(pricingContext?.customer_id).not.toEqual("1")
|
||||
|
||||
return originalFn.bind(pricingModule)(...args)
|
||||
}
|
||||
|
||||
const { result } = await createCartWorkflow(appContainer).run({
|
||||
@@ -947,17 +968,9 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
setPricingContextHook = undefined
|
||||
pricingModule.listPriceSets = originalFn
|
||||
pricingModule.calculatePrices = originalFn
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
unit_price: 200,
|
||||
region_id: region.id,
|
||||
currency_code: "usd",
|
||||
})
|
||||
)
|
||||
expect(pricingContext.customer_id).toBeDefined()
|
||||
expect(pricingContext.customer_id).not.toEqual("1")
|
||||
expect(calculatePricesHasBeenCalled).toBe(true)
|
||||
|
||||
const cart = await cartModuleService.retrieveCart(result.id, {
|
||||
relations: ["items"],
|
||||
@@ -1851,7 +1864,7 @@ medusaIntegrationTestRunner({
|
||||
|
||||
expect(errors).toEqual([
|
||||
{
|
||||
action: "validate-variant-prices",
|
||||
action: "get-variant-price-sets",
|
||||
handlerType: "invoke",
|
||||
error: expect.objectContaining({
|
||||
message: expect.stringContaining(
|
||||
@@ -1960,10 +1973,22 @@ medusaIntegrationTestRunner({
|
||||
* correct arguments passed to the function
|
||||
*/
|
||||
let pricingContext: any
|
||||
const originalFn = pricingModule.listPriceSets.bind(pricingModule)
|
||||
pricingModule.listPriceSets = function () {
|
||||
pricingContext = { ...arguments[0].context }
|
||||
return originalFn.bind(pricingModule)(...arguments)
|
||||
let calculatePricessHaveBeenCalled = false
|
||||
const originalFn = pricingModule.calculatePrices.bind(pricingModule)
|
||||
pricingModule.calculatePrices = function (...args) {
|
||||
pricingContext = args[1]!
|
||||
calculatePricessHaveBeenCalled = true
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
context: expect.objectContaining({
|
||||
unit_price: 100,
|
||||
currency_code: "usd",
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
return originalFn.bind(pricingModule)(...args)
|
||||
}
|
||||
|
||||
await addToCartWorkflow(appContainer).run({
|
||||
@@ -1979,14 +2004,9 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
setPricingContextHook = undefined
|
||||
pricingModule.listPriceSets = originalFn
|
||||
pricingModule.calculatePrices = originalFn
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
unit_price: 100,
|
||||
currency_code: "usd",
|
||||
})
|
||||
)
|
||||
expect(calculatePricessHaveBeenCalled).toBe(true)
|
||||
|
||||
cart = await cartModuleService.retrieveCart(cart.id, {
|
||||
relations: ["items"],
|
||||
@@ -2114,9 +2134,24 @@ medusaIntegrationTestRunner({
|
||||
* correct arguments passed to the function
|
||||
*/
|
||||
let pricingContext: any
|
||||
const originalFn = pricingModule.listPriceSets.bind(pricingModule)
|
||||
pricingModule.listPriceSets = function () {
|
||||
pricingContext = { ...arguments[0].context }
|
||||
let calculatePricessHaveBeenCalled = false
|
||||
|
||||
const originalFn = pricingModule.calculatePrices.bind(pricingModule)
|
||||
pricingModule.calculatePrices = function (...args) {
|
||||
pricingContext = args[1]!
|
||||
calculatePricessHaveBeenCalled = true
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
context: expect.objectContaining({
|
||||
unit_price: 200,
|
||||
region_id: cart.region_id,
|
||||
customer_id: cart.customer_id,
|
||||
currency_code: "usd",
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
return originalFn.bind(pricingModule)(...arguments)
|
||||
}
|
||||
|
||||
@@ -2133,21 +2168,14 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
setPricingContextHook = undefined
|
||||
pricingModule.listPriceSets = originalFn
|
||||
|
||||
expect(pricingContext).toEqual(
|
||||
expect.objectContaining({
|
||||
unit_price: 200,
|
||||
region_id: cart.region_id,
|
||||
customer_id: cart.customer_id,
|
||||
currency_code: "usd",
|
||||
})
|
||||
)
|
||||
pricingModule.calculatePrices = originalFn
|
||||
|
||||
cart = await cartModuleService.retrieveCart(cart.id, {
|
||||
relations: ["items"],
|
||||
})
|
||||
|
||||
expect(calculatePricessHaveBeenCalled).toBe(true)
|
||||
|
||||
expect(cart).toEqual(
|
||||
expect.objectContaining({
|
||||
id: cart.id,
|
||||
|
||||
@@ -10,7 +10,12 @@ import {
|
||||
IStockLocationServiceNext,
|
||||
ITaxModuleService,
|
||||
} from "@medusajs/types"
|
||||
import { ContainerRegistrationKeys, Modules } from "@medusajs/utils"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
Modules,
|
||||
PromotionStatus,
|
||||
PromotionType,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
adminHeaders,
|
||||
createAdminUser,
|
||||
@@ -25,30 +30,25 @@ medusaIntegrationTestRunner({
|
||||
env,
|
||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||
let appContainer
|
||||
let cartModuleService: ICartModuleService
|
||||
let regionModuleService: IRegionModuleService
|
||||
let scModuleService: ISalesChannelModuleService
|
||||
let productModule: IProductModuleService
|
||||
let pricingModule: IPricingModuleService
|
||||
let inventoryModule: IInventoryServiceNext
|
||||
let stockLocationModule: IStockLocationServiceNext
|
||||
let fulfillmentModule: IFulfillmentModuleService
|
||||
let taxModule: ITaxModuleService
|
||||
let remoteLink, remoteQuery
|
||||
let remoteLink
|
||||
|
||||
beforeAll(async () => {
|
||||
appContainer = getContainer()
|
||||
cartModuleService = appContainer.resolve(Modules.CART)
|
||||
regionModuleService = appContainer.resolve(Modules.REGION)
|
||||
scModuleService = appContainer.resolve(Modules.SALES_CHANNEL)
|
||||
productModule = appContainer.resolve(Modules.PRODUCT)
|
||||
pricingModule = appContainer.resolve(Modules.PRICING)
|
||||
inventoryModule = appContainer.resolve(Modules.INVENTORY)
|
||||
stockLocationModule = appContainer.resolve(Modules.STOCK_LOCATION)
|
||||
fulfillmentModule = appContainer.resolve(Modules.FULFILLMENT)
|
||||
taxModule = appContainer.resolve(Modules.TAX)
|
||||
remoteLink = appContainer.resolve(ContainerRegistrationKeys.REMOTE_LINK)
|
||||
remoteQuery = appContainer.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -199,7 +199,6 @@ medusaIntegrationTestRunner({
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
},
|
||||
promo_codes: ["testytest"],
|
||||
items: [
|
||||
{
|
||||
variant_id: product.variants[0].id,
|
||||
@@ -386,6 +385,388 @@ medusaIntegrationTestRunner({
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("should create a draft order applying the correct promotion on the items", async () => {
|
||||
const region = await regionModuleService.createRegions({
|
||||
name: "US",
|
||||
currency_code: "usd",
|
||||
})
|
||||
|
||||
const salesChannel = await scModuleService.createSalesChannels({
|
||||
name: "Webshop",
|
||||
})
|
||||
|
||||
const location = await stockLocationModule.createStockLocations({
|
||||
name: "Warehouse",
|
||||
})
|
||||
|
||||
const [product, product_2] = await productModule.createProducts([
|
||||
{
|
||||
title: "Test product",
|
||||
variants: [
|
||||
{
|
||||
title: "Test variant",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Another product",
|
||||
variants: [
|
||||
{
|
||||
title: "Variant variable",
|
||||
manage_inventory: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
const inventoryItem = await inventoryModule.createInventoryItems({
|
||||
sku: "inv-1234",
|
||||
})
|
||||
|
||||
await inventoryModule.createInventoryLevels([
|
||||
{
|
||||
inventory_item_id: inventoryItem.id,
|
||||
location_id: location.id,
|
||||
stocked_quantity: 2,
|
||||
reserved_quantity: 0,
|
||||
},
|
||||
])
|
||||
|
||||
const [priceSet, priceSet_2] = await pricingModule.createPriceSets([
|
||||
{
|
||||
prices: [
|
||||
{
|
||||
amount: 3000,
|
||||
currency_code: "usd",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
prices: [
|
||||
{
|
||||
amount: 1000,
|
||||
currency_code: "usd",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
/**
|
||||
* Create a promotion to test with
|
||||
*/
|
||||
const promotion = (
|
||||
await api.post(
|
||||
`/admin/promotions`,
|
||||
{
|
||||
code: "testytest",
|
||||
type: PromotionType.STANDARD,
|
||||
status: PromotionStatus.ACTIVE,
|
||||
application_method: {
|
||||
target_type: "items",
|
||||
type: "fixed",
|
||||
allocation: "each",
|
||||
currency_code: "usd",
|
||||
value: 100,
|
||||
max_quantity: 100,
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "variant_id",
|
||||
operator: "in",
|
||||
values: [product.variants[0].id, product_2.variants[0].id],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.promotion
|
||||
|
||||
await api.post(
|
||||
"/admin/price-preferences",
|
||||
{
|
||||
attribute: "currency_code",
|
||||
value: "usd",
|
||||
is_tax_inclusive: true,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
await remoteLink.create([
|
||||
{
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product.variants[0].id,
|
||||
},
|
||||
[Modules.PRICING]: {
|
||||
price_set_id: priceSet.id,
|
||||
},
|
||||
},
|
||||
{
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product_2.variants[0].id,
|
||||
},
|
||||
[Modules.PRICING]: {
|
||||
price_set_id: priceSet_2.id,
|
||||
},
|
||||
},
|
||||
{
|
||||
[Modules.SALES_CHANNEL]: {
|
||||
sales_channel_id: salesChannel.id,
|
||||
},
|
||||
[Modules.STOCK_LOCATION]: {
|
||||
stock_location_id: location.id,
|
||||
},
|
||||
},
|
||||
{
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product.variants[0].id,
|
||||
},
|
||||
[Modules.INVENTORY]: {
|
||||
inventory_item_id: inventoryItem.id,
|
||||
},
|
||||
},
|
||||
{
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product_2.variants[0].id,
|
||||
},
|
||||
[Modules.INVENTORY]: {
|
||||
inventory_item_id: inventoryItem.id,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await setupTaxStructure(taxModule)
|
||||
|
||||
const payload = {
|
||||
email: "oli@test.dk",
|
||||
region_id: region.id,
|
||||
sales_channel_id: salesChannel.id,
|
||||
currency_code: "usd",
|
||||
shipping_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Test",
|
||||
address_1: "Test",
|
||||
city: "Test",
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
phone: "12345",
|
||||
},
|
||||
billing_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Test",
|
||||
address_1: "Test",
|
||||
city: "Test",
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
},
|
||||
promo_codes: ["testytest"],
|
||||
items: [
|
||||
{
|
||||
variant_id: product.variants[0].id,
|
||||
is_discountable: true,
|
||||
quantity: 2,
|
||||
},
|
||||
{
|
||||
variant_id: product_2.variants[0].id,
|
||||
is_discountable: true,
|
||||
unit_price: 200,
|
||||
quantity: 1,
|
||||
metadata: {
|
||||
note: "reduced price",
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Custom Item",
|
||||
variant_sku: "sku123",
|
||||
variant_barcode: "barcode123",
|
||||
is_discountable: true,
|
||||
unit_price: 2200,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "test-method",
|
||||
shipping_option_id: "test-option",
|
||||
amount: 100,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await api.post(
|
||||
"/admin/draft-orders",
|
||||
payload,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.data).toEqual(
|
||||
expect.objectContaining({
|
||||
draft_order: expect.objectContaining({
|
||||
status: "draft",
|
||||
version: 1,
|
||||
summary: expect.objectContaining({
|
||||
// TODO: add summary fields
|
||||
}),
|
||||
items: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: "Test product",
|
||||
subtitle: "Test variant",
|
||||
product_title: "Test product",
|
||||
product_description: null,
|
||||
product_subtitle: null,
|
||||
product_type: null,
|
||||
product_type_id: null,
|
||||
product_collection: null,
|
||||
product_handle: "test-product",
|
||||
variant_sku: null,
|
||||
variant_barcode: null,
|
||||
variant_title: "Test variant",
|
||||
variant_option_values: null,
|
||||
requires_shipping: true,
|
||||
is_discountable: true,
|
||||
is_tax_inclusive: true,
|
||||
is_custom_price: false,
|
||||
raw_compare_at_unit_price: null,
|
||||
raw_unit_price: expect.objectContaining({
|
||||
value: "3000",
|
||||
}),
|
||||
metadata: {},
|
||||
tax_lines: [
|
||||
expect.objectContaining({
|
||||
code: "US_DEF",
|
||||
provider_id: "system",
|
||||
rate: 2,
|
||||
}),
|
||||
],
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 200,
|
||||
code: "testytest",
|
||||
is_tax_inclusive: false,
|
||||
promotion_id: promotion.id,
|
||||
provider_id: null,
|
||||
}),
|
||||
],
|
||||
unit_price: 3000,
|
||||
quantity: 2,
|
||||
raw_quantity: expect.objectContaining({
|
||||
value: "2",
|
||||
}),
|
||||
detail: expect.objectContaining({
|
||||
raw_quantity: expect.objectContaining({
|
||||
value: "2",
|
||||
}),
|
||||
raw_fulfilled_quantity: expect.objectContaining({
|
||||
value: "0",
|
||||
}),
|
||||
raw_shipped_quantity: expect.objectContaining({
|
||||
value: "0",
|
||||
}),
|
||||
raw_return_requested_quantity: expect.objectContaining({
|
||||
value: "0",
|
||||
}),
|
||||
raw_return_received_quantity: expect.objectContaining({
|
||||
value: "0",
|
||||
}),
|
||||
raw_return_dismissed_quantity: expect.objectContaining({
|
||||
value: "0",
|
||||
}),
|
||||
raw_written_off_quantity: expect.objectContaining({
|
||||
value: "0",
|
||||
}),
|
||||
quantity: 2,
|
||||
fulfilled_quantity: 0,
|
||||
shipped_quantity: 0,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
title: "Another product",
|
||||
subtitle: "Variant variable",
|
||||
raw_unit_price: expect.objectContaining({
|
||||
value: "200",
|
||||
}),
|
||||
metadata: {
|
||||
note: "reduced price",
|
||||
},
|
||||
unit_price: 200,
|
||||
is_tax_inclusive: true,
|
||||
quantity: 1,
|
||||
raw_quantity: expect.objectContaining({
|
||||
value: "1",
|
||||
}),
|
||||
adjustments: [
|
||||
expect.objectContaining({
|
||||
amount: 100,
|
||||
code: "testytest",
|
||||
is_tax_inclusive: false,
|
||||
promotion_id: promotion.id,
|
||||
provider_id: null,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
title: "Custom Item",
|
||||
variant_sku: "sku123",
|
||||
variant_barcode: "barcode123",
|
||||
variant_title: null,
|
||||
is_custom_price: true,
|
||||
raw_unit_price: expect.objectContaining({
|
||||
value: "2200",
|
||||
}),
|
||||
unit_price: 2200,
|
||||
quantity: 1,
|
||||
raw_quantity: expect.objectContaining({
|
||||
value: "1",
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
shipping_address: expect.objectContaining({
|
||||
last_name: "Test",
|
||||
address_1: "Test",
|
||||
city: "Test",
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
phone: "12345",
|
||||
}),
|
||||
billing_address: expect.objectContaining({
|
||||
first_name: "Test",
|
||||
last_name: "Test",
|
||||
address_1: "Test",
|
||||
city: "Test",
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
}),
|
||||
shipping_methods: [
|
||||
expect.objectContaining({
|
||||
name: "test-method",
|
||||
raw_amount: expect.objectContaining({
|
||||
value: "100",
|
||||
}),
|
||||
is_tax_inclusive: false,
|
||||
shipping_option_id: "test-option",
|
||||
data: null,
|
||||
tax_lines: [
|
||||
expect.objectContaining({
|
||||
code: "US_DEF",
|
||||
provider_id: "system",
|
||||
rate: 2,
|
||||
}),
|
||||
],
|
||||
adjustments: [],
|
||||
amount: 100,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("should create a draft order and apply tax by product type", async () => {
|
||||
const productType = await productModule.createProductTypes({
|
||||
value: "test_product_type",
|
||||
@@ -396,11 +777,17 @@ medusaIntegrationTestRunner({
|
||||
currency_code: "usd",
|
||||
})
|
||||
|
||||
const [taxRegion] = await taxModule.createTaxRegions([{
|
||||
country_code: "US",
|
||||
provider_id: "tp_system",
|
||||
default_tax_rate: { name: "US Default Rate", rate: 5, code: "US_DEF" },
|
||||
}])
|
||||
const [taxRegion] = await taxModule.createTaxRegions([
|
||||
{
|
||||
country_code: "US",
|
||||
provider_id: "tp_system",
|
||||
default_tax_rate: {
|
||||
name: "US Default Rate",
|
||||
rate: 5,
|
||||
code: "US_DEF",
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const [taxRate] = await taxModule.createTaxRates([
|
||||
{
|
||||
@@ -408,14 +795,15 @@ medusaIntegrationTestRunner({
|
||||
name: "US Reduced",
|
||||
rate: 3,
|
||||
code: "USREDUCE_PROD_TYPE",
|
||||
}])
|
||||
},
|
||||
])
|
||||
|
||||
await taxModule.createTaxRateRules([
|
||||
{
|
||||
reference: "product_type",
|
||||
reference_id: productType.id,
|
||||
tax_rate_id: taxRate.id,
|
||||
}
|
||||
},
|
||||
])
|
||||
|
||||
const salesChannel = await scModuleService.createSalesChannels({
|
||||
@@ -426,7 +814,6 @@ medusaIntegrationTestRunner({
|
||||
name: "Warehouse",
|
||||
})
|
||||
|
||||
|
||||
const [product] = await productModule.createProducts([
|
||||
{
|
||||
title: "Test product",
|
||||
@@ -473,6 +860,35 @@ medusaIntegrationTestRunner({
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a promotion to test with
|
||||
*/
|
||||
const promotion = (
|
||||
await api.post(
|
||||
`/admin/promotions`,
|
||||
{
|
||||
code: "testytest",
|
||||
type: PromotionType.STANDARD,
|
||||
status: PromotionStatus.ACTIVE,
|
||||
application_method: {
|
||||
target_type: "items",
|
||||
type: "fixed",
|
||||
allocation: "each",
|
||||
currency_code: "usd",
|
||||
value: 100,
|
||||
max_quantity: 100,
|
||||
target_rules: [
|
||||
{
|
||||
attribute: "variant_id",
|
||||
operator: "in",
|
||||
values: [product.variants[0].id],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.promotion
|
||||
|
||||
await remoteLink.create([
|
||||
{
|
||||
@@ -546,7 +962,9 @@ medusaIntegrationTestRunner({
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.data.draft_order.items[0].tax_lines[0].code).toEqual("USREDUCE_PROD_TYPE")
|
||||
expect(response.data.draft_order.items[0].tax_lines[0].code).toEqual(
|
||||
"USREDUCE_PROD_TYPE"
|
||||
)
|
||||
expect(response.data.draft_order.items[0].tax_lines[0].rate).toEqual(3)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { createOrderChangeWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
createOrderChangeWorkflow,
|
||||
createOrderWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
||||
import { IOrderModuleService, OrderDTO } from "@medusajs/types"
|
||||
import { Modules } from "@medusajs/utils"
|
||||
import {
|
||||
CreateOrderLineItemDTO,
|
||||
IOrderModuleService,
|
||||
OrderDTO,
|
||||
} from "@medusajs/types"
|
||||
import { Modules, ProductStatus } from "@medusajs/utils"
|
||||
import {
|
||||
adminHeaders,
|
||||
createAdminUser,
|
||||
@@ -26,6 +33,172 @@ medusaIntegrationTestRunner({
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
})
|
||||
|
||||
describe("CreateOrderWorkflow", () => {
|
||||
it("should create an order with items quantity and no unit price and calculate prices based on the correct pricing context including quantity", async () => {
|
||||
const salesChannel = await api.post(
|
||||
"/admin/sales-channels",
|
||||
{
|
||||
name: "Test Sales Channel",
|
||||
description: "Test Sales Channel Description",
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
const productData = {
|
||||
title: "Medusa T-Shirt based quantity",
|
||||
handle: "t-shirt-with-quantity-prices",
|
||||
status: ProductStatus.PUBLISHED,
|
||||
sales_channels: [
|
||||
{
|
||||
id: salesChannel.data.sales_channel.id,
|
||||
},
|
||||
],
|
||||
options: [
|
||||
{
|
||||
title: "Size",
|
||||
values: ["S"],
|
||||
},
|
||||
],
|
||||
variants: [
|
||||
{
|
||||
title: "S",
|
||||
sku: "SHIRT-S-BLACK-w-quantity-prices",
|
||||
options: {
|
||||
Size: "S",
|
||||
},
|
||||
manage_inventory: false,
|
||||
prices: [
|
||||
{
|
||||
amount: 1500,
|
||||
currency_code: "usd",
|
||||
min_quantity: 1,
|
||||
max_quantity: 4,
|
||||
},
|
||||
{
|
||||
amount: 1000,
|
||||
currency_code: "usd",
|
||||
min_quantity: 5,
|
||||
max_quantity: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const newProduct = await api.post(
|
||||
`/admin/products`,
|
||||
productData,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
const variantId = newProduct.data.product.variants[0].id
|
||||
const salesChannelId = salesChannel.data.sales_channel.id
|
||||
const customer = (
|
||||
await api.post(
|
||||
"/admin/customers",
|
||||
{
|
||||
email: "test1@email.com",
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.customer
|
||||
const region = (
|
||||
await api.post(
|
||||
"/admin/regions",
|
||||
{ name: "US", currency_code: "usd", countries: ["us"] },
|
||||
adminHeaders
|
||||
)
|
||||
).data.region
|
||||
|
||||
const { result: created } = await createOrderWorkflow(appContainer).run(
|
||||
{
|
||||
input: {
|
||||
email: customer.email,
|
||||
metadata: {
|
||||
foo: "bar",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
title: "Medusa T-Shirt based quantity",
|
||||
variant_id: variantId,
|
||||
quantity: 6,
|
||||
} as CreateOrderLineItemDTO,
|
||||
],
|
||||
sales_channel_id: salesChannelId,
|
||||
region_id: region.id,
|
||||
shipping_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Test",
|
||||
address_1: "Test",
|
||||
city: "Test",
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
phone: "12345",
|
||||
},
|
||||
billing_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Test",
|
||||
address_1: "Test",
|
||||
city: "Test",
|
||||
country_code: "US",
|
||||
postal_code: "12345",
|
||||
},
|
||||
shipping_methods: [
|
||||
{
|
||||
name: "Test shipping method",
|
||||
amount: 10,
|
||||
data: {},
|
||||
tax_lines: [
|
||||
{
|
||||
description: "shipping Tax 1",
|
||||
tax_rate_id: "tax_usa_shipping",
|
||||
code: "code",
|
||||
rate: 10,
|
||||
},
|
||||
],
|
||||
adjustments: [
|
||||
{
|
||||
code: "VIP_10",
|
||||
amount: 1,
|
||||
description: "VIP discount",
|
||||
promotion_id: "prom_123",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
currency_code: "usd",
|
||||
customer_id: customer.id,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const order = (
|
||||
await api.get(
|
||||
"/admin/orders/" +
|
||||
created.id +
|
||||
"?fields=+raw_total,+raw_subtotal,+raw_discount_total",
|
||||
adminHeaders
|
||||
)
|
||||
).data.order
|
||||
|
||||
expect(order).toEqual(
|
||||
expect.objectContaining({
|
||||
original_item_subtotal: 6000,
|
||||
original_item_tax_total: 0,
|
||||
original_item_total: 6000,
|
||||
original_shipping_subtotal: 10,
|
||||
original_shipping_tax_total: 1,
|
||||
original_shipping_total: 11,
|
||||
original_tax_total: 1,
|
||||
original_total: 6011,
|
||||
item_subtotal: 6000,
|
||||
item_tax_total: 0,
|
||||
item_total: 6000,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Orders - Admin", () => {
|
||||
it("should get an order", async () => {
|
||||
const created = await orderModule.createOrders({
|
||||
@@ -107,7 +280,7 @@ medusaIntegrationTestRunner({
|
||||
id: expect.any(String),
|
||||
status: "pending",
|
||||
version: 1,
|
||||
display_id: 1,
|
||||
display_id: 2,
|
||||
payment_collections: [],
|
||||
payment_status: "not_paid",
|
||||
region_id: "test_region_id",
|
||||
|
||||
Reference in New Issue
Block a user