From 4b0119f7ceec10fdf3fb9921de6a50b7831e266c Mon Sep 17 00:00:00 2001 From: Stevche Radevski Date: Fri, 2 Aug 2024 17:55:47 +0200 Subject: [PATCH] fix: Don't remove pricing if no variant is passed to update (#8416) --- .../product/admin/product-import.spec.ts | 16 +++- .../__tests__/product/admin/product.spec.ts | 77 +++++++++++++++++++ .../steps/get-variant-ids-for-products.ts | 36 --------- .../src/product/workflows/update-products.ts | 34 +++++++- .../workflows/upsert-variant-prices.ts | 2 +- 5 files changed, 124 insertions(+), 41 deletions(-) delete mode 100644 packages/core/core-flows/src/product/steps/get-variant-ids-for-products.ts diff --git a/integration-tests/http/__tests__/product/admin/product-import.spec.ts b/integration-tests/http/__tests__/product/admin/product-import.spec.ts index 172f93011b..7a4753dd48 100644 --- a/integration-tests/http/__tests__/product/admin/product-import.spec.ts +++ b/integration-tests/http/__tests__/product/admin/product-import.spec.ts @@ -689,7 +689,21 @@ medusaIntegrationTestRunner({ barcode: "test-barcode-4", allow_backorder: false, manage_inventory: true, - prices: [], + prices: [ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + + expect.objectContaining({ + currency_code: "eur", + amount: 45, + }), + expect.objectContaining({ + currency_code: "dkk", + amount: 30, + }), + ], options: [ expect.objectContaining({ value: "Large", diff --git a/integration-tests/http/__tests__/product/admin/product.spec.ts b/integration-tests/http/__tests__/product/admin/product.spec.ts index 688b5a7c41..0765a8702d 100644 --- a/integration-tests/http/__tests__/product/admin/product.spec.ts +++ b/integration-tests/http/__tests__/product/admin/product.spec.ts @@ -1634,6 +1634,83 @@ medusaIntegrationTestRunner({ expect(response.data.product.images.length).toEqual(0) }) + it("updating the product without variants keeps the variants and prices intact", async () => { + const payload = { + title: "Test an update", + } + + await api + .post(`/admin/products/${baseProduct.id}`, payload, adminHeaders) + .catch((err) => { + console.log(err) + }) + + const updatedProduct = ( + await api.get(`/admin/products/${baseProduct.id}`, adminHeaders) + ).data.product + + expect(updatedProduct.variants).toEqual([ + expect.objectContaining({ + id: baseProduct.variants[0].id, + prices: expect.arrayContaining([ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + expect.objectContaining({ + currency_code: "eur", + amount: 45, + }), + expect.objectContaining({ + currency_code: "dkk", + amount: 30, + }), + ]), + }), + ]) + }) + + it("updating the product variants without prices keeps the prices intact", async () => { + const payload = { + title: "Test an update", + variants: baseProduct.variants.map((variant) => ({ + id: variant.id, + title: variant.id, + })), + } + + await api + .post(`/admin/products/${baseProduct.id}`, payload, adminHeaders) + .catch((err) => { + console.log(err) + }) + + const updatedProduct = ( + await api.get(`/admin/products/${baseProduct.id}`, adminHeaders) + ).data.product + + expect(updatedProduct.variants).toEqual([ + expect.objectContaining({ + id: baseProduct.variants[0].id, + title: baseProduct.variants[0].id, + prices: expect.arrayContaining([ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + expect.objectContaining({ + currency_code: "eur", + amount: 45, + }), + expect.objectContaining({ + currency_code: "dkk", + amount: 30, + }), + ]), + }), + ]) + }) + it("updates a product by deleting a field from metadata", async () => { const created = ( await api.post( diff --git a/packages/core/core-flows/src/product/steps/get-variant-ids-for-products.ts b/packages/core/core-flows/src/product/steps/get-variant-ids-for-products.ts deleted file mode 100644 index 7e1c053017..0000000000 --- a/packages/core/core-flows/src/product/steps/get-variant-ids-for-products.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { StepResponse, createStep } from "@medusajs/workflows-sdk" -import { UpdateProductsStepInput } from "./update-products" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" - -export const getVariantIdsForProductsStepId = "get-variant-ids-for-products" -export const getVariantIdsForProductsStep = createStep( - getVariantIdsForProductsStepId, - async (data: UpdateProductsStepInput, { container }) => { - const service = container.resolve( - ModuleRegistrationName.PRODUCT - ) - let filters = {} - if ("products" in data) { - if (!data.products.length) { - return new StepResponse([]) - } - - filters = { - id: data.products.map((p) => p.id), - } - } else { - filters = data.selector - } - - const products = await service.listProducts(filters, { - select: ["variants.id"], - relations: ["variants"], - take: null, - }) - - return new StepResponse( - products.flatMap((p) => p.variants.map((v) => v.id)) - ) - } -) diff --git a/packages/core/core-flows/src/product/workflows/update-products.ts b/packages/core/core-flows/src/product/workflows/update-products.ts index 1472c553ea..e0971cf96b 100644 --- a/packages/core/core-flows/src/product/workflows/update-products.ts +++ b/packages/core/core-flows/src/product/workflows/update-products.ts @@ -19,7 +19,6 @@ import { useRemoteQueryStep, } from "../../common" import { upsertVariantPricesWorkflow } from "./upsert-variant-prices" -import { getVariantIdsForProductsStep } from "../steps/get-variant-ids-for-products" type UpdateProductsStepInputSelector = { selector: ProductTypes.FilterableProductProps @@ -214,7 +213,36 @@ export const updateProductsWorkflowId = "update-products" export const updateProductsWorkflow = createWorkflow( updateProductsWorkflowId, (input: WorkflowData) => { - const previousVariantIds = getVariantIdsForProductsStep(input) + // We only get the variant ids of products that are updating the variants and prices. + const variantIdsSelector = transform({ input }, (data) => { + if ("products" in data.input) { + return { + filters: { + id: data.input.products + .filter((p) => !!p.variants) + .map((p) => p.id), + }, + } + } + + return { + filters: data.input.update?.variants ? data.input.selector : { id: [] }, + } + }) + const previousProductsWithVariants = useRemoteQueryStep({ + entry_point: "product", + fields: ["variants.id"], + variables: variantIdsSelector, + }).config({ name: "get-previous-products-variants-step" }) + + const previousVariantIds = transform( + { previousProductsWithVariants }, + (data) => { + return data.previousProductsWithVariants.flatMap((p) => + p.variants?.map((v) => v.id) + ) + } + ) const toUpdateInput = transform({ input }, prepareUpdateProductInput) const updatedProducts = updateProductsStep(toUpdateInput) @@ -237,7 +265,7 @@ export const updateProductsWorkflow = createWorkflow( entry_point: "product_sales_channel", fields: ["product_id", "sales_channel_id"], variables: { filters: { product_id: updatedProductIds } }, - }) + }).config({ name: "get-current-sales-channel-links-step" }) const toDeleteSalesChannelLinks = transform( { currentSalesChannelLinks }, diff --git a/packages/core/core-flows/src/product/workflows/upsert-variant-prices.ts b/packages/core/core-flows/src/product/workflows/upsert-variant-prices.ts index d1bed23686..7c289a0732 100644 --- a/packages/core/core-flows/src/product/workflows/upsert-variant-prices.ts +++ b/packages/core/core-flows/src/product/workflows/upsert-variant-prices.ts @@ -72,7 +72,7 @@ export const upsertVariantPricesWorkflow = createWorkflow( .map((v) => { const priceSetId = linksMap.get(v.variant_id) - if (!priceSetId) { + if (!priceSetId || !v.prices) { return }