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:
Adrien de Peretti
2023-09-20 10:19:02 +02:00
committed by GitHub
parent 889154c440
commit 6c808dd6d9
3 changed files with 126 additions and 21 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
fix(medusa): Handle variant error during line item generation

View File

@@ -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"),

View File

@@ -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`
)
}
}
}