payservedb 5.7.4 → 5.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payservedb",
3
- "version": "5.7.4",
3
+ "version": "5.7.6",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -22,7 +22,12 @@ const PropertyManagerContractSchema = new Schema(
22
22
  ref: 'Customer',
23
23
  required: [true, 'Customer ID is required']
24
24
  },
25
- // Optional fields - only required when status is "Active"
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
- invoiceDay: {
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, 'Invoice day must be between 1 and 31'],
44
- max: [31, 'Invoice day must be between 1 and 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
- dueDate: {
47
- type: String, // Store as string like "5th", "10th", etc.
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
- collectionFrequency: {
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 - matching LeaseAgreement pattern
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
- // Virtual populate for Property Manager details
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
- // Pre-save middleware to auto-update status based on completion
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.invoiceDay = leaseData.financialTerms?.paymentDueDate || this.invoiceDay;
153
+ this.paymentDueDate = leaseData.financialTerms?.paymentDueDate || this.paymentDueDate;
314
154
  this.balanceBroughtForward = leaseData.financialTerms?.balanceBroughtForward || this.balanceBroughtForward;
315
- this.collectionFrequency = leaseData.billingCycle?.frequency || this.collectionFrequency;
155
+ this.frequency = leaseData.billingCycle?.frequency || this.frequency;
316
156
  this.autoSend = leaseData.billingCycle?.autoSend !== undefined ? leaseData.billingCycle.autoSend : this.autoSend;
317
-
318
- // Copy GL accounts if available
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
- // Indexes for efficient queries
163
+ // Basic indexes
344
164
  PropertyManagerContractSchema.index({ customerId: 1, status: 1 });
345
165
  PropertyManagerContractSchema.index({ facilityId: 1 });
346
- PropertyManagerContractSchema.index({ units: 1 });
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 = PropertyManagerContract;
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,
@@ -47,6 +47,14 @@ const rfqResponseSchema = new mongoose.Schema({
47
47
  default: '',
48
48
  }
49
49
  }],
50
+
51
+ vatAmount: {
52
+ type: Number,
53
+ required: false,
54
+ min: 0,
55
+ default: 0,
56
+ },
57
+
50
58
  deliveryDays: {
51
59
  type: Number,
52
60
  required: true,
@@ -100,7 +108,4 @@ const rfqResponseSchema = new mongoose.Schema({
100
108
  timestamps: true,
101
109
  });
102
110
 
103
- // Unique response per supplier per RFQ
104
- rfqResponseSchema.index({ rfqId: 1, supplierId: 1 }, { unique: true });
105
-
106
111
  module.exports = mongoose.model('RFQResponse', rfqResponseSchema);