@infuro/cms-core 1.0.30 → 1.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +20 -15
  2. package/dist/admin.cjs +13061 -7814
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +13 -2
  5. package/dist/admin.d.ts +13 -2
  6. package/dist/admin.js +8416 -3167
  7. package/dist/admin.js.map +1 -1
  8. package/dist/api.cjs +5667 -1110
  9. package/dist/api.cjs.map +1 -1
  10. package/dist/api.d.cts +2 -2
  11. package/dist/api.d.ts +2 -2
  12. package/dist/api.js +5418 -855
  13. package/dist/api.js.map +1 -1
  14. package/dist/auth.cjs +620 -76
  15. package/dist/auth.cjs.map +1 -1
  16. package/dist/auth.d.cts +93 -52
  17. package/dist/auth.d.ts +93 -52
  18. package/dist/auth.js +578 -52
  19. package/dist/auth.js.map +1 -1
  20. package/dist/cli.cjs +19 -15
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +19 -15
  23. package/dist/cli.js.map +1 -1
  24. package/dist/{index-BPQSXgXF.d.cts → index-DWd5Gjc4.d.ts} +38 -5
  25. package/dist/{index-D9SdaDJ0.d.ts → index-rZTnpK7y.d.cts} +38 -5
  26. package/dist/index.cjs +5921 -1177
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +334 -59
  29. package/dist/index.d.ts +334 -59
  30. package/dist/index.js +5733 -1026
  31. package/dist/index.js.map +1 -1
  32. package/dist/migrations/1775400000001-AddDiscountAndOrderAddresses.ts +274 -0
  33. package/dist/migrations/1775800000000-VendorsAndVendorUsers.ts +74 -0
  34. package/dist/migrations/1775900000000-StoreVendorIdColumns.ts +124 -0
  35. package/dist/migrations/1775910000000-VendorOwnerRbacSeed.ts +54 -0
  36. package/dist/migrations/1775920000000-VendorOwnerSettingsPermission.ts +25 -0
  37. package/dist/migrations/1775930000000-VendorGroupStorePermissions.ts +54 -0
  38. package/dist/migrations/1775940000000-VendorRls.ts +71 -0
  39. package/dist/migrations/1775950000000-VendorCustomers.ts +87 -0
  40. package/dist/migrations/1775950000001-VendorCustomersPermissions.ts +67 -0
  41. package/dist/migrations/1778652250860-CreateCurrencyTables.ts +16 -0
  42. package/dist/migrations/1778652250861-OrderAddressTables.ts +88 -0
  43. package/dist/migrations/1778652250862-UpdateDiscountandRules.ts +100 -0
  44. package/dist/migrations/1778652250863-MakeCouponCodeNullable.ts +19 -0
  45. package/dist/migrations/1778652250864-RemoveUniqueConstraintFromDiscountCouponCode.ts +22 -0
  46. package/dist/migrations/1778652250865-FixOrdersAddressForeignKeys.ts +71 -0
  47. package/dist/migrations/1778660000000-DiscountVendorId.ts +90 -0
  48. package/dist/migrations/1778660000001-FixOrdersAddressFkToOrderAddresses.ts +79 -0
  49. package/dist/migrations/1778660000002-VendorUserIdInviteStatus.ts +61 -0
  50. package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
  51. package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
  52. package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
  53. package/dist/theme.d.cts +2 -2
  54. package/dist/theme.d.ts +2 -2
  55. package/dist/{types-D34wmivy.d.cts → types-DCVaXlPV.d.cts} +1 -1
  56. package/dist/{types-D34wmivy.d.ts → types-DCVaXlPV.d.ts} +1 -1
  57. package/dist/vendor-scope-DTYhJk_I.d.cts +129 -0
  58. package/dist/vendor-scope-DTYhJk_I.d.ts +129 -0
  59. package/package.json +3 -2
  60. package/dist/helpers-dlrF_49e.d.cts +0 -60
  61. package/dist/helpers-dlrF_49e.d.ts +0 -60
@@ -0,0 +1,87 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ /**
4
+ * Creates the `vendor_customers` table and enables Row Level Security on it.
5
+ *
6
+ * Each row links a vendor to one of their contacts (customers). The RLS policy
7
+ * mirrors the one on all other vendor-scoped store tables: a row is visible only
8
+ * when `app.vendor_id` matches the row's `vendorId`, or when `app.vendor_id` is
9
+ * unset / '0' (platform-admin / no restriction).
10
+ */
11
+ export class VendorCustomers1775950000000 implements MigrationInterface {
12
+ name = 'VendorCustomers1775950000000';
13
+
14
+ public async up(queryRunner: QueryRunner): Promise<void> {
15
+ await queryRunner.query(`
16
+ CREATE TABLE IF NOT EXISTS "vendor_customers" (
17
+ "id" SERIAL NOT NULL,
18
+ "vendorId" integer NOT NULL,
19
+ "contactId" integer NOT NULL,
20
+ "notes" text,
21
+ "tags" text,
22
+ "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
23
+ "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
24
+ CONSTRAINT "PK_vendor_customers" PRIMARY KEY ("id")
25
+ )
26
+ `);
27
+
28
+ await queryRunner.query(`
29
+ DO $$ BEGIN
30
+ ALTER TABLE "vendor_customers"
31
+ ADD CONSTRAINT "FK_vendor_customers_vendor"
32
+ FOREIGN KEY ("vendorId") REFERENCES "vendors"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
33
+ EXCEPTION WHEN duplicate_object THEN NULL; END $$
34
+ `);
35
+
36
+ await queryRunner.query(`
37
+ DO $$ BEGIN
38
+ ALTER TABLE "vendor_customers"
39
+ ADD CONSTRAINT "FK_vendor_customers_contact"
40
+ FOREIGN KEY ("contactId") REFERENCES "contacts"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
41
+ EXCEPTION WHEN duplicate_object THEN NULL; END $$
42
+ `);
43
+
44
+ await queryRunner.query(`
45
+ DO $$ BEGIN
46
+ ALTER TABLE "vendor_customers"
47
+ ADD CONSTRAINT "UQ_vendor_customers_vendor_contact"
48
+ UNIQUE ("vendorId", "contactId");
49
+ EXCEPTION WHEN duplicate_object THEN NULL; END $$
50
+ `);
51
+
52
+ await queryRunner.query(`
53
+ CREATE INDEX IF NOT EXISTS "IDX_vendor_customers_vendor"
54
+ ON "vendor_customers" ("vendorId")
55
+ `);
56
+
57
+ await queryRunner.query(`
58
+ CREATE INDEX IF NOT EXISTS "IDX_vendor_customers_contact"
59
+ ON "vendor_customers" ("contactId")
60
+ `);
61
+
62
+ // Row Level Security — same pattern as other vendor-scoped tables.
63
+ await queryRunner.query(`ALTER TABLE "vendor_customers" ENABLE ROW LEVEL SECURITY`);
64
+ await queryRunner.query(`ALTER TABLE "vendor_customers" FORCE ROW LEVEL SECURITY`);
65
+ await queryRunner.query(`DROP POLICY IF EXISTS "vendor_isolation" ON "vendor_customers"`);
66
+ await queryRunner.query(`
67
+ CREATE POLICY "vendor_isolation" ON "vendor_customers"
68
+ USING (
69
+ COALESCE(NULLIF(current_setting('app.vendor_id', true), ''), '0') = '0'
70
+ OR "vendorId" = NULLIF(current_setting('app.vendor_id', true), '')::integer
71
+ )
72
+ WITH CHECK (
73
+ COALESCE(NULLIF(current_setting('app.vendor_id', true), ''), '0') = '0'
74
+ OR "vendorId" = NULLIF(current_setting('app.vendor_id', true), '')::integer
75
+ )
76
+ `);
77
+ }
78
+
79
+ public async down(queryRunner: QueryRunner): Promise<void> {
80
+ await queryRunner.query(`DROP POLICY IF EXISTS "vendor_isolation" ON "vendor_customers"`);
81
+ await queryRunner.query(`ALTER TABLE "vendor_customers" NO FORCE ROW LEVEL SECURITY`);
82
+ await queryRunner.query(`ALTER TABLE "vendor_customers" DISABLE ROW LEVEL SECURITY`);
83
+ await queryRunner.query(`DROP INDEX IF EXISTS "IDX_vendor_customers_contact"`);
84
+ await queryRunner.query(`DROP INDEX IF EXISTS "IDX_vendor_customers_vendor"`);
85
+ await queryRunner.query(`DROP TABLE IF EXISTS "vendor_customers"`);
86
+ }
87
+ }
@@ -0,0 +1,67 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ /** Grant vendor groups CRUD on `vendor_customers` (Customers tab). */
4
+ export class VendorCustomersPermissions1775950000001 implements MigrationInterface {
5
+ name = 'VendorCustomersPermissions1775950000001';
6
+
7
+ public async up(queryRunner: QueryRunner): Promise<void> {
8
+ // Ensure unique (groupId, entity) so future permission seeds can use ON CONFLICT.
9
+ await queryRunner.query(`
10
+ DELETE FROM permissions a USING permissions b
11
+ WHERE a.id > b.id AND a."groupId" = b."groupId" AND a.entity = b.entity
12
+ `);
13
+ await queryRunner.query(`
14
+ CREATE UNIQUE INDEX IF NOT EXISTS "UQ_permissions_group_entity"
15
+ ON "permissions" ("groupId", "entity")
16
+ `);
17
+
18
+ await queryRunner.query(`
19
+ INSERT INTO "permissions" ("groupId", "entity", "canCreate", "canRead", "canUpdate", "canDelete")
20
+ SELECT g.id, 'vendor_customers', true, true, true, true
21
+ FROM "user_groups" g
22
+ WHERE g.deleted = false
23
+ AND (
24
+ lower(g.name) LIKE '%vendor%'
25
+ OR g.name = 'Vendor Owner'
26
+ )
27
+ AND g.name <> 'Administrator'
28
+ AND NOT EXISTS (
29
+ SELECT 1 FROM "permissions" p
30
+ WHERE p."groupId" = g.id AND p.entity = 'vendor_customers'
31
+ )
32
+ `);
33
+
34
+ await queryRunner.query(`
35
+ UPDATE "permissions" p
36
+ SET
37
+ "canCreate" = true,
38
+ "canRead" = true,
39
+ "canUpdate" = true,
40
+ "canDelete" = true
41
+ FROM "user_groups" g
42
+ WHERE p."groupId" = g.id
43
+ AND p.entity = 'vendor_customers'
44
+ AND g.deleted = false
45
+ AND (
46
+ lower(g.name) LIKE '%vendor%'
47
+ OR g.name = 'Vendor Owner'
48
+ )
49
+ AND g.name <> 'Administrator'
50
+ `);
51
+ }
52
+
53
+ public async down(queryRunner: QueryRunner): Promise<void> {
54
+ await queryRunner.query(`
55
+ DELETE FROM "permissions" p
56
+ USING "user_groups" g
57
+ WHERE p."groupId" = g.id
58
+ AND p.entity = 'vendor_customers'
59
+ AND g.deleted = false
60
+ AND (
61
+ lower(g.name) LIKE '%vendor%'
62
+ OR g.name = 'Vendor Owner'
63
+ )
64
+ AND g.name <> 'Administrator'
65
+ `);
66
+ }
67
+ }
@@ -0,0 +1,16 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class CreateCurrencyTables1778652250860 implements MigrationInterface {
4
+ name = 'CreateCurrencyTables1778652250860'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`CREATE TABLE "currency" ("id" SERIAL NOT NULL, "code" character varying NOT NULL, "name" character varying NOT NULL, "symbol" character varying NOT NULL, "isActive" boolean NOT NULL DEFAULT true, "isBaseCurrency" boolean NOT NULL DEFAULT false, CONSTRAINT "UQ_723472e41cae44beb0763f4039c" UNIQUE ("code"), CONSTRAINT "PK_3cda65c731a6264f0e444cc9b91" PRIMARY KEY ("id"))`);
8
+ await queryRunner.query(`CREATE TABLE "currency_exchange" ("id" SERIAL NOT NULL, "fromCurrency" character varying NOT NULL, "toCurrency" character varying NOT NULL, "rate" numeric(12,6) NOT NULL, CONSTRAINT "PK_408ce7731cf7527a37ad3848d2b" PRIMARY KEY ("id"))`);
9
+ }
10
+
11
+ public async down(queryRunner: QueryRunner): Promise<void> {
12
+ await queryRunner.query(`DROP TABLE "currency_exchange"`);
13
+ await queryRunner.query(`DROP TABLE "currency"`);
14
+ }
15
+
16
+ }
@@ -0,0 +1,88 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ export class UpdateOrdersAddressRelations1778652250861
4
+ implements MigrationInterface
5
+ {
6
+ name = 'UpdateOrdersAddressRelations1778652250861';
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ await queryRunner.query(`
10
+ ALTER TABLE "orders"
11
+ DROP CONSTRAINT IF EXISTS "FK_orders_billingAddressId_address"
12
+ `);
13
+
14
+ await queryRunner.query(`
15
+ ALTER TABLE "orders"
16
+ DROP CONSTRAINT IF EXISTS "FK_orders_shippingAddressId_address"
17
+ `);
18
+
19
+ await queryRunner.query(`
20
+ ALTER TABLE "orders"
21
+ ADD CONSTRAINT "FK_orders_billing_order_address"
22
+ FOREIGN KEY ("billingAddressId")
23
+ REFERENCES "order_addresses"("id")
24
+ ON DELETE SET NULL
25
+ `);
26
+
27
+ await queryRunner.query(`
28
+ ALTER TABLE "orders"
29
+ ADD CONSTRAINT "FK_orders_shipping_order_address"
30
+ FOREIGN KEY ("shippingAddressId")
31
+ REFERENCES "order_addresses"("id")
32
+ ON DELETE SET NULL
33
+ `);
34
+
35
+ await queryRunner.query(`
36
+ ALTER TABLE "order_addresses"
37
+ DROP CONSTRAINT IF EXISTS "FK_order_addresses_contact"
38
+ `);
39
+
40
+ await queryRunner.query(`
41
+ ALTER TABLE "order_addresses"
42
+ ADD CONSTRAINT "FK_order_addresses_contact"
43
+ FOREIGN KEY ("contactId")
44
+ REFERENCES "contacts"("id")
45
+ ON DELETE CASCADE
46
+ `);
47
+ }
48
+
49
+ public async down(queryRunner: QueryRunner): Promise<void> {
50
+ await queryRunner.query(`
51
+ ALTER TABLE "orders"
52
+ DROP CONSTRAINT IF EXISTS "FK_orders_billing_order_address"
53
+ `);
54
+
55
+ await queryRunner.query(`
56
+ ALTER TABLE "orders"
57
+ DROP CONSTRAINT IF EXISTS "FK_orders_shipping_order_address"
58
+ `);
59
+
60
+ await queryRunner.query(`
61
+ ALTER TABLE "orders"
62
+ ADD CONSTRAINT "FK_orders_billingAddressId_address"
63
+ FOREIGN KEY ("billingAddressId")
64
+ REFERENCES "address"("id")
65
+ ON DELETE SET NULL
66
+ `);
67
+
68
+ await queryRunner.query(`
69
+ ALTER TABLE "orders"
70
+ ADD CONSTRAINT "FK_orders_shippingAddressId_address"
71
+ FOREIGN KEY ("shippingAddressId")
72
+ REFERENCES "address"("id")
73
+ ON DELETE SET NULL
74
+ `);
75
+
76
+ await queryRunner.query(`
77
+ ALTER TABLE "order_addresses"
78
+ DROP CONSTRAINT IF EXISTS "FK_order_addresses_contact"
79
+ `);
80
+
81
+ await queryRunner.query(`
82
+ ALTER TABLE "order_addresses"
83
+ ADD CONSTRAINT "FK_order_addresses_contact"
84
+ FOREIGN KEY ("contactId")
85
+ REFERENCES "contacts"("id")
86
+ `);
87
+ }
88
+ }
@@ -0,0 +1,100 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class UpdateDiscountAndRules1778652250862 implements MigrationInterface {
4
+ name = 'UpdateDiscountAndRules1778652250862'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+
8
+ // Add isAutomatic column
9
+ await queryRunner.query(`
10
+ ALTER TABLE "discounts"
11
+ ADD COLUMN "isAutomatic" boolean NOT NULL DEFAULT false
12
+ `);
13
+
14
+ // Add currency column
15
+ await queryRunner.query(`
16
+ ALTER TABLE "discounts"
17
+ ADD COLUMN "currency" varchar NOT NULL DEFAULT 'INR'
18
+ `);
19
+
20
+ // Update enum for discount_rules.type
21
+ await queryRunner.query(`
22
+ ALTER TYPE "public"."discount_rules_type_enum"
23
+ RENAME TO "discount_rules_type_enum_old"
24
+ `);
25
+
26
+ await queryRunner.query(`
27
+ CREATE TYPE "public"."discount_rules_type_enum" AS ENUM(
28
+ 'minAmount',
29
+ 'user',
30
+ 'product',
31
+ 'category',
32
+ 'cart',
33
+ 'paymentMethod',
34
+ 'order',
35
+ 'quantity',
36
+ 'time',
37
+ 'shipping',
38
+ 'referral',
39
+ 'reward'
40
+ )
41
+ `);
42
+
43
+ await queryRunner.query(`
44
+ ALTER TABLE "discount_rules"
45
+ ALTER COLUMN "type"
46
+ TYPE "public"."discount_rules_type_enum"
47
+ USING "type"::text::"public"."discount_rules_type_enum"
48
+ `);
49
+
50
+ await queryRunner.query(`
51
+ DROP TYPE "public"."discount_rules_type_enum_old"
52
+ `);
53
+ }
54
+
55
+ public async down(queryRunner: QueryRunner): Promise<void> {
56
+
57
+ // Revert enum changes
58
+ await queryRunner.query(`
59
+ CREATE TYPE "public"."discount_rules_type_enum_old" AS ENUM(
60
+ 'minAmount',
61
+ 'user',
62
+ 'product',
63
+ 'category',
64
+ 'cart',
65
+ 'paymentMethod',
66
+ 'order',
67
+ 'quantity',
68
+ 'time',
69
+ 'shipping'
70
+ )
71
+ `);
72
+
73
+ await queryRunner.query(`
74
+ ALTER TABLE "discount_rules"
75
+ ALTER COLUMN "type"
76
+ TYPE "public"."discount_rules_type_enum_old"
77
+ USING "type"::text::"public"."discount_rules_type_enum_old"
78
+ `);
79
+
80
+ await queryRunner.query(`
81
+ DROP TYPE "public"."discount_rules_type_enum"
82
+ `);
83
+
84
+ await queryRunner.query(`
85
+ ALTER TYPE "public"."discount_rules_type_enum_old"
86
+ RENAME TO "discount_rules_type_enum"
87
+ `);
88
+
89
+ // Remove added columns
90
+ await queryRunner.query(`
91
+ ALTER TABLE "discounts"
92
+ DROP COLUMN "currency"
93
+ `);
94
+
95
+ await queryRunner.query(`
96
+ ALTER TABLE "discounts"
97
+ DROP COLUMN "isAutomatic"
98
+ `);
99
+ }
100
+ }
@@ -0,0 +1,19 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class MakeCouponCodeNullable1778652250863 implements MigrationInterface {
4
+ name = 'MakeCouponCodeNullable1778652250863'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`
8
+ ALTER TABLE "discounts"
9
+ ALTER COLUMN "couponCode" DROP NOT NULL
10
+ `);
11
+ }
12
+
13
+ public async down(queryRunner: QueryRunner): Promise<void> {
14
+ await queryRunner.query(`
15
+ ALTER TABLE "discounts"
16
+ ALTER COLUMN "couponCode" SET NOT NULL
17
+ `);
18
+ }
19
+ }
@@ -0,0 +1,22 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class RemoveUniqueConstraintFromDiscountCouponCode1778652250864
4
+ implements MigrationInterface
5
+ {
6
+ name = 'RemoveUniqueConstraintFromDiscountCouponCode1778652250864';
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ await queryRunner.query(`
10
+ ALTER TABLE "discounts"
11
+ DROP CONSTRAINT IF EXISTS "discounts_couponCode_key"
12
+ `);
13
+ }
14
+
15
+ public async down(queryRunner: QueryRunner): Promise<void> {
16
+ await queryRunner.query(`
17
+ ALTER TABLE "discounts"
18
+ ADD CONSTRAINT "discounts_couponCode_key"
19
+ UNIQUE ("couponCode")
20
+ `);
21
+ }
22
+ }
@@ -0,0 +1,71 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ export class RemoveOldOrdersAddressForeignKeys1778652250865
4
+ implements MigrationInterface
5
+ {
6
+ name = 'RemoveOldOrdersAddressForeignKeys1778652250866';
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ // Remove old FK constraints pointing to addresses table
10
+ await queryRunner.query(`
11
+ ALTER TABLE "orders"
12
+ DROP CONSTRAINT IF EXISTS "FK_orders_billing_address"
13
+ `);
14
+
15
+ await queryRunner.query(`
16
+ ALTER TABLE "orders"
17
+ DROP CONSTRAINT IF EXISTS "FK_orders_shipping_address"
18
+ `);
19
+
20
+ // Remove possible alternate old constraint names
21
+ await queryRunner.query(`
22
+ ALTER TABLE "orders"
23
+ DROP CONSTRAINT IF EXISTS "FK_orders_billingAddressId_address"
24
+ `);
25
+
26
+ await queryRunner.query(`
27
+ ALTER TABLE "orders"
28
+ DROP CONSTRAINT IF EXISTS "FK_orders_shippingAddressId_address"
29
+ `);
30
+
31
+ await queryRunner.query(`
32
+ DO $$ BEGIN
33
+ ALTER TABLE "orders"
34
+ ADD CONSTRAINT "FK_orders_billing_order_address"
35
+ FOREIGN KEY ("billingAddressId") REFERENCES "order_addresses"("id")
36
+ ON DELETE SET NULL ON UPDATE NO ACTION;
37
+ EXCEPTION WHEN duplicate_object THEN NULL;
38
+ END $$;
39
+ `);
40
+
41
+ await queryRunner.query(`
42
+ DO $$ BEGIN
43
+ ALTER TABLE "orders"
44
+ ADD CONSTRAINT "FK_orders_shipping_order_address"
45
+ FOREIGN KEY ("shippingAddressId") REFERENCES "order_addresses"("id")
46
+ ON DELETE SET NULL ON UPDATE NO ACTION;
47
+ EXCEPTION WHEN duplicate_object THEN NULL;
48
+ END $$;
49
+ `);
50
+ }
51
+
52
+ public async down(queryRunner: QueryRunner): Promise<void> {
53
+ // Restore old constraints back to addresses table
54
+
55
+ await queryRunner.query(`
56
+ ALTER TABLE "orders"
57
+ ADD CONSTRAINT "FK_orders_billing_address"
58
+ FOREIGN KEY ("billingAddressId")
59
+ REFERENCES "addresses"("id")
60
+ ON DELETE SET NULL
61
+ `);
62
+
63
+ await queryRunner.query(`
64
+ ALTER TABLE "orders"
65
+ ADD CONSTRAINT "FK_orders_shipping_address"
66
+ FOREIGN KEY ("shippingAddressId")
67
+ REFERENCES "addresses"("id")
68
+ ON DELETE SET NULL
69
+ `);
70
+ }
71
+ }
@@ -0,0 +1,90 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ /**
4
+ * Scope discounts to a vendor store (`vendorId` column, FK, RLS, permissions).
5
+ */
6
+ export class DiscountVendorId1778660000000 implements MigrationInterface {
7
+ name = 'DiscountVendorId1778660000000';
8
+
9
+ public async up(queryRunner: QueryRunner): Promise<void> {
10
+ await queryRunner.query(`ALTER TABLE "discounts" ADD COLUMN IF NOT EXISTS "vendorId" integer`);
11
+
12
+ await queryRunner.query(`
13
+ UPDATE "discounts" d
14
+ SET "vendorId" = COALESCE(
15
+ (SELECT o."vendorId" FROM "order_discounts" od
16
+ INNER JOIN "orders" o ON o.id = od."orderId"
17
+ WHERE od."discountId" = d.id
18
+ ORDER BY od.id DESC LIMIT 1),
19
+ (SELECT id FROM "vendors" WHERE "slug" = 'default' LIMIT 1)
20
+ )
21
+ WHERE d."vendorId" IS NULL
22
+ `);
23
+
24
+ await queryRunner.query(`ALTER TABLE "discounts" ALTER COLUMN "vendorId" SET NOT NULL`);
25
+
26
+ await queryRunner.query(`
27
+ DO $$ BEGIN
28
+ ALTER TABLE "discounts" ADD CONSTRAINT "FK_discounts_vendorId"
29
+ FOREIGN KEY ("vendorId") REFERENCES "vendors"("id") ON DELETE RESTRICT ON UPDATE NO ACTION;
30
+ EXCEPTION WHEN duplicate_object THEN NULL;
31
+ END $$
32
+ `);
33
+
34
+ await queryRunner.query(
35
+ `CREATE INDEX IF NOT EXISTS "IDX_discounts_vendorId" ON "discounts" ("vendorId")`
36
+ );
37
+
38
+ await queryRunner.query(`
39
+ CREATE UNIQUE INDEX IF NOT EXISTS "UQ_discounts_vendor_couponCode"
40
+ ON "discounts" ("vendorId", "couponCode")
41
+ WHERE "couponCode" IS NOT NULL AND TRIM("couponCode") <> ''
42
+ `);
43
+
44
+ await queryRunner.query(`ALTER TABLE "discounts" ENABLE ROW LEVEL SECURITY`);
45
+ await queryRunner.query(`ALTER TABLE "discounts" FORCE ROW LEVEL SECURITY`);
46
+ await queryRunner.query(`DROP POLICY IF EXISTS "vendor_isolation" ON "discounts"`);
47
+ await queryRunner.query(`
48
+ CREATE POLICY "vendor_isolation" ON "discounts"
49
+ USING (
50
+ COALESCE(NULLIF(current_setting('app.vendor_id', true), ''), '0') = '0'
51
+ OR "vendorId" = NULLIF(current_setting('app.vendor_id', true), '')::integer
52
+ )
53
+ WITH CHECK (
54
+ COALESCE(NULLIF(current_setting('app.vendor_id', true), ''), '0') = '0'
55
+ OR "vendorId" = NULLIF(current_setting('app.vendor_id', true), '')::integer
56
+ )
57
+ `);
58
+
59
+ await queryRunner.query(`
60
+ INSERT INTO "permissions" ("groupId", "entity", "canCreate", "canRead", "canUpdate", "canDelete")
61
+ SELECT g.id, 'discounts', true, true, true, true
62
+ FROM "user_groups" g
63
+ WHERE g.deleted = false
64
+ AND lower(g.name) LIKE '%vendor%'
65
+ AND g.name <> 'Administrator'
66
+ ON CONFLICT ("groupId", "entity") DO NOTHING
67
+ `);
68
+ }
69
+
70
+ public async down(queryRunner: QueryRunner): Promise<void> {
71
+ await queryRunner.query(`
72
+ DELETE FROM "permissions" p
73
+ USING "user_groups" g
74
+ WHERE p."groupId" = g.id
75
+ AND g.deleted = false
76
+ AND lower(g.name) LIKE '%vendor%'
77
+ AND g.name <> 'Administrator'
78
+ AND p.entity = 'discounts'
79
+ `);
80
+
81
+ await queryRunner.query(`DROP POLICY IF EXISTS "vendor_isolation" ON "discounts"`);
82
+ await queryRunner.query(`ALTER TABLE "discounts" NO FORCE ROW LEVEL SECURITY`);
83
+ await queryRunner.query(`ALTER TABLE "discounts" DISABLE ROW LEVEL SECURITY`);
84
+
85
+ await queryRunner.query(`DROP INDEX IF EXISTS "UQ_discounts_vendor_couponCode"`);
86
+ await queryRunner.query(`ALTER TABLE "discounts" DROP CONSTRAINT IF EXISTS "FK_discounts_vendorId"`);
87
+ await queryRunner.query(`DROP INDEX IF EXISTS "IDX_discounts_vendorId"`);
88
+ await queryRunner.query(`ALTER TABLE "discounts" DROP COLUMN IF EXISTS "vendorId"`);
89
+ }
90
+ }
@@ -0,0 +1,79 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ /**
4
+ * Orders.billingAddressId / shippingAddressId must reference order_addresses,
5
+ * not the legacy contacts `addresses` table (TypeORM / old migrations may leave wrong FKs).
6
+ */
7
+ export class FixOrdersAddressFkToOrderAddresses1778660000001 implements MigrationInterface {
8
+ name = 'FixOrdersAddressFkToOrderAddresses1778660000001';
9
+
10
+ public async up(queryRunner: QueryRunner): Promise<void> {
11
+ await queryRunner.query(`
12
+ DO $$
13
+ DECLARE r RECORD;
14
+ BEGIN
15
+ FOR r IN
16
+ SELECT con.conname AS conname
17
+ FROM pg_constraint con
18
+ INNER JOIN pg_class rel ON rel.oid = con.conrelid AND rel.relname = 'orders'
19
+ INNER JOIN pg_class frel ON frel.oid = con.confrelid AND frel.relname = 'addresses'
20
+ WHERE con.contype = 'f'
21
+ AND EXISTS (
22
+ SELECT 1
23
+ FROM pg_attribute a
24
+ WHERE a.attrelid = con.conrelid
25
+ AND a.attnum = ANY (con.conkey)
26
+ AND a.attname IN ('billingAddressId', 'shippingAddressId')
27
+ )
28
+ LOOP
29
+ EXECUTE format('ALTER TABLE orders DROP CONSTRAINT IF EXISTS %I', r.conname);
30
+ END LOOP;
31
+ END $$;
32
+ `);
33
+
34
+ await queryRunner.query(`
35
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_orders_billing_address"
36
+ `);
37
+ await queryRunner.query(`
38
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_orders_shipping_address"
39
+ `);
40
+ await queryRunner.query(`
41
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_orders_billingAddressId_address"
42
+ `);
43
+ await queryRunner.query(`
44
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_orders_shippingAddressId_address"
45
+ `);
46
+ await queryRunner.query(`
47
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_820a4c09ddad44884a97378d336"
48
+ `);
49
+
50
+ await queryRunner.query(`
51
+ DO $$ BEGIN
52
+ ALTER TABLE "orders"
53
+ ADD CONSTRAINT "FK_orders_billing_order_address"
54
+ FOREIGN KEY ("billingAddressId") REFERENCES "order_addresses"("id")
55
+ ON DELETE SET NULL ON UPDATE NO ACTION;
56
+ EXCEPTION WHEN duplicate_object THEN NULL;
57
+ END $$;
58
+ `);
59
+
60
+ await queryRunner.query(`
61
+ DO $$ BEGIN
62
+ ALTER TABLE "orders"
63
+ ADD CONSTRAINT "FK_orders_shipping_order_address"
64
+ FOREIGN KEY ("shippingAddressId") REFERENCES "order_addresses"("id")
65
+ ON DELETE SET NULL ON UPDATE NO ACTION;
66
+ EXCEPTION WHEN duplicate_object THEN NULL;
67
+ END $$;
68
+ `);
69
+ }
70
+
71
+ public async down(queryRunner: QueryRunner): Promise<void> {
72
+ await queryRunner.query(`
73
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_orders_billing_order_address"
74
+ `);
75
+ await queryRunner.query(`
76
+ ALTER TABLE "orders" DROP CONSTRAINT IF EXISTS "FK_orders_shipping_order_address"
77
+ `);
78
+ }
79
+ }