fix: Compute "virtual" adjustments for order previews (#13306)

* wip

* add wip

* wip

* reuse action

* finish first draft

* fix tests

* cleanup

* Only compute adjustments when necessary

* Create hot-carrots-look.md

* address comments

* minor tweaks

* fix pay col

* fix test

* wip

* Dwip

* wip

* fix: adjustment typo

* fix: import

* fix: workflow imports

* wip: update test

* feat: upsert versioned  adjustments when previewing order

* fix: revert unique codes change

* fix: order spec test with versioning

* wip: save

* feat: make adjustments work for preview and confirm flow, wip base repo filtering of older version adjustments

* fix: missing populate where

* wip: populate where loading versioned adjustments

* fix: filter out older adjustment versions

* temp: comment adjustments in repo

* test: add adjustment if no version

* wip: configure populate where in order base repository

* fix: rm manual filtering

* fix: revert base repo changes

* fix: revert

* fix: use order item version instead of order version

* fix: rm only in test

* fix: update case spec

* fix: remove sceanrio, wip test with draft promotion

* feat: test correct adjustments when disabling promotion

* feat: complex test case

* feat: test consecutive order edits

* feat: 2 promotions test case with a fixed promo

* feat: migrate existing order line item adjustments to order items latest version

* feat: update dep after merge

* wip: load adjustments separatley

* feat: adjustments collections

* fix: spread result, handle related entity case

* fix: update lock

* feat: make sure version is loaded, refactor, handle related entity case

* fix: check fields

* feat: loading adjustments for list and count

* fix: correct items version field

* fix: rm empty array

* fix: wip order modules spec

* fix: order module specs

* feat: preinit items adjustments

* fix: rm only

* fix: rm only

* chore: cleanup

* fix: migration files

* fix: dont change formatting

* fix: core package build

* chore: more cleanup

* fix: item update util

* fix: duplicate import

* fix: refresh adjustments for exchanges (#13992)

* wip: exchange adjustments

* feat: test - receive items

* feat: finish test case

* fix: casing

* fix(draft-orders, core-flows, orders) refresh adjustments for draft orders (#14025)

* wip: draft orders adjustments refresh

* feat: rewrite to use REPLACE action + test

* fix: rm only

* feat: cleanup old REPLACE actions

* feat: cleanup adjustemnts when 0 promotions

* wip: canceling draft order

* fix: make version arg optional

* fix: restore promotion links

* feat: test reverting on cancelation

* fix: address comments in tests

* wip: fix summary on preview

* fix: get pending diff on preview summary from total

* fix: revert pending diff change

---------

Co-authored-by: fPolic <mainacc.polic@gmail.com>
Co-authored-by: Frane Polić <16856471+fPolic@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2025-11-25 10:41:14 +01:00
1 parent 0ddd9e36b5
commit 78842af1c3
60 files changed
+3271 -233

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
---
"@medusajs/order": patch
"@medusajs/promotion": patch
"@medusajs/core-flows": patch
"@medusajs/types": patch
"@medusajs/utils": patch
"integration-tests-http": patch
---
fix: Compute "virtual" adjustments for order previews
@@ -1,8 +1,11 @@
import { medusaIntegrationTestRunner } from "@medusajs/test-utils" import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
import { IOrderModuleService, IPromotionModuleService } from "@medusajs/types"
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
Modules, Modules,
ProductStatus, ProductStatus,
PromotionStatus,
PromotionType,
RuleOperator, RuleOperator,
} from "@medusajs/utils" } from "@medusajs/utils"
import { import {
@@ -913,6 +916,305 @@ medusaIntegrationTestRunner({
expect(updatedClaimShippingMethods).toHaveLength(0) expect(updatedClaimShippingMethods).toHaveLength(0)
}) })
}) })
describe("Exchange adjustments", () => {
let appliedPromotion
let promotionModule: IPromotionModuleService
let orderModule: IOrderModuleService
let remoteLink
let orderWithPromotion
let productForAdjustmentTest
beforeEach(async () => {
const container = getContainer()
promotionModule = container.resolve(Modules.PROMOTION)
orderModule = container.resolve(Modules.ORDER)
remoteLink = container.resolve(ContainerRegistrationKeys.LINK)
productForAdjustmentTest = (
await api.post(
"/admin/products",
{
title: "Product for adjustment test",
status: ProductStatus.PUBLISHED,
shipping_profile_id: shippingProfile.id,
options: [{ title: "size", values: ["large", "small"] }],
variants: [
{
title: "Test variant",
sku: "test-variant-adjustment",
manage_inventory: false,
options: { size: "large" },
prices: [
{
currency_code: "usd",
amount: 12,
},
],
},
],
},
adminHeaders
)
).data.product
appliedPromotion = await promotionModule.createPromotions({
code: "PROMOTION_APPLIED",
type: PromotionType.STANDARD,
status: PromotionStatus.ACTIVE,
application_method: {
type: "percentage",
target_type: "order",
allocation: "each",
value: 10,
max_quantity: 5,
currency_code: "usd",
target_rules: [],
},
})
await remoteLink.create([
{
[Modules.SALES_CHANNEL]: {
sales_channel_id: (
await api.get("/admin/sales-channels", adminHeaders)
).data.sales_channels[0].id,
},
[Modules.STOCK_LOCATION]: {
stock_location_id: location.id,
},
},
])
// @ts-ignore
orderWithPromotion = await orderModule.createOrders({
email: "foo@bar.com",
region_id: (
await api.get("/admin/regions", adminHeaders)
).data.regions[0].id,
sales_channel_id: (
await api.get("/admin/sales-channels", adminHeaders)
).data.sales_channels[0].id,
items: [
{
// @ts-ignore
id: "item-1",
title: "Custom Item",
quantity: 1,
unit_price: 10,
},
],
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",
},
currency_code: "usd",
})
await orderModule.createOrderLineItemTaxLines(orderWithPromotion.id, [
{
// @ts-ignore
item_id: "item-1",
code: "standard",
rate: 10,
description: "tax-1",
provider_id: "system",
total: 1.2,
subtotal: 1.2,
},
])
await orderModule.createOrderLineItemAdjustments([
{
version: 1,
code: appliedPromotion.code!,
amount: 1,
item_id: "item-1",
promotion_id: appliedPromotion.id,
},
])
await remoteLink.create({
[Modules.ORDER]: { order_id: orderWithPromotion.id },
[Modules.PROMOTION]: { promotion_id: appliedPromotion.id },
})
})
it("should update adjustments when adding an inbound and outbound item", async () => {
// First item -> 10$ | 10% discount tax excl. | 10% tax
// Second item -> 12$ | 10% discount tax excl. | 2% tax
// fulfill item so it can be returned
await api.post(
`/admin/orders/${orderWithPromotion.id}/fulfillments`,
{
items: [
{
id: orderWithPromotion.items[0].id,
quantity: 1,
},
],
},
adminHeaders
)
let result = await api.post(
"/admin/exchanges",
{
order_id: orderWithPromotion.id,
description: "Test",
},
adminHeaders
)
const exchangeId = result.data.exchange.id
const orderId = result.data.exchange.order_id
result = (await api.get(`/admin/orders/${orderId}`, adminHeaders))
.data.order
expect(result.original_total).toEqual(11) // $10 + 10% tax
expect(result.total).toEqual(10 * 0.9 * 1.1) // ($10 - 10% discount) + 10% tax
// Add outbound item with price $12, 10% discount and 10% tax
result = (
await api
.post(
`/admin/exchanges/${exchangeId}/outbound/items`,
{
items: [
{
variant_id: productForAdjustmentTest.variants[0].id,
quantity: 1,
},
],
},
adminHeaders
)
.catch((e) => console.log(e))
).data.order_preview
expect(result.total).toEqual(20.916) // 10 * 0.9 * 1.1 + 12 * 0.9 * 1.02
expect(result.original_total).toEqual(23.24) // 10 * 1.1 + 12 * 1.02
// Confirm that the adjustment values are correct
const adjustments = result.items[0].adjustments
const adjustments2 = result.items[1].adjustments
expect(adjustments).toEqual([
expect.objectContaining({
amount: 1,
}),
])
expect(adjustments2).toEqual([
expect.objectContaining({
amount: 1.2,
}),
])
let orderResult = (
await api.get(`/admin/orders/${orderId}`, adminHeaders)
).data.order
// confirm original order is not updated
expect(orderResult.total).toEqual(9.9) // initial item 10$ and 10% discount and 10% tax
expect(orderResult.original_total).toEqual(11) // initial item 10$ + 10% tax
const originalItemId = result.items[0].id
// Request inbound item return
result = (
await api
.post(
`/admin/exchanges/${exchangeId}/inbound/items`,
{
items: [
{
id: originalItemId,
reason_id: returnReason.id,
quantity: 1,
},
],
},
adminHeaders
)
.catch((e) => console.log(e))
).data.order_preview
const returnId = result.order_change.return_id
await api.post(
`/admin/exchanges/${exchangeId}/request`,
{},
adminHeaders
)
orderResult = (
await api.get(`/admin/orders/${orderId}`, adminHeaders)
).data.order
// after exchange request order contains both items and adjustments untill return is received
expect(orderResult.total).toEqual(20.916) // 10 * 0.9 * 1.1 + 12 * 0.9 * 1.02
expect(orderResult.original_total).toEqual(23.24) // 10 * 1.1 + 12 * 1.02
await api.post(`/admin/returns/${returnId}/receive`, {}, adminHeaders)
orderResult = (
await api.get(`/admin/orders/${orderId}`, adminHeaders)
).data.order
// still the same state while return receive process is pending
expect(orderResult.total).toEqual(20.916) // 10 * 0.9 * 1.1 + 12 * 0.9 * 1.02
expect(orderResult.original_total).toEqual(23.24) // 10 * 1.1 + 12 * 1.02
await api.post(
`/admin/returns/${returnId}/receive-items`,
{
items: [
{
id: originalItemId,
quantity: 1,
},
],
},
adminHeaders
)
orderResult = (
await api.get(`/admin/orders/${orderId}`, adminHeaders)
).data.order
// still the same state while return receive process is pending
expect(orderResult.total).toEqual(20.916) // 10 * 0.9 * 1.1 + 12 * 0.9 * 1.02
expect(orderResult.original_total).toEqual(23.24) // 10 * 1.1 + 12 * 1.02
await api.post(
`/admin/returns/${returnId}/receive/confirm`,
{},
adminHeaders
)
const orderResult2 = (
await api.get(`/admin/orders/${orderId}`, adminHeaders)
).data.order
// after confirmation only first added item is active
expect(orderResult2.total).toEqual(11.016)
expect(orderResult2.original_total).toEqual(12.24)
})
})
}) })
}, },
}) })
File diff suppressed because it is too large. Load diff
@@ -20,6 +20,7 @@ import {
createAdminUser, createAdminUser,
} from "../../../helpers/create-admin-user" } from "../../../helpers/create-admin-user"
import { setupTaxStructure } from "../fixtures" import { setupTaxStructure } from "../fixtures"
import { removeDraftOrderPromotionsWorkflow } from "../../../../packages/core/core-flows/dist/draft-order/workflows/remove-draft-order-promotions"
jest.setTimeout(100000) jest.setTimeout(100000)
@@ -770,6 +771,702 @@ medusaIntegrationTestRunner({
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
}) })
it("should apply promotion to a draft order via order edit", 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",
status: ProductStatus.PUBLISHED,
variants: [
{
title: "Test variant",
},
],
},
{
title: "Another product",
status: ProductStatus.PUBLISHED,
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,
is_tax_inclusive: true,
application_method: {
target_type: "items",
type: "percentage",
allocation: "each",
currency_code: "usd",
value: 10,
max_quantity: 10,
},
},
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",
},
items: [
{
variant_id: product.variants[0].id,
is_discountable: true,
quantity: 2, // 2 * 3000$ = 6000$ TAX INCLUSIVE
},
{
variant_id: product_2.variants[0].id,
is_discountable: true,
quantity: 1, // 1 * 1000$ = 1000$ TAX INCLUSIVE
},
],
shipping_methods: [
{
name: "test-method",
shipping_option_id: "test-option",
amount: 0,
},
],
}
const response = await api.post(
"/admin/draft-orders",
payload,
adminHeaders
)
// begin Order Edit on a Draft Order
let orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit`,
{},
adminHeaders
)
).data.draft_order_preview
orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit/promotions`,
{
promo_codes: [promotion.code],
},
adminHeaders
)
).data.draft_order_preview
expect(orderPreview.total).toEqual(6300) // 2 * 3000$ - 10% + 1 * 1000$ - 10%
expect(orderPreview.original_total).toEqual(7000)
expect(orderPreview.discount_total).toEqual(700)
expect(orderPreview.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
total: 5400, // 2 * 3000$ - 10% = 5400$
original_total: 6000,
discount_total: 600,
variant_id: product.variants[0].id,
adjustments: expect.arrayContaining([
expect.objectContaining({
code: "testytest",
amount: 600,
promotion_id: promotion.id,
is_tax_inclusive: true,
}),
]),
}),
expect.objectContaining({
total: 900, // 1000$ - 10% = 900$
original_total: 1000,
discount_total: 100,
variant_id: product_2.variants[0].id,
adjustments: expect.arrayContaining([
expect.objectContaining({
code: "testytest",
amount: 100,
promotion_id: promotion.id,
is_tax_inclusive: true,
}),
]),
}),
])
)
orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit/confirm`,
{},
adminHeaders
)
).data.draft_order_preview
const draftOrder = (
await api.get(
`/admin/draft-orders/${response.data.draft_order.id}?fields=+total,+original_total,+discount_total,+version,items.*`,
adminHeaders
)
).data.draft_order
expect(draftOrder.total).toEqual(6300) // 2 * 3000$ - 10% + 1 * 1000$ - 10%
expect(draftOrder.original_total).toEqual(7000)
expect(draftOrder.discount_total).toEqual(700)
expect(draftOrder.version).toEqual(2)
expect(draftOrder.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
total: 5400,
original_total: 6000,
discount_total: 600,
variant_id: product.variants[0].id,
adjustments: [
expect.objectContaining({
code: "testytest",
amount: 600,
promotion_id: promotion.id,
is_tax_inclusive: true,
version: 2,
}),
],
}),
expect.objectContaining({
total: 900,
original_total: 1000,
discount_total: 100,
variant_id: product_2.variants[0].id,
adjustments: [
expect.objectContaining({
code: "testytest",
amount: 100,
promotion_id: promotion.id,
is_tax_inclusive: true,
version: 2,
}),
],
}),
])
)
})
it("should restore promotions and adjustments on a draft order after edit is canceled", 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",
status: ProductStatus.PUBLISHED,
variants: [
{
title: "Test variant",
},
],
},
{
title: "Another product",
status: ProductStatus.PUBLISHED,
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,
is_tax_inclusive: true,
application_method: {
target_type: "items",
type: "percentage",
allocation: "each",
currency_code: "usd",
value: 10,
max_quantity: 10,
},
},
adminHeaders
)
).data.promotion
// additional promotion that will be added then removed
const promotionAdditional20 = (
await api.post(
`/admin/promotions`,
{
code: "additional_20",
type: PromotionType.STANDARD,
status: PromotionStatus.ACTIVE,
is_tax_inclusive: true,
application_method: {
target_type: "items",
type: "percentage",
allocation: "each",
currency_code: "usd",
value: 20,
max_quantity: 10,
},
},
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",
},
items: [
{
variant_id: product.variants[0].id,
is_discountable: true,
quantity: 2, // 2 * 3000$ = 6000$ TAX INCLUSIVE
},
{
variant_id: product_2.variants[0].id,
is_discountable: true,
quantity: 1, // 1 * 1000$ = 1000$ TAX INCLUSIVE
},
],
shipping_methods: [
{
name: "test-method",
shipping_option_id: "test-option",
amount: 0,
},
],
}
const response = await api.post(
"/admin/draft-orders",
payload,
adminHeaders
)
// begin Order Edit on a Draft Order
let orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit`,
{},
adminHeaders
)
).data.draft_order_preview
// add the promotion
orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit/promotions`,
{
promo_codes: [promotion.code],
},
adminHeaders
)
).data.draft_order_preview
// confirm changes which applies adjustemnts to the draft order
orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit/confirm`,
{},
adminHeaders
)
).data.draft_order_preview
const draftOrder = (
await api.get(
`/admin/draft-orders/${response.data.draft_order.id}?fields=+total,+original_total,+discount_total,+version,items.*`,
adminHeaders
)
).data.draft_order
expect(draftOrder.total).toEqual(6300) // 2 * 3000$ - 10% + 1 * 1000$ - 10%
expect(draftOrder.original_total).toEqual(7000)
expect(draftOrder.discount_total).toEqual(700)
expect(draftOrder.version).toEqual(2)
expect(draftOrder.items[0].adjustments[0].version).toEqual(2)
expect(draftOrder.items[1].adjustments[0].version).toEqual(2)
expect(orderPreview.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
total: 5400,
original_total: 6000,
discount_total: 600,
variant_id: product.variants[0].id,
adjustments: [
expect.objectContaining({
code: "testytest",
amount: 600,
promotion_id: promotion.id,
is_tax_inclusive: true,
}),
],
}),
expect.objectContaining({
total: 900,
original_total: 1000,
discount_total: 100,
variant_id: product_2.variants[0].id,
adjustments: [
expect.objectContaining({
code: "testytest",
amount: 100,
promotion_id: promotion.id,
is_tax_inclusive: true,
}),
],
}),
])
)
// begin another edit...
orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit`,
{},
adminHeaders
)
).data.draft_order_preview
// ...and add the additional promotion
orderPreview = (
await api.post(
`/admin/draft-orders/${response.data.draft_order.id}/edit/promotions`,
{
promo_codes: [promotionAdditional20.code],
},
adminHeaders
)
).data.draft_order_preview
expect(orderPreview.total).toEqual(5040) // (2 * 3000$ - 10%) - 20% + (1 * 1000$ - 10%) - 20%
expect(orderPreview.original_total).toEqual(7000)
expect(orderPreview.discount_total).toEqual(600 + 100 + 1080 + 180)
expect(orderPreview.version).toEqual(2)
expect(orderPreview.items[0].adjustments.length).toEqual(2)
expect(orderPreview.items[1].adjustments.length).toEqual(2)
// new adjustments exists on the preview
expect(orderPreview.items).toEqual(
expect.arrayContaining([
expect.objectContaining({
total: 4320,
original_total: 6000,
discount_total: 1680,
variant_id: product.variants[0].id,
adjustments: expect.arrayContaining([
expect.objectContaining({
code: "testytest",
amount: 480,
promotion_id: promotion.id,
is_tax_inclusive: true,
}),
expect.objectContaining({
code: "additional_20",
amount: 1200,
promotion_id: promotionAdditional20.id,
is_tax_inclusive: true,
}),
]),
}),
expect.objectContaining({
total: 720,
original_total: 1000,
discount_total: 280,
variant_id: product_2.variants[0].id,
adjustments: expect.arrayContaining([
expect.objectContaining({
code: "testytest",
amount: 80,
promotion_id: promotion.id,
is_tax_inclusive: true,
}),
expect.objectContaining({
code: "additional_20",
amount: 200,
promotion_id: promotionAdditional20.id,
is_tax_inclusive: true,
}),
]),
}),
])
)
await api.delete(
`/admin/draft-orders/${response.data.draft_order.id}/edit`,
adminHeaders
)
const draftOrderAfterCancel = (
await api.get(
`/admin/draft-orders/${response.data.draft_order.id}?fields=+total,+original_total,+discount_total`,
adminHeaders
)
).data.draft_order
// reverted to be same as before second edit started (10% discount only applied)
expect(draftOrderAfterCancel.total).toEqual(6300)
expect(draftOrderAfterCancel.original_total).toEqual(7000)
expect(draftOrderAfterCancel.discount_total).toEqual(700)
expect(draftOrderAfterCancel.version).toEqual(2)
})
it("should create a draft order and apply tax by product type", async () => { it("should create a draft order and apply tax by product type", async () => {
const productType = await productModule.createProductTypes({ const productType = await productModule.createProductTypes({
value: "test_product_type", value: "test_product_type",
@@ -372,6 +372,7 @@ medusaIntegrationTestRunner({
value: "5e-18", value: "5e-18",
precision: 20, precision: 20,
}, },
version: 1,
provider_id: expect.any(String), provider_id: expect.any(String),
created_at: expect.any(String), created_at: expect.any(String),
updated_at: expect.any(String), updated_at: expect.any(String),
@@ -1,56 +1,63 @@
import type { import {
CartDTO, ComputeActionContext,
IPromotionModuleService, ComputeActionOptions,
IPromotionModuleService
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils" import { Modules } from "@medusajs/framework/utils"
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk" import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
/** /**
* The details of the cart and its applied promotions. * The details of the items and shipping methods and its applied promotions.
*/ */
export interface GetActionsToComputeFromPromotionsStepInput { export interface GetActionsToComputeFromPromotionsStepInput {
/** /**
* The cart to compute the actions for. * The items and shipping methods to compute the actions for.
*/ */
cart: CartDTO computeActionContext: ComputeActionContext
/** /**
* The promotion codes applied on the cart. * The promotion codes applied on the items and shipping methods.
*/ */
promotionCodesToApply: string[] promotionCodesToApply: string[]
/**
* The options to configure how the actions are computed.
*/
options?: ComputeActionOptions
} }
export const getActionsToComputeFromPromotionsStepId = export const getActionsToComputeFromPromotionsStepId =
"get-actions-to-compute-from-promotions" "get-actions-to-compute-from-promotions"
/** /**
* This step retrieves the actions to compute based on the promotions * This step retrieves the actions to compute based on the promotions
* applied on a cart. * applied on items and shipping methods.
* *
* :::tip * :::tip
* *
* You can use the {@link retrieveCartStep} to retrieve a cart's details. * You can use the {@link retrieveCartStep} to retrieve items and shipping methods' details.
* *
* ::: * :::
* *
* @example * @example
* const data = getActionsToComputeFromPromotionsStep({ * const data = getActionsToComputeFromPromotionsStep({
* // retrieve the details of the cart from another workflow * // retrieve the details of the items and shipping methods from another workflow
* // or in another step using the Cart Module's service * // or in another step using the Cart Module's service
* cart, * computeActionContext,
* promotionCodesToApply: ["10OFF"] * promotionCodesToApply: ["10OFF"]
* }) * })
*/ */
export const getActionsToComputeFromPromotionsStep = createStep( export const getActionsToComputeFromPromotionsStep = createStep(
getActionsToComputeFromPromotionsStepId, getActionsToComputeFromPromotionsStepId,
async (data: GetActionsToComputeFromPromotionsStepInput, { container }) => { async (data: GetActionsToComputeFromPromotionsStepInput, { container }) => {
const { cart, promotionCodesToApply = [] } = data const { computeActionContext, promotionCodesToApply = [], options } = data
const promotionService = container.resolve<IPromotionModuleService>( const promotionService = container.resolve<IPromotionModuleService>(
Modules.PROMOTION Modules.PROMOTION
) )
const actionsToCompute = await promotionService.computeActions( const actionsToCompute = await promotionService.computeActions(
promotionCodesToApply, promotionCodesToApply,
cart as any computeActionContext,
options
) )
return new StepResponse(actionsToCompute) return new StepResponse(actionsToCompute)
@@ -125,7 +125,7 @@ export const updateCartPromotionsWorkflow = createWorkflow(
}) })
const actions = getActionsToComputeFromPromotionsStep({ const actions = getActionsToComputeFromPromotionsStep({
cart, computeActionContext: cart,
promotionCodesToApply, promotionCodesToApply,
}) })
@@ -20,6 +20,10 @@ export interface CreateDraftOrderLineItemAdjustmentsStepInput {
* The line item adjustments to create. * The line item adjustments to create.
*/ */
lineItemAdjustmentsToCreate: CreateLineItemAdjustmentDTO[] lineItemAdjustmentsToCreate: CreateLineItemAdjustmentDTO[]
/**
* The version of the order change to create the line item adjustments for.
*/
version?: number
} }
/** /**
@@ -43,7 +47,7 @@ export const createDraftOrderLineItemAdjustmentsStep = createStep(
data: CreateDraftOrderLineItemAdjustmentsStepInput, data: CreateDraftOrderLineItemAdjustmentsStepInput,
{ container } { container }
) { ) {
const { lineItemAdjustmentsToCreate = [], order_id } = data const { lineItemAdjustmentsToCreate = [], order_id, version } = data
if (!lineItemAdjustmentsToCreate?.length) { if (!lineItemAdjustmentsToCreate?.length) {
return new StepResponse(void 0, []) return new StepResponse(void 0, [])
@@ -65,6 +69,7 @@ export const createDraftOrderLineItemAdjustmentsStep = createStep(
const lineItemAdjustments = await service.createOrderLineItemAdjustments( const lineItemAdjustments = await service.createOrderLineItemAdjustments(
filteredAdjustments.map((adjustment) => ({ filteredAdjustments.map((adjustment) => ({
...adjustment, ...adjustment,
version,
order_id, order_id,
})) }))
) )
@@ -1,8 +1,4 @@
import { import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
ChangeActionType,
OrderChangeStatus,
PromotionActions,
} from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
transform, transform,
@@ -24,8 +20,8 @@ import {
} from "../../order" } from "../../order"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const addDraftOrderItemsWorkflowId = "add-draft-order-items" export const addDraftOrderItemsWorkflowId = "add-draft-order-items"
@@ -74,7 +70,7 @@ export const addDraftOrderItemsWorkflow = createWorkflow(
const orderChange: OrderChangeDTO = useRemoteQueryStep({ const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change", entry_point: "order_change",
fields: ["id", "status"], fields: ["id", "status", "version"],
variables: { variables: {
filters: { filters: {
order_id: input.order_id, order_id: input.order_id,
@@ -114,11 +110,9 @@ export const addDraftOrderItemsWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -21,8 +21,9 @@ import {
} from "../../order" } from "../../order"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { validatePromoCodesToAddStep } from "../steps/validate-promo-codes-to-add" import { validatePromoCodesToAddStep } from "../steps/validate-promo-codes-to-add"
import { updateDraftOrderPromotionsStep } from "../steps/update-draft-order-promotions"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
export const addDraftOrderPromotionWorkflowId = "add-draft-order-promotion" export const addDraftOrderPromotionWorkflowId = "add-draft-order-promotion"
@@ -82,7 +83,7 @@ export const addDraftOrderPromotionWorkflow = createWorkflow(
const orderChange: OrderChangeDTO = useRemoteQueryStep({ const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change", entry_point: "order_change",
fields: ["id", "status"], fields: ["id", "status", "version"],
variables: { variables: {
filters: { filters: {
order_id: input.order_id, order_id: input.order_id,
@@ -110,11 +111,15 @@ export const addDraftOrderPromotionWorkflow = createWorkflow(
promotions, promotions,
}) })
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ updateDraftOrderPromotionsStep({
id: input.order_id,
promo_codes: input.promo_codes,
action: PromotionActions.ADD,
})
computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order, order_id: input.order_id,
promo_codes: input.promo_codes,
action: PromotionActions.ADD,
}, },
}) })
@@ -3,7 +3,6 @@ import {
isDefined, isDefined,
MedusaError, MedusaError,
OrderChangeStatus, OrderChangeStatus,
PromotionActions,
ShippingOptionPriceType, ShippingOptionPriceType,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import { import {
@@ -30,8 +29,8 @@ import { createOrderShippingMethods } from "../../order/steps/create-order-shipp
import { prepareShippingMethod } from "../../order/utils/prepare-shipping-method" import { prepareShippingMethod } from "../../order/utils/prepare-shipping-method"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
const validateShippingOptionStep = createStep( const validateShippingOptionStep = createStep(
"validate-shipping-option", "validate-shipping-option",
@@ -187,19 +186,9 @@ export const addDraftOrderShippingMethodsWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
const refetchedOrder = useRemoteQueryStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
entry_point: "orders",
fields: draftOrderFieldsForRefreshSteps,
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
}).config({ name: "refetched-order-query" })
refreshDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order: refetchedOrder, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -16,8 +16,8 @@ import { deleteOrderChangesStep, deleteOrderShippingMethods } from "../../order"
import { restoreDraftOrderShippingMethodsStep } from "../steps/restore-draft-order-shipping-methods" import { restoreDraftOrderShippingMethodsStep } from "../steps/restore-draft-order-shipping-methods"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { updateDraftOrderPromotionsStep } from "../steps/update-draft-order-promotions"
export const cancelDraftOrderEditWorkflowId = "cancel-draft-order-edit" export const cancelDraftOrderEditWorkflowId = "cancel-draft-order-edit"
@@ -85,34 +85,6 @@ export const cancelDraftOrderEditWorkflow = createWorkflow(
validateDraftOrderChangeStep({ order, orderChange }) validateDraftOrderChangeStep({ order, orderChange })
const shippingToRemove = transform(
{ orderChange, input },
({ orderChange }) => {
return (orderChange.actions ?? [])
.filter((a) => a.action === ChangeActionType.SHIPPING_ADD)
.map(({ reference_id }) => reference_id)
}
)
const shippingToRestore = transform(
{ orderChange, input },
({ orderChange }) => {
return (orderChange.actions ?? [])
.filter((a) => a.action === ChangeActionType.SHIPPING_UPDATE)
.map(({ reference_id, details }) => ({
id: reference_id,
before: {
shipping_option_id: details?.old_shipping_option_id,
amount: details?.old_amount,
},
after: {
shipping_option_id: details?.new_shipping_option_id,
amount: details?.new_amount,
},
}))
}
)
const promotionsToRemove = transform( const promotionsToRemove = transform(
{ orderChange, input }, { orderChange, input },
({ orderChange }) => { ({ orderChange }) => {
@@ -155,19 +127,45 @@ export const cancelDraftOrderEditWorkflow = createWorkflow(
} }
) )
updateDraftOrderPromotionsStep({
id: input.order_id,
promo_codes: promotionsToRefresh as string[],
action: PromotionActions.REPLACE,
})
const shippingToRemove = transform(
{ orderChange, input },
({ orderChange }) => {
return (orderChange.actions ?? [])
.filter((a) => a.action === ChangeActionType.SHIPPING_ADD)
.map(({ reference_id }) => reference_id)
}
)
const shippingToRestore = transform(
{ orderChange, input },
({ orderChange }) => {
return (orderChange.actions ?? [])
.filter((a) => a.action === ChangeActionType.SHIPPING_UPDATE)
.map(({ reference_id, details }) => ({
id: reference_id,
before: {
shipping_option_id: details?.old_shipping_option_id,
amount: details?.old_amount,
},
after: {
shipping_option_id: details?.new_shipping_option_id,
amount: details?.new_amount,
},
}))
}
)
parallelize( parallelize(
deleteOrderChangesStep({ ids: [orderChange.id] }), deleteOrderChangesStep({ ids: [orderChange.id] }),
deleteOrderShippingMethods({ ids: shippingToRemove }) deleteOrderShippingMethods({ ids: shippingToRemove })
) )
refreshDraftOrderAdjustmentsWorkflow.runAsStep({
input: {
order,
promo_codes: promotionsToRefresh,
action: PromotionActions.REPLACE,
},
})
when(shippingToRestore, (methods) => !!methods?.length).then(() => { when(shippingToRestore, (methods) => !!methods?.length).then(() => {
restoreDraftOrderShippingMethodsStep({ restoreDraftOrderShippingMethodsStep({
shippingMethods: shippingToRestore as any, shippingMethods: shippingToRestore as any,
@@ -0,0 +1,213 @@
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
import {
createWorkflow,
transform,
when,
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import type {
ComputeActionContext,
OrderChangeDTO,
OrderDTO,
PromotionDTO,
} from "@medusajs/framework/types"
import {
getActionsToComputeFromPromotionsStep,
prepareAdjustmentsFromPromotionActionsStep,
} from "../../cart"
import { createOrderChangeActionsWorkflow } from "../../order/workflows/create-order-change-actions"
import { previewOrderChangeStep } from "../../order/steps/preview-order-change"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { useRemoteQueryStep } from "../../common"
import { acquireLockStep, releaseLockStep } from "../../locking"
import { deleteOrderChangeActionsStep } from "../../order/steps/delete-order-change-actions"
export const computeDraftOrderAdjustmentsWorkflowId =
"compute-draft-order-adjustments"
/**
* The details of the draft order to refresh the adjustments for.
*/
export interface ComputeDraftOrderAdjustmentsWorkflowInput {
/**
* The ID of the draft order to refresh the adjustments for.
*/
order_id: string
}
/**
* This workflow computes the adjustments or promotions for a draft order. It's used by other workflows
* to compute new adjustments for the promotions whenever changes are made to the draft order.
* Created adjustments are "virtual" meaning they live on the action and no line item adjustments records are created
* in the database until the edit is confirmed.
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around
* computing the adjustments for a draft order.
*
* @example
* const { result } = await computeDraftOrderAdjustmentsWorkflow(container)
* .run({
* input: {
* order_id: "order_123",
* }
* })
*
* @summary
*
* Refresh the promotions in a draft order.
*/
export const computeDraftOrderAdjustmentsWorkflow = createWorkflow(
computeDraftOrderAdjustmentsWorkflowId,
function (input: WorkflowData<ComputeDraftOrderAdjustmentsWorkflowInput>) {
acquireLockStep({
key: input.order_id,
timeout: 2,
ttl: 10,
})
const order: OrderDTO & { promotions: PromotionDTO[] } = useRemoteQueryStep(
{
entry_point: "orders",
fields: draftOrderFieldsForRefreshSteps,
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
}
).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
},
list: false,
}).config({ name: "order-change-query" })
validateDraftOrderChangeStep({ order, orderChange })
const toDeleteActions = transform(orderChange, (orderChange) => {
return orderChange.actions
.filter(
(action) =>
action.action === ChangeActionType.ITEM_ADJUSTMENTS_REPLACE
)
.map((action) => {
return action.id
})
})
when(toDeleteActions, (toDeleteActions) => toDeleteActions.length > 0).then(
() => {
// clean up old replace actions from the current order change
deleteOrderChangeActionsStep({ ids: toDeleteActions })
}
)
const previewedOrder = previewOrderChangeStep(input.order_id)
when(
{ order },
({ order }) => Array.isArray(order.promotions) && !order.promotions.length
).then(() => {
const orderChangeActionAdjustmentsInput = transform(
{ order, previewedOrder, orderChange },
({ order, previewedOrder, orderChange }) => {
return previewedOrder.items.map((item) => {
return {
order_id: order.id,
order_change_id: orderChange.id,
version: orderChange.version,
action: ChangeActionType.ITEM_ADJUSTMENTS_REPLACE,
details: {
reference_id: item.id,
adjustments: [],
},
}
})
}
)
createOrderChangeActionsWorkflow
.runAsStep({ input: orderChangeActionAdjustmentsInput })
.config({ name: "order-change-action-adjustments-input-remove" })
})
when({ order }, ({ order }) => !!order.promotions?.length).then(() => {
const orderPromotions = transform({ order }, ({ order }) => {
return order.promotions
.map((p) => p.code)
.filter((p) => p !== undefined)
})
const actionsToComputeItemsInput = transform(
{ previewedOrder, order },
({ previewedOrder, order }) => {
return {
currency_code: order.currency_code,
items: previewedOrder.items.map((item) => ({
...item,
// Buy-Get promotions rely on the product ID, so we need to manually set it before refreshing adjustments
product: { id: item.product_id },
})),
} as ComputeActionContext
}
)
const actions = getActionsToComputeFromPromotionsStep({
computeActionContext: actionsToComputeItemsInput,
promotionCodesToApply: orderPromotions,
})
const { lineItemAdjustmentsToCreate } =
prepareAdjustmentsFromPromotionActionsStep({ actions })
const orderChangeActionAdjustmentsInput = transform(
{
order,
previewedOrder,
orderChange,
lineItemAdjustmentsToCreate,
},
({
order,
previewedOrder,
orderChange,
lineItemAdjustmentsToCreate,
}) => {
return previewedOrder.items.map((item) => {
const itemAdjustments = lineItemAdjustmentsToCreate.filter(
(adjustment) => adjustment.item_id === item.id
)
return {
order_change_id: orderChange.id,
order_id: order.id,
version: orderChange.version,
action: ChangeActionType.ITEM_ADJUSTMENTS_REPLACE,
details: {
reference_id: item.id,
adjustments: itemAdjustments,
},
}
})
}
)
createOrderChangeActionsWorkflow
.runAsStep({ input: orderChangeActionAdjustmentsInput })
.config({ name: "order-change-action-adjustments-input" })
})
releaseLockStep({
key: input.order_id,
})
return new WorkflowResponse(void 0)
}
)
@@ -5,6 +5,7 @@ export * from "./begin-draft-order-edit"
export * from "./cancel-draft-order-edit" export * from "./cancel-draft-order-edit"
export * from "./confirm-draft-order-edit" export * from "./confirm-draft-order-edit"
export * from "./convert-draft-order" export * from "./convert-draft-order"
export * from "./compute-draft-order-adjustments"
export * from "./remove-draft-order-action-item" export * from "./remove-draft-order-action-item"
export * from "./remove-draft-order-action-shipping-method" export * from "./remove-draft-order-action-shipping-method"
export * from "./remove-draft-order-promotions" export * from "./remove-draft-order-promotions"
@@ -51,6 +51,10 @@ export interface RefreshDraftOrderAdjustmentsWorkflowInput {
* - Replace the existing promo codes with the new ones. * - Replace the existing promo codes with the new ones.
*/ */
action: PromotionActions action: PromotionActions
/**
* The version of the order change to refresh the adjustments for.
*/
version?: number
} }
/** /**
@@ -92,7 +96,7 @@ export const refreshDraftOrderAdjustmentsWorkflow = createWorkflow(
}) })
const actions = getActionsToComputeFromPromotionsStep({ const actions = getActionsToComputeFromPromotionsStep({
cart: input.order as any, computeActionContext: input.order as any,
promotionCodesToApply, promotionCodesToApply,
}) })
@@ -114,6 +118,7 @@ export const refreshDraftOrderAdjustmentsWorkflow = createWorkflow(
createDraftOrderLineItemAdjustmentsStep({ createDraftOrderLineItemAdjustmentsStep({
lineItemAdjustmentsToCreate: lineItemAdjustmentsToCreate, lineItemAdjustmentsToCreate: lineItemAdjustmentsToCreate,
order_id: input.order.id, order_id: input.order.id,
version: input.version,
}), }),
createDraftOrderShippingMethodAdjustmentsStep({ createDraftOrderShippingMethodAdjustmentsStep({
shippingMethodAdjustmentsToCreate: shippingMethodAdjustmentsToCreate, shippingMethodAdjustmentsToCreate: shippingMethodAdjustmentsToCreate,
@@ -1,4 +1,4 @@
import { OrderChangeStatus, PromotionActions } from "@medusajs/framework/utils" import { OrderChangeStatus } from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
transform, transform,
@@ -20,8 +20,8 @@ import {
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { validateDraftOrderRemoveActionItemStep } from "../steps/validate-draft-order-remove-action-item" import { validateDraftOrderRemoveActionItemStep } from "../steps/validate-draft-order-remove-action-item"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const removeDraftOrderActionItemWorkflowId = export const removeDraftOrderActionItemWorkflowId =
"remove-draft-order-action-item" "remove-draft-order-action-item"
@@ -109,11 +109,9 @@ export const removeDraftOrderActionItemWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order: refetchedOrder, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -1,4 +1,4 @@
import { OrderChangeStatus, PromotionActions } from "@medusajs/framework/utils" import { OrderChangeStatus } from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
parallelize, parallelize,
@@ -24,8 +24,8 @@ import { getDraftOrderPromotionContextStep } from "../steps/get-draft-order-prom
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { validateDraftOrderShippingMethodActionStep } from "../steps/validate-draft-order-shipping-method-action" import { validateDraftOrderShippingMethodActionStep } from "../steps/validate-draft-order-shipping-method-action"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const removeDraftOrderActionShippingMethodWorkflowId = export const removeDraftOrderActionShippingMethodWorkflowId =
"remove-draft-order-action-shipping-method" "remove-draft-order-action-shipping-method"
@@ -117,11 +117,9 @@ export const removeDraftOrderActionShippingMethodWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -21,9 +21,10 @@ import {
} from "../../order" } from "../../order"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { validatePromoCodesToRemoveStep } from "../steps/validate-promo-codes-to-remove" import { validatePromoCodesToRemoveStep } from "../steps/validate-promo-codes-to-remove"
import { updateDraftOrderPromotionsStep } from "../steps/update-draft-order-promotions"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const removeDraftOrderPromotionsWorkflowId = export const removeDraftOrderPromotionsWorkflowId =
"remove-draft-order-promotions" "remove-draft-order-promotions"
@@ -83,7 +84,7 @@ export const removeDraftOrderPromotionsWorkflow = createWorkflow(
const orderChange: OrderChangeDTO = useRemoteQueryStep({ const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change", entry_point: "order_change",
fields: ["id", "status"], fields: ["id", "status", "version"],
variables: { variables: {
filters: { filters: {
order_id: input.order_id, order_id: input.order_id,
@@ -111,11 +112,15 @@ export const removeDraftOrderPromotionsWorkflow = createWorkflow(
promotions, promotions,
}) })
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ updateDraftOrderPromotionsStep({
id: input.order_id,
promo_codes: input.promo_codes,
action: PromotionActions.REMOVE,
})
computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order, order_id: input.order_id,
promo_codes: input.promo_codes,
action: PromotionActions.REMOVE,
}, },
}) })
@@ -1,8 +1,4 @@
import { import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
ChangeActionType,
OrderChangeStatus,
PromotionActions,
} from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
transform, transform,
@@ -18,8 +14,8 @@ import {
} from "../../order" } from "../../order"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const removeDraftOrderShippingMethodWorkflowId = export const removeDraftOrderShippingMethodWorkflowId =
"remove-draft-order-shipping-method" "remove-draft-order-shipping-method"
@@ -103,19 +99,9 @@ export const removeDraftOrderShippingMethodWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
const refetchedOrder = useRemoteQueryStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
entry_point: "orders",
fields: draftOrderFieldsForRefreshSteps,
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
}).config({ name: "refetched-order-query" })
refreshDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order: refetchedOrder, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -1,4 +1,4 @@
import { OrderChangeStatus, PromotionActions } from "@medusajs/framework/utils" import { OrderChangeStatus } from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
transform, transform,
@@ -21,8 +21,8 @@ import { getDraftOrderPromotionContextStep } from "../steps/get-draft-order-prom
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { validateDraftOrderUpdateActionItemStep } from "../steps/validate-draft-order-update-action-item" import { validateDraftOrderUpdateActionItemStep } from "../steps/validate-draft-order-update-action-item"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const updateDraftOrderActionItemId = "update-draft-order-action-item" export const updateDraftOrderActionItemId = "update-draft-order-action-item"
@@ -134,11 +134,9 @@ export const updateDraftOrderActionItemWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order: context, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -1,4 +1,4 @@
import { OrderChangeStatus, PromotionActions } from "@medusajs/framework/utils" import { OrderChangeStatus } from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
parallelize, parallelize,
@@ -25,8 +25,8 @@ import { getDraftOrderPromotionContextStep } from "../steps/get-draft-order-prom
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { validateDraftOrderShippingMethodActionStep } from "../steps/validate-draft-order-shipping-method-action" import { validateDraftOrderShippingMethodActionStep } from "../steps/validate-draft-order-shipping-method-action"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const updateDraftOrderActionShippingMethodWorkflowId = export const updateDraftOrderActionShippingMethodWorkflowId =
"update-draft-order-action-shipping-method" "update-draft-order-action-shipping-method"
@@ -159,11 +159,9 @@ export const updateDraftOrderActionShippingMethodWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -3,7 +3,6 @@ import {
ChangeActionType, ChangeActionType,
MathBN, MathBN,
OrderChangeStatus, OrderChangeStatus,
PromotionActions,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
@@ -26,8 +25,8 @@ import {
import { getDraftOrderPromotionContextStep } from "../steps/get-draft-order-promotion-context" import { getDraftOrderPromotionContextStep } from "../steps/get-draft-order-promotion-context"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const updateDraftOrderItemWorkflowId = "update-draft-order-item" export const updateDraftOrderItemWorkflowId = "update-draft-order-item"
@@ -72,7 +71,7 @@ export const updateDraftOrderItemWorkflow = createWorkflow(
const orderChange: OrderChangeDTO = useRemoteQueryStep({ const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change", entry_point: "order_change",
fields: ["id", "status"], fields: ["id", "status", "version"],
variables: { variables: {
filters: { filters: {
order_id: input.order_id, order_id: input.order_id,
@@ -133,11 +132,9 @@ export const updateDraftOrderItemWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order: context, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -1,8 +1,4 @@
import { import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
ChangeActionType,
OrderChangeStatus,
PromotionActions,
} from "@medusajs/framework/utils"
import { import {
createWorkflow, createWorkflow,
transform, transform,
@@ -24,8 +20,8 @@ import {
import { updateDraftOrderShippingMethodStep } from "../steps/update-draft-order-shipping-metod" import { updateDraftOrderShippingMethodStep } from "../steps/update-draft-order-shipping-metod"
import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change" import { validateDraftOrderChangeStep } from "../steps/validate-draft-order-change"
import { draftOrderFieldsForRefreshSteps } from "../utils/fields" import { draftOrderFieldsForRefreshSteps } from "../utils/fields"
import { refreshDraftOrderAdjustmentsWorkflow } from "./refresh-draft-order-adjustments"
import { acquireLockStep, releaseLockStep } from "../../locking" import { acquireLockStep, releaseLockStep } from "../../locking"
import { computeDraftOrderAdjustmentsWorkflow } from "./compute-draft-order-adjustments"
export const updateDraftOrderShippingMethodWorkflowId = export const updateDraftOrderShippingMethodWorkflowId =
"update-draft-order-shipping-method" "update-draft-order-shipping-method"
@@ -144,11 +140,9 @@ export const updateDraftOrderShippingMethodWorkflow = createWorkflow(
appliedPromoCodes, appliedPromoCodes,
(appliedPromoCodes) => appliedPromoCodes.length > 0 (appliedPromoCodes) => appliedPromoCodes.length > 0
).then(() => { ).then(() => {
refreshDraftOrderAdjustmentsWorkflow.runAsStep({ computeDraftOrderAdjustmentsWorkflow.runAsStep({
input: { input: {
order: refetchedOrder, order_id: input.order_id,
promo_codes: appliedPromoCodes,
action: PromotionActions.REPLACE,
}, },
}) })
}) })
@@ -129,7 +129,7 @@ export const createOrUpdateOrderPaymentCollectionWorkflow = createWorkflow(
return ( return (
!!existingPaymentCollection?.id && !!existingPaymentCollection?.id &&
!shouldRecreate && !shouldRecreate &&
MathBN.gt(amountPending, 0) MathBN.gte(amountPending, 0)
) )
} }
).then(() => { ).then(() => {
@@ -4,6 +4,7 @@ import {
OrderExchangeDTO, OrderExchangeDTO,
OrderPreviewDTO, OrderPreviewDTO,
OrderWorkflow, OrderWorkflow,
PromotionDTO,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils" import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
import { import {
@@ -21,6 +22,7 @@ import {
} from "../../utils/order-validation" } from "../../utils/order-validation"
import { addOrderLineItemsWorkflow } from "../add-line-items" import { addOrderLineItemsWorkflow } from "../add-line-items"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions" import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { computeAdjustmentsForPreviewWorkflow } from "../order-edit/compute-adjustments-for-preview"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines" import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { refreshExchangeShippingWorkflow } from "./refresh-shipping" import { refreshExchangeShippingWorkflow } from "./refresh-shipping"
@@ -123,7 +125,14 @@ export const orderExchangeAddNewItemWorkflow = createWorkflow(
const order: OrderDTO = useRemoteQueryStep({ const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders", entry_point: "orders",
fields: ["id", "status", "canceled_at", "items.*"], fields: [
"id",
"status",
"canceled_at",
"currency_code",
"items.*",
"promotions.*",
],
variables: { id: orderExchange.order_id }, variables: { id: orderExchange.order_id },
list: false, list: false,
throw_if_key_not_found: true, throw_if_key_not_found: true,
@@ -131,7 +140,7 @@ export const orderExchangeAddNewItemWorkflow = createWorkflow(
const orderChange: OrderChangeDTO = useRemoteQueryStep({ const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change", entry_point: "order_change",
fields: ["id", "status"], fields: ["id", "status", "version"],
variables: { variables: {
filters: { filters: {
order_id: orderExchange.order_id, order_id: orderExchange.order_id,
@@ -192,6 +201,21 @@ export const orderExchangeAddNewItemWorkflow = createWorkflow(
input: orderChangeActionInput, input: orderChangeActionInput,
}) })
const orderWithPromotions = transform({ order }, ({ order }) => {
return {
...order,
promotions: (order as any).promotions ?? [],
} as OrderDTO & { promotions: PromotionDTO[] }
})
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order: orderWithPromotions,
orderChange,
exchange_id: orderExchange.id,
},
})
const refreshArgs = transform( const refreshArgs = transform(
{ orderChange, orderExchange }, { orderChange, orderExchange },
({ orderChange, orderExchange }) => { ({ orderChange, orderExchange }) => {
@@ -4,6 +4,7 @@ import {
OrderExchangeDTO, OrderExchangeDTO,
OrderPreviewDTO, OrderPreviewDTO,
OrderWorkflow, OrderWorkflow,
PromotionDTO,
ReturnDTO, ReturnDTO,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { import {
@@ -32,6 +33,7 @@ import {
throwIfOrderChangeIsNotActive, throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation" } from "../../utils/order-validation"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions" import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { computeAdjustmentsForPreviewWorkflow } from "../order-edit/compute-adjustments-for-preview"
import { refreshExchangeShippingWorkflow } from "./refresh-shipping" import { refreshExchangeShippingWorkflow } from "./refresh-shipping"
/** /**
@@ -178,10 +180,12 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow(
fields: [ fields: [
"id", "id",
"status", "status",
"currency_code",
"items.*", "items.*",
"items.variant.manage_inventory", "items.variant.manage_inventory",
"items.variant.inventory_items.inventory_item_id", "items.variant.inventory_items.inventory_item_id",
"items.variant.inventory_items.inventory.location_levels.location_id", "items.variant.inventory_items.inventory.location_levels.location_id",
"promotions.*",
], ],
variables: { id: orderExchange.order_id }, variables: { id: orderExchange.order_id },
list: false, list: false,
@@ -190,7 +194,7 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow(
const orderChange: OrderChangeDTO = useRemoteQueryStep({ const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change", entry_point: "order_change",
fields: ["id", "status"], fields: ["id", "status", "version"],
variables: { variables: {
filters: { filters: {
order_id: orderExchange.order_id, order_id: orderExchange.order_id,
@@ -306,6 +310,21 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow(
input: orderChangeActionInput, input: orderChangeActionInput,
}) })
const orderWithPromotions = transform({ order }, ({ order }) => {
return {
...order,
promotions: (order as any).promotions ?? [],
} as OrderDTO & { promotions: PromotionDTO[] }
})
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order: orderWithPromotions,
orderChange,
exchange_id: orderExchange.id,
},
})
const refreshArgs = transform( const refreshArgs = transform(
{ orderChange, orderExchange }, { orderChange, orderExchange },
({ orderChange, orderExchange }) => { ({ orderChange, orderExchange }) => {
@@ -30,7 +30,6 @@ export * from "./decline-order-change"
export * from "./delete-order-change" export * from "./delete-order-change"
export * from "./delete-order-change-actions" export * from "./delete-order-change-actions"
export * from "./delete-order-payment-collection" export * from "./delete-order-payment-collection"
export * from "./fetch-shipping-option"
export * from "./exchange/begin-order-exchange" export * from "./exchange/begin-order-exchange"
export * from "./exchange/cancel-begin-order-exchange" export * from "./exchange/cancel-begin-order-exchange"
export * from "./exchange/cancel-exchange" export * from "./exchange/cancel-exchange"
@@ -42,13 +41,16 @@ export * from "./exchange/remove-exchange-item-action"
export * from "./exchange/remove-exchange-shipping-method" export * from "./exchange/remove-exchange-shipping-method"
export * from "./exchange/update-exchange-add-item" export * from "./exchange/update-exchange-add-item"
export * from "./exchange/update-exchange-shipping-method" export * from "./exchange/update-exchange-shipping-method"
export * from "./fetch-shipping-option"
export * from "./get-order-detail" export * from "./get-order-detail"
export * from "./get-orders-list" export * from "./get-orders-list"
export * from "./list-shipping-options-for-order"
export * from "./mark-order-fulfillment-as-delivered" export * from "./mark-order-fulfillment-as-delivered"
export * from "./mark-payment-collection-as-paid" export * from "./mark-payment-collection-as-paid"
export * from "./maybe-refresh-shipping-methods" export * from "./maybe-refresh-shipping-methods"
export * from "./order-edit/begin-order-edit" export * from "./order-edit/begin-order-edit"
export * from "./order-edit/cancel-begin-order-edit" export * from "./order-edit/cancel-begin-order-edit"
export * from "./order-edit/compute-adjustments-for-preview"
export * from "./order-edit/confirm-order-edit-request" export * from "./order-edit/confirm-order-edit-request"
export * from "./order-edit/create-order-edit-shipping-method" export * from "./order-edit/create-order-edit-shipping-method"
export * from "./order-edit/order-edit-add-new-item" export * from "./order-edit/order-edit-add-new-item"
@@ -87,4 +89,3 @@ export * from "./update-order"
export * from "./update-order-change-actions" export * from "./update-order-change-actions"
export * from "./update-order-changes" export * from "./update-order-changes"
export * from "./update-tax-lines" export * from "./update-tax-lines"
export * from "./list-shipping-options-for-order"
@@ -104,6 +104,8 @@ export const beginOrderEditOrderWorkflow = createWorkflow(
} }
}) })
return new WorkflowResponse(createOrderChangeStep(orderChangeInput)) const orderChange = createOrderChangeStep(orderChangeInput)
return new WorkflowResponse(orderChange)
} }
) )
@@ -0,0 +1,163 @@
import {
ComputeActionContext,
OrderChangeDTO,
OrderDTO,
PromotionDTO,
} from "@medusajs/framework/types"
import { ChangeActionType } from "@medusajs/framework/utils"
import {
createWorkflow,
transform,
when,
WorkflowData,
} from "@medusajs/framework/workflows-sdk"
import {
getActionsToComputeFromPromotionsStep,
prepareAdjustmentsFromPromotionActionsStep,
} from "../../../cart"
import { previewOrderChangeStep } from "../../steps/preview-order-change"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
/**
* The data to compute adjustments for an order edit, exchange, claim, or return.
*/
export type ComputeAdjustmentsForPreviewWorkflowInput = {
/**
* The order's details.
*/
order: OrderDTO & { promotions: PromotionDTO[] }
/**
* The order change's details.
*/
orderChange: OrderChangeDTO
/**
* Optional exchange ID to include in the order change action.
*/
exchange_id?: string
/**
* Optional claim ID to include in the order change action.
*/
claim_id?: string
/**
* Optional return ID to include in the order change action.
*/
return_id?: string
}
export const computeAdjustmentsForPreviewWorkflowId =
"compute-adjustments-for-preview"
/**
* This workflow computes adjustments for an order edit, exchange, claim, or return.
* It's used by the [Add Items to Order Edit Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditems),
* [Add Outbound Items Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidoutbounditems),
* and [Add Inbound Items Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidinbounditems).
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to compute adjustments
* in your custom flows.
*
* @example
* const { result } = await computeAdjustmentsForPreviewWorkflow(container)
* .run({
* input: {
* order: {
* id: "order_123",
* // other order details...
* },
* orderChange: {
* id: "orch_123",
* // other order change details...
* },
* exchange_id: "exchange_123", // optional, for exchanges
* }
* })
*
* @summary
*
* Compute adjustments for an order edit, exchange, claim, or return.
*/
export const computeAdjustmentsForPreviewWorkflow = createWorkflow(
computeAdjustmentsForPreviewWorkflowId,
function (input: WorkflowData<ComputeAdjustmentsForPreviewWorkflowInput>) {
const previewedOrder = previewOrderChangeStep(input.order.id)
when({ order: input.order }, ({ order }) => !!order.promotions.length).then(
() => {
const actionsToComputeItemsInput = transform(
{ previewedOrder, order: input.order },
({ previewedOrder, order }) => {
return {
currency_code: order.currency_code,
items: previewedOrder.items.map((item) => ({
...item,
// Buy-Get promotions rely on the product ID, so we need to manually set it before refreshing adjustments
product: { id: item.product_id },
})),
} as ComputeActionContext
}
)
const orderPromotions = transform(
{ order: input.order },
({ order }) => {
return order.promotions
.map((p) => p.code)
.filter((p) => p !== undefined)
}
)
const actions = getActionsToComputeFromPromotionsStep({
computeActionContext: actionsToComputeItemsInput,
promotionCodesToApply: orderPromotions,
})
const { lineItemAdjustmentsToCreate } =
prepareAdjustmentsFromPromotionActionsStep({ actions })
const orderChangeActionAdjustmentsInput = transform(
{
order: input.order,
previewedOrder,
orderChange: input.orderChange,
lineItemAdjustmentsToCreate,
exchangeId: input.exchange_id,
claimId: input.claim_id,
returnId: input.return_id,
},
({
order,
previewedOrder,
orderChange,
lineItemAdjustmentsToCreate,
exchangeId,
claimId,
returnId,
}) => {
return previewedOrder.items.map((item) => {
const itemAdjustments = lineItemAdjustmentsToCreate.filter(
(adjustment) => adjustment.item_id === item.id
)
return {
order_change_id: orderChange.id,
order_id: order.id,
...(exchangeId && { exchange_id: exchangeId }),
...(claimId && { claim_id: claimId }),
...(returnId && { return_id: returnId }),
version: orderChange.version,
action: ChangeActionType.ITEM_ADJUSTMENTS_REPLACE,
details: {
reference_id: item.id,
adjustments: itemAdjustments,
},
}
})
}
)
createOrderChangeActionsWorkflow
.runAsStep({ input: orderChangeActionAdjustmentsInput })
.config({ name: "order-change-action-adjustments-input" })
}
)
}
)
@@ -6,26 +6,23 @@ import {
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { import {
ChangeActionType, ChangeActionType,
deduplicate,
MathBN, MathBN,
OrderChangeStatus, OrderChangeStatus,
OrderEditWorkflowEvents, OrderEditWorkflowEvents,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import { import {
WorkflowResponse,
createStep, createStep,
createWorkflow, createWorkflow,
transform, transform,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { reserveInventoryStep } from "../../../cart/steps/reserve-inventory" import { reserveInventoryStep } from "../../../cart/steps/reserve-inventory"
import { import {
prepareConfirmInventoryInput, prepareConfirmInventoryInput,
requiredOrderFieldsForInventoryConfirmation, requiredOrderFieldsForInventoryConfirmation,
} from "../../../cart/utils/prepare-confirm-inventory-input" } from "../../../cart/utils/prepare-confirm-inventory-input"
import { import { emitEventStep, useQueryGraphStep } from "../../../common"
emitEventStep,
useQueryGraphStep,
useRemoteQueryStep,
} from "../../../common"
import { deleteReservationsByLineItemsStep } from "../../../reservation" import { deleteReservationsByLineItemsStep } from "../../../reservation"
import { previewOrderChangeStep } from "../../steps" import { previewOrderChangeStep } from "../../steps"
import { confirmOrderChanges } from "../../steps/confirm-order-changes" import { confirmOrderChanges } from "../../steps/confirm-order-changes"
@@ -176,22 +173,27 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
confirmed_by: input.confirmed_by, confirmed_by: input.confirmed_by,
}) })
const orderItems = useRemoteQueryStep({ const { data: refreshedOrder } = useQueryGraphStep({
entry_point: "order", entity: "order",
fields: requiredOrderFieldsForInventoryConfirmation, fields: deduplicate([
variables: { id: input.order_id }, ...requiredOrderFieldsForInventoryConfirmation,
list: false, ...fieldsToRefreshOrderEdit,
throw_if_key_not_found: true, ]),
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
isList: false,
},
}).config({ name: "order-items-query" }) }).config({ name: "order-items-query" })
const { variants, items, toRemoveReservationLineItemIds } = transform( const { variants, items, toRemoveReservationLineItemIds } = transform(
{ orderItems, previousOrderItems: order.items, orderPreview }, { refreshedOrder, previousOrderItems: order.items, orderPreview },
({ orderItems, previousOrderItems, orderPreview }) => { ({ refreshedOrder, previousOrderItems, orderPreview }) => {
const allItems: any[] = [] const allItems: any[] = []
const allVariants: any[] = [] const allVariants: any[] = []
const previousItemIds = (previousOrderItems || []).map(({ id }) => id) const previousItemIds = (previousOrderItems || []).map(({ id }) => id)
const currentItemIds = orderItems.items.map(({ id }) => id) const currentItemIds = refreshedOrder.items.map(({ id }) => id)
const removedItemIds = previousItemIds.filter( const removedItemIds = previousItemIds.filter(
(id) => !currentItemIds.includes(id) (id) => !currentItemIds.includes(id)
@@ -199,7 +201,7 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
const updatedItemIds: string[] = [] const updatedItemIds: string[] = []
orderItems.items.forEach((ordItem) => { refreshedOrder.items.forEach((ordItem) => {
const itemAction = orderPreview.items?.find( const itemAction = orderPreview.items?.find(
(item) => (item) =>
item.id === ordItem.id && item.id === ordItem.id &&
@@ -214,13 +216,6 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
return return
} }
const unitPrice: BigNumberInput =
itemAction.raw_unit_price ?? itemAction.unit_price
const compareAtUnitPrice: BigNumberInput | undefined =
itemAction.raw_compare_at_unit_price ??
itemAction.compare_at_unit_price
const updateAction = itemAction.actions!.find( const updateAction = itemAction.actions!.find(
(a) => a.action === ChangeActionType.ITEM_UPDATE (a) => a.action === ChangeActionType.ITEM_UPDATE
) )
@@ -241,8 +236,6 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
id: ordItem.id, id: ordItem.id,
variant_id: ordItem.variant_id, variant_id: ordItem.variant_id,
quantity: reservationQuantity, quantity: reservationQuantity,
unit_price: unitPrice,
compare_at_unit_price: compareAtUnitPrice,
}) })
allVariants.push(ordItem.variant) allVariants.push(ordItem.variant)
}) })
@@ -261,7 +254,7 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
const formatedInventoryItems = transform( const formatedInventoryItems = transform(
{ {
input: { input: {
sales_channel_id: (orderItems as any).sales_channel_id, sales_channel_id: (refreshedOrder as any).sales_channel_id,
variants, variants,
items, items,
}, },
@@ -4,16 +4,13 @@ import {
OrderPreviewDTO, OrderPreviewDTO,
OrderWorkflow, OrderWorkflow,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
import { import {
ChangeActionType,
OrderChangeStatus
} from "@medusajs/framework/utils"
import {
WorkflowData,
WorkflowResponse,
createStep, createStep,
createWorkflow, createWorkflow,
transform, transform,
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "../../../common" import { useQueryGraphStep } from "../../../common"
import { previewOrderChangeStep } from "../../steps/preview-order-change" import { previewOrderChangeStep } from "../../steps/preview-order-change"
@@ -25,6 +22,7 @@ import { addOrderLineItemsWorkflow } from "../add-line-items"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions" import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines" import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { fieldsToRefreshOrderEdit } from "./utils/fields" import { fieldsToRefreshOrderEdit } from "./utils/fields"
import { computeAdjustmentsForPreviewWorkflow } from "./compute-adjustments-for-preview"
/** /**
* The data to validate that new items can be added to an order edit. * The data to validate that new items can be added to an order edit.
@@ -158,7 +156,12 @@ export const orderEditAddNewItemWorkflow = createWorkflow(
}) })
const orderChangeActionInput = transform( const orderChangeActionInput = transform(
{ order, orderChange, items: input.items, lineItems }, {
order,
orderChange,
items: input.items,
lineItems,
},
({ order, orderChange, items, lineItems }) => { ({ order, orderChange, items, lineItems }) => {
return items.map((item, index) => ({ return items.map((item, index) => ({
order_change_id: orderChange.id, order_change_id: orderChange.id,
@@ -183,6 +186,13 @@ export const orderEditAddNewItemWorkflow = createWorkflow(
input: orderChangeActionInput, input: orderChangeActionInput,
}) })
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order,
orderChange,
},
})
return new WorkflowResponse(previewOrderChangeStep(input.order_id)) return new WorkflowResponse(previewOrderChangeStep(input.order_id))
} }
) )
@@ -11,11 +11,11 @@ import {
OrderChangeStatus, OrderChangeStatus,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import { import {
WorkflowData,
WorkflowResponse,
createStep, createStep,
createWorkflow, createWorkflow,
transform, transform,
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "../../../common" import { useQueryGraphStep } from "../../../common"
import { previewOrderChangeStep } from "../../steps/preview-order-change" import { previewOrderChangeStep } from "../../steps/preview-order-change"
@@ -24,6 +24,7 @@ import {
throwIfOrderChangeIsNotActive, throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation" } from "../../utils/order-validation"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions" import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { computeAdjustmentsForPreviewWorkflow } from "./compute-adjustments-for-preview"
import { fieldsToRefreshOrderEdit } from "./utils/fields" import { fieldsToRefreshOrderEdit } from "./utils/fields"
/** /**
@@ -80,6 +81,10 @@ export const orderEditUpdateItemQuantityWorkflowId =
* This workflow updates the quantity of an existing item in an order's edit. It's used by the * This workflow updates the quantity of an existing item in an order's edit. It's used by the
* [Update Order Item Quantity Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditemsitemitem_id). * [Update Order Item Quantity Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditemsitemitem_id).
* *
* This workflow is different from the `updateOrderEditItemQuantityWorkflow` workflow in that this should be used
* when the item to update was part of the original order before the edit. The other workflow is for items
* that were added to the order as part of the edit.
*
* You can also use this workflow to remove an item from an order by setting its quantity to `0`. * You can also use this workflow to remove an item from an order by setting its quantity to `0`.
* *
* You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity of an existing * You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity of an existing
@@ -143,9 +148,13 @@ export const orderEditUpdateItemQuantityWorkflow = createWorkflow(
}) })
const orderChangeActionInput = transform( const orderChangeActionInput = transform(
{ order, orderChange, items: input.items }, {
order,
orderChange,
items: input.items,
},
({ order, orderChange, items }) => { ({ order, orderChange, items }) => {
return items.map((item) => { const itemsUpdates = items.map((item) => {
const existing = order?.items?.find( const existing = order?.items?.find(
(exItem) => exItem.id === item.id (exItem) => exItem.id === item.id
)! )!
@@ -169,6 +178,8 @@ export const orderEditUpdateItemQuantityWorkflow = createWorkflow(
}, },
} }
}) })
return [...itemsUpdates]
} }
) )
@@ -176,6 +187,13 @@ export const orderEditUpdateItemQuantityWorkflow = createWorkflow(
input: orderChangeActionInput, input: orderChangeActionInput,
}) })
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order,
orderChange,
},
})
return new WorkflowResponse(previewOrderChangeStep(input.order_id)) return new WorkflowResponse(previewOrderChangeStep(input.order_id))
} }
) )
@@ -5,10 +5,7 @@ import {
OrderPreviewDTO, OrderPreviewDTO,
OrderWorkflow, OrderWorkflow,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
ChangeActionType,
OrderChangeStatus
} from "@medusajs/framework/utils"
import { import {
WorkflowData, WorkflowData,
WorkflowResponse, WorkflowResponse,
@@ -25,6 +22,7 @@ import {
throwIfIsCancelled, throwIfIsCancelled,
throwIfOrderChangeIsNotActive, throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation" } from "../../utils/order-validation"
import { computeAdjustmentsForPreviewWorkflow } from "./compute-adjustments-for-preview"
import { fieldsToRefreshOrderEdit } from "./utils/fields" import { fieldsToRefreshOrderEdit } from "./utils/fields"
/** /**
@@ -167,6 +165,13 @@ export const removeItemOrderEditActionWorkflow = createWorkflow(
deleteOrderChangeActionsStep({ ids: [input.action_id] }) deleteOrderChangeActionsStep({ ids: [input.action_id] })
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order,
orderChange,
},
})
return new WorkflowResponse(previewOrderChangeStep(order.id)) return new WorkflowResponse(previewOrderChangeStep(order.id))
} }
) )
@@ -22,6 +22,7 @@ import {
throwIfIsCancelled, throwIfIsCancelled,
throwIfOrderChangeIsNotActive, throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation" } from "../../utils/order-validation"
import { computeAdjustmentsForPreviewWorkflow } from "./compute-adjustments-for-preview"
import { fieldsToRefreshOrderEdit } from "./utils/fields" import { fieldsToRefreshOrderEdit } from "./utils/fields"
/** /**
@@ -185,6 +186,13 @@ export const updateOrderEditAddItemWorkflow = createWorkflow(
updateOrderChangeActionsStep([updateData]) updateOrderChangeActionsStep([updateData])
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order,
orderChange,
},
})
return new WorkflowResponse(previewOrderChangeStep(order.id)) return new WorkflowResponse(previewOrderChangeStep(order.id))
} }
) )
@@ -22,6 +22,7 @@ import {
throwIfIsCancelled, throwIfIsCancelled,
throwIfOrderChangeIsNotActive, throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation" } from "../../utils/order-validation"
import { computeAdjustmentsForPreviewWorkflow } from "./compute-adjustments-for-preview"
import { fieldsToRefreshOrderEdit } from "./utils/fields" import { fieldsToRefreshOrderEdit } from "./utils/fields"
/** /**
@@ -105,6 +106,9 @@ export const updateOrderEditItemQuantityWorkflowId =
"update-order-edit-update-quantity" "update-order-edit-update-quantity"
/** /**
* This workflow updates an existing order item that was previously added to the order edit. * This workflow updates an existing order item that was previously added to the order edit.
* It is different from the `orderEditUpdateItemQuantityWorkflow` workflow in that this should be used
* when the item to update was added as part of the order edit. The other workflow is for items
* that were already in the order before the edit.
* *
* You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity * You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity
* of an existing item in an order edit in your custom flows. * of an existing item in an order edit in your custom flows.
@@ -185,6 +189,13 @@ export const updateOrderEditItemQuantityWorkflow = createWorkflow(
updateOrderChangeActionsStep([updateData]) updateOrderChangeActionsStep([updateData])
computeAdjustmentsForPreviewWorkflow.runAsStep({
input: {
order,
orderChange,
},
})
return new WorkflowResponse(previewOrderChangeStep(order.id)) return new WorkflowResponse(previewOrderChangeStep(order.id))
} }
) )
@@ -4,8 +4,13 @@ export const fieldsToRefreshOrderEdit = [
"version", "version",
"currency_code", "currency_code",
"canceled_at", "canceled_at",
"items.*",
"items.product.id",
"promotions.*", "promotions.*",
"subtotal",
"items.*",
"items.subtotal",
"items.product.id",
"items.adjustments.*",
"shipping_methods.*",
"shipping_methods.adjustments.*",
"shipping_address.*", "shipping_address.*",
] ]
@@ -4,6 +4,7 @@ import {
transform, transform,
when, when,
WorkflowData, WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "../../common" import { useQueryGraphStep } from "../../common"
import { getItemTaxLinesStep } from "../../tax/steps/get-item-tax-lines" import { getItemTaxLinesStep } from "../../tax/steps/get-item-tax-lines"
@@ -179,9 +180,7 @@ export const updateOrderTaxLinesWorkflowId = "update-order-tax-lines"
*/ */
export const updateOrderTaxLinesWorkflow = createWorkflow( export const updateOrderTaxLinesWorkflow = createWorkflow(
updateOrderTaxLinesWorkflowId, updateOrderTaxLinesWorkflowId,
( (input: WorkflowData<UpdateOrderTaxLinesWorkflowInput>) => {
input: WorkflowData<UpdateOrderTaxLinesWorkflowInput>
): WorkflowData<void> => {
const isFullOrder = transform(input, (data) => { const isFullOrder = transform(input, (data) => {
return !data.item_ids && !data.shipping_method_ids return !data.item_ids && !data.shipping_method_ids
}) })
@@ -209,9 +208,13 @@ export const updateOrderTaxLinesWorkflow = createWorkflow(
return orderLineItems return orderLineItems
}) })
const shippingMethods = when("get-order-shipping-methods", { input }, ({ input }) => { const shippingMethods = when(
return input.shipping_method_ids!?.length > 0 "get-order-shipping-methods",
}).then(() => { { input },
({ input }) => {
return input.shipping_method_ids!?.length > 0
}
).then(() => {
const { data: orderShippingMethods } = useQueryGraphStep({ const { data: orderShippingMethods } = useQueryGraphStep({
entity: "order_shipping_method", entity: "order_shipping_method",
filters: { id: input.shipping_method_ids }, filters: { id: input.shipping_method_ids },
@@ -250,5 +253,10 @@ export const updateOrderTaxLinesWorkflow = createWorkflow(
item_tax_lines: taxLineItems.lineItemTaxLines, item_tax_lines: taxLineItems.lineItemTaxLines,
shipping_tax_lines: taxLineItems.shippingMethodsTaxLines, shipping_tax_lines: taxLineItems.shippingMethodsTaxLines,
}) })
return new WorkflowResponse({
itemTaxLines: taxLineItems.lineItemTaxLines,
shippingTaxLines: taxLineItems.shippingMethodsTaxLines,
})
} }
) )
+1 -1
View File
@@ -80,7 +80,7 @@
"@medusajs/workflows-sdk": "2.11.3", "@medusajs/workflows-sdk": "2.11.3",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"compression": "^1.8.0", "compression": "^1.8.1",
"connect-redis": "5.2.0", "connect-redis": "5.2.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"cors": "^2.8.5", "cors": "^2.8.5",
+6
View File
@@ -30,6 +30,7 @@ export type ChangeActionType =
| "CREDIT_LINE_ADD" | "CREDIT_LINE_ADD"
| "PROMOTION_ADD" | "PROMOTION_ADD"
| "PROMOTION_REMOVE" | "PROMOTION_REMOVE"
| "ITEM_ADJUSTMENTS_REPLACE"
export type OrderChangeStatus = export type OrderChangeStatus =
| "confirmed" | "confirmed"
@@ -2310,6 +2311,11 @@ export interface OrderChangeActionDTO {
*/ */
internal_note: string | null internal_note: string | null
/**
* The ordering of the order change action
*/
ordering: number
/** /**
* When the order change action was created * When the order change action was created
*/ */
@@ -301,6 +301,11 @@ export interface CreateOrderAdjustmentDTO {
* Whether the adjustment is tax inclusive. * Whether the adjustment is tax inclusive.
*/ */
is_tax_inclusive?: boolean is_tax_inclusive?: boolean
/**
* The version of the adjustment.
*/
version?: number
} }
/** /**
@@ -90,6 +90,11 @@ export interface RemoveItemAdjustmentAction {
*/ */
adjustment_id: string adjustment_id: string
/**
* The associated item's ID.
*/
item_id: string
/** /**
* The promotion's description. * The promotion's description.
*/ */
@@ -145,6 +150,11 @@ export interface RemoveShippingMethodAdjustment {
*/ */
adjustment_id: string adjustment_id: string
/**
* The associated shipping method's ID.
*/
shipping_method_id: string
/** /**
* The promotion's code. * The promotion's code.
*/ */
@@ -244,7 +254,7 @@ export interface ComputeActionContext extends Record<string, unknown> {
/** /**
* The cart's email * The cart's email
* *
* @since 2.11.0 * @since 2.11.0
*/ */
email?: string email?: string
@@ -20,4 +20,5 @@ export enum ChangeActionType {
CREDIT_LINE_ADD = "CREDIT_LINE_ADD", CREDIT_LINE_ADD = "CREDIT_LINE_ADD",
PROMOTION_ADD = "PROMOTION_ADD", PROMOTION_ADD = "PROMOTION_ADD",
PROMOTION_REMOVE = "PROMOTION_REMOVE", PROMOTION_REMOVE = "PROMOTION_REMOVE",
ITEM_ADJUSTMENTS_REPLACE = "ITEM_ADJUSTMENTS_REPLACE",
} }
@@ -214,7 +214,6 @@ export function decorateCartTotals(
shippingOriginalSubtotal shippingOriginalSubtotal
) )
// TODO: subtract (cart.gift_card_total + cart.gift_card_tax_total)
const tempTotal = MathBN.add(subtotal, taxTotal) const tempTotal = MathBN.add(subtotal, taxTotal)
const total = MathBN.sub(tempTotal, discountSubtotal, creditLinesTotal) const total = MathBN.sub(tempTotal, discountSubtotal, creditLinesTotal)
@@ -107,7 +107,7 @@ function setRefundableTotal(
totals.refundable_total = new BigNumber(refundableTotal) totals.refundable_total = new BigNumber(refundableTotal)
} }
function getLineItemTotals( export function getLineItemTotals(
item: GetItemTotalInput, item: GetItemTotalInput,
context: GetLineItemsTotalsContext context: GetLineItemsTotalsContext
) { ) {
@@ -33,7 +33,6 @@ export const DELETE = async (
) => { ) => {
const { id } = req.params const { id } = req.params
const { result } = await removeDraftOrderPromotionsWorkflow(req.scope).run({ const { result } = await removeDraftOrderPromotionsWorkflow(req.scope).run({
input: { input: {
...req.validatedBody, ...req.validatedBody,
@@ -868,6 +868,86 @@ moduleIntegrationTestRunner<IOrderModuleService>({
}) })
) )
}) })
it("should create an order change, update items, and have the pending difference updated", async function () {
const createdOrder = await service.createOrders({
email: "foo@bar.com",
items: [
{
title: "Item 1",
subtitle: "Subtitle 1",
thumbnail: "thumbnail1.jpg",
quantity: new BigNumber(1),
product_id: "product1",
product_title: "Product 1",
product_description: "Description 1",
product_subtitle: "Product Subtitle 1",
product_type: "Type 1",
product_collection: "Collection 1",
product_handle: "handle1",
variant_id: "variant1",
variant_sku: "SKU1",
variant_barcode: "Barcode1",
variant_title: "Variant 1",
variant_option_values: {
color: "Red",
size: "Large",
},
requires_shipping: true,
is_discountable: true,
is_tax_inclusive: true,
compare_at_unit_price: 10,
unit_price: 10,
tax_lines: [],
adjustments: [
{
code: "VIP_10",
amount: 1,
description: "VIP discount",
promotion_id: "prom_123",
provider_id: "coupon_kings",
},
],
},
],
sales_channel_id: "test",
transactions: [
{
amount: 9,
currency_code: "USD",
reference: "payment",
reference_id: "pay_123",
},
],
currency_code: "usd",
customer_id: "joe",
} as CreateOrderDTO)
const orderChange = await service.createOrderChange({
order_id: createdOrder.id,
actions: [
{
action: ChangeActionType.ITEM_UPDATE,
details: {
reference_id: createdOrder.items![0].id,
quantity: 0,
},
},
],
})
await service.confirmOrderChange({
id: orderChange.id,
})
const changedOrder = await service.retrieveOrder(createdOrder.id, {
select: ["total", "summary", "total"],
relations: ["items"],
})
// @ts-ignore
expect(changedOrder.summary?.pending_difference.numeric).toEqual(-9)
})
}) })
}, },
}) })
@@ -1978,6 +1978,15 @@
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_order_item_order_id_version\" ON \"order_item\" (\"order_id\", \"version\") WHERE deleted_at IS NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_order_item_order_id_version\" ON \"order_item\" (\"order_id\", \"version\") WHERE deleted_at IS NULL"
}, },
{
"keyName": "IDX_order_item_version",
"columnNames": [],
"composite": false,
"constraint": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_order_item_version\" ON \"order_item\" (version) WHERE deleted_at IS NULL"
},
{ {
"keyName": "IDX_order_item_item_id", "keyName": "IDX_order_item_item_id",
"columnNames": [], "columnNames": [],
@@ -2048,6 +2057,16 @@
"nullable": false, "nullable": false,
"mappedType": "text" "mappedType": "text"
}, },
"version": {
"name": "version",
"type": "integer",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "1",
"mappedType": "integer"
},
"description": { "description": {
"name": "description", "name": "description",
"type": "text", "type": "text",
@@ -0,0 +1,33 @@
import { Migration } from "@mikro-orm/migrations"
export class Migration20251016160403 extends Migration {
override async up(): Promise<void> {
this.addSql(
`alter table if exists "order_line_item_adjustment" add column if not exists "version" integer not null default 1;`
)
this.addSql(`
WITH latest_order_item_version AS (
SELECT
oli.id AS item_id,
MAX(oi.version) AS version
FROM "order_line_item" oli
INNER JOIN "order_item" oi
ON oi.item_id = oli.id
AND oi.deleted_at IS NULL
GROUP BY oli.id
)
UPDATE "order_line_item_adjustment" olia
SET version = latest_order_item_version.version
FROM latest_order_item_version
WHERE olia.item_id = latest_order_item_version.item_id
AND olia.version <> latest_order_item_version.version;
`)
}
override async down(): Promise<void> {
this.addSql(
`alter table if exists "order_line_item_adjustment" drop column if exists "version";`
)
}
}
@@ -4,6 +4,7 @@ import { OrderLineItem } from "./line-item"
const _OrderLineItemAdjustment = model const _OrderLineItemAdjustment = model
.define("OrderLineItemAdjustment", { .define("OrderLineItemAdjustment", {
id: model.id({ prefix: "ordliadj" }).primaryKey(), id: model.id({ prefix: "ordliadj" }).primaryKey(),
version: model.number().default(1),
description: model.text().nullable(), description: model.text().nullable(),
promotion_id: model.text().nullable(), promotion_id: model.text().nullable(),
code: model.text().nullable(), code: model.text().nullable(),
@@ -2540,19 +2540,29 @@ export default class OrderModuleService
sharedContext sharedContext
) )
const { itemsToUpsert, shippingMethodsToUpsert, calculatedOrders } = // We need to apply the latest ordering actions last
await applyChangesToOrder( const sortedActions = orderChange.actions.sort((a, b) => {
[order], return a.ordering - b.ordering
{ [order.id]: orderChange.actions }, })
{ addActionReferenceToObject: true }
) const {
itemsToUpsert,
shippingMethodsToUpsert,
calculatedOrders,
lineItemAdjustmentsToCreate,
} = await applyChangesToOrder(
[order],
{ [order.id]: sortedActions },
{ addActionReferenceToObject: true }
)
const calculated = calculatedOrders[order.id] const calculated = calculatedOrders[order.id]
await this.includeTaxLinesAndAdjustementsToPreview( await this.includeTaxLinesAndAdjustmentsToPreview(
calculated.order, calculated.order,
itemsToUpsert, itemsToUpsert,
shippingMethodsToUpsert, shippingMethodsToUpsert,
lineItemAdjustmentsToCreate, // this will add "virtual" adjustments for the preview version but no actual adjustments will be created in the DB
sharedContext sharedContext
) )
@@ -2568,10 +2578,11 @@ export default class OrderModuleService
return calcOrder return calcOrder
} }
private async includeTaxLinesAndAdjustementsToPreview( private async includeTaxLinesAndAdjustmentsToPreview(
order, order,
itemsToUpsert, itemsToUpsert,
shippingMethodsToUpsert, shippingMethodsToUpsert,
lineItemAdjustmentsToCreate,
sharedContext: Context = {} sharedContext: Context = {}
) { ) {
const addedItems = {} const addedItems = {}
@@ -2619,6 +2630,11 @@ export default class OrderModuleService
//@ts-ignore //@ts-ignore
const newItem = itemsToUpsert.find((d) => d.item_id === item.id)! const newItem = itemsToUpsert.find((d) => d.item_id === item.id)!
const adjustments = lineItemAdjustmentsToCreate.filter(
(d) => d.item_id === newItem.item_id
)
const unitPrice = newItem?.unit_price ?? item.unit_price const unitPrice = newItem?.unit_price ?? item.unit_price
const compareAtUnitPrice = const compareAtUnitPrice =
newItem?.compare_at_unit_price ?? item.compare_at_unit_price newItem?.compare_at_unit_price ?? item.compare_at_unit_price
@@ -2632,6 +2648,7 @@ export default class OrderModuleService
quantity: newItem.quantity, quantity: newItem.quantity,
unit_price: unitPrice, unit_price: unitPrice,
compare_at_unit_price: compareAtUnitPrice || null, compare_at_unit_price: compareAtUnitPrice || null,
adjustments: adjustments,
detail: { detail: {
...newItem, ...newItem,
...item, ...item,
@@ -3539,11 +3556,12 @@ export default class OrderModuleService
summariesToUpsert, summariesToUpsert,
orderToUpdate, orderToUpdate,
creditLinesToUpsert, creditLinesToUpsert,
lineItemAdjustmentsToCreate,
} = await applyChangesToOrder(orders, actionsMap, { } = await applyChangesToOrder(orders, actionsMap, {
addActionReferenceToObject: true, addActionReferenceToObject: true,
includeTaxLinesAndAdjustementsToPreview: async (...args) => { includeTaxLinesAndAdjustmentsToPreview: async (...args) => {
args.push(sharedContext) args.push(sharedContext)
return await this.includeTaxLinesAndAdjustementsToPreview.apply( return await this.includeTaxLinesAndAdjustmentsToPreview.apply(
this, this,
args args
) )
@@ -3582,6 +3600,14 @@ export default class OrderModuleService
sharedContext sharedContext
) )
: null, : null,
lineItemAdjustmentsToCreate.length
? this.orderLineItemAdjustmentService_.create(
// this is called when a new order version is confirmed so we only create a new set of adjustments for that version
// there is no removal or upsert
lineItemAdjustmentsToCreate,
sharedContext
)
: null,
]) ])
return { return {
@@ -1,6 +1,8 @@
import { import {
BigNumberInput, BigNumberInput,
CreateOrderCreditLineDTO, CreateOrderCreditLineDTO,
LineItemAdjustmentDTO,
LineItemTaxLineDTO,
OrderCreditLineDTO, OrderCreditLineDTO,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
@@ -13,10 +15,13 @@ export type VirtualOrder = {
return_id?: string return_id?: string
claim_id?: string claim_id?: string
exchange_id?: string exchange_id?: string
is_tax_inclusive?: boolean
unit_price: BigNumberInput unit_price: BigNumberInput
compare_at_unit_price: BigNumberInput | null compare_at_unit_price: BigNumberInput | null
quantity: BigNumberInput quantity: BigNumberInput
adjustments?: (LineItemAdjustmentDTO & { version: number })[]
tax_lines?: LineItemTaxLineDTO[]
detail: { detail: {
id?: string id?: string
@@ -24,7 +29,6 @@ export type VirtualOrder = {
return_id?: string return_id?: string
claim_id?: string claim_id?: string
exchange_id?: string exchange_id?: string
item_id?: string item_id?: string
unit_price?: BigNumberInput unit_price?: BigNumberInput
compare_at_unit_price?: BigNumberInput | null compare_at_unit_price?: BigNumberInput | null
@@ -5,6 +5,7 @@ export * from "./credit-line-add"
export * from "./deliver-item" export * from "./deliver-item"
export * from "./fulfill-item" export * from "./fulfill-item"
export * from "./item-add" export * from "./item-add"
export * from "./item-adjustments-replace"
export * from "./item-remove" export * from "./item-remove"
export * from "./item-update" export * from "./item-update"
export * from "./promotion-add" export * from "./promotion-add"
@@ -19,3 +20,4 @@ export * from "./shipping-remove"
export * from "./shipping-update" export * from "./shipping-update"
export * from "./transfer-customer" export * from "./transfer-customer"
export * from "./write-off-item" export * from "./write-off-item"
@@ -29,7 +29,6 @@ OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_ADD, {
return_id: action.return_id, return_id: action.return_id,
claim_id: action.claim_id, claim_id: action.claim_id,
exchange_id: action.exchange_id, exchange_id: action.exchange_id,
unit_price: action.details.unit_price, unit_price: action.details.unit_price,
compare_at_unit_price: action.details.compare_at_unit_price, compare_at_unit_price: action.details.compare_at_unit_price,
quantity: action.details.quantity, quantity: action.details.quantity,
@@ -0,0 +1,32 @@
import { ChangeActionType, MedusaError } from "@medusajs/framework/utils"
import { OrderChangeProcessing } from "../calculate-order-change"
import { setActionReference } from "../set-action-reference"
OrderChangeProcessing.registerActionType(
ChangeActionType.ITEM_ADJUSTMENTS_REPLACE,
{
operation({ action, currentOrder, options }) {
let existing = currentOrder.items.find(
(item) => item.id === action.details.reference_id
)
if (!existing) {
return
}
existing.adjustments = action.details.adjustments ?? []
setActionReference(existing, action, options)
},
validate({ action }) {
const refId = action.details?.reference_id
if (!action.details.adjustments) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Adjustments of item ${refId} must exist.`
)
}
},
}
)
@@ -27,6 +27,10 @@ OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_UPDATE, {
existing.quantity = currentQuantity existing.quantity = currentQuantity
existing.detail.quantity = currentQuantity existing.detail.quantity = currentQuantity
if (action.details.adjustments) {
existing.adjustments = action.details.adjustments
}
if (action.details.unit_price) { if (action.details.unit_price) {
const currentUnitPrice = MathBN.convert(action.details.unit_price) const currentUnitPrice = MathBN.convert(action.details.unit_price)
const originalTotal = MathBN.mult(originalUnitPrice, originalQuantity) const originalTotal = MathBN.mult(originalUnitPrice, originalQuantity)
@@ -1,4 +1,5 @@
import { import {
CreateOrderLineItemAdjustmentDTO,
InferEntityType, InferEntityType,
OrderChangeActionDTO, OrderChangeActionDTO,
OrderDTO, OrderDTO,
@@ -25,13 +26,14 @@ export async function applyChangesToOrder(
actionsMap: Record<string, any[]>, actionsMap: Record<string, any[]>,
options?: { options?: {
addActionReferenceToObject?: boolean addActionReferenceToObject?: boolean
includeTaxLinesAndAdjustementsToPreview?: (...args) => void includeTaxLinesAndAdjustmentsToPreview?: (...args) => void
} }
) { ) {
const itemsToUpsert: InferEntityType<typeof OrderItem>[] = [] const itemsToUpsert: InferEntityType<typeof OrderItem>[] = []
const creditLinesToUpsert: InferEntityType<typeof OrderCreditLine>[] = [] const creditLinesToUpsert: InferEntityType<typeof OrderCreditLine>[] = []
const shippingMethodsToUpsert: InferEntityType<typeof OrderShippingMethod>[] = const shippingMethodsToUpsert: InferEntityType<typeof OrderShippingMethod>[] =
[] []
const lineItemAdjustmentsToCreate: CreateOrderLineItemAdjustmentDTO[] = []
const summariesToUpsert: any[] = [] const summariesToUpsert: any[] = []
const orderToUpdate: any[] = [] const orderToUpdate: any[] = []
@@ -94,6 +96,20 @@ export async function applyChangesToOrder(
metadata: orderItem.metadata, metadata: orderItem.metadata,
} as any } as any
if (version > order.version) {
item.adjustments?.forEach((adjustment) => {
lineItemAdjustmentsToCreate.push({
item_id: itemId,
version,
amount: adjustment.amount,
description: adjustment.description,
promotion_id: adjustment.promotion_id,
code: adjustment.code,
is_tax_inclusive: adjustment.is_tax_inclusive,
})
})
}
itemsToUpsert.push(itemToUpsert) itemsToUpsert.push(itemToUpsert)
} }
@@ -157,11 +173,12 @@ export async function applyChangesToOrder(
} }
// Including tax lines and adjustments for added items and shipping methods // Including tax lines and adjustments for added items and shipping methods
if (options?.includeTaxLinesAndAdjustementsToPreview) { if (options?.includeTaxLinesAndAdjustmentsToPreview) {
await options?.includeTaxLinesAndAdjustementsToPreview( await options?.includeTaxLinesAndAdjustmentsToPreview(
calculated.order, calculated.order,
itemsToUpsert, itemsToUpsert,
shippingMethodsToUpsert shippingMethodsToUpsert,
lineItemAdjustmentsToCreate
) )
decorateCartTotals(calculated.order) decorateCartTotals(calculated.order)
} }
@@ -194,6 +211,7 @@ export async function applyChangesToOrder(
} }
return { return {
lineItemAdjustmentsToCreate,
itemsToUpsert, itemsToUpsert,
creditLinesToUpsert, creditLinesToUpsert,
shippingMethodsToUpsert, shippingMethodsToUpsert,
@@ -1,7 +1,8 @@
import { Constructor, Context, DAL } from "@medusajs/framework/types" import { Constructor, Context, DAL } from "@medusajs/framework/types"
import { toMikroORMEntity } from "@medusajs/framework/utils" import { toMikroORMEntity } from "@medusajs/framework/utils"
import { LoadStrategy } from "@medusajs/framework/mikro-orm/core" import { LoadStrategy } from "@medusajs/framework/mikro-orm/core"
import { Order, OrderClaim } from "@models" import { Order, OrderClaim, OrderLineItemAdjustment } from "@models"
import { mapRepositoryToOrderModel } from "." import { mapRepositoryToOrderModel } from "."
export function setFindMethods<T>(klass: Constructor<T>, entity: any) { export function setFindMethods<T>(klass: Constructor<T>, entity: any) {
@@ -76,13 +77,43 @@ export function setFindMethods<T>(klass: Constructor<T>, entity: any) {
configurePopulateWhere(config, isRelatedEntity, version) configurePopulateWhere(config, isRelatedEntity, version)
let loadAdjustments = false
if (config.options.populate.includes("items.item.adjustments")) {
// TODO: handle if populate is an object
loadAdjustments = true
config.options.populate.splice(
config.options.populate.indexOf("items.item.adjustments"),
1
)
config.options.populate.push("items")
config.options.populate.push("items.item")
// make sure version is loaded if adjustments are requested
if (config.options.fields?.some((f) => f.includes("items.item."))) {
config.options.fields.push(
isRelatedEntity ? "order.items.version" : "items.version"
)
}
}
if (!config.options.orderBy) { if (!config.options.orderBy) {
config.options.orderBy = { id: "ASC" } config.options.orderBy = { id: "ASC" }
} }
config.where ??= {} config.where ??= {}
return await manager.find(this.entity, config.where, config.options) const result = await manager.find(this.entity, config.where, config.options)
if (loadAdjustments) {
const orders = !isRelatedEntity
? [...result]
: [...result].map((r) => r.order).filter(Boolean)
await loadItemAdjustments(manager, orders)
}
return result
} }
klass.prototype.findAndCount = async function findAndCount( klass.prototype.findAndCount = async function findAndCount(
@@ -136,6 +167,25 @@ export function setFindMethods<T>(klass: Constructor<T>, entity: any) {
const version = config.where.version ?? defaultVersion const version = config.where.version ?? defaultVersion
delete config.where.version delete config.where.version
let loadAdjustments = false
if (config.options.populate.includes("items.item.adjustments")) {
loadAdjustments = true
config.options.populate.splice(
config.options.populate.indexOf("items.item.adjustments"),
1
)
config.options.populate.push("items")
config.options.populate.push("items.item")
// make sure version is loaded if adjustments are requested
if (config.options.fields?.some((f) => f.includes("items.item."))) {
config.options.fields.push(
isRelatedEntity ? "order.items.version" : "items.version"
)
}
}
configurePopulateWhere( configurePopulateWhere(
config, config,
isRelatedEntity, isRelatedEntity,
@@ -148,7 +198,57 @@ export function setFindMethods<T>(klass: Constructor<T>, entity: any) {
config.options.orderBy = { id: "ASC" } config.options.orderBy = { id: "ASC" }
} }
return await manager.findAndCount(this.entity, config.where, config.options) const [result, count] = await manager.findAndCount(
this.entity,
config.where,
config.options
)
if (loadAdjustments) {
const orders = !isRelatedEntity
? [...result]
: [...result].map((r) => r.order).filter(Boolean)
await loadItemAdjustments(manager, orders)
}
return [result, count]
}
}
/**
* Load adjustment for the lates items/order version
* @param manager MikroORM manager
* @param orders Orders to load adjustments for
*/
async function loadItemAdjustments(manager, orders) {
const items = orders.flatMap((r) => [...(r.items ?? [])])
const itemsIdMap = new Map<string, any>(items.map((i) => [i.item.id, i.item]))
const params = items.map((i) => {
// preinitialise all items so an empty array is returned for ones without adjustments
if (!i.item.adjustments.isInitialized()) {
i.item.adjustments.initialized = true
}
if (!i.version) {
throw new Error("Item version is required to load adjustments")
}
return {
item_id: i.item.id,
version: i.version,
}
})
const adjustments = await manager.find(OrderLineItemAdjustment, {
$or: params,
})
for (const adjustment of adjustments) {
const item = itemsIdMap.get(adjustment.item_id)
if (item) {
item.adjustments.add(adjustment)
}
} }
} }
@@ -228,6 +228,8 @@ export class OrderChangeProcessing {
public getSummaryFromOrder(order: OrderDTO): OrderSummaryDTO { public getSummaryFromOrder(order: OrderDTO): OrderSummaryDTO {
const summary_ = this.summary const summary_ = this.summary
const total = order.total const total = order.total
// const pendingDifference = MathBN.sub(total, summary_.transaction_total)
const orderSummary = { const orderSummary = {
transaction_total: new BigNumber(summary_.transaction_total), transaction_total: new BigNumber(summary_.transaction_total),
original_order_total: new BigNumber(summary_.original_order_total), original_order_total: new BigNumber(summary_.original_order_total),
@@ -725,6 +725,7 @@ export default class PromotionModuleService
action: ComputedActions.REMOVE_ITEM_ADJUSTMENT, action: ComputedActions.REMOVE_ITEM_ADJUSTMENT,
adjustment_id: adjustment.id, adjustment_id: adjustment.id,
code, code,
item_id: adjustment.item_id as string,
}) })
} }
@@ -733,11 +734,12 @@ export default class PromotionModuleService
action: ComputedActions.REMOVE_SHIPPING_METHOD_ADJUSTMENT, action: ComputedActions.REMOVE_SHIPPING_METHOD_ADJUSTMENT,
adjustment_id: adjustment.id, adjustment_id: adjustment.id,
code, code,
shipping_method_id: adjustment.shipping_method_id as string,
}) })
} }
} }
const promotionCodeSet = new Set<string>(promotionCodes) const promotionCodeSet = new Set<string>(promotionCodes) // TODO: uniquePromotionCodes
const automaticPromotionCodeSet = new Set<string>(automaticPromotionCodes) const automaticPromotionCodeSet = new Set<string>(automaticPromotionCodes)
const sortedPromotionsToApply = promotions const sortedPromotionsToApply = promotions
+2 -2
View File
@@ -3584,7 +3584,7 @@ __metadata:
"@medusajs/workflows-sdk": 2.11.3 "@medusajs/workflows-sdk": 2.11.3
"@types/express": ^4.17.21 "@types/express": ^4.17.21
chokidar: ^3.5.3 chokidar: ^3.5.3
compression: ^1.8.0 compression: ^1.8.1
connect-redis: 5.2.0 connect-redis: 5.2.0
cookie-parser: ^1.4.6 cookie-parser: ^1.4.6
cors: ^2.8.5 cors: ^2.8.5
@@ -14563,7 +14563,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"compression@npm:^1.8.0": "compression@npm:^1.8.0, compression@npm:^1.8.1":
version: 1.8.1 version: 1.8.1
resolution: "compression@npm:1.8.1" resolution: "compression@npm:1.8.1"
dependencies: dependencies: