Skip to content

Commit

Permalink
Merge branch 'develop' into feat/stripe-payment-processor
Browse files Browse the repository at this point in the history
  • Loading branch information
olivermrbl authored Feb 28, 2023
2 parents f5993c9 + d61d6c7 commit 3534810
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-pans-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---

fix(medusa): Account for multiple inventory items when getting inventory
16 changes: 11 additions & 5 deletions packages/medusa/src/api/routes/admin/variants/get-inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
} from "../../../../types/inventory"
import ProductVariantInventoryService from "../../../../services/product-variant-inventory"
import {
SalesChannelInventoryService,
SalesChannelLocationService,
SalesChannelService,
} from "../../../../services"
Expand Down Expand Up @@ -75,6 +76,8 @@ export default async (req, res) => {
const channelLocationService: SalesChannelLocationService = req.scope.resolve(
"salesChannelLocationService"
)
const salesChannelInventoryService: SalesChannelInventoryService =
req.scope.resolve("salesChannelInventoryService")
const channelService: SalesChannelService = req.scope.resolve(
"salesChannelService"
)
Expand Down Expand Up @@ -106,11 +109,13 @@ export default async (req, res) => {
})
)

const variantInventoryItems =
await productVariantInventoryService.listByVariant(variant.id)

const inventory =
await productVariantInventoryService.listInventoryItemsByVariant(variant.id)
responseVariant.inventory = await joinLevels(inventory, [], inventoryService)

// TODO: adjust for required quantity
if (inventory.length) {
responseVariant.sales_channel_availability = await Promise.all(
channels.map(async (channel) => {
Expand All @@ -122,10 +127,11 @@ export default async (req, res) => {
}
}

const quantity = await inventoryService.retrieveAvailableQuantity(
inventory[0].id,
channel.locations
)
const quantity =
await productVariantInventoryService.getVariantQuantityFromVariantInventoryItems(
variantInventoryItems,
channel.id
)

return {
channel_name: channel.name as string,
Expand Down
76 changes: 52 additions & 24 deletions packages/medusa/src/services/product-variant-inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class ProductVariantInventoryService extends TransactionBaseService {
* @param variantId variant id
* @returns variant inventory items for the variant id
*/
private async listByVariant(
public async listByVariant(
variantId: string | string[]
): Promise<ProductVariantInventoryItem[]> {
const variantInventoryRepo = this.activeManager_.getRepository(
Expand Down Expand Up @@ -615,30 +615,11 @@ class ProductVariantInventoryService extends TransactionBaseService {
// first get all inventory items required for a variant
const variantInventory = await this.listByVariant(variant.id)

const salesChannelInventoryServiceTx =
this.salesChannelInventoryService_.withTransaction(
this.activeManager_
variant.inventory_quantity =
await this.getVariantQuantityFromVariantInventoryItems(
variantInventory,
salesChannelId
)
// the inventory quantity of the variant should be equal to the inventory
// item with the smallest stock, adjusted for quantity required to fulfill
// the given variant
variant.inventory_quantity = Math.min(
...(await Promise.all(
variantInventory.map(async (variantInventory) => {
// get the total available quantity for the given sales channel
// divided by the required quantity to account for how many of the
// variant we can fulfill at the current time. Take the minimum we
// can fulfill and set that as quantity
return (
// eslint-disable-next-line max-len
(await salesChannelInventoryServiceTx.retrieveAvailableItemQuantity(
salesChannelId,
variantInventory.inventory_item_id
)) / variantInventory.required_quantity
)
})
))
)

return variant
})
Expand All @@ -664,6 +645,53 @@ class ProductVariantInventoryService extends TransactionBaseService {
})
)
}

/**
* Get the quantity of a variant from a list of variantInventoryItems
* The inventory quantity of the variant should be equal to the inventory
* item with the smallest stock, adjusted for quantity required to fulfill
* the given variant.
*
* @param variantInventoryItems List of inventoryItems for a given variant, These must all be for the same variant
* @param channelId Sales channel id to fetch availability for
* @returns The available quantity of the variant from the inventoryItems
*/
async getVariantQuantityFromVariantInventoryItems(
variantInventoryItems: ProductVariantInventoryItem[],
channelId: string
): Promise<number> {
const variantItemsAreMixed = variantInventoryItems.some(
(inventoryItem) =>
inventoryItem.variant_id !== variantInventoryItems[0].variant_id
)

if (variantInventoryItems.length && variantItemsAreMixed) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"All variant inventory items must belong to the same variant"
)
}

return Math.min(
...(await Promise.all(
variantInventoryItems.map(async (variantInventory) => {
// get the total available quantity for the given sales channel
// divided by the required quantity to account for how many of the
// variant we can fulfill at the current time. Take the minimum we
// can fulfill and set that as quantity
return (
// eslint-disable-next-line max-len
(await this.salesChannelInventoryService_
.withTransaction(this.activeManager_)
.retrieveAvailableItemQuantity(
channelId,
variantInventory.inventory_item_id
)) / variantInventory.required_quantity
)
})
))
)
}
}

export default ProductVariantInventoryService

0 comments on commit 3534810

Please sign in to comment.