payservedb 8.3.5 → 8.3.6
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.
- package/.env +2 -2
- package/.idea/material_theme_project_new.xml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/psdb.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/index.js +306 -306
- package/package.json +17 -17
- package/src/models/account.js +52 -52
- package/src/models/agent_departments.js +59 -59
- package/src/models/agent_notifications.js +53 -53
- package/src/models/agent_performance.js +127 -127
- package/src/models/agent_roles.js +77 -77
- package/src/models/agents.js +154 -154
- package/src/models/apilog.js +18 -18
- package/src/models/approvalsWorkflows.js +49 -49
- package/src/models/archivedapilog.js +18 -18
- package/src/models/asset.js +92 -92
- package/src/models/assetsAssignment.js +64 -64
- package/src/models/auditTrail.js +346 -346
- package/src/models/bankdetails.js +47 -43
- package/src/models/billerAddress.js +124 -124
- package/src/models/booking_invoice.js +151 -151
- package/src/models/bookinganalytics.js +63 -63
- package/src/models/bookingconfig.js +45 -45
- package/src/models/bookingproperty.js +122 -122
- package/src/models/bookingreservation.js +192 -192
- package/src/models/bookingrevenuerecord.js +84 -84
- package/src/models/budget.js +95 -95
- package/src/models/budgetCategory.js +19 -19
- package/src/models/campaigns.js +108 -108
- package/src/models/cashpayment.js +264 -264
- package/src/models/combinedUnits.js +62 -62
- package/src/models/common_area_electricity.js +38 -38
- package/src/models/common_area_generator.js +41 -41
- package/src/models/common_area_utility_alert.js +37 -37
- package/src/models/common_area_water.js +39 -39
- package/src/models/communication_status.js +33 -33
- package/src/models/communication_user_opt.js +32 -32
- package/src/models/company.js +53 -53
- package/src/models/coreBaseSettings.js +16 -16
- package/src/models/coreInvoiceSettings.js +100 -100
- package/src/models/counter_schema.js +21 -21
- package/src/models/country_tax.js +42 -42
- package/src/models/currency_settings.js +39 -39
- package/src/models/customer.js +210 -210
- package/src/models/customer_satisfaction_survey.js +278 -278
- package/src/models/customer_surveys.js +139 -139
- package/src/models/customer_tickets.js +239 -239
- package/src/models/dailyChecklist.js +312 -312
- package/src/models/default_payment_details.js +17 -17
- package/src/models/deliveryTimeMarks.js +18 -18
- package/src/models/document_type.js +19 -19
- package/src/models/dutyRosterChecklist.js +250 -250
- package/src/models/dutyroster.js +136 -136
- package/src/models/email.js +37 -37
- package/src/models/email_sms_queue.js +61 -61
- package/src/models/entry_exit.js +53 -53
- package/src/models/expense.js +99 -99
- package/src/models/expense_category.js +45 -45
- package/src/models/facility.js +62 -62
- package/src/models/facilityBillingPrices.js +29 -29
- package/src/models/facilityInvoice.js +223 -240
- package/src/models/facilityInvoicePayment.js +47 -52
- package/src/models/facilityInvoiceRecipient.js +32 -32
- package/src/models/facilityWalletTransactionsMetadata.js +236 -236
- package/src/models/facility_departements.js +20 -20
- package/src/models/facility_payment_details.js +20 -20
- package/src/models/facilityasset.js +25 -25
- package/src/models/faq.js +18 -18
- package/src/models/gl_account_double_entries.js +25 -25
- package/src/models/gl_accounts.js +56 -56
- package/src/models/gl_entries.js +49 -49
- package/src/models/goodsReceivedNotes.js +115 -115
- package/src/models/guard.js +47 -47
- package/src/models/handover.js +247 -247
- package/src/models/inspection_category.js +38 -38
- package/src/models/invoice.js +387 -387
- package/src/models/invoicing_schedule.js +36 -36
- package/src/models/item_inspection.js +96 -96
- package/src/models/knowledge_base.js +109 -109
- package/src/models/knowledge_base_rating.js +44 -44
- package/src/models/leaseagreement.js +236 -243
- package/src/models/leasetemplate.js +17 -17
- package/src/models/levy.js +223 -223
- package/src/models/levy_invoice_settings.js +26 -26
- package/src/models/levycontract.js +177 -173
- package/src/models/levytype.js +23 -23
- package/src/models/maintenance_service_vendor.js +38 -38
- package/src/models/maintenance_services.js +17 -17
- package/src/models/maintenancerequisition.js +31 -31
- package/src/models/master_workplan.js +32 -32
- package/src/models/master_workplan_child.js +34 -34
- package/src/models/message.js +38 -38
- package/src/models/module.js +21 -21
- package/src/models/notification.js +44 -44
- package/src/models/paymentTermsMarks.js +19 -19
- package/src/models/penalty.js +76 -76
- package/src/models/pendingCredentials.js +32 -32
- package/src/models/powerMeterCommunicationProtocol.js +17 -17
- package/src/models/powerMeterCustomerAccount.js +78 -78
- package/src/models/powerMeterCustomerBand.js +14 -14
- package/src/models/powerMeterDailyReading.js +30 -30
- package/src/models/powerMeterGateways.js +40 -40
- package/src/models/powerMeterMonthlyReading.js +34 -34
- package/src/models/powerMeterPowerCharges.js +85 -85
- package/src/models/powerMeterSettings.js +159 -159
- package/src/models/powerMeterSingleDayReading.js +32 -32
- package/src/models/powerMeters.js +116 -116
- package/src/models/powerMetersManufacturer.js +14 -14
- package/src/models/power_meter_account.js +81 -81
- package/src/models/power_meter_command_logs.js +30 -30
- package/src/models/power_meter_command_queue.js +33 -33
- package/src/models/power_meter_negative_balance.js +44 -44
- package/src/models/power_prepaid_credits.js +47 -47
- package/src/models/power_prepaid_debits.js +53 -53
- package/src/models/power_prepaid_orders.js +78 -78
- package/src/models/power_sms_notification.js +26 -26
- package/src/models/propertyManagerContract.js +556 -556
- package/src/models/propertyManagerRevenue.js +195 -195
- package/src/models/purchaseOrderInvoice.js +74 -74
- package/src/models/purchase_order.js +213 -213
- package/src/models/purchase_request.js +110 -110
- package/src/models/refresh_token.js +23 -23
- package/src/models/reminder.js +197 -197
- package/src/models/report.js +13 -13
- package/src/models/resident.js +121 -121
- package/src/models/rfq_details.js +131 -131
- package/src/models/rfq_response.js +153 -153
- package/src/models/service_charge_invoice_upload.js +42 -42
- package/src/models/service_charge_payments.js +27 -27
- package/src/models/servicerequest.js +55 -55
- package/src/models/settings.js +62 -62
- package/src/models/short_urls.js +21 -21
- package/src/models/smart_meter_daily_consumption.js +44 -44
- package/src/models/sms_africastalking.js +20 -20
- package/src/models/sms_balance_notification.js +26 -26
- package/src/models/sms_meliora.js +20 -20
- package/src/models/staff.js +36 -36
- package/src/models/stocksandspare.js +161 -161
- package/src/models/suppliers.js +74 -74
- package/src/models/tickets.js +173 -173
- package/src/models/tickets_category.js +72 -72
- package/src/models/unitManagementTemplate.js +44 -44
- package/src/models/unitasset.js +25 -25
- package/src/models/units.js +118 -118
- package/src/models/user.js +186 -186
- package/src/models/valueaddedservices.js +79 -79
- package/src/models/vas_invoices_upload.js +50 -50
- package/src/models/vas_payments.js +24 -24
- package/src/models/vasinvoice.js +192 -192
- package/src/models/vasvendor.js +57 -57
- package/src/models/visitLog.js +95 -95
- package/src/models/visitor.js +67 -67
- package/src/models/waitlist.js +45 -45
- package/src/models/wallet.js +44 -44
- package/src/models/wallet_transactions.js +50 -50
- package/src/models/water_invoice.js +351 -351
- package/src/models/water_meter_Command_Queue.js +33 -33
- package/src/models/water_meter_account.js +82 -82
- package/src/models/water_meter_billing.js +58 -58
- package/src/models/water_meter_communication.js +17 -17
- package/src/models/water_meter_communication_logs.js +39 -39
- package/src/models/water_meter_concentrator.js +70 -70
- package/src/models/water_meter_daily_history.js +32 -32
- package/src/models/water_meter_high_risk.js +36 -36
- package/src/models/water_meter_iot_cards.js +34 -34
- package/src/models/water_meter_manufacturer.js +35 -35
- package/src/models/water_meter_monthly_history.js +36 -36
- package/src/models/water_meter_negative_amounts.js +44 -44
- package/src/models/water_meter_settings.js +283 -276
- package/src/models/water_meter_single_day_history.js +34 -34
- package/src/models/water_meter_size.js +15 -15
- package/src/models/water_meters.js +133 -133
- package/src/models/water_meters_delivery.js +76 -76
- package/src/models/water_prepaid_credit.js +47 -47
- package/src/models/water_prepaid_debit.js +50 -50
- package/src/models/workorder.js +49 -49
package/src/models/reminder.js
CHANGED
|
@@ -1,198 +1,198 @@
|
|
|
1
|
-
const mongoose = require("mongoose");
|
|
2
|
-
const moment = require("moment-timezone");
|
|
3
|
-
|
|
4
|
-
const reminderSchema = new mongoose.Schema(
|
|
5
|
-
{
|
|
6
|
-
name: {
|
|
7
|
-
type: String,
|
|
8
|
-
required: true,
|
|
9
|
-
trim: true,
|
|
10
|
-
},
|
|
11
|
-
type: {
|
|
12
|
-
type: String,
|
|
13
|
-
required: true,
|
|
14
|
-
enum: ['standard', 'custom'],
|
|
15
|
-
default: 'standard'
|
|
16
|
-
},
|
|
17
|
-
module: {
|
|
18
|
-
type: String,
|
|
19
|
-
required: true,
|
|
20
|
-
enum: ['levy', 'lease', 'utility'],
|
|
21
|
-
default: 'levy'
|
|
22
|
-
},
|
|
23
|
-
moduleId: {
|
|
24
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
25
|
-
required: true,
|
|
26
|
-
refPath: 'module'
|
|
27
|
-
},
|
|
28
|
-
remindOn: {
|
|
29
|
-
invoiceDate: {
|
|
30
|
-
type: Boolean,
|
|
31
|
-
default: true,
|
|
32
|
-
},
|
|
33
|
-
dueDate: {
|
|
34
|
-
type: Boolean,
|
|
35
|
-
default: false,
|
|
36
|
-
},
|
|
37
|
-
afterOverdue: {
|
|
38
|
-
enabled: {
|
|
39
|
-
type: Boolean,
|
|
40
|
-
default: false,
|
|
41
|
-
},
|
|
42
|
-
daily: {
|
|
43
|
-
type: Boolean,
|
|
44
|
-
default: false,
|
|
45
|
-
},
|
|
46
|
-
days: {
|
|
47
|
-
type: [Number],
|
|
48
|
-
validate: {
|
|
49
|
-
validator: function (value) {
|
|
50
|
-
// If daily reminders are enabled, no need to validate days
|
|
51
|
-
if (this.remindOn?.afterOverdue?.daily === true) return true;
|
|
52
|
-
|
|
53
|
-
// If overdue reminders are disabled, no validation needed
|
|
54
|
-
if (!this.remindOn?.afterOverdue?.enabled) return true;
|
|
55
|
-
|
|
56
|
-
// If overdue is enabled but daily is false, then validate days array
|
|
57
|
-
return Array.isArray(value) &&
|
|
58
|
-
value.length > 0 &&
|
|
59
|
-
value.every(day => [1, 3, 7].includes(day));
|
|
60
|
-
},
|
|
61
|
-
message: 'When overdue reminders are enabled (and daily is false), days must include only values of 1, 3, or 7'
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
time: {
|
|
67
|
-
type: String,
|
|
68
|
-
required: true,
|
|
69
|
-
default: "09:00",
|
|
70
|
-
validate: {
|
|
71
|
-
validator: function (value) {
|
|
72
|
-
return /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/.test(value);
|
|
73
|
-
},
|
|
74
|
-
message: 'Time must be in HH:mm format'
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
isActive: {
|
|
78
|
-
type: Boolean,
|
|
79
|
-
required: true,
|
|
80
|
-
default: true,
|
|
81
|
-
},
|
|
82
|
-
processed: {
|
|
83
|
-
type: Boolean,
|
|
84
|
-
required: true,
|
|
85
|
-
default: false,
|
|
86
|
-
},
|
|
87
|
-
lastProcessed: {
|
|
88
|
-
type: Date,
|
|
89
|
-
},
|
|
90
|
-
notificationTypes: {
|
|
91
|
-
type: [String],
|
|
92
|
-
required: true,
|
|
93
|
-
validate: {
|
|
94
|
-
validator: function (value) {
|
|
95
|
-
return value.length > 0 &&
|
|
96
|
-
value.every(type => ['SMS', 'EMAIL'].includes(type.toUpperCase()));
|
|
97
|
-
},
|
|
98
|
-
message: 'At least one valid notification type is required'
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
message: {
|
|
102
|
-
type: String,
|
|
103
|
-
maxLength: [500, 'Message cannot exceed 500 characters']
|
|
104
|
-
},
|
|
105
|
-
facilityId: {
|
|
106
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
107
|
-
ref: "Facility",
|
|
108
|
-
required: true,
|
|
109
|
-
index: true
|
|
110
|
-
},
|
|
111
|
-
timezone: {
|
|
112
|
-
type: String,
|
|
113
|
-
required: true,
|
|
114
|
-
default: 'UTC',
|
|
115
|
-
validate: {
|
|
116
|
-
validator: function (value) {
|
|
117
|
-
return moment.tz.names().includes(value);
|
|
118
|
-
},
|
|
119
|
-
message: 'Invalid timezone'
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
timestamps: true,
|
|
125
|
-
indexes: [
|
|
126
|
-
{ facilityId: 1, isActive: 1 },
|
|
127
|
-
{ facilityId: 1, isActive: 1, 'remindOn.invoiceDate': 1 },
|
|
128
|
-
{ facilityId: 1, isActive: 1, 'remindOn.dueDate': 1 },
|
|
129
|
-
{ facilityId: 1, isActive: 1, 'remindOn.afterOverdue.enabled': 1 },
|
|
130
|
-
{ facilityId: 1, isActive: 1, 'remindOn.afterOverdue.daily': 1 },
|
|
131
|
-
{ moduleId: 1, isActive: 1 },
|
|
132
|
-
{ facilityId: 1, lastProcessed: 1 }
|
|
133
|
-
]
|
|
134
|
-
}
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
// Helper method to check if reminder should be processed
|
|
138
|
-
reminderSchema.methods.shouldProcess = function (currentTime, invoice) {
|
|
139
|
-
if (!this.isActive || !invoice) return false;
|
|
140
|
-
|
|
141
|
-
const now = moment(currentTime);
|
|
142
|
-
const invoiceDate = moment(invoice.createdAt);
|
|
143
|
-
const dueDate = moment(invoice.dueDate);
|
|
144
|
-
const today = moment().startOf('day');
|
|
145
|
-
|
|
146
|
-
// Check if current time matches reminder time
|
|
147
|
-
if (!this.isTimeToProcess(now)) return false;
|
|
148
|
-
|
|
149
|
-
// Check for invoice date reminder
|
|
150
|
-
if (this.remindOn.invoiceDate && invoiceDate.isSame(today, 'day')) {
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Check for due date reminder
|
|
155
|
-
if (this.remindOn.dueDate && dueDate.isSame(today, 'day')) {
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Check for overdue reminder
|
|
160
|
-
if (this.remindOn.afterOverdue.enabled && dueDate.isBefore(today, 'day')) {
|
|
161
|
-
// If daily reminders are enabled, send reminder every day after due date
|
|
162
|
-
if (this.remindOn.afterOverdue.daily) {
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Otherwise, check if today is one of the specific days after due date
|
|
167
|
-
const daysOverdue = today.diff(dueDate, 'days');
|
|
168
|
-
return this.remindOn.afterOverdue.days.includes(daysOverdue);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return false;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
// Helper to check if current time is close to scheduled reminder time
|
|
175
|
-
reminderSchema.methods.isTimeToProcess = function (currentTime) {
|
|
176
|
-
const reminderTime = moment(this.time, 'HH:mm');
|
|
177
|
-
const currentMoment = moment(currentTime).format('HH:mm');
|
|
178
|
-
const diffMinutes = Math.abs(
|
|
179
|
-
moment(currentMoment, 'HH:mm').diff(reminderTime, 'minutes')
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
// Allow processing within 5 minutes of scheduled time
|
|
183
|
-
return diffMinutes <= 5;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
// Method to check if reminder has been processed today
|
|
187
|
-
reminderSchema.methods.hasBeenProcessedToday = function () {
|
|
188
|
-
if (!this.lastProcessed) return false;
|
|
189
|
-
|
|
190
|
-
const today = moment().startOf('day');
|
|
191
|
-
const processedDate = moment(this.lastProcessed).startOf('day');
|
|
192
|
-
|
|
193
|
-
return processedDate.isSame(today, 'day');
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const Reminder = mongoose.model("Reminder", reminderSchema);
|
|
197
|
-
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
const moment = require("moment-timezone");
|
|
3
|
+
|
|
4
|
+
const reminderSchema = new mongoose.Schema(
|
|
5
|
+
{
|
|
6
|
+
name: {
|
|
7
|
+
type: String,
|
|
8
|
+
required: true,
|
|
9
|
+
trim: true,
|
|
10
|
+
},
|
|
11
|
+
type: {
|
|
12
|
+
type: String,
|
|
13
|
+
required: true,
|
|
14
|
+
enum: ['standard', 'custom'],
|
|
15
|
+
default: 'standard'
|
|
16
|
+
},
|
|
17
|
+
module: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true,
|
|
20
|
+
enum: ['levy', 'lease', 'utility'],
|
|
21
|
+
default: 'levy'
|
|
22
|
+
},
|
|
23
|
+
moduleId: {
|
|
24
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
25
|
+
required: true,
|
|
26
|
+
refPath: 'module'
|
|
27
|
+
},
|
|
28
|
+
remindOn: {
|
|
29
|
+
invoiceDate: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: true,
|
|
32
|
+
},
|
|
33
|
+
dueDate: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false,
|
|
36
|
+
},
|
|
37
|
+
afterOverdue: {
|
|
38
|
+
enabled: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
daily: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false,
|
|
45
|
+
},
|
|
46
|
+
days: {
|
|
47
|
+
type: [Number],
|
|
48
|
+
validate: {
|
|
49
|
+
validator: function (value) {
|
|
50
|
+
// If daily reminders are enabled, no need to validate days
|
|
51
|
+
if (this.remindOn?.afterOverdue?.daily === true) return true;
|
|
52
|
+
|
|
53
|
+
// If overdue reminders are disabled, no validation needed
|
|
54
|
+
if (!this.remindOn?.afterOverdue?.enabled) return true;
|
|
55
|
+
|
|
56
|
+
// If overdue is enabled but daily is false, then validate days array
|
|
57
|
+
return Array.isArray(value) &&
|
|
58
|
+
value.length > 0 &&
|
|
59
|
+
value.every(day => [1, 3, 7].includes(day));
|
|
60
|
+
},
|
|
61
|
+
message: 'When overdue reminders are enabled (and daily is false), days must include only values of 1, 3, or 7'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
time: {
|
|
67
|
+
type: String,
|
|
68
|
+
required: true,
|
|
69
|
+
default: "09:00",
|
|
70
|
+
validate: {
|
|
71
|
+
validator: function (value) {
|
|
72
|
+
return /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/.test(value);
|
|
73
|
+
},
|
|
74
|
+
message: 'Time must be in HH:mm format'
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
isActive: {
|
|
78
|
+
type: Boolean,
|
|
79
|
+
required: true,
|
|
80
|
+
default: true,
|
|
81
|
+
},
|
|
82
|
+
processed: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
required: true,
|
|
85
|
+
default: false,
|
|
86
|
+
},
|
|
87
|
+
lastProcessed: {
|
|
88
|
+
type: Date,
|
|
89
|
+
},
|
|
90
|
+
notificationTypes: {
|
|
91
|
+
type: [String],
|
|
92
|
+
required: true,
|
|
93
|
+
validate: {
|
|
94
|
+
validator: function (value) {
|
|
95
|
+
return value.length > 0 &&
|
|
96
|
+
value.every(type => ['SMS', 'EMAIL'].includes(type.toUpperCase()));
|
|
97
|
+
},
|
|
98
|
+
message: 'At least one valid notification type is required'
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
message: {
|
|
102
|
+
type: String,
|
|
103
|
+
maxLength: [500, 'Message cannot exceed 500 characters']
|
|
104
|
+
},
|
|
105
|
+
facilityId: {
|
|
106
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
107
|
+
ref: "Facility",
|
|
108
|
+
required: true,
|
|
109
|
+
index: true
|
|
110
|
+
},
|
|
111
|
+
timezone: {
|
|
112
|
+
type: String,
|
|
113
|
+
required: true,
|
|
114
|
+
default: 'UTC',
|
|
115
|
+
validate: {
|
|
116
|
+
validator: function (value) {
|
|
117
|
+
return moment.tz.names().includes(value);
|
|
118
|
+
},
|
|
119
|
+
message: 'Invalid timezone'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
timestamps: true,
|
|
125
|
+
indexes: [
|
|
126
|
+
{ facilityId: 1, isActive: 1 },
|
|
127
|
+
{ facilityId: 1, isActive: 1, 'remindOn.invoiceDate': 1 },
|
|
128
|
+
{ facilityId: 1, isActive: 1, 'remindOn.dueDate': 1 },
|
|
129
|
+
{ facilityId: 1, isActive: 1, 'remindOn.afterOverdue.enabled': 1 },
|
|
130
|
+
{ facilityId: 1, isActive: 1, 'remindOn.afterOverdue.daily': 1 },
|
|
131
|
+
{ moduleId: 1, isActive: 1 },
|
|
132
|
+
{ facilityId: 1, lastProcessed: 1 }
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Helper method to check if reminder should be processed
|
|
138
|
+
reminderSchema.methods.shouldProcess = function (currentTime, invoice) {
|
|
139
|
+
if (!this.isActive || !invoice) return false;
|
|
140
|
+
|
|
141
|
+
const now = moment(currentTime);
|
|
142
|
+
const invoiceDate = moment(invoice.createdAt);
|
|
143
|
+
const dueDate = moment(invoice.dueDate);
|
|
144
|
+
const today = moment().startOf('day');
|
|
145
|
+
|
|
146
|
+
// Check if current time matches reminder time
|
|
147
|
+
if (!this.isTimeToProcess(now)) return false;
|
|
148
|
+
|
|
149
|
+
// Check for invoice date reminder
|
|
150
|
+
if (this.remindOn.invoiceDate && invoiceDate.isSame(today, 'day')) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check for due date reminder
|
|
155
|
+
if (this.remindOn.dueDate && dueDate.isSame(today, 'day')) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check for overdue reminder
|
|
160
|
+
if (this.remindOn.afterOverdue.enabled && dueDate.isBefore(today, 'day')) {
|
|
161
|
+
// If daily reminders are enabled, send reminder every day after due date
|
|
162
|
+
if (this.remindOn.afterOverdue.daily) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Otherwise, check if today is one of the specific days after due date
|
|
167
|
+
const daysOverdue = today.diff(dueDate, 'days');
|
|
168
|
+
return this.remindOn.afterOverdue.days.includes(daysOverdue);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return false;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Helper to check if current time is close to scheduled reminder time
|
|
175
|
+
reminderSchema.methods.isTimeToProcess = function (currentTime) {
|
|
176
|
+
const reminderTime = moment(this.time, 'HH:mm');
|
|
177
|
+
const currentMoment = moment(currentTime).format('HH:mm');
|
|
178
|
+
const diffMinutes = Math.abs(
|
|
179
|
+
moment(currentMoment, 'HH:mm').diff(reminderTime, 'minutes')
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Allow processing within 5 minutes of scheduled time
|
|
183
|
+
return diffMinutes <= 5;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Method to check if reminder has been processed today
|
|
187
|
+
reminderSchema.methods.hasBeenProcessedToday = function () {
|
|
188
|
+
if (!this.lastProcessed) return false;
|
|
189
|
+
|
|
190
|
+
const today = moment().startOf('day');
|
|
191
|
+
const processedDate = moment(this.lastProcessed).startOf('day');
|
|
192
|
+
|
|
193
|
+
return processedDate.isSame(today, 'day');
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const Reminder = mongoose.model("Reminder", reminderSchema);
|
|
197
|
+
|
|
198
198
|
module.exports = Reminder;
|
package/src/models/report.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const mongoose = require("mongoose");
|
|
2
|
-
|
|
3
|
-
const ReportSchema = new mongoose.Schema({
|
|
4
|
-
type: {
|
|
5
|
-
type: String,
|
|
6
|
-
enum: ['revenue', 'leasePerformance', 'expiredLeases'],
|
|
7
|
-
required: true
|
|
8
|
-
},
|
|
9
|
-
data: { type: mongoose.Schema.Types.Mixed, required: true },
|
|
10
|
-
generatedAt: { type: Date, default: Date.now },
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
module.exports = mongoose.model('Report', ReportSchema);
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
const ReportSchema = new mongoose.Schema({
|
|
4
|
+
type: {
|
|
5
|
+
type: String,
|
|
6
|
+
enum: ['revenue', 'leasePerformance', 'expiredLeases'],
|
|
7
|
+
required: true
|
|
8
|
+
},
|
|
9
|
+
data: { type: mongoose.Schema.Types.Mixed, required: true },
|
|
10
|
+
generatedAt: { type: Date, default: Date.now },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
module.exports = mongoose.model('Report', ReportSchema);
|
|
14
14
|
|
package/src/models/resident.js
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
const mongoose = require('mongoose');
|
|
2
|
-
|
|
3
|
-
// Define the schema for Resident
|
|
4
|
-
const residentSchema = new mongoose.Schema({
|
|
5
|
-
residentId: {
|
|
6
|
-
type: String,
|
|
7
|
-
required: true,
|
|
8
|
-
unique: true
|
|
9
|
-
},
|
|
10
|
-
name: {
|
|
11
|
-
type: String,
|
|
12
|
-
required: true
|
|
13
|
-
},
|
|
14
|
-
email: {
|
|
15
|
-
type: String,
|
|
16
|
-
required: true
|
|
17
|
-
},
|
|
18
|
-
phone: {
|
|
19
|
-
type: String,
|
|
20
|
-
required: true
|
|
21
|
-
},
|
|
22
|
-
nationalId: {
|
|
23
|
-
type: String,
|
|
24
|
-
required: true
|
|
25
|
-
},
|
|
26
|
-
unitId: {
|
|
27
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
28
|
-
ref: 'Unit',
|
|
29
|
-
required: true
|
|
30
|
-
},
|
|
31
|
-
unitName: {
|
|
32
|
-
type: String,
|
|
33
|
-
required: true
|
|
34
|
-
},
|
|
35
|
-
facilityId: {
|
|
36
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
37
|
-
ref: 'Facility',
|
|
38
|
-
required: true
|
|
39
|
-
},
|
|
40
|
-
contracts: [{
|
|
41
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
42
|
-
ref: 'LevyContract'
|
|
43
|
-
}],
|
|
44
|
-
levies: [{
|
|
45
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
46
|
-
ref: 'Levy'
|
|
47
|
-
}],
|
|
48
|
-
invoices: [{
|
|
49
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
50
|
-
ref: 'Invoice'
|
|
51
|
-
}],
|
|
52
|
-
paymentHistory: [{
|
|
53
|
-
paymentDate: {
|
|
54
|
-
type: Date,
|
|
55
|
-
required: true
|
|
56
|
-
},
|
|
57
|
-
amount: {
|
|
58
|
-
type: Number,
|
|
59
|
-
required: true
|
|
60
|
-
},
|
|
61
|
-
paymentMethod: {
|
|
62
|
-
type: String
|
|
63
|
-
},
|
|
64
|
-
transactionId: {
|
|
65
|
-
type: String
|
|
66
|
-
}
|
|
67
|
-
}],
|
|
68
|
-
status: {
|
|
69
|
-
type: String,
|
|
70
|
-
enum: ['Active', 'Inactive'],
|
|
71
|
-
default: 'Active'
|
|
72
|
-
},
|
|
73
|
-
registrationDate: {
|
|
74
|
-
type: Date,
|
|
75
|
-
default: Date.now
|
|
76
|
-
},
|
|
77
|
-
paymentFrequency: {
|
|
78
|
-
type: String,
|
|
79
|
-
enum: ['Monthly', 'Quarterly', 'Annually']
|
|
80
|
-
},
|
|
81
|
-
notificationPreferences: {
|
|
82
|
-
email: {
|
|
83
|
-
type: Boolean,
|
|
84
|
-
default: true
|
|
85
|
-
},
|
|
86
|
-
sms: {
|
|
87
|
-
type: Boolean,
|
|
88
|
-
default: true
|
|
89
|
-
},
|
|
90
|
-
push: {
|
|
91
|
-
type: Boolean,
|
|
92
|
-
default: true
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
reminders: [{
|
|
96
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
97
|
-
ref: 'Reminder'
|
|
98
|
-
}],
|
|
99
|
-
notifications: [{
|
|
100
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
101
|
-
ref: 'Notification'
|
|
102
|
-
}],
|
|
103
|
-
penalties: [{
|
|
104
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
105
|
-
ref: 'Penalty'
|
|
106
|
-
}],
|
|
107
|
-
penaltyStatus: {
|
|
108
|
-
type: String,
|
|
109
|
-
enum: ['Pending', 'Paid', 'Waived'],
|
|
110
|
-
default: 'Pending'
|
|
111
|
-
},
|
|
112
|
-
notes: {
|
|
113
|
-
type: String
|
|
114
|
-
}
|
|
115
|
-
}, {
|
|
116
|
-
timestamps: true
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const Resident = mongoose.model('Resident', residentSchema);
|
|
120
|
-
|
|
121
|
-
module.exports = Resident;
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
// Define the schema for Resident
|
|
4
|
+
const residentSchema = new mongoose.Schema({
|
|
5
|
+
residentId: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: true,
|
|
8
|
+
unique: true
|
|
9
|
+
},
|
|
10
|
+
name: {
|
|
11
|
+
type: String,
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
email: {
|
|
15
|
+
type: String,
|
|
16
|
+
required: true
|
|
17
|
+
},
|
|
18
|
+
phone: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true
|
|
21
|
+
},
|
|
22
|
+
nationalId: {
|
|
23
|
+
type: String,
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
unitId: {
|
|
27
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
28
|
+
ref: 'Unit',
|
|
29
|
+
required: true
|
|
30
|
+
},
|
|
31
|
+
unitName: {
|
|
32
|
+
type: String,
|
|
33
|
+
required: true
|
|
34
|
+
},
|
|
35
|
+
facilityId: {
|
|
36
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
37
|
+
ref: 'Facility',
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
contracts: [{
|
|
41
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
42
|
+
ref: 'LevyContract'
|
|
43
|
+
}],
|
|
44
|
+
levies: [{
|
|
45
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
46
|
+
ref: 'Levy'
|
|
47
|
+
}],
|
|
48
|
+
invoices: [{
|
|
49
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
50
|
+
ref: 'Invoice'
|
|
51
|
+
}],
|
|
52
|
+
paymentHistory: [{
|
|
53
|
+
paymentDate: {
|
|
54
|
+
type: Date,
|
|
55
|
+
required: true
|
|
56
|
+
},
|
|
57
|
+
amount: {
|
|
58
|
+
type: Number,
|
|
59
|
+
required: true
|
|
60
|
+
},
|
|
61
|
+
paymentMethod: {
|
|
62
|
+
type: String
|
|
63
|
+
},
|
|
64
|
+
transactionId: {
|
|
65
|
+
type: String
|
|
66
|
+
}
|
|
67
|
+
}],
|
|
68
|
+
status: {
|
|
69
|
+
type: String,
|
|
70
|
+
enum: ['Active', 'Inactive'],
|
|
71
|
+
default: 'Active'
|
|
72
|
+
},
|
|
73
|
+
registrationDate: {
|
|
74
|
+
type: Date,
|
|
75
|
+
default: Date.now
|
|
76
|
+
},
|
|
77
|
+
paymentFrequency: {
|
|
78
|
+
type: String,
|
|
79
|
+
enum: ['Monthly', 'Quarterly', 'Annually']
|
|
80
|
+
},
|
|
81
|
+
notificationPreferences: {
|
|
82
|
+
email: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
default: true
|
|
85
|
+
},
|
|
86
|
+
sms: {
|
|
87
|
+
type: Boolean,
|
|
88
|
+
default: true
|
|
89
|
+
},
|
|
90
|
+
push: {
|
|
91
|
+
type: Boolean,
|
|
92
|
+
default: true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
reminders: [{
|
|
96
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
97
|
+
ref: 'Reminder'
|
|
98
|
+
}],
|
|
99
|
+
notifications: [{
|
|
100
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
101
|
+
ref: 'Notification'
|
|
102
|
+
}],
|
|
103
|
+
penalties: [{
|
|
104
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
105
|
+
ref: 'Penalty'
|
|
106
|
+
}],
|
|
107
|
+
penaltyStatus: {
|
|
108
|
+
type: String,
|
|
109
|
+
enum: ['Pending', 'Paid', 'Waived'],
|
|
110
|
+
default: 'Pending'
|
|
111
|
+
},
|
|
112
|
+
notes: {
|
|
113
|
+
type: String
|
|
114
|
+
}
|
|
115
|
+
}, {
|
|
116
|
+
timestamps: true
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const Resident = mongoose.model('Resident', residentSchema);
|
|
120
|
+
|
|
121
|
+
module.exports = Resident;
|