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:
1 parent
889154c440
commit
6c808dd6d9
3 files changed
+115
-10
No files matched your search
@@ -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 { PricingServiceMock } from "../__mocks__/pricing"
|
||||||
import { ProductVariantServiceMock } from "../__mocks__/product-variant"
|
import { ProductVariantServiceMock } from "../__mocks__/product-variant"
|
||||||
import { RegionServiceMock } from "../__mocks__/region"
|
import { RegionServiceMock } from "../__mocks__/region"
|
||||||
|
|
||||||
|
const unknownVariantId = "unknown-variant"
|
||||||
|
|
||||||
;[true, false].forEach((isTaxInclusiveEnabled) => {
|
;[true, false].forEach((isTaxInclusiveEnabled) => {
|
||||||
describe(`tax inclusive flag set to: ${isTaxInclusiveEnabled}`, () => {
|
describe(`tax inclusive flag set to: ${isTaxInclusiveEnabled}`, () => {
|
||||||
describe("LineItemService", () => {
|
describe("LineItemService", () => {
|
||||||
@@ -480,16 +483,21 @@ describe("LineItemService", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("generate", () => {
|
describe("generate", () => {
|
||||||
const lineItemRepository = MockRepository({
|
const lineItemRepository = MockRepository({
|
||||||
create: (data) => data,
|
create: (data) => data,
|
||||||
})
|
})
|
||||||
|
|
||||||
const cartRepository = MockRepository({
|
const cartRepository = MockRepository({
|
||||||
findOne: () =>
|
findOne: ({ id }) =>
|
||||||
Promise.resolve({
|
Promise.resolve(
|
||||||
|
!id
|
||||||
|
? null
|
||||||
|
: {
|
||||||
region_id: IdMap.getId("test-region"),
|
region_id: IdMap.getId("test-region"),
|
||||||
}),
|
}
|
||||||
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
const regionService = {
|
const regionService = {
|
||||||
@@ -521,7 +529,12 @@ describe("LineItemService", () => {
|
|||||||
},
|
},
|
||||||
getRegionPrice: () => 100,
|
getRegionPrice: () => 100,
|
||||||
list: jest.fn().mockImplementation(async (selector) => {
|
list: jest.fn().mockImplementation(async (selector) => {
|
||||||
return (selector.id || []).map((id) => {
|
return (selector.id || [])
|
||||||
|
.map((id) => {
|
||||||
|
if (id === unknownVariantId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
title: "Test variant",
|
title: "Test variant",
|
||||||
@@ -531,6 +544,7 @@ describe("LineItemService", () => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.filter(Boolean)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,6 +584,48 @@ describe("LineItemService", () => {
|
|||||||
jest.clearAllMocks()
|
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 () => {
|
it("successfully create a line item with tax inclusive set to false", async () => {
|
||||||
await lineItemService.generate(
|
await lineItemService.generate(
|
||||||
IdMap.getId("test-variant"),
|
IdMap.getId("test-variant"),
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ class LineItemService extends TransactionBaseService {
|
|||||||
quantity
|
quantity
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Resolve data
|
||||||
const data = isString(variantIdOrData)
|
const data = isString(variantIdOrData)
|
||||||
? {
|
? {
|
||||||
variantId: variantIdOrData,
|
variantId: variantIdOrData,
|
||||||
@@ -235,6 +236,7 @@ class LineItemService extends TransactionBaseService {
|
|||||||
resolvedData.map((d) => [d.variantId, d])
|
resolvedData.map((d) => [d.variantId, d])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Retrieve variants
|
||||||
const variants = await this.productVariantService_.list(
|
const variants = await this.productVariantService_.list(
|
||||||
{
|
{
|
||||||
id: resolvedData.map((d) => d.variantId),
|
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 variantsMap = new Map<string, ProductVariant>()
|
||||||
const variantsToCalculatePricingFor: {
|
const variantsToCalculatePricingFor: {
|
||||||
variantId: string
|
variantId: string
|
||||||
@@ -277,6 +296,7 @@ class LineItemService extends TransactionBaseService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate line items
|
||||||
const generatedItems: LineItem[] = []
|
const generatedItems: LineItem[] = []
|
||||||
|
|
||||||
for (const variantData of resolvedData) {
|
for (const variantData of resolvedData) {
|
||||||
@@ -601,22 +621,46 @@ class LineItemService extends TransactionBaseService {
|
|||||||
regionIdOrContext: T extends string ? string : GenerateLineItemContext,
|
regionIdOrContext: T extends string ? string : GenerateLineItemContext,
|
||||||
quantity?: number
|
quantity?: number
|
||||||
): void | never {
|
): void | never {
|
||||||
|
const errorMessage =
|
||||||
|
"Unable to generate the line item because one or more required argument(s) are missing"
|
||||||
|
|
||||||
if (isString(variantIdOrData)) {
|
if (isString(variantIdOrData)) {
|
||||||
if (!quantity || !regionIdOrContext || !isString(regionIdOrContext)) {
|
if (!quantity || !regionIdOrContext || !isString(regionIdOrContext)) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.UNEXPECTED_STATE,
|
MedusaError.Types.INVALID_DATA,
|
||||||
"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."
|
`${errorMessage}. Ensure quantity, regionId, and variantId are passed`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
if (!variantIdOrData) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`${errorMessage}. Ensure variant id is passed`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const resolvedContext = regionIdOrContext as GenerateLineItemContext
|
const resolvedContext = regionIdOrContext as GenerateLineItemContext
|
||||||
|
|
||||||
if (!resolvedContext.region_id) {
|
if (!resolvedContext?.region_id) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.UNEXPECTED_STATE,
|
MedusaError.Types.INVALID_DATA,
|
||||||
"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."
|
`${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