fix(core-flows, types): reservation of shared inventory item (#11403)
**What** - if a cart contains variants that share inventory items, reservation of the item would fail also causing complete cart to fail - include `completed_at` when compensating cart update - account for multiple reservations of the same item when creating the locking key --- CLOSES SUP-587
This commit is contained in:
@@ -2,7 +2,6 @@ import { MathBN, Modules } from "@medusajs/framework/utils"
|
||||
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
||||
import { BigNumberInput } from "@medusajs/types"
|
||||
|
||||
|
||||
/**
|
||||
* The details of the items and their quantity to reserve.
|
||||
*/
|
||||
@@ -45,7 +44,7 @@ export const reserveInventoryStepId = "reserve-inventory-step"
|
||||
/**
|
||||
* This step reserves the quantity of line items from the associated
|
||||
* variant's inventory.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* const data = reserveInventoryStep({
|
||||
* "items": [{
|
||||
@@ -80,7 +79,9 @@ export const reserveInventoryStep = createStep(
|
||||
}
|
||||
})
|
||||
|
||||
const reservations = await locking.execute(inventoryItemIds, async () => {
|
||||
const lockingKeys = Array.from(new Set(inventoryItemIds))
|
||||
|
||||
const reservations = await locking.execute(lockingKeys, async () => {
|
||||
return await inventoryService.createReservationItems(items)
|
||||
})
|
||||
|
||||
@@ -98,7 +99,9 @@ export const reserveInventoryStep = createStep(
|
||||
const locking = container.resolve(Modules.LOCKING)
|
||||
|
||||
const inventoryItemIds = data.inventoryItemIds
|
||||
await locking.execute(inventoryItemIds, async () => {
|
||||
const lockingKeys = Array.from(new Set(inventoryItemIds))
|
||||
|
||||
await locking.execute(lockingKeys, async () => {
|
||||
await inventoryService.deleteReservationItems(data.reservations)
|
||||
})
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export type UpdateCartsStepInput = UpdateCartWorkflowInputDTO[]
|
||||
export const updateCartsStepId = "update-carts"
|
||||
/**
|
||||
* This step updates a cart.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* const data = updateCartsStep([{
|
||||
* id: "cart_123",
|
||||
@@ -57,6 +57,7 @@ export const updateCartsStep = createStep(
|
||||
email: cart.email,
|
||||
currency_code: cart.currency_code,
|
||||
metadata: cart.metadata,
|
||||
completed_at: cart.completed_at,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -73,8 +73,10 @@ export const prepareConfirmInventoryInput = (data: {
|
||||
|
||||
if (inventory_items) {
|
||||
const inventoryItemId = inventory_items.inventory_item_id
|
||||
if (!productVariantInventoryItems.has(inventoryItemId)) {
|
||||
productVariantInventoryItems.set(inventoryItemId, {
|
||||
const mapKey = `${inventoryItemId}-${inventory_items.variant_id}`
|
||||
|
||||
if (!productVariantInventoryItems.has(mapKey)) {
|
||||
productVariantInventoryItems.set(mapKey, {
|
||||
variant_id: inventory_items.variant_id,
|
||||
inventory_item_id: inventoryItemId,
|
||||
required_quantity: inventory_items.required_quantity,
|
||||
|
||||
@@ -6,14 +6,15 @@ import { MathBN, Modules } from "@medusajs/framework/utils"
|
||||
/**
|
||||
* The data to adjust the inventory levels.
|
||||
*/
|
||||
export type AdjustInventoryLevelsStepInput = InventoryTypes.BulkAdjustInventoryLevelInput[]
|
||||
export type AdjustInventoryLevelsStepInput =
|
||||
InventoryTypes.BulkAdjustInventoryLevelInput[]
|
||||
|
||||
export const adjustInventoryLevelsStepId = "adjust-inventory-levels-step"
|
||||
/**
|
||||
* This step adjusts the stocked quantity of one or more inventory levels. You can
|
||||
* This step adjusts the stocked quantity of one or more inventory levels. You can
|
||||
* pass a positive value in `adjustment` to add to the stocked quantity, or a negative value to
|
||||
* subtract from the stocked quantity.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* const data = adjustInventoryLevelsStep([
|
||||
* {
|
||||
@@ -25,16 +26,15 @@ export const adjustInventoryLevelsStepId = "adjust-inventory-levels-step"
|
||||
*/
|
||||
export const adjustInventoryLevelsStep = createStep(
|
||||
adjustInventoryLevelsStepId,
|
||||
async (
|
||||
input: AdjustInventoryLevelsStepInput,
|
||||
{ container }
|
||||
) => {
|
||||
async (input: AdjustInventoryLevelsStepInput, { container }) => {
|
||||
const inventoryService = container.resolve(Modules.INVENTORY)
|
||||
const locking = container.resolve(Modules.LOCKING)
|
||||
const inventoryItemIds = input.map((item) => item.inventory_item_id)
|
||||
|
||||
const lockingKeys = Array.from(new Set(inventoryItemIds))
|
||||
|
||||
const adjustedLevels: InventoryTypes.InventoryLevelDTO[] =
|
||||
await locking.execute(inventoryItemIds, async () => {
|
||||
await locking.execute(lockingKeys, async () => {
|
||||
return await inventoryService.adjustInventory(
|
||||
input.map((item) => {
|
||||
return {
|
||||
@@ -67,13 +67,15 @@ export const adjustInventoryLevelsStep = createStep(
|
||||
(item) => item.inventory_item_id
|
||||
)
|
||||
|
||||
const lockingKeys = Array.from(new Set(inventoryItemIds))
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* The method "adjustInventory" was broken, it was receiving the
|
||||
* "inventoryItemId" and "locationId" as snake case, whereas
|
||||
* the expected object needed these properties as camelCase
|
||||
*/
|
||||
await locking.execute(inventoryItemIds, async () => {
|
||||
await locking.execute(lockingKeys, async () => {
|
||||
await inventoryService.adjustInventory(
|
||||
adjustedLevels.map((level) => {
|
||||
return {
|
||||
|
||||
@@ -6,12 +6,13 @@ import { Modules } from "@medusajs/framework/utils"
|
||||
/**
|
||||
* The data to create reservation items.
|
||||
*/
|
||||
export type CreateReservationsStepInput = InventoryTypes.CreateReservationItemInput[]
|
||||
export type CreateReservationsStepInput =
|
||||
InventoryTypes.CreateReservationItemInput[]
|
||||
|
||||
export const createReservationsStepId = "create-reservations-step"
|
||||
/**
|
||||
* This step creates one or more reservations.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* const data = createReservationsStep([
|
||||
* {
|
||||
@@ -29,7 +30,9 @@ export const createReservationsStep = createStep(
|
||||
|
||||
const inventoryItemIds = data.map((item) => item.inventory_item_id)
|
||||
|
||||
const created = await locking.execute(inventoryItemIds, async () => {
|
||||
const lockingKeys = Array.from(new Set(inventoryItemIds))
|
||||
|
||||
const created = await locking.execute(lockingKeys, async () => {
|
||||
return await service.createReservationItems(data)
|
||||
})
|
||||
|
||||
@@ -47,7 +50,9 @@ export const createReservationsStep = createStep(
|
||||
const locking = container.resolve(Modules.LOCKING)
|
||||
|
||||
const inventoryItemIds = data.inventoryItemIds
|
||||
await locking.execute(inventoryItemIds, async () => {
|
||||
const lockingKeys = Array.from(new Set(inventoryItemIds))
|
||||
|
||||
await locking.execute(lockingKeys, async () => {
|
||||
await service.deleteReservationItems(data.reservations)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user