vr-migrations 1.0.11 → 1.0.13

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.
@@ -1,82 +1,112 @@
1
+ // migrations/XXXXXXXXXXXXXX-create-pricings.js
1
2
  "use strict";
2
3
 
3
4
  module.exports = {
4
- async up(queryInterface, Sequelize) {
5
+ up: async (queryInterface, Sequelize) => {
5
6
  await queryInterface.createTable("pricings", {
6
7
  id: {
7
8
  type: Sequelize.UUID,
8
9
  defaultValue: Sequelize.UUIDV4,
9
10
  primaryKey: true,
10
- allowNull: false
11
+ allowNull: false,
11
12
  },
12
-
13
13
  productId: {
14
14
  type: Sequelize.UUID,
15
15
  allowNull: false,
16
16
  references: {
17
17
  model: "products",
18
- key: "id"
18
+ key: "id",
19
19
  },
20
20
  onUpdate: "CASCADE",
21
- onDelete: "CASCADE"
21
+ onDelete: "CASCADE",
22
22
  },
23
-
24
23
  name: {
25
24
  type: Sequelize.STRING(100),
26
- allowNull: false
25
+ allowNull: false,
27
26
  },
28
-
29
- upfrontPrice: {
27
+ type: {
28
+ type: Sequelize.ENUM("HIRE_PURCHASE", "FULL_PAYMENT"),
29
+ allowNull: false,
30
+ },
31
+ totalAmount: {
30
32
  type: Sequelize.DECIMAL(10, 2),
31
- allowNull: false
33
+ allowNull: false,
34
+ field: "total_amount",
32
35
  },
33
-
34
36
  downPayment: {
35
37
  type: Sequelize.DECIMAL(10, 2),
36
38
  allowNull: false,
37
- defaultValue: 0
39
+ defaultValue: 0,
38
40
  },
39
-
40
41
  installmentAmount: {
41
42
  type: Sequelize.DECIMAL(10, 2),
42
- allowNull: true
43
+ allowNull: true,
43
44
  },
44
-
45
- installmentIntervalDays: {
45
+ installmentFrequency: {
46
+ type: Sequelize.ENUM("DAILY", "WEEKLY", "MONTHLY"),
47
+ allowNull: true,
48
+ },
49
+ installmentCount: {
46
50
  type: Sequelize.INTEGER,
47
- allowNull: true
51
+ allowNull: true,
48
52
  },
49
-
50
- totalAmount: {
51
- type: Sequelize.DECIMAL(10, 2),
52
- allowNull: false
53
+ gracePeriodDays: {
54
+ type: Sequelize.INTEGER,
55
+ allowNull: false,
56
+ defaultValue: 2,
57
+ },
58
+ autoLockOnMiss: {
59
+ type: Sequelize.BOOLEAN,
60
+ allowNull: false,
61
+ defaultValue: true,
53
62
  },
54
-
55
63
  isActive: {
56
64
  type: Sequelize.BOOLEAN,
57
65
  allowNull: false,
58
- defaultValue: true
66
+ defaultValue: true,
59
67
  },
60
-
61
68
  createdAt: {
62
69
  type: Sequelize.DATE,
63
70
  allowNull: false,
64
- defaultValue: Sequelize.fn("NOW")
71
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
65
72
  },
66
-
67
73
  updatedAt: {
68
74
  type: Sequelize.DATE,
69
75
  allowNull: false,
70
- defaultValue: Sequelize.fn("NOW")
71
- }
76
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
77
+ },
72
78
  });
73
79
 
74
- // Optional but recommended indexes
75
- await queryInterface.addIndex("pricings", ["productId"]);
76
- await queryInterface.addIndex("pricings", ["isActive"]);
80
+ // Add indexes
81
+ await queryInterface.addIndex("pricings", ["productId"], {
82
+ name: "pricings_product_id_idx",
83
+ });
84
+
85
+ await queryInterface.addIndex("pricings", ["type"], {
86
+ name: "pricings_type_idx",
87
+ });
88
+
89
+ await queryInterface.addIndex("pricings", ["isActive"], {
90
+ name: "pricings_is_active_idx",
91
+ });
92
+
93
+ // Add composite unique constraint for productId + name
94
+ await queryInterface.addIndex("pricings", ["productId", "name"], {
95
+ name: "pricings_product_id_name_unique",
96
+ unique: true,
97
+ });
77
98
  },
78
99
 
79
- async down(queryInterface) {
100
+ down: async (queryInterface, Sequelize) => {
101
+ // Drop ENUMs first
102
+ await queryInterface.sequelize.query(
103
+ 'DROP TYPE IF EXISTS "enum_pricings_type";'
104
+ );
105
+ await queryInterface.sequelize.query(
106
+ 'DROP TYPE IF EXISTS "enum_pricings_installmentFrequency";'
107
+ );
108
+
109
+ // Drop table
80
110
  await queryInterface.dropTable("pricings");
81
- }
111
+ },
82
112
  };
@@ -0,0 +1,96 @@
1
+ // migrations/XXXXXXXXXXXXXX-create-device-payment-plans.js
2
+ "use strict";
3
+
4
+ module.exports = {
5
+ up: async (queryInterface, Sequelize) => {
6
+ await queryInterface.createTable("device_payment_plans", {
7
+ id: {
8
+ type: Sequelize.UUID,
9
+ defaultValue: Sequelize.UUIDV4,
10
+ primaryKey: true,
11
+ allowNull: false,
12
+ },
13
+ userId: {
14
+ type: Sequelize.UUID,
15
+ allowNull: false,
16
+ references: {
17
+ model: "users",
18
+ key: "id",
19
+ },
20
+ onUpdate: "CASCADE",
21
+ onDelete: "RESTRICT",
22
+ },
23
+ pricingSnapshot: {
24
+ type: Sequelize.JSONB,
25
+ allowNull: false,
26
+ },
27
+ paidAmount: {
28
+ type: Sequelize.FLOAT,
29
+ allowNull: false,
30
+ defaultValue: 0,
31
+ },
32
+ outstandingAmount: {
33
+ type: Sequelize.FLOAT,
34
+ allowNull: false,
35
+ },
36
+ lastPaymentAt: {
37
+ type: Sequelize.DATE,
38
+ allowNull: true,
39
+ },
40
+ nextInstallmentDueAt: {
41
+ type: Sequelize.DATE,
42
+ allowNull: true,
43
+ },
44
+ status: {
45
+ type: Sequelize.ENUM("ACTIVE", "COMPLETED", "DEFAULTED", "CANCELLED"),
46
+ allowNull: false,
47
+ defaultValue: "ACTIVE",
48
+ },
49
+ completedAt: {
50
+ type: Sequelize.DATE,
51
+ allowNull: true,
52
+ },
53
+ createdAt: {
54
+ type: Sequelize.DATE,
55
+ allowNull: false,
56
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
57
+ },
58
+ updatedAt: {
59
+ type: Sequelize.DATE,
60
+ allowNull: false,
61
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
62
+ },
63
+ });
64
+
65
+ // Add indexes
66
+ await queryInterface.addIndex("device_payment_plans", ["userId"], {
67
+ name: "device_payment_plans_user_id_idx",
68
+ });
69
+
70
+ await queryInterface.addIndex("device_payment_plans", ["status"], {
71
+ name: "device_payment_plans_status_idx",
72
+ });
73
+
74
+ await queryInterface.addIndex(
75
+ "device_payment_plans",
76
+ ["nextInstallmentDueAt"],
77
+ {
78
+ name: "device_payment_plans_next_due_idx",
79
+ }
80
+ );
81
+
82
+ await queryInterface.addIndex("device_payment_plans", ["createdAt"], {
83
+ name: "device_payment_plans_created_at_idx",
84
+ });
85
+ },
86
+
87
+ down: async (queryInterface, Sequelize) => {
88
+ // Drop ENUM first
89
+ await queryInterface.sequelize.query(
90
+ 'DROP TYPE IF EXISTS "enum_device_payment_plans_status";'
91
+ );
92
+
93
+ // Drop table
94
+ await queryInterface.dropTable("device_payment_plans");
95
+ },
96
+ };
@@ -0,0 +1,103 @@
1
+ // migrations/XXXXXXXXXXXXXX-create-devices.js (UPDATED)
2
+ "use strict";
3
+
4
+ module.exports = {
5
+ up: async (queryInterface, Sequelize) => {
6
+ await queryInterface.createTable("devices", {
7
+ id: {
8
+ type: Sequelize.UUID,
9
+ defaultValue: Sequelize.UUIDV4,
10
+ primaryKey: true,
11
+ allowNull: false,
12
+ },
13
+ serialNumber: {
14
+ type: Sequelize.STRING(64),
15
+ allowNull: false,
16
+ unique: true,
17
+ },
18
+ productId: {
19
+ type: Sequelize.UUID,
20
+ allowNull: false,
21
+ references: {
22
+ model: "products",
23
+ key: "id",
24
+ },
25
+ onUpdate: "CASCADE",
26
+ onDelete: "RESTRICT",
27
+ },
28
+ devicePaymentPlanId: {
29
+ type: Sequelize.UUID,
30
+ allowNull: true,
31
+ references: {
32
+ model: "device_payment_plans",
33
+ key: "id",
34
+ },
35
+ onUpdate: "CASCADE",
36
+ onDelete: "SET NULL",
37
+ },
38
+ status: {
39
+ type: Sequelize.ENUM("locked", "unlocked", "disabled"),
40
+ allowNull: false,
41
+ defaultValue: "locked",
42
+ },
43
+ dedicatedUser: {
44
+ type: Sequelize.ENUM("PASSENGER", "RIDER", "N/A"),
45
+ allowNull: false,
46
+ defaultValue: "N/A",
47
+ },
48
+ isPermanentlyUnlocked: {
49
+ type: Sequelize.BOOLEAN,
50
+ allowNull: false,
51
+ defaultValue: false,
52
+ },
53
+ activatedAt: {
54
+ type: Sequelize.DATE,
55
+ allowNull: true,
56
+ },
57
+ createdAt: {
58
+ type: Sequelize.DATE,
59
+ allowNull: false,
60
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
61
+ },
62
+ updatedAt: {
63
+ type: Sequelize.DATE,
64
+ allowNull: false,
65
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
66
+ },
67
+ });
68
+
69
+ // Add indexes
70
+ await queryInterface.addIndex("devices", ["serialNumber"], {
71
+ name: "devices_serial_number_idx",
72
+ });
73
+
74
+ await queryInterface.addIndex("devices", ["productId"], {
75
+ name: "devices_product_id_idx",
76
+ });
77
+
78
+ await queryInterface.addIndex("devices", ["devicePaymentPlanId"], {
79
+ name: "devices_payment_plan_id_idx",
80
+ });
81
+
82
+ await queryInterface.addIndex("devices", ["status"], {
83
+ name: "devices_status_idx",
84
+ });
85
+
86
+ await queryInterface.addIndex("devices", ["dedicatedUser"], {
87
+ name: "devices_dedicated_user_idx",
88
+ });
89
+ },
90
+
91
+ down: async (queryInterface, Sequelize) => {
92
+ // Drop ENUMs first
93
+ await queryInterface.sequelize.query(
94
+ 'DROP TYPE IF EXISTS "enum_devices_status";'
95
+ );
96
+ await queryInterface.sequelize.query(
97
+ 'DROP TYPE IF EXISTS "enum_devices_dedicatedUser";'
98
+ );
99
+
100
+ // Drop table
101
+ await queryInterface.dropTable("devices");
102
+ },
103
+ };
@@ -0,0 +1,117 @@
1
+ // migrations/XXXXXXXXXXXXXX-create-installments.js
2
+ "use strict";
3
+
4
+ module.exports = {
5
+ up: async (queryInterface, Sequelize) => {
6
+ await queryInterface.createTable("installments", {
7
+ id: {
8
+ type: Sequelize.UUID,
9
+ defaultValue: Sequelize.UUIDV4,
10
+ primaryKey: true,
11
+ allowNull: false,
12
+ },
13
+ devicePaymentPlanId: {
14
+ type: Sequelize.UUID,
15
+ allowNull: false,
16
+ references: {
17
+ model: "device_payment_plans",
18
+ key: "id",
19
+ },
20
+ onUpdate: "CASCADE",
21
+ onDelete: "CASCADE",
22
+ },
23
+ installmentNumber: {
24
+ type: Sequelize.INTEGER,
25
+ allowNull: false,
26
+ },
27
+ amount: {
28
+ type: Sequelize.DECIMAL(10, 2),
29
+ allowNull: false,
30
+ validate: {
31
+ min: 0,
32
+ },
33
+ },
34
+ dueDate: {
35
+ type: Sequelize.DATE,
36
+ allowNull: false,
37
+ },
38
+ paidAt: {
39
+ type: Sequelize.DATE,
40
+ allowNull: true,
41
+ },
42
+ paidAmount: {
43
+ type: Sequelize.DECIMAL(10, 2),
44
+ allowNull: true,
45
+ },
46
+ status: {
47
+ type: Sequelize.ENUM("PENDING", "PAID", "OVERDUE", "SKIPPED"),
48
+ allowNull: false,
49
+ defaultValue: "PENDING",
50
+ },
51
+ paymentId: {
52
+ type: Sequelize.UUID,
53
+ allowNull: true,
54
+ references: {
55
+ model: "payments",
56
+ key: "id",
57
+ },
58
+ onUpdate: "CASCADE",
59
+ onDelete: "SET NULL",
60
+ },
61
+ isAutoGenerated: {
62
+ type: Sequelize.BOOLEAN,
63
+ allowNull: false,
64
+ defaultValue: true,
65
+ },
66
+ metadata: {
67
+ type: Sequelize.JSONB,
68
+ allowNull: false,
69
+ defaultValue: {},
70
+ },
71
+ createdAt: {
72
+ type: Sequelize.DATE,
73
+ allowNull: false,
74
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
75
+ },
76
+ updatedAt: {
77
+ type: Sequelize.DATE,
78
+ allowNull: false,
79
+ defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
80
+ },
81
+ });
82
+
83
+ // Add unique constraint for (devicePaymentPlanId, installmentNumber)
84
+ await queryInterface.addConstraint("installments", {
85
+ fields: ["devicePaymentPlanId", "installmentNumber"],
86
+ type: "unique",
87
+ name: "unique_installment_number_per_plan",
88
+ });
89
+
90
+ // Add indexes
91
+ await queryInterface.addIndex("installments", ["devicePaymentPlanId"], {
92
+ name: "installments_plan_id_idx",
93
+ });
94
+
95
+ await queryInterface.addIndex("installments", ["status"], {
96
+ name: "installments_status_idx",
97
+ });
98
+
99
+ await queryInterface.addIndex("installments", ["dueDate"], {
100
+ name: "installments_due_date_idx",
101
+ });
102
+
103
+ await queryInterface.addIndex("installments", ["paymentId"], {
104
+ name: "installments_payment_id_idx",
105
+ });
106
+ },
107
+
108
+ down: async (queryInterface, Sequelize) => {
109
+ // Drop ENUM first
110
+ await queryInterface.sequelize.query(
111
+ 'DROP TYPE IF EXISTS "enum_installments_status";'
112
+ );
113
+
114
+ // Drop table
115
+ await queryInterface.dropTable("installments");
116
+ },
117
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vr-migrations",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Database migration and seeding package for VR applications",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,63 +0,0 @@
1
- "use strict";
2
-
3
- /** @type {import('sequelize').QueryInterface} */
4
- module.exports = {
5
- async up(queryInterface, Sequelize) {
6
- await queryInterface.createTable("devices", {
7
- id: {
8
- type: Sequelize.UUID,
9
- defaultValue: Sequelize.UUIDV4,
10
- primaryKey: true,
11
- allowNull: false
12
- },
13
- serialNumber: {
14
- type: Sequelize.STRING(64),
15
- allowNull: false,
16
- unique: true
17
- },
18
- productId: {
19
- type: Sequelize.UUID,
20
- allowNull: false,
21
- references: {
22
- model: "products",
23
- key: "id"
24
- },
25
- onUpdate: "CASCADE",
26
- onDelete: "RESTRICT"
27
- },
28
-
29
- status: {
30
- type: Sequelize.ENUM("locked", "unlocked", "disabled"),
31
- allowNull: false,
32
- defaultValue: "locked"
33
- },
34
- isPermanentlyUnlocked: {
35
- type: Sequelize.BOOLEAN,
36
- allowNull: false,
37
- defaultValue: false
38
- },
39
- activatedAt: {
40
- type: Sequelize.DATE,
41
- allowNull: true
42
- },
43
- createdAt: {
44
- type: Sequelize.DATE,
45
- allowNull: false,
46
- defaultValue: Sequelize.fn("NOW")
47
- },
48
- updatedAt: {
49
- type: Sequelize.DATE,
50
- allowNull: false,
51
- defaultValue: Sequelize.fn("NOW")
52
- }
53
- });
54
- },
55
-
56
- async down(queryInterface) {
57
- await queryInterface.dropTable("devices");
58
-
59
- await queryInterface.sequelize.query(
60
- 'DROP TYPE IF EXISTS "enum_devices_status"'
61
- );
62
- }
63
- };
@@ -1,115 +0,0 @@
1
- "use strict";
2
-
3
- /** @type {import('sequelize').QueryInterface} */
4
- module.exports = {
5
- async up(queryInterface, Sequelize) {
6
- await queryInterface.createTable("device_payment_plans", {
7
- id: {
8
- type: Sequelize.UUID,
9
- defaultValue: Sequelize.UUIDV4,
10
- primaryKey: true,
11
- allowNull: false
12
- },
13
- deviceId: {
14
- type: Sequelize.UUID,
15
- allowNull: false,
16
- unique: true,
17
- references: {
18
- model: "devices",
19
- key: "id"
20
- },
21
- onUpdate: "CASCADE",
22
- onDelete: "CASCADE"
23
- },
24
- userId: {
25
- type: Sequelize.UUID,
26
- allowNull: false,
27
- references: {
28
- model: "users",
29
- key: "id"
30
- },
31
- onUpdate: "CASCADE",
32
- onDelete: "CASCADE"
33
- },
34
- pricingSnapshot: {
35
- type: Sequelize.JSONB,
36
- allowNull: false
37
- },
38
- totalAmount: {
39
- type: Sequelize.FLOAT,
40
- allowNull: false
41
- },
42
- downPayment: {
43
- type: Sequelize.FLOAT,
44
- allowNull: false
45
- },
46
- installmentAmount: {
47
- type: Sequelize.FLOAT,
48
- allowNull: false
49
- },
50
- installmentFrequency: {
51
- type: Sequelize.ENUM("DAILY", "WEEKLY", "MONTHLY"),
52
- allowNull: false,
53
- defaultValue: "WEEKLY"
54
- },
55
- paidAmount: {
56
- type: Sequelize.FLOAT,
57
- allowNull: false,
58
- defaultValue: 0
59
- },
60
- outstandingAmount: {
61
- type: Sequelize.FLOAT,
62
- allowNull: false
63
- },
64
- lastPaymentAt: {
65
- type: Sequelize.DATE,
66
- allowNull: true
67
- },
68
- nextInstallmentDueAt: {
69
- type: Sequelize.DATE,
70
- allowNull: true
71
- },
72
- gracePeriodDays: {
73
- type: Sequelize.INTEGER,
74
- allowNull: false,
75
- defaultValue: 2
76
- },
77
- autoLockOnMiss: {
78
- type: Sequelize.BOOLEAN,
79
- allowNull: false,
80
- defaultValue: true
81
- },
82
- status: {
83
- type: Sequelize.ENUM("ACTIVE", "COMPLETED", "DEFAULTED", "CANCELLED"),
84
- allowNull: false,
85
- defaultValue: "ACTIVE"
86
- },
87
- completedAt: {
88
- type: Sequelize.DATE,
89
- allowNull: true
90
- },
91
- createdAt: {
92
- type: Sequelize.DATE,
93
- allowNull: false,
94
- defaultValue: Sequelize.fn("NOW")
95
- },
96
- updatedAt: {
97
- type: Sequelize.DATE,
98
- allowNull: false,
99
- defaultValue: Sequelize.fn("NOW")
100
- }
101
- });
102
- },
103
-
104
- async down(queryInterface) {
105
- await queryInterface.dropTable("device_payment_plans");
106
-
107
- // Remove the enums
108
- await queryInterface.sequelize.query(
109
- 'DROP TYPE IF EXISTS "enum_device_payment_plans_status"'
110
- );
111
- await queryInterface.sequelize.query(
112
- 'DROP TYPE IF EXISTS "enum_device_payment_plans_installmentFrequency"'
113
- );
114
- }
115
- };