fix(core-flows): Avoid checking inventory items on fulfillment cancel for unmanaged inventory variants (#14177)
* Avoid checking existent inventory item on fulfillment cancellation for variants without managed inventory * Add changeset * Dismiss existent variant inventory links when updating to unmanaged inventory * Update input type and step name * Dismiss inventory when variant is updated to unmanaged inventory * Review changes * Fix * Fix * Comments * Include Map to avoid iterating unnecessarily
This commit is contained in:
@@ -160,7 +160,9 @@ function prepareCancelOrderFulfillmentData({
|
||||
(i) => i.id === lineItemId
|
||||
) as OrderItemWithVariantDTO
|
||||
// find inventory items
|
||||
const iitems = orderItem!.variant?.inventory_items
|
||||
const iitems = orderItem!.variant?.manage_inventory
|
||||
? orderItem!.variant?.inventory_items
|
||||
: undefined
|
||||
// find fulfillment item
|
||||
const fitem = fulfillment.items.find(
|
||||
(i) => i.line_item_id === lineItemId
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
import { ContainerRegistrationKeys, Modules } from "@medusajs/framework/utils"
|
||||
import { Link, Query } from "@medusajs/framework/modules-sdk"
|
||||
import { LinkDefinition } from "@medusajs/types"
|
||||
|
||||
export const dismissProductVariantsInventoryStepId =
|
||||
"dismiss-product-variants-inventory"
|
||||
|
||||
export type DismissProductVariantsInventoryStepInput = {
|
||||
variantIds: string[]
|
||||
}
|
||||
|
||||
async function dismissVariantsInventory(
|
||||
variantIds: string[],
|
||||
query: Query,
|
||||
link: Link
|
||||
): Promise<Record<string, string[]>> {
|
||||
const dismissedVariantInventoryItems: Record<string, string[]> = {}
|
||||
if (!variantIds.length) {
|
||||
return dismissedVariantInventoryItems
|
||||
}
|
||||
|
||||
const { data: variantInventoryItems } = await query.graph({
|
||||
entity: "product_variant_inventory_item",
|
||||
fields: ["inventory_item_id", "variant_id"],
|
||||
filters: {
|
||||
variant_id: variantIds,
|
||||
},
|
||||
})
|
||||
|
||||
const variantInventoryItemsMap = new Map<string, string[]>()
|
||||
for (const item of variantInventoryItems) {
|
||||
variantInventoryItemsMap.set(item.variant_id, [
|
||||
...(variantInventoryItemsMap.get(item.variant_id) ?? []),
|
||||
item.inventory_item_id,
|
||||
])
|
||||
}
|
||||
|
||||
const dismissLinks: LinkDefinition[] = []
|
||||
for (const variantId of variantIds) {
|
||||
if (!variantId) {
|
||||
continue
|
||||
}
|
||||
|
||||
dismissedVariantInventoryItems[variantId] =
|
||||
variantInventoryItemsMap.get(variantId) ?? []
|
||||
|
||||
for (const inventoryItemId of variantInventoryItemsMap.get(variantId) ??
|
||||
[]) {
|
||||
dismissLinks.push({
|
||||
[Modules.PRODUCT]: { variant_id: variantId },
|
||||
[Modules.INVENTORY]: { inventory_item_id: inventoryItemId },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
await link.dismiss(dismissLinks)
|
||||
|
||||
return dismissedVariantInventoryItems
|
||||
}
|
||||
|
||||
export const dismissProductVariantsInventoryStep = createStep(
|
||||
dismissProductVariantsInventoryStepId,
|
||||
async (data: DismissProductVariantsInventoryStepInput, { container }) => {
|
||||
const query = container.resolve(ContainerRegistrationKeys.QUERY)
|
||||
const link = container.resolve(ContainerRegistrationKeys.LINK)
|
||||
const variantIds = data.variantIds || []
|
||||
|
||||
if (!variantIds.length) {
|
||||
return new StepResponse(void 0)
|
||||
}
|
||||
|
||||
const dismissedVariantInventoryItems = await dismissVariantsInventory(
|
||||
variantIds,
|
||||
query as Query,
|
||||
link
|
||||
)
|
||||
return new StepResponse(void 0, dismissedVariantInventoryItems)
|
||||
},
|
||||
async (dismissedVariantInventoryItems, { container }) => {
|
||||
if (!dismissedVariantInventoryItems) {
|
||||
return
|
||||
}
|
||||
|
||||
const linksToCreate: LinkDefinition[] = []
|
||||
for (const [variantId, inventoryItemIds] of Object.entries(
|
||||
dismissedVariantInventoryItems
|
||||
)) {
|
||||
for (const inventoryItemId of inventoryItemIds) {
|
||||
linksToCreate.push({
|
||||
[Modules.PRODUCT]: { variant_id: variantId },
|
||||
[Modules.INVENTORY]: { inventory_item_id: inventoryItemId },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const link = container.resolve(ContainerRegistrationKeys.LINK)
|
||||
await link.create(linksToCreate)
|
||||
}
|
||||
)
|
||||
@@ -32,3 +32,4 @@ export * from "./get-variant-availability"
|
||||
export * from "./normalize-products"
|
||||
export * from "./normalize-products-to-chunks"
|
||||
export * from "./process-import-chunks"
|
||||
export * from "./dismiss-product-variants-inventory"
|
||||
|
||||
@@ -13,7 +13,10 @@ import {
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { emitEventStep } from "../../common"
|
||||
import { updatePriceSetsStep } from "../../pricing"
|
||||
import { updateProductVariantsStep } from "../steps"
|
||||
import {
|
||||
dismissProductVariantsInventoryStep,
|
||||
updateProductVariantsStep,
|
||||
} from "../steps"
|
||||
import { getVariantPricingLinkStep } from "../steps/get-variant-pricing-link"
|
||||
|
||||
/**
|
||||
@@ -57,12 +60,12 @@ export const updateProductVariantsWorkflowId = "update-product-variants"
|
||||
* allows you to update custom data models linked to the product variants.
|
||||
*
|
||||
* You can also use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around product-variant update.
|
||||
*
|
||||
*
|
||||
* :::note
|
||||
*
|
||||
* Learn more about adding rules to the product variant's prices in the Pricing Module's
|
||||
*
|
||||
* Learn more about adding rules to the product variant's prices in the Pricing Module's
|
||||
* [Price Rules](https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules) documentation.
|
||||
*
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* @example
|
||||
@@ -151,6 +154,32 @@ export const updateProductVariantsWorkflow = createWorkflow(
|
||||
|
||||
const updatedVariants = updateProductVariantsStep(updateWithoutPrices)
|
||||
|
||||
const variantsToDismissInventory = transform(
|
||||
{ input, updatedVariants },
|
||||
(data) => {
|
||||
const variantIds: string[] = []
|
||||
|
||||
if ("product_variants" in data.input) {
|
||||
for (const variant of data.input.product_variants) {
|
||||
if (variant.id && variant.manage_inventory === false) {
|
||||
variantIds.push(variant.id)
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
data.input.update &&
|
||||
data.input.update?.manage_inventory === false
|
||||
) {
|
||||
variantIds.push(...data.updatedVariants.map((v) => v.id))
|
||||
}
|
||||
|
||||
return variantIds
|
||||
}
|
||||
)
|
||||
|
||||
dismissProductVariantsInventoryStep({
|
||||
variantIds: variantsToDismissInventory,
|
||||
})
|
||||
|
||||
// We don't want to do any pricing updates if the prices didn't change
|
||||
const variantIds = transform({ input, updatedVariants }, (data) => {
|
||||
if ("product_variants" in data.input) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
useRemoteQueryStep,
|
||||
} from "../../common"
|
||||
import { upsertVariantPricesWorkflow } from "./upsert-variant-prices"
|
||||
import { dismissProductVariantsInventoryStep } from "../steps/dismiss-product-variants-inventory"
|
||||
|
||||
/**
|
||||
* Update products that match a specified selector, along with custom data that's passed to the workflow's hooks.
|
||||
@@ -444,6 +445,35 @@ export const updateProductsWorkflow = createWorkflow(
|
||||
const toUpdateInput = transform({ input }, prepareUpdateProductInput)
|
||||
const updatedProducts = updateProductsStep(toUpdateInput)
|
||||
|
||||
const variantsToDismissInventory = transform(
|
||||
{ input, updatedProducts },
|
||||
(data) => {
|
||||
const variantIds: string[] = []
|
||||
|
||||
if ("products" in data.input) {
|
||||
for (const product of data.input.products) {
|
||||
for (const variant of product.variants ?? []) {
|
||||
if (variant.id && variant.manage_inventory === false) {
|
||||
variantIds.push(variant.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (data.input.update?.variants?.length) {
|
||||
for (const variant of data.input.update.variants) {
|
||||
if (variant.id && variant.manage_inventory === false) {
|
||||
variantIds.push(variant.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return variantIds
|
||||
}
|
||||
)
|
||||
|
||||
dismissProductVariantsInventoryStep({
|
||||
variantIds: variantsToDismissInventory,
|
||||
})
|
||||
|
||||
const salesChannelLinks = transform(
|
||||
{ input, updatedProducts },
|
||||
prepareSalesChannelLinks
|
||||
|
||||
Reference in New Issue
Block a user