chore: complete cart part 2 (#7227)
This commit is contained in:
@@ -415,10 +415,12 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
expect(errors).toEqual([
|
expect(errors).toEqual([
|
||||||
{
|
{
|
||||||
action: "confirm-inventory-step",
|
action: "confirm-item-inventory-as-step",
|
||||||
handlerType: "invoke",
|
handlerType: "invoke",
|
||||||
error: expect.objectContaining({
|
error: expect.objectContaining({
|
||||||
message: "Some variant does not have the required inventory",
|
message: expect.stringContaining(
|
||||||
|
"Some variant does not have the required inventory"
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -707,10 +709,13 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
expect(errors).toEqual([
|
expect(errors).toEqual([
|
||||||
{
|
{
|
||||||
action: "confirm-inventory-step",
|
action: "confirm-item-inventory-as-step",
|
||||||
handlerType: "invoke",
|
handlerType: "invoke",
|
||||||
error: expect.objectContaining({
|
error: expect.objectContaining({
|
||||||
message: `Variants with IDs ${product.variants[0].id} do not have a price`,
|
// TODO: FIX runAsStep nested errors
|
||||||
|
message: expect.stringContaining(
|
||||||
|
`Variants with IDs ${product.variants[0].id} do not have a price`
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /store/carts", () => {
|
describe("POST /store/carts", () => {
|
||||||
it.skip("should create a cart", async () => {
|
it("should create a cart", async () => {
|
||||||
const region = await regionModule.create({
|
const region = await regionModule.create({
|
||||||
name: "US",
|
name: "US",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ interface StepInput {
|
|||||||
items: {
|
items: {
|
||||||
inventory_item_id: string
|
inventory_item_id: string
|
||||||
required_quantity: number
|
required_quantity: number
|
||||||
|
allow_backorder: boolean
|
||||||
quantity: number
|
quantity: number
|
||||||
location_ids: string[]
|
location_ids: string[]
|
||||||
}[]
|
}[]
|
||||||
@@ -23,6 +24,10 @@ export const confirmInventoryStep = createStep(
|
|||||||
|
|
||||||
// TODO: Should be bulk
|
// TODO: Should be bulk
|
||||||
const promises = data.items.map(async (item) => {
|
const promises = data.items.map(async (item) => {
|
||||||
|
if (item.allow_backorder) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
const itemQuantity = item.required_quantity * item.quantity
|
const itemQuantity = item.required_quantity * item.quantity
|
||||||
|
|
||||||
return await inventoryService.confirmInventory(
|
return await inventoryService.confirmInventory(
|
||||||
|
|||||||
@@ -37,6 +37,26 @@ export const completeCartFields = [
|
|||||||
"original_shipping_tax_total",
|
"original_shipping_tax_total",
|
||||||
"original_shipping_tax_subtotal",
|
"original_shipping_tax_subtotal",
|
||||||
"original_shipping_total",
|
"original_shipping_total",
|
||||||
|
"raw_total",
|
||||||
|
"raw_subtotal",
|
||||||
|
"raw_tax_total",
|
||||||
|
"raw_discount_total",
|
||||||
|
"raw_discount_tax_total",
|
||||||
|
"raw_original_total",
|
||||||
|
"raw_original_tax_total",
|
||||||
|
"raw_item_total",
|
||||||
|
"raw_item_subtotal",
|
||||||
|
"raw_item_tax_total",
|
||||||
|
"raw_sales_channel_id",
|
||||||
|
"raw_original_item_total",
|
||||||
|
"raw_original_item_subtotal",
|
||||||
|
"raw_original_item_tax_total",
|
||||||
|
"raw_shipping_total",
|
||||||
|
"raw_shipping_subtotal",
|
||||||
|
"raw_shipping_tax_total",
|
||||||
|
"raw_original_shipping_tax_total",
|
||||||
|
"raw_original_shipping_tax_subtotal",
|
||||||
|
"raw_original_shipping_total",
|
||||||
"items.*",
|
"items.*",
|
||||||
"items.tax_lines.*",
|
"items.tax_lines.*",
|
||||||
"items.adjustments.*",
|
"items.adjustments.*",
|
||||||
@@ -49,4 +69,37 @@ export const completeCartFields = [
|
|||||||
"region.*",
|
"region.*",
|
||||||
"payment_collection.*",
|
"payment_collection.*",
|
||||||
"payment_collection.payment_sessions.*",
|
"payment_collection.payment_sessions.*",
|
||||||
|
"items.variant.id",
|
||||||
|
"items.variant.manage_inventory",
|
||||||
|
"items.variant.allow_backorder",
|
||||||
|
"items.variant.inventory_items.inventory_item_id",
|
||||||
|
"items.variant.inventory_items.required_quantity",
|
||||||
|
"items.variant.inventory_items.inventory.location_levels.stock_locations.id",
|
||||||
|
"items.variant.inventory_items.inventory.location_levels.stock_locations.name",
|
||||||
|
"items.variant.inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
||||||
|
"items.variant.inventory_items.inventory.location_levels.stock_locations.sales_channels.name",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const productVariantsFields = [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"sku",
|
||||||
|
"manage_inventory",
|
||||||
|
"allow_backorder",
|
||||||
|
"barcode",
|
||||||
|
"product.id",
|
||||||
|
"product.title",
|
||||||
|
"product.description",
|
||||||
|
"product.subtitle",
|
||||||
|
"product.thumbnail",
|
||||||
|
"product.type",
|
||||||
|
"product.collection",
|
||||||
|
"product.handle",
|
||||||
|
"calculated_price.calculated_amount",
|
||||||
|
"inventory_items.inventory_item_id",
|
||||||
|
"inventory_items.required_quantity",
|
||||||
|
"inventory_items.inventory.location_levels.stock_locations.id",
|
||||||
|
"inventory_items.inventory.location_levels.stock_locations.name",
|
||||||
|
"inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
||||||
|
"inventory_items.inventory.location_levels.stock_locations.sales_channels.name",
|
||||||
]
|
]
|
||||||
|
|||||||
+12
-3
@@ -7,14 +7,22 @@ interface ConfirmInventoryPreparationInput {
|
|||||||
inventory_item_id: string
|
inventory_item_id: string
|
||||||
required_quantity: number
|
required_quantity: number
|
||||||
}[]
|
}[]
|
||||||
items: { variant_id?: string; quantity: BigNumberInput }[]
|
items: {
|
||||||
variants: { id: string; manage_inventory?: boolean }[]
|
variant_id?: string
|
||||||
|
quantity: BigNumberInput
|
||||||
|
}[]
|
||||||
|
variants: {
|
||||||
|
id: string
|
||||||
|
manage_inventory?: boolean
|
||||||
|
allow_backorder?: boolean
|
||||||
|
}[]
|
||||||
location_ids: string[]
|
location_ids: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfirmInventoryItem {
|
interface ConfirmInventoryItem {
|
||||||
inventory_item_id: string
|
inventory_item_id: string
|
||||||
required_quantity: number
|
required_quantity: number
|
||||||
|
allow_backorder: boolean
|
||||||
quantity: number
|
quantity: number
|
||||||
location_ids: string[]
|
location_ids: string[]
|
||||||
}
|
}
|
||||||
@@ -31,7 +39,7 @@ export const prepareConfirmInventoryInput = ({
|
|||||||
|
|
||||||
const variantsMap = new Map<
|
const variantsMap = new Map<
|
||||||
string,
|
string,
|
||||||
{ id: string; manage_inventory?: boolean }
|
ConfirmInventoryPreparationInput["variants"][0]
|
||||||
>(variants.map((v) => [v.id, v]))
|
>(variants.map((v) => [v.id, v]))
|
||||||
|
|
||||||
const itemsToConfirm: ConfirmInventoryItem[] = []
|
const itemsToConfirm: ConfirmInventoryItem[] = []
|
||||||
@@ -57,6 +65,7 @@ export const prepareConfirmInventoryInput = ({
|
|||||||
itemsToConfirm.push({
|
itemsToConfirm.push({
|
||||||
inventory_item_id: variantInventoryItem.inventory_item_id,
|
inventory_item_id: variantInventoryItem.inventory_item_id,
|
||||||
required_quantity: variantInventoryItem.required_quantity,
|
required_quantity: variantInventoryItem.required_quantity,
|
||||||
|
allow_backorder: !!variant.allow_backorder,
|
||||||
quantity: item.quantity as number, // TODO: update type to BigNumberInput
|
quantity: item.quantity as number, // TODO: update type to BigNumberInput
|
||||||
location_ids: location_ids,
|
location_ids: location_ids,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,18 +7,16 @@ import {
|
|||||||
createWorkflow,
|
createWorkflow,
|
||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
||||||
import {
|
import { addToCartStep, refreshCartShippingMethodsStep } from "../steps"
|
||||||
addToCartStep,
|
|
||||||
confirmInventoryStep,
|
|
||||||
refreshCartShippingMethodsStep,
|
|
||||||
} from "../steps"
|
|
||||||
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
import { updateTaxLinesStep } from "../steps/update-tax-lines"
|
import { updateTaxLinesStep } from "../steps/update-tax-lines"
|
||||||
import { cartFieldsForRefreshSteps } from "../utils/fields"
|
import {
|
||||||
import { prepareConfirmInventoryInput } from "../utils/prepare-confirm-inventory-input"
|
cartFieldsForRefreshSteps,
|
||||||
|
productVariantsFields,
|
||||||
|
} from "../utils/fields"
|
||||||
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
||||||
|
import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
|
||||||
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
||||||
|
|
||||||
// TODO: The AddToCartWorkflow are missing the following steps:
|
// TODO: The AddToCartWorkflow are missing the following steps:
|
||||||
@@ -43,32 +41,7 @@ export const addToCartWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const variants = useRemoteQueryStep({
|
const variants = useRemoteQueryStep({
|
||||||
entry_point: "variants",
|
entry_point: "variants",
|
||||||
fields: [
|
fields: productVariantsFields,
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"sku",
|
|
||||||
"barcode",
|
|
||||||
"manage_inventory",
|
|
||||||
"product.id",
|
|
||||||
"product.title",
|
|
||||||
"product.description",
|
|
||||||
"product.subtitle",
|
|
||||||
"product.thumbnail",
|
|
||||||
"product.type",
|
|
||||||
"product.collection",
|
|
||||||
"product.handle",
|
|
||||||
|
|
||||||
"calculated_price.calculated_amount",
|
|
||||||
|
|
||||||
"inventory_items.inventory_item_id",
|
|
||||||
"inventory_items.required_quantity",
|
|
||||||
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.id",
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.name",
|
|
||||||
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.name",
|
|
||||||
],
|
|
||||||
variables: {
|
variables: {
|
||||||
id: variantIds,
|
id: variantIds,
|
||||||
calculated_price: {
|
calculated_price: {
|
||||||
@@ -78,71 +51,14 @@ export const addToCartWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const confirmInventoryInput = transform({ input, variants }, (data) => {
|
confirmVariantInventoryWorkflow.runAsStep({
|
||||||
const managedVariants = data.variants.filter((v) => v.manage_inventory)
|
input: {
|
||||||
if (!managedVariants.length) {
|
sales_channel_id: input.cart.sales_channel_id as string,
|
||||||
return { items: [] }
|
variants,
|
||||||
}
|
items: input.items,
|
||||||
|
},
|
||||||
const productVariantInventoryItems: any[] = []
|
|
||||||
|
|
||||||
const stockLocations = data.variants
|
|
||||||
.map((v) => v.inventory_items)
|
|
||||||
.flat()
|
|
||||||
.map((ii) => {
|
|
||||||
productVariantInventoryItems.push({
|
|
||||||
variant_id: ii.variant_id,
|
|
||||||
inventory_item_id: ii.inventory_item_id,
|
|
||||||
required_quantity: ii.required_quantity,
|
|
||||||
})
|
|
||||||
|
|
||||||
return ii.inventory.location_levels
|
|
||||||
})
|
|
||||||
.flat()
|
|
||||||
.map((ll) => ll.stock_locations)
|
|
||||||
.flat()
|
|
||||||
|
|
||||||
const salesChannelId = data.input.cart.sales_channel_id
|
|
||||||
if (salesChannelId) {
|
|
||||||
const salesChannels = stockLocations
|
|
||||||
.map((sl) => sl.sales_channels)
|
|
||||||
.flat()
|
|
||||||
.filter((sc) => sc.id === salesChannelId)
|
|
||||||
|
|
||||||
if (!salesChannels.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Sales channel ${salesChannelId} is not associated with any stock locations.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const priceNotFound: string[] = data.variants
|
|
||||||
.filter((v) => !v.calculated_price)
|
|
||||||
.map((v) => v.id)
|
|
||||||
|
|
||||||
if (priceNotFound.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Variants with IDs ${priceNotFound.join(", ")} do not have a price`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = prepareConfirmInventoryInput({
|
|
||||||
product_variant_inventory_items: productVariantInventoryItems,
|
|
||||||
location_ids: stockLocations.map((l) => l.id),
|
|
||||||
items: data.input.items!,
|
|
||||||
variants: data.variants.map((v) => ({
|
|
||||||
id: v.id,
|
|
||||||
manage_inventory: v.manage_inventory,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
|
|
||||||
return { items }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
confirmInventoryStep(confirmInventoryInput)
|
|
||||||
|
|
||||||
const lineItems = transform({ input, variants }, (data) => {
|
const lineItems = transform({ input, variants }, (data) => {
|
||||||
const items = (data.input.items ?? []).map((item) => {
|
const items = (data.input.items ?? []).map((item) => {
|
||||||
const variant = data.variants.find((v) => v.id === item.variant_id)!
|
const variant = data.variants.find((v) => v.id === item.variant_id)!
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import { CompleteCartWorkflowInputDTO, OrderDTO } from "@medusajs/types"
|
import { OrderDTO } from "@medusajs/types"
|
||||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
} from "@medusajs/workflows-sdk"
|
||||||
import { useRemoteQueryStep } from "../../../common"
|
import { useRemoteQueryStep } from "../../../common"
|
||||||
import { createOrderFromCartStep } from "../steps"
|
import { createOrderFromCartStep } from "../steps"
|
||||||
import { updateTaxLinesStep } from "../steps/update-tax-lines"
|
import { updateTaxLinesStep } from "../steps/update-tax-lines"
|
||||||
import { completeCartFields } from "../utils/fields"
|
import { completeCartFields } from "../utils/fields"
|
||||||
|
import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- [] Create Tax Lines
|
- [] Create Tax Lines
|
||||||
@@ -19,9 +24,7 @@ import { completeCartFields } from "../utils/fields"
|
|||||||
export const completeCartWorkflowId = "complete-cart"
|
export const completeCartWorkflowId = "complete-cart"
|
||||||
export const completeCartWorkflow = createWorkflow(
|
export const completeCartWorkflow = createWorkflow(
|
||||||
completeCartWorkflowId,
|
completeCartWorkflowId,
|
||||||
(
|
(input: WorkflowData<any>): WorkflowData<OrderDTO> => {
|
||||||
input: WorkflowData<CompleteCartWorkflowInputDTO>
|
|
||||||
): WorkflowData<OrderDTO> => {
|
|
||||||
const cart = useRemoteQueryStep({
|
const cart = useRemoteQueryStep({
|
||||||
entry_point: "cart",
|
entry_point: "cart",
|
||||||
fields: completeCartFields,
|
fields: completeCartFields,
|
||||||
@@ -29,6 +32,37 @@ export const completeCartWorkflow = createWorkflow(
|
|||||||
list: false,
|
list: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { variants, items, sales_channel_id } = transform(
|
||||||
|
{ cart },
|
||||||
|
(data) => {
|
||||||
|
const allItems: any[] = []
|
||||||
|
const allVariants: any[] = []
|
||||||
|
data.cart.items.forEach((item) => {
|
||||||
|
allItems.push({
|
||||||
|
id: item.id,
|
||||||
|
quantity: item.quantity,
|
||||||
|
})
|
||||||
|
|
||||||
|
allVariants.push(item.variant)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
variants: allVariants,
|
||||||
|
items: allItems,
|
||||||
|
sales_channel_id: data.cart.sales_channel_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
confirmVariantInventoryWorkflow.runAsStep({
|
||||||
|
input: {
|
||||||
|
ignore_price_check: true,
|
||||||
|
sales_channel_id,
|
||||||
|
variants,
|
||||||
|
items,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
updateTaxLinesStep({ cart_or_cart_id: cart, force_tax_calculation: true })
|
updateTaxLinesStep({ cart_or_cart_id: cart, force_tax_calculation: true })
|
||||||
|
|
||||||
const finalCart = useRemoteQueryStep({
|
const finalCart = useRemoteQueryStep({
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { ConfirmVariantInventoryWorkflowInputDTO } from "@medusajs/types"
|
||||||
|
import { MedusaError, deepFlatMap, isDefined } from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
} from "@medusajs/workflows-sdk"
|
||||||
|
import { confirmInventoryStep } from "../steps"
|
||||||
|
import { prepareConfirmInventoryInput } from "../utils/prepare-confirm-inventory-input"
|
||||||
|
|
||||||
|
export const confirmVariantInventoryWorkflowId = "confirm-item-inventory"
|
||||||
|
export const confirmVariantInventoryWorkflow = createWorkflow(
|
||||||
|
confirmVariantInventoryWorkflowId,
|
||||||
|
(input: WorkflowData<ConfirmVariantInventoryWorkflowInputDTO>) => {
|
||||||
|
const confirmInventoryInput = transform({ input }, (data) => {
|
||||||
|
const productVariantInventoryItems = new Map<string, any>()
|
||||||
|
const priceNotFound: string[] = []
|
||||||
|
const stockLocationIds = new Set<string>()
|
||||||
|
const allVariants = new Map<string, any>()
|
||||||
|
let hasSalesChannelStockLocation = false
|
||||||
|
let hasManagedInventory = false
|
||||||
|
|
||||||
|
const salesChannelId = data.input.sales_channel_id
|
||||||
|
|
||||||
|
deepFlatMap(
|
||||||
|
data.input,
|
||||||
|
"variants.inventory_items.inventory.location_levels.stock_locations.sales_channels",
|
||||||
|
({ variants, inventory_items, stock_locations, sales_channels }) => {
|
||||||
|
if (
|
||||||
|
!hasSalesChannelStockLocation &&
|
||||||
|
sales_channels?.id === salesChannelId
|
||||||
|
) {
|
||||||
|
hasSalesChannelStockLocation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDefined(variants.calculated_price)) {
|
||||||
|
priceNotFound.push(variants.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
stockLocationIds.add(stock_locations.id)
|
||||||
|
|
||||||
|
const inventoryItemId = inventory_items.inventory_item_id
|
||||||
|
if (!productVariantInventoryItems.has(inventoryItemId)) {
|
||||||
|
productVariantInventoryItems.set(inventoryItemId, {
|
||||||
|
variant_id: inventory_items.variant_id,
|
||||||
|
inventory_item_id: inventoryItemId,
|
||||||
|
required_quantity: inventory_items.required_quantity,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allVariants.has(variants.id)) {
|
||||||
|
if (!hasManagedInventory && variants.manage_inventory) {
|
||||||
|
hasManagedInventory = true
|
||||||
|
}
|
||||||
|
|
||||||
|
allVariants.set(variants.id, {
|
||||||
|
id: variants.id,
|
||||||
|
manage_inventory: variants.manage_inventory,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!hasManagedInventory) {
|
||||||
|
return { items: [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (salesChannelId && !hasSalesChannelStockLocation) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Sales channel ${salesChannelId} is not associated with any stock locations.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priceNotFound.length && !data.input.ignore_price_check) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Variants with IDs ${priceNotFound.join(", ")} do not have a price`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = prepareConfirmInventoryInput({
|
||||||
|
product_variant_inventory_items: Array.from(
|
||||||
|
productVariantInventoryItems.values()
|
||||||
|
),
|
||||||
|
location_ids: Array.from(stockLocationIds),
|
||||||
|
items: data.input.items,
|
||||||
|
variants: Array.from(allVariants.values()),
|
||||||
|
})
|
||||||
|
|
||||||
|
return { items }
|
||||||
|
})
|
||||||
|
|
||||||
|
confirmInventoryStep(confirmInventoryInput)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -5,10 +5,8 @@ import {
|
|||||||
parallelize,
|
parallelize,
|
||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
||||||
import {
|
import {
|
||||||
confirmInventoryStep,
|
|
||||||
createCartsStep,
|
createCartsStep,
|
||||||
findOneOrAnyRegionStep,
|
findOneOrAnyRegionStep,
|
||||||
findOrCreateCustomerStep,
|
findOrCreateCustomerStep,
|
||||||
@@ -17,8 +15,9 @@ import {
|
|||||||
} from "../steps"
|
} from "../steps"
|
||||||
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
import { updateTaxLinesStep } from "../steps/update-tax-lines"
|
import { updateTaxLinesStep } from "../steps/update-tax-lines"
|
||||||
import { prepareConfirmInventoryInput } from "../utils/prepare-confirm-inventory-input"
|
import { productVariantsFields } from "../utils/fields"
|
||||||
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
||||||
|
import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
|
||||||
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
||||||
|
|
||||||
// TODO: The createCartWorkflow are missing the following steps:
|
// TODO: The createCartWorkflow are missing the following steps:
|
||||||
@@ -59,32 +58,7 @@ export const createCartWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const variants = useRemoteQueryStep({
|
const variants = useRemoteQueryStep({
|
||||||
entry_point: "variants",
|
entry_point: "variants",
|
||||||
fields: [
|
fields: productVariantsFields,
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"sku",
|
|
||||||
"manage_inventory",
|
|
||||||
"barcode",
|
|
||||||
"product.id",
|
|
||||||
"product.title",
|
|
||||||
"product.description",
|
|
||||||
"product.subtitle",
|
|
||||||
"product.thumbnail",
|
|
||||||
"product.type",
|
|
||||||
"product.collection",
|
|
||||||
"product.handle",
|
|
||||||
|
|
||||||
"calculated_price.calculated_amount",
|
|
||||||
|
|
||||||
"inventory_items.inventory_item_id",
|
|
||||||
"inventory_items.required_quantity",
|
|
||||||
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.id",
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.name",
|
|
||||||
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.name",
|
|
||||||
],
|
|
||||||
variables: {
|
variables: {
|
||||||
id: variantIds,
|
id: variantIds,
|
||||||
calculated_price: {
|
calculated_price: {
|
||||||
@@ -94,73 +68,13 @@ export const createCartWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const confirmInventoryInput = transform(
|
confirmVariantInventoryWorkflow.runAsStep({
|
||||||
{ input, salesChannel, variants },
|
input: {
|
||||||
(data) => {
|
sales_channel_id: salesChannel.id,
|
||||||
const managedVariants = data.variants.filter((v) => v.manage_inventory)
|
variants,
|
||||||
if (!managedVariants.length) {
|
items: input.items!,
|
||||||
return { items: [] }
|
},
|
||||||
}
|
})
|
||||||
|
|
||||||
const productVariantInventoryItems: any[] = []
|
|
||||||
|
|
||||||
const stockLocations = managedVariants
|
|
||||||
.map((v) => v.inventory_items)
|
|
||||||
.flat()
|
|
||||||
.map((ii) => {
|
|
||||||
productVariantInventoryItems.push({
|
|
||||||
variant_id: ii.variant_id,
|
|
||||||
inventory_item_id: ii.inventory_item_id,
|
|
||||||
required_quantity: ii.required_quantity,
|
|
||||||
})
|
|
||||||
|
|
||||||
return ii.inventory.location_levels
|
|
||||||
})
|
|
||||||
.flat()
|
|
||||||
.map((ll) => ll.stock_locations)
|
|
||||||
.flat()
|
|
||||||
|
|
||||||
const salesChannelId = data.salesChannel?.id
|
|
||||||
if (salesChannelId) {
|
|
||||||
const salesChannels = stockLocations
|
|
||||||
.map((sl) => sl.sales_channels)
|
|
||||||
.flat()
|
|
||||||
.filter((sc) => sc.id === salesChannelId)
|
|
||||||
|
|
||||||
if (!salesChannels.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Sales channel ${salesChannelId} is not associated with any stock locations.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const priceNotFound: string[] = data.variants
|
|
||||||
.filter((v) => !v.calculated_price)
|
|
||||||
.map((v) => v.id)
|
|
||||||
|
|
||||||
if (priceNotFound.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Variants with IDs ${priceNotFound.join(", ")} do not have a price`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = prepareConfirmInventoryInput({
|
|
||||||
product_variant_inventory_items: productVariantInventoryItems,
|
|
||||||
location_ids: stockLocations.map((l) => l.id),
|
|
||||||
items: data.input.items!,
|
|
||||||
variants: data.variants.map((v) => ({
|
|
||||||
id: v.id,
|
|
||||||
manage_inventory: v.manage_inventory,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
|
|
||||||
return { items }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
confirmInventoryStep(confirmInventoryInput)
|
|
||||||
|
|
||||||
const priceSets = getVariantPriceSetsStep({
|
const priceSets = getVariantPriceSetsStep({
|
||||||
variantIds,
|
variantIds,
|
||||||
|
|||||||
+2
-10
@@ -1,13 +1,9 @@
|
|||||||
import {
|
import { CreatePaymentCollectionForCartWorkflowInputDTO } from "@medusajs/types"
|
||||||
CartDTO,
|
|
||||||
CreatePaymentCollectionForCartWorkflowInputDTO,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
WorkflowData,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import { retrieveCartStep } from "../steps"
|
|
||||||
import { createPaymentCollectionsStep } from "../steps/create-payment-collection"
|
import { createPaymentCollectionsStep } from "../steps/create-payment-collection"
|
||||||
import { linkCartAndPaymentCollectionsStep } from "../steps/link-cart-payment-collection"
|
import { linkCartAndPaymentCollectionsStep } from "../steps/link-cart-payment-collection"
|
||||||
|
|
||||||
@@ -17,7 +13,7 @@ export const createPaymentCollectionForCartWorkflow = createWorkflow(
|
|||||||
createPaymentCollectionForCartWorkflowId,
|
createPaymentCollectionForCartWorkflowId,
|
||||||
(
|
(
|
||||||
input: WorkflowData<CreatePaymentCollectionForCartWorkflowInputDTO>
|
input: WorkflowData<CreatePaymentCollectionForCartWorkflowInputDTO>
|
||||||
): WorkflowData<CartDTO> => {
|
): WorkflowData<void> => {
|
||||||
const created = createPaymentCollectionsStep([input])
|
const created = createPaymentCollectionsStep([input])
|
||||||
|
|
||||||
const link = transform({ cartId: input.cart_id, created }, (data) => ({
|
const link = transform({ cartId: input.cart_id, created }, (data) => ({
|
||||||
@@ -30,9 +26,5 @@ export const createPaymentCollectionForCartWorkflow = createWorkflow(
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
linkCartAndPaymentCollectionsStep(link)
|
linkCartAndPaymentCollectionsStep(link)
|
||||||
|
|
||||||
const cart = retrieveCartStep({ id: input.cart_id })
|
|
||||||
|
|
||||||
return cart
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
+16
-92
@@ -4,13 +4,15 @@ import {
|
|||||||
createWorkflow,
|
createWorkflow,
|
||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
||||||
import { updateLineItemsStep } from "../../line-item/steps"
|
import { updateLineItemsStep } from "../../line-item/steps"
|
||||||
import { confirmInventoryStep, refreshCartShippingMethodsStep } from "../steps"
|
import { refreshCartShippingMethodsStep } from "../steps"
|
||||||
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
import { cartFieldsForRefreshSteps } from "../utils/fields"
|
import {
|
||||||
import { prepareConfirmInventoryInput } from "../utils/prepare-confirm-inventory-input"
|
cartFieldsForRefreshSteps,
|
||||||
|
productVariantsFields,
|
||||||
|
} from "../utils/fields"
|
||||||
|
import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
|
||||||
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
||||||
|
|
||||||
// TODO: The UpdateLineItemsWorkflow are missing the following steps:
|
// TODO: The UpdateLineItemsWorkflow are missing the following steps:
|
||||||
@@ -35,32 +37,7 @@ export const updateLineItemInCartWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const variants = useRemoteQueryStep({
|
const variants = useRemoteQueryStep({
|
||||||
entry_point: "variants",
|
entry_point: "variants",
|
||||||
fields: [
|
fields: productVariantsFields,
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"sku",
|
|
||||||
"barcode",
|
|
||||||
"manage_inventory",
|
|
||||||
"product.id",
|
|
||||||
"product.title",
|
|
||||||
"product.description",
|
|
||||||
"product.subtitle",
|
|
||||||
"product.thumbnail",
|
|
||||||
"product.type",
|
|
||||||
"product.collection",
|
|
||||||
"product.handle",
|
|
||||||
|
|
||||||
"calculated_price.calculated_amount",
|
|
||||||
|
|
||||||
"inventory_items.inventory_item_id",
|
|
||||||
"inventory_items.required_quantity",
|
|
||||||
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.id",
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.name",
|
|
||||||
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
|
||||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.name",
|
|
||||||
],
|
|
||||||
variables: {
|
variables: {
|
||||||
id: variantIds,
|
id: variantIds,
|
||||||
calculated_price: {
|
calculated_price: {
|
||||||
@@ -70,70 +47,17 @@ export const updateLineItemInCartWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const confirmInventoryInput = transform({ input, variants }, (data) => {
|
const items = transform({ input }, (data) => {
|
||||||
const managedVariants = data.variants.filter((v) => v.manage_inventory)
|
return [data.input.item]
|
||||||
if (!managedVariants.length) {
|
|
||||||
return { items: [] }
|
|
||||||
}
|
|
||||||
|
|
||||||
const productVariantInventoryItems: any[] = []
|
|
||||||
|
|
||||||
const stockLocations = data.variants
|
|
||||||
.map((v) => v.inventory_items)
|
|
||||||
.flat()
|
|
||||||
.map((ii) => {
|
|
||||||
productVariantInventoryItems.push({
|
|
||||||
variant_id: ii.variant_id,
|
|
||||||
inventory_item_id: ii.inventory_item_id,
|
|
||||||
required_quantity: ii.required_quantity,
|
|
||||||
})
|
|
||||||
|
|
||||||
return ii.inventory.location_levels
|
|
||||||
})
|
|
||||||
.flat()
|
|
||||||
.map((ll) => ll.stock_locations)
|
|
||||||
.flat()
|
|
||||||
|
|
||||||
const salesChannelId = data.input.cart.sales_channel_id
|
|
||||||
if (salesChannelId) {
|
|
||||||
const salesChannels = stockLocations
|
|
||||||
.map((sl) => sl.sales_channels)
|
|
||||||
.flat()
|
|
||||||
.filter((sc) => sc.id === salesChannelId)
|
|
||||||
|
|
||||||
if (!salesChannels.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Sales channel ${salesChannelId} is not associated with any stock locations.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const priceNotFound: string[] = data.variants
|
|
||||||
.filter((v) => !v.calculated_price)
|
|
||||||
.map((v) => v.id)
|
|
||||||
|
|
||||||
if (priceNotFound.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Variants with IDs ${priceNotFound.join(", ")} do not have a price`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = prepareConfirmInventoryInput({
|
|
||||||
product_variant_inventory_items: productVariantInventoryItems,
|
|
||||||
location_ids: stockLocations.map((l) => l.id),
|
|
||||||
items: [data.input.item!],
|
|
||||||
variants: data.variants.map((v) => ({
|
|
||||||
id: v.id,
|
|
||||||
manage_inventory: v.manage_inventory,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
|
|
||||||
return { items }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
confirmInventoryStep(confirmInventoryInput)
|
confirmVariantInventoryWorkflow.runAsStep({
|
||||||
|
input: {
|
||||||
|
sales_channel_id: input.cart.sales_channel_id as string,
|
||||||
|
variants,
|
||||||
|
items,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const lineItemUpdate = transform({ input, variants }, (data) => {
|
const lineItemUpdate = transform({ input, variants }, (data) => {
|
||||||
const variant = data.variants[0]
|
const variant = data.variants[0]
|
||||||
|
|||||||
@@ -122,3 +122,32 @@ export interface PricedShippingOptionDTO extends ShippingOptionDTO {
|
|||||||
export interface CompleteCartWorkflowInputDTO {
|
export interface CompleteCartWorkflowInputDTO {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ConfirmVariantInventoryWorkflowInputDTO {
|
||||||
|
ignore_price_check?: boolean
|
||||||
|
|
||||||
|
sales_channel_id: string
|
||||||
|
variants: {
|
||||||
|
id: string
|
||||||
|
manage_inventory: boolean
|
||||||
|
inventory_items: {
|
||||||
|
inventory_item_id: string
|
||||||
|
variant_id: string
|
||||||
|
required_quantity: BigNumberInput
|
||||||
|
inventory: {
|
||||||
|
location_levels: {
|
||||||
|
stock_locations: {
|
||||||
|
id: string
|
||||||
|
sales_channels: {
|
||||||
|
id: string
|
||||||
|
}[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
}[]
|
||||||
|
}[]
|
||||||
|
}[]
|
||||||
|
items: {
|
||||||
|
variant_id?: string
|
||||||
|
quantity: BigNumberInput
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import {
|
|||||||
WorkflowManager,
|
WorkflowManager,
|
||||||
} from "@medusajs/orchestration"
|
} from "@medusajs/orchestration"
|
||||||
import { LoadedModule, MedusaContainer } from "@medusajs/types"
|
import { LoadedModule, MedusaContainer } from "@medusajs/types"
|
||||||
import { isString, OrchestrationUtils } from "@medusajs/utils"
|
import { OrchestrationUtils, isString } from "@medusajs/utils"
|
||||||
import { exportWorkflow } from "../../helper"
|
import { exportWorkflow } from "../../helper"
|
||||||
|
import { createStep } from "./create-step"
|
||||||
|
import { StepResponse } from "./helpers"
|
||||||
import { proxify } from "./helpers/proxy"
|
import { proxify } from "./helpers/proxy"
|
||||||
import {
|
import {
|
||||||
CreateWorkflowComposerContext,
|
CreateWorkflowComposerContext,
|
||||||
@@ -14,8 +16,6 @@ import {
|
|||||||
WorkflowData,
|
WorkflowData,
|
||||||
WorkflowDataProperties,
|
WorkflowDataProperties,
|
||||||
} from "./type"
|
} from "./type"
|
||||||
import { createStep } from "./create-step"
|
|
||||||
import { StepResponse } from "./helpers"
|
|
||||||
|
|
||||||
global[OrchestrationUtils.SymbolMedusaWorkflowComposerContext] = null
|
global[OrchestrationUtils.SymbolMedusaWorkflowComposerContext] = null
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const POST = async (
|
|||||||
req: MedusaRequest<StoreCompleteCartType>,
|
req: MedusaRequest<StoreCompleteCartType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const { idempotency_key: idempotencyKey } = req.validatedBody
|
const cart_id = req.params.id
|
||||||
|
|
||||||
// If the idempotencyKey is present:
|
// If the idempotencyKey is present:
|
||||||
// - is workflow is running?
|
// - is workflow is running?
|
||||||
@@ -17,6 +17,9 @@ export const POST = async (
|
|||||||
|
|
||||||
const { errors, result } = await completeCartWorkflow(req.scope).run({
|
const { errors, result } = await completeCartWorkflow(req.scope).run({
|
||||||
input: { id: req.params.id },
|
input: { id: req.params.id },
|
||||||
|
context: {
|
||||||
|
transactionId: cart_id,
|
||||||
|
},
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
|||||||
select: [
|
select: [
|
||||||
"id",
|
"id",
|
||||||
"sales_channel_id",
|
"sales_channel_id",
|
||||||
"subtotal",
|
|
||||||
"currency_code",
|
"currency_code",
|
||||||
"shipping_address.city",
|
"shipping_address.city",
|
||||||
"shipping_address.country_code",
|
"shipping_address.country_code",
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
export * from "./cart-customer"
|
|
||||||
export * from "./cart-payment-collection"
|
export * from "./cart-payment-collection"
|
||||||
export * from "./cart-promotion"
|
export * from "./cart-promotion"
|
||||||
export * from "./cart-region"
|
export * from "./fulfillment-set-location"
|
||||||
export * from "./cart-sales-channel"
|
|
||||||
export * from "./inventory-level-stock-location"
|
|
||||||
export * from "./location-fulfillment-set"
|
|
||||||
export * from "./order-customer"
|
|
||||||
export * from "./order-promotion"
|
export * from "./order-promotion"
|
||||||
export * from "./order-region"
|
export * from "./order-region"
|
||||||
export * from "./order-sales-channel"
|
export * from "./order-sales-channel"
|
||||||
@@ -14,8 +9,7 @@ export * from "./product-shipping-profile"
|
|||||||
export * from "./product-variant-inventory-item"
|
export * from "./product-variant-inventory-item"
|
||||||
export * from "./product-variant-price-set"
|
export * from "./product-variant-price-set"
|
||||||
export * from "./publishable-api-key-sales-channel"
|
export * from "./publishable-api-key-sales-channel"
|
||||||
|
export * from "./readonly"
|
||||||
export * from "./region-payment-provider"
|
export * from "./region-payment-provider"
|
||||||
export * from "./sales-channel-location"
|
export * from "./sales-channel-location"
|
||||||
export * from "./shipping-option-price-set"
|
export * from "./shipping-option-price-set"
|
||||||
export * from "./store-default-currency"
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Modules } from "@medusajs/modules-sdk"
|
||||||
|
import { ModuleJoinerConfig } from "@medusajs/types"
|
||||||
|
|
||||||
|
export const CartProduct: ModuleJoinerConfig = {
|
||||||
|
isLink: true,
|
||||||
|
isReadOnlyLink: true,
|
||||||
|
extends: [
|
||||||
|
{
|
||||||
|
serviceName: Modules.CART,
|
||||||
|
relationship: {
|
||||||
|
serviceName: Modules.PRODUCT,
|
||||||
|
primaryKey: "id",
|
||||||
|
foreignKey: "items.product_id",
|
||||||
|
alias: "product",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serviceName: Modules.CART,
|
||||||
|
relationship: {
|
||||||
|
serviceName: Modules.PRODUCT,
|
||||||
|
primaryKey: "id",
|
||||||
|
foreignKey: "items.variant_id",
|
||||||
|
alias: "variant",
|
||||||
|
args: {
|
||||||
|
methodSuffix: "Variants",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serviceName: Modules.PRODUCT,
|
||||||
|
relationship: {
|
||||||
|
serviceName: Modules.CART,
|
||||||
|
primaryKey: "variant_id",
|
||||||
|
foreignKey: "id",
|
||||||
|
alias: "cart_items",
|
||||||
|
isList: true,
|
||||||
|
args: {
|
||||||
|
methodSuffix: "LineItems",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export * from "./cart-customer"
|
||||||
|
export * from "./cart-product"
|
||||||
|
export * from "./cart-region"
|
||||||
|
export * from "./cart-sales-channel"
|
||||||
|
export * from "./inventory-level-stock-location"
|
||||||
|
export * from "./order-customer"
|
||||||
|
export * from "./store-default-currency"
|
||||||
Reference in New Issue
Block a user