feat: Confirm inventory in create cart workflow (#6635)
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
|||||||
ICartModuleService,
|
ICartModuleService,
|
||||||
ICustomerModuleService,
|
ICustomerModuleService,
|
||||||
IFulfillmentModuleService,
|
IFulfillmentModuleService,
|
||||||
|
IInventoryServiceNext,
|
||||||
IPaymentModuleService,
|
IPaymentModuleService,
|
||||||
IPricingModuleService,
|
IPricingModuleService,
|
||||||
IProductModuleService,
|
IProductModuleService,
|
||||||
@@ -45,6 +46,8 @@ medusaIntegrationTestRunner({
|
|||||||
let productModule: IProductModuleService
|
let productModule: IProductModuleService
|
||||||
let pricingModule: IPricingModuleService
|
let pricingModule: IPricingModuleService
|
||||||
let paymentModule: IPaymentModuleService
|
let paymentModule: IPaymentModuleService
|
||||||
|
let inventoryModule: IInventoryServiceNext
|
||||||
|
let stockLocationModule: IStockLocationServiceNext
|
||||||
let fulfillmentModule: IFulfillmentModuleService
|
let fulfillmentModule: IFulfillmentModuleService
|
||||||
let locationModule: IStockLocationServiceNext
|
let locationModule: IStockLocationServiceNext
|
||||||
let remoteLink, remoteQuery
|
let remoteLink, remoteQuery
|
||||||
@@ -64,6 +67,10 @@ medusaIntegrationTestRunner({
|
|||||||
productModule = appContainer.resolve(ModuleRegistrationName.PRODUCT)
|
productModule = appContainer.resolve(ModuleRegistrationName.PRODUCT)
|
||||||
pricingModule = appContainer.resolve(ModuleRegistrationName.PRICING)
|
pricingModule = appContainer.resolve(ModuleRegistrationName.PRICING)
|
||||||
paymentModule = appContainer.resolve(ModuleRegistrationName.PAYMENT)
|
paymentModule = appContainer.resolve(ModuleRegistrationName.PAYMENT)
|
||||||
|
inventoryModule = appContainer.resolve(ModuleRegistrationName.INVENTORY)
|
||||||
|
stockLocationModule = appContainer.resolve(
|
||||||
|
ModuleRegistrationName.STOCK_LOCATION
|
||||||
|
)
|
||||||
fulfillmentModule = appContainer.resolve(
|
fulfillmentModule = appContainer.resolve(
|
||||||
ModuleRegistrationName.FULFILLMENT
|
ModuleRegistrationName.FULFILLMENT
|
||||||
)
|
)
|
||||||
@@ -97,6 +104,10 @@ medusaIntegrationTestRunner({
|
|||||||
name: "Webshop",
|
name: "Webshop",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const location = await stockLocationModule.create({
|
||||||
|
name: "Warehouse",
|
||||||
|
})
|
||||||
|
|
||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
{
|
{
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
@@ -108,6 +119,19 @@ medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryModule.create({
|
||||||
|
sku: "inv-1234",
|
||||||
|
})
|
||||||
|
|
||||||
|
await inventoryModule.createInventoryLevels([
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
location_id: location.id,
|
||||||
|
stocked_quantity: 2,
|
||||||
|
reserved_quantity: 0,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const priceSet = await pricingModule.create({
|
const priceSet = await pricingModule.create({
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
@@ -119,13 +143,29 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
await remoteLink.create([
|
await remoteLink.create([
|
||||||
{
|
{
|
||||||
productService: {
|
[Modules.PRODUCT]: {
|
||||||
variant_id: product.variants[0].id,
|
variant_id: product.variants[0].id,
|
||||||
},
|
},
|
||||||
pricingService: {
|
[Modules.PRICING]: {
|
||||||
price_set_id: priceSet.id,
|
price_set_id: priceSet.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.INVENTORY]: {
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
const { result } = await createCartWorkflow(appContainer).run({
|
const { result } = await createCartWorkflow(appContainer).run({
|
||||||
@@ -184,6 +224,99 @@ medusaIntegrationTestRunner({
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should throw if variants are out of stock", async () => {
|
||||||
|
const salesChannel = await scModuleService.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
|
const location = await stockLocationModule.create({
|
||||||
|
name: "Warehouse",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [product] = await productModule.create([
|
||||||
|
{
|
||||||
|
title: "Test product",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryModule.create({
|
||||||
|
sku: "inv-1234",
|
||||||
|
})
|
||||||
|
|
||||||
|
await inventoryModule.createInventoryLevels([
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
location_id: location.id,
|
||||||
|
stocked_quantity: 2,
|
||||||
|
reserved_quantity: 2,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const priceSet = await pricingModule.create({
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
amount: 3000,
|
||||||
|
currency_code: "usd",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await remoteLink.create([
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.PRICING]: {
|
||||||
|
price_set_id: priceSet.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.INVENTORY]: {
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const { errors } = await createCartWorkflow(appContainer).run({
|
||||||
|
input: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(errors).toEqual([
|
||||||
|
{
|
||||||
|
action: "confirm-inventory-step",
|
||||||
|
handlerType: "invoke",
|
||||||
|
error: new Error(
|
||||||
|
"Some variant does not have the required inventory"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
it("should throw if sales channel is disabled", async () => {
|
it("should throw if sales channel is disabled", async () => {
|
||||||
const salesChannel = await scModuleService.create({
|
const salesChannel = await scModuleService.create({
|
||||||
name: "Webshop",
|
name: "Webshop",
|
||||||
@@ -283,8 +416,17 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
describe("AddToCartWorkflow", () => {
|
describe("AddToCartWorkflow", () => {
|
||||||
it("should add item to cart", async () => {
|
it("should add item to cart", async () => {
|
||||||
|
const salesChannel = await scModuleService.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
|
const location = await stockLocationModule.create({
|
||||||
|
name: "Warehouse",
|
||||||
|
})
|
||||||
|
|
||||||
let cart = await cartModuleService.create({
|
let cart = await cartModuleService.create({
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
@@ -298,6 +440,19 @@ medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryModule.create({
|
||||||
|
sku: "inv-1234",
|
||||||
|
})
|
||||||
|
|
||||||
|
await inventoryModule.createInventoryLevels([
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
location_id: location.id,
|
||||||
|
stocked_quantity: 2,
|
||||||
|
reserved_quantity: 0,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const priceSet = await pricingModule.create({
|
const priceSet = await pricingModule.create({
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
@@ -309,13 +464,29 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
await remoteLink.create([
|
await remoteLink.create([
|
||||||
{
|
{
|
||||||
productService: {
|
[Modules.PRODUCT]: {
|
||||||
variant_id: product.variants[0].id,
|
variant_id: product.variants[0].id,
|
||||||
},
|
},
|
||||||
pricingService: {
|
[Modules.PRICING]: {
|
||||||
price_set_id: priceSet.id,
|
price_set_id: priceSet.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.INVENTORY]: {
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
cart = await cartModuleService.retrieve(cart.id, {
|
cart = await cartModuleService.retrieve(cart.id, {
|
||||||
@@ -354,8 +525,17 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should throw if no price sets for variant exist", async () => {
|
it("should throw if no price sets for variant exist", async () => {
|
||||||
const cart = await cartModuleService.create({
|
const salesChannel = await scModuleService.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
|
const location = await stockLocationModule.create({
|
||||||
|
name: "Warehouse",
|
||||||
|
})
|
||||||
|
|
||||||
|
let cart = await cartModuleService.create({
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
@@ -369,6 +549,38 @@ medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryModule.create({
|
||||||
|
sku: "inv-1234",
|
||||||
|
})
|
||||||
|
|
||||||
|
await inventoryModule.createInventoryLevels([
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
location_id: location.id,
|
||||||
|
stocked_quantity: 2,
|
||||||
|
reserved_quantity: 0,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
await remoteLink.create([
|
||||||
|
{
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.INVENTORY]: {
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const { errors } = await addToCartWorkflow(appContainer).run({
|
const { errors } = await addToCartWorkflow(appContainer).run({
|
||||||
input: {
|
input: {
|
||||||
items: [
|
items: [
|
||||||
@@ -423,6 +635,14 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
describe("updateLineItemInCartWorkflow", () => {
|
describe("updateLineItemInCartWorkflow", () => {
|
||||||
it("should update item in cart", async () => {
|
it("should update item in cart", async () => {
|
||||||
|
const salesChannel = await scModuleService.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
|
const location = await stockLocationModule.create({
|
||||||
|
name: "Warehouse",
|
||||||
|
})
|
||||||
|
|
||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
{
|
{
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
@@ -434,6 +654,19 @@ medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryModule.create({
|
||||||
|
sku: "inv-1234",
|
||||||
|
})
|
||||||
|
|
||||||
|
await inventoryModule.createInventoryLevels([
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
location_id: location.id,
|
||||||
|
stocked_quantity: 2,
|
||||||
|
reserved_quantity: 0,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const priceSet = await pricingModule.create({
|
const priceSet = await pricingModule.create({
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
@@ -445,17 +678,34 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
await remoteLink.create([
|
await remoteLink.create([
|
||||||
{
|
{
|
||||||
productService: {
|
[Modules.PRODUCT]: {
|
||||||
variant_id: product.variants[0].id,
|
variant_id: product.variants[0].id,
|
||||||
},
|
},
|
||||||
pricingService: {
|
[Modules.PRICING]: {
|
||||||
price_set_id: priceSet.id,
|
price_set_id: priceSet.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.INVENTORY]: {
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
let cart = await cartModuleService.create({
|
let cart = await cartModuleService.create({
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
variant_id: product.variants[0].id,
|
variant_id: product.variants[0].id,
|
||||||
@@ -473,7 +723,9 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
const item = cart.items?.[0]!
|
const item = cart.items?.[0]!
|
||||||
|
|
||||||
await updateLineItemInCartWorkflow(appContainer).run({
|
const { errors } = await updateLineItemInCartWorkflow(
|
||||||
|
appContainer
|
||||||
|
).run({
|
||||||
input: {
|
input: {
|
||||||
cart,
|
cart,
|
||||||
item,
|
item,
|
||||||
@@ -510,6 +762,14 @@ medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const salesChannel = await scModuleService.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
|
const location = await stockLocationModule.create({
|
||||||
|
name: "Warehouse",
|
||||||
|
})
|
||||||
|
|
||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
{
|
{
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
@@ -521,6 +781,55 @@ medusaIntegrationTestRunner({
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const inventoryItem = await inventoryModule.create({
|
||||||
|
sku: "inv-1234",
|
||||||
|
})
|
||||||
|
|
||||||
|
await inventoryModule.createInventoryLevels([
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
location_id: location.id,
|
||||||
|
stocked_quantity: 2,
|
||||||
|
reserved_quantity: 0,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const priceSet = await pricingModule.create({
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
amount: 3000,
|
||||||
|
currency_code: "usd",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await remoteLink.create([
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.PRICING]: {
|
||||||
|
price_set_id: priceSet.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[Modules.PRODUCT]: {
|
||||||
|
variant_id: product.variants[0].id,
|
||||||
|
},
|
||||||
|
[Modules.INVENTORY]: {
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
let cart = await cartModuleService.create({
|
let cart = await cartModuleService.create({
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
items: [
|
items: [
|
||||||
@@ -533,26 +842,6 @@ medusaIntegrationTestRunner({
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const priceSet = await pricingModule.create({
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
amount: 5000,
|
|
||||||
currency_code: "usd",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
await remoteLink.create([
|
|
||||||
{
|
|
||||||
productService: {
|
|
||||||
variant_id: product.variants[0].id,
|
|
||||||
},
|
|
||||||
pricingService: {
|
|
||||||
price_set_id: priceSet.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
cart = await cartModuleService.retrieve(cart.id, {
|
cart = await cartModuleService.retrieve(cart.id, {
|
||||||
select: ["id", "region_id", "currency_code"],
|
select: ["id", "region_id", "currency_code"],
|
||||||
relations: ["items", "items.variant_id", "items.metadata"],
|
relations: ["items", "items.variant_id", "items.metadata"],
|
||||||
|
|||||||
@@ -80,9 +80,11 @@ medusaIntegrationTestRunner({
|
|||||||
title: "Test product",
|
title: "Test product",
|
||||||
variants: [
|
variants: [
|
||||||
{
|
{
|
||||||
|
manage_inventory: false,
|
||||||
title: "Test variant",
|
title: "Test variant",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
manage_inventory: false,
|
||||||
title: "Test variant 2",
|
title: "Test variant 2",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -178,10 +180,16 @@ medusaIntegrationTestRunner({
|
|||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
{
|
{
|
||||||
title: "Test product default tax",
|
title: "Test product default tax",
|
||||||
variants: [{ title: "Test variant default tax" }],
|
variants: [
|
||||||
|
{ title: "Test variant default tax", manage_inventory: false },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const salesChannel = await scModule.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
const [priceSet] = await pricingModule.create([
|
const [priceSet] = await pricingModule.create([
|
||||||
{ prices: [{ amount: 3000, currency_code: "usd" }] },
|
{ prices: [{ amount: 3000, currency_code: "usd" }] },
|
||||||
])
|
])
|
||||||
@@ -204,6 +212,7 @@ medusaIntegrationTestRunner({
|
|||||||
province: "NY",
|
province: "NY",
|
||||||
postal_code: "94016",
|
postal_code: "94016",
|
||||||
},
|
},
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
@@ -789,25 +798,32 @@ medusaIntegrationTestRunner({
|
|||||||
email: "tony@stark-industries.com",
|
email: "tony@stark-industries.com",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const salesChannel = await scModule.create({
|
||||||
|
name: "Webshop",
|
||||||
|
})
|
||||||
|
|
||||||
const [productWithSpecialTax] = await productModule.create([
|
const [productWithSpecialTax] = await productModule.create([
|
||||||
{
|
{
|
||||||
// This product ID is setup in the tax structure fixture (setupTaxStructure)
|
// This product ID is setup in the tax structure fixture (setupTaxStructure)
|
||||||
id: "product_id_1",
|
id: "product_id_1",
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
variants: [{ title: "Test variant" }],
|
variants: [{ title: "Test variant", manage_inventory: false }],
|
||||||
} as any,
|
} as any,
|
||||||
])
|
])
|
||||||
|
|
||||||
const [productWithDefaultTax] = await productModule.create([
|
const [productWithDefaultTax] = await productModule.create([
|
||||||
{
|
{
|
||||||
title: "Test product default tax",
|
title: "Test product default tax",
|
||||||
variants: [{ title: "Test variant default tax" }],
|
variants: [
|
||||||
|
{ title: "Test variant default tax", manage_inventory: false },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
const cart = await cartModule.create({
|
const cart = await cartModule.create({
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
customer_id: customer.id,
|
customer_id: customer.id,
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
region_id: region.id,
|
region_id: region.id,
|
||||||
shipping_address: {
|
shipping_address: {
|
||||||
customer_id: customer.id,
|
customer_id: customer.id,
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { IInventoryService } from "@medusajs/types"
|
||||||
|
import { promiseAll } from "@medusajs/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import { ModuleRegistrationName } from "../../../../../modules-sdk/dist"
|
||||||
|
|
||||||
|
interface StepInput {
|
||||||
|
items: {
|
||||||
|
inventory_item_id: string
|
||||||
|
required_quantity: number
|
||||||
|
quantity: number
|
||||||
|
location_ids: string[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const confirmInventoryStepId = "confirm-inventory-step"
|
||||||
|
export const confirmInventoryStep = createStep(
|
||||||
|
confirmInventoryStepId,
|
||||||
|
async (data: StepInput, { container }) => {
|
||||||
|
const inventoryService = container.resolve<IInventoryService>(
|
||||||
|
ModuleRegistrationName.INVENTORY
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Should be bulk
|
||||||
|
const promises = data.items.map((item) => {
|
||||||
|
const itemQuantity = item.required_quantity * item.quantity
|
||||||
|
|
||||||
|
return inventoryService.confirmInventory(
|
||||||
|
item.inventory_item_id,
|
||||||
|
item.location_ids,
|
||||||
|
itemQuantity
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const inventoryCoverage = await promiseAll(promises)
|
||||||
|
|
||||||
|
if (inventoryCoverage.some((hasCoverage) => !hasCoverage)) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
`Some variant does not have the required inventory`,
|
||||||
|
MedusaError.Codes.INSUFFICIENT_INVENTORY
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StepResponse(null)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export * from "./add-shipping-method-to-cart"
|
export * from "./add-shipping-method-to-cart"
|
||||||
export * from "./add-to-cart"
|
export * from "./add-to-cart"
|
||||||
|
export * from "./confirm-inventory"
|
||||||
export * from "./create-carts"
|
export * from "./create-carts"
|
||||||
export * from "./create-line-item-adjustments"
|
export * from "./create-line-item-adjustments"
|
||||||
export * from "./create-shipping-method-adjustments"
|
export * from "./create-shipping-method-adjustments"
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
|
||||||
|
interface ConfirmInventoryPreparationInput {
|
||||||
|
product_variant_inventory_items: {
|
||||||
|
variant_id: string
|
||||||
|
inventory_item_id: string
|
||||||
|
required_quantity: number
|
||||||
|
}[]
|
||||||
|
items: { variant_id?: string; quantity: number }[]
|
||||||
|
variants: { id: string; manage_inventory?: boolean }[]
|
||||||
|
location_ids: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConfirmInventoryItem {
|
||||||
|
inventory_item_id: string
|
||||||
|
required_quantity: number
|
||||||
|
quantity: number
|
||||||
|
location_ids: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const prepareConfirmInventoryInput = ({
|
||||||
|
product_variant_inventory_items,
|
||||||
|
location_ids,
|
||||||
|
items,
|
||||||
|
variants,
|
||||||
|
}: ConfirmInventoryPreparationInput) => {
|
||||||
|
if (!product_variant_inventory_items.length) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const variantsMap = new Map<
|
||||||
|
string,
|
||||||
|
{ id: string; manage_inventory?: boolean }
|
||||||
|
>(variants.map((v) => [v.id, v]))
|
||||||
|
|
||||||
|
const itemsToConfirm: ConfirmInventoryItem[] = []
|
||||||
|
|
||||||
|
items.forEach((item) => {
|
||||||
|
const variantInventoryItem = product_variant_inventory_items.find(
|
||||||
|
(i) => i.variant_id === item.variant_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!variantInventoryItem) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Variant ${item.variant_id} does not have any inventory items associated with it.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const variant = variantsMap.get(item.variant_id!)
|
||||||
|
|
||||||
|
if (variant?.manage_inventory) {
|
||||||
|
itemsToConfirm.push({
|
||||||
|
inventory_item_id: variantInventoryItem.inventory_item_id,
|
||||||
|
required_quantity: variantInventoryItem.required_quantity,
|
||||||
|
quantity: item.quantity,
|
||||||
|
location_ids: location_ids,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return itemsToConfirm
|
||||||
|
}
|
||||||
@@ -7,31 +7,95 @@ 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 {
|
import {
|
||||||
addToCartStep,
|
addToCartStep,
|
||||||
|
confirmInventoryStep,
|
||||||
getVariantPriceSetsStep,
|
getVariantPriceSetsStep,
|
||||||
getVariantsStep,
|
getVariantsStep,
|
||||||
validateVariantsExistStep,
|
validateVariantsExistStep,
|
||||||
} 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 { prepareLineItemData } from "../utils/prepare-line-item-data"
|
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
||||||
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:
|
||||||
// - Confirm inventory exists (inventory module)
|
|
||||||
// - Refresh/delete shipping methods (fulfillment module)
|
// - Refresh/delete shipping methods (fulfillment module)
|
||||||
|
|
||||||
export const addToCartWorkflowId = "add-to-cart"
|
export const addToCartWorkflowId = "add-to-cart"
|
||||||
export const addToCartWorkflow = createWorkflow(
|
export const addToCartWorkflow = createWorkflow(
|
||||||
addToCartWorkflowId,
|
addToCartWorkflowId,
|
||||||
(input: WorkflowData<AddToCartWorkflowInputDTO>) => {
|
(input: WorkflowData<AddToCartWorkflowInputDTO>) => {
|
||||||
const variantIds = validateVariantsExistStep({
|
const variantIds = transform({ input }, (data) => {
|
||||||
variantIds: transform({ input }, (data) => {
|
return (data.input.items ?? []).map((i) => i.variant_id)
|
||||||
return (data.input.items ?? []).map((i) => i.variant_id)
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
validateVariantsExistStep({ variantIds })
|
||||||
|
|
||||||
|
const variants = getVariantsStep({
|
||||||
|
filter: { id: variantIds },
|
||||||
|
config: {
|
||||||
|
select: [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"sku",
|
||||||
|
"barcode",
|
||||||
|
"product.id",
|
||||||
|
"product.title",
|
||||||
|
"product.description",
|
||||||
|
"product.subtitle",
|
||||||
|
"product.thumbnail",
|
||||||
|
"product.type",
|
||||||
|
"product.collection",
|
||||||
|
"product.handle",
|
||||||
|
],
|
||||||
|
relations: ["product"],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const salesChannelLocations = useRemoteQueryStep({
|
||||||
|
entry_point: "sales_channels",
|
||||||
|
fields: ["id", "name", "stock_locations.id", "stock_locations.name"],
|
||||||
|
variables: { id: input.cart.sales_channel_id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const productVariantInventoryItems = useRemoteQueryStep({
|
||||||
|
entry_point: "product_variant_inventory_items",
|
||||||
|
fields: ["variant_id", "inventory_item_id", "required_quantity"],
|
||||||
|
variables: { variant_id: variantIds },
|
||||||
|
}).config({ name: "inventory-items" })
|
||||||
|
|
||||||
|
const confirmInventoryInput = transform(
|
||||||
|
{ productVariantInventoryItems, salesChannelLocations, input, variants },
|
||||||
|
(data) => {
|
||||||
|
if (!data.salesChannelLocations.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Sales channel ${data.input.cart.sales_channel_id} is not associated with any stock locations.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = prepareConfirmInventoryInput({
|
||||||
|
product_variant_inventory_items: data.productVariantInventoryItems,
|
||||||
|
location_ids: data.salesChannelLocations[0].stock_locations.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)
|
||||||
|
|
||||||
// TODO: This is on par with the context used in v1.*, but we can be more flexible.
|
// TODO: This is on par with the context used in v1.*, but we can be more flexible.
|
||||||
const pricingContext = transform({ cart: input.cart }, (data) => {
|
const pricingContext = transform({ cart: input.cart }, (data) => {
|
||||||
return {
|
return {
|
||||||
@@ -46,31 +110,6 @@ export const addToCartWorkflow = createWorkflow(
|
|||||||
context: pricingContext,
|
context: pricingContext,
|
||||||
})
|
})
|
||||||
|
|
||||||
const variants = getVariantsStep(
|
|
||||||
transform({ variantIds }, (data) => {
|
|
||||||
return {
|
|
||||||
filter: { id: data.variantIds },
|
|
||||||
config: {
|
|
||||||
select: [
|
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"sku",
|
|
||||||
"barcode",
|
|
||||||
"product.id",
|
|
||||||
"product.title",
|
|
||||||
"product.description",
|
|
||||||
"product.subtitle",
|
|
||||||
"product.thumbnail",
|
|
||||||
"product.type",
|
|
||||||
"product.collection",
|
|
||||||
"product.handle",
|
|
||||||
],
|
|
||||||
relations: ["product"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const lineItems = transform({ priceSets, input, variants }, (data) => {
|
const lineItems = transform({ priceSets, 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)!
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ 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 {
|
import {
|
||||||
|
confirmInventoryStep,
|
||||||
createCartsStep,
|
createCartsStep,
|
||||||
findOneOrAnyRegionStep,
|
findOneOrAnyRegionStep,
|
||||||
findOrCreateCustomerStep,
|
findOrCreateCustomerStep,
|
||||||
@@ -16,11 +19,11 @@ 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 { prepareLineItemData } from "../utils/prepare-line-item-data"
|
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
||||||
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
import { refreshPaymentCollectionForCartStep } from "./refresh-payment-collection"
|
||||||
|
|
||||||
// TODO: The UpdateLineItemsWorkflow are missing the following steps:
|
// TODO: The createCartWorkflow are missing the following steps:
|
||||||
// - Confirm inventory exists (inventory module)
|
|
||||||
// - Refresh/delete shipping methods (fulfillment module)
|
// - Refresh/delete shipping methods (fulfillment module)
|
||||||
|
|
||||||
export const createCartWorkflowId = "create-cart"
|
export const createCartWorkflowId = "create-cart"
|
||||||
@@ -45,6 +48,73 @@ export const createCartWorkflow = createWorkflow(
|
|||||||
validateVariantsExistStep({ variantIds })
|
validateVariantsExistStep({ variantIds })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const variants = getVariantsStep({
|
||||||
|
filter: { id: variantIds },
|
||||||
|
config: {
|
||||||
|
select: [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"sku",
|
||||||
|
"manage_inventory",
|
||||||
|
"barcode",
|
||||||
|
"product.id",
|
||||||
|
"product.title",
|
||||||
|
"product.description",
|
||||||
|
"product.subtitle",
|
||||||
|
"product.thumbnail",
|
||||||
|
"product.type",
|
||||||
|
"product.collection",
|
||||||
|
"product.handle",
|
||||||
|
],
|
||||||
|
relations: ["product"],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const salesChannelLocations = useRemoteQueryStep({
|
||||||
|
entry_point: "sales_channels",
|
||||||
|
fields: ["id", "name", "stock_locations.id", "stock_locations.name"],
|
||||||
|
variables: { id: salesChannel.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const productVariantInventoryItems = useRemoteQueryStep({
|
||||||
|
entry_point: "product_variant_inventory_items",
|
||||||
|
fields: ["variant_id", "inventory_item_id", "required_quantity"],
|
||||||
|
variables: { variant_id: variantIds },
|
||||||
|
}).config({ name: "inventory-items" })
|
||||||
|
|
||||||
|
const confirmInventoryInput = transform(
|
||||||
|
{ productVariantInventoryItems, salesChannelLocations, input, variants },
|
||||||
|
(data) => {
|
||||||
|
// We don't want to confirm inventory if there are no items in the cart.
|
||||||
|
if (!data.input.items) {
|
||||||
|
return { items: [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.salesChannelLocations.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Sales channel ${data.input.sales_channel_id} is not associated with any stock locations.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = prepareConfirmInventoryInput({
|
||||||
|
product_variant_inventory_items: data.productVariantInventoryItems,
|
||||||
|
location_ids: data.salesChannelLocations[0].stock_locations.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)
|
||||||
|
|
||||||
// TODO: This is on par with the context used in v1.*, but we can be more flexible.
|
// TODO: This is on par with the context used in v1.*, but we can be more flexible.
|
||||||
const pricingContext = transform(
|
const pricingContext = transform(
|
||||||
{ input, region, customerData },
|
{ input, region, customerData },
|
||||||
@@ -84,31 +154,6 @@ export const createCartWorkflow = createWorkflow(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const variants = getVariantsStep(
|
|
||||||
transform({ variantIds }, (data) => {
|
|
||||||
return {
|
|
||||||
filter: { id: data.variantIds },
|
|
||||||
config: {
|
|
||||||
select: [
|
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"sku",
|
|
||||||
"barcode",
|
|
||||||
"product.id",
|
|
||||||
"product.title",
|
|
||||||
"product.description",
|
|
||||||
"product.subtitle",
|
|
||||||
"product.thumbnail",
|
|
||||||
"product.type",
|
|
||||||
"product.collection",
|
|
||||||
"product.handle",
|
|
||||||
],
|
|
||||||
relations: ["product"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const lineItems = transform({ priceSets, input, variants }, (data) => {
|
const lineItems = transform({ priceSets, 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)!
|
||||||
|
|||||||
@@ -4,15 +4,20 @@ import {
|
|||||||
createWorkflow,
|
createWorkflow,
|
||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import {
|
||||||
|
confirmInventoryStep,
|
||||||
|
getVariantPriceSetsStep,
|
||||||
|
getVariantsStep,
|
||||||
|
} from ".."
|
||||||
|
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
||||||
import { updateLineItemsStep } from "../../line-item/steps"
|
import { updateLineItemsStep } from "../../line-item/steps"
|
||||||
import { getVariantPriceSetsStep } from "../steps"
|
|
||||||
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
|
import { prepareConfirmInventoryInput } from "../utils/prepare-confirm-inventory-input"
|
||||||
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:
|
||||||
// - Confirm inventory exists (inventory module)
|
|
||||||
// - Validate shipping methods for new items (fulfillment module)
|
// - Validate shipping methods for new items (fulfillment module)
|
||||||
// - Refresh line item adjustments (promotion module)
|
|
||||||
|
|
||||||
export const updateLineItemInCartWorkflowId = "update-line-item-in-cart"
|
export const updateLineItemInCartWorkflowId = "update-line-item-in-cart"
|
||||||
export const updateLineItemInCartWorkflow = createWorkflow(
|
export const updateLineItemInCartWorkflow = createWorkflow(
|
||||||
@@ -32,6 +37,51 @@ export const updateLineItemInCartWorkflow = createWorkflow(
|
|||||||
data.input.item.variant_id!,
|
data.input.item.variant_id!,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const salesChannelLocations = useRemoteQueryStep({
|
||||||
|
entry_point: "sales_channels",
|
||||||
|
fields: ["id", "name", "stock_locations.id", "stock_locations.name"],
|
||||||
|
variables: { id: input.cart.sales_channel_id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const productVariantInventoryItems = useRemoteQueryStep({
|
||||||
|
entry_point: "product_variant_inventory_items",
|
||||||
|
fields: ["variant_id", "inventory_item_id", "required_quantity"],
|
||||||
|
variables: { variant_id: variantIds },
|
||||||
|
}).config({ name: "inventory-items" })
|
||||||
|
|
||||||
|
const variants = getVariantsStep({
|
||||||
|
filter: { id: variantIds },
|
||||||
|
config: { select: ["id", "manage_inventory"] },
|
||||||
|
})
|
||||||
|
|
||||||
|
const confirmInventoryInput = transform(
|
||||||
|
{ productVariantInventoryItems, salesChannelLocations, input, variants },
|
||||||
|
(data) => {
|
||||||
|
if (!data.salesChannelLocations.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Sales channel ${data.input.cart.sales_channel_id} is not associated with any stock locations.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = prepareConfirmInventoryInput({
|
||||||
|
product_variant_inventory_items: data.productVariantInventoryItems,
|
||||||
|
location_ids: data.salesChannelLocations[0].stock_locations.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)
|
||||||
|
|
||||||
const priceSets = getVariantPriceSetsStep({
|
const priceSets = getVariantPriceSetsStep({
|
||||||
variantIds,
|
variantIds,
|
||||||
context: pricingContext,
|
context: pricingContext,
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
import { InternalModuleDeclaration } from "@medusajs/modules-sdk"
|
import { InternalModuleDeclaration } from "@medusajs/modules-sdk"
|
||||||
import {
|
import {
|
||||||
Context,
|
Context,
|
||||||
|
DAL,
|
||||||
IInventoryServiceNext,
|
IInventoryServiceNext,
|
||||||
|
InventoryNext,
|
||||||
InventoryTypes,
|
InventoryTypes,
|
||||||
ModuleJoinerConfig,
|
ModuleJoinerConfig,
|
||||||
ModulesSdkTypes,
|
ModulesSdkTypes,
|
||||||
InventoryNext,
|
|
||||||
ReservationItemDTO,
|
ReservationItemDTO,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
|
CommonEvents,
|
||||||
EmitEvents,
|
EmitEvents,
|
||||||
|
InjectManager,
|
||||||
|
InjectTransactionManager,
|
||||||
|
InventoryEvents,
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
MedusaError,
|
MedusaError,
|
||||||
ModulesSdkUtils,
|
ModulesSdkUtils,
|
||||||
|
isDefined,
|
||||||
|
partitionArray,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
|
||||||
import { InventoryItem, InventoryLevel, ReservationItem } from "@models"
|
import { InventoryItem, InventoryLevel, ReservationItem } from "@models"
|
||||||
import { DAL } from "@medusajs/types"
|
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
||||||
import { InjectTransactionManager } from "@medusajs/utils"
|
|
||||||
import { InjectManager } from "@medusajs/utils"
|
|
||||||
import InventoryLevelService from "./inventory-level"
|
import InventoryLevelService from "./inventory-level"
|
||||||
import { partitionArray } from "@medusajs/utils"
|
|
||||||
import { InventoryEvents } from "@medusajs/utils"
|
|
||||||
import { CommonEvents } from "@medusajs/utils"
|
|
||||||
import { isDefined } from "@medusajs/utils"
|
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
baseRepository: DAL.RepositoryService
|
baseRepository: DAL.RepositoryService
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const SalesChannelLocation: ModuleJoinerConfig = {
|
|||||||
serviceName: LINKS.SalesChannelLocation,
|
serviceName: LINKS.SalesChannelLocation,
|
||||||
isLink: true,
|
isLink: true,
|
||||||
databaseConfig: {
|
databaseConfig: {
|
||||||
tableName: "sales_channel_locations",
|
tableName: "sales_channel_stock_location",
|
||||||
idPrefix: "scloc",
|
idPrefix: "scloc",
|
||||||
},
|
},
|
||||||
alias: [
|
alias: [
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import * as StockLocationModels from "@models"
|
|||||||
import * as StockLocationRepostiories from "@repositories"
|
import * as StockLocationRepostiories from "@repositories"
|
||||||
import * as StockLocationServices from "@services"
|
import * as StockLocationServices from "@services"
|
||||||
|
|
||||||
import { ModuleExports } from "@medusajs/types"
|
|
||||||
import { Modules } from "@medusajs/modules-sdk"
|
import { Modules } from "@medusajs/modules-sdk"
|
||||||
|
import { ModuleExports } from "@medusajs/types"
|
||||||
import { ModulesSdkUtils } from "@medusajs/utils"
|
import { ModulesSdkUtils } from "@medusajs/utils"
|
||||||
import { StockLocationModuleService } from "@services"
|
import { StockLocationModuleService } from "@services"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user