diff --git a/.changeset/fuzzy-ears-look.md b/.changeset/fuzzy-ears-look.md new file mode 100644 index 0000000000000..6d3e77cffb3e2 --- /dev/null +++ b/.changeset/fuzzy-ears-look.md @@ -0,0 +1,8 @@ +--- +"@medusajs/pricing": patch +"@medusajs/types": patch +"@medusajs/utils": patch +--- + +feat(pricing, types): add soft deletion for money-amounts +feat(utils): cascade soft delete across 1:1 relationships \ No newline at end of file diff --git a/.changeset/smart-zoos-nail.md b/.changeset/smart-zoos-nail.md new file mode 100644 index 0000000000000..c8438cb4e8f0a --- /dev/null +++ b/.changeset/smart-zoos-nail.md @@ -0,0 +1,6 @@ +--- +"@medusajs/medusa": patch +"medusa-payment-stripe": patch +--- + +fix(medusa, medusa-payment-stripe): fix stripe error handling diff --git a/.github/workflows/test-cli-with-database.yml b/.github/workflows/test-cli-with-database.yml index 0a2eb01b0c79d..400b89e8ae933 100644 --- a/.github/workflows/test-cli-with-database.yml +++ b/.github/workflows/test-cli-with-database.yml @@ -45,6 +45,7 @@ jobs: uses: ./.github/actions/setup-server with: cache-extension: "cli-test" + node-version: "16.14" - name: Install Medusa cli run: npm i -g @medusajs/medusa-cli diff --git a/packages/medusa-payment-stripe/src/core/stripe-base.ts b/packages/medusa-payment-stripe/src/core/stripe-base.ts index 454bce3133d98..0cdd4b2beedd4 100644 --- a/packages/medusa-payment-stripe/src/core/stripe-base.ts +++ b/packages/medusa-payment-stripe/src/core/stripe-base.ts @@ -322,16 +322,16 @@ abstract class StripeBase extends AbstractPaymentProcessor { protected buildError( message: string, - e: Stripe.StripeRawError | PaymentProcessorError | Error + error: Stripe.StripeRawError | PaymentProcessorError | Error ): PaymentProcessorError { return { error: message, - code: "code" in e ? e.code : "", - detail: isPaymentProcessorError(e) - ? `${e.error}${EOL}${e.detail ?? ""}` - : "detail" in e - ? e.detail - : e.message ?? "", + code: "code" in error ? error.code : "unknown", + detail: isPaymentProcessorError(error) + ? `${error.error}${EOL}${error.detail ?? ""}` + : "detail" in error + ? error.detail + : error.message ?? "", } } } diff --git a/packages/medusa/src/interfaces/payment-processor.ts b/packages/medusa/src/interfaces/payment-processor.ts index 97ac9771e4a13..fd6cb9ecc7886 100644 --- a/packages/medusa/src/interfaces/payment-processor.ts +++ b/packages/medusa/src/interfaces/payment-processor.ts @@ -777,5 +777,5 @@ export abstract class AbstractPaymentProcessor implements PaymentProcessor { export function isPaymentProcessorError( obj: any ): obj is PaymentProcessorError { - return obj && typeof obj === "object" && (obj.error || obj.code || obj.detail) + return obj && typeof obj === "object" && obj.error && obj.code && obj.detail } diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts index 010dd0521980e..2b8fd005c8e50 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts @@ -6,6 +6,11 @@ import { initialize } from "../../../../src" import { createCurrencies } from "../../../__fixtures__/currency" import { createMoneyAmounts } from "../../../__fixtures__/money-amount" import { DB_URL, MikroOrmWrapper } from "../../../utils" +import { createPriceSetMoneyAmounts } from "../../../__fixtures__/price-set-money-amount" +import { createPriceSets } from "../../../__fixtures__/price-set" +import { createRuleTypes } from "../../../__fixtures__/rule-type" +import { createPriceRules } from "../../../__fixtures__/price-rule" +import { createPriceSetMoneyAmountRules } from "../../../__fixtures__/price-set-money-amount-rules" jest.setTimeout(30000) @@ -264,6 +269,94 @@ describe("PricingModule Service - MoneyAmount", () => { }) }) + describe("softDeleteMoneyAmounts", () => { + const id = "money-amount-USD" + + it("should softDelete priceSetMoneyAmount and PriceRule when soft-deleting money amount", async () => { + await createPriceSets(testManager) + await createRuleTypes(testManager) + await createPriceSetMoneyAmounts(testManager) + await createPriceRules(testManager) + await createPriceSetMoneyAmountRules(testManager) + await service.softDeleteMoneyAmounts([id]) + + const [moneyAmount] = await service.listMoneyAmounts( + { + id: [id], + }, + { + relations: [ + "price_set_money_amount", + "price_set_money_amount.price_rules", + ], + withDeleted: true, + } + ) + + expect(moneyAmount).toBeTruthy() + + const deletedAt = moneyAmount.deleted_at + + expect(moneyAmount).toEqual( + expect.objectContaining({ + deleted_at: deletedAt, + price_set_money_amount: expect.objectContaining({ + deleted_at: deletedAt, + price_rules: [ + expect.objectContaining({ + deleted_at: deletedAt, + }), + ], + }), + }) + ) + }) + }) + + describe("restoreDeletedMoneyAmounts", () => { + const id = "money-amount-USD" + + it("should restore softDeleted priceSetMoneyAmount and PriceRule when restoring soft-deleting money amount", async () => { + await createPriceSets(testManager) + await createRuleTypes(testManager) + await createPriceSetMoneyAmounts(testManager) + await createPriceRules(testManager) + await createPriceSetMoneyAmountRules(testManager) + await service.softDeleteMoneyAmounts([id]) + await service.restoreDeletedMoneyAmounts([id]) + + const [moneyAmount] = await service.listMoneyAmounts( + { + id: [id], + }, + { + relations: [ + "price_set_money_amount", + "price_set_money_amount.price_rules", + ], + } + ) + + expect(moneyAmount).toBeTruthy() + + const deletedAt = null + + expect(moneyAmount).toEqual( + expect.objectContaining({ + deleted_at: deletedAt, + price_set_money_amount: expect.objectContaining({ + deleted_at: deletedAt, + price_rules: [ + expect.objectContaining({ + deleted_at: deletedAt, + }), + ], + }), + }) + ) + }) + }) + describe("updateMoneyAmounts", () => { const id = "money-amount-USD" diff --git a/packages/pricing/src/joiner-config.ts b/packages/pricing/src/joiner-config.ts index 7be13f7c8b88a..bc3342e90e4c2 100644 --- a/packages/pricing/src/joiner-config.ts +++ b/packages/pricing/src/joiner-config.ts @@ -16,6 +16,7 @@ export const LinkableKeys = { price_list_id: PriceList.name, price_set_money_amount_id: PriceSetMoneyAmount.name, } + const entityLinkableKeysMap: MapToConfig = {} Object.entries(LinkableKeys).forEach(([key, value]) => { entityLinkableKeysMap[value] ??= [] diff --git a/packages/pricing/src/migrations/.snapshot-medusa-pricing.json b/packages/pricing/src/migrations/.snapshot-medusa-pricing.json index 403a6b2e356ee..8cf12f0ba0a04 100644 --- a/packages/pricing/src/migrations/.snapshot-medusa-pricing.json +++ b/packages/pricing/src/migrations/.snapshot-medusa-pricing.json @@ -1,5 +1,7 @@ { - "namespaces": ["public"], + "namespaces": [ + "public" + ], "name": "public", "tables": [ { @@ -46,7 +48,9 @@ "indexes": [ { "keyName": "currency_pkey", - "columnNames": ["code"], + "columnNames": [ + "code" + ], "composite": false, "primary": true, "unique": true @@ -139,14 +143,18 @@ "schema": "public", "indexes": [ { - "columnNames": ["currency_code"], + "columnNames": [ + "currency_code" + ], "composite": false, "keyName": "IDX_money_amount_currency_code", "primary": false, "unique": false }, { - "columnNames": ["deleted_at"], + "columnNames": [ + "deleted_at" + ], "composite": false, "keyName": "IDX_money_amount_deleted_at", "primary": false, @@ -154,7 +162,9 @@ }, { "keyName": "money_amount_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -164,9 +174,13 @@ "foreignKeys": { "money_amount_currency_code_foreign": { "constraintName": "money_amount_currency_code_foreign", - "columnNames": ["currency_code"], + "columnNames": [ + "currency_code" + ], "localTableName": "public.money_amount", - "referencedColumnNames": ["code"], + "referencedColumnNames": [ + "code" + ], "referencedTableName": "public.currency", "deleteRule": "set null", "updateRule": "cascade" @@ -210,7 +224,10 @@ "primary": false, "nullable": false, "default": "'draft'", - "enumItems": ["active", "draft"], + "enumItems": [ + "active", + "draft" + ], "mappedType": "enum" }, "type": { @@ -221,7 +238,10 @@ "primary": false, "nullable": false, "default": "'sale'", - "enumItems": ["sale", "override"], + "enumItems": [ + "sale", + "override" + ], "mappedType": "enum" }, "starts_at": { @@ -291,7 +311,9 @@ "schema": "public", "indexes": [ { - "columnNames": ["deleted_at"], + "columnNames": [ + "deleted_at" + ], "composite": false, "keyName": "IDX_price_list_deleted_at", "primary": false, @@ -299,7 +321,9 @@ }, { "keyName": "price_list_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -325,7 +349,9 @@ "indexes": [ { "keyName": "price_set_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -390,42 +416,93 @@ "primary": false, "nullable": true, "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" } }, "name": "price_set_money_amount", "schema": "public", "indexes": [ { - "columnNames": ["price_set_id"], + "columnNames": [ + "price_set_id" + ], "composite": false, "keyName": "IDX_price_set_money_amount_price_set_id", "primary": false, "unique": false }, { - "columnNames": ["money_amount_id"], + "columnNames": [ + "money_amount_id" + ], "composite": false, "keyName": "IDX_price_set_money_amount_money_amount_id", "primary": false, "unique": false }, { - "columnNames": ["money_amount_id"], + "columnNames": [ + "money_amount_id" + ], "composite": false, "keyName": "price_set_money_amount_money_amount_id_unique", "primary": false, "unique": true }, { - "columnNames": ["price_list_id"], + "columnNames": [ + "price_list_id" + ], "composite": false, "keyName": "IDX_price_rule_price_list_id", "primary": false, "unique": false }, + { + "columnNames": [ + "deleted_at" + ], + "composite": false, + "keyName": "IDX_price_set_money_amount_deleted_at", + "primary": false, + "unique": false + }, { "keyName": "price_set_money_amount_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -435,30 +512,41 @@ "foreignKeys": { "price_set_money_amount_price_set_id_foreign": { "constraintName": "price_set_money_amount_price_set_id_foreign", - "columnNames": ["price_set_id"], + "columnNames": [ + "price_set_id" + ], "localTableName": "public.price_set_money_amount", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_set", "deleteRule": "cascade", "updateRule": "cascade" }, "price_set_money_amount_money_amount_id_foreign": { "constraintName": "price_set_money_amount_money_amount_id_foreign", - "columnNames": ["money_amount_id"], + "columnNames": [ + "money_amount_id" + ], "localTableName": "public.price_set_money_amount", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.money_amount", "deleteRule": "cascade", "updateRule": "cascade" }, "price_set_money_amount_price_list_id_foreign": { "constraintName": "price_set_money_amount_price_list_id_foreign", - "columnNames": ["price_list_id"], + "columnNames": [ + "price_list_id" + ], "localTableName": "public.price_set_money_amount", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_list", - "deleteRule": "cascade", - "updateRule": "cascade" + "deleteRule": "cascade" } } }, @@ -506,7 +594,9 @@ "schema": "public", "indexes": [ { - "columnNames": ["rule_attribute"], + "columnNames": [ + "rule_attribute" + ], "composite": false, "keyName": "IDX_rule_type_rule_attribute", "primary": false, @@ -514,7 +604,9 @@ }, { "keyName": "rule_type_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -557,14 +649,18 @@ "schema": "public", "indexes": [ { - "columnNames": ["price_set_id"], + "columnNames": [ + "price_set_id" + ], "composite": false, "keyName": "IDX_price_set_rule_type_price_set_id", "primary": false, "unique": false }, { - "columnNames": ["rule_type_id"], + "columnNames": [ + "rule_type_id" + ], "composite": false, "keyName": "IDX_price_set_rule_type_rule_type_id", "primary": false, @@ -572,7 +668,9 @@ }, { "keyName": "price_set_rule_type_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -582,18 +680,26 @@ "foreignKeys": { "price_set_rule_type_price_set_id_foreign": { "constraintName": "price_set_rule_type_price_set_id_foreign", - "columnNames": ["price_set_id"], + "columnNames": [ + "price_set_id" + ], "localTableName": "public.price_set_rule_type", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_set", "deleteRule": "cascade", "updateRule": "cascade" }, "price_set_rule_type_rule_type_id_foreign": { "constraintName": "price_set_rule_type_rule_type_id_foreign", - "columnNames": ["rule_type_id"], + "columnNames": [ + "rule_type_id" + ], "localTableName": "public.price_set_rule_type", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.rule_type", "updateRule": "cascade" } @@ -642,14 +748,18 @@ "schema": "public", "indexes": [ { - "columnNames": ["price_set_money_amount_id"], + "columnNames": [ + "price_set_money_amount_id" + ], "composite": false, "keyName": "IDX_price_set_money_amount_rules_price_set_money_amount_id", "primary": false, "unique": false }, { - "columnNames": ["rule_type_id"], + "columnNames": [ + "rule_type_id" + ], "composite": false, "keyName": "IDX_price_set_money_amount_rules_rule_type_id", "primary": false, @@ -657,7 +767,9 @@ }, { "keyName": "price_set_money_amount_rules_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -667,18 +779,26 @@ "foreignKeys": { "price_set_money_amount_rules_price_set_money_amount_id_foreign": { "constraintName": "price_set_money_amount_rules_price_set_money_amount_id_foreign", - "columnNames": ["price_set_money_amount_id"], + "columnNames": [ + "price_set_money_amount_id" + ], "localTableName": "public.price_set_money_amount_rules", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_set_money_amount", "deleteRule": "cascade", "updateRule": "cascade" }, "price_set_money_amount_rules_rule_type_id_foreign": { "constraintName": "price_set_money_amount_rules_rule_type_id_foreign", - "columnNames": ["rule_type_id"], + "columnNames": [ + "rule_type_id" + ], "localTableName": "public.price_set_money_amount_rules", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.rule_type", "updateRule": "cascade" } @@ -713,16 +833,6 @@ "nullable": false, "mappedType": "text" }, - "is_dynamic": { - "name": "is_dynamic", - "type": "boolean", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": false, - "default": "false", - "mappedType": "boolean" - }, "value": { "name": "value", "type": "text", @@ -750,35 +860,84 @@ "primary": false, "nullable": false, "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" } }, "name": "price_rule", "schema": "public", "indexes": [ { - "columnNames": ["price_set_id"], + "columnNames": [ + "price_set_id" + ], "composite": false, "keyName": "IDX_price_rule_price_set_id", "primary": false, "unique": false }, { - "columnNames": ["rule_type_id"], + "columnNames": [ + "rule_type_id" + ], "composite": false, "keyName": "IDX_price_rule_rule_type_id", "primary": false, "unique": false }, { - "columnNames": ["price_set_money_amount_id"], + "columnNames": [ + "price_set_money_amount_id" + ], "composite": false, "keyName": "IDX_price_rule_price_set_money_amount_id", "primary": false, "unique": false }, + { + "columnNames": [ + "deleted_at" + ], + "composite": false, + "keyName": "IDX_price_rule_deleted_at", + "primary": false, + "unique": false + }, { "keyName": "price_rule_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -788,26 +947,38 @@ "foreignKeys": { "price_rule_price_set_id_foreign": { "constraintName": "price_rule_price_set_id_foreign", - "columnNames": ["price_set_id"], + "columnNames": [ + "price_set_id" + ], "localTableName": "public.price_rule", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_set", "deleteRule": "cascade", "updateRule": "cascade" }, "price_rule_rule_type_id_foreign": { "constraintName": "price_rule_rule_type_id_foreign", - "columnNames": ["rule_type_id"], + "columnNames": [ + "rule_type_id" + ], "localTableName": "public.price_rule", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.rule_type", "updateRule": "cascade" }, "price_rule_price_set_money_amount_id_foreign": { "constraintName": "price_rule_price_set_money_amount_id_foreign", - "columnNames": ["price_set_money_amount_id"], + "columnNames": [ + "price_set_money_amount_id" + ], "localTableName": "public.price_rule", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_set_money_amount", "deleteRule": "cascade", "updateRule": "cascade" @@ -825,8 +996,8 @@ "nullable": false, "mappedType": "text" }, - "rule_type_id": { - "name": "rule_type_id", + "price_list_id": { + "name": "price_list_id", "type": "text", "unsigned": false, "autoincrement": false, @@ -834,8 +1005,8 @@ "nullable": false, "mappedType": "text" }, - "price_list_id": { - "name": "price_list_id", + "rule_type_id": { + "name": "rule_type_id", "type": "text", "unsigned": false, "autoincrement": false, @@ -848,29 +1019,38 @@ "schema": "public", "indexes": [ { - "columnNames": ["rule_type_id"], + "columnNames": [ + "price_list_id" + ], "composite": false, - "keyName": "IDX_price_list_rule_rule_type_id", + "keyName": "IDX_price_list_rule_price_list_id", "primary": false, "unique": false }, { - "columnNames": ["price_list_id"], + "columnNames": [ + "rule_type_id" + ], "composite": false, - "keyName": "IDX_price_list_rule_price_list_id", + "keyName": "IDX_price_list_rule_rule_type_id", "primary": false, "unique": false }, { "keyName": "IDX_price_list_rule_rule_type_id_price_list_id_unique", - "columnNames": ["price_list_id", "rule_type_id"], + "columnNames": [ + "price_list_id", + "rule_type_id" + ], "composite": true, "primary": false, "unique": true }, { "keyName": "price_list_rule_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -878,21 +1058,29 @@ ], "checks": [], "foreignKeys": { - "price_list_rule_rule_type_id_foreign": { - "constraintName": "price_list_rule_rule_type_id_foreign", - "columnNames": ["rule_type_id"], - "localTableName": "public.price_list_rule", - "referencedColumnNames": ["id"], - "referencedTableName": "public.rule_type", - "updateRule": "cascade" - }, "price_list_rule_price_list_id_foreign": { "constraintName": "price_list_rule_price_list_id_foreign", - "columnNames": ["price_list_id"], + "columnNames": [ + "price_list_id" + ], "localTableName": "public.price_list_rule", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_list", "updateRule": "cascade" + }, + "price_list_rule_rule_type_id_foreign": { + "constraintName": "price_list_rule_rule_type_id_foreign", + "columnNames": [ + "rule_type_id" + ], + "localTableName": "public.price_list_rule", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.rule_type", + "updateRule": "cascade" } } }, @@ -930,7 +1118,9 @@ "schema": "public", "indexes": [ { - "columnNames": ["price_list_rule_id"], + "columnNames": [ + "price_list_rule_id" + ], "composite": false, "keyName": "IDX_price_list_rule_price_list_rule_value_id", "primary": false, @@ -938,7 +1128,9 @@ }, { "keyName": "price_list_rule_value_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -948,9 +1140,13 @@ "foreignKeys": { "price_list_rule_value_price_list_rule_id_foreign": { "constraintName": "price_list_rule_value_price_list_rule_id_foreign", - "columnNames": ["price_list_rule_id"], + "columnNames": [ + "price_list_rule_id" + ], "localTableName": "public.price_list_rule_value", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.price_list_rule", "deleteRule": "cascade", "updateRule": "cascade" diff --git a/packages/pricing/src/migrations/Migration20240103140327.ts b/packages/pricing/src/migrations/Migration20240103140327.ts new file mode 100644 index 0000000000000..c53c56d874c2d --- /dev/null +++ b/packages/pricing/src/migrations/Migration20240103140327.ts @@ -0,0 +1,55 @@ +import { Migration } from "@mikro-orm/migrations" + +export class Migration20240103140327 extends Migration { + async up(): Promise { + this.addSql( + 'alter table "price_set_money_amount" drop constraint "price_set_money_amount_price_list_id_foreign";' + ) + + this.addSql( + 'alter table "price_set_money_amount" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now(), add column "deleted_at" timestamptz null;' + ) + this.addSql( + 'alter table "price_set_money_amount" add constraint "price_set_money_amount_price_list_id_foreign" foreign key ("price_list_id") references "price_list" ("id") on delete cascade;' + ) + this.addSql( + 'create index "IDX_price_set_money_amount_deleted_at" on "price_set_money_amount" ("deleted_at");' + ) + + this.addSql( + 'alter table "price_rule" add column "created_at" timestamptz not null default now(), add column "updated_at" timestamptz not null default now(), add column "deleted_at" timestamptz null;' + ) + this.addSql('alter table "price_rule" drop column "is_dynamic";') + this.addSql( + 'create index "IDX_price_rule_deleted_at" on "price_rule" ("deleted_at");' + ) + } + + async down(): Promise { + this.addSql( + 'alter table "price_set_money_amount" drop constraint "price_set_money_amount_price_list_id_foreign";' + ) + + this.addSql('drop index "IDX_price_set_money_amount_deleted_at";') + this.addSql( + 'alter table "price_set_money_amount" drop column "created_at";' + ) + this.addSql( + 'alter table "price_set_money_amount" drop column "updated_at";' + ) + this.addSql( + 'alter table "price_set_money_amount" drop column "deleted_at";' + ) + this.addSql( + 'alter table "price_set_money_amount" add constraint "price_set_money_amount_price_list_id_foreign" foreign key ("price_list_id") references "price_list" ("id") on update cascade on delete cascade;' + ) + + this.addSql( + 'alter table "price_rule" add column "is_dynamic" boolean not null default false;' + ) + this.addSql('drop index "IDX_price_rule_deleted_at";') + this.addSql('alter table "price_rule" drop column "created_at";') + this.addSql('alter table "price_rule" drop column "updated_at";') + this.addSql('alter table "price_rule" drop column "deleted_at";') + } +} diff --git a/packages/pricing/src/models/money-amount.ts b/packages/pricing/src/models/money-amount.ts index dc6c2b5a47b36..f4a2c1f2647ba 100644 --- a/packages/pricing/src/models/money-amount.ts +++ b/packages/pricing/src/models/money-amount.ts @@ -1,12 +1,14 @@ -import { generateEntityId } from "@medusajs/utils" +import { DALUtils, generateEntityId } from "@medusajs/utils" import { BeforeCreate, Collection, Entity, + Filter, Index, ManyToMany, ManyToOne, OneToOne, + OnInit, OptionalProps, PrimaryKey, Property, @@ -17,18 +19,20 @@ import { PriceSetMoneyAmount } from "./index" import PriceSet from "./price-set" @Entity() +@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) class MoneyAmount { [OptionalProps]?: | "created_at" | "updated_at" | "deleted_at" | "price_set_money_amount" + | "amount" @PrimaryKey({ columnType: "text" }) id!: string @Property({ columnType: "text", nullable: true }) - currency_code?: string + currency_code: string | null @ManyToMany({ entity: () => PriceSet, @@ -39,6 +43,7 @@ class MoneyAmount { @OneToOne({ entity: () => PriceSetMoneyAmount, mappedBy: (psma) => psma.money_amount, + cascade: ["soft-remove"] as any, }) price_set_money_amount: PriceSetMoneyAmount @@ -47,16 +52,20 @@ class MoneyAmount { index: "IDX_money_amount_currency_code", fieldName: "currency_code", }) - currency?: Currency + currency: Currency - @Property({ columnType: "numeric", nullable: true, serializer: Number }) - amount?: number + @Property({ + columnType: "numeric", + nullable: true, + serializer: Number, + }) + amount: number | null @Property({ columnType: "numeric", nullable: true }) - min_quantity?: number | null + min_quantity: number | null @Property({ columnType: "numeric", nullable: true }) - max_quantity?: number | null + max_quantity: number | null @Property({ onCreate: () => new Date(), @@ -75,12 +84,17 @@ class MoneyAmount { @Index({ name: "IDX_money_amount_deleted_at" }) @Property({ columnType: "timestamptz", nullable: true }) - deleted_at: Date + deleted_at: Date | null @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "ma") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "ma") + } } export default MoneyAmount diff --git a/packages/pricing/src/models/price-list-rule-value.ts b/packages/pricing/src/models/price-list-rule-value.ts index c2c9e5d9ac07c..58f7cb0bfcd29 100644 --- a/packages/pricing/src/models/price-list-rule-value.ts +++ b/packages/pricing/src/models/price-list-rule-value.ts @@ -2,6 +2,7 @@ import { BeforeCreate, Entity, ManyToOne, + OnInit, PrimaryKey, Property, } from "@mikro-orm/core" @@ -16,7 +17,7 @@ export default class PriceListRuleValue { @ManyToOne(() => PriceListRule, { onDelete: "cascade", - fieldName: 'price_list_rule_id', + fieldName: "price_list_rule_id", index: "IDX_price_list_rule_price_list_rule_value_id", }) price_list_rule: PriceListRule @@ -28,4 +29,9 @@ export default class PriceListRuleValue { onCreate() { this.id = generateEntityId(this.id, "plrv") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "plrv") + } } diff --git a/packages/pricing/src/models/price-list-rule.ts b/packages/pricing/src/models/price-list-rule.ts index edbdbde218027..239048f18b0fe 100644 --- a/packages/pricing/src/models/price-list-rule.ts +++ b/packages/pricing/src/models/price-list-rule.ts @@ -5,6 +5,7 @@ import { Entity, ManyToOne, OneToMany, + OnInit, OptionalProps, PrimaryKey, Unique, @@ -54,4 +55,9 @@ export default class PriceListRule { beforeCreate() { this.id = generateEntityId(this.id, "plrule") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "plrule") + } } diff --git a/packages/pricing/src/models/price-list.ts b/packages/pricing/src/models/price-list.ts index ca6ba9081213d..89468074e417b 100644 --- a/packages/pricing/src/models/price-list.ts +++ b/packages/pricing/src/models/price-list.ts @@ -1,4 +1,8 @@ -import { generateEntityId } from "@medusajs/utils" +import { + generateEntityId, + PriceListStatus, + PriceListType, +} from "@medusajs/utils" import { BeforeCreate, Cascade, @@ -8,12 +12,11 @@ import { Index, ManyToMany, OneToMany, + OnInit, OptionalProps, PrimaryKey, Property, } from "@mikro-orm/core" - -import { PriceListStatus, PriceListType } from "@medusajs/utils" import PriceListRule from "./price-list-rule" import PriceSetMoneyAmount from "./price-set-money-amount" import RuleType from "./rule-type" @@ -47,22 +50,22 @@ export default class PriceList { description: string @Enum({ items: () => PriceListStatus, default: PriceListStatus.DRAFT }) - status?: PriceListStatus + status: PriceListStatus @Enum({ items: () => PriceListType, default: PriceListType.SALE }) - type?: PriceListType + type: PriceListType @Property({ columnType: "timestamptz", nullable: true, }) - starts_at?: Date | null + starts_at: Date | null @Property({ columnType: "timestamptz", nullable: true, }) - ends_at?: Date | null + ends_at: Date | null @OneToMany(() => PriceSetMoneyAmount, (psma) => psma.price_list, { cascade: [Cascade.REMOVE], @@ -89,7 +92,7 @@ export default class PriceList { columnType: "timestamptz", defaultRaw: "now()", }) - created_at?: Date + created_at: Date @Property({ onCreate: () => new Date(), @@ -97,14 +100,19 @@ export default class PriceList { columnType: "timestamptz", defaultRaw: "now()", }) - updated_at?: Date + updated_at: Date @Index({ name: "IDX_price_list_deleted_at" }) @Property({ columnType: "timestamptz", nullable: true }) - deleted_at?: Date + deleted_at: Date | null @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "plist") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "plist") + } } diff --git a/packages/pricing/src/models/price-rule.ts b/packages/pricing/src/models/price-rule.ts index a1d786759bda1..d0e6a7c310465 100644 --- a/packages/pricing/src/models/price-rule.ts +++ b/packages/pricing/src/models/price-rule.ts @@ -1,21 +1,31 @@ import { BeforeCreate, Entity, + Filter, + Index, ManyToOne, + OnInit, OptionalProps, PrimaryKey, Property, } from "@mikro-orm/core" +import { DALUtils, generateEntityId } from "@medusajs/utils" -import { generateEntityId } from "@medusajs/utils" import PriceSet from "./price-set" import PriceSetMoneyAmount from "./price-set-money-amount" import RuleType from "./rule-type" -type OptionalFields = "id" | "is_dynamic" | "priority" +type OptionalFields = + | "id" + | "is_dynamic" + | "priority" + | "created_at" + | "updated_at" + | "deleted_at" type OptionalRelations = "price_set" | "rule_type" | "price_set_money_amount" @Entity() +@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) export default class PriceRule { [OptionalProps]: OptionalFields | OptionalRelations @@ -54,8 +64,32 @@ export default class PriceRule { }) price_set_money_amount: PriceSetMoneyAmount + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date + + @Index({ name: "IDX_price_rule_deleted_at" }) + @Property({ columnType: "timestamptz", nullable: true }) + deleted_at: Date | null + @BeforeCreate() beforeCreate() { this.id = generateEntityId(this.id, "prule") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "prule") + } } diff --git a/packages/pricing/src/models/price-set-money-amount-rules.ts b/packages/pricing/src/models/price-set-money-amount-rules.ts index c4040d5ce0c2f..184ced8ebc006 100644 --- a/packages/pricing/src/models/price-set-money-amount-rules.ts +++ b/packages/pricing/src/models/price-set-money-amount-rules.ts @@ -3,6 +3,7 @@ import { BeforeCreate, Entity, ManyToOne, + OnInit, PrimaryKey, Property, } from "@mikro-orm/core" @@ -19,12 +20,12 @@ export default class PriceSetMoneyAmountRules { onDelete: "cascade", index: "IDX_price_set_money_amount_rules_price_set_money_amount_id", }) - price_set_money_amount?: PriceSetMoneyAmount | string + price_set_money_amount: PriceSetMoneyAmount @ManyToOne(() => RuleType, { index: "IDX_price_set_money_amount_rules_rule_type_id", }) - rule_type?: RuleType | string + rule_type: RuleType @Property({ columnType: "text" }) value: string @@ -33,4 +34,9 @@ export default class PriceSetMoneyAmountRules { onCreate() { this.id = generateEntityId(this.id, "psmar") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "psmar") + } } diff --git a/packages/pricing/src/models/price-set-money-amount.ts b/packages/pricing/src/models/price-set-money-amount.ts index 0c6479d22d880..4c381e78b1ec0 100644 --- a/packages/pricing/src/models/price-set-money-amount.ts +++ b/packages/pricing/src/models/price-set-money-amount.ts @@ -1,15 +1,20 @@ -import { generateEntityId } from "@medusajs/utils" import { BeforeCreate, + Cascade, Collection, Entity, + Filter, + Index, ManyToOne, + OnInit, OneToMany, OneToOne, + OptionalProps, PrimaryKey, PrimaryKeyType, Property, } from "@mikro-orm/core" +import { DALUtils, generateEntityId } from "@medusajs/utils" import MoneyAmount from "./money-amount" import PriceList from "./price-list" @@ -18,7 +23,10 @@ import PriceSet from "./price-set" import PriceSetMoneyAmountRules from "./price-set-money-amount-rules" @Entity() +@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) export default class PriceSetMoneyAmount { + [OptionalProps]?: "created_at" | "updated_at" | "deleted_at" + @PrimaryKey({ columnType: "text" }) id!: string @@ -29,20 +37,21 @@ export default class PriceSetMoneyAmount { onDelete: "cascade", index: "IDX_price_set_money_amount_price_set_id", }) - price_set?: PriceSet + price_set: PriceSet @OneToOne(() => MoneyAmount, { onDelete: "cascade", index: "IDX_price_set_money_amount_money_amount_id", }) - money_amount?: MoneyAmount + money_amount: MoneyAmount @Property({ columnType: "integer", default: 0 }) - rules_count?: number + rules_count: number @OneToMany({ entity: () => PriceRule, mappedBy: (pr) => pr.price_set_money_amount, + cascade: ["soft-remove"] as any, }) price_rules = new Collection(this) @@ -55,15 +64,39 @@ export default class PriceSetMoneyAmount { @ManyToOne(() => PriceList, { index: "IDX_price_rule_price_list_id", onDelete: "cascade", + cascade: [Cascade.REMOVE, "soft-remove"] as any, nullable: true, }) - price_list?: PriceList + price_list: PriceList | null + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date + + @Property({ columnType: "timestamptz", nullable: true , index: "IDX_price_set_money_amount_deleted_at"}) + deleted_at: Date | null @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "psma") } + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "psma") + } + [PrimaryKeyType]?: [string, string] constructor(money_amount: MoneyAmount, price_set: PriceSet) { diff --git a/packages/pricing/src/models/price-set-rule-type.ts b/packages/pricing/src/models/price-set-rule-type.ts index f1921f5d5844b..0cb27b3b2d846 100644 --- a/packages/pricing/src/models/price-set-rule-type.ts +++ b/packages/pricing/src/models/price-set-rule-type.ts @@ -2,8 +2,8 @@ import { BeforeCreate, Entity, ManyToOne, + OnInit, PrimaryKey, - PrimaryKeyType, } from "@mikro-orm/core" import PriceSet from "./price-set" @@ -30,4 +30,9 @@ export default class PriceSetRuleType { onCreate() { this.id = generateEntityId(this.id, "psrt") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "psrt") + } } diff --git a/packages/pricing/src/models/price-set.ts b/packages/pricing/src/models/price-set.ts index 3b4d7a50ea1b3..ebe2264081fa4 100644 --- a/packages/pricing/src/models/price-set.ts +++ b/packages/pricing/src/models/price-set.ts @@ -6,6 +6,7 @@ import { Entity, ManyToMany, OneToMany, + OnInit, OptionalProps, PrimaryKey, } from "@mikro-orm/core" @@ -50,4 +51,9 @@ export default class PriceSet { onCreate() { this.id = generateEntityId(this.id, "pset") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "pset") + } } diff --git a/packages/pricing/src/models/rule-type.ts b/packages/pricing/src/models/rule-type.ts index d393faada638d..10c2926f172e2 100644 --- a/packages/pricing/src/models/rule-type.ts +++ b/packages/pricing/src/models/rule-type.ts @@ -4,6 +4,7 @@ import { Collection, Entity, ManyToMany, + OnInit, OptionalProps, PrimaryKey, Property, @@ -28,13 +29,18 @@ class RuleType { @Property({ columnType: "integer", default: 0 }) default_priority: number - @ManyToMany(() => PriceSet, priceSet => priceSet.rule_types) - price_sets = new Collection(this); + @ManyToMany(() => PriceSet, (priceSet) => priceSet.rule_types) + price_sets = new Collection(this) @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "rul-typ") } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "rul-typ") + } } export default RuleType diff --git a/packages/pricing/src/repositories/money-amount.ts b/packages/pricing/src/repositories/money-amount.ts index 097558504d88e..e2ce6afebe54b 100644 --- a/packages/pricing/src/repositories/money-amount.ts +++ b/packages/pricing/src/repositories/money-amount.ts @@ -1,9 +1,9 @@ import { Context, DAL } from "@medusajs/types" import { DALUtils, MedusaError } from "@medusajs/utils" import { - LoadStrategy, FilterQuery as MikroFilterQuery, FindOptions as MikroOptions, + LoadStrategy, } from "@mikro-orm/core" import { MoneyAmount } from "@models" @@ -72,7 +72,7 @@ export class MoneyAmountRepository extends DALUtils.MikroOrmBaseRepository { const manager = this.getActiveManager(context) const moneyAmounts = data.map((moneyAmountData) => { - return manager.create(MoneyAmount, moneyAmountData) + return manager.create(MoneyAmount, moneyAmountData as any) }) manager.persist(moneyAmounts) diff --git a/packages/pricing/src/repositories/price-set-money-amount-rules.ts b/packages/pricing/src/repositories/price-set-money-amount-rules.ts index 1e7756930e3f9..811e11a0d7abc 100644 --- a/packages/pricing/src/repositories/price-set-money-amount-rules.ts +++ b/packages/pricing/src/repositories/price-set-money-amount-rules.ts @@ -1,9 +1,9 @@ import { Context, DAL } from "@medusajs/types" import { DALUtils, MedusaError } from "@medusajs/utils" import { - LoadStrategy, FilterQuery as MikroFilterQuery, FindOptions as MikroOptions, + LoadStrategy, } from "@mikro-orm/core" import { PriceSetMoneyAmountRules } from "@models" @@ -72,7 +72,7 @@ export class PriceSetMoneyAmountRulesRepository extends DALUtils.MikroOrmBaseRep const manager = this.getActiveManager(context) const psmar = data.map((psmarData) => { - return manager.create(PriceSetMoneyAmountRules, psmarData) + return manager.create(PriceSetMoneyAmountRules, psmarData as any) }) manager.persist(psmar) @@ -114,7 +114,7 @@ export class PriceSetMoneyAmountRulesRepository extends DALUtils.MikroOrmBaseRep ) } - return manager.assign(existingRecord, psmarData) + return manager.assign(existingRecord, psmarData as any) }) manager.persist(psmar) diff --git a/packages/pricing/src/scripts/seed.ts b/packages/pricing/src/scripts/seed.ts index 6aac156a3fe29..bc1a6b6f057cf 100644 --- a/packages/pricing/src/scripts/seed.ts +++ b/packages/pricing/src/scripts/seed.ts @@ -1,7 +1,7 @@ import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types" import { DALUtils, ModulesSdkUtils } from "@medusajs/utils" import { EntitySchema, RequiredEntityData } from "@mikro-orm/core" -import { SqlEntityManager } from "@mikro-orm/postgresql" +import { PostgreSqlDriver, SqlEntityManager } from "@mikro-orm/postgresql" import * as PricingModels from "@models" import { EOL } from "os" import { resolve } from "path" @@ -49,10 +49,10 @@ export async function run({ try { logger.info("Inserting price_sets, currencies & money_amounts") - await createCurrencies(manager, currenciesData) - await createMoneyAmounts(manager, moneyAmountsData) - await createPriceSets(manager, priceSetsData) - await createPriceSetMoneyAmounts(manager, priceSetMoneyAmountsData) + await createCurrencies(manager as any, currenciesData) + await createMoneyAmounts(manager as any, moneyAmountsData) + await createPriceSets(manager as any, priceSetsData) + await createPriceSetMoneyAmounts(manager as any, priceSetMoneyAmountsData) } catch (e) { logger.error( `Failed to insert the seed data in the PostgreSQL database ${dbData.clientUrl}.${EOL}${e}` @@ -63,7 +63,7 @@ export async function run({ } async function createCurrencies( - manager: SqlEntityManager, + manager: SqlEntityManager, data: RequiredEntityData[] ) { const currencies = data.map((currencyData) => { @@ -76,7 +76,7 @@ async function createCurrencies( } async function createMoneyAmounts( - manager: SqlEntityManager, + manager: SqlEntityManager, data: RequiredEntityData[] ) { const moneyAmounts = data.map((moneyAmountData) => { @@ -89,7 +89,7 @@ async function createMoneyAmounts( } async function createPriceSets( - manager: SqlEntityManager, + manager: SqlEntityManager, data: RequiredEntityData[] ) { const priceSets = data.map((priceSetData) => { @@ -102,7 +102,7 @@ async function createPriceSets( } async function createPriceSetMoneyAmounts( - manager: SqlEntityManager, + manager: SqlEntityManager, data: RequiredEntityData[] ) { const priceSetMoneyAmounts = data.map((priceSetMoneyAmountData) => { diff --git a/packages/pricing/src/services/money-amount.ts b/packages/pricing/src/services/money-amount.ts index 40f05d6cd69aa..640eacd1f7c94 100644 --- a/packages/pricing/src/services/money-amount.ts +++ b/packages/pricing/src/services/money-amount.ts @@ -101,4 +101,20 @@ export default class MoneyAmountService< ): Promise { await this.moneyAmountRepository_.delete(ids, sharedContext) } + + @InjectTransactionManager("moneyAmountRepository_") + async softDelete( + ids: string[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + await this.moneyAmountRepository_.softDelete(ids, sharedContext) + } + + @InjectTransactionManager("moneyAmountRepository_") + async restore( + ids: string[], + @MedusaContext() sharedContext: Context = {} + ): Promise<[TEntity[], Record]> { + return await this.moneyAmountRepository_.restore(ids, sharedContext) + } } diff --git a/packages/pricing/src/services/price-set-money-amount.ts b/packages/pricing/src/services/price-set-money-amount.ts index ddc39855e0d1f..ff21ef8a22899 100644 --- a/packages/pricing/src/services/price-set-money-amount.ts +++ b/packages/pricing/src/services/price-set-money-amount.ts @@ -44,7 +44,7 @@ export default class PriceSetMoneyAmountService< @InjectManager("priceSetMoneyAmountRepository_") async list( filters: ServiceTypes.FilterablePriceSetMoneyAmountProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { return (await this.priceSetMoneyAmountRepository_.find( @@ -56,7 +56,7 @@ export default class PriceSetMoneyAmountService< @InjectManager("priceSetMoneyAmountRepository_") async listAndCount( filters: ServiceTypes.FilterablePriceSetMoneyAmountProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[TEntity[], number]> { return (await this.priceSetMoneyAmountRepository_.findAndCount( @@ -67,7 +67,7 @@ export default class PriceSetMoneyAmountService< private buildQueryForList( filters: ServiceTypes.FilterablePriceSetMoneyAmountProps = {}, - config: FindConfig = {} + config: FindConfig = {} ) { const queryOptions = ModulesSdkUtils.buildQuery(filters, config) diff --git a/packages/pricing/src/services/pricing-module.ts b/packages/pricing/src/services/pricing-module.ts index 68906fd1c6582..68d00fbc473fa 100644 --- a/packages/pricing/src/services/pricing-module.ts +++ b/packages/pricing/src/services/pricing-module.ts @@ -13,6 +13,7 @@ import { PricingFilters, PricingRepositoryService, PricingTypes, + RestoreReturn, RuleTypeDTO, } from "@medusajs/types" import { @@ -24,6 +25,7 @@ import { arrayDifference, deduplicate, groupBy, + mapObjectTo, removeNullish, } from "@medusajs/utils" @@ -54,7 +56,11 @@ import { PriceSetService, RuleTypeService, } from "@services" -import { joinerConfig } from "../joiner-config" +import { + LinkableKeys, + entityNameToLinkableKeysMap, + joinerConfig, +} from "../joiner-config" import { validatePriceListDates } from "@utils" import { ServiceTypes } from "@types" import { CreatePriceListRuleValueDTO } from "src/types/services" @@ -861,6 +867,41 @@ export default class PricingModuleService< await this.moneyAmountService_.delete(ids, sharedContext) } + @InjectTransactionManager("baseRepository_") + async softDeleteMoneyAmounts( + ids: string[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + await this.moneyAmountService_.softDelete(ids, sharedContext) + } + + @InjectTransactionManager("baseRepository_") + async restoreDeletedMoneyAmounts< + TReturnableLinkableKeys extends string = Lowercase< + keyof typeof LinkableKeys + > + >( + ids: string[], + { returnLinkableKeys }: RestoreReturn = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise, string[]> | void> { + const [_, cascadedEntitiesMap] = await this.moneyAmountService_.restore( + ids, + sharedContext + ) + + let mappedCascadedEntitiesMap + if (returnLinkableKeys) { + mappedCascadedEntitiesMap = mapObjectTo< + Record, string[]> + >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { + pick: returnLinkableKeys, + }) + } + + return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 + } + @InjectManager("baseRepository_") async retrieveCurrency( code: string, @@ -1132,7 +1173,7 @@ export default class PricingModuleService< ) return this.baseRepository_.serialize< - PricingTypes.PriceSetMoneyAmountRulesDTO[] + PricingTypes.PriceSetMoneyAmountDTO[] >(records, { populate: true, }) @@ -1153,7 +1194,7 @@ export default class PricingModuleService< return [ await this.baseRepository_.serialize< - PricingTypes.PriceSetMoneyAmountRulesDTO[] + PricingTypes.PriceSetMoneyAmountDTO[] >(records, { populate: true, }), diff --git a/packages/pricing/src/types/services/money-amount.ts b/packages/pricing/src/types/services/money-amount.ts index 1252696a8085c..70f41fb2dc807 100644 --- a/packages/pricing/src/types/services/money-amount.ts +++ b/packages/pricing/src/types/services/money-amount.ts @@ -30,6 +30,9 @@ export interface MoneyAmountDTO { min_quantity?: number max_quantity?: number price_set_money_amount?: PriceSetMoneyAmountDTO + created_at: Date + updated_at: Date + deleted_at: Date | null } export interface FilterableMoneyAmountProps diff --git a/packages/pricing/src/types/services/price-rule.ts b/packages/pricing/src/types/services/price-rule.ts index 3ee33e43c2c3c..d3db234d02b24 100644 --- a/packages/pricing/src/types/services/price-rule.ts +++ b/packages/pricing/src/types/services/price-rule.ts @@ -33,6 +33,9 @@ export interface PriceRuleDTO { priority: number price_set_money_amount_id: string price_list_id: string + created_at: Date + updated_at: Date + deleted_at: Date | null } export interface FilterablePriceRuleProps diff --git a/packages/pricing/src/types/services/price-set-money-amount.ts b/packages/pricing/src/types/services/price-set-money-amount.ts index dd6fa09cc73b6..11fcee3e5934e 100644 --- a/packages/pricing/src/types/services/price-set-money-amount.ts +++ b/packages/pricing/src/types/services/price-set-money-amount.ts @@ -36,4 +36,7 @@ export interface PriceSetMoneyAmountDTO { price_set_id?: string price_rules?: PriceRuleDTO[] money_amount?: MoneyAmountDTO + created_at: Date + updated_at: Date + deleted_at: Date | null } diff --git a/packages/types/src/pricing/common/money-amount.ts b/packages/types/src/pricing/common/money-amount.ts index 160abead7bcb5..2270139fa99e7 100644 --- a/packages/types/src/pricing/common/money-amount.ts +++ b/packages/types/src/pricing/common/money-amount.ts @@ -18,7 +18,7 @@ export interface MoneyAmountDTO { currency_code?: string /** * The money amount's currency. - * + * * @expandable */ currency?: CurrencyDTO @@ -38,6 +38,18 @@ export interface MoneyAmountDTO { * The details of the relation between the money amount and its associated price set. */ price_set_money_amount?: PriceSetMoneyAmountDTO + /** + * When the money_amount was created. + */ + created_at: Date + /** + * When the money_amount was updated. + */ + updated_at: Date + /** + * When the money_amount was deleted. + */ + deleted_at: null | Date } /** diff --git a/packages/types/src/pricing/common/price-rule.ts b/packages/types/src/pricing/common/price-rule.ts index 61ff8176c1a2f..52556f0025eed 100644 --- a/packages/types/src/pricing/common/price-rule.ts +++ b/packages/types/src/pricing/common/price-rule.ts @@ -48,6 +48,18 @@ export interface PriceRuleDTO { * The ID of the associated price list. */ price_list_id: string + /** + * When the price_rule was created. + */ + created_at: Date + /** + * When the price_rule was updated. + */ + updated_at: Date + /** + * When the price_rule was deleted. + */ + deleted_at: null | Date } /** diff --git a/packages/types/src/pricing/common/price-set-money-amount.ts b/packages/types/src/pricing/common/price-set-money-amount.ts index c207f04bcfe8f..80ae6490cd4d7 100644 --- a/packages/types/src/pricing/common/price-set-money-amount.ts +++ b/packages/types/src/pricing/common/price-set-money-amount.ts @@ -1,8 +1,8 @@ -import { BaseFilterable } from "../../dal" -import { MoneyAmountDTO } from "./money-amount" -import { PriceListDTO } from "./price-list" -import { PriceRuleDTO } from "./price-rule" -import { PriceSetDTO } from "./price-set" +import { BaseFilterable } from "../../dal"; +import { MoneyAmountDTO } from "./money-amount"; +import { PriceListDTO } from "./price-list"; +import { PriceRuleDTO } from "./price-rule"; +import { PriceSetDTO } from "./price-set"; /** * @interface @@ -46,6 +46,18 @@ export interface PriceSetMoneyAmountDTO { * @expandable */ money_amount?: MoneyAmountDTO + /** + * When the price_set_money_amount was created. + */ + created_at: Date + /** + * When the price_set_money_amount was updated. + */ + updated_at: Date + /** + * When the price_set_money_amount was deleted. + */ + deleted_at: null | Date } export interface UpdatePriceSetMoneyAmountDTO { diff --git a/packages/types/src/pricing/service.ts b/packages/types/src/pricing/service.ts index 0480950494182..9c9a7a10e3c69 100644 --- a/packages/types/src/pricing/service.ts +++ b/packages/types/src/pricing/service.ts @@ -47,6 +47,7 @@ import { import { FindConfig } from "../common" import { ModuleJoinerConfig } from "../modules-sdk" import { Context } from "../shared-context" +import { RestoreReturn } from "../dal" export interface IPricingModuleService { /** @@ -1274,6 +1275,58 @@ export interface IPricingModuleService { */ deleteMoneyAmounts(ids: string[], sharedContext?: Context): Promise + /** + * This method soft deletes money amounts by their IDs. + * + * @param {string[]} ids - The IDs of the money amounts to delete. + * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. + * @returns {Promise} Resolves when the money amounts are successfully deleted. + * + * @example + * import { + * initialize as initializePricingModule, + * } from "@medusajs/pricing" + * + * async function softDeleteMoneyAmounts (moneyAmountIds: string[]) { + * const pricingService = await initializePricingModule() + * + * await pricingService.softDeleteMoneyAmounts( + * moneyAmountIds + * ) + * } + */ + softDeleteMoneyAmounts(ids: string[], sharedContext?: Context): Promise + + /** + * This method restores soft deleted money amounts by their IDs. + * + * @param {string[]} ids - The IDs of the money amounts to delete. + * @param {RestoreReturn} config - + * Configurations determining which relations to restore along with each of the money amounts. You can pass to its `returnLinkableKeys` + * property any of the money_amount's relation attribute names, such as `price_set_money_amount_id`. + * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. + * @returns {Promise | void>} + * An object that includes the IDs of related records that were restored, such as the ID of associated product variants. The object's keys are the ID attribute names of the product entity's relations, such as `variant_id`, and its value is an array of strings, each being the ID of the record associated with the product through this relation, such as the IDs of associated product variants. + * + * @example + * import { + * initialize as initializePricingModule, + * } from "@medusajs/pricing" + * + * async function softDeleteMoneyAmounts (moneyAmountIds: string[]) { + * const pricingService = await initializePricingModule() + * + * await pricingService.softDeleteMoneyAmounts( + * moneyAmountIds + * ) + * } + */ + restoreDeletedMoneyAmounts( + ids: string[], + config?: RestoreReturn, + sharedContext?: Context + ): Promise | void> + /** * This method retrieves a currency by its code and and optionally based on the provided configurations. * diff --git a/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts b/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts index 0bcc495237a80..2f8fe52d329bb 100644 --- a/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts +++ b/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts @@ -6,7 +6,7 @@ import { } from "@medusajs/types" import { isString } from "../../common" import { MedusaContext } from "../../decorators" -import { InjectTransactionManager, buildQuery } from "../../modules-sdk" +import { buildQuery, InjectTransactionManager } from "../../modules-sdk" import { getSoftDeletedCascadedEntitiesIdsMappedBy, transactionWrapper, diff --git a/packages/utils/src/dal/mikro-orm/utils.ts b/packages/utils/src/dal/mikro-orm/utils.ts index 63d599eb2c1fd..fc5d1f55d78a3 100644 --- a/packages/utils/src/dal/mikro-orm/utils.ts +++ b/packages/utils/src/dal/mikro-orm/utils.ts @@ -1,5 +1,3 @@ -import { SoftDeletableFilterKey } from "./mikro-orm-soft-deletable-filter" - export const mikroOrmUpdateDeletedAtRecursively = async < T extends object = any >( @@ -22,19 +20,25 @@ export const mikroOrmUpdateDeletedAtRecursively = async < ) for (const relation of relationsToCascade) { - let collectionRelation = entity[relation.name] + let entityRelation = entity[relation.name] - if (!collectionRelation.isInitialized()) { - await collectionRelation.init() + // Handle optional relationships + if (relation.nullable && !entityRelation) { + continue } - const relationEntities = await collectionRelation.getItems({ - filters: { - [SoftDeletableFilterKey]: { - withDeleted: true, - }, - }, - }) + const isCollection = "toArray" in entityRelation + let relationEntities: any[] = [] + + if (isCollection) { + if (!entityRelation.isInitialized()) { + entityRelation = await entityRelation.init({ populate: true }) + } + relationEntities = entityRelation.getItems() + } else { + const initializedEntityRelation = await entityRelation.__helper?.init() + relationEntities = [initializedEntityRelation] + } await mikroOrmUpdateDeletedAtRecursively(manager, relationEntities, value) }