From e021c9258cd3bf7b92213b0bd2d529f72200142e Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Thu, 12 Dec 2024 15:05:11 +0530 Subject: [PATCH] Feat/tax dml (#10525) Fixes: FRMW-2842 There are zero breaking changes and the users will have to run the migrations --- .changeset/unlucky-radios-fry.md | 5 + .../integration-tests/__tests__/index.spec.ts | 4 +- .../src/migrations/.snapshot-medusa-tax.json | 247 ++++++++++++------ .../src/migrations/Migration20241212052837.ts | 27 ++ .../modules/tax/src/models/tax-provider.ts | 24 +- .../modules/tax/src/models/tax-rate-rule.ts | 140 ++-------- packages/modules/tax/src/models/tax-rate.ts | 155 +++-------- packages/modules/tax/src/models/tax-region.ts | 194 ++++---------- .../tax/src/services/tax-module-service.ts | 29 +- 9 files changed, 334 insertions(+), 491 deletions(-) create mode 100644 .changeset/unlucky-radios-fry.md create mode 100644 packages/modules/tax/src/migrations/Migration20241212052837.ts diff --git a/.changeset/unlucky-radios-fry.md b/.changeset/unlucky-radios-fry.md new file mode 100644 index 0000000000000..7ecb0124a41d1 --- /dev/null +++ b/.changeset/unlucky-radios-fry.md @@ -0,0 +1,5 @@ +--- +"@medusajs/tax": patch +--- + +Feat/tax dml diff --git a/packages/modules/tax/integration-tests/__tests__/index.spec.ts b/packages/modules/tax/integration-tests/__tests__/index.spec.ts index b07761e3a98c4..beeea521fce50 100644 --- a/packages/modules/tax/integration-tests/__tests__/index.spec.ts +++ b/packages/modules/tax/integration-tests/__tests__/index.spec.ts @@ -1,5 +1,5 @@ import { ITaxModuleService } from "@medusajs/framework/types" -import { Module, Modules } from "@medusajs/framework/utils" +import { Module, Modules, toMikroORMEntity } from "@medusajs/framework/utils" import { TaxModuleService } from "@services" import { moduleIntegrationTestRunner } from "@medusajs/test-utils" import { setupTaxStructure } from "../utils/setup-tax-structure" @@ -11,7 +11,7 @@ moduleIntegrationTestRunner({ testSuite: ({ service }) => { describe("TaxModuleService", function () { it(`should export the appropriate linkable configuration`, () => { - const linkable = Module(Modules.TAX, { + const linkable = Module(toMikroORMEntity(Modules.TAX), { service: TaxModuleService, }).linkable diff --git a/packages/modules/tax/src/migrations/.snapshot-medusa-tax.json b/packages/modules/tax/src/migrations/.snapshot-medusa-tax.json index 0c76f681c9303..bafd28cd676e0 100644 --- a/packages/modules/tax/src/migrations/.snapshot-medusa-tax.json +++ b/packages/modules/tax/src/migrations/.snapshot-medusa-tax.json @@ -1,5 +1,7 @@ { - "namespaces": ["public"], + "namespaces": [ + "public" + ], "name": "public", "tables": [ { @@ -22,14 +24,56 @@ "nullable": false, "default": "true", "mappedType": "boolean" + }, + "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": "tax_provider", "schema": "public", "indexes": [ + { + "keyName": "IDX_tax_provider_deleted_at", + "columnNames": [], + "composite": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_provider_deleted_at\" ON \"tax_provider\" (deleted_at) WHERE deleted_at IS NULL" + }, { "keyName": "tax_provider_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -49,26 +93,35 @@ "nullable": false, "mappedType": "text" }, - "provider_id": { - "name": "provider_id", + "country_code": { + "name": "country_code", "type": "text", "unsigned": false, "autoincrement": false, "primary": false, - "nullable": true, + "nullable": false, "mappedType": "text" }, - "country_code": { - "name": "country_code", + "province_code": { + "name": "province_code", "type": "text", "unsigned": false, "autoincrement": false, "primary": false, - "nullable": false, + "nullable": true, "mappedType": "text" }, - "province_code": { - "name": "province_code", + "metadata": { + "name": "metadata", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "created_by": { + "name": "created_by", "type": "text", "unsigned": false, "autoincrement": false, @@ -76,8 +129,8 @@ "nullable": true, "mappedType": "text" }, - "parent_id": { - "name": "parent_id", + "provider_id": { + "name": "provider_id", "type": "text", "unsigned": false, "autoincrement": false, @@ -85,14 +138,14 @@ "nullable": true, "mappedType": "text" }, - "metadata": { - "name": "metadata", - "type": "jsonb", + "parent_id": { + "name": "parent_id", + "type": "text", "unsigned": false, "autoincrement": false, "primary": false, "nullable": true, - "mappedType": "json" + "mappedType": "text" }, "created_at": { "name": "created_at", @@ -116,15 +169,6 @@ "default": "now()", "mappedType": "datetime" }, - "created_by": { - "name": "created_by", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "mappedType": "text" - }, "deleted_at": { "name": "deleted_at", "type": "timestamptz", @@ -140,19 +184,28 @@ "schema": "public", "indexes": [ { - "columnNames": ["parent_id"], + "keyName": "IDX_tax_region_provider_id", + "columnNames": [], "composite": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_region_provider_id\" ON \"tax_region\" (provider_id) WHERE deleted_at IS NULL" + }, + { "keyName": "IDX_tax_region_parent_id", + "columnNames": [], + "composite": false, "primary": false, - "unique": false + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_region_parent_id\" ON \"tax_region\" (parent_id) WHERE deleted_at IS NULL" }, { "keyName": "IDX_tax_region_deleted_at", - "columnNames": ["deleted_at"], + "columnNames": [], "composite": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_region_deleted_at\" ON \"tax_region\" (deleted_at) WHERE deleted_at IS NOT NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_region_deleted_at\" ON \"tax_region\" (deleted_at) WHERE deleted_at IS NULL" }, { "keyName": "IDX_tax_region_unique_country_province", @@ -172,39 +225,49 @@ }, { "keyName": "tax_region_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true } ], "checks": [ - { - "name": "CK_tax_region_country_top_level", - "expression": "parent_id IS NULL OR province_code IS NOT NULL", - "definition": "check ((parent_id IS NULL OR province_code IS NOT NULL))" - }, { "name": "CK_tax_region_provider_top_level", "expression": "parent_id IS NULL OR provider_id IS NULL", "definition": "check ((parent_id IS NULL OR provider_id IS NULL))" + }, + { + "name": "CK_tax_region_country_top_level", + "expression": "parent_id IS NULL OR province_code IS NOT NULL", + "definition": "check ((parent_id IS NULL OR province_code IS NOT NULL))" } ], "foreignKeys": { "tax_region_provider_id_foreign": { "constraintName": "tax_region_provider_id_foreign", - "columnNames": ["provider_id"], + "columnNames": [ + "provider_id" + ], "localTableName": "public.tax_region", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.tax_provider", "deleteRule": "set null", "updateRule": "cascade" }, "tax_region_parent_id_foreign": { "constraintName": "tax_region_parent_id_foreign", - "columnNames": ["parent_id"], + "columnNames": [ + "parent_id" + ], "localTableName": "public.tax_region", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.tax_region", "deleteRule": "cascade", "updateRule": "cascade" @@ -228,7 +291,7 @@ "unsigned": false, "autoincrement": false, "primary": false, - "nullable": false, + "nullable": true, "mappedType": "float" }, "code": { @@ -251,7 +314,7 @@ }, "is_default": { "name": "is_default", - "type": "bool", + "type": "boolean", "unsigned": false, "autoincrement": false, "primary": false, @@ -261,7 +324,7 @@ }, "is_combinable": { "name": "is_combinable", - "type": "bool", + "type": "boolean", "unsigned": false, "autoincrement": false, "primary": false, @@ -287,6 +350,15 @@ "nullable": true, "mappedType": "json" }, + "created_by": { + "name": "created_by", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, "created_at": { "name": "created_at", "type": "timestamptz", @@ -309,15 +381,6 @@ "default": "now()", "mappedType": "datetime" }, - "created_by": { - "name": "created_by", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "mappedType": "text" - }, "deleted_at": { "name": "deleted_at", "type": "timestamptz", @@ -334,7 +397,7 @@ "indexes": [ { "keyName": "IDX_tax_rate_tax_region_id", - "columnNames": ["tax_region_id"], + "columnNames": [], "composite": false, "primary": false, "unique": false, @@ -342,11 +405,11 @@ }, { "keyName": "IDX_tax_rate_deleted_at", - "columnNames": ["deleted_at"], + "columnNames": [], "composite": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_deleted_at\" ON \"tax_rate\" (deleted_at) WHERE deleted_at IS NOT NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_deleted_at\" ON \"tax_rate\" (deleted_at) WHERE deleted_at IS NULL" }, { "keyName": "IDX_single_default_region", @@ -358,7 +421,9 @@ }, { "keyName": "tax_rate_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -368,9 +433,13 @@ "foreignKeys": { "tax_rate_tax_region_id_foreign": { "constraintName": "tax_rate_tax_region_id_foreign", - "columnNames": ["tax_region_id"], + "columnNames": [ + "tax_region_id" + ], "localTableName": "public.tax_rate", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.tax_region", "deleteRule": "cascade", "updateRule": "cascade" @@ -388,17 +457,26 @@ "nullable": false, "mappedType": "text" }, - "tax_rate_id": { - "name": "tax_rate_id", + "metadata": { + "name": "metadata", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "created_by": { + "name": "created_by", "type": "text", "unsigned": false, "autoincrement": false, "primary": false, - "nullable": false, + "nullable": true, "mappedType": "text" }, - "reference_id": { - "name": "reference_id", + "tax_rate_id": { + "name": "tax_rate_id", "type": "text", "unsigned": false, "autoincrement": false, @@ -415,14 +493,14 @@ "nullable": false, "mappedType": "text" }, - "metadata": { - "name": "metadata", - "type": "jsonb", + "reference_id": { + "name": "reference_id", + "type": "text", "unsigned": false, "autoincrement": false, "primary": false, - "nullable": true, - "mappedType": "json" + "nullable": false, + "mappedType": "text" }, "created_at": { "name": "created_at", @@ -446,15 +524,6 @@ "default": "now()", "mappedType": "datetime" }, - "created_by": { - "name": "created_by", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "mappedType": "text" - }, "deleted_at": { "name": "deleted_at", "type": "timestamptz", @@ -471,27 +540,27 @@ "indexes": [ { "keyName": "IDX_tax_rate_rule_tax_rate_id", - "columnNames": ["tax_rate_id"], + "columnNames": [], "composite": false, "primary": false, "unique": false, "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_rule_tax_rate_id\" ON \"tax_rate_rule\" (tax_rate_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_tax_rate_rule_reference_id", - "columnNames": ["reference_id"], + "keyName": "IDX_tax_rate_rule_deleted_at", + "columnNames": [], "composite": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_rule_reference_id\" ON \"tax_rate_rule\" (reference_id) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_rule_deleted_at\" ON \"tax_rate_rule\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_tax_rate_rule_deleted_at", - "columnNames": ["deleted_at"], + "keyName": "IDX_tax_rate_rule_reference_id", + "columnNames": [], "composite": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_rule_deleted_at\" ON \"tax_rate_rule\" (deleted_at) WHERE deleted_at IS NOT NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_tax_rate_rule_reference_id\" ON \"tax_rate_rule\" (reference_id) WHERE deleted_at IS NULL" }, { "keyName": "IDX_tax_rate_rule_unique_rate_reference", @@ -503,7 +572,9 @@ }, { "keyName": "tax_rate_rule_pkey", - "columnNames": ["id"], + "columnNames": [ + "id" + ], "composite": false, "primary": true, "unique": true @@ -513,9 +584,13 @@ "foreignKeys": { "tax_rate_rule_tax_rate_id_foreign": { "constraintName": "tax_rate_rule_tax_rate_id_foreign", - "columnNames": ["tax_rate_id"], + "columnNames": [ + "tax_rate_id" + ], "localTableName": "public.tax_rate_rule", - "referencedColumnNames": ["id"], + "referencedColumnNames": [ + "id" + ], "referencedTableName": "public.tax_rate", "deleteRule": "cascade", "updateRule": "cascade" diff --git a/packages/modules/tax/src/migrations/Migration20241212052837.ts b/packages/modules/tax/src/migrations/Migration20241212052837.ts new file mode 100644 index 0000000000000..ee1b6fa003f5c --- /dev/null +++ b/packages/modules/tax/src/migrations/Migration20241212052837.ts @@ -0,0 +1,27 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20241212052837 extends Migration { + + async up(): Promise { + this.addSql('alter table if exists "tax_provider" add column if not exists "created_at" timestamptz not null default now(), add column if not exists "updated_at" timestamptz not null default now(), add column if not exists "deleted_at" timestamptz null;'); + this.addSql('CREATE INDEX IF NOT EXISTS "IDX_tax_provider_deleted_at" ON "tax_provider" (deleted_at) WHERE deleted_at IS NULL;'); + + this.addSql('CREATE INDEX IF NOT EXISTS "IDX_tax_region_provider_id" ON "tax_region" (provider_id) WHERE deleted_at IS NULL;'); + + this.addSql('alter table if exists "tax_rate" alter column "rate" type real using ("rate"::real);'); + this.addSql('alter table if exists "tax_rate" alter column "rate" drop not null;'); + } + + async down(): Promise { + this.addSql('drop index if exists "IDX_tax_provider_deleted_at";'); + this.addSql('alter table if exists "tax_provider" drop column if exists "created_at";'); + this.addSql('alter table if exists "tax_provider" drop column if exists "updated_at";'); + this.addSql('alter table if exists "tax_provider" drop column if exists "deleted_at";'); + + this.addSql('drop index if exists "IDX_tax_region_provider_id";'); + + this.addSql('alter table if exists "tax_rate" alter column "rate" type real using ("rate"::real);'); + this.addSql('alter table if exists "tax_rate" alter column "rate" set not null;'); + } + +} diff --git a/packages/modules/tax/src/models/tax-provider.ts b/packages/modules/tax/src/models/tax-provider.ts index e08a3c952c23d..2d237883db3cf 100644 --- a/packages/modules/tax/src/models/tax-provider.ts +++ b/packages/modules/tax/src/models/tax-provider.ts @@ -1,16 +1,12 @@ -import { Entity, OptionalProps, PrimaryKey, Property } from "@mikro-orm/core" +import { model } from "@medusajs/framework/utils" +import { TaxRegion } from "@models" -const TABLE_NAME = "tax_provider" -@Entity({ tableName: TABLE_NAME }) -export default class TaxProvider { - [OptionalProps]?: "is_enabled" +const TaxProvider = model.define("TaxProvider", { + id: model.id().primaryKey(), + is_enabled: model.boolean().default(true), + regions: model.hasMany(() => TaxRegion, { + mappedBy: "provider", + }), +}) - @PrimaryKey({ columnType: "text" }) - id: string - - @Property({ - default: true, - columnType: "boolean", - }) - is_enabled: boolean = true -} +export default TaxProvider diff --git a/packages/modules/tax/src/models/tax-rate-rule.ts b/packages/modules/tax/src/models/tax-rate-rule.ts index a76b940f588ae..7f8732b68bd0a 100644 --- a/packages/modules/tax/src/models/tax-rate-rule.ts +++ b/packages/modules/tax/src/models/tax-rate-rule.ts @@ -1,117 +1,29 @@ -import { DAL } from "@medusajs/framework/types" -import { - createPsqlIndexStatementHelper, - DALUtils, - generateEntityId, -} from "@medusajs/framework/utils" -import { - BeforeCreate, - Entity, - Filter, - ManyToOne, - OnInit, - OptionalProps, - PrimaryKey, - Property, - Rel, -} from "@mikro-orm/core" +import { model } from "@medusajs/framework/utils" import TaxRate from "./tax-rate" -const TABLE_NAME = "tax_rate_rule" - -type OptionalRuleProps = DAL.SoftDeletableModelDateColumns - -const taxRateIdIndexName = "IDX_tax_rate_rule_tax_rate_id" -const taxRateIdIndexStatement = createPsqlIndexStatementHelper({ - name: taxRateIdIndexName, - tableName: TABLE_NAME, - columns: "tax_rate_id", - where: "deleted_at IS NULL", -}) -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - tableName: TABLE_NAME, - columns: "deleted_at", - where: "deleted_at IS NOT NULL", -}) - -const referenceIdIndexName = "IDX_tax_rate_rule_reference_id" -const referenceIdIndexStatement = createPsqlIndexStatementHelper({ - name: referenceIdIndexName, - tableName: TABLE_NAME, - columns: "reference_id", - where: "deleted_at IS NULL", -}) - -export const uniqueRateReferenceIndexName = - "IDX_tax_rate_rule_unique_rate_reference" -const uniqueRateReferenceIndexStatement = createPsqlIndexStatementHelper({ - name: uniqueRateReferenceIndexName, - tableName: TABLE_NAME, - columns: ["tax_rate_id", "reference_id"], - unique: true, - where: "deleted_at IS NULL", -}) - -@Entity({ tableName: TABLE_NAME }) -@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) -@uniqueRateReferenceIndexStatement.MikroORMIndex() -export default class TaxRateRule { - [OptionalProps]?: OptionalRuleProps - - @PrimaryKey({ columnType: "text" }) - id!: string - - @ManyToOne(() => TaxRate, { - type: "text", - fieldName: "tax_rate_id", - mapToPk: true, - onDelete: "cascade", +const TaxRateRule = model + .define("TaxRateRule", { + id: model.id({ prefix: "txrule" }).primaryKey(), + metadata: model.json().nullable(), + created_by: model.text().nullable(), + tax_rate: model.belongsTo(() => TaxRate, { + mappedBy: "rules", + }), + reference: model.text(), + reference_id: model.text(), }) - @taxRateIdIndexStatement.MikroORMIndex() - tax_rate_id: string - - @Property({ columnType: "text" }) - @referenceIdIndexStatement.MikroORMIndex() - reference_id: string - - @Property({ columnType: "text" }) - reference: string - - @ManyToOne(() => TaxRate, { persist: false }) - tax_rate: Rel - - @Property({ columnType: "jsonb", nullable: true }) - metadata: Record | null = 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: "text", nullable: true }) - created_by: string | null = null - - @deletedAtIndexStatement.MikroORMIndex() - @Property({ columnType: "timestamptz", nullable: true }) - deleted_at: Date | null = null - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "txrule") - } - - @OnInit() - onInit() { - this.id = generateEntityId(this.id, "txrule") - } -} + .indexes([ + { + name: "IDX_tax_rate_rule_reference_id", + on: ["reference_id"], + where: "deleted_at IS NULL", + }, + { + name: "IDX_tax_rate_rule_unique_rate_reference", + on: ["tax_rate_id", "reference_id"], + unique: true, + where: "deleted_at IS NULL", + }, + ]) + +export default TaxRateRule diff --git a/packages/modules/tax/src/models/tax-rate.ts b/packages/modules/tax/src/models/tax-rate.ts index 678ed85d17180..1b57fbc5a45c8 100644 --- a/packages/modules/tax/src/models/tax-rate.ts +++ b/packages/modules/tax/src/models/tax-rate.ts @@ -1,128 +1,39 @@ -import { DAL } from "@medusajs/framework/types" -import { - createPsqlIndexStatementHelper, - DALUtils, - generateEntityId, - Searchable, -} from "@medusajs/framework/utils" -import { - BeforeCreate, - Cascade, - Collection, - Entity, - Filter, - ManyToOne, - OneToMany, - OnInit, - OptionalProps, - PrimaryKey, - Property, - Rel, -} from "@mikro-orm/core" +import { model } from "@medusajs/framework/utils" import TaxRateRule from "./tax-rate-rule" import TaxRegion from "./tax-region" -type OptionalTaxRateProps = DAL.SoftDeletableModelDateColumns - -const TABLE_NAME = "tax_rate" - -export const singleDefaultRegionIndexName = "IDX_single_default_region" -const singleDefaultRegionIndexStatement = createPsqlIndexStatementHelper({ - name: singleDefaultRegionIndexName, - tableName: TABLE_NAME, - columns: "tax_region_id", - unique: true, - where: "is_default = true AND deleted_at IS NULL", -}) - -const taxRegionIdIndexName = "IDX_tax_rate_tax_region_id" -const taxRegionIdIndexStatement = createPsqlIndexStatementHelper({ - name: taxRegionIdIndexName, - tableName: TABLE_NAME, - columns: "tax_region_id", - where: "deleted_at IS NULL", -}) -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - tableName: TABLE_NAME, - columns: "deleted_at", - where: "deleted_at IS NOT NULL", -}) - -@singleDefaultRegionIndexStatement.MikroORMIndex() -@Entity({ tableName: TABLE_NAME }) -@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) -export default class TaxRate { - [OptionalProps]?: OptionalTaxRateProps - - @PrimaryKey({ columnType: "text" }) - id!: string - - @Property({ columnType: "real", nullable: true }) - rate: number | null = null - - @Searchable() - @Property({ columnType: "text" }) - code: string - - @Searchable() - @Property({ columnType: "text" }) - name: string - - @Property({ columnType: "bool", default: false }) - is_default: boolean = false - - @Property({ columnType: "bool", default: false }) - is_combinable: boolean = false - - @ManyToOne(() => TaxRegion, { - columnType: "text", - fieldName: "tax_region_id", - mapToPk: true, - onDelete: "cascade", +const TaxRate = model + .define("TaxRate", { + id: model.id({ prefix: "txr" }).primaryKey(), + rate: model.float().nullable(), + code: model.text().searchable(), + name: model.text().searchable(), + is_default: model.boolean().default(false), + is_combinable: model.boolean().default(false), + tax_region: model.belongsTo(() => TaxRegion, { + mappedBy: "tax_rates", + }), + rules: model.hasMany(() => TaxRateRule, { + mappedBy: "tax_rate", + }), + metadata: model.json().nullable(), + created_by: model.text().nullable(), }) - @taxRegionIdIndexStatement.MikroORMIndex() - tax_region_id: string - - @ManyToOne({ entity: () => TaxRegion, persist: false }) - tax_region: Rel - - @OneToMany(() => TaxRateRule, (rule) => rule.tax_rate, { - cascade: ["soft-remove" as Cascade], - }) - rules = new Collection>(this) - - @Property({ columnType: "jsonb", nullable: true }) - metadata: Record | null = null - - @Property({ - onCreate: () => new Date(), - columnType: "timestamptz", - defaultRaw: "now()", + .indexes([ + { + name: "IDX_tax_rate_tax_region_id", + on: ["tax_region_id"], + where: "deleted_at IS NULL", + }, + { + name: "IDX_single_default_region", + on: ["tax_region_id"], + unique: true, + where: "is_default = true AND deleted_at IS NULL", + }, + ]) + .cascades({ + delete: ["rules"], }) - created_at: Date - - @Property({ - onCreate: () => new Date(), - onUpdate: () => new Date(), - columnType: "timestamptz", - defaultRaw: "now()", - }) - updated_at: Date - - @Property({ columnType: "text", nullable: true }) - created_by: string | null = null - - @deletedAtIndexStatement.MikroORMIndex() - @Property({ columnType: "timestamptz", nullable: true }) - deleted_at: Date | null = null - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "txr") - } - @OnInit() - onInit() { - this.id = generateEntityId(this.id, "txr") - } -} +export default TaxRate diff --git a/packages/modules/tax/src/models/tax-region.ts b/packages/modules/tax/src/models/tax-region.ts index 65afb90097853..a1feaf7e29a05 100644 --- a/packages/modules/tax/src/models/tax-region.ts +++ b/packages/modules/tax/src/models/tax-region.ts @@ -1,153 +1,61 @@ -import { DAL } from "@medusajs/framework/types" -import { - createPsqlIndexStatementHelper, - DALUtils, - generateEntityId, - Searchable, -} from "@medusajs/framework/utils" -import { - BeforeCreate, - Cascade, - Check, - Collection, - Entity, - Filter, - ManyToOne, - OneToMany, - OnInit, - OptionalProps, - PrimaryKey, - Property, - Rel, -} from "@mikro-orm/core" +import { model } from "@medusajs/framework/utils" import TaxProvider from "./tax-provider" import TaxRate from "./tax-rate" -type OptionalTaxRegionProps = DAL.SoftDeletableModelDateColumns - -const TABLE_NAME = "tax_region" - -export const countryCodeNullProvinceIndexName = - "IDX_tax_region_unique_country_nullable_province" -export const countryCodeProvinceIndexName = - "IDX_tax_region_unique_country_province" -const countryCodeProvinceIndexStatement = createPsqlIndexStatementHelper({ - name: countryCodeProvinceIndexName, - tableName: TABLE_NAME, - columns: ["country_code", "province_code"], - unique: true, - where: "deleted_at IS NULL", -}) -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - tableName: TABLE_NAME, - columns: "deleted_at", - where: "deleted_at IS NOT NULL", -}) - -const countryCodeNullableProvinceIndexStatement = - createPsqlIndexStatementHelper({ - name: countryCodeNullProvinceIndexName, - tableName: TABLE_NAME, - columns: ["country_code"], - unique: true, - where: "province_code IS NULL AND deleted_at IS NULL", - }) - export const taxRegionProviderTopLevelCheckName = "CK_tax_region_provider_top_level" export const taxRegionCountryTopLevelCheckName = "CK_tax_region_country_top_level" -@Check({ - name: taxRegionProviderTopLevelCheckName, - expression: `parent_id IS NULL OR provider_id IS NULL`, -}) -@Check({ - name: taxRegionCountryTopLevelCheckName, - expression: `parent_id IS NULL OR province_code IS NOT NULL`, -}) -@countryCodeNullableProvinceIndexStatement.MikroORMIndex() -@countryCodeProvinceIndexStatement.MikroORMIndex() -@Entity({ tableName: TABLE_NAME }) -@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) -export default class TaxRegion { - [OptionalProps]?: OptionalTaxRegionProps - - @PrimaryKey({ columnType: "text" }) - id!: string - - @ManyToOne(() => TaxProvider, { - fieldName: "provider_id", - mapToPk: true, - nullable: true, +const TaxRegion = model + .define("TaxRegion", { + id: model.id({ prefix: "txreg" }).primaryKey(), + country_code: model.text().searchable(), + province_code: model.text().searchable().nullable(), + metadata: model.json().nullable(), + created_by: model.text().nullable(), + provider: model + .belongsTo(() => TaxProvider, { + mappedBy: "regions", + }) + .nullable(), + parent: model + .belongsTo(() => TaxRegion, { + mappedBy: "children", + }) + .nullable(), + children: model.hasMany(() => TaxRegion, { + mappedBy: "parent", + }), + tax_rates: model.hasMany(() => TaxRate, { + mappedBy: "tax_region", + }), }) - provider_id: string | null = null - - @ManyToOne(() => TaxProvider, { persist: false }) - provider: Rel - - @Searchable() - @Property({ columnType: "text" }) - country_code: string - - @Searchable() - @Property({ columnType: "text", nullable: true }) - province_code: string | null = null - - @ManyToOne(() => TaxRegion, { - index: "IDX_tax_region_parent_id", - fieldName: "parent_id", - onDelete: "cascade", - mapToPk: true, - nullable: true, + .checks([ + { + name: taxRegionProviderTopLevelCheckName, + expression: `parent_id IS NULL OR provider_id IS NULL`, + }, + { + name: taxRegionCountryTopLevelCheckName, + expression: `parent_id IS NULL OR province_code IS NOT NULL`, + }, + ]) + .indexes([ + { + name: "IDX_tax_region_unique_country_province", + on: ["country_code", "province_code"], + unique: true, + where: "deleted_at IS NULL", + }, + { + name: "IDX_tax_region_unique_country_nullable_province", + on: ["country_code"], + unique: true, + where: "province_code IS NULL AND deleted_at IS NULL", + }, + ]) + .cascades({ + delete: ["children", "tax_rates"], }) - parent_id: string | null = null - - @ManyToOne(() => TaxRegion, { persist: false }) - parent: Rel - - @OneToMany(() => TaxRate, (label) => label.tax_region, { - cascade: ["soft-remove" as Cascade], - }) - tax_rates = new Collection(this) - - @OneToMany(() => TaxRegion, (label) => label.parent, { - cascade: ["soft-remove" as Cascade], - }) - children = new Collection>(this) - - @Property({ columnType: "jsonb", nullable: true }) - metadata: Record | null = 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: "text", nullable: true }) - created_by: string | null = null - - @deletedAtIndexStatement.MikroORMIndex() - @Property({ columnType: "timestamptz", nullable: true }) - deleted_at: Date | null = null - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "txreg") - } - - @OnInit() - onInit() { - this.id = generateEntityId(this.id, "txreg") - } -} +export default TaxRegion diff --git a/packages/modules/tax/src/services/tax-module-service.ts b/packages/modules/tax/src/services/tax-module-service.ts index 497b40c5fd2aa..8412a28e7cf46 100644 --- a/packages/modules/tax/src/services/tax-module-service.ts +++ b/packages/modules/tax/src/services/tax-module-service.ts @@ -1,6 +1,7 @@ import { Context, DAL, + InferEntityType, InternalModuleDeclaration, ITaxModuleService, ITaxProvider, @@ -32,7 +33,7 @@ type InjectedDependencies = { const generateForModels = { TaxRate, TaxRegion, TaxRateRule, TaxProvider } type ItemWithRates = { - rates: TaxRate[] + rates: InferEntityType[] item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO } @@ -47,10 +48,18 @@ export default class TaxModuleService { protected readonly container_: InjectedDependencies protected baseRepository_: DAL.RepositoryService - protected taxRateService_: ModulesSdkTypes.IMedusaInternalService - protected taxRegionService_: ModulesSdkTypes.IMedusaInternalService - protected taxRateRuleService_: ModulesSdkTypes.IMedusaInternalService - protected taxProviderService_: ModulesSdkTypes.IMedusaInternalService + protected taxRateService_: ModulesSdkTypes.IMedusaInternalService< + InferEntityType + > + protected taxRegionService_: ModulesSdkTypes.IMedusaInternalService< + InferEntityType + > + protected taxRateRuleService_: ModulesSdkTypes.IMedusaInternalService< + InferEntityType + > + protected taxProviderService_: ModulesSdkTypes.IMedusaInternalService< + InferEntityType + > constructor( { @@ -568,8 +577,8 @@ export default class TaxModuleService private async getTaxRatesForItem( item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO, - rates: TaxRate[] - ): Promise { + rates: InferEntityType[] + ): Promise[]> { if (!rates.length) { return [] } @@ -630,7 +639,7 @@ export default class TaxModuleService } private checkRuleMatches( - rate: TaxRate, + rate: InferEntityType, item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO ) { if (rate.rules.length === 0) { @@ -670,7 +679,7 @@ export default class TaxModuleService } private prioritizeRates( - rates: TaxRate[], + rates: InferEntityType[], item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO ) { const decoratedRates = rates.map((rate) => { @@ -700,7 +709,7 @@ export default class TaxModuleService } return decoratedRate - }) as (TaxRate & { + }) as (InferEntityType & { priority_score: number })[]