@churchsoln/dbms 1.0.9 → 1.0.11

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.
@@ -35,4 +35,11 @@ const ONBOARD_STATUS = {
35
35
  SEED_COMPLETED: "seed_completed",
36
36
  ONBOARD_COMPLETED: "onboard_completed",
37
37
  };
38
- module.exports = { ROLES, TRANSFER_STATUS, QUEUES, WORKERS, AUTH_DATA, ONBOARD_STATUS };
38
+
39
+ const SUBSCRIPTION_PLAN_ID = {
40
+ FREE_TRAIL: 1,
41
+ BASIC: 2,
42
+ PREMIUM: 3,
43
+ CUSTOM: 4
44
+ }
45
+ module.exports = { ROLES, TRANSFER_STATUS, QUEUES, WORKERS, AUTH_DATA, ONBOARD_STATUS, SUBSCRIPTION_PLAN_ID };
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, DataTypes) => {
5
+ await queryInterface
6
+ .createTable(
7
+ "MembershipType",
8
+ {
9
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
10
+ name: { type: DataTypes.STRING },
11
+ isDefault: { type: DataTypes.BOOLEAN, defaultValue: false },
12
+ status: { type: DataTypes.BOOLEAN, defaultValue: true },
13
+ createdAt: {
14
+ type: DataTypes.DATE,
15
+ defaultValue: DataTypes.literal("CURRENT_TIMESTAMP"),
16
+ },
17
+ updatedAt: {
18
+ type: DataTypes.DATE,
19
+ defaultValue: DataTypes.literal("CURRENT_TIMESTAMP"),
20
+ },
21
+ }
22
+ )
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, DataTypes) => {
5
+ return Promise.all([
6
+ queryInterface.addColumn("User", "membershipTypeId", {
7
+ type: DataTypes.INTEGER,
8
+ }).then(() => {
9
+ queryInterface.addConstraint("User", {
10
+ fields: ["membershipTypeId"],
11
+ type: "foreign key",
12
+ name: "user_membershipTypeId_fk",
13
+ references: {
14
+ table: "MembershipType",
15
+ field: "id",
16
+ },
17
+ onDelete: "cascade",
18
+ onUpdate: "cascade",
19
+ });
20
+ })
21
+ ]);
22
+ },
23
+ down: async (queryInterface) => {},
24
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, DataTypes) => {
5
+ return Promise.all([
6
+ queryInterface.addColumn("Permission", "isSubscription", {
7
+ type: DataTypes.BOOLEAN,
8
+ defaultValue: false,
9
+ }),
10
+ queryInterface.addColumn("Permission", "cost", {
11
+ type: DataTypes.FLOAT,
12
+ defaultValue: 0,
13
+ }),
14
+ ]);
15
+ },
16
+ down: async (queryInterface) => {},
17
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, DataTypes) => {
5
+ return Promise.all([
6
+ queryInterface.removeColumn("SubscriptionPlan", "planCost"),
7
+ queryInterface.removeColumn("SubscriptionPlan", "validity"),
8
+ queryInterface.addColumn("SubscriptionPlan", "isFree", {
9
+ type: DataTypes.BOOLEAN,
10
+ defaultValue: false,
11
+ }),
12
+ queryInterface.addColumn("SubscriptionPlan", "isCustom", {
13
+ type: DataTypes.BOOLEAN,
14
+ defaultValue: false,
15
+ }),
16
+ ]);
17
+ },
18
+
19
+ down: async (queryInterface) => {},
20
+ };
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ module.exports = {
3
+ up: async (queryInterface, DataTypes) => {
4
+ await queryInterface
5
+ .createTable(
6
+ "SubscriptionPlanPermission",
7
+ {
8
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
9
+ subscriptionPlanId: { type: DataTypes.INTEGER },
10
+ permissionId: { type: DataTypes.INTEGER },
11
+ status: { type: DataTypes.BOOLEAN, defaultValue: true },
12
+ createdAt: {
13
+ type: DataTypes.DATE,
14
+ defaultValue: DataTypes.literal("CURRENT_TIMESTAMP"),
15
+ },
16
+ updatedAt: {
17
+ type: DataTypes.DATE,
18
+ defaultValue: DataTypes.literal("CURRENT_TIMESTAMP"),
19
+ },
20
+ },
21
+ { timestamps: false }
22
+ )
23
+ .then(() =>
24
+ queryInterface.addConstraint("SubscriptionPlanPermission", {
25
+ fields: ["subscriptionPlanId"],
26
+ type: "foreign key",
27
+ name: "SPlan_SPlanPermission_Fkey",
28
+ references: {
29
+ table: "SubscriptionPlan",
30
+ field: "id",
31
+ },
32
+ onDelete: "cascade",
33
+ onUpdate: "cascade",
34
+ })
35
+ )
36
+ .then(() =>
37
+ queryInterface.addConstraint("SubscriptionPlanPermission", {
38
+ fields: ["permissionId"],
39
+ type: "foreign key",
40
+ name: "SPlan_Permission_Fkey",
41
+ references: {
42
+ table: "Permission",
43
+ field: "id",
44
+ },
45
+ onDelete: "cascade",
46
+ onUpdate: "cascade",
47
+ })
48
+ );
49
+ },
50
+ down: async (queryInterface) => {
51
+ await queryInterface.dropTable("SubscriptionPlanPermission");
52
+ },
53
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, DataTypes) => {
5
+ return Promise.all([
6
+ queryInterface.addColumn("Church", "expiresAt", {
7
+ type: DataTypes.DATEONLY,
8
+ }),
9
+ ]);
10
+ },
11
+ down: async (queryInterface) => {},
12
+ };
@@ -0,0 +1,16 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const membershipType = sequelize.define(
3
+ "MembershipType",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ name: { type: DataTypes.STRING },
7
+ isDefault: { type: DataTypes.BOOLEAN, defaultValue: false },
8
+ status: { type: DataTypes.BOOLEAN, defaultValue: true },
9
+ createdAt: { type: DataTypes.DATE },
10
+ updatedAt: { type: DataTypes.DATE },
11
+ },
12
+ { freezeTableName: true, timestamps: false }
13
+ );
14
+ membershipType.selectedFields = ["id", "name", "isDefault", "status", "createdAt", "updatedAt"];
15
+ return membershipType;
16
+ };
@@ -86,6 +86,12 @@ module.exports = (sequelize, DataTypes) => {
86
86
  postalCode: { type: DataTypes.STRING },
87
87
  showPostal: { type: DataTypes.BOOLEAN, defaultValue: false },
88
88
  otp: { type: DataTypes.INTEGER },
89
+ membershipTypeId: {
90
+ type: DataTypes.INTEGER,
91
+ set(membershipTypeId) {
92
+ this.setDataValue("membershipTypeId", membershipTypeId?.id || membershipTypeId);
93
+ },
94
+ },
89
95
  isUserAuthenticated: { type: DataTypes.BOOLEAN, defaultValue: false },
90
96
  delUpdateAccess: { type: DataTypes.BOOLEAN, defaultValue: false },
91
97
  directoryVisibility: { type: DataTypes.BOOLEAN, defaultValue: false },
@@ -109,6 +115,10 @@ module.exports = (sequelize, DataTypes) => {
109
115
  as: "emergencyContactRelationship",
110
116
  });
111
117
  user.belongsTo(models.subRole, { foreignKey: "subRoleId", as: "subRole" });
118
+ user.belongsTo(models.membershipType, {
119
+ foreignKey: "membershipTypeId",
120
+ as: "membershipType",
121
+ });
112
122
  };
113
123
  user.selectedFields = [
114
124
  "id",
@@ -156,6 +166,7 @@ module.exports = (sequelize, DataTypes) => {
156
166
  "postalCode",
157
167
  "showPostal",
158
168
  "otp",
169
+ "membershipTypeId",
159
170
  "isUserAuthenticated",
160
171
  "delUpdateAccess",
161
172
  "directoryVisibility",
@@ -213,6 +224,7 @@ module.exports = (sequelize, DataTypes) => {
213
224
  "directoryVisibility",
214
225
  "userLoginAccess",
215
226
  "isEmailSubscribed",
227
+ "membershipTypeId",
216
228
  "status",
217
229
  ];
218
230
  user.listFields = [
@@ -226,6 +238,7 @@ module.exports = (sequelize, DataTypes) => {
226
238
  "lastName",
227
239
  "address",
228
240
  "isUserAuthenticated",
241
+ "membershipTypeId",
229
242
  "status",
230
243
  ];
231
244
  user.transferFields = [
@@ -13,6 +13,7 @@ module.exports = (sequelize, DataTypes) => {
13
13
  registeredAt: { type: DataTypes.DATEONLY },
14
14
  subscribedAt: { type: DataTypes.DATEONLY },
15
15
  subscriptionPlanId: { type: DataTypes.INTEGER },
16
+ expiresAt: { type: DataTypes.DATEONLY },
16
17
  dbCreationStatus: {
17
18
  type: DataTypes.STRING,
18
19
  defaultValue: ONBOARD_STATUS.DB_CREATION_IN_PROGRESS,
@@ -44,6 +45,7 @@ module.exports = (sequelize, DataTypes) => {
44
45
  "contactPerson",
45
46
  "registeredAt",
46
47
  "subscribedAt",
48
+ "expiresAt",
47
49
  "subscriptionPlanId",
48
50
  "dbCreationStatus",
49
51
  "migrationStatus",
@@ -4,12 +4,14 @@ module.exports = (sequelize, DataTypes) => {
4
4
  {
5
5
  id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
6
  name: { type: DataTypes.STRING },
7
+ isSubscription: { type: DataTypes.BOOLEAN, defaultValue: false },
8
+ cost: { type: DataTypes.FLOAT, defaultValue: 0 },
7
9
  status: { type: DataTypes.BOOLEAN, defaultValue: true },
8
10
  createdAt: { type: DataTypes.DATE },
9
11
  updatedAt: { type: DataTypes.DATE },
10
12
  },
11
13
  { freezeTableName: true, timestamps: false }
12
14
  );
13
- permission.selectedFields = ["id", "name", "createdAt"];
15
+ permission.selectedFields = ["id", "name", "isSubscription", "cost", "createdAt"];
14
16
  return permission;
15
17
  };
@@ -8,19 +8,25 @@ module.exports = (sequelize, DataTypes) => {
8
8
  autoIncrement: true,
9
9
  },
10
10
  name: { type: DataTypes.STRING },
11
- planCost: { type: DataTypes.INTEGER },
12
- validity: { type: DataTypes.INTEGER },
11
+ isFree: { type: DataTypes.BOOLEAN, defaultValue: false },
12
+ isCustom: { type: DataTypes.BOOLEAN, defaultValue: false },
13
13
  status: { type: DataTypes.BOOLEAN },
14
14
  createdAt: { type: DataTypes.DATE },
15
15
  updatedAt: { type: DataTypes.DATE },
16
16
  },
17
17
  { freezeTableName: true, timestamps: false }
18
18
  );
19
+ subscriptionPlan.associate = function (models) {
20
+ subscriptionPlan.hasMany(models.subscriptionPlanPermission, {
21
+ foreignKey: "subscriptionPlanId",
22
+ as: "subscriptionPlanPermission",
23
+ });
24
+ };
19
25
  subscriptionPlan.selectedFields = [
20
26
  "id",
21
27
  "name",
22
- "planCost",
23
- "validity",
28
+ "isFree",
29
+ "isCustom",
24
30
  "createdAt",
25
31
  "updatedAt",
26
32
  ];
@@ -0,0 +1,33 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const subscriptionPlanPermission = sequelize.define(
3
+ "SubscriptionPlanPermission",
4
+ {
5
+ id: {
6
+ type: DataTypes.INTEGER,
7
+ primaryKey: true,
8
+ autoIncrement: true,
9
+ },
10
+ subscriptionPlanId: { type: DataTypes.INTEGER },
11
+ permissionId: { type: DataTypes.INTEGER },
12
+ status: { type: DataTypes.BOOLEAN },
13
+ createdAt: { type: DataTypes.DATE },
14
+ updatedAt: { type: DataTypes.DATE },
15
+ },
16
+ { freezeTableName: true, timestamps: false }
17
+ );
18
+ subscriptionPlanPermission.associate = function (models) {
19
+ subscriptionPlanPermission.belongsTo(models.permission, {
20
+ foreignKey: "permissionId",
21
+ as: "permission",
22
+ });
23
+ };
24
+ subscriptionPlanPermission.selectedFields = [
25
+ "id",
26
+ "subscriptionPlanId",
27
+ "permissionId",
28
+ "status",
29
+ "createdAt",
30
+ "updatedAt",
31
+ ];
32
+ return subscriptionPlanPermission;
33
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@churchsoln/dbms",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "prestart": "node db-setup.js",
@@ -51,6 +51,8 @@
51
51
  "phoneNumber": "1234",
52
52
  "contactPerson": "string",
53
53
  "subscriptionPlanId": 1,
54
+ "validity": 30,
55
+ "permissionId": [1],
54
56
  "churchAdminDetails": {
55
57
  "firstName": "Jose",
56
58
  "lastName": "Mathew",
@@ -153,6 +155,8 @@
153
155
  "phoneNumber": "1234",
154
156
  "contactPerson": "string",
155
157
  "subscriptionPlanId": 1,
158
+ "validity": 30,
159
+ "permissionId": [1],
156
160
  "status": true
157
161
  }
158
162
  }
@@ -336,6 +340,7 @@
336
340
  "phoneNumber",
337
341
  "contactPerson",
338
342
  "subscriptionPlanId",
343
+ "validity",
339
344
  "churchAdminDetails"
340
345
  ],
341
346
  "type": "object",
@@ -356,6 +361,16 @@
356
361
  "type": "integer",
357
362
  "format": "int32"
358
363
  },
364
+ "validity": {
365
+ "type": "integer",
366
+ "format": "int32"
367
+ },
368
+ "permissionId": {
369
+ "type": "array",
370
+ "items": {
371
+ "type": "number"
372
+ }
373
+ },
359
374
  "churchAdminDetails": {
360
375
  "type": "object",
361
376
  "$ref": "#/components/schemas/ChurchAdminDataRequest"
@@ -367,6 +382,8 @@
367
382
  "phoneNumber": "1234",
368
383
  "contactPerson": "string",
369
384
  "subscriptionPlanId": 1,
385
+ "validity": 30,
386
+ "permissionId": [1],
370
387
  "churchAdminDetails": {
371
388
  "firstName": "Jose",
372
389
  "lastName": "Mathew",
@@ -397,6 +414,16 @@
397
414
  "type": "integer",
398
415
  "format": "int32"
399
416
  },
417
+ "validity": {
418
+ "type": "integer",
419
+ "format": "int32"
420
+ },
421
+ "permissionId": {
422
+ "type": "array",
423
+ "items": {
424
+ "type": "number"
425
+ }
426
+ },
400
427
  "status": {
401
428
  "type": "boolean"
402
429
  }
@@ -407,6 +434,8 @@
407
434
  "phoneNumber": "1234",
408
435
  "contactPerson": "string",
409
436
  "subscriptionPlanId": 1,
437
+ "validity": 30,
438
+ "permissionId": [1],
410
439
  "status": true
411
440
  }
412
441
  },
@@ -44,8 +44,9 @@
44
44
  },
45
45
  "example": {
46
46
  "name": "Free",
47
- "planCost": 0,
48
- "validity": 365
47
+ "subscriptionPlanPermission": [
48
+ { "permissionId": 1 }
49
+ ]
49
50
  }
50
51
  }
51
52
  },
@@ -137,8 +138,9 @@
137
138
  },
138
139
  "example": {
139
140
  "name": "Free",
140
- "planCost": 0,
141
- "validity": 365
141
+ "subscriptionPlanPermission": [
142
+ { "permissionId": 1 }
143
+ ]
142
144
  }
143
145
  }
144
146
  },
@@ -785,25 +787,35 @@
785
787
  },
786
788
  "SubscriptionPlanDataRequest": {
787
789
  "title": "SubscriptionPlanDataRequest",
788
- "required": ["name", "planCost", "validity"],
790
+ "required": ["name", "subscriptionPlanPermission"],
789
791
  "type": "object",
790
792
  "properties": {
791
793
  "name": {
792
794
  "type": "string"
793
795
  },
794
- "planCost": {
795
- "type": "integer",
796
- "format": "int32"
797
- },
798
- "validity": {
799
- "type": "integer",
800
- "format": "int32"
796
+ "subscriptionPlanPermission": {
797
+ "type": "array",
798
+ "items": {
799
+ "type": "object",
800
+ "properties": {
801
+ "permissionId": {
802
+ "type": "integer",
803
+ "format": "int32"
804
+ }
805
+ },
806
+ "example": {
807
+ "permissionId": 1
808
+ }
809
+ }
801
810
  }
802
811
  },
803
812
  "example": {
804
813
  "name": "Free",
805
- "planCost": 0,
806
- "validity": 365
814
+ "subscriptionPlanPermission": [
815
+ {
816
+ "permissionId": 1
817
+ }
818
+ ]
807
819
  }
808
820
  },
809
821
  "AddPermissionDataRequest": {
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ up: async (queryInterface, Sequelize) => {
5
+ const membershipTypes = [
6
+ { name: "Subscription", isDefault: true },
7
+ ];
8
+
9
+ for (const membershipType of membershipTypes) {
10
+ const existingMembershipType = await queryInterface.rawSelect(
11
+ "MembershipType",
12
+ {
13
+ where: { name: membershipType.name },
14
+ },
15
+ ["id"]
16
+ );
17
+
18
+ if (existingMembershipType) {
19
+ await queryInterface.bulkUpdate(
20
+ "MembershipType",
21
+ { isDefault: membershipType.isDefault },
22
+ { name: membershipType.name }
23
+ );
24
+ } else {
25
+ await queryInterface.bulkInsert("MembershipType", [membershipType], {});
26
+ }
27
+ }
28
+ },
29
+
30
+ down: async (queryInterface, Sequelize) => {
31
+ await queryInterface.bulkDelete(
32
+ "MembershipType",
33
+ {
34
+ name: membershipTypes.map((membershipType) => membershipType.name),
35
+ },
36
+ {}
37
+ );
38
+ },
39
+ };
@@ -1,18 +1,25 @@
1
1
  "use strict";
2
2
 
3
+ const { SUBSCRIPTION_PLAN_ID } = require("../../constants");
4
+
3
5
  module.exports = {
4
6
  up: async (queryInterface, Sequelize) => {
5
7
  const subscriptionPlans = [
6
- { name: "Premium", planCost: 100, validity: 365 },
7
- { name: "Basic", planCost: 50, validity: 180 },
8
- { name: "Free Trail", planCost: 0, validity: 30 },
8
+ {
9
+ id: SUBSCRIPTION_PLAN_ID.FREE_TRAIL,
10
+ name: "Free Trail",
11
+ isFree: true
12
+ },
13
+ { id: SUBSCRIPTION_PLAN_ID.BASIC, name: "Basic" },
14
+ { id: SUBSCRIPTION_PLAN_ID.PREMIUM, name: "Premium" },
15
+ { id: SUBSCRIPTION_PLAN_ID.CUSTOM, name: "Custom", isCustom: true },
9
16
  ];
10
17
 
11
18
  for (const plan of subscriptionPlans) {
12
19
  const existingPlan = await queryInterface.rawSelect(
13
20
  "SubscriptionPlan",
14
21
  {
15
- where: { name: plan.name },
22
+ where: { id: plan.id },
16
23
  },
17
24
  ["id"] // Only need the 'id' to check existence
18
25
  );
@@ -20,11 +27,8 @@ module.exports = {
20
27
  if (existingPlan) {
21
28
  await queryInterface.bulkUpdate(
22
29
  "SubscriptionPlan",
23
- {
24
- planCost: plan.planCost, // Update fields if necessary
25
- validity: plan.validity, // Match on 'name'
26
- },
27
- { name: plan.name }
30
+ { name: plan.name, isFree: plan.isFree || false, isCustom: plan.isCustom || false },
31
+ { id: plan.id }
28
32
  );
29
33
  } else {
30
34
  // If the record doesn't exist, insert it
@@ -1,29 +1,183 @@
1
1
  "use strict";
2
2
 
3
+ const { SUBSCRIPTION_PLAN_ID } = require("../../constants");
4
+
3
5
  module.exports = {
4
6
  up: async (queryInterface, Sequelize) => {
5
7
  const permissions = [
6
- { name: "Events & Updates", status: true },
7
- { name: "Ministries at Church", status: true },
8
- { name: "Gallery", status: true },
9
- { name: "Banners", status: true },
10
- { name: "Users", status: true },
11
- { name: "User Transfers", status: true },
12
- { name: "Director Board", status: true },
13
- { name: "Volunteer", status: true },
14
- { name: "Documents", status: true },
15
- { name: "Urls", status: true },
16
- { name: "Accounts", status: true },
17
- { name: "Donations", status: true },
18
- { name: "Transfer Type", status: true },
19
- { name: "Groups", status: true },
8
+ {
9
+ name: "Events & Updates",
10
+ status: true,
11
+ subscriptionPlanId: [
12
+ SUBSCRIPTION_PLAN_ID.FREE_TRAIL,
13
+ SUBSCRIPTION_PLAN_ID.BASIC,
14
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
15
+ SUBSCRIPTION_PLAN_ID.CUSTOM
16
+ ]
17
+ },
18
+ {
19
+ name: "Ministries at Church",
20
+ status: true,
21
+ subscriptionPlanId: [
22
+ SUBSCRIPTION_PLAN_ID.FREE_TRAIL,
23
+ SUBSCRIPTION_PLAN_ID.BASIC,
24
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
25
+ SUBSCRIPTION_PLAN_ID.CUSTOM
26
+ ]
27
+ },
28
+ {
29
+ name: "Gallery",
30
+ status: true,
31
+ subscriptionPlanId: [
32
+ SUBSCRIPTION_PLAN_ID.FREE_TRAIL,
33
+ SUBSCRIPTION_PLAN_ID.BASIC,
34
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
35
+ SUBSCRIPTION_PLAN_ID.CUSTOM
36
+ ]
37
+ },
38
+ {
39
+ name: "Banners",
40
+ status: true,
41
+ subscriptionPlanId: [
42
+ SUBSCRIPTION_PLAN_ID.FREE_TRAIL,
43
+ SUBSCRIPTION_PLAN_ID.BASIC,
44
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
45
+ SUBSCRIPTION_PLAN_ID.CUSTOM
46
+ ]
47
+ },
48
+ {
49
+ name: "Users",
50
+ status: true,
51
+ subscriptionPlanId: [
52
+ SUBSCRIPTION_PLAN_ID.FREE_TRAIL,
53
+ SUBSCRIPTION_PLAN_ID.BASIC,
54
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
55
+ SUBSCRIPTION_PLAN_ID.CUSTOM
56
+ ]
57
+ },
58
+ {
59
+ name: "User Transfers",
60
+ isSubscription: true,
61
+ cost: 0.5,
62
+ status: true,
63
+ subscriptionPlanId: [
64
+ SUBSCRIPTION_PLAN_ID.BASIC,
65
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
66
+ SUBSCRIPTION_PLAN_ID.CUSTOM
67
+ ]
68
+ },
69
+ {
70
+ name: "Director Board",
71
+ isSubscription: true,
72
+ cost: 1,
73
+ status: true,
74
+ subscriptionPlanId: [
75
+ SUBSCRIPTION_PLAN_ID.BASIC,
76
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
77
+ SUBSCRIPTION_PLAN_ID.CUSTOM
78
+ ]
79
+ },
80
+ {
81
+ name: "Volunteer",
82
+ isSubscription: true,
83
+ cost: 0.5,
84
+ status: true,
85
+ subscriptionPlanId: [
86
+ SUBSCRIPTION_PLAN_ID.BASIC,
87
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
88
+ SUBSCRIPTION_PLAN_ID.CUSTOM
89
+ ]
90
+ },
91
+ {
92
+ name: "Documents",
93
+ isSubscription: true,
94
+ cost: 0.5,
95
+ status: true,
96
+ subscriptionPlanId: [
97
+ SUBSCRIPTION_PLAN_ID.BASIC,
98
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
99
+ SUBSCRIPTION_PLAN_ID.CUSTOM
100
+ ]
101
+ },
102
+ {
103
+ name: "Urls",
104
+ isSubscription: true,
105
+ cost: 0.5,
106
+ status: true,
107
+ subscriptionPlanId: [
108
+ SUBSCRIPTION_PLAN_ID.BASIC,
109
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
110
+ SUBSCRIPTION_PLAN_ID.CUSTOM
111
+ ]
112
+ },
113
+ {
114
+ name: "Accounts",
115
+ isSubscription: true,
116
+ cost: 1.5,
117
+ status: true,
118
+ subscriptionPlanId: [
119
+ SUBSCRIPTION_PLAN_ID.BASIC,
120
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
121
+ SUBSCRIPTION_PLAN_ID.CUSTOM
122
+ ]
123
+ },
124
+ {
125
+ name: "Donations",
126
+ isSubscription: true,
127
+ cost: 4,
128
+ status: true,
129
+ subscriptionPlanId: [
130
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
131
+ SUBSCRIPTION_PLAN_ID.CUSTOM
132
+ ]
133
+ },
134
+ {
135
+ name: "Transfer Type",
136
+ isSubscription: true,
137
+ cost: 0.5,
138
+ status: true,
139
+ subscriptionPlanId: [
140
+ SUBSCRIPTION_PLAN_ID.BASIC,
141
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
142
+ SUBSCRIPTION_PLAN_ID.CUSTOM
143
+ ]
144
+ },
145
+ {
146
+ name: "Groups",
147
+ isSubscription: true,
148
+ cost: 3,
149
+ status: true,
150
+ subscriptionPlanId: [
151
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
152
+ SUBSCRIPTION_PLAN_ID.CUSTOM
153
+ ]
154
+ },
155
+ {
156
+ name: "Membership Management",
157
+ isSubscription: true,
158
+ cost: 2,
159
+ status: true,
160
+ subscriptionPlanId: [
161
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
162
+ SUBSCRIPTION_PLAN_ID.CUSTOM
163
+ ]
164
+ },
165
+ {
166
+ name: "Accounts Management",
167
+ isSubscription: true,
168
+ cost: 2,
169
+ status: true,
170
+ subscriptionPlanId: [
171
+ SUBSCRIPTION_PLAN_ID.PREMIUM,
172
+ SUBSCRIPTION_PLAN_ID.CUSTOM
173
+ ]
174
+ },
20
175
  ];
21
-
22
- for (const permission of permissions) {
176
+ for (const [index, { subscriptionPlanId, ...permission}] of permissions.entries()) {
23
177
  const existingPermission = await queryInterface.rawSelect(
24
178
  "Permission",
25
179
  {
26
- where: { name: permission.name },
180
+ where: { id: index + 1 },
27
181
  },
28
182
  ["id"]
29
183
  );
@@ -31,11 +185,37 @@ module.exports = {
31
185
  if (existingPermission) {
32
186
  await queryInterface.bulkUpdate(
33
187
  "Permission",
34
- { status: permission.status },
35
- { name: permission.name }
188
+ {
189
+ name: permission.name,
190
+ status: permission.status,
191
+ isSubscription: permission.isSubscription || false,
192
+ cost: permission.cost || 0,
193
+ },
194
+ { id: index + 1 }
195
+ );
196
+ await queryInterface.bulkDelete(
197
+ "SubscriptionPlanPermission",
198
+ { permissionId: index + 1 },
199
+ {}
200
+ );
201
+ await queryInterface.bulkInsert(
202
+ "SubscriptionPlanPermission",
203
+ subscriptionPlanId.map((planId) => ({
204
+ permissionId: index + 1,
205
+ subscriptionPlanId: planId,
206
+ })),
207
+ {}
36
208
  );
37
209
  } else {
38
- await queryInterface.bulkInsert("Permission", [permission], {});
210
+ await queryInterface.bulkInsert("Permission", [{ id: index + 1, ...permission }], {});
211
+ await queryInterface.bulkInsert(
212
+ "SubscriptionPlanPermission",
213
+ subscriptionPlanId.map((planId) => ({
214
+ permissionId: index + 1,
215
+ subscriptionPlanId: planId,
216
+ })),
217
+ {}
218
+ );
39
219
  }
40
220
  }
41
221
  },
@@ -4,7 +4,7 @@ const errorCodes = require("../config/errorCodes");
4
4
  const errorMsgs = require("../config/errorMsgs");
5
5
  const { masterQueue, masterQueueEvents } = require("../queues");
6
6
  const churchManager = require("../utils/churchManager");
7
- const { QUEUES, ROLES, AUTH_DATA } = require("../constants");
7
+ const { QUEUES, ROLES, AUTH_DATA, SUBSCRIPTION_PLAN_ID } = require("../constants");
8
8
  const bcrypt = require("bcrypt");
9
9
  const cryptr = require("../utils/crypto");
10
10
  const jwt = require("jsonwebtoken");
@@ -12,7 +12,7 @@ const jwt = require("jsonwebtoken");
12
12
  class ChurchService {
13
13
  async onboardChurch(params) {
14
14
  try {
15
- const { name, churchAdminDetails } = params;
15
+ const { name, churchAdminDetails, validity } = params;
16
16
  const alreadyExists = await commonDb.church.findOne({
17
17
  where: { name: { [Op.iLike]: name } },
18
18
  attributes: commonDb.church.selectedFields,
@@ -23,11 +23,14 @@ class ChurchService {
23
23
  code: errorCodes.HTTP_CONFLICT,
24
24
  message: errorMsgs.churchAlreadyExists,
25
25
  };
26
+ const expiresAt = new Date();
27
+ expiresAt.setDate(expiresAt.getDate() + validity);
26
28
  const churchData = await commonDb.church.create(
27
29
  {
28
30
  ...params,
29
31
  registeredAt: new Date(),
30
32
  subscribedAt: new Date(),
33
+ expiresAt,
31
34
  connectionUrl: process.env.CHURCH_SHADOW_DATABASE_URL.replace(
32
35
  "church_shadow",
33
36
  name.toLowerCase()
@@ -43,6 +46,31 @@ class ChurchService {
43
46
  },
44
47
  { include: { model: commonDb.churchDomain, as: "churchDomain" } }
45
48
  );
49
+ let permissionId;
50
+ if (params.subscriptionPlanId == SUBSCRIPTION_PLAN_ID.CUSTOM) {
51
+ permissionId = params.permissionId;
52
+ } else {
53
+ let subscriptionPlan = await commonDb.subscriptionPlan.findOne({
54
+ where: { id: params.subscriptionPlanId },
55
+ attributes: commonDb.subscriptionPlan.selectedFields,
56
+ include: {
57
+ model: commonDb.subscriptionPlanPermission,
58
+ as: "subscriptionPlanPermission",
59
+ attributes: commonDb.subscriptionPlanPermission.selectedFields,
60
+ required: false,
61
+ },
62
+ });
63
+ subscriptionPlan = subscriptionPlan.get({ plain: true });
64
+ permissionId = subscriptionPlan.subscriptionPlanPermission.map(
65
+ (x) => x.permissionId
66
+ );
67
+ }
68
+ await commonDb.churchPermission.bulkCreate(
69
+ permissionId.map((x) => ({
70
+ churchId: churchData.id,
71
+ permissionId: x,
72
+ }))
73
+ );
46
74
  const jobs = [
47
75
  {
48
76
  queue: QUEUES.DB_CREATE,
@@ -117,7 +145,49 @@ class ChurchService {
117
145
  try {
118
146
  const { id, ...restParams } = params;
119
147
  if(restParams.subscriptionPlanId) {
148
+ const churchData = await commonDb.church.findOne({
149
+ where: { id },
150
+ attributes: commonDb.church.selectedFields,
151
+ raw: true,
152
+ });
153
+ if (churchData.expiresAt) {
154
+ const expiresAt = new Date(churchData.expiresAt);
155
+ expiresAt.setDate(expiresAt.getDate() + params.validity);
156
+ restParams.expiresAt = expiresAt;
157
+ } else {
158
+ const expiresAt = new Date();
159
+ expiresAt.setDate(expiresAt.getDate() + params.validity);
160
+ restParams.expiresAt = expiresAt;
161
+ }
120
162
  restParams.subscribedAt = new Date();
163
+ await commonDb.churchPermission.destroy({
164
+ where: { churchId: id },
165
+ });
166
+ let permissionId;
167
+ if (params.subscriptionPlanId == SUBSCRIPTION_PLAN_ID.CUSTOM) {
168
+ permissionId = params.permissionId;
169
+ } else {
170
+ let subscriptionPlan = await commonDb.subscriptionPlan.findOne({
171
+ where: { id: params.subscriptionPlanId },
172
+ attributes: commonDb.subscriptionPlan.selectedFields,
173
+ include: {
174
+ model: commonDb.subscriptionPlanPermission,
175
+ as: "subscriptionPlanPermission",
176
+ attributes: commonDb.subscriptionPlanPermission.selectedFields,
177
+ required: false,
178
+ },
179
+ });
180
+ subscriptionPlan = subscriptionPlan.get({ plain: true });
181
+ permissionId = subscriptionPlan.subscriptionPlanPermission.map(
182
+ (x) => x.permissionId
183
+ );
184
+ }
185
+ await commonDb.churchPermission.bulkCreate(
186
+ permissionId.map((x) => ({
187
+ churchId: id,
188
+ permissionId: x,
189
+ }))
190
+ );
121
191
  }
122
192
  await commonDb.church.update(restParams, { where: { id } });
123
193
  return { code: errorCodes.HTTP_OK, message: errorMsgs.churchUpdated };
@@ -195,18 +265,6 @@ class ChurchService {
195
265
  });
196
266
  if (!churchPermissionDetails)
197
267
  return { code: errorCodes.HTTP_BAD_REQUEST, message: errorMsgs.invalidId };
198
- const churchDb = await churchManager.getChurchDbConnectionById(churchId);
199
- const subRolesByChurchId = await churchDb.subRole.findAll({
200
- attributes: churchDb.subRole.selectedFields,
201
- raw: true,
202
- });
203
- const subRoleIds = subRolesByChurchId.map((x) => x.id);
204
- await churchDb.subRolePermission.destroy({
205
- where: {
206
- permissionId: churchPermissionDetails.permissionId,
207
- subRoleId: subRoleIds,
208
- },
209
- });
210
268
  await commonDb.churchPermission.destroy({ where: { id, churchId } });
211
269
  return { code: errorCodes.HTTP_OK, message: errorMsgs.success };
212
270
  } catch (err) {
@@ -16,7 +16,10 @@ class MasterService {
16
16
  code: errorCodes.HTTP_CONFLICT,
17
17
  message: errorMsgs.subscriptionAlreadyExists,
18
18
  };
19
- await commonDb.subscriptionPlan.create({ ...params });
19
+ await commonDb.subscriptionPlan.create(
20
+ { ...params, isFree: false, isCustom: false },
21
+ { include: { model: commonDb.subscriptionPlanPermission, as: "subscriptionPlanPermission" } }
22
+ );
20
23
  return { code: errorCodes.HTTP_OK, message: errorMsgs.success };
21
24
  } catch (err) {
22
25
  return { code: errorCodes.HTTP_INTERNAL_SERVER_ERROR, message: err };
@@ -28,11 +31,32 @@ class MasterService {
28
31
  const searchCondition = !!search
29
32
  ? { name: { [Op.like]: `%${search}%` } }
30
33
  : {};
31
- const data = await commonDb.subscriptionPlan.findAll({
34
+ let data = await commonDb.subscriptionPlan.findAll({
32
35
  where: { status: true, ...searchCondition },
36
+ include: [
37
+ {
38
+ model: commonDb.subscriptionPlanPermission,
39
+ as: "subscriptionPlanPermission",
40
+ required: false,
41
+ attributes: commonDb.subscriptionPlanPermission.selectedFields,
42
+ include: {
43
+ model: commonDb.permission,
44
+ as: "permission",
45
+ required: false,
46
+ attributes: commonDb.permission.selectedFields,
47
+ }
48
+ }
49
+ ],
33
50
  attributes: commonDb.subscriptionPlan.selectedFields,
34
- raw: true,
51
+ order: [["isFree", "DESC"], ["isCustom", "ASC"]],
35
52
  });
53
+ data = data.map((item) => {
54
+ item = item.get({ plain: true });
55
+ item.subscriptionPlanPermission = item.subscriptionPlanPermission.map(
56
+ (permission) => permission.permission
57
+ );
58
+ return item;
59
+ })
36
60
  return {
37
61
  code: errorCodes.HTTP_OK,
38
62
  message: errorMsgs.success,
@@ -45,11 +69,28 @@ class MasterService {
45
69
  async subscriptionPlanByIdService(params) {
46
70
  try {
47
71
  const { id } = params;
48
- const data = await commonDb.subscriptionPlan.findOne({
72
+ let data = await commonDb.subscriptionPlan.findOne({
49
73
  where: { status: true, id },
74
+ include: [
75
+ {
76
+ model: commonDb.subscriptionPlanPermission,
77
+ as: "subscriptionPlanPermission",
78
+ required: false,
79
+ attributes: commonDb.subscriptionPlanPermission.selectedFields,
80
+ include: {
81
+ model: commonDb.permission,
82
+ as: "permission",
83
+ required: false,
84
+ attributes: commonDb.permission.selectedFields,
85
+ }
86
+ }
87
+ ],
50
88
  attributes: commonDb.subscriptionPlan.selectedFields,
51
- raw: true,
52
89
  });
90
+ data = data.get({ plain: true });
91
+ data.subscriptionPlanPermission = data.subscriptionPlanPermission.map(
92
+ (permission) => permission.permission
93
+ );
53
94
  return { code: errorCodes.HTTP_OK, message: errorMsgs.success, data };
54
95
  } catch (err) {
55
96
  return { code: errorCodes.HTTP_INTERNAL_SERVER_ERROR, message: err };
@@ -57,21 +98,63 @@ class MasterService {
57
98
  }
58
99
  async updateSubscriptionPlanByIdService(params) {
59
100
  try {
60
- const { id, name, ...restData } = params;
61
- const alreadyExists = await commonDb.subscriptionPlan.findOne({
62
- where: { name, id: { [Op.ne]: id } },
101
+ const { id, name, subscriptionPlanPermission = [], ...restData } = params;
102
+ const subscriptionPlanDetails = await commonDb.subscriptionPlan.findOne({
103
+ where: { id, status: true },
63
104
  attributes: commonDb.subscriptionPlan.selectedFields,
64
105
  raw: true,
65
106
  });
66
- if (alreadyExists)
107
+ if (!subscriptionPlanDetails)
108
+ return {
109
+ code: errorCodes.HTTP_BAD_REQUEST,
110
+ message: errorMsgs.invalidId,
111
+ };
112
+ const checkSubscriptionPlanExists = await commonDb.subscriptionPlan.findOne({
113
+ where: { id: { [Op.ne]: id }, name: { [Op.like]: `%${name}%` } },
114
+ raw: true,
115
+ });
116
+ if (checkSubscriptionPlanExists)
67
117
  return {
68
118
  code: errorCodes.HTTP_CONFLICT,
69
- message: errorMsgs.masterAlreadyExists,
119
+ message: errorMsgs.subscriptionAlreadyExists,
70
120
  };
71
121
  await commonDb.subscriptionPlan.update(
72
122
  { name, ...restData },
73
123
  { where: { id } }
74
124
  );
125
+ const existingSubscriptionPlanPermission = await commonDb.subscriptionPlanPermission.findAll({
126
+ where: { subscriptionPlanId: id },
127
+ attributes: commonDb.subscriptionPlanPermission.selectedFields,
128
+ raw: true,
129
+ });
130
+ const permissionIds = existingSubscriptionPlanPermission.map(
131
+ (permission) => permission.permissionId
132
+ );
133
+ const newPermissionIds = subscriptionPlanPermission.map(
134
+ (permission) => permission.permissionId
135
+ );
136
+ const newPermission = newPermissionIds.filter(
137
+ (permission) => !permissionIds.includes(permission)
138
+ );
139
+ const deletePermission = permissionIds.filter(
140
+ (permission) => !newPermissionIds.includes(permission)
141
+ );
142
+ if (newPermission.length) {
143
+ await commonDb.subscriptionPlanPermission.bulkCreate(
144
+ newPermission.map((permission) => ({
145
+ subscriptionPlanId: id,
146
+ permissionId: permission,
147
+ }))
148
+ );
149
+ }
150
+ if (deletePermission.length) {
151
+ await commonDb.subscriptionPlanPermission.destroy({
152
+ where: {
153
+ subscriptionPlanId: id,
154
+ permissionId: deletePermission,
155
+ },
156
+ });
157
+ }
75
158
  return { code: errorCodes.HTTP_OK, message: errorMsgs.success };
76
159
  } catch (err) {
77
160
  return { code: errorCodes.HTTP_INTERNAL_SERVER_ERROR, message: err };
@@ -1,5 +1,7 @@
1
1
  const BaseJoi = require("joi");
2
2
  const response = require("../utils/response");
3
+ const permission = require("../models/common/permission");
4
+ const { SUBSCRIPTION_PLAN_ID } = require("../constants");
3
5
  const schemas = {
4
6
  onboardChurch: BaseJoi.object({
5
7
  name: BaseJoi.string()
@@ -10,6 +12,12 @@ const schemas = {
10
12
  phoneNumber: BaseJoi.string().required(),
11
13
  contactPerson: BaseJoi.string().optional().allow(null),
12
14
  subscriptionPlanId: BaseJoi.number().required(),
15
+ validity: BaseJoi.number().required(),
16
+ permissionId: BaseJoi.array().items(BaseJoi.number().required()).when("subscriptionPlanId", {
17
+ is: BaseJoi.number().valid(SUBSCRIPTION_PLAN_ID.CUSTOM),
18
+ then: BaseJoi.required(),
19
+ otherwise: BaseJoi.optional(),
20
+ }),
13
21
  churchAdminDetails: BaseJoi.object({
14
22
  firstName: BaseJoi.string().required(),
15
23
  lastName: BaseJoi.string().required(),
@@ -25,6 +33,19 @@ const schemas = {
25
33
  phoneNumber: BaseJoi.string().optional(),
26
34
  contactPerson: BaseJoi.string().optional(),
27
35
  subscriptionPlanId: BaseJoi.number().optional(),
36
+ validity: BaseJoi.number().when('subscriptionPlanId', {
37
+ is: BaseJoi.exist(),
38
+ then: BaseJoi.required(),
39
+ otherwise: BaseJoi.optional()
40
+ }),
41
+ permissionId: BaseJoi.array()
42
+ .items(BaseJoi.number().required())
43
+ .optional()
44
+ .when("subscriptionPlanId", {
45
+ is: BaseJoi.number().valid(SUBSCRIPTION_PLAN_ID.CUSTOM),
46
+ then: BaseJoi.required(),
47
+ otherwise: BaseJoi.optional(),
48
+ }),
28
49
  status: BaseJoi.boolean().optional(),
29
50
  }),
30
51
  addChurchPermission: BaseJoi.object({
@@ -14,14 +14,16 @@ const schemas = {
14
14
  }),
15
15
  addSubscriptionPlan: BaseJoi.object({
16
16
  name: BaseJoi.string().required(),
17
- planCost: BaseJoi.number().required(),
18
- validity: BaseJoi.number().required(),
17
+ subscriptionPlanPermission: BaseJoi.array().items({
18
+ permissionId: BaseJoi.number().required(),
19
+ }),
19
20
  }),
20
21
  updateSubscriptionPlan: BaseJoi.object({
21
22
  id: BaseJoi.number().required(),
22
23
  name: BaseJoi.string().required(),
23
- planCost: BaseJoi.number().required(),
24
- validity: BaseJoi.number().required(),
24
+ subscriptionPlanPermission: BaseJoi.array().items({
25
+ permissionId: BaseJoi.number().required(),
26
+ }),
25
27
  }),
26
28
  addCity: BaseJoi.object({
27
29
  provinceId: BaseJoi.number().required(),