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:
60 files changed
+3271
-233
No files matched your search
@@ -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,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -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
-14
@@ -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,
|
||||||
|
|||||||
+213
@@ -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"
|
||||||
|
|||||||
+6
-1
@@ -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,
|
||||||
|
|||||||
+4
-6
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-6
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+11
-6
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+4
-18
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-6
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-6
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-10
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -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 }) => {
|
||||||
|
|||||||
+20
-1
@@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+163
@@ -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" })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
+19
-26
@@ -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))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+22
-4
@@ -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))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+9
-4
@@ -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))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
+11
@@ -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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in new issue
Block a user