payservedb 8.4.6 → 8.4.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.
- package/.env +2 -2
- package/ZOHO_INTEGRATION_SCHEMA.md +644 -644
- package/index.js +312 -312
- 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 -47
- package/src/models/billerAddress.js +124 -124
- package/src/models/booking_invoice.js +165 -165
- package/src/models/bookinganalytics.js +63 -63
- package/src/models/bookingconfig.js +45 -45
- package/src/models/bookingproperty.js +173 -173
- package/src/models/bookingreservation.js +209 -209
- 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/community_guidelines.js +24 -24
- 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 +71 -71
- package/src/models/facilityBillingPrices.js +29 -29
- package/src/models/facilityInvoice.js +240 -240
- package/src/models/facilityInvoicePayment.js +52 -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 +14 -14
- 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 +480 -480
- package/src/models/invoicing_schedule.js +41 -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 -236
- 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 -177
- 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/privacy_policy.js +19 -19
- 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/terms_and_conditions.js +19 -19
- package/src/models/tickets.js +186 -186
- 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 +87 -87
- 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 +287 -287
- 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/zohoAccount.js +453 -453
- package/src/models/zohoIntegration.js +262 -262
- package/src/models/zohoItem.js +504 -504
package/src/models/handover.js
CHANGED
|
@@ -1,248 +1,248 @@
|
|
|
1
|
-
const mongoose = require('mongoose');
|
|
2
|
-
|
|
3
|
-
const handoverItemSchema = new mongoose.Schema({
|
|
4
|
-
name: {
|
|
5
|
-
type: String,
|
|
6
|
-
required: true,
|
|
7
|
-
trim: true
|
|
8
|
-
},
|
|
9
|
-
category: {
|
|
10
|
-
type: String,
|
|
11
|
-
required: true,
|
|
12
|
-
trim: true,
|
|
13
|
-
enum: ['Furniture', 'Appliance', 'Electronics', 'Fixture', 'Utility', 'Other']
|
|
14
|
-
},
|
|
15
|
-
description: {
|
|
16
|
-
type: String,
|
|
17
|
-
trim: true
|
|
18
|
-
},
|
|
19
|
-
condition: {
|
|
20
|
-
type: String,
|
|
21
|
-
required: true,
|
|
22
|
-
enum: ['Excellent', 'Good', 'Fair', 'Poor', 'Damaged', 'Non-functional']
|
|
23
|
-
},
|
|
24
|
-
quantity: {
|
|
25
|
-
type: Number,
|
|
26
|
-
required: true,
|
|
27
|
-
default: 1,
|
|
28
|
-
min: [1, 'Quantity must be at least 1']
|
|
29
|
-
},
|
|
30
|
-
serialNumber: {
|
|
31
|
-
type: String,
|
|
32
|
-
trim: true
|
|
33
|
-
},
|
|
34
|
-
images: [{
|
|
35
|
-
type: String, // URLs to stored images
|
|
36
|
-
trim: true
|
|
37
|
-
}],
|
|
38
|
-
notes: {
|
|
39
|
-
type: String,
|
|
40
|
-
trim: true
|
|
41
|
-
}
|
|
42
|
-
}, { _id: true });
|
|
43
|
-
|
|
44
|
-
// Define the main Handover schema
|
|
45
|
-
const handoverSchema = new mongoose.Schema({
|
|
46
|
-
// References
|
|
47
|
-
facilityId: {
|
|
48
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
49
|
-
ref: 'Facility',
|
|
50
|
-
required: true
|
|
51
|
-
},
|
|
52
|
-
unitId: {
|
|
53
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
54
|
-
ref: 'Unit',
|
|
55
|
-
required: true
|
|
56
|
-
},
|
|
57
|
-
// IMPORTANT: For Customer, we don't specify 'ref' since it's in a different database
|
|
58
|
-
// This avoids the cross-database population errors
|
|
59
|
-
customerId: {
|
|
60
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
61
|
-
required: true
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
// Handover details
|
|
65
|
-
handoverType: {
|
|
66
|
-
type: String,
|
|
67
|
-
required: true,
|
|
68
|
-
enum: ['MoveIn', 'MoveOut'],
|
|
69
|
-
trim: true
|
|
70
|
-
},
|
|
71
|
-
handoverDate: {
|
|
72
|
-
type: Date,
|
|
73
|
-
required: true,
|
|
74
|
-
default: Date.now
|
|
75
|
-
},
|
|
76
|
-
status: {
|
|
77
|
-
type: String,
|
|
78
|
-
required: true,
|
|
79
|
-
enum: ['Draft', 'Completed', 'Disputed', 'Resolved'],
|
|
80
|
-
default: 'Draft'
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
// If this is a move-out handover, reference the original move-in handover
|
|
84
|
-
relatedHandoverId: {
|
|
85
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
86
|
-
ref: 'Handover',
|
|
87
|
-
default: null // Only populated for move-out handovers
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
// Items included in the handover
|
|
91
|
-
items: [handoverItemSchema],
|
|
92
|
-
|
|
93
|
-
// Additional information
|
|
94
|
-
meterReadings: {
|
|
95
|
-
electricity: {
|
|
96
|
-
reading: Number,
|
|
97
|
-
imageUrl: String
|
|
98
|
-
},
|
|
99
|
-
water: {
|
|
100
|
-
reading: Number,
|
|
101
|
-
imageUrl: String
|
|
102
|
-
},
|
|
103
|
-
gas: {
|
|
104
|
-
reading: Number,
|
|
105
|
-
imageUrl: String
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
// Key handover confirmation
|
|
110
|
-
keysHandedOver: {
|
|
111
|
-
type: Number,
|
|
112
|
-
default: 0,
|
|
113
|
-
min: 0
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
// Security deposit info (for move-out)
|
|
117
|
-
securityDeposit: {
|
|
118
|
-
amount: {
|
|
119
|
-
type: Number,
|
|
120
|
-
default: 0
|
|
121
|
-
},
|
|
122
|
-
deductions: [{
|
|
123
|
-
reason: {
|
|
124
|
-
type: String,
|
|
125
|
-
trim: true
|
|
126
|
-
},
|
|
127
|
-
amount: {
|
|
128
|
-
type: Number,
|
|
129
|
-
min: 0
|
|
130
|
-
},
|
|
131
|
-
description: String,
|
|
132
|
-
invoiceId: {
|
|
133
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
134
|
-
ref: 'Invoice',
|
|
135
|
-
default: null
|
|
136
|
-
}
|
|
137
|
-
}],
|
|
138
|
-
refundAmount: {
|
|
139
|
-
type: Number,
|
|
140
|
-
default: 0
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
// Signature and agreement info
|
|
145
|
-
signatures: {
|
|
146
|
-
propertyManager: {
|
|
147
|
-
signature: String, // URL to stored signature image or digital signature data
|
|
148
|
-
date: Date
|
|
149
|
-
},
|
|
150
|
-
customer: {
|
|
151
|
-
signature: String, // URL to stored signature image or digital signature data
|
|
152
|
-
date: Date,
|
|
153
|
-
agreement: {
|
|
154
|
-
type: Boolean,
|
|
155
|
-
default: false
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
// General notes
|
|
161
|
-
notes: {
|
|
162
|
-
type: String,
|
|
163
|
-
trim: true
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
// Any attached documents
|
|
167
|
-
attachments: [{
|
|
168
|
-
name: String, // Custom descriptive name (e.g., "Chair Image 23")
|
|
169
|
-
fileName: String, // Original file name
|
|
170
|
-
fileUrl: String,
|
|
171
|
-
uploadDate: {
|
|
172
|
-
type: Date,
|
|
173
|
-
default: Date.now
|
|
174
|
-
}
|
|
175
|
-
}]
|
|
176
|
-
}, {
|
|
177
|
-
timestamps: true,
|
|
178
|
-
toJSON: { virtuals: true }, // Enable virtuals when converting to JSON
|
|
179
|
-
toObject: { virtuals: true } // Enable virtuals when converting to object
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// Add indexes for common queries
|
|
183
|
-
handoverSchema.index({ facilityId: 1, unitId: 1, handoverType: 1 });
|
|
184
|
-
handoverSchema.index({ customerId: 1, handoverType: 1 });
|
|
185
|
-
handoverSchema.index({ handoverDate: -1 });
|
|
186
|
-
|
|
187
|
-
// Virtual for calculating total deductions
|
|
188
|
-
handoverSchema.virtual('totalDeductions').get(function() {
|
|
189
|
-
if (!this.securityDeposit.deductions || this.securityDeposit.deductions.length === 0) {
|
|
190
|
-
return 0;
|
|
191
|
-
}
|
|
192
|
-
return this.securityDeposit.deductions.reduce((total, deduction) => total + (deduction.amount || 0), 0);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Add method to compare move-in and move-out states
|
|
196
|
-
handoverSchema.methods.compareWithMoveIn = async function() {
|
|
197
|
-
if (this.handoverType !== 'MoveOut' || !this.relatedHandoverId) {
|
|
198
|
-
throw new Error('This method can only be called on a move-out handover with a related move-in handover');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Find the related move-in handover
|
|
202
|
-
const MoveInHandover = mongoose.model('Handover');
|
|
203
|
-
const moveInHandover = await MoveInHandover.findById(this.relatedHandoverId);
|
|
204
|
-
|
|
205
|
-
if (!moveInHandover) {
|
|
206
|
-
throw new Error('Related move-in handover not found');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Compare items and return differences
|
|
210
|
-
const differences = {
|
|
211
|
-
missing: [],
|
|
212
|
-
damaged: [],
|
|
213
|
-
changed: []
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// Check for missing or damaged items
|
|
217
|
-
moveInHandover.items.forEach(moveInItem => {
|
|
218
|
-
const moveOutItem = this.items.find(item =>
|
|
219
|
-
item.name === moveInItem.name &&
|
|
220
|
-
item.category === moveInItem.category
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
if (!moveOutItem) {
|
|
224
|
-
differences.missing.push(moveInItem);
|
|
225
|
-
} else if (moveOutItem.condition !== moveInItem.condition) {
|
|
226
|
-
if (['Poor', 'Damaged', 'Non-functional'].includes(moveOutItem.condition)) {
|
|
227
|
-
differences.damaged.push({
|
|
228
|
-
item: moveOutItem,
|
|
229
|
-
originalCondition: moveInItem.condition,
|
|
230
|
-
currentCondition: moveOutItem.condition
|
|
231
|
-
});
|
|
232
|
-
} else {
|
|
233
|
-
differences.changed.push({
|
|
234
|
-
item: moveOutItem,
|
|
235
|
-
originalCondition: moveInItem.condition,
|
|
236
|
-
currentCondition: moveOutItem.condition
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
return differences;
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// Create and export the model with the standard pattern
|
|
246
|
-
const Handover = mongoose.model('Handover', handoverSchema);
|
|
247
|
-
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const handoverItemSchema = new mongoose.Schema({
|
|
4
|
+
name: {
|
|
5
|
+
type: String,
|
|
6
|
+
required: true,
|
|
7
|
+
trim: true
|
|
8
|
+
},
|
|
9
|
+
category: {
|
|
10
|
+
type: String,
|
|
11
|
+
required: true,
|
|
12
|
+
trim: true,
|
|
13
|
+
enum: ['Furniture', 'Appliance', 'Electronics', 'Fixture', 'Utility', 'Other']
|
|
14
|
+
},
|
|
15
|
+
description: {
|
|
16
|
+
type: String,
|
|
17
|
+
trim: true
|
|
18
|
+
},
|
|
19
|
+
condition: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: true,
|
|
22
|
+
enum: ['Excellent', 'Good', 'Fair', 'Poor', 'Damaged', 'Non-functional']
|
|
23
|
+
},
|
|
24
|
+
quantity: {
|
|
25
|
+
type: Number,
|
|
26
|
+
required: true,
|
|
27
|
+
default: 1,
|
|
28
|
+
min: [1, 'Quantity must be at least 1']
|
|
29
|
+
},
|
|
30
|
+
serialNumber: {
|
|
31
|
+
type: String,
|
|
32
|
+
trim: true
|
|
33
|
+
},
|
|
34
|
+
images: [{
|
|
35
|
+
type: String, // URLs to stored images
|
|
36
|
+
trim: true
|
|
37
|
+
}],
|
|
38
|
+
notes: {
|
|
39
|
+
type: String,
|
|
40
|
+
trim: true
|
|
41
|
+
}
|
|
42
|
+
}, { _id: true });
|
|
43
|
+
|
|
44
|
+
// Define the main Handover schema
|
|
45
|
+
const handoverSchema = new mongoose.Schema({
|
|
46
|
+
// References
|
|
47
|
+
facilityId: {
|
|
48
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
49
|
+
ref: 'Facility',
|
|
50
|
+
required: true
|
|
51
|
+
},
|
|
52
|
+
unitId: {
|
|
53
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
54
|
+
ref: 'Unit',
|
|
55
|
+
required: true
|
|
56
|
+
},
|
|
57
|
+
// IMPORTANT: For Customer, we don't specify 'ref' since it's in a different database
|
|
58
|
+
// This avoids the cross-database population errors
|
|
59
|
+
customerId: {
|
|
60
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
61
|
+
required: true
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// Handover details
|
|
65
|
+
handoverType: {
|
|
66
|
+
type: String,
|
|
67
|
+
required: true,
|
|
68
|
+
enum: ['MoveIn', 'MoveOut'],
|
|
69
|
+
trim: true
|
|
70
|
+
},
|
|
71
|
+
handoverDate: {
|
|
72
|
+
type: Date,
|
|
73
|
+
required: true,
|
|
74
|
+
default: Date.now
|
|
75
|
+
},
|
|
76
|
+
status: {
|
|
77
|
+
type: String,
|
|
78
|
+
required: true,
|
|
79
|
+
enum: ['Draft', 'Completed', 'Disputed', 'Resolved'],
|
|
80
|
+
default: 'Draft'
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// If this is a move-out handover, reference the original move-in handover
|
|
84
|
+
relatedHandoverId: {
|
|
85
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
86
|
+
ref: 'Handover',
|
|
87
|
+
default: null // Only populated for move-out handovers
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Items included in the handover
|
|
91
|
+
items: [handoverItemSchema],
|
|
92
|
+
|
|
93
|
+
// Additional information
|
|
94
|
+
meterReadings: {
|
|
95
|
+
electricity: {
|
|
96
|
+
reading: Number,
|
|
97
|
+
imageUrl: String
|
|
98
|
+
},
|
|
99
|
+
water: {
|
|
100
|
+
reading: Number,
|
|
101
|
+
imageUrl: String
|
|
102
|
+
},
|
|
103
|
+
gas: {
|
|
104
|
+
reading: Number,
|
|
105
|
+
imageUrl: String
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// Key handover confirmation
|
|
110
|
+
keysHandedOver: {
|
|
111
|
+
type: Number,
|
|
112
|
+
default: 0,
|
|
113
|
+
min: 0
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// Security deposit info (for move-out)
|
|
117
|
+
securityDeposit: {
|
|
118
|
+
amount: {
|
|
119
|
+
type: Number,
|
|
120
|
+
default: 0
|
|
121
|
+
},
|
|
122
|
+
deductions: [{
|
|
123
|
+
reason: {
|
|
124
|
+
type: String,
|
|
125
|
+
trim: true
|
|
126
|
+
},
|
|
127
|
+
amount: {
|
|
128
|
+
type: Number,
|
|
129
|
+
min: 0
|
|
130
|
+
},
|
|
131
|
+
description: String,
|
|
132
|
+
invoiceId: {
|
|
133
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
134
|
+
ref: 'Invoice',
|
|
135
|
+
default: null
|
|
136
|
+
}
|
|
137
|
+
}],
|
|
138
|
+
refundAmount: {
|
|
139
|
+
type: Number,
|
|
140
|
+
default: 0
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
// Signature and agreement info
|
|
145
|
+
signatures: {
|
|
146
|
+
propertyManager: {
|
|
147
|
+
signature: String, // URL to stored signature image or digital signature data
|
|
148
|
+
date: Date
|
|
149
|
+
},
|
|
150
|
+
customer: {
|
|
151
|
+
signature: String, // URL to stored signature image or digital signature data
|
|
152
|
+
date: Date,
|
|
153
|
+
agreement: {
|
|
154
|
+
type: Boolean,
|
|
155
|
+
default: false
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// General notes
|
|
161
|
+
notes: {
|
|
162
|
+
type: String,
|
|
163
|
+
trim: true
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// Any attached documents
|
|
167
|
+
attachments: [{
|
|
168
|
+
name: String, // Custom descriptive name (e.g., "Chair Image 23")
|
|
169
|
+
fileName: String, // Original file name
|
|
170
|
+
fileUrl: String,
|
|
171
|
+
uploadDate: {
|
|
172
|
+
type: Date,
|
|
173
|
+
default: Date.now
|
|
174
|
+
}
|
|
175
|
+
}]
|
|
176
|
+
}, {
|
|
177
|
+
timestamps: true,
|
|
178
|
+
toJSON: { virtuals: true }, // Enable virtuals when converting to JSON
|
|
179
|
+
toObject: { virtuals: true } // Enable virtuals when converting to object
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Add indexes for common queries
|
|
183
|
+
handoverSchema.index({ facilityId: 1, unitId: 1, handoverType: 1 });
|
|
184
|
+
handoverSchema.index({ customerId: 1, handoverType: 1 });
|
|
185
|
+
handoverSchema.index({ handoverDate: -1 });
|
|
186
|
+
|
|
187
|
+
// Virtual for calculating total deductions
|
|
188
|
+
handoverSchema.virtual('totalDeductions').get(function() {
|
|
189
|
+
if (!this.securityDeposit.deductions || this.securityDeposit.deductions.length === 0) {
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
return this.securityDeposit.deductions.reduce((total, deduction) => total + (deduction.amount || 0), 0);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Add method to compare move-in and move-out states
|
|
196
|
+
handoverSchema.methods.compareWithMoveIn = async function() {
|
|
197
|
+
if (this.handoverType !== 'MoveOut' || !this.relatedHandoverId) {
|
|
198
|
+
throw new Error('This method can only be called on a move-out handover with a related move-in handover');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Find the related move-in handover
|
|
202
|
+
const MoveInHandover = mongoose.model('Handover');
|
|
203
|
+
const moveInHandover = await MoveInHandover.findById(this.relatedHandoverId);
|
|
204
|
+
|
|
205
|
+
if (!moveInHandover) {
|
|
206
|
+
throw new Error('Related move-in handover not found');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Compare items and return differences
|
|
210
|
+
const differences = {
|
|
211
|
+
missing: [],
|
|
212
|
+
damaged: [],
|
|
213
|
+
changed: []
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Check for missing or damaged items
|
|
217
|
+
moveInHandover.items.forEach(moveInItem => {
|
|
218
|
+
const moveOutItem = this.items.find(item =>
|
|
219
|
+
item.name === moveInItem.name &&
|
|
220
|
+
item.category === moveInItem.category
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (!moveOutItem) {
|
|
224
|
+
differences.missing.push(moveInItem);
|
|
225
|
+
} else if (moveOutItem.condition !== moveInItem.condition) {
|
|
226
|
+
if (['Poor', 'Damaged', 'Non-functional'].includes(moveOutItem.condition)) {
|
|
227
|
+
differences.damaged.push({
|
|
228
|
+
item: moveOutItem,
|
|
229
|
+
originalCondition: moveInItem.condition,
|
|
230
|
+
currentCondition: moveOutItem.condition
|
|
231
|
+
});
|
|
232
|
+
} else {
|
|
233
|
+
differences.changed.push({
|
|
234
|
+
item: moveOutItem,
|
|
235
|
+
originalCondition: moveInItem.condition,
|
|
236
|
+
currentCondition: moveOutItem.condition
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return differences;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Create and export the model with the standard pattern
|
|
246
|
+
const Handover = mongoose.model('Handover', handoverSchema);
|
|
247
|
+
|
|
248
248
|
module.exports = Handover;
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
const mongoose = require('mongoose');
|
|
2
|
-
|
|
3
|
-
// Define the schema for inspection categories
|
|
4
|
-
const inspectionCategorySchema = new mongoose.Schema({
|
|
5
|
-
name: {
|
|
6
|
-
type: String,
|
|
7
|
-
required: [true, 'Category name is required'],
|
|
8
|
-
trim: true,
|
|
9
|
-
unique: false // Unique per facility, not globally
|
|
10
|
-
},
|
|
11
|
-
description: {
|
|
12
|
-
type: String,
|
|
13
|
-
trim: true,
|
|
14
|
-
default: ''
|
|
15
|
-
},
|
|
16
|
-
active: {
|
|
17
|
-
type: Boolean,
|
|
18
|
-
default: true
|
|
19
|
-
},
|
|
20
|
-
facilityId: {
|
|
21
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
22
|
-
ref: 'Facility',
|
|
23
|
-
required: true
|
|
24
|
-
}
|
|
25
|
-
}, {
|
|
26
|
-
timestamps: true
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Add compound index to ensure unique category names per facility
|
|
30
|
-
inspectionCategorySchema.index({ facilityId: 1, name: 1 }, { unique: true });
|
|
31
|
-
|
|
32
|
-
// Add index for common queries
|
|
33
|
-
inspectionCategorySchema.index({ facilityId: 1 });
|
|
34
|
-
|
|
35
|
-
// Create InspectionCategory model
|
|
36
|
-
const InspectionCategory = mongoose.model('InspectionCategory', inspectionCategorySchema);
|
|
37
|
-
|
|
38
|
-
module.exports = InspectionCategory;
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
// Define the schema for inspection categories
|
|
4
|
+
const inspectionCategorySchema = new mongoose.Schema({
|
|
5
|
+
name: {
|
|
6
|
+
type: String,
|
|
7
|
+
required: [true, 'Category name is required'],
|
|
8
|
+
trim: true,
|
|
9
|
+
unique: false // Unique per facility, not globally
|
|
10
|
+
},
|
|
11
|
+
description: {
|
|
12
|
+
type: String,
|
|
13
|
+
trim: true,
|
|
14
|
+
default: ''
|
|
15
|
+
},
|
|
16
|
+
active: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: true
|
|
19
|
+
},
|
|
20
|
+
facilityId: {
|
|
21
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
22
|
+
ref: 'Facility',
|
|
23
|
+
required: true
|
|
24
|
+
}
|
|
25
|
+
}, {
|
|
26
|
+
timestamps: true
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Add compound index to ensure unique category names per facility
|
|
30
|
+
inspectionCategorySchema.index({ facilityId: 1, name: 1 }, { unique: true });
|
|
31
|
+
|
|
32
|
+
// Add index for common queries
|
|
33
|
+
inspectionCategorySchema.index({ facilityId: 1 });
|
|
34
|
+
|
|
35
|
+
// Create InspectionCategory model
|
|
36
|
+
const InspectionCategory = mongoose.model('InspectionCategory', inspectionCategorySchema);
|
|
37
|
+
|
|
38
|
+
module.exports = InspectionCategory;
|