fix(medusa): Handle variant error during line item generation (#5145)
* fix(medusa): Handle variant error during line item generation * improve and tests * cleanup * update messages * Create few-masks-draw.md * change error type * fix unit tests
This commit is contained in:
committed by
GitHub
parent
889154c440
commit
6c808dd6d9
5
.changeset/few-masks-draw.md
Normal file
5
.changeset/few-masks-draw.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
fix(medusa): Handle variant error during line item generation
|
||||
@@ -4,6 +4,9 @@ import LineItemService from "../line-item"
|
||||
import { PricingServiceMock } from "../__mocks__/pricing"
|
||||
import { ProductVariantServiceMock } from "../__mocks__/product-variant"
|
||||
import { RegionServiceMock } from "../__mocks__/region"
|
||||
|
||||
const unknownVariantId = "unknown-variant"
|
||||
|
||||
;[true, false].forEach((isTaxInclusiveEnabled) => {
|
||||
describe(`tax inclusive flag set to: ${isTaxInclusiveEnabled}`, () => {
|
||||
describe("LineItemService", () => {
|
||||
@@ -480,16 +483,21 @@ describe("LineItemService", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("generate", () => {
|
||||
const lineItemRepository = MockRepository({
|
||||
create: (data) => data,
|
||||
})
|
||||
|
||||
const cartRepository = MockRepository({
|
||||
findOne: () =>
|
||||
Promise.resolve({
|
||||
region_id: IdMap.getId("test-region"),
|
||||
}),
|
||||
findOne: ({ id }) =>
|
||||
Promise.resolve(
|
||||
!id
|
||||
? null
|
||||
: {
|
||||
region_id: IdMap.getId("test-region"),
|
||||
}
|
||||
),
|
||||
})
|
||||
|
||||
const regionService = {
|
||||
@@ -521,16 +529,22 @@ describe("LineItemService", () => {
|
||||
},
|
||||
getRegionPrice: () => 100,
|
||||
list: jest.fn().mockImplementation(async (selector) => {
|
||||
return (selector.id || []).map((id) => {
|
||||
return {
|
||||
id,
|
||||
title: "Test variant",
|
||||
product: {
|
||||
title: "Test product",
|
||||
thumbnail: "",
|
||||
},
|
||||
}
|
||||
})
|
||||
return (selector.id || [])
|
||||
.map((id) => {
|
||||
if (id === unknownVariantId) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
title: "Test variant",
|
||||
product: {
|
||||
title: "Test product",
|
||||
thumbnail: "",
|
||||
},
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -570,6 +584,48 @@ describe("LineItemService", () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("should not succeed to generate a line item if a variant id is not provided", async () => {
|
||||
const err = await lineItemService
|
||||
.generate(
|
||||
[
|
||||
{
|
||||
variantId: "",
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
{
|
||||
region_id: IdMap.getId("test-region"),
|
||||
}
|
||||
)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(err).toBeDefined()
|
||||
expect(err.message).toEqual(
|
||||
"Unable to generate the line item because one or more required argument(s) are missing. Ensure a variant id is passed for each variant"
|
||||
)
|
||||
})
|
||||
|
||||
it("should not succeed to generate a line item if a variant id is not found", async () => {
|
||||
const err = await lineItemService
|
||||
.generate(
|
||||
[
|
||||
{
|
||||
variantId: unknownVariantId,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
{
|
||||
region_id: IdMap.getId("test-region"),
|
||||
}
|
||||
)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(err).toBeDefined()
|
||||
expect(err.message).toEqual(
|
||||
"Unable to generate the line items, some variant has not been found: unknown-variant"
|
||||
)
|
||||
})
|
||||
|
||||
it("successfully create a line item with tax inclusive set to false", async () => {
|
||||
await lineItemService.generate(
|
||||
IdMap.getId("test-variant"),
|
||||
|
||||
@@ -210,6 +210,7 @@ class LineItemService extends TransactionBaseService {
|
||||
quantity
|
||||
)
|
||||
|
||||
// Resolve data
|
||||
const data = isString(variantIdOrData)
|
||||
? {
|
||||
variantId: variantIdOrData,
|
||||
@@ -235,6 +236,7 @@ class LineItemService extends TransactionBaseService {
|
||||
resolvedData.map((d) => [d.variantId, d])
|
||||
)
|
||||
|
||||
// Retrieve variants
|
||||
const variants = await this.productVariantService_.list(
|
||||
{
|
||||
id: resolvedData.map((d) => d.variantId),
|
||||
@@ -244,6 +246,23 @@ class LineItemService extends TransactionBaseService {
|
||||
}
|
||||
)
|
||||
|
||||
// Validate that all variants has been found
|
||||
const inputDataVariantId = new Set(resolvedData.map((d) => d.variantId))
|
||||
const foundVariants = new Set(variants.map((v) => v.id))
|
||||
const notFoundVariants = new Set(
|
||||
[...inputDataVariantId].filter((x) => !foundVariants.has(x))
|
||||
)
|
||||
|
||||
if (notFoundVariants.size) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Unable to generate the line items, some variant has not been found: ${[
|
||||
...notFoundVariants,
|
||||
].join(", ")}`
|
||||
)
|
||||
}
|
||||
|
||||
// Prepare data to retrieve variant pricing
|
||||
const variantsMap = new Map<string, ProductVariant>()
|
||||
const variantsToCalculatePricingFor: {
|
||||
variantId: string
|
||||
@@ -277,6 +296,7 @@ class LineItemService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
// Generate line items
|
||||
const generatedItems: LineItem[] = []
|
||||
|
||||
for (const variantData of resolvedData) {
|
||||
@@ -601,22 +621,46 @@ class LineItemService extends TransactionBaseService {
|
||||
regionIdOrContext: T extends string ? string : GenerateLineItemContext,
|
||||
quantity?: number
|
||||
): void | never {
|
||||
const errorMessage =
|
||||
"Unable to generate the line item because one or more required argument(s) are missing"
|
||||
|
||||
if (isString(variantIdOrData)) {
|
||||
if (!quantity || !regionIdOrContext || !isString(regionIdOrContext)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNEXPECTED_STATE,
|
||||
"The generate method has been called with a variant id but one of the argument quantity or regionId is missing. Please, provide the variantId, quantity and regionId."
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`${errorMessage}. Ensure quantity, regionId, and variantId are passed`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const resolvedContext = regionIdOrContext as GenerateLineItemContext
|
||||
|
||||
if (!resolvedContext.region_id) {
|
||||
if (!variantIdOrData) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNEXPECTED_STATE,
|
||||
"The generate method has been called with the data but the context is missing either region_id or region. Please provide at least one of region or region_id."
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`${errorMessage}. Ensure variant id is passed`
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const resolvedContext = regionIdOrContext as GenerateLineItemContext
|
||||
|
||||
if (!resolvedContext?.region_id) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`${errorMessage}. Ensure region or region_id are passed`
|
||||
)
|
||||
}
|
||||
|
||||
const variantsData = Array.isArray(variantIdOrData)
|
||||
? variantIdOrData
|
||||
: [variantIdOrData]
|
||||
|
||||
const hasMissingVariantId = variantsData.some((d) => !d?.variantId)
|
||||
|
||||
if (hasMissingVariantId) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`${errorMessage}. Ensure a variant id is passed for each variant`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user