diff --git a/packages/modules/product/integration-tests/__tests__/product-module-service/products.spec.ts b/packages/modules/product/integration-tests/__tests__/product-module-service/products.spec.ts index 84c1427906..4271c828de 100644 --- a/packages/modules/product/integration-tests/__tests__/product-module-service/products.spec.ts +++ b/packages/modules/product/integration-tests/__tests__/product-module-service/products.spec.ts @@ -300,6 +300,169 @@ moduleIntegrationTestRunner({ ) }) + it("should upsert variants (update one and create one)", async () => { + let [product] = await service.createProducts([ + { + title: "New product", + description: "New description", + options: [ + { title: "size", values: ["x", "l"] }, + { title: "color", values: ["red", "green"] }, + ], + variants: [ + { + title: "new variant 1", + options: { size: "l", color: "red" }, + }, + { + title: "new variant 2", + options: { size: "l", color: "green" }, + }, + ], + }, + ]) + + product = await service.retrieveProduct(product.id, { + relations: [ + "options", + "options.values", + "variants", + "variants.options", + ], + }) + + expect(product).toEqual( + expect.objectContaining({ + title: "New product", + description: "New description", + options: expect.arrayContaining([ + expect.objectContaining({ + title: "size", + values: expect.arrayContaining([ + expect.objectContaining({ + value: "x", + }), + expect.objectContaining({ + value: "l", + }), + ]), + }), + expect.objectContaining({ + title: "color", + values: expect.arrayContaining([ + expect.objectContaining({ + value: "red", + }), + expect.objectContaining({ + value: "green", + }), + ]), + }), + ]), + variants: expect.arrayContaining([ + expect.objectContaining({ + title: "new variant 1", + options: expect.arrayContaining([ + expect.objectContaining({ + value: "l", + }), + expect.objectContaining({ + value: "red", + }), + ]), + }), + expect.objectContaining({ + title: "new variant 2", + options: expect.arrayContaining([ + expect.objectContaining({ + value: "l", + }), + expect.objectContaining({ + value: "green", + }), + ]), + }), + ]), + }) + ) + + const existingVariant1 = product.variants.find( + (v) => v.title === "new variant 1" + ) + + const existingVariant2 = product.variants.find( + (v) => v.title === "new variant 2" + ) + + await service.upsertProductVariants([ + { + id: existingVariant1.id, + product_id: product.id, + title: "updated variant 1", + options: { size: "x", color: "red" }, // update options + }, + { + id: existingVariant2.id, + title: "new variant 2", + options: { size: "l", color: "green" }, // just preserve old one + }, + { + product_id: product.id, + title: "created variant 3", + options: { size: "x", color: "green" }, // create a new variant + }, + ]) + + product = await service.retrieveProduct(product.id, { + relations: [ + "options", + "options.values", + "variants", + "variants.options", + ], + }) + + expect(product.variants).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: existingVariant1.id, + title: "updated variant 1", + options: expect.arrayContaining([ + expect.objectContaining({ + value: "x", + }), + expect.objectContaining({ + value: "red", + }), + ]), + }), + expect.objectContaining({ + id: existingVariant2.id, + title: "new variant 2", + options: expect.arrayContaining([ + expect.objectContaining({ + value: "l", + }), + expect.objectContaining({ + value: "green", + }), + ]), + }), + expect.objectContaining({ + title: "created variant 3", + options: expect.arrayContaining([ + expect.objectContaining({ + value: "x", + }), + expect.objectContaining({ + value: "green", + }), + ]), + }), + ]) + ) + }) + it("should preserve option and value identity on update", async () => { const productBefore = await service.retrieveProduct(productTwo.id, { relations: [ diff --git a/packages/modules/product/src/services/product-module-service.ts b/packages/modules/product/src/services/product-module-service.ts index 1a8201a1ea..628887674f 100644 --- a/packages/modules/product/src/services/product-module-service.ts +++ b/packages/modules/product/src/services/product-module-service.ts @@ -380,10 +380,12 @@ export default class ProductModuleService productOptions ) - ProductModuleService.checkIfVariantWithOptionsAlreadyExists( - productVariantsWithOptions as any, - allVariants - ) + if (data.some((d) => !!d.options)) { + ProductModuleService.checkIfVariantWithOptionsAlreadyExists( + productVariantsWithOptions as any, + allVariants + ) + } const { entities: productVariants, performedActions } = await this.productVariantService_.upsertWithReplace( @@ -1819,7 +1821,7 @@ export default class ProductModuleService protected static checkIfVariantWithOptionsAlreadyExists( data: (( | ProductTypes.CreateProductVariantDTO - | ProductTypes.UpdateProductVariantDTO + | UpdateProductVariantInput ) & { options: { id: string }[]; product_id: string })[], variants: ProductVariant[] ) { @@ -1832,6 +1834,10 @@ export default class ProductModuleService return false } + if ((variantData as UpdateProductVariantInput)?.id === v.id) { + return false + } + return (variantData.options as unknown as { id: string }[])!.every( (optionValue) => { const variantOptionValue = v.options.find(