Chore(core-flows,order): exchange/claim add item (#8126)
This commit is contained in:
committed by
GitHub
parent
5bb870948a
commit
8d530aa7f2
@@ -361,7 +361,7 @@ medusaIntegrationTestRunner({
|
||||
it("should begin a claim order", async () => {
|
||||
const order = await createOrderFixture({ container, product })
|
||||
|
||||
const createClaimOrderData: OrderWorkflow.beginOrderClaimWorkflowInput =
|
||||
const createClaimOrderData: OrderWorkflow.BeginOrderClaimWorkflowInput =
|
||||
{
|
||||
type: ClaimType.REFUND,
|
||||
order_id: order.id,
|
||||
@@ -425,8 +425,6 @@ medusaIntegrationTestRunner({
|
||||
action: "RETURN_ITEM",
|
||||
details: expect.objectContaining({
|
||||
quantity: 1,
|
||||
return_id: expect.stringContaining("return_"),
|
||||
claim_id: claimOrder.id,
|
||||
reference_id: order.items![0].id,
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
beginExchangeOrderWorkflow,
|
||||
createShippingOptionsWorkflow,
|
||||
orderExchangeAddNewItemWorkflow,
|
||||
orderExchangeRequestItemReturnWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import {
|
||||
@@ -9,7 +10,10 @@ import {
|
||||
IStockLocationService,
|
||||
OrderWorkflow,
|
||||
ProductDTO,
|
||||
RegionDTO,
|
||||
SalesChannelDTO,
|
||||
StockLocationDTO,
|
||||
UserDTO,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
@@ -38,6 +42,12 @@ async function prepareDataFixtures({ container }) {
|
||||
const productModule = container.resolve(ModuleRegistrationName.PRODUCT)
|
||||
const pricingModule = container.resolve(ModuleRegistrationName.PRICING)
|
||||
const inventoryModule = container.resolve(ModuleRegistrationName.INVENTORY)
|
||||
const customerService = container.resolve(ModuleRegistrationName.CUSTOMER)
|
||||
|
||||
const customer = await customerService.createCustomers({
|
||||
first_name: "joe",
|
||||
email: "joe@gmail.com",
|
||||
})
|
||||
|
||||
const shippingProfile = await fulfillmentService.createShippingProfiles({
|
||||
name: "test",
|
||||
@@ -96,17 +106,44 @@ async function prepareDataFixtures({ container }) {
|
||||
title: "Test variant",
|
||||
sku: "test-variant",
|
||||
},
|
||||
{
|
||||
title: "another product variant",
|
||||
sku: "another-variant",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
const inventoryItem = await inventoryModule.createInventoryItems({
|
||||
sku: "inv-1234",
|
||||
})
|
||||
const priceSets = await pricingModule.createPriceSets([
|
||||
{
|
||||
prices: [
|
||||
{
|
||||
amount: 45.987,
|
||||
region_id: region.id,
|
||||
currency_code: "eur",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
const inventoryItems = await inventoryModule.createInventoryItems([
|
||||
{
|
||||
sku: "inv-1234",
|
||||
},
|
||||
{
|
||||
sku: "another-inv-987",
|
||||
},
|
||||
])
|
||||
|
||||
await inventoryModule.createInventoryLevels([
|
||||
{
|
||||
inventory_item_id: inventoryItem.id,
|
||||
inventory_item_id: inventoryItems[0].id,
|
||||
location_id: location.id,
|
||||
stocked_quantity: 2,
|
||||
reserved_quantity: 0,
|
||||
},
|
||||
{
|
||||
inventory_item_id: inventoryItems[1].id,
|
||||
location_id: location.id,
|
||||
stocked_quantity: 2,
|
||||
reserved_quantity: 0,
|
||||
@@ -137,17 +174,28 @@ async function prepareDataFixtures({ container }) {
|
||||
variant_id: product.variants[0].id,
|
||||
},
|
||||
[Modules.INVENTORY]: {
|
||||
inventory_item_id: inventoryItem.id,
|
||||
inventory_item_id: inventoryItems[0].id,
|
||||
},
|
||||
},
|
||||
{
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product.variants[1].id,
|
||||
},
|
||||
[Modules.INVENTORY]: {
|
||||
inventory_item_id: inventoryItems[1].id,
|
||||
},
|
||||
},
|
||||
{
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product.variants[1].id,
|
||||
},
|
||||
[Modules.PRICING]: {
|
||||
price_set_id: priceSets[0].id,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
await pricingModule.createPricePreferences([
|
||||
{
|
||||
attribute: "currency_code",
|
||||
value: "usd",
|
||||
is_tax_inclusive: true,
|
||||
},
|
||||
{
|
||||
attribute: "region_id",
|
||||
value: region.id,
|
||||
@@ -223,13 +271,20 @@ async function prepareDataFixtures({ container }) {
|
||||
location,
|
||||
product,
|
||||
fulfillmentSet,
|
||||
customer,
|
||||
}
|
||||
}
|
||||
|
||||
async function createOrderFixture({ container, product }) {
|
||||
async function createOrderFixture({
|
||||
container,
|
||||
product,
|
||||
salesChannel,
|
||||
customer,
|
||||
region,
|
||||
}) {
|
||||
const orderService = container.resolve(ModuleRegistrationName.ORDER)
|
||||
let order = await orderService.createOrders({
|
||||
region_id: "test_region_id",
|
||||
region_id: region.id,
|
||||
email: "foo@bar.com",
|
||||
items: [
|
||||
{
|
||||
@@ -249,7 +304,7 @@ async function createOrderFixture({ container, product }) {
|
||||
],
|
||||
} as any,
|
||||
],
|
||||
sales_channel_id: "test",
|
||||
sales_channel_id: salesChannel.id,
|
||||
shipping_address: {
|
||||
first_name: "Test",
|
||||
last_name: "Test",
|
||||
@@ -290,8 +345,8 @@ async function createOrderFixture({ container, product }) {
|
||||
],
|
||||
},
|
||||
],
|
||||
currency_code: "usd",
|
||||
customer_id: "joe",
|
||||
currency_code: "eur",
|
||||
customer_id: customer.id,
|
||||
})
|
||||
|
||||
await orderService.addOrderAction([
|
||||
@@ -339,6 +394,9 @@ medusaIntegrationTestRunner({
|
||||
|
||||
describe("Begin exchange order workflow", () => {
|
||||
let product: ProductDTO
|
||||
let salesChannel: SalesChannelDTO
|
||||
let customer: UserDTO
|
||||
let region: RegionDTO
|
||||
|
||||
beforeEach(async () => {
|
||||
const fixtures = await prepareDataFixtures({
|
||||
@@ -346,12 +404,21 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
product = fixtures.product
|
||||
salesChannel = fixtures.salesChannel
|
||||
customer = fixtures.customer
|
||||
region = fixtures.region
|
||||
})
|
||||
|
||||
it("should begin an exchange order, request item return", async () => {
|
||||
const order = await createOrderFixture({ container, product })
|
||||
const order = await createOrderFixture({
|
||||
container,
|
||||
product,
|
||||
salesChannel,
|
||||
customer,
|
||||
region,
|
||||
})
|
||||
|
||||
const createExchangeOrderData: OrderWorkflow.beginOrderExchangeWorkflowInput =
|
||||
const createExchangeOrderData: OrderWorkflow.BeginOrderExchangeWorkflowInput =
|
||||
{
|
||||
order_id: order.id,
|
||||
metadata: {
|
||||
@@ -423,8 +490,6 @@ medusaIntegrationTestRunner({
|
||||
action: "RETURN_ITEM",
|
||||
details: expect.objectContaining({
|
||||
quantity: 1,
|
||||
return_id: expect.stringContaining("return_"),
|
||||
exchange_id: exchangeOrder.id,
|
||||
reference_id: order.items![0].id,
|
||||
}),
|
||||
}),
|
||||
@@ -490,6 +555,34 @@ medusaIntegrationTestRunner({
|
||||
],
|
||||
})
|
||||
)
|
||||
|
||||
const { result: addItemPreview } =
|
||||
await orderExchangeAddNewItemWorkflow.run({
|
||||
container,
|
||||
input: {
|
||||
exchange_id: exchangeOrder.id,
|
||||
items: [
|
||||
{
|
||||
variant_id: product.variants[1].id,
|
||||
quantity: 2,
|
||||
unit_price: 14.786,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(addItemPreview.items).toHaveLength(2)
|
||||
expect(addItemPreview.items[1].actions).toEqual([
|
||||
expect.objectContaining({
|
||||
action: "ITEM_ADD",
|
||||
reference: "order_exchange",
|
||||
reference_id: exchangeOrder.id,
|
||||
details: expect.objectContaining({
|
||||
quantity: 2,
|
||||
unit_price: 14.786,
|
||||
}),
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -359,7 +359,7 @@ medusaIntegrationTestRunner({
|
||||
it("should begin a return order", async () => {
|
||||
const order = await createOrderFixture({ container, product })
|
||||
|
||||
const createReturnOrderData: OrderWorkflow.beginOrderReturnWorkflowInput =
|
||||
const createReturnOrderData: OrderWorkflow.BeginOrderReturnWorkflowInput =
|
||||
{
|
||||
order_id: order.id,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { CreateOrderLineItemDTO } from "@medusajs/types"
|
||||
import { ModuleRegistrationName } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
interface StepInput {
|
||||
items: CreateOrderLineItemDTO[]
|
||||
}
|
||||
|
||||
export const createOrderLineItemsStepId = "create-line-items-step"
|
||||
export const createOrderLineItemsStep = createStep(
|
||||
createOrderLineItemsStepId,
|
||||
async (input: StepInput, { container }) => {
|
||||
const orderModule = container.resolve(ModuleRegistrationName.ORDER)
|
||||
|
||||
const createdItems = input.items.length
|
||||
? await orderModule.createLineItems(input.items)
|
||||
: []
|
||||
|
||||
return new StepResponse(
|
||||
createdItems,
|
||||
createdItems.map((c) => c.id)
|
||||
)
|
||||
},
|
||||
async (itemIds, { container }) => {
|
||||
if (!itemIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const orderModule = container.resolve(ModuleRegistrationName.ORDER)
|
||||
|
||||
await orderModule.deleteLineItems(itemIds)
|
||||
}
|
||||
)
|
||||
@@ -8,6 +8,7 @@ export * from "./complete-orders"
|
||||
export * from "./create-claims"
|
||||
export * from "./create-complete-return"
|
||||
export * from "./create-exchanges"
|
||||
export * from "./create-line-items"
|
||||
export * from "./create-order-change"
|
||||
export * from "./create-order-change-actions"
|
||||
export * from "./create-orders"
|
||||
|
||||
148
packages/core/core-flows/src/order/workflows/add-line-items.ts
Normal file
148
packages/core/core-flows/src/order/workflows/add-line-items.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { OrderLineItemDTO, OrderWorkflow } from "@medusajs/types"
|
||||
import { MathBN, MedusaError } from "@medusajs/utils"
|
||||
import {
|
||||
WorkflowData,
|
||||
createWorkflow,
|
||||
parallelize,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { useRemoteQueryStep } from "../../common"
|
||||
import { findOneOrAnyRegionStep } from "../../definition/cart/steps/find-one-or-any-region"
|
||||
import { findOrCreateCustomerStep } from "../../definition/cart/steps/find-or-create-customer"
|
||||
import { findSalesChannelStep } from "../../definition/cart/steps/find-sales-channel"
|
||||
import { getVariantPriceSetsStep } from "../../definition/cart/steps/get-variant-price-sets"
|
||||
import { validateVariantPricesStep } from "../../definition/cart/steps/validate-variant-prices"
|
||||
import { prepareLineItemData } from "../../definition/cart/utils/prepare-line-item-data"
|
||||
import { confirmVariantInventoryWorkflow } from "../../definition/cart/workflows/confirm-variant-inventory"
|
||||
import { createOrderLineItemsStep } from "../steps"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
import { prepareCustomLineItemData } from "../utils/prepare-custom-line-item-data"
|
||||
|
||||
function prepareLineItems(data) {
|
||||
const items = (data.input.items ?? []).map((item) => {
|
||||
const variant = data.variants.find((v) => v.id === item.variant_id)!
|
||||
|
||||
if (!variant) {
|
||||
return prepareCustomLineItemData({
|
||||
variant: {
|
||||
...item,
|
||||
},
|
||||
unitPrice: MathBN.max(0, item.unit_price),
|
||||
isTaxInclusive: item.is_tax_inclusive,
|
||||
quantity: item.quantity as number,
|
||||
metadata: item?.metadata ?? {},
|
||||
})
|
||||
}
|
||||
|
||||
return prepareLineItemData({
|
||||
variant: variant,
|
||||
unitPrice: MathBN.max(
|
||||
0,
|
||||
item.unit_price ??
|
||||
data.priceSets[item.variant_id!]?.raw_calculated_amount
|
||||
),
|
||||
isTaxInclusive:
|
||||
item.is_tax_inclusive ??
|
||||
data.priceSets[item.variant_id!]?.is_calculated_price_tax_inclusive,
|
||||
quantity: item.quantity as number,
|
||||
metadata: item?.metadata ?? {},
|
||||
taxLines: item.tax_lines || [],
|
||||
adjustments: item.adjustments || [],
|
||||
})
|
||||
})
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
export const addOrderLineItemsWorkflowId = "order-add-line-items"
|
||||
export const addOrderLineItemsWorkflow = createWorkflow(
|
||||
addOrderLineItemsWorkflowId,
|
||||
(
|
||||
input: WorkflowData<OrderWorkflow.OrderAddLineItemWorkflowInput>
|
||||
): WorkflowData<OrderLineItemDTO[]> => {
|
||||
const order = useRemoteQueryStep({
|
||||
entry_point: "orders",
|
||||
fields: [
|
||||
"id",
|
||||
"sales_channel_id",
|
||||
"region_id",
|
||||
"customer_id",
|
||||
"email",
|
||||
"currency_code",
|
||||
],
|
||||
variables: { id: input.order_id },
|
||||
list: false,
|
||||
throw_if_key_not_found: true,
|
||||
}).config({ name: "order-query" })
|
||||
|
||||
const variantIds = transform({ input }, (data) => {
|
||||
return (data.input.items ?? [])
|
||||
.map((item) => item.variant_id)
|
||||
.filter(Boolean) as string[]
|
||||
})
|
||||
|
||||
const [salesChannel, region, customerData] = parallelize(
|
||||
findSalesChannelStep({
|
||||
salesChannelId: order.sales_channel_id,
|
||||
}),
|
||||
findOneOrAnyRegionStep({
|
||||
regionId: order.region_id,
|
||||
}),
|
||||
findOrCreateCustomerStep({
|
||||
customerId: order.customer_id,
|
||||
email: order.email,
|
||||
})
|
||||
)
|
||||
|
||||
const pricingContext = transform(
|
||||
{ input, region, customerData, order },
|
||||
(data) => {
|
||||
if (!data.region) {
|
||||
throw new MedusaError(MedusaError.Types.NOT_FOUND, "Region not found")
|
||||
}
|
||||
|
||||
return {
|
||||
currency_code: data.order.currency_code ?? data.region.currency_code,
|
||||
region_id: data.region.id,
|
||||
customer_id: data.customerData.customer?.id,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const variants = useRemoteQueryStep({
|
||||
entry_point: "variants",
|
||||
fields: productVariantsFields,
|
||||
variables: {
|
||||
id: variantIds,
|
||||
calculated_price: {
|
||||
context: pricingContext,
|
||||
},
|
||||
},
|
||||
throw_if_key_not_found: true,
|
||||
}).config({ name: "variants-query" })
|
||||
|
||||
validateVariantPricesStep({ variants })
|
||||
|
||||
confirmVariantInventoryWorkflow.runAsStep({
|
||||
input: {
|
||||
sales_channel_id: salesChannel.id,
|
||||
variants,
|
||||
items: input.items!,
|
||||
},
|
||||
})
|
||||
|
||||
const priceSets = getVariantPriceSetsStep({
|
||||
variantIds,
|
||||
context: pricingContext,
|
||||
})
|
||||
|
||||
const lineItems = transform(
|
||||
{ priceSets, input, variants },
|
||||
prepareLineItems
|
||||
)
|
||||
|
||||
return createOrderLineItemsStep({
|
||||
items: lineItems,
|
||||
})
|
||||
}
|
||||
)
|
||||
@@ -21,7 +21,7 @@ export const beginClaimOrderWorkflowId = "begin-claim-order"
|
||||
export const beginClaimOrderWorkflow = createWorkflow(
|
||||
beginClaimOrderWorkflowId,
|
||||
function (
|
||||
input: WorkflowData<OrderWorkflow.beginOrderClaimWorkflowInput>
|
||||
input: WorkflowData<OrderWorkflow.BeginOrderClaimWorkflowInput>
|
||||
): WorkflowData<OrderChangeDTO> {
|
||||
const order: OrderDTO = useRemoteQueryStep({
|
||||
entry_point: "orders",
|
||||
|
||||
@@ -21,7 +21,7 @@ export const beginExchangeOrderWorkflowId = "begin-exchange-order"
|
||||
export const beginExchangeOrderWorkflow = createWorkflow(
|
||||
beginExchangeOrderWorkflowId,
|
||||
function (
|
||||
input: WorkflowData<OrderWorkflow.beginOrderExchangeWorkflowInput>
|
||||
input: WorkflowData<OrderWorkflow.BeginOrderExchangeWorkflowInput>
|
||||
): WorkflowData<OrderChangeDTO> {
|
||||
const order: OrderDTO = useRemoteQueryStep({
|
||||
entry_point: "orders",
|
||||
|
||||
@@ -21,7 +21,7 @@ export const beginReturnOrderWorkflowId = "begin-return-order"
|
||||
export const beginReturnOrderWorkflow = createWorkflow(
|
||||
beginReturnOrderWorkflowId,
|
||||
function (
|
||||
input: WorkflowData<OrderWorkflow.beginOrderReturnWorkflowInput>
|
||||
input: WorkflowData<OrderWorkflow.BeginOrderReturnWorkflowInput>
|
||||
): WorkflowData<OrderChangeDTO> {
|
||||
const order: OrderDTO = useRemoteQueryStep({
|
||||
entry_point: "orders",
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
OrderChangeDTO,
|
||||
OrderClaimDTO,
|
||||
OrderDTO,
|
||||
OrderWorkflow,
|
||||
} from "@medusajs/types"
|
||||
import { ChangeActionType } from "@medusajs/utils"
|
||||
import {
|
||||
WorkflowData,
|
||||
createStep,
|
||||
createWorkflow,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { useRemoteQueryStep } from "../../common"
|
||||
import { createOrderChangeActionsStep } from "../steps/create-order-change-actions"
|
||||
import { previewOrderChangeStep } from "../steps/preview-order-change"
|
||||
import {
|
||||
throwIfIsCancelled,
|
||||
throwIfOrderChangeIsNotActive,
|
||||
throwIfOrderIsCancelled,
|
||||
} from "../utils/order-validation"
|
||||
import { addOrderLineItemsWorkflow } from "./add-line-items"
|
||||
|
||||
const validationStep = createStep(
|
||||
"claim-add-new-item-validation",
|
||||
async function ({
|
||||
order,
|
||||
orderChange,
|
||||
orderClaim,
|
||||
}: {
|
||||
order: OrderDTO
|
||||
orderClaim: OrderClaimDTO
|
||||
orderChange: OrderChangeDTO
|
||||
}) {
|
||||
throwIfOrderIsCancelled({ order })
|
||||
throwIfIsCancelled(orderClaim, "Claim")
|
||||
throwIfOrderChangeIsNotActive({ orderChange })
|
||||
}
|
||||
)
|
||||
|
||||
export const orderClaimAddNewItemWorkflowId = "claim-add-new-item"
|
||||
export const orderClaimAddNewItemWorkflow = createWorkflow(
|
||||
orderClaimAddNewItemWorkflowId,
|
||||
function (
|
||||
input: WorkflowData<OrderWorkflow.OrderClaimAddNewItemWorkflowInput>
|
||||
): WorkflowData<OrderDTO> {
|
||||
const orderClaim = useRemoteQueryStep({
|
||||
entry_point: "order_claim",
|
||||
fields: ["id", "order_id"],
|
||||
variables: { id: input.claim_id },
|
||||
list: false,
|
||||
throw_if_key_not_found: true,
|
||||
}).config({ name: "claim-query" })
|
||||
|
||||
const order: OrderDTO = useRemoteQueryStep({
|
||||
entry_point: "orders",
|
||||
fields: ["id", "status", "items.*"],
|
||||
variables: { id: orderClaim.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"],
|
||||
variables: { order_id: orderClaim.order_id },
|
||||
list: false,
|
||||
}).config({ name: "order-change-query" })
|
||||
|
||||
validationStep({
|
||||
order,
|
||||
orderClaim,
|
||||
orderChange,
|
||||
})
|
||||
|
||||
const lineItems = addOrderLineItemsWorkflow.runAsStep({
|
||||
input: {
|
||||
order_id: order.id,
|
||||
items: input.items,
|
||||
},
|
||||
})
|
||||
|
||||
const orderChangeActionInput = transform(
|
||||
{ order, orderChange, orderClaim, items: input.items, lineItems },
|
||||
({ order, orderChange, orderClaim, items, lineItems }) => {
|
||||
return items.map((item, index) => ({
|
||||
order_change_id: orderChange.id,
|
||||
order_id: order.id,
|
||||
claim_id: orderClaim.id,
|
||||
version: orderChange.version,
|
||||
action: ChangeActionType.ITEM_ADD,
|
||||
internal_note: item.internal_note,
|
||||
reference: "order_claim",
|
||||
reference_id: orderClaim.id,
|
||||
details: {
|
||||
reference_id: lineItems[index].id,
|
||||
quantity: item.quantity,
|
||||
unit_price: item.unit_price,
|
||||
metadata: item.metadata,
|
||||
},
|
||||
}))
|
||||
}
|
||||
)
|
||||
|
||||
createOrderChangeActionsStep(orderChangeActionInput)
|
||||
|
||||
return previewOrderChangeStep(orderClaim.order_id)
|
||||
}
|
||||
)
|
||||
@@ -147,8 +147,6 @@ export const orderClaimRequestItemReturnWorkflow = createWorkflow(
|
||||
reference_id: orderReturn.id,
|
||||
details: {
|
||||
reference_id: item.id,
|
||||
claim_id: orderClaim.id,
|
||||
return_id: orderReturn.id,
|
||||
quantity: item.quantity,
|
||||
metadata: item.metadata,
|
||||
},
|
||||
|
||||
@@ -38,7 +38,8 @@ function prepareLineItems(data) {
|
||||
variant: variant,
|
||||
unitPrice: MathBN.max(
|
||||
0,
|
||||
item.unit_price ?? data.priceSets[item.variant_id!]?.calculated_amount
|
||||
item.unit_price ??
|
||||
data.priceSets[item.variant_id!]?.raw_calculated_amount
|
||||
),
|
||||
isTaxInclusive:
|
||||
item.is_tax_inclusive ??
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
OrderChangeDTO,
|
||||
OrderDTO,
|
||||
OrderExchangeDTO,
|
||||
OrderWorkflow,
|
||||
} from "@medusajs/types"
|
||||
import { ChangeActionType } from "@medusajs/utils"
|
||||
import {
|
||||
WorkflowData,
|
||||
createStep,
|
||||
createWorkflow,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { useRemoteQueryStep } from "../../common"
|
||||
import { createOrderChangeActionsStep } from "../steps/create-order-change-actions"
|
||||
import { previewOrderChangeStep } from "../steps/preview-order-change"
|
||||
import {
|
||||
throwIfIsCancelled,
|
||||
throwIfOrderChangeIsNotActive,
|
||||
throwIfOrderIsCancelled,
|
||||
} from "../utils/order-validation"
|
||||
import { addOrderLineItemsWorkflow } from "./add-line-items"
|
||||
|
||||
const validationStep = createStep(
|
||||
"exchange-add-new-item-validation",
|
||||
async function ({
|
||||
order,
|
||||
orderChange,
|
||||
orderExchange,
|
||||
}: {
|
||||
order: OrderDTO
|
||||
orderExchange: OrderExchangeDTO
|
||||
orderChange: OrderChangeDTO
|
||||
}) {
|
||||
throwIfOrderIsCancelled({ order })
|
||||
throwIfIsCancelled(orderExchange, "Exchange")
|
||||
throwIfOrderChangeIsNotActive({ orderChange })
|
||||
}
|
||||
)
|
||||
|
||||
export const orderExchangeAddNewItemWorkflowId = "exchange-add-new-item"
|
||||
export const orderExchangeAddNewItemWorkflow = createWorkflow(
|
||||
orderExchangeAddNewItemWorkflowId,
|
||||
function (
|
||||
input: WorkflowData<OrderWorkflow.OrderExchangeAddNewItemWorkflowInput>
|
||||
): WorkflowData<OrderDTO> {
|
||||
const orderExchange = useRemoteQueryStep({
|
||||
entry_point: "order_exchange",
|
||||
fields: ["id", "order_id"],
|
||||
variables: { id: input.exchange_id },
|
||||
list: false,
|
||||
throw_if_key_not_found: true,
|
||||
}).config({ name: "exchange-query" })
|
||||
|
||||
const order: OrderDTO = useRemoteQueryStep({
|
||||
entry_point: "orders",
|
||||
fields: ["id", "status", "items.*"],
|
||||
variables: { id: orderExchange.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"],
|
||||
variables: { order_id: orderExchange.order_id },
|
||||
list: false,
|
||||
}).config({ name: "order-change-query" })
|
||||
|
||||
validationStep({
|
||||
order,
|
||||
orderExchange,
|
||||
orderChange,
|
||||
})
|
||||
|
||||
const lineItems = addOrderLineItemsWorkflow.runAsStep({
|
||||
input: {
|
||||
order_id: order.id,
|
||||
items: input.items,
|
||||
},
|
||||
})
|
||||
|
||||
const orderChangeActionInput = transform(
|
||||
{ order, orderChange, orderExchange, items: input.items, lineItems },
|
||||
({ order, orderChange, orderExchange, items, lineItems }) => {
|
||||
return items.map((item, index) => ({
|
||||
order_change_id: orderChange.id,
|
||||
order_id: order.id,
|
||||
exchange_id: orderExchange.id,
|
||||
version: orderChange.version,
|
||||
action: ChangeActionType.ITEM_ADD,
|
||||
internal_note: item.internal_note,
|
||||
reference: "order_exchange",
|
||||
reference_id: orderExchange.id,
|
||||
details: {
|
||||
reference_id: lineItems[index].id,
|
||||
quantity: item.quantity,
|
||||
unit_price: item.unit_price,
|
||||
metadata: item.metadata,
|
||||
},
|
||||
}))
|
||||
}
|
||||
)
|
||||
|
||||
createOrderChangeActionsStep(orderChangeActionInput)
|
||||
|
||||
return previewOrderChangeStep(orderExchange.order_id)
|
||||
}
|
||||
)
|
||||
@@ -148,8 +148,6 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow(
|
||||
reference_id: orderReturn.id,
|
||||
details: {
|
||||
reference_id: item.id,
|
||||
exchange_id: orderExchange.id,
|
||||
return_id: orderReturn.id,
|
||||
quantity: item.quantity,
|
||||
metadata: item.metadata,
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./add-line-items"
|
||||
export * from "./archive-orders"
|
||||
export * from "./begin-order-claim"
|
||||
export * from "./begin-order-exchange"
|
||||
@@ -18,6 +19,7 @@ export * from "./create-shipment"
|
||||
export * from "./decline-order-change"
|
||||
export * from "./delete-order-change"
|
||||
export * from "./delete-order-change-actions"
|
||||
export * from "./exchange-add-new-item"
|
||||
export * from "./exchange-request-item-return"
|
||||
export * from "./get-order-detail"
|
||||
export * from "./get-orders-list"
|
||||
|
||||
@@ -50,7 +50,6 @@ import {
|
||||
CreateOrderDTO,
|
||||
CreateOrderExchangeDTO,
|
||||
CreateOrderLineItemDTO,
|
||||
CreateOrderLineItemForOrderDTO,
|
||||
CreateOrderLineItemTaxLineDTO,
|
||||
CreateOrderReturnDTO,
|
||||
CreateOrderReturnReasonDTO,
|
||||
@@ -559,12 +558,8 @@ export interface IOrderModuleService extends IModuleService {
|
||||
sharedContext?: Context
|
||||
): Promise<OrderLineItemDTO[]>
|
||||
|
||||
createLineItems(
|
||||
data: CreateOrderLineItemForOrderDTO
|
||||
): Promise<OrderLineItemDTO[]>
|
||||
createLineItems(
|
||||
data: CreateOrderLineItemForOrderDTO[]
|
||||
): Promise<OrderLineItemDTO[]>
|
||||
createLineItems(data: CreateOrderLineItemDTO): Promise<OrderLineItemDTO[]>
|
||||
createLineItems(data: CreateOrderLineItemDTO[]): Promise<OrderLineItemDTO[]>
|
||||
createLineItems(
|
||||
orderId: string,
|
||||
items: CreateOrderLineItemDTO[],
|
||||
|
||||
34
packages/core/types/src/workflow/order/add-new-item.ts
Normal file
34
packages/core/types/src/workflow/order/add-new-item.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { BigNumberInput } from "../../totals"
|
||||
|
||||
export interface OrderExchangeAddNewItemWorkflowInput {
|
||||
exchange_id: string
|
||||
items: {
|
||||
variant_id: string
|
||||
quantity: BigNumberInput
|
||||
unit_price?: BigNumberInput
|
||||
internal_note?: string
|
||||
metadata?: Record<string, any> | null
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface OrderClaimAddNewItemWorkflowInput {
|
||||
claim_id: string
|
||||
items: {
|
||||
variant_id: string
|
||||
quantity: BigNumberInput
|
||||
unit_price?: BigNumberInput
|
||||
internal_note?: string
|
||||
metadata?: Record<string, any> | null
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface OrderAddLineItemWorkflowInput {
|
||||
order_id: string
|
||||
items: {
|
||||
variant_id: string
|
||||
quantity: BigNumberInput
|
||||
unit_price?: BigNumberInput
|
||||
internal_note?: string
|
||||
metadata?: Record<string, any> | null
|
||||
}[]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { OrderClaimType } from "../../order/mutations"
|
||||
|
||||
export interface beginOrderClaimWorkflowInput {
|
||||
export interface BeginOrderClaimWorkflowInput {
|
||||
type: OrderClaimType
|
||||
order_id: string
|
||||
created_by?: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface beginOrderExchangeWorkflowInput {
|
||||
export interface BeginOrderExchangeWorkflowInput {
|
||||
order_id: string
|
||||
created_by?: string
|
||||
internal_note?: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface beginOrderReturnWorkflowInput {
|
||||
export interface BeginOrderReturnWorkflowInput {
|
||||
order_id: string
|
||||
created_by?: string
|
||||
internal_note?: string
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./add-new-item"
|
||||
export * from "./begin-claim-order"
|
||||
export * from "./begin-exchange-order"
|
||||
export * from "./begin-return-order"
|
||||
|
||||
@@ -171,7 +171,6 @@ describe("Order Exchange - Actions", function () {
|
||||
id: "item_555",
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
detail: {},
|
||||
actions: [
|
||||
{
|
||||
action: "ITEM_ADD",
|
||||
@@ -194,7 +193,6 @@ describe("Order Exchange - Actions", function () {
|
||||
{
|
||||
id: "shipping_345",
|
||||
price: 5,
|
||||
detail: {},
|
||||
actions: [
|
||||
{
|
||||
action: "SHIPPING_ADD",
|
||||
@@ -206,7 +204,6 @@ describe("Order Exchange - Actions", function () {
|
||||
{
|
||||
id: "return_shipping_345",
|
||||
price: 7.5,
|
||||
detail: {},
|
||||
actions: [
|
||||
{
|
||||
action: "SHIPPING_ADD",
|
||||
|
||||
@@ -1969,18 +1969,57 @@ export default class OrderModuleService<
|
||||
}
|
||||
})
|
||||
|
||||
const calculated = calculateOrderChange({
|
||||
order: order as any,
|
||||
actions: orderChange.actions,
|
||||
transactions: order.transactions ?? [],
|
||||
options: {
|
||||
addActionReferenceToObject: true,
|
||||
},
|
||||
})
|
||||
const { itemsToUpsert, shippingMethodsToUpsert, calculatedOrders } =
|
||||
applyChangesToOrder(
|
||||
[order],
|
||||
{ [order.id]: orderChange.actions },
|
||||
{ addActionReferenceToObject: true }
|
||||
)
|
||||
|
||||
createRawPropertiesFromBigNumber(calculated)
|
||||
const calculated = calculatedOrders[order.id]
|
||||
|
||||
const addedItems = {}
|
||||
for (const item of calculated.order.items) {
|
||||
const isExistingItem = item.id === item.detail?.item_id
|
||||
|
||||
if (!isExistingItem) {
|
||||
addedItems[item.id] = item
|
||||
}
|
||||
}
|
||||
if (Object.keys(addedItems).length > 0) {
|
||||
const addedItemDetails = await this.listLineItems(
|
||||
{ id: Object.keys(addedItems) },
|
||||
{
|
||||
relations: ["adjustments", "tax_lines"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
calculated.order.items.forEach((item, idx) => {
|
||||
if (addedItems[item.id]) {
|
||||
const lineItem = addedItemDetails.find((d) => d.id === item.id) as any
|
||||
|
||||
const actions = item.actions
|
||||
delete item.actions
|
||||
|
||||
const newItem = itemsToUpsert.find((d) => d.item_id === item.id)!
|
||||
calculated.order.items[idx] = {
|
||||
...lineItem,
|
||||
actions,
|
||||
quantity: newItem.quantity,
|
||||
detail: {
|
||||
...newItem,
|
||||
...item,
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TODO - add new shipping methods
|
||||
|
||||
const calcOrder = calculated.order
|
||||
|
||||
const calcOrder = calculated.order as any
|
||||
decorateCartTotals(calcOrder as DecorateCartLikeInputDTO)
|
||||
calcOrder.summary = calculated.summary
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_ADD, {
|
||||
existing = {
|
||||
id: action.details.reference_id!,
|
||||
order_id: currentOrder.id,
|
||||
return_id: action.details.return_id,
|
||||
claim_id: action.details.claim_id,
|
||||
exchange_id: action.details.exchange_id,
|
||||
return_id: action.return_id,
|
||||
claim_id: action.claim_id,
|
||||
exchange_id: action.exchange_id,
|
||||
|
||||
unit_price: action.details.unit_price,
|
||||
quantity: action.details.quantity,
|
||||
|
||||
@@ -12,22 +12,29 @@ export interface ApplyOrderChangeDTO extends OrderChangeActionDTO {
|
||||
|
||||
export function applyChangesToOrder(
|
||||
orders: any[],
|
||||
actionsMap: Record<string, any[]>
|
||||
actionsMap: Record<string, any[]>,
|
||||
options?: {
|
||||
addActionReferenceToObject?: boolean
|
||||
}
|
||||
) {
|
||||
const itemsToUpsert: OrderItem[] = []
|
||||
const shippingMethodsToUpsert: OrderShippingMethod[] = []
|
||||
const summariesToUpsert: any[] = []
|
||||
const orderToUpdate: any[] = []
|
||||
|
||||
const calculatedOrders = {}
|
||||
for (const order of orders) {
|
||||
const calculated = calculateOrderChange({
|
||||
order: order as any,
|
||||
actions: actionsMap[order.id],
|
||||
transactions: order.transactions ?? [],
|
||||
options,
|
||||
})
|
||||
|
||||
createRawPropertiesFromBigNumber(calculated)
|
||||
|
||||
calculatedOrders[order.id] = calculated
|
||||
|
||||
const version = actionsMap[order.id][0].version ?? 1
|
||||
|
||||
for (const item of calculated.order.items) {
|
||||
@@ -41,11 +48,11 @@ export function applyChangesToOrder(
|
||||
order_id: order.id,
|
||||
version,
|
||||
quantity: orderItem.quantity,
|
||||
fulfilled_quantity: orderItem.fulfilled_quantity,
|
||||
shipped_quantity: orderItem.shipped_quantity,
|
||||
return_requested_quantity: orderItem.return_requested_quantity,
|
||||
return_received_quantity: orderItem.return_received_quantity,
|
||||
return_dismissed_quantity: orderItem.return_dismissed_quantity,
|
||||
fulfilled_quantity: orderItem.fulfilled_quantity ?? 0,
|
||||
shipped_quantity: orderItem.shipped_quantity ?? 0,
|
||||
return_requested_quantity: orderItem.return_requested_quantity ?? 0,
|
||||
return_received_quantity: orderItem.return_received_quantity ?? 0,
|
||||
return_dismissed_quantity: orderItem.return_dismissed_quantity ?? 0,
|
||||
written_off_quantity: orderItem.written_off_quantity,
|
||||
metadata: orderItem.metadata,
|
||||
} as OrderItem)
|
||||
@@ -90,5 +97,6 @@ export function applyChangesToOrder(
|
||||
shippingMethodsToUpsert,
|
||||
summariesToUpsert,
|
||||
orderToUpdate,
|
||||
calculatedOrders,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
export function setActionReference(existing, action, options) {
|
||||
existing.detail ??= {}
|
||||
|
||||
existing.detail.order_id ??= action.order_id
|
||||
existing.detail.return_id ??= action.return_id
|
||||
existing.detail.claim_id ??= action.claim_id
|
||||
existing.detail.exchange_id ??= action.exchange_id
|
||||
|
||||
if (options?.addActionReferenceToObject) {
|
||||
existing.actions ??= []
|
||||
existing.actions.push(action)
|
||||
|
||||
@@ -33,6 +33,11 @@ export function formatOrder(
|
||||
}
|
||||
|
||||
mainOrder.items = mainOrder.items?.map((orderItem) => {
|
||||
const isFormatted = isDefined(orderItem.detail?.fulfilled_quantity)
|
||||
if (isFormatted) {
|
||||
return orderItem
|
||||
}
|
||||
|
||||
const detail = { ...orderItem }
|
||||
delete detail.order
|
||||
delete detail.item
|
||||
@@ -62,6 +67,10 @@ export function formatOrder(
|
||||
|
||||
if (order.shipping_methods) {
|
||||
order.shipping_methods = order.shipping_methods?.map((shippingMethod) => {
|
||||
if (shippingMethod.detail) {
|
||||
return shippingMethod
|
||||
}
|
||||
|
||||
const sm = { ...shippingMethod.shipping_method }
|
||||
|
||||
delete shippingMethod.shipping_method
|
||||
|
||||
Reference in New Issue
Block a user