feat(medusa,stock-location,inventory): Integration tests (#3149)

This commit is contained in:
Carlos R. L. Rodrigues
2023-02-06 09:02:43 -03:00
committed by GitHub
parent 71fdd28198
commit 923ccece24
17 changed files with 2019 additions and 32 deletions

View File

@@ -0,0 +1,270 @@
const path = require("path")
const { bootstrapApp } = require("../../../../helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../helpers/use-db")
const { setPort, useApi } = require("../../../../helpers/use-api")
const adminSeeder = require("../../../helpers/admin-seeder")
const cartSeeder = require("../../../helpers/cart-seeder")
const { simpleProductFactory } = require("../../../../api/factories")
const { simpleSalesChannelFactory } = require("../../../../api/factories")
jest.setTimeout(30000)
const adminHeaders = { headers: { Authorization: "Bearer test_token" } }
describe("/store/carts", () => {
let express
let appContainer
let dbConnection
let variantId
let inventoryItemId
let locationId
const doAfterEach = async () => {
const db = useDb()
return await db.teardown()
}
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
const { container, app, port } = await bootstrapApp({ cwd })
appContainer = container
setPort(port)
express = app.listen(port, (err) => {
process.send(port)
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
express.close()
})
afterEach(async () => {
jest.clearAllMocks()
const db = useDb()
return await db.teardown()
})
describe("POST /store/carts/:id", () => {
beforeEach(async () => {
await simpleSalesChannelFactory(dbConnection, {
id: "test-channel",
is_default: true,
})
await adminSeeder(dbConnection)
await cartSeeder(dbConnection, { sales_channel_id: "test-channel" })
await simpleProductFactory(
dbConnection,
{
id: "product1",
sales_channels: [{ id: "test-channel" }],
variants: [],
},
100
)
const api = useApi()
// Add payment provider
await api.post(
`/admin/regions/test-region/payment-providers`,
{
provider_id: "test-pay",
},
adminHeaders
)
const prodVarInventoryService = appContainer.resolve(
"productVariantInventoryService"
)
const response = await api.post(
`/admin/products/product1/variants`,
{
title: "Test Variant w. inventory",
sku: "MY_SKU",
material: "material",
origin_country: "UK",
hs_code: "hs001",
mid_code: "mids",
weight: 300,
length: 100,
height: 200,
width: 150,
options: [
{
option_id: "product1-option",
value: "SS",
},
],
manage_inventory: true,
prices: [{ currency_code: "usd", amount: 2300 }],
},
adminHeaders
)
const variant = response.data.product.variants[0]
variantId = variant.id
const inventoryItems =
await prodVarInventoryService.listInventoryItemsByVariant(variantId)
inventoryItemId = inventoryItems[0].id
// Add Stock location
const stockRes = await api.post(
`/admin/stock-locations`,
{
name: "Fake Warehouse",
},
adminHeaders
)
locationId = stockRes.data.stock_location.id
// Add stock level
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: locationId,
stocked_quantity: 5,
},
adminHeaders
)
// Associate Stock Location with sales channel
await api.post(
`/admin/sales-channels/test-channel/stock-locations`,
{
location_id: locationId,
},
adminHeaders
)
})
afterEach(async () => {
await doAfterEach()
})
it("reserve quantity when completing the cart", async () => {
const api = useApi()
const cartId = "test-cart"
// Add standard line item to cart
await api.post(
`/store/carts/${cartId}/line-items`,
{
variant_id: variantId,
quantity: 3,
},
{ withCredentials: true }
)
await api.post(`/store/carts/${cartId}/payment-sessions`)
await api.post(`/store/carts/${cartId}/payment-session`, {
provider_id: "test-pay",
})
const getRes = await api.post(`/store/carts/${cartId}/complete`)
expect(getRes.status).toEqual(200)
expect(getRes.data.type).toEqual("order")
const inventoryService = appContainer.resolve("inventoryService")
const stockLevel = await inventoryService.retrieveInventoryLevel(
inventoryItemId,
locationId
)
expect(stockLevel.location_id).toEqual(locationId)
expect(stockLevel.inventory_item_id).toEqual(inventoryItemId)
expect(stockLevel.reserved_quantity).toEqual(3)
expect(stockLevel.stocked_quantity).toEqual(5)
})
it("fails to add a item on the cart if the inventory isn't enough", async () => {
const api = useApi()
const cartId = "test-cart"
// Add standard line item to cart
const addCart = await api
.post(
`/store/carts/${cartId}/line-items`,
{
variant_id: variantId,
quantity: 6,
},
{ withCredentials: true }
)
.catch((e) => e)
expect(addCart.response.status).toEqual(400)
expect(addCart.response.data.code).toEqual("insufficient_inventory")
expect(addCart.response.data.message).toEqual(
`Variant with id: ${variantId} does not have the required inventory`
)
})
it("fails to complete cart with items inventory not covered", async () => {
const api = useApi()
const cartId = "test-cart"
// Add standard line item to cart
await api.post(
`/store/carts/${cartId}/line-items`,
{
variant_id: variantId,
quantity: 5,
},
{ withCredentials: true }
)
await api.post(`/store/carts/${cartId}/payment-sessions`)
await api.post(`/store/carts/${cartId}/payment-session`, {
provider_id: "test-pay",
})
// Another proccess reserves items before the cart is completed
const inventoryService = appContainer.resolve("inventoryService")
inventoryService.createReservationItem({
line_item_id: "line_item_123",
inventory_item_id: inventoryItemId,
location_id: locationId,
quantity: 2,
})
const completeCartRes = await api
.post(`/store/carts/${cartId}/complete`)
.catch((e) => e)
expect(completeCartRes.response.status).toEqual(409)
expect(completeCartRes.response.data.code).toEqual(
"insufficient_inventory"
)
expect(completeCartRes.response.data.message).toEqual(
`Variant with id: ${variantId} does not have the required inventory`
)
const stockLevel = await inventoryService.retrieveInventoryLevel(
inventoryItemId,
locationId
)
expect(stockLevel.location_id).toEqual(locationId)
expect(stockLevel.inventory_item_id).toEqual(inventoryItemId)
expect(stockLevel.reserved_quantity).toEqual(2)
expect(stockLevel.stocked_quantity).toEqual(5)
})
})
})

View File

@@ -0,0 +1,366 @@
const path = require("path")
const { bootstrapApp } = require("../../../../helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../helpers/use-db")
const { setPort, useApi } = require("../../../../helpers/use-api")
const adminSeeder = require("../../../helpers/admin-seeder")
jest.setTimeout(30000)
const { simpleProductFactory } = require("../../../factories")
const adminHeaders = { headers: { Authorization: "Bearer test_token" } }
describe("Inventory Items endpoints", () => {
let appContainer
let dbConnection
let express
let variantId
let inventoryItems
let locationId
let location2Id
let location3Id
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
const { container, app, port } = await bootstrapApp({ cwd })
appContainer = container
setPort(port)
express = app.listen(port, (err) => {
process.send(port)
})
})
beforeEach(async () => {
// create inventory item
await adminSeeder(dbConnection)
const api = useApi()
await simpleProductFactory(
dbConnection,
{
id: "test-product",
variants: [],
},
100
)
const prodVarInventoryService = appContainer.resolve(
"productVariantInventoryService"
)
const response = await api.post(
`/admin/products/test-product/variants`,
{
title: "Test Variant w. inventory",
sku: "MY_SKU",
material: "material",
origin_country: "UK",
hs_code: "hs001",
mid_code: "mids",
weight: 300,
length: 100,
height: 200,
width: 150,
manage_inventory: true,
options: [
{
option_id: "test-product-option",
value: "SS",
},
],
prices: [{ currency_code: "usd", amount: 2300 }],
},
adminHeaders
)
const variant = response.data.product.variants[0]
variantId = variant.id
inventoryItems = await prodVarInventoryService.listInventoryItemsByVariant(
variantId
)
const stockRes = await api.post(
`/admin/stock-locations`,
{
name: "Fake Warehouse",
},
adminHeaders
)
locationId = stockRes.data.stock_location.id
const secondStockRes = await api.post(
`/admin/stock-locations`,
{
name: "Another random Warehouse",
},
adminHeaders
)
location2Id = secondStockRes.data.stock_location.id
const thirdStockRes = await api.post(
`/admin/stock-locations`,
{
name: "Another random Warehouse",
},
adminHeaders
)
location3Id = thirdStockRes.data.stock_location.id
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
express.close()
})
afterEach(async () => {
jest.clearAllMocks()
const db = useDb()
return await db.teardown()
})
describe("Inventory Items", () => {
it("Create, update and delete inventory location level", async () => {
const api = useApi()
const inventoryItemId = inventoryItems[0].id
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: locationId,
stocked_quantity: 17,
incoming_quantity: 2,
},
adminHeaders
)
const inventoryService = appContainer.resolve("inventoryService")
const stockLevel = await inventoryService.retrieveInventoryLevel(
inventoryItemId,
locationId
)
expect(stockLevel.location_id).toEqual(locationId)
expect(stockLevel.inventory_item_id).toEqual(inventoryItemId)
expect(stockLevel.stocked_quantity).toEqual(17)
expect(stockLevel.incoming_quantity).toEqual(2)
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}`,
{
stocked_quantity: 21,
incoming_quantity: 0,
},
adminHeaders
)
const newStockLevel = await inventoryService.retrieveInventoryLevel(
inventoryItemId,
locationId
)
expect(newStockLevel.stocked_quantity).toEqual(21)
expect(newStockLevel.incoming_quantity).toEqual(0)
await api.delete(
`/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}`,
adminHeaders
)
const invLevel = await inventoryService
.retrieveInventoryLevel(inventoryItemId, locationId)
.catch((e) => e)
expect(invLevel.message).toEqual(
`Inventory level for item ${inventoryItemId} and location ${locationId} not found`
)
})
it("Update inventory item", async () => {
const api = useApi()
const inventoryItemId = inventoryItems[0].id
const response = await api.post(
`/admin/inventory-items/${inventoryItemId}`,
{
mid_code: "updated mid_code",
weight: 120,
},
adminHeaders
)
expect(response.data.inventory_item).toEqual(
expect.objectContaining({
origin_country: "UK",
hs_code: "hs001",
mid_code: "updated mid_code",
weight: 120,
length: 100,
height: 200,
width: 150,
})
)
})
it("Retrieve an inventory item", async () => {
const api = useApi()
const inventoryItemId = inventoryItems[0].id
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: locationId,
stocked_quantity: 15,
incoming_quantity: 5,
},
adminHeaders
)
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: location2Id,
stocked_quantity: 7,
incoming_quantity: 0,
},
adminHeaders
)
const response = await api.get(
`/admin/inventory-items/${inventoryItemId}`,
adminHeaders
)
expect(response.data).toEqual({
inventory_item: expect.objectContaining({
height: 200,
hs_code: "hs001",
id: inventoryItemId,
length: 100,
location_levels: [
expect.objectContaining({
available_quantity: 15,
deleted_at: null,
id: expect.any(String),
incoming_quantity: 5,
inventory_item_id: inventoryItemId,
location_id: locationId,
metadata: null,
reserved_quantity: 0,
stocked_quantity: 15,
}),
expect.objectContaining({
available_quantity: 7,
deleted_at: null,
id: expect.any(String),
incoming_quantity: 0,
inventory_item_id: inventoryItemId,
location_id: location2Id,
metadata: null,
reserved_quantity: 0,
stocked_quantity: 7,
}),
],
material: "material",
metadata: null,
mid_code: "mids",
origin_country: "UK",
requires_shipping: true,
sku: "MY_SKU",
weight: 300,
width: 150,
}),
})
})
it("List inventory items", async () => {
const api = useApi()
const inventoryItemId = inventoryItems[0].id
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: location2Id,
stocked_quantity: 10,
},
adminHeaders
)
await api.post(
`/admin/inventory-items/${inventoryItemId}/location-levels`,
{
location_id: location3Id,
stocked_quantity: 5,
},
adminHeaders
)
const response = await api.get(`/admin/inventory-items`, adminHeaders)
expect(response.data.inventory_items).toEqual([
expect.objectContaining({
id: inventoryItemId,
sku: "MY_SKU",
origin_country: "UK",
hs_code: "hs001",
mid_code: "mids",
material: "material",
weight: 300,
length: 100,
height: 200,
width: 150,
requires_shipping: true,
metadata: null,
variants: expect.arrayContaining([
expect.objectContaining({
id: variantId,
title: "Test Variant w. inventory",
product_id: "test-product",
sku: "MY_SKU",
manage_inventory: true,
hs_code: "hs001",
origin_country: "UK",
mid_code: "mids",
material: "material",
weight: 300,
length: 100,
height: 200,
width: 150,
metadata: null,
product: expect.objectContaining({
id: "test-product",
}),
}),
]),
location_levels: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
inventory_item_id: inventoryItemId,
location_id: location2Id,
stocked_quantity: 10,
reserved_quantity: 0,
incoming_quantity: 0,
metadata: null,
available_quantity: 10,
}),
expect.objectContaining({
id: expect.any(String),
inventory_item_id: inventoryItemId,
location_id: location3Id,
stocked_quantity: 5,
reserved_quantity: 0,
incoming_quantity: 0,
metadata: null,
available_quantity: 5,
}),
]),
}),
])
})
})
})

View File

@@ -0,0 +1,173 @@
const path = require("path")
const { bootstrapApp } = require("../../../../helpers/bootstrap-app")
const { initDb, useDb } = require("../../../../helpers/use-db")
const { setPort, useApi } = require("../../../../helpers/use-api")
const {
ProductVariantInventoryService,
ProductVariantService,
} = require("@medusajs/medusa")
const adminSeeder = require("../../../helpers/admin-seeder")
jest.setTimeout(30000)
const { simpleProductFactory } = require("../../../factories")
describe("Create Variant", () => {
let appContainer
let dbConnection
let express
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
const { container, app, port } = await bootstrapApp({ cwd })
appContainer = container
setPort(port)
express = app.listen(port, (err) => {
process.send(port)
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
express.close()
})
afterEach(async () => {
jest.clearAllMocks()
const db = useDb()
return await db.teardown()
})
describe("Inventory Items", () => {
it("When creating a new product variant it should create an Inventory Item", async () => {
await adminSeeder(dbConnection)
const api = useApi()
await simpleProductFactory(
dbConnection,
{
id: "test-product",
variants: [{ id: "test-variant" }],
},
100
)
const response = await api.post(
`/admin/products/test-product/variants`,
{
title: "Test Variant w. inventory",
sku: "MY_SKU",
material: "material",
origin_country: "UK",
hs_code: "hs001",
mid_code: "mids",
weight: 300,
length: 100,
height: 200,
width: 150,
manage_inventory: true,
options: [
{
option_id: "test-product-option",
value: "SS",
},
],
prices: [{ currency_code: "usd", amount: 2300 }],
},
{ headers: { Authorization: "Bearer test_token" } }
)
expect(response.status).toEqual(200)
const variantId = response.data.product.variants.find(
(v) => v.id !== "test-variant"
).id
const variantInventoryService = appContainer.resolve(
"productVariantInventoryService"
)
const inventory =
await variantInventoryService.listInventoryItemsByVariant(variantId)
expect(inventory).toHaveLength(1)
expect(inventory).toEqual([
expect.objectContaining({
origin_country: "UK",
hs_code: "hs001",
mid_code: "mids",
weight: 300,
length: 100,
height: 200,
width: 150,
}),
])
})
it("When creating a new variant fails, it should revert all the transaction", async () => {
await adminSeeder(dbConnection)
const api = useApi()
await simpleProductFactory(
dbConnection,
{
id: "test-product",
variants: [{ id: "test-variant" }],
},
100
)
jest
.spyOn(ProductVariantInventoryService.prototype, "attachInventoryItem")
.mockImplementation(() => {
throw new Error("Failure while attaching inventory item")
})
const prodVariantDeleteMock = jest.spyOn(
ProductVariantService.prototype,
"delete"
)
const error = await api
.post(
`/admin/products/test-product/variants`,
{
title: "Test Variant w. inventory",
sku: "MY_SKU",
material: "material",
origin_country: "UK",
hs_code: "hs001",
mid_code: "mids",
weight: 300,
length: 100,
height: 200,
width: 150,
manage_inventory: true,
options: [
{
option_id: "test-product-option",
value: "SS",
},
],
prices: [{ currency_code: "usd", amount: 2300 }],
},
{ headers: { Authorization: "Bearer test_token" } }
)
.catch((e) => e)
expect(error.response.status).toEqual(400)
expect(error.response.data.message).toEqual(
"Failure while attaching inventory item"
)
expect(prodVariantDeleteMock).toHaveBeenCalledTimes(1)
})
})
})

View File

@@ -0,0 +1,717 @@
const path = require("path")
const { bootstrapApp } = require("../../../helpers/bootstrap-app")
const { initDb, useDb } = require("../../../helpers/use-db")
jest.setTimeout(30000)
describe("Inventory Module", () => {
let appContainer
let dbConnection
let express
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
const { container, app, port } = await bootstrapApp({ cwd })
appContainer = container
express = app.listen(port, (err) => {
process.send(port)
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
express.close()
})
afterEach(async () => {
const db = useDb()
return await db.teardown()
})
describe("Inventory Module Interface", () => {
it("createInventoryItem", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
origin_country: "CH",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
metadata: {
abc: 123,
},
hs_code: "hs_code 123",
requires_shipping: true,
})
expect(inventoryItem).toEqual(
expect.objectContaining({
id: expect.any(String),
sku: "sku_1",
origin_country: "CH",
hs_code: "hs_code 123",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
requires_shipping: true,
metadata: { abc: 123 },
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
})
it("updateInventoryItem", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const item = await inventoryService.createInventoryItem({
sku: "sku_1",
origin_country: "CH",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
metadata: {
abc: 123,
},
hs_code: "hs_code 123",
requires_shipping: true,
})
const updatedInventoryItem = await inventoryService.updateInventoryItem(
item.id,
{
origin_country: "CZ",
mid_code: "mid code 345",
material: "lycra and polyester",
weight: 500,
metadata: {
dce: 456,
},
}
)
expect(updatedInventoryItem).toEqual(
expect.objectContaining({
id: item.id,
sku: item.sku,
origin_country: "CZ",
hs_code: item.hs_code,
mid_code: "mid code 345",
material: "lycra and polyester",
weight: 500,
length: item.length,
height: item.height,
width: item.width,
requires_shipping: true,
metadata: { dce: 456 },
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
})
it("deleteInventoryItem and retrieveInventoryItem", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const item = await inventoryService.createInventoryItem({
sku: "sku_1",
origin_country: "CH",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
metadata: {
abc: 123,
},
hs_code: "hs_code 123",
requires_shipping: true,
})
await inventoryService.deleteInventoryItem(item.id)
const deletedItem = inventoryService.retrieveInventoryItem(item.id)
await expect(deletedItem).rejects.toThrow(
`InventoryItem with id ${item.id} was not found`
)
})
it("createInventoryLevel", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
origin_country: "CH",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
metadata: {
abc: 123,
},
hs_code: "hs_code 123",
requires_shipping: true,
})
const inventoryLevel = await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: "location_123",
stocked_quantity: 50,
reserved_quantity: 15,
incoming_quantity: 4,
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: "second_location",
stocked_quantity: 10,
reserved_quantity: 1,
})
expect(inventoryLevel).toEqual(
expect.objectContaining({
id: expect.any(String),
incoming_quantity: 4,
inventory_item_id: inventoryItem.id,
location_id: "location_123",
metadata: null,
reserved_quantity: 15,
stocked_quantity: 50,
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
expect(
await inventoryService.retrieveStockedQuantity(inventoryItem.id, [
"location_123",
])
).toEqual(50)
expect(
await inventoryService.retrieveAvailableQuantity(inventoryItem.id, [
"location_123",
])
).toEqual(35)
expect(
await inventoryService.retrieveReservedQuantity(inventoryItem.id, [
"location_123",
])
).toEqual(15)
expect(
await inventoryService.retrieveStockedQuantity(inventoryItem.id, [
"location_123",
"second_location",
])
).toEqual(60)
expect(
await inventoryService.retrieveAvailableQuantity(inventoryItem.id, [
"location_123",
"second_location",
])
).toEqual(44)
expect(
await inventoryService.retrieveReservedQuantity(inventoryItem.id, [
"location_123",
"second_location",
])
).toEqual(16)
})
it("updateInventoryLevel", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
origin_country: "CH",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
metadata: {
abc: 123,
},
hs_code: "hs_code 123",
requires_shipping: true,
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: "location_123",
stocked_quantity: 50,
reserved_quantity: 0,
incoming_quantity: 0,
})
const updatedLevel = await inventoryService.updateInventoryLevel(
inventoryItem.id,
"location_123",
{
stocked_quantity: 25,
reserved_quantity: 4,
incoming_quantity: 10,
}
)
expect(updatedLevel).toEqual(
expect.objectContaining({
id: expect.any(String),
incoming_quantity: 10,
inventory_item_id: inventoryItem.id,
location_id: "location_123",
metadata: null,
reserved_quantity: 4,
stocked_quantity: 25,
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
})
it("deleteInventoryLevel", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
origin_country: "CH",
mid_code: "mid code",
material: "lycra",
weight: 100,
length: 200,
height: 50,
width: 50,
metadata: {
abc: 123,
},
hs_code: "hs_code 123",
requires_shipping: true,
})
const inventoryLevel = await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: "location_123",
stocked_quantity: 50,
reserved_quantity: 0,
incoming_quantity: 0,
})
await inventoryService.deleteInventoryLevel(
inventoryItem.id,
"location_123"
)
const deletedLevel = inventoryService.retrieveInventoryLevel(
inventoryItem.id,
"location_123"
)
await expect(deletedLevel).rejects.toThrow(
`Inventory level for item ${inventoryItem.id} and location location_123 not found`
)
})
it("createReservationItem", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const locationId = "location_123"
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
})
const tryReserve = inventoryService.createReservationItem({
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 10,
metadata: {
abc: 123,
},
})
await expect(tryReserve).rejects.toThrow(
`Item ${inventoryItem.id} is not stocked at location ${locationId}`
)
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 50,
reserved_quantity: 0,
incoming_quantity: 0,
})
const inventoryReservation = await inventoryService.createReservationItem(
{
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 10,
metadata: {
abc: 123,
},
}
)
expect(inventoryReservation).toEqual(
expect.objectContaining({
id: expect.any(String),
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 10,
metadata: { abc: 123 },
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
const [available, reserved] = await Promise.all([
inventoryService.retrieveAvailableQuantity(inventoryItem.id, [
locationId,
]),
inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId),
])
expect(available).toEqual(40)
expect(reserved).toEqual(10)
})
it("updateReservationItem", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const locationId = "location_123"
const newLocationId = "location_new"
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 50,
reserved_quantity: 0,
incoming_quantity: 0,
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: newLocationId,
stocked_quantity: 20,
reserved_quantity: 5,
incoming_quantity: 0,
})
const inventoryReservation = await inventoryService.createReservationItem(
{
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 15,
metadata: {
abc: 123,
},
}
)
const [available, reserved] = await Promise.all([
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
locationId
),
inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId),
])
expect(available).toEqual(35)
expect(reserved).toEqual(15)
const updatedReservation = await inventoryService.updateReservationItem(
inventoryReservation.id,
{
quantity: 5,
}
)
expect(updatedReservation).toEqual(
expect.objectContaining({
id: expect.any(String),
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 5,
metadata: { abc: 123 },
})
)
const [newAvailable, newReserved] = await Promise.all([
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
locationId
),
inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId),
])
expect(newAvailable).toEqual(45)
expect(newReserved).toEqual(5)
const updatedReservationLocation =
await inventoryService.updateReservationItem(inventoryReservation.id, {
quantity: 12,
location_id: newLocationId,
})
expect(updatedReservationLocation).toEqual(
expect.objectContaining({
id: expect.any(String),
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: newLocationId,
quantity: 12,
metadata: { abc: 123 },
})
)
const [
oldLocationAvailable,
oldLocationReserved,
newLocationAvailable,
newLocationReserved,
] = await Promise.all([
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
locationId
),
inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId),
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
newLocationId
),
inventoryService.retrieveReservedQuantity(
inventoryItem.id,
newLocationId
),
])
expect(oldLocationAvailable).toEqual(50)
expect(oldLocationReserved).toEqual(0)
expect(newLocationAvailable).toEqual(3)
expect(newLocationReserved).toEqual(17)
})
it("deleteReservationItem and deleteReservationItemsByLineItem", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const locationId = "location_123"
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 10,
})
const inventoryReservation = await inventoryService.createReservationItem(
{
line_item_id: "line_item_123",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 1,
}
)
for (let quant = 1; quant <= 3; quant++) {
await inventoryService.createReservationItem({
line_item_id: "line_item_444",
inventory_item_id: inventoryItem.id,
location_id: locationId,
quantity: 1,
})
}
const [available, reserved] = await Promise.all([
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
locationId
),
inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId),
])
expect(available).toEqual(6)
expect(reserved).toEqual(4)
await inventoryService.deleteReservationItemsByLineItem("line_item_444")
const [afterDeleteLineitemAvailable, afterDeleteLineitemReserved] =
await Promise.all([
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
locationId
),
inventoryService.retrieveReservedQuantity(
inventoryItem.id,
locationId
),
])
expect(afterDeleteLineitemAvailable).toEqual(9)
expect(afterDeleteLineitemReserved).toEqual(1)
await inventoryService.deleteReservationItem(inventoryReservation.id)
const [afterDeleteReservationAvailable, afterDeleteReservationReserved] =
await Promise.all([
inventoryService.retrieveAvailableQuantity(
inventoryItem.id,
locationId
),
inventoryService.retrieveReservedQuantity(
inventoryItem.id,
locationId
),
])
expect(afterDeleteReservationAvailable).toEqual(10)
expect(afterDeleteReservationReserved).toEqual(0)
})
it("confirmInventory", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const locationId = "location_123"
const secondLocationId = "location_551"
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 10,
reserved_quantity: 5,
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: secondLocationId,
stocked_quantity: 6,
reserved_quantity: 1,
})
expect(
await inventoryService.confirmInventory(inventoryItem.id, locationId, 5)
).toBeTruthy()
expect(
await inventoryService.confirmInventory(
inventoryItem.id,
[locationId, secondLocationId],
10
)
).toBeTruthy()
expect(
await inventoryService.confirmInventory(inventoryItem.id, locationId, 6)
).toBeFalsy()
expect(
await inventoryService.confirmInventory(
inventoryItem.id,
[locationId, secondLocationId],
11
)
).toBeFalsy()
})
it("adjustInventory", async () => {
const inventoryService = appContainer.resolve("inventoryService")
const locationId = "location_123"
const secondLocationId = "location_551"
const inventoryItem = await inventoryService.createInventoryItem({
sku: "sku_1",
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 10,
reserved_quantity: 5,
})
await inventoryService.createInventoryLevel({
inventory_item_id: inventoryItem.id,
location_id: secondLocationId,
stocked_quantity: 6,
reserved_quantity: 1,
})
expect(
await inventoryService.adjustInventory(inventoryItem.id, locationId, -5)
).toEqual(
expect.objectContaining({
id: expect.any(String),
inventory_item_id: inventoryItem.id,
location_id: locationId,
stocked_quantity: 5,
reserved_quantity: 5,
incoming_quantity: 0,
metadata: null,
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
expect(
await inventoryService.adjustInventory(
inventoryItem.id,
secondLocationId,
-10
)
).toEqual(
expect.objectContaining({
id: expect.any(String),
inventory_item_id: inventoryItem.id,
location_id: secondLocationId,
stocked_quantity: -4,
reserved_quantity: 1,
incoming_quantity: 0,
metadata: null,
deleted_at: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
})
})
})

View File

@@ -368,7 +368,7 @@ Object {
"height": null,
"hs_code": null,
"id": "test-variant",
"inventory_quantity": 11,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -486,7 +486,7 @@ Object {
"height": null,
"hs_code": null,
"id": "test-variant",
"inventory_quantity": 11,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -670,7 +670,7 @@ Object {
"height": null,
"hs_code": null,
"id": "test-variant",
"inventory_quantity": 11,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -836,7 +836,7 @@ Object {
"height": null,
"hs_code": null,
"id": "test-variant",
"inventory_quantity": 12,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -2022,7 +2022,7 @@ Object {
"height": null,
"hs_code": null,
"id": "variant-2",
"inventory_quantity": 9,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -2130,7 +2130,7 @@ Object {
"height": null,
"hs_code": null,
"id": "test-variant",
"inventory_quantity": 9,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -2252,7 +2252,7 @@ Object {
"height": null,
"hs_code": null,
"id": "variant-2",
"inventory_quantity": 9,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,
@@ -2368,7 +2368,7 @@ Object {
"height": null,
"hs_code": null,
"id": "variant-2",
"inventory_quantity": 9,
"inventory_quantity": 10,
"length": null,
"manage_inventory": true,
"material": null,

View File

@@ -0,0 +1,271 @@
const path = require("path")
const { bootstrapApp } = require("../../../helpers/bootstrap-app")
const { initDb, useDb } = require("../../../helpers/use-db")
jest.setTimeout(30000)
describe("Inventory Module", () => {
let appContainer
let dbConnection
let express
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
const { container, app, port } = await bootstrapApp({ cwd })
appContainer = container
express = app.listen(port, (err) => {
process.send(port)
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
express.close()
})
afterEach(async () => {
const db = useDb()
return await db.teardown()
})
describe("Stock Location Module Interface", () => {
it("create", async () => {
const stockLocationService = appContainer.resolve("stockLocationService")
expect(
await stockLocationService.create({
name: "first location",
})
).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "first location",
deleted_at: null,
address_id: null,
metadata: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
})
)
expect(
await stockLocationService.create({
name: "second location",
metadata: {
extra: "abc",
},
address: {
address_1: "addr_1",
address_2: "line 2",
country_code: "DK",
city: "city",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: {
abc: 123,
},
},
})
).toEqual(
expect.objectContaining({
id: expect.any(String),
name: "second location",
metadata: {
extra: "abc",
},
address_id: expect.any(String),
})
)
})
it("update", async () => {
const stockLocationService = appContainer.resolve("stockLocationService")
const loc = await stockLocationService.create({
name: "location",
address: {
address_1: "addr_1",
address_2: "line 2",
country_code: "DK",
city: "city",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: {
abc: 123,
},
},
})
const addressId = loc.address_id
expect(
await stockLocationService.retrieve(loc.id, {
relations: ["address"],
})
).toEqual(
expect.objectContaining({
id: loc.id,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
name: "location",
address_id: addressId,
metadata: null,
address: expect.objectContaining({
id: addressId,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
address_1: "addr_1",
address_2: "line 2",
company: null,
city: "city",
country_code: "DK",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: { abc: 123 },
}),
})
)
expect(
await stockLocationService.update(loc.id, {
name: "location name",
address_id: addressId,
address: {
address_1: "addr_1 updated",
country_code: "US",
},
})
).toEqual(
expect.objectContaining({
id: loc.id,
name: "location name",
address_id: addressId,
})
)
expect(
await stockLocationService.retrieve(loc.id, {
relations: ["address"],
})
).toEqual(
expect.objectContaining({
id: loc.id,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
name: "location name",
address_id: addressId,
metadata: null,
address: expect.objectContaining({
id: addressId,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
address_1: "addr_1 updated",
address_2: "line 2",
company: null,
city: "city",
country_code: "US",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: { abc: 123 },
}),
})
)
})
it("updateAddress", async () => {
const stockLocationService = appContainer.resolve("stockLocationService")
const loc = await stockLocationService.create({
name: "location",
address: {
address_1: "addr_1",
address_2: "line 2",
country_code: "DK",
city: "city",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: {
abc: 123,
},
},
})
const addressId = loc.address_id
expect(
await stockLocationService.updateAddress(addressId, {
address_1: "addr_1 updated",
country_code: "US",
})
).toEqual(
expect.objectContaining({
id: addressId,
address_1: "addr_1 updated",
address_2: "line 2",
country_code: "US",
city: "city",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: {
abc: 123,
},
})
)
expect(
await stockLocationService.retrieve(loc.id, {
relations: ["address"],
})
).toEqual(
expect.objectContaining({
id: loc.id,
address_id: addressId,
address: expect.objectContaining({
id: addressId,
address_1: "addr_1 updated",
}),
})
)
})
it("delete", async () => {
const stockLocationService = appContainer.resolve("stockLocationService")
const loc = await stockLocationService.create({
name: "location",
address: {
address_1: "addr_1",
address_2: "line 2",
country_code: "DK",
city: "city",
phone: "111222333",
province: "province",
postal_code: "555-714",
metadata: {
abc: 123,
},
},
})
await stockLocationService.delete(loc.id)
const deletedItem = stockLocationService.retrieve(loc.id)
await expect(deletedItem).rejects.toThrow(
`StockLocation with id ${loc.id} was not found`
)
})
})
})

View File

@@ -17,6 +17,8 @@ const {
} = require("@medusajs/medusa")
module.exports = async (connection, data = {}) => {
const salesChannelId = data?.sales_channel_id
const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))(
new Date()
)
@@ -240,7 +242,7 @@ module.exports = async (connection, data = {}) => {
is_disabled: false,
starts_at: tenDaysAgo,
ends_at: tenDaysFromToday,
valid_duration: "P1M", //one month
valid_duration: "P1M", // one month
})
DynamicDiscount.regions = [r]
@@ -381,6 +383,7 @@ module.exports = async (connection, data = {}) => {
const cart = manager.create(Cart, {
id: "test-cart",
customer_id: "some-customer",
sales_channel_id: salesChannelId,
email: "some-customer@email.com",
shipping_address: {
id: "test-shipping-address",
@@ -397,6 +400,7 @@ module.exports = async (connection, data = {}) => {
const cart2 = manager.create(Cart, {
id: "test-cart-2",
customer_id: "some-customer",
sales_channel_id: salesChannelId,
email: "some-customer@email.com",
shipping_address: {
id: "test-shipping-address",
@@ -413,6 +417,7 @@ module.exports = async (connection, data = {}) => {
id: "swap-cart",
type: "swap",
customer_id: "some-customer",
sales_channel_id: salesChannelId,
email: "some-customer@email.com",
shipping_address: {
id: "test-shipping-address",

View File

@@ -28,4 +28,16 @@ module.exports = {
jwt_secret: "test",
cookie_secret: "test",
},
modules: {
stockLocationService: {
scope: "internal",
resources: "shared",
resolve: "@medusajs/stock-location",
},
inventoryService: {
scope: "internal",
resources: "shared",
resolve: "@medusajs/inventory",
},
},
}

View File

@@ -223,8 +223,12 @@ export default class InventoryLevelService extends TransactionBaseService {
*/
async getStockedQuantity(
inventoryItemId: string,
locationIds: string[]
locationIds: string[] | string
): Promise<number> {
if (!Array.isArray(locationIds)) {
locationIds = [locationIds]
}
const manager = this.getManager()
const levelRepository = manager.getRepository(InventoryLevel)
@@ -235,7 +239,7 @@ export default class InventoryLevelService extends TransactionBaseService {
.andWhere("location_id IN (:...locationIds)", { locationIds })
.getRawOne()
return result.quantity
return parseFloat(result.quantity)
}
/**
@@ -246,8 +250,12 @@ export default class InventoryLevelService extends TransactionBaseService {
*/
async getAvailableQuantity(
inventoryItemId: string,
locationIds: string[]
locationIds: string[] | string
): Promise<number> {
if (!Array.isArray(locationIds)) {
locationIds = [locationIds]
}
const manager = this.getManager()
const levelRepository = manager.getRepository(InventoryLevel)
@@ -258,7 +266,7 @@ export default class InventoryLevelService extends TransactionBaseService {
.andWhere("location_id IN (:...locationIds)", { locationIds })
.getRawOne()
return result.quantity
return parseFloat(result.quantity)
}
/**
@@ -269,8 +277,12 @@ export default class InventoryLevelService extends TransactionBaseService {
*/
async getReservedQuantity(
inventoryItemId: string,
locationIds: string[]
locationIds: string[] | string
): Promise<number> {
if (!Array.isArray(locationIds)) {
locationIds = [locationIds]
}
const manager = this.getManager()
const levelRepository = manager.getRepository(InventoryLevel)
@@ -281,6 +293,6 @@ export default class InventoryLevelService extends TransactionBaseService {
.andWhere("location_id IN (:...locationIds)", { locationIds })
.getRawOne()
return result.quantity
return parseFloat(result.quantity)
}
}

View File

@@ -173,8 +173,31 @@ export default class ReservationItemService extends TransactionBaseService {
const shouldUpdateQuantity =
isDefined(data.quantity) && data.quantity !== item.quantity
const shouldUpdateLocation =
isDefined(data.location_id) &&
isDefined(data.quantity) &&
data.location_id !== item.location_id
const ops: Promise<unknown>[] = []
if (shouldUpdateQuantity) {
if (shouldUpdateLocation) {
ops.push(
this.inventoryLevelService_
.withTransaction(manager)
.adjustReservedQuantity(
item.inventory_item_id,
item.location_id,
item.quantity * -1
),
this.inventoryLevelService_
.withTransaction(manager)
.adjustReservedQuantity(
item.inventory_item_id,
data.location_id!,
data.quantity!
)
)
} else if (shouldUpdateQuantity) {
const quantityDiff = data.quantity! - item.quantity
ops.push(
this.inventoryLevelService_

View File

@@ -12,9 +12,9 @@ export const buildLevelsByInventoryItemId = (
inventoryLevels: InventoryLevelDTO[],
locationIds: string[]
) => {
const filteredLevels = inventoryLevels.filter((level) =>
locationIds?.includes(level.location_id)
)
const filteredLevels = inventoryLevels.filter((level) => {
return !locationIds.length || locationIds.includes(level.location_id)
})
return filteredLevels.reduce((acc, level) => {
acc[level.inventory_item_id] = acc[level.inventory_item_id] ?? []
@@ -58,6 +58,7 @@ export const joinLevels = async (
locationIds,
inventoryService
)
return inventoryItems.map((inventoryItem) => ({
...inventoryItem,
location_levels: levelsByItemId[inventoryItem.id] || [],

View File

@@ -82,12 +82,7 @@ export const createVariantTransaction = async (
const productVariantServiceTx = productVariantService.withTransaction(manager)
async function createVariant(variantInput: CreateProductVariantInput) {
const variant = await productVariantServiceTx.create(
productId,
variantInput
)
return { variant }
return await productVariantServiceTx.create(productId, variantInput)
}
async function removeVariant(variant: ProductVariant) {
@@ -101,7 +96,7 @@ export const createVariantTransaction = async (
return
}
const inventoryItem = await inventoryServiceTx!.createInventoryItem({
return await inventoryServiceTx!.createInventoryItem({
sku: variant.sku,
origin_country: variant.origin_country,
hs_code: variant.hs_code,
@@ -112,8 +107,6 @@ export const createVariantTransaction = async (
height: variant.height,
width: variant.width,
})
return { inventoryItem }
}
async function removeInventoryItem(inventoryItem: InventoryItemDTO) {

View File

@@ -0,0 +1,93 @@
export const InventoryServiceMock = {
withTransaction: function () {
return this
},
listInventoryItems: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
listReservationItems: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
listInventoryLevels: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
retrieveInventoryItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
retrieveInventoryLevel: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
createReservationItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
createInventoryItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
createInventoryLevel: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
updateInventoryLevel: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
updateInventoryItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
updateReservationItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
deleteReservationItemsByLineItem: jest
.fn()
.mockImplementation((id, config) => {
return Promise.resolve()
}),
deleteReservationItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
deleteInventoryItem: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
deleteInventoryLevel: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
adjustInventory: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
confirmInventory: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
retrieveAvailableQuantity: jest.fn().mockImplementation((id, config) => {
return Promise.resolve(10)
}),
retrieveStockedQuantity: jest.fn().mockImplementation((id, config) => {
return Promise.resolve(9)
}),
retrieveReservedQuantity: jest.fn().mockImplementation((id, config) => {
return Promise.resolve(1)
}),
}
const mock = jest.fn().mockImplementation(() => {
return InventoryServiceMock
})
export default mock

View File

@@ -0,0 +1,46 @@
import { IdMap } from "medusa-test-utils"
export const StockLocationServiceMock = {
withTransaction: function () {
return this
},
retrieve: jest.fn().mockImplementation((id, config) => {
return Promise.resolve({
id: id,
name: "stock location 1 name",
})
}),
update: jest.fn().mockImplementation((id, data) => {
return Promise.resolve({ id, ...data })
}),
listAndCount: jest.fn().mockImplementation(() => {
return Promise.resolve([
[
{
id: IdMap.getId("stock_location_1"),
name: "stock location 1 name",
},
],
1,
])
}),
create: jest.fn().mockImplementation((data) => {
return Promise.resolve({
id: id,
...data,
})
}),
delete: jest.fn().mockImplementation((id, config) => {
return Promise.resolve()
}),
}
const mock = jest.fn().mockImplementation(() => {
return StockLocationServiceMock
})
export default mock

View File

@@ -69,11 +69,17 @@ class SalesChannelLocationService extends TransactionBaseService {
const salesChannel = await this.salesChannelService_
.withTransaction(manager)
.retrieve(salesChannelId)
const stockLocation = await this.stockLocationService.retrieve(locationId)
const stockLocationId = locationId
if (this.stockLocationService) {
const stockLocation = await this.stockLocationService.retrieve(locationId)
locationId = stockLocation.id
}
const salesChannelLocation = manager.create(SalesChannelLocation, {
sales_channel_id: salesChannel.id,
location_id: stockLocation.id,
location_id: stockLocationId,
})
await manager.save(salesChannelLocation)

View File

@@ -209,7 +209,6 @@ export type CreateInventoryItemInput = {
}
export type CreateReservationItemInput = {
type?: string
line_item_id?: string
inventory_item_id: string
location_id: string

View File

@@ -199,7 +199,7 @@ export default class StockLocationService extends TransactionBaseService {
}
}
const { metadata, ...fields } = updateData
const { metadata, ...fields } = data
const toSave = locationRepo.merge(item, fields)
if (metadata) {