From e7cb76ab6e13fe756e090fd1a0a3ff645c30c69a Mon Sep 17 00:00:00 2001 From: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com> Date: Sun, 8 May 2022 16:12:31 +0200 Subject: [PATCH] fix: Cascade remove prices + option values on variant and product delete (#1465) --- .../api/__tests__/admin/product.js | 173 +++++++++++++++++- .../medusa/src/services/product-variant.ts | 2 +- packages/medusa/src/services/product.js | 2 +- 3 files changed, 174 insertions(+), 3 deletions(-) diff --git a/integration-tests/api/__tests__/admin/product.js b/integration-tests/api/__tests__/admin/product.js index df71a7530f..831a12296d 100644 --- a/integration-tests/api/__tests__/admin/product.js +++ b/integration-tests/api/__tests__/admin/product.js @@ -6,7 +6,7 @@ const { initDb, useDb } = require("../../../helpers/use-db") const adminSeeder = require("../../helpers/admin-seeder") const productSeeder = require("../../helpers/product-seeder") -const { ProductVariant } = require("@medusajs/medusa") +const { ProductVariant, ProductOptionValue, MoneyAmount } = require("@medusajs/medusa") const priceListSeeder = require("../../helpers/price-list-seeder") jest.setTimeout(50000) @@ -1737,6 +1737,177 @@ describe("/admin/products", () => { expect(variant).toEqual(undefined) }) + it("successfully deletes a product variant and its associated option values", async () => { + const api = useApi() + + // Validate that the option value exists + const optValPre = await dbConnection.manager.findOne(ProductOptionValue, { + variant_id: "test-variant_2", + }) + + expect(optValPre).not.toEqual(undefined) + + // Soft delete the variant + const response = await api.delete( + "/admin/products/test-product/variants/test-variant_2", + { + headers: { + Authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + // Validate that the option value was deleted + const optValPost = await dbConnection.manager.findOne( + ProductOptionValue, + { + variant_id: "test-variant_2", + } + ) + + expect(optValPost).toEqual(undefined) + + // Validate that the option still exists in the DB with deleted_at + const optValDeleted = await dbConnection.manager.findOne(ProductOptionValue, { + variant_id: "test-variant_2", + }, { + withDeleted: true, + }) + + expect(optValDeleted).toEqual(expect.objectContaining({ + deleted_at: expect.any(Date), + variant_id: "test-variant_2", + })) + }) + + it("successfully deletes a product and any option value associated with one of its variants", async () => { + const api = useApi() + + // Validate that the option value exists + const optValPre = await dbConnection.manager.findOne(ProductOptionValue, { + variant_id: "test-variant_2", + }) + + expect(optValPre).not.toEqual(undefined) + + // Soft delete the product + const response = await api.delete("/admin/products/test-product", { + headers: { + Authorization: "Bearer test_token", + }, + }) + + expect(response.status).toEqual(200) + + // Validate that the option value has been deleted + const optValPost = await dbConnection.manager.findOne( + ProductOptionValue, + { + variant_id: "test-variant_2", + } + ) + + expect(optValPost).toEqual(undefined) + + // Validate that the option still exists in the DB with deleted_at + const optValDeleted = await dbConnection.manager.findOne(ProductOptionValue, { + variant_id: "test-variant_2", + }, { + withDeleted: true, + }) + + expect(optValDeleted).toEqual(expect.objectContaining({ + deleted_at: expect.any(Date), + variant_id: "test-variant_2", + })) + }) + + it("successfully deletes a product variant and its associated prices", async () => { + const api = useApi() + + // Validate that the price exists + const pricePre = await dbConnection.manager.findOne(MoneyAmount, { + id: "test-price", + }) + + expect(pricePre).not.toEqual(undefined) + + // Soft delete the variant + const response = await api.delete( + "/admin/products/test-product/variants/test-variant", + { + headers: { + Authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + // Validate that the price was deleted + const pricePost = await dbConnection.manager.findOne( + MoneyAmount, + { + id: "test-price", + } + ) + + expect(pricePost).toEqual(undefined) + + // Validate that the price still exists in the DB with deleted_at + const optValDeleted = await dbConnection.manager.findOne(MoneyAmount, { + id: "test-price", + }, { + withDeleted: true, + }) + + expect(optValDeleted).toEqual(expect.objectContaining({ + deleted_at: expect.any(Date), + id: "test-price", + })) + }) + + it("successfully deletes a product and any prices associated with one of its variants", async () => { + const api = useApi() + + // Validate that the price exists + const pricePre = await dbConnection.manager.findOne(MoneyAmount, { + id: "test-price", + }) + + expect(pricePre).not.toEqual(undefined) + + // Soft delete the product + const response = await api.delete("/admin/products/test-product", { + headers: { + Authorization: "Bearer test_token", + }, + }) + + expect(response.status).toEqual(200) + + // Validate that the price has been deleted + const pricePost = await dbConnection.manager.findOne(MoneyAmount, { + id: "test-price", + }) + + expect(pricePost).toEqual(undefined) + + // Validate that the price still exists in the DB with deleted_at + const optValDeleted = await dbConnection.manager.findOne(MoneyAmount, { + id: "test-price", + }, { + withDeleted: true, + }) + + expect(optValDeleted).toEqual(expect.objectContaining({ + deleted_at: expect.any(Date), + id: "test-price", + })) + }) + it("successfully creates product with soft-deleted product handle and deletes it again", async () => { const api = useApi() diff --git a/packages/medusa/src/services/product-variant.ts b/packages/medusa/src/services/product-variant.ts index 62fe890150..2d8f6cf4af 100644 --- a/packages/medusa/src/services/product-variant.ts +++ b/packages/medusa/src/services/product-variant.ts @@ -751,7 +751,7 @@ class ProductVariantService extends BaseService { const variant = await variantRepo.findOne({ where: { id: variantId }, - relations: ["prices"], + relations: ["prices", "options"], }) if (!variant) { diff --git a/packages/medusa/src/services/product.js b/packages/medusa/src/services/product.js index 5e1da6caa8..b746e2e049 100644 --- a/packages/medusa/src/services/product.js +++ b/packages/medusa/src/services/product.js @@ -668,7 +668,7 @@ class ProductService extends BaseService { // Should not fail, if product does not exist, since delete is idempotent const product = await productRepo.findOne( { id: productId }, - { relations: ["variants"] } + { relations: ["variants", "variants.prices", "variants.options"] } ) if (!product) {