@b2y/ecommerce-common 1.2.5 → 1.2.7

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.
@@ -33,7 +33,6 @@ const StatusMessageConstants = {
33
33
  TENANT_SETTINGS_ALREADY_EXISTS: 'Tenant settings already exist for this tenant',
34
34
  INVALID_REQUEST: 'Invalid request',
35
35
  TENANT_SETTINGS_UPDATE_ERROR: 'Failed to update tenant settings',
36
- TENANT_SETTINGS_SINGLE_LOGO_ALLOWED: "Only one logo is allowed per tenant.",
37
36
  //Location
38
37
  STATE_CODE_COUNTRY_CODE_REQUIRE: "State code and country code are required to fetch cities",
39
38
  CITIES_NOT_FOUND: "No cities found for given state code",
@@ -1,352 +1,8 @@
1
1
  const LocationUtility = require('../utility/LocationUtility');
2
2
  const StatusMessage = require('../constants/StatusMessageConstants');
3
3
  const AppUtil = require('../utility/AppUtil');
4
- const SubscriptionStatusEnum = require('../enum/SubscriptionStatusEnum');
5
- const AppConstants = require('../constants/AppConstants');
6
4
  const EntityTypeEnum = require('../enum/EntityTypeEnum');
7
- const updateTenant = (
8
- Tenant,
9
- TenantSubscription,
10
- SubscriptionPlan,
11
- UpdatedBy,
12
- sequelize,
13
- logger,
14
- ) => {
15
- return async (req, res) => {
16
- let transaction;
17
- try {
18
- const tenantId =
19
- req.params && req.params.TenantID
20
- ? req.params.TenantID
21
- : req.body.TenantID;
22
- if (!tenantId) {
23
- logger.warn("TenantID is required for update.");
24
- return AppUtil.generateResponse(
25
- 400,
26
- StatusMessage.FAILURE,
27
- StatusMessage.TENANT_ID_REQUIRED_FIELD,
28
- null,
29
- res,
30
- );
31
- }
32
-
33
- const existing = await Tenant.findOne({ where: { TenantID: tenantId } });
34
- if (!existing) {
35
- logger.warn("Tenant not found with ID:", tenantId);
36
- return AppUtil.generateResponse(
37
- 404,
38
- StatusMessage.FAILURE,
39
- StatusMessage.TENANT_NOT_FOUND,
40
- null,
41
- res,
42
- );
43
- }
44
-
45
- const {
46
- CompanyName,
47
- CompanyCode,
48
- Email,
49
- PhoneNumber,
50
- CountryCallingCode,
51
- GSTNo,
52
- CustomerPortalDomain,
53
- AdminPortalDomain,
54
- AddressLine,
55
- CityName,
56
- StateCode,
57
- CountryCode,
58
- Zipcode,
59
- SubscriptionPlanID,
60
- Status,
61
- StartDate,
62
- EndDate,
63
- AutoRenew,
64
- IsTrial,
65
- GraceEndDate,
66
- TrialEndDate,
67
- } = req.body;
68
-
69
- // Validate optional fields when provided
70
- if (Email && !AppUtil.isValidEmail(Email)) {
71
- logger.warn("Invalid email format provided for update.");
72
- return AppUtil.generateResponse(
73
- 400,
74
- StatusMessage.FAILURE,
75
- StatusMessage.INVALID_EMAIL_FORMAT,
76
- null,
77
- res,
78
- );
79
- }
80
-
81
- if (PhoneNumber && !AppUtil.isValidPhone(PhoneNumber)) {
82
- logger.warn("Invalid phone number format provided for update.");
83
- return AppUtil.generateResponse(
84
- 400,
85
- StatusMessage.FAILURE,
86
- StatusMessage.INVALID_PHONE_FORMAT,
87
- null,
88
- res,
89
- );
90
- }
91
-
92
- if (CompanyCode !== undefined) {
93
- if (
94
- !Number.isInteger(Number(CompanyCode)) ||
95
- Number(CompanyCode) <= 0
96
- ) {
97
- logger.warn("Invalid company code provided for update.");
98
- return AppUtil.generateResponse(
99
- 400,
100
- StatusMessage.FAILURE,
101
- StatusMessage.INVALID_COMPANY_CODE,
102
- null,
103
- res,
104
- );
105
- }
106
- }
107
-
108
- // Validate country code, state code and city name
109
- if (CountryCode && StateCode && CityName && CountryCallingCode) {
110
- const validation = await LocationUtility.validateCountryAndState(
111
- CountryCode,
112
- StateCode,
113
- CityName,
114
- CountryCallingCode,
115
- logger,
116
- );
117
- if (!validation.isValid) {
118
- return AppUtil.generateResponse(
119
- 400,
120
- StatusMessage.FAILURE,
121
- validation.error,
122
- null,
123
- res,
124
- );
125
- }
126
- }
127
- if (Status && !Object.values(SubscriptionStatusEnum).includes(Status)) {
128
- logger.warn("Invalid Subscription status");
129
- return AppUtil.generateResponse(
130
- 400,
131
- StatusMessage.FAILURE,
132
- StatusMessage.INVALID_SUBSCRIPTION_STATUS,
133
- null,
134
- res,
135
- );
136
- }
137
-
138
- if (
139
- AutoRenew !== undefined &&
140
- typeof AutoRenew !== AppConstants.BOOLEAN
141
- ) {
142
- logger.warn("AutoRenew must be boolean type");
143
- return AppUtil.generateResponse(
144
- 400,
145
- StatusMessage.FAILURE,
146
- StatusMessage.INVALID_BOOLEAN_TYPE.replace("{field}", "AutoRenew"),
147
- null,
148
- res,
149
- );
150
- }
151
- if (IsTrial !== undefined && typeof IsTrial !== AppConstants.BOOLEAN) {
152
- logger.warn("IsTrial must be boolean type");
153
- return AppUtil.generateResponse(
154
- 400,
155
- StatusMessage.FAILURE,
156
- StatusMessage.INVALID_BOOLEAN_TYPE.replace("{field}", "IsTrial"),
157
- null,
158
- res,
159
- );
160
- }
161
- transaction = await sequelize.transaction();
162
- if (SubscriptionPlanID) {
163
- const subscriptionPlan = await SubscriptionPlan.findOne({
164
- where: {
165
- SubscriptionPlanID,
166
- IsActive: true,
167
- },
168
- transaction,
169
- });
170
- if (!subscriptionPlan) {
171
- await transaction.rollback();
172
- logger.warn("subscription plan not found");
173
- return AppUtil.generateResponse(
174
- 404,
175
- StatusMessage.FAILURE,
176
- StatusMessage.SUBSCRIPTION_PLAN_NOT_FOUND,
177
- null,
178
- res,
179
- );
180
- }
181
- }
182
- // Build update payload only with provided fields
183
- const updatePayload = {};
184
- const fields = {
185
- CompanyName,
186
- CompanyCode,
187
- Email,
188
- PhoneNumber,
189
- CountryCode,
190
- GSTNo,
191
- CustomerPortalDomain,
192
- AdminPortalDomain,
193
- AddressLine,
194
- CityName,
195
- StateCode,
196
- CountryCallingCode,
197
- Zipcode,
198
- };
199
- Object.keys(fields).forEach((k) => {
200
- if (fields[k] !== undefined)
201
- updatePayload[k] =
202
- k === AppConstants.COMPANY_CODE ? Number(fields[k]) : fields[k];
203
- });
204
-
205
- updatePayload.UpdatedBy =
206
- UpdatedBy;
207
- updatePayload.UpdatedAt = new Date();
208
-
209
- await existing.update(updatePayload, { transaction });
210
-
211
- // update subscription
212
- const updateSubscriptionPayload = {};
213
- const updateSubscriptionfields = {
214
- SubscriptionPlanID,
215
- Status,
216
- StartDate,
217
- EndDate,
218
- GraceEndDate,
219
- TrialEndDate,
220
- IsTrial,
221
- AutoRenew,
222
- };
223
- Object.keys(updateSubscriptionfields).forEach((k) => {
224
- if (updateSubscriptionfields[k] !== undefined)
225
- updateSubscriptionPayload[k] = updateSubscriptionfields[k];
226
- });
227
- if (Object.keys(updateSubscriptionPayload).length !== 0) {
228
- updateSubscriptionPayload.UpdatedBy = UpdatedBy;
229
- updateSubscriptionPayload.UpdatedAt = new Date();
230
5
 
231
- // find the existing subscription
232
- const tenantSubscription = await TenantSubscription.findOne({
233
- where: {
234
- TenantID: tenantId,
235
- },
236
- transaction,
237
- });
238
- if (tenantSubscription) {
239
- await tenantSubscription.update(updateSubscriptionPayload, {
240
- transaction,
241
- });
242
- } else {
243
- await TenantSubscription.create(
244
- {
245
- TenantID: tenantId,
246
- ...updateSubscriptionPayload,
247
- CreatedBy:UpdatedBy,
248
- UpdatedBy: UpdatedBy,
249
- CreatedAt: new Date(),
250
- UpdatedAt: new Date()
251
- },
252
- { transaction },
253
- );
254
- }
255
- }
256
- await transaction.commit();
257
-
258
- logger.info("Tenant updated successfully with ID:", tenantId);
259
- return AppUtil.generateResponse(
260
- 200,
261
- StatusMessage.SUCCESS,
262
- StatusMessage.TENANT_UPDATED_SUCCESS,
263
- null,
264
- res,
265
- );
266
- } catch (error) {
267
- if (transaction) await transaction.rollback();
268
-
269
- if (error.name === "SequelizeUniqueConstraintError") {
270
- const detail = error.original?.detail || "";
271
- if (detail.includes(AppConstants.COMPANY_NAME)) {
272
- return AppUtil.generateResponse(
273
- 400,
274
- StatusMessage.FAILURE,
275
- StatusMessage.COMPANY_NAME_EXISTS,
276
- null,
277
- res,
278
- );
279
- } else if (detail.includes(AppConstants.COMPANY_CODE)) {
280
- return AppUtil.generateResponse(
281
- 400,
282
- StatusMessage.FAILURE,
283
- StatusMessage.COMPANY_CODE_EXISTS,
284
- null,
285
- res,
286
- );
287
- } else if (detail.includes(AppConstants.EMAIL)) {
288
- return AppUtil.generateResponse(
289
- 400,
290
- StatusMessage.FAILURE,
291
- StatusMessage.EMAIL_EXISTS,
292
- null,
293
- res,
294
- );
295
- } else if (detail.includes(AppConstants.PHONE_NUMBER)) {
296
- return AppUtil.generateResponse(
297
- 400,
298
- StatusMessage.FAILURE,
299
- StatusMessage.PHONE_NUMBER_EXISTS,
300
- null,
301
- res,
302
- );
303
- } else if (detail.includes(AppConstants.CUSTOMER_PORTAL_DOMAIN)) {
304
- return AppUtil.generateResponse(
305
- 400,
306
- StatusMessage.FAILURE,
307
- StatusMessage.CUSTOMER_PORTAL_DOMAIN_EXISTS,
308
- null,
309
- res,
310
- );
311
- } else if (detail.includes(AppConstants.ADMIN_PORTAL_DOMAIN)) {
312
- return AppUtil.generateResponse(
313
- 400,
314
- StatusMessage.FAILURE,
315
- StatusMessage.ADMIN_PORTAL_DOMAIN_EXISTS,
316
- null,
317
- res,
318
- );
319
- }
320
- return AppUtil.generateResponse(
321
- 400,
322
- StatusMessage.FAILURE,
323
- StatusMessage.TENANT_ALREADY_EXISTS,
324
- null,
325
- res,
326
- );
327
- } else if (error.name === "SequelizeValidationError") {
328
- const details = error.errors.map((e) => e.message);
329
- logger.warn(`Validation Error detected: ${details.join("; ")}`);
330
- return AppUtil.generateResponse(
331
- 400,
332
- StatusMessage.FAILURE,
333
- StatusMessage.INVALID_REQUEST,
334
- null,
335
- res,
336
- );
337
- } else {
338
- logger.error("Error in UpdateTenant:", error);
339
- return AppUtil.generateResponse(
340
- 500,
341
- StatusMessage.FAILURE,
342
- StatusMessage.TENANT_UPDATE_ERROR,
343
- null,
344
- res,
345
- );
346
- }
347
- }
348
- };
349
- };
350
6
 
351
7
  const getTenantById = (
352
8
  Tenant,
@@ -402,7 +58,7 @@ const getTenantById = (
402
58
  {
403
59
  model: SubscriptionPlan,
404
60
  as: "SubscriptionPlan",
405
- attributes: ["SubscriptionPlanID", "PlanName", "PlanCode"],
61
+ attributes: ["SubscriptionPlanID", "PlanName", "PlanCode", "BillingCycle"],
406
62
  },
407
63
  ],
408
64
  },
@@ -462,6 +118,7 @@ const getTenantById = (
462
118
  TenantLogo: logo,
463
119
  SubscriptionPlanID: tenant.CurrentSubscription?.SubscriptionPlan?.SubscriptionPlanID,
464
120
  PlanName: tenant.CurrentSubscription?.SubscriptionPlan?.PlanName,
121
+ BillingCycle: tenant.CurrentSubscription?.SubscriptionPlan?.BillingCycle,
465
122
  TenantSubscriptionStatus: tenant.CurrentSubscription?.Status,
466
123
  StartDate: tenant.CurrentSubscription?.StartDate,
467
124
  EndDate: tenant.CurrentSubscription?.EndDate,
@@ -491,5 +148,5 @@ const getTenantById = (
491
148
  };
492
149
  };
493
150
 
494
- module.exports = { updateTenant, getTenantById };
151
+ module.exports = { getTenantById };
495
152
 
@@ -2,7 +2,8 @@ const AccessModeEnum = Object.freeze({
2
2
  FULL: "Full",
3
3
  READ_ONLY: "Read Only",
4
4
  BLOCKED: "Blocked",
5
- PAYMENT_REQUIRED: "Payment Required"
5
+ PAYMENT_REQUIRED: "Payment Required",
6
+ RENEW_SUBSCRIPTION: "Renew Subscription"
6
7
  });
7
8
 
8
9
  module.exports = AccessModeEnum;
@@ -28,7 +28,7 @@ module.exports = (sequelize) => {
28
28
  },
29
29
  EndDate: {
30
30
  type: DataTypes.DATE,
31
- allowNull: false,
31
+ allowNull: true,
32
32
  },
33
33
  GraceEndDate: {
34
34
  type: DataTypes.DATE,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b2y/ecommerce-common",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "E-commerce common library",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -4,25 +4,48 @@ function ResolveAccessMode(subscription) {
4
4
  const now = new Date();
5
5
 
6
6
  if (!subscription) return AccessModeEnum.BLOCKED;
7
+ const status = subscription.Status;
8
+ // paid endDate
9
+ const endDate = subscription.EndDate
10
+ ? new Date(subscription.EndDate)
11
+ : null;
12
+ // paid graceEndDate
13
+ const graceEndDate = subscription.GraceEndDate
14
+ ? new Date(subscription.GraceEndDate)
15
+ : null;
16
+ //trialEndDate
17
+ const trialEndDate = subscription.TrialEndDate
18
+ ? new Date(subscription.TrialEndDate)
19
+ : null;
20
+
7
21
 
8
- if ([SubscriptionStatusEnum.CANCELLED, SubscriptionStatusEnum.EXPIRED, SubscriptionStatusEnum.SUSPENDED].includes(subscription.Status)) {
22
+ if (status === SubscriptionStatusEnum.SUSPENDED) {
9
23
  return AccessModeEnum.BLOCKED;
10
24
  }
25
+ if(status === SubscriptionStatusEnum.EXPIRED) {
26
+ return AccessModeEnum.RENEW_SUBSCRIPTION;
27
+ }
28
+ // CANCELLED -> still allow till expiry
29
+ if(status === SubscriptionStatusEnum.CANCELLED) {
30
+ if (endDate && now < endDate) {
31
+ return AccessModeEnum.FULL;
32
+ }
11
33
 
34
+ if (graceEndDate && now <= graceEndDate) {
35
+ return AccessModeEnum.READ_ONLY;
36
+ }
37
+
38
+ return AccessModeEnum.RENEW_SUBSCRIPTION;
39
+ }
12
40
  if (subscription.Status === SubscriptionStatusEnum.ACTIVE) {
41
+ // trial plan
13
42
  if (subscription.IsTrial === true) {
14
- const trialEndDate = subscription.TrialEndDate
15
- ? new Date(subscription.TrialEndDate)
16
- : null;
17
43
  if (trialEndDate && now < trialEndDate) {
18
44
  return AccessModeEnum.FULL;
19
45
  }
20
46
  return AccessModeEnum.PAYMENT_REQUIRED;
21
47
  }
22
- const endDate = new Date(subscription.EndDate);
23
- const graceEndDate = subscription.GraceEndDate
24
- ? new Date(subscription.GraceEndDate)
25
- : null;
48
+ // paid plan
26
49
  // Still in the paid period
27
50
  if (now < endDate) {
28
51
  return AccessModeEnum.FULL;
@@ -32,7 +55,7 @@ function ResolveAccessMode(subscription) {
32
55
  return AccessModeEnum.READ_ONLY;
33
56
  }
34
57
  // Past both EndDate and Grace Period
35
- return AccessModeEnum.BLOCKED;
58
+ return AccessModeEnum.RENEW_SUBSCRIPTION;
36
59
  }
37
60
  return AccessModeEnum.BLOCKED;
38
61
  };