payservedb 5.7.3 → 5.7.5
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/package.json
CHANGED
|
@@ -22,7 +22,12 @@ const PropertyManagerContractSchema = new Schema(
|
|
|
22
22
|
ref: 'Customer',
|
|
23
23
|
required: [true, 'Customer ID is required']
|
|
24
24
|
},
|
|
25
|
-
|
|
25
|
+
facilityId: {
|
|
26
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
27
|
+
ref: 'Facility',
|
|
28
|
+
required: [true, 'Facility ID is required']
|
|
29
|
+
},
|
|
30
|
+
// Lease term details
|
|
26
31
|
startDate: {
|
|
27
32
|
type: Date,
|
|
28
33
|
required: function() {
|
|
@@ -35,33 +40,38 @@ const PropertyManagerContractSchema = new Schema(
|
|
|
35
40
|
return this.status === 'Active';
|
|
36
41
|
}
|
|
37
42
|
},
|
|
38
|
-
|
|
43
|
+
// Payment details - aligned with LeaseAgreement
|
|
44
|
+
paymentDueDate: {
|
|
39
45
|
type: Number,
|
|
40
46
|
required: function() {
|
|
41
47
|
return this.status === 'Active';
|
|
42
48
|
},
|
|
43
|
-
min: [1, '
|
|
44
|
-
max: [31, '
|
|
49
|
+
min: [1, 'Payment due date must be between 1 and 31'],
|
|
50
|
+
max: [31, 'Payment due date must be between 1 and 31']
|
|
45
51
|
},
|
|
46
|
-
|
|
47
|
-
type: String,
|
|
52
|
+
frequency: {
|
|
53
|
+
type: String,
|
|
54
|
+
enum: ['Monthly', 'Quarterly', 'Annually'],
|
|
55
|
+
default: 'Monthly',
|
|
48
56
|
required: function() {
|
|
49
57
|
return this.status === 'Active';
|
|
50
58
|
}
|
|
51
59
|
},
|
|
60
|
+
nextInvoiceDate: {
|
|
61
|
+
type: Date
|
|
62
|
+
},
|
|
63
|
+
lastInvoiceDate: {
|
|
64
|
+
type: Date
|
|
65
|
+
},
|
|
66
|
+
autoSend: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: false
|
|
69
|
+
},
|
|
52
70
|
balanceBroughtForward: {
|
|
53
71
|
type: Number,
|
|
54
72
|
default: 0
|
|
55
73
|
},
|
|
56
|
-
|
|
57
|
-
type: String,
|
|
58
|
-
enum: ['Daily', 'Weekly', 'Bi-Weekly', 'Monthly', 'Quarterly', 'Semi-Annually', 'Annually'],
|
|
59
|
-
default: 'Monthly',
|
|
60
|
-
required: function() {
|
|
61
|
-
return this.status === 'Active';
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
// Always required fields regardless of status
|
|
74
|
+
// Management fee
|
|
65
75
|
managementFee: {
|
|
66
76
|
type: {
|
|
67
77
|
type: String,
|
|
@@ -74,7 +84,7 @@ const PropertyManagerContractSchema = new Schema(
|
|
|
74
84
|
min: [0, 'Management fee value cannot be negative']
|
|
75
85
|
}
|
|
76
86
|
},
|
|
77
|
-
// GL Account configurations
|
|
87
|
+
// GL Account configurations
|
|
78
88
|
invoiceDoubleEntryAccount: {
|
|
79
89
|
type: mongoose.Schema.Types.ObjectId,
|
|
80
90
|
ref: 'GLAccountDoubleEntries'
|
|
@@ -83,7 +93,6 @@ const PropertyManagerContractSchema = new Schema(
|
|
|
83
93
|
type: mongoose.Schema.Types.ObjectId,
|
|
84
94
|
ref: 'GLAccountDoubleEntries'
|
|
85
95
|
},
|
|
86
|
-
// GL Account direct configurations (used when creating double entry records)
|
|
87
96
|
glAccounts: {
|
|
88
97
|
invoice: {
|
|
89
98
|
debit: {
|
|
@@ -112,248 +121,52 @@ const PropertyManagerContractSchema = new Schema(
|
|
|
112
121
|
default: 'Inactive',
|
|
113
122
|
required: [true, 'Status is required']
|
|
114
123
|
},
|
|
115
|
-
facilityId: {
|
|
116
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
117
|
-
ref: 'Facility',
|
|
118
|
-
required: [true, 'Facility ID is required']
|
|
119
|
-
},
|
|
120
|
-
lastInvoiceDate: {
|
|
121
|
-
type: Date
|
|
122
|
-
},
|
|
123
|
-
nextInvoiceDate: {
|
|
124
|
-
type: Date
|
|
125
|
-
},
|
|
126
|
-
autoSend: {
|
|
127
|
-
type: Boolean,
|
|
128
|
-
default: false
|
|
129
|
-
},
|
|
130
|
-
// Track data source and sync information
|
|
131
|
-
leaseDataSource: {
|
|
132
|
-
type: String,
|
|
133
|
-
enum: ['lease', 'manual'],
|
|
134
|
-
default: 'manual'
|
|
135
|
-
},
|
|
136
|
-
lastSyncedAt: {
|
|
137
|
-
type: Date
|
|
138
|
-
},
|
|
139
|
-
// Track which units have lease agreements
|
|
140
|
-
unitsWithLeases: [{
|
|
141
|
-
unitId: {
|
|
142
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
143
|
-
ref: 'Unit'
|
|
144
|
-
},
|
|
145
|
-
leaseId: {
|
|
146
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
147
|
-
ref: 'LeaseAgreement'
|
|
148
|
-
},
|
|
149
|
-
syncedAt: {
|
|
150
|
-
type: Date,
|
|
151
|
-
default: Date.now
|
|
152
|
-
}
|
|
153
|
-
}],
|
|
154
124
|
createdBy: {
|
|
155
125
|
type: mongoose.Schema.Types.ObjectId,
|
|
156
126
|
ref: 'User'
|
|
157
|
-
}
|
|
158
|
-
updatedBy: {
|
|
159
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
160
|
-
ref: 'User'
|
|
161
|
-
},
|
|
162
|
-
// Track contract edit history
|
|
163
|
-
editHistory: [{
|
|
164
|
-
editedBy: {
|
|
165
|
-
type: mongoose.Schema.Types.Mixed,
|
|
166
|
-
ref: 'User'
|
|
167
|
-
},
|
|
168
|
-
editedAt: {
|
|
169
|
-
type: Date,
|
|
170
|
-
default: Date.now
|
|
171
|
-
},
|
|
172
|
-
reason: {
|
|
173
|
-
type: String,
|
|
174
|
-
required: true
|
|
175
|
-
},
|
|
176
|
-
changes: {
|
|
177
|
-
type: Object
|
|
178
|
-
}
|
|
179
|
-
}]
|
|
127
|
+
}
|
|
180
128
|
},
|
|
181
129
|
{
|
|
182
|
-
timestamps: true
|
|
183
|
-
toJSON: { virtuals: true },
|
|
184
|
-
toObject: { virtuals: true }
|
|
130
|
+
timestamps: true
|
|
185
131
|
}
|
|
186
132
|
);
|
|
187
133
|
|
|
188
|
-
//
|
|
189
|
-
PropertyManagerContractSchema.virtual('propertyManagerDetails', {
|
|
190
|
-
ref: 'User',
|
|
191
|
-
localField: 'propertyManager',
|
|
192
|
-
foreignField: '_id',
|
|
193
|
-
justOne: true
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Virtual populate for Customer details
|
|
197
|
-
PropertyManagerContractSchema.virtual('customer', {
|
|
198
|
-
ref: 'Customer',
|
|
199
|
-
localField: 'customerId',
|
|
200
|
-
foreignField: '_id',
|
|
201
|
-
justOne: true
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// Virtual populate for Units details
|
|
205
|
-
PropertyManagerContractSchema.virtual('unitDetails', {
|
|
206
|
-
ref: 'Unit',
|
|
207
|
-
localField: 'units',
|
|
208
|
-
foreignField: '_id'
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
// Virtual populate for invoice double entry account
|
|
212
|
-
PropertyManagerContractSchema.virtual('invoiceDoubleEntry', {
|
|
213
|
-
ref: 'GLAccountDoubleEntries',
|
|
214
|
-
localField: 'invoiceDoubleEntryAccount',
|
|
215
|
-
foreignField: '_id',
|
|
216
|
-
justOne: true
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Virtual populate for payment double entry account
|
|
220
|
-
PropertyManagerContractSchema.virtual('paymentDoubleEntry', {
|
|
221
|
-
ref: 'GLAccountDoubleEntries',
|
|
222
|
-
localField: 'paymentDoubleEntryAccount',
|
|
223
|
-
foreignField: '_id',
|
|
224
|
-
justOne: true
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// Virtual populate for Facility details
|
|
228
|
-
PropertyManagerContractSchema.virtual('facility', {
|
|
229
|
-
ref: 'Facility',
|
|
230
|
-
localField: 'facilityId',
|
|
231
|
-
foreignField: '_id',
|
|
232
|
-
justOne: true
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// Virtual to check if contract is complete (has all lease-dependent fields)
|
|
236
|
-
PropertyManagerContractSchema.virtual('isComplete').get(function() {
|
|
237
|
-
return this.startDate && this.endDate && this.invoiceDay && this.dueDate && this.collectionFrequency;
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// Virtual to get completion percentage
|
|
241
|
-
PropertyManagerContractSchema.virtual('completionPercentage').get(function() {
|
|
242
|
-
const requiredFields = ['startDate', 'endDate', 'invoiceDay', 'dueDate', 'collectionFrequency'];
|
|
243
|
-
const completedFields = requiredFields.filter(field => this[field] != null).length;
|
|
244
|
-
return Math.round((completedFields / requiredFields.length) * 100);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// Pre-save middleware to ensure endDate is after startDate (only when both exist)
|
|
134
|
+
// Basic validation
|
|
248
135
|
PropertyManagerContractSchema.pre('save', function (next) {
|
|
249
136
|
if (this.startDate && this.endDate && this.startDate >= this.endDate) {
|
|
250
137
|
next(new Error('End date must be after start date'));
|
|
251
|
-
} else {
|
|
252
|
-
next();
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
// Pre-save middleware to validate units array is not empty
|
|
257
|
-
PropertyManagerContractSchema.pre('save', function (next) {
|
|
258
|
-
if (!this.units || this.units.length === 0) {
|
|
138
|
+
} else if (!this.units || this.units.length === 0) {
|
|
259
139
|
next(new Error('At least one unit must be specified'));
|
|
260
|
-
} else {
|
|
261
|
-
next();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// Pre-save middleware to validate management fee
|
|
266
|
-
PropertyManagerContractSchema.pre('save', function (next) {
|
|
267
|
-
if (this.managementFee.type === 'percentage' && this.managementFee.value > 100) {
|
|
140
|
+
} else if (this.managementFee.type === 'percentage' && this.managementFee.value > 100) {
|
|
268
141
|
next(new Error('Management fee percentage cannot exceed 100%'));
|
|
269
142
|
} else {
|
|
270
143
|
next();
|
|
271
144
|
}
|
|
272
145
|
});
|
|
273
146
|
|
|
274
|
-
//
|
|
275
|
-
PropertyManagerContractSchema.pre('save', function (next) {
|
|
276
|
-
// If contract has all required lease fields and is currently Inactive, make it Active
|
|
277
|
-
if (this.status === 'Inactive' && this.isComplete) {
|
|
278
|
-
this.status = 'Active';
|
|
279
|
-
this.leaseDataSource = 'lease';
|
|
280
|
-
this.lastSyncedAt = new Date();
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// If contract is missing required fields and is currently Active, make it Inactive
|
|
284
|
-
if (this.status === 'Active' && !this.isComplete) {
|
|
285
|
-
this.status = 'Inactive';
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
next();
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// Pre-save middleware to set next invoice date based on collection frequency (only for active contracts)
|
|
292
|
-
PropertyManagerContractSchema.pre('save', function (next) {
|
|
293
|
-
if (this.isNew && this.status === 'Active' && this.startDate && this.invoiceDay && !this.nextInvoiceDate) {
|
|
294
|
-
const baseDate = new Date(this.startDate);
|
|
295
|
-
baseDate.setDate(this.invoiceDay);
|
|
296
|
-
|
|
297
|
-
// If the invoice day has passed this month, set for next month
|
|
298
|
-
if (baseDate < this.startDate) {
|
|
299
|
-
baseDate.setMonth(baseDate.getMonth() + 1);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
this.nextInvoiceDate = baseDate;
|
|
303
|
-
}
|
|
304
|
-
next();
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// Method to sync with lease data
|
|
147
|
+
// Sync with lease data
|
|
308
148
|
PropertyManagerContractSchema.methods.syncWithLeaseData = async function(leaseData) {
|
|
309
149
|
if (!leaseData) return;
|
|
310
150
|
|
|
311
151
|
this.startDate = leaseData.leaseTerms?.startDate || this.startDate;
|
|
312
152
|
this.endDate = leaseData.leaseTerms?.endDate || this.endDate;
|
|
313
|
-
this.
|
|
153
|
+
this.paymentDueDate = leaseData.financialTerms?.paymentDueDate || this.paymentDueDate;
|
|
314
154
|
this.balanceBroughtForward = leaseData.financialTerms?.balanceBroughtForward || this.balanceBroughtForward;
|
|
315
|
-
this.
|
|
155
|
+
this.frequency = leaseData.billingCycle?.frequency || this.frequency;
|
|
316
156
|
this.autoSend = leaseData.billingCycle?.autoSend !== undefined ? leaseData.billingCycle.autoSend : this.autoSend;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (leaseData.glAccounts) {
|
|
320
|
-
this.glAccounts = leaseData.glAccounts;
|
|
321
|
-
}
|
|
322
|
-
if (leaseData.invoiceDoubleEntryAccount) {
|
|
323
|
-
this.invoiceDoubleEntryAccount = leaseData.invoiceDoubleEntryAccount;
|
|
324
|
-
}
|
|
325
|
-
if (leaseData.paymentDoubleEntryAccount) {
|
|
326
|
-
this.paymentDoubleEntryAccount = leaseData.paymentDoubleEntryAccount;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
this.leaseDataSource = 'lease';
|
|
330
|
-
this.lastSyncedAt = new Date();
|
|
331
|
-
|
|
332
|
-
// Auto-calculate due date from payment due date if not set
|
|
333
|
-
if (this.invoiceDay && !this.dueDate) {
|
|
334
|
-
const dueDateMap = {
|
|
335
|
-
1: "1st", 5: "5th", 10: "10th", 15: "15th"
|
|
336
|
-
};
|
|
337
|
-
this.dueDate = dueDateMap[this.invoiceDay] || `${this.invoiceDay}th`;
|
|
338
|
-
}
|
|
157
|
+
this.nextInvoiceDate = leaseData.billingCycle?.nextInvoiceDate || this.nextInvoiceDate;
|
|
158
|
+
this.lastInvoiceDate = leaseData.billingCycle?.lastInvoiceDate || this.lastInvoiceDate;
|
|
339
159
|
|
|
340
160
|
return this.save();
|
|
341
161
|
};
|
|
342
162
|
|
|
343
|
-
//
|
|
163
|
+
// Basic indexes
|
|
344
164
|
PropertyManagerContractSchema.index({ customerId: 1, status: 1 });
|
|
345
165
|
PropertyManagerContractSchema.index({ facilityId: 1 });
|
|
346
|
-
PropertyManagerContractSchema.index({
|
|
347
|
-
PropertyManagerContractSchema.index({ propertyManager: 1 }); // New index for property manager
|
|
348
|
-
PropertyManagerContractSchema.index({ invoiceDoubleEntryAccount: 1 });
|
|
349
|
-
PropertyManagerContractSchema.index({ paymentDoubleEntryAccount: 1 });
|
|
350
|
-
PropertyManagerContractSchema.index({ startDate: 1, endDate: 1 });
|
|
166
|
+
PropertyManagerContractSchema.index({ propertyManager: 1 });
|
|
351
167
|
PropertyManagerContractSchema.index({ nextInvoiceDate: 1, status: 1 });
|
|
352
|
-
PropertyManagerContractSchema.index({ leaseDataSource: 1 });
|
|
353
|
-
PropertyManagerContractSchema.index({ 'unitsWithLeases.unitId': 1 });
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
// Compile the model from the schema
|
|
357
|
-
const PropertyManagerContract = mongoose.model("PropertyManagerContract", PropertyManagerContractSchema);
|
|
358
168
|
|
|
359
|
-
module.exports =
|
|
169
|
+
module.exports = {
|
|
170
|
+
schema: PropertyManagerContractSchema,
|
|
171
|
+
name: 'PropertyManagerContract'
|
|
172
|
+
};
|
|
@@ -21,6 +21,12 @@ const purchaseOrderSchema = new mongoose.Schema({
|
|
|
21
21
|
index: true,
|
|
22
22
|
ref: 'PurchaseRequest'
|
|
23
23
|
},
|
|
24
|
+
rfqNumber: {
|
|
25
|
+
type: String,
|
|
26
|
+
trim: true,
|
|
27
|
+
index: true,
|
|
28
|
+
ref: 'RFQDetails'
|
|
29
|
+
},
|
|
24
30
|
supplier: {
|
|
25
31
|
type: mongoose.Schema.Types.ObjectId,
|
|
26
32
|
ref: 'Supplier',
|
|
@@ -52,7 +58,9 @@ const purchaseOrderSchema = new mongoose.Schema({
|
|
|
52
58
|
},
|
|
53
59
|
budget: {
|
|
54
60
|
type: String,
|
|
55
|
-
trim: true
|
|
61
|
+
trim: true,
|
|
62
|
+
index: true,
|
|
63
|
+
ref: 'Budget'
|
|
56
64
|
},
|
|
57
65
|
status: {
|
|
58
66
|
type: String,
|
package/src/models/tickets.js
CHANGED
|
@@ -23,9 +23,9 @@ const ticketSchema = new mongoose.Schema({
|
|
|
23
23
|
priority: {
|
|
24
24
|
type: String,
|
|
25
25
|
},
|
|
26
|
-
|
|
26
|
+
images: [{
|
|
27
27
|
type: String,
|
|
28
|
-
},
|
|
28
|
+
}],
|
|
29
29
|
date: {
|
|
30
30
|
type: Date,
|
|
31
31
|
},
|
|
@@ -64,9 +64,9 @@ const ticketSchema = new mongoose.Schema({
|
|
|
64
64
|
type: String,
|
|
65
65
|
required: false,
|
|
66
66
|
},
|
|
67
|
-
|
|
67
|
+
assessImages: [{
|
|
68
68
|
type: String,
|
|
69
|
-
},
|
|
69
|
+
}],
|
|
70
70
|
closingReason: {
|
|
71
71
|
type: String,
|
|
72
72
|
required: false,
|