feat(): Sync order translations (#14267)
* feat(): Sync order translations * feat(): Sync order translations * tests * Create tender-melons-develop.md * fix tests * cleanup * cleanup
This commit is contained in:
committed by
GitHub
parent
fe314ab5bc
commit
f13c23a4b7
@@ -10,7 +10,6 @@ export * from "./find-or-create-customer"
|
||||
export * from "./find-sales-channel"
|
||||
export * from "./get-actions-to-compute-from-promotions"
|
||||
export * from "./get-line-item-actions"
|
||||
export * from "./get-translated-line-items"
|
||||
export * from "./update-cart-items-translations"
|
||||
export * from "./get-promotion-codes-to-apply"
|
||||
export * from "./get-variant-price-sets"
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Modules,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
import { applyTranslationsToItems } from "../utils/apply-translations-to-items"
|
||||
import { applyTranslationsToItems } from "../../common/utils/apply-translations-to-items"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
|
||||
export interface UpdateCartItemsTranslationsStepInput {
|
||||
|
||||
@@ -53,6 +53,7 @@ export const completeCartFields = [
|
||||
"id",
|
||||
"currency_code",
|
||||
"email",
|
||||
"locale",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"completed_at",
|
||||
|
||||
@@ -17,13 +17,12 @@ import {
|
||||
when,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { useQueryGraphStep } from "../../common"
|
||||
import { getTranslatedLineItemsStep, useQueryGraphStep } from "../../common"
|
||||
import { emitEventStep } from "../../common/steps/emit-event"
|
||||
import { acquireLockStep, releaseLockStep } from "../../locking"
|
||||
import {
|
||||
createLineItemsStep,
|
||||
getLineItemActionsStep,
|
||||
getTranslatedLineItemsStep,
|
||||
updateLineItemsStep,
|
||||
} from "../steps"
|
||||
import { validateCartStep } from "../steps/validate-cart"
|
||||
|
||||
@@ -75,47 +75,47 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* You can use this workflow within your own customizations or custom workflows, allowing you to wrap custom logic around completing a cart.
|
||||
* For example, in the [Subscriptions recipe](https://docs.medusajs.com/resources/recipes/subscriptions/examples/standard#create-workflow),
|
||||
* this workflow is used within another workflow that creates a subscription order.
|
||||
*
|
||||
*
|
||||
* ## Cart Completion Idempotency
|
||||
*
|
||||
*
|
||||
* This workflow's logic is idempotent, meaning that if it is executed multiple times with the same input, it will not create duplicate orders. The
|
||||
* same order will be returned for subsequent executions with the same cart ID. This is necessary to avoid rolling back payments or causing
|
||||
* other side effects if the workflow is retried or fails due to transient errors.
|
||||
*
|
||||
*
|
||||
* So, if you use this workflow within your own, make sure your workflow's steps are idempotent as well to avoid unintended side effects.
|
||||
* Your workflow must also acquire and release locks around this workflow to prevent concurrent executions for the same cart.
|
||||
*
|
||||
*
|
||||
* The following sections cover some common scenarios and how to handle them.
|
||||
*
|
||||
*
|
||||
* ### Creating Links and Linked Records
|
||||
*
|
||||
*
|
||||
* In some cases, you might want to create custom links or linked records to the order. For example, you might want to create a link from the order to a
|
||||
* digital order.
|
||||
*
|
||||
* In such cases, ensure that your workflow's logic checks for existing links or records before creating new ones. You can query the
|
||||
*
|
||||
* In such cases, ensure that your workflow's logic checks for existing links or records before creating new ones. You can query the
|
||||
* [entry point of the link](https://docs.medusajs.com/learn/fundamentals/module-links/custom-columns#method-2-using-entry-point)
|
||||
* to check for existing links before creating new ones.
|
||||
*
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* import {
|
||||
* createWorkflow,
|
||||
* when,
|
||||
* WorkflowResponse
|
||||
* } from "@medusajs/framework/workflows-sdk"
|
||||
* import {
|
||||
* import {
|
||||
* useQueryGraphStep,
|
||||
* completeCartWorkflow,
|
||||
* acquireLockStep,
|
||||
* releaseLockStep
|
||||
* } from "@medusajs/framework/workflows-sdk"
|
||||
* import digitalProductOrderOrderLink from "../../links/digital-product-order"
|
||||
*
|
||||
*
|
||||
* type WorkflowInput = {
|
||||
* cart_id: string
|
||||
* }
|
||||
*
|
||||
*
|
||||
* const createDigitalProductOrderWorkflow = createWorkflow(
|
||||
* "create-digital-product-order",
|
||||
* (input: WorkflowInput) => {
|
||||
@@ -129,14 +129,14 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* id: input.cart_id
|
||||
* }
|
||||
* })
|
||||
*
|
||||
*
|
||||
* const { data: existingLinks } = useQueryGraphStep({
|
||||
* entity: digitalProductOrderOrderLink.entryPoint,
|
||||
* fields: ["digital_product_order.id"],
|
||||
* filters: { order_id: id },
|
||||
* }).config({ name: "retrieve-existing-links" });
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* const digital_product_order = when(
|
||||
* "create-digital-product-order-condition",
|
||||
* { existingLinks },
|
||||
@@ -149,60 +149,60 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* .then(() => {
|
||||
* // create digital product order logic...
|
||||
* })
|
||||
*
|
||||
*
|
||||
* // other workflow logic...
|
||||
*
|
||||
*
|
||||
* releaseLockStep({
|
||||
* key: input.cart_id,
|
||||
* })
|
||||
*
|
||||
*
|
||||
* return new WorkflowResponse({
|
||||
* // workflow output...
|
||||
* })
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Custom Validation with Conflicts
|
||||
*
|
||||
*
|
||||
* Some use cases require custom validation that may cause conflicts on subsequent executions of the workflow.
|
||||
* For example, if you're selling tickets to an event, you might want to validate that the tickets are available
|
||||
* on selected dates.
|
||||
*
|
||||
*
|
||||
* In this scenario, if the workflow is retried after the first execution, the validation
|
||||
* will fail since the tickets would have already been reserved in the first execution. This makes the cart
|
||||
* completion non-idempotent.
|
||||
*
|
||||
*
|
||||
* To handle these cases, you can create a step that throws an error if the validation fails. Then, in the compensation function,
|
||||
* you can cancel the order if the validation fails. For example:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
* import { MedusaError } from "@medusajs/framework/utils"
|
||||
* import { cancelOrderWorkflow } from "@medusajs/medusa/core-flows"
|
||||
*
|
||||
*
|
||||
* type StepInput = {
|
||||
* order_id: string
|
||||
* // other input fields...
|
||||
* }
|
||||
*
|
||||
*
|
||||
* export const customCartValidationStep = createStep(
|
||||
* "custom-cart-validation",
|
||||
* async (input, { container }) => {
|
||||
* const isValid = true // replace with actual validation logic
|
||||
*
|
||||
*
|
||||
* if (!isValid) {
|
||||
* throw new MedusaError(
|
||||
* MedusaError.Types.INVALID_DATA,
|
||||
* "Custom cart validation failed"
|
||||
* )
|
||||
* }
|
||||
*
|
||||
*
|
||||
* return new StepResponse(void 0, input.order_id)
|
||||
* },
|
||||
* async (order_id, { container, context }) => {
|
||||
* if (!order_id) return
|
||||
*
|
||||
*
|
||||
* cancelOrderWorkflow(container).run({
|
||||
* input: {
|
||||
* id: order_id,
|
||||
@@ -213,10 +213,10 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Then, in your custom workflow, only run the validation step if the order is being created for the first time. For example,
|
||||
* only run the validation if the link from the order to your custom data does not exist yet:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* import {
|
||||
* createWorkflow,
|
||||
@@ -225,11 +225,11 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* } from "@medusajs/framework/workflows-sdk"
|
||||
* import { useQueryGraphStep } from "@medusajs/framework/workflows-sdk"
|
||||
* import ticketOrderLink from "../../links/ticket-order"
|
||||
*
|
||||
*
|
||||
* type WorkflowInput = {
|
||||
* cart_id: string
|
||||
* }
|
||||
*
|
||||
*
|
||||
* const createTicketOrderWorkflow = createWorkflow(
|
||||
* "create-ticket-order",
|
||||
* (input: WorkflowInput) => {
|
||||
@@ -243,14 +243,14 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* id: input.cart_id
|
||||
* }
|
||||
* })
|
||||
*
|
||||
*
|
||||
* const { data: existingLinks } = useQueryGraphStep({
|
||||
* entity: ticketOrderLink.entryPoint,
|
||||
* fields: ["ticket.id"],
|
||||
* filters: { order_id: id },
|
||||
* }).config({ name: "retrieve-existing-links" });
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* const ticket_order = when(
|
||||
* "create-ticket-order-condition",
|
||||
* { existingLinks },
|
||||
@@ -264,23 +264,23 @@ export const completeCartWorkflowId = "complete-cart"
|
||||
* customCartValidationStep({ order_id: id })
|
||||
* // create ticket order logic...
|
||||
* })
|
||||
*
|
||||
*
|
||||
* // other workflow logic...
|
||||
*
|
||||
*
|
||||
* releaseLockStep({
|
||||
* key: input.cart_id,
|
||||
* })
|
||||
*
|
||||
*
|
||||
* return new WorkflowResponse({
|
||||
* // workflow output...
|
||||
* })
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* The first time this workflow is executed for a cart, the validation step will run and validate the cart. If the validation fails,
|
||||
* the order will be canceled in the compensation function.
|
||||
*
|
||||
*
|
||||
* If the validation is successful and the workflow is retried, the validation step will be skipped since the link from the order to the
|
||||
* ticket order already exists. This ensures that the workflow remains idempotent.
|
||||
*
|
||||
@@ -472,6 +472,7 @@ export const completeCartWorkflow = createWorkflow(
|
||||
status: OrderStatus.PENDING,
|
||||
email: cart.email,
|
||||
currency_code: cart.currency_code,
|
||||
locale: cart.locale,
|
||||
shipping_address: shippingAddress,
|
||||
billing_address: billingAddress,
|
||||
no_notification: false,
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
findOneOrAnyRegionStep,
|
||||
findOrCreateCustomerStep,
|
||||
findSalesChannelStep,
|
||||
getTranslatedLineItemsStep,
|
||||
} from "../steps"
|
||||
import { validateSalesChannelStep } from "../steps/validate-sales-channel"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
@@ -35,6 +34,7 @@ import { getVariantsAndItemsWithPrices } from "./get-variants-and-items-with-pri
|
||||
import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-collection"
|
||||
import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
|
||||
import { updateTaxLinesWorkflow } from "./update-tax-lines"
|
||||
import { getTranslatedLineItemsStep } from "../../common"
|
||||
|
||||
/**
|
||||
* The data to create the cart, along with custom data that's passed to the workflow's hooks.
|
||||
|
||||
@@ -12,3 +12,4 @@ export * from "./workflows/batch-links"
|
||||
export * from "./workflows/create-links"
|
||||
export * from "./workflows/dismiss-links"
|
||||
export * from "./workflows/update-links"
|
||||
export * from "./steps/get-translated-line-items"
|
||||
|
||||
@@ -10,7 +10,7 @@ import { applyTranslationsToItems } from "../utils/apply-translations-to-items"
|
||||
export interface GetTranslatedLineItemsStepInput<T> {
|
||||
items: T[] | undefined
|
||||
variants: Partial<ProductVariantDTO>[]
|
||||
locale: string | undefined
|
||||
locale: string | null | undefined
|
||||
}
|
||||
|
||||
export const getTranslatedLineItemsStepId = "get-translated-line-items"
|
||||
@@ -1,12 +1,3 @@
|
||||
import { Modules, OrderWorkflowEvents } from "@medusajs/framework/utils"
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
StepResponse,
|
||||
transform,
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
IOrderModuleService,
|
||||
OrderDTO,
|
||||
@@ -14,10 +5,24 @@ import {
|
||||
UpdateOrderDTO,
|
||||
UpsertOrderAddressDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import { Modules, OrderWorkflowEvents } from "@medusajs/framework/utils"
|
||||
import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
StepResponse,
|
||||
transform,
|
||||
when,
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { emitEventStep, useRemoteQueryStep } from "../../common"
|
||||
import { previewOrderChangeStep, registerOrderChangesStep } from "../../order"
|
||||
import { validateDraftOrderStep } from "../steps/validate-draft-order"
|
||||
import { acquireLockStep, releaseLockStep } from "../../locking"
|
||||
import {
|
||||
previewOrderChangeStep,
|
||||
registerOrderChangesStep,
|
||||
updateOrderItemsTranslationsStep,
|
||||
} from "../../order"
|
||||
import { validateDraftOrderStep } from "../steps/validate-draft-order"
|
||||
|
||||
export const updateDraftOrderWorkflowId = "update-draft-order"
|
||||
|
||||
@@ -53,6 +58,11 @@ export interface UpdateDraftOrderWorkflowInput {
|
||||
* The ID of the sales channel to associate the draft order with.
|
||||
*/
|
||||
sales_channel_id?: string
|
||||
/**
|
||||
* The new locale of the draft order. When changed, all line items
|
||||
* will be re-translated to the new locale.
|
||||
*/
|
||||
locale?: string | null
|
||||
/**
|
||||
* The new metadata of the draft order.
|
||||
*/
|
||||
@@ -166,6 +176,7 @@ export const updateDraftOrderWorkflow = createWorkflow(
|
||||
"sales_channel_id",
|
||||
"email",
|
||||
"customer_id",
|
||||
"locale",
|
||||
"shipping_address.*",
|
||||
"billing_address.*",
|
||||
"metadata",
|
||||
@@ -306,12 +317,35 @@ export const updateDraftOrderWorkflow = createWorkflow(
|
||||
})
|
||||
}
|
||||
|
||||
if (!!input.locale && input.locale !== order.locale) {
|
||||
changes.push({
|
||||
change_type: "update_order" as const,
|
||||
order_id: input.id,
|
||||
created_by: input.user_id,
|
||||
confirmed_by: input.user_id,
|
||||
details: {
|
||||
type: "locale",
|
||||
old: order.locale,
|
||||
new: updatedOrder.locale,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
)
|
||||
|
||||
registerOrderChangesStep(orderChangeInput)
|
||||
|
||||
when({ input, order }, ({ input, order }) => {
|
||||
return !!input.locale && input.locale !== order.locale
|
||||
}).then(() => {
|
||||
updateOrderItemsTranslationsStep({
|
||||
order_id: input.id,
|
||||
locale: input.locale!,
|
||||
})
|
||||
})
|
||||
|
||||
emitEventStep({
|
||||
eventName: OrderWorkflowEvents.UPDATED,
|
||||
data: { id: input.id },
|
||||
|
||||
@@ -35,5 +35,6 @@ export * from "./return/update-returns"
|
||||
export * from "./set-tax-lines-for-items"
|
||||
export * from "./update-order-change-actions"
|
||||
export * from "./update-order-changes"
|
||||
export * from "./update-order-items-translations"
|
||||
export * from "./update-orders"
|
||||
export * from "./update-shipping-methods"
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
import { MedusaContainer } from "@medusajs/framework"
|
||||
import {
|
||||
IOrderModuleService,
|
||||
ProductVariantDTO,
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
applyTranslations,
|
||||
ContainerRegistrationKeys,
|
||||
deduplicate,
|
||||
FeatureFlag,
|
||||
Modules,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
import { applyTranslationsToItems } from "../../common/utils/apply-translations-to-items"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
|
||||
export interface UpdateOrderItemsTranslationsStepInput {
|
||||
order_id: string
|
||||
locale: string
|
||||
/**
|
||||
* Pre-loaded items to avoid re-fetching.
|
||||
*/
|
||||
items?: { id: string; variant_id?: string; [key: string]: any }[]
|
||||
}
|
||||
|
||||
const BATCH_SIZE = 100
|
||||
|
||||
const lineItemFields = [
|
||||
"id",
|
||||
"variant_id",
|
||||
"product_id",
|
||||
"title",
|
||||
"subtitle",
|
||||
"product_title",
|
||||
"product_description",
|
||||
"product_subtitle",
|
||||
"product_type",
|
||||
"product_collection",
|
||||
"product_handle",
|
||||
"variant_title",
|
||||
]
|
||||
|
||||
export const updateOrderItemsTranslationsStepId =
|
||||
"update-order-items-translations"
|
||||
|
||||
type ItemTranslationSnapshot = {
|
||||
id: string
|
||||
title: string
|
||||
subtitle: string
|
||||
product_title: string
|
||||
product_description: string
|
||||
product_subtitle: string
|
||||
product_type: string
|
||||
product_collection: string
|
||||
product_handle: string
|
||||
variant_title: string
|
||||
}
|
||||
|
||||
async function compensation(
|
||||
originalItems: ItemTranslationSnapshot[] | undefined,
|
||||
{ container }: { container: MedusaContainer }
|
||||
) {
|
||||
if (!originalItems?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const orderModule = container.resolve<IOrderModuleService>(Modules.ORDER)
|
||||
|
||||
for (let i = 0; i < originalItems.length; i += BATCH_SIZE) {
|
||||
const batch = originalItems.slice(i, i + BATCH_SIZE)
|
||||
await orderModule.updateOrderLineItems(
|
||||
batch.map((item) => ({
|
||||
selector: { id: item.id },
|
||||
data: {
|
||||
title: item.title,
|
||||
subtitle: item.subtitle,
|
||||
product_title: item.product_title,
|
||||
product_description: item.product_description,
|
||||
product_subtitle: item.product_subtitle,
|
||||
product_type: item.product_type,
|
||||
product_collection: item.product_collection,
|
||||
product_handle: item.product_handle,
|
||||
variant_title: item.variant_title,
|
||||
},
|
||||
}))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This step re-translates all order line items when the order's locale changes.
|
||||
* It fetches items and their variants in batches to handle large orders gracefully.
|
||||
*/
|
||||
export const updateOrderItemsTranslationsStep = createStep(
|
||||
updateOrderItemsTranslationsStepId,
|
||||
async (data: UpdateOrderItemsTranslationsStepInput, { container }) => {
|
||||
const originalItems: ItemTranslationSnapshot[] = []
|
||||
try {
|
||||
const isTranslationEnabled = FeatureFlag.isFeatureEnabled("translation")
|
||||
|
||||
if (!isTranslationEnabled || !data.locale) {
|
||||
return new StepResponse(void 0, [])
|
||||
}
|
||||
|
||||
const orderModule = container.resolve<IOrderModuleService>(Modules.ORDER)
|
||||
const query = container.resolve<RemoteQueryFunction>(
|
||||
ContainerRegistrationKeys.QUERY
|
||||
)
|
||||
|
||||
const processBatch = async (
|
||||
items: { id: string; variant_id?: string; [key: string]: any }[]
|
||||
) => {
|
||||
const variantIds = deduplicate(
|
||||
items
|
||||
.map((item) => item.variant_id)
|
||||
.filter((id): id is string => !!id)
|
||||
)
|
||||
|
||||
if (variantIds.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Store original values before updating
|
||||
for (const item of items) {
|
||||
originalItems.push({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
subtitle: item.subtitle,
|
||||
product_title: item.product_title,
|
||||
product_description: item.product_description,
|
||||
product_subtitle: item.product_subtitle,
|
||||
product_type: item.product_type,
|
||||
product_collection: item.product_collection,
|
||||
product_handle: item.product_handle,
|
||||
variant_title: item.variant_title,
|
||||
})
|
||||
}
|
||||
|
||||
const { data: variants } = await query.graph({
|
||||
entity: "variants",
|
||||
filters: { id: variantIds },
|
||||
fields: productVariantsFields,
|
||||
})
|
||||
|
||||
await applyTranslations({
|
||||
localeCode: data.locale,
|
||||
objects: variants as Record<string, any>[],
|
||||
container,
|
||||
})
|
||||
|
||||
const translatedItems = applyTranslationsToItems(
|
||||
items as { variant_id?: string; [key: string]: any }[],
|
||||
variants as Partial<ProductVariantDTO>[]
|
||||
)
|
||||
|
||||
const itemsToUpdate = translatedItems
|
||||
.filter((item) => item.id)
|
||||
.map((item) => ({
|
||||
selector: { id: item.id },
|
||||
data: {
|
||||
title: item.title,
|
||||
subtitle: item.subtitle,
|
||||
product_title: item.product_title,
|
||||
product_description: item.product_description,
|
||||
product_subtitle: item.product_subtitle,
|
||||
product_type: item.product_type,
|
||||
product_collection: item.product_collection,
|
||||
product_handle: item.product_handle,
|
||||
variant_title: item.variant_title,
|
||||
},
|
||||
}))
|
||||
|
||||
if (itemsToUpdate.length > 0) {
|
||||
await orderModule.updateOrderLineItems(itemsToUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.items?.length) {
|
||||
await processBatch(data.items)
|
||||
return new StepResponse(void 0, originalItems)
|
||||
}
|
||||
|
||||
const { data: orders } = await query.graph({
|
||||
entity: "orders",
|
||||
filters: { id: data.order_id },
|
||||
fields: lineItemFields.map((f) => `items.${f}`),
|
||||
})
|
||||
|
||||
const orderData = orders[0] as {
|
||||
items?: { id: string; variant_id?: string }[]
|
||||
}
|
||||
const items = orderData?.items ?? []
|
||||
|
||||
// Process items in batches
|
||||
for (let i = 0; i < items.length; i += BATCH_SIZE) {
|
||||
const batch = items.slice(i, i + BATCH_SIZE)
|
||||
await processBatch(batch)
|
||||
}
|
||||
|
||||
return new StepResponse(void 0, originalItems)
|
||||
} catch (error) {
|
||||
await compensation(originalItems, { container })
|
||||
throw error
|
||||
}
|
||||
},
|
||||
compensation
|
||||
)
|
||||
@@ -21,7 +21,7 @@ import { requiredVariantFieldsForInventoryConfirmation } from "../../cart/utils/
|
||||
import { pricingContextResult } from "../../cart/utils/schemas"
|
||||
import { confirmVariantInventoryWorkflow } from "../../cart/workflows/confirm-variant-inventory"
|
||||
import { getVariantsAndItemsWithPrices } from "../../cart/workflows/get-variants-and-items-with-prices"
|
||||
import { useQueryGraphStep } from "../../common"
|
||||
import { getTranslatedLineItemsStep, useQueryGraphStep } from "../../common"
|
||||
import { createOrderLineItemsStep } from "../steps"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
|
||||
@@ -108,6 +108,7 @@ export const addOrderLineItemsWorkflow = createWorkflow(
|
||||
"customer_id",
|
||||
"email",
|
||||
"currency_code",
|
||||
"locale",
|
||||
],
|
||||
options: { throwIfKeyNotFound: true, isList: false },
|
||||
}).config({ name: "order-query" })
|
||||
@@ -176,9 +177,15 @@ export const addOrderLineItemsWorkflow = createWorkflow(
|
||||
})
|
||||
})
|
||||
|
||||
const translatedItems = getTranslatedLineItemsStep({
|
||||
items,
|
||||
variants,
|
||||
locale: order.locale,
|
||||
})
|
||||
|
||||
return new WorkflowResponse(
|
||||
createOrderLineItemsStep({
|
||||
items: items,
|
||||
items: translatedItems,
|
||||
}) satisfies OrderAddLineItemWorkflowOutput,
|
||||
{
|
||||
hooks: [setPricingContext] as const,
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import type { OrderDTO, OrderWorkflow } from "@medusajs/framework/types"
|
||||
import {
|
||||
OrderPreviewDTO,
|
||||
RegisterOrderChangeDTO,
|
||||
UpdateOrderDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
MedusaError,
|
||||
OrderWorkflowEvents,
|
||||
@@ -10,17 +15,14 @@ import {
|
||||
createStep,
|
||||
createWorkflow,
|
||||
transform,
|
||||
when,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
OrderPreviewDTO,
|
||||
RegisterOrderChangeDTO,
|
||||
UpdateOrderDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
|
||||
import { emitEventStep, useQueryGraphStep } from "../../common"
|
||||
import {
|
||||
previewOrderChangeStep,
|
||||
registerOrderChangesStep,
|
||||
updateOrderItemsTranslationsStep,
|
||||
updateOrdersStep,
|
||||
} from "../steps"
|
||||
import { throwIfOrderIsCancelled } from "../utils/order-validation"
|
||||
@@ -128,6 +130,7 @@ export const updateOrderWorkflow = createWorkflow(
|
||||
"id",
|
||||
"status",
|
||||
"email",
|
||||
"locale",
|
||||
"shipping_address.*",
|
||||
"billing_address.*",
|
||||
"metadata",
|
||||
@@ -235,12 +238,35 @@ export const updateOrderWorkflow = createWorkflow(
|
||||
})
|
||||
}
|
||||
|
||||
if (!!input.locale && input.locale !== order.locale) {
|
||||
changes.push({
|
||||
change_type: "update_order" as const,
|
||||
order_id: input.id,
|
||||
created_by: input.user_id,
|
||||
confirmed_by: input.user_id,
|
||||
details: {
|
||||
type: "locale",
|
||||
old: order.locale,
|
||||
new: input.locale,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
)
|
||||
|
||||
registerOrderChangesStep(orderChangeInput)
|
||||
|
||||
when("locale-changed", { input, order }, ({ input, order }) => {
|
||||
return !!input.locale && input.locale !== order.locale
|
||||
}).then(() => {
|
||||
updateOrderItemsTranslationsStep({
|
||||
order_id: input.id,
|
||||
locale: input.locale!,
|
||||
})
|
||||
})
|
||||
|
||||
emitEventStep({
|
||||
eventName: OrderWorkflowEvents.UPDATED,
|
||||
data: { id: input.id },
|
||||
|
||||
Reference in New Issue
Block a user