payservedb 9.1.0 → 9.1.2
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 +401 -401
- package/package.json +17 -17
- package/src/models/InvoiceWithholdingTax.js +67 -67
- 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/auto_reply_rule.js +68 -68
- 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 +179 -179
- package/src/models/bookingreservation.js +239 -239
- 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 +290 -290
- package/src/models/combinedUnits.js +62 -62
- package/src/models/combined_invoice.js +424 -424
- 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 +35 -35
- 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 +234 -234
- package/src/models/customer_preference.js +52 -52
- package/src/models/customer_satisfaction_survey.js +297 -297
- package/src/models/customer_surveys.js +139 -139
- package/src/models/customer_tickets.js +237 -237
- 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_cc_config.js +48 -48
- package/src/models/email_sms_queue.js +61 -61
- package/src/models/email_thread.js +35 -35
- 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 +76 -76
- 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_etims_config.js +116 -116
- package/src/models/facility_payment_details.js +20 -20
- package/src/models/facility_rating.js +78 -78
- package/src/models/facilityasset.js +25 -25
- package/src/models/faq.js +15 -15
- 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 +258 -258
- package/src/models/inspection_category.js +38 -38
- package/src/models/invoice.js +528 -525
- package/src/models/invoiceCreditAdjustment.js +45 -45
- package/src/models/invoice_edit_log.js +81 -81
- package/src/models/invoice_generation_approval.js +86 -86
- package/src/models/invoicing_schedule.js +40 -40
- 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 +243 -243
- package/src/models/leasetemplate.js +17 -17
- package/src/models/levy.js +212 -212
- package/src/models/levy_invoice_settings.js +26 -26
- package/src/models/levycontract.js +215 -215
- 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/movein_application.js +29 -29
- package/src/models/movein_audit_log.js +21 -21
- package/src/models/movein_booking.js +33 -33
- package/src/models/movein_commission.js +46 -46
- package/src/models/movein_conversation.js +25 -25
- package/src/models/movein_deal.js +79 -79
- package/src/models/movein_handoff_token.js +16 -16
- package/src/models/movein_landlord.js +18 -18
- package/src/models/movein_landlord_user.js +20 -20
- package/src/models/movein_message.js +27 -27
- package/src/models/movein_notification.js +27 -27
- package/src/models/movein_otp.js +14 -14
- package/src/models/movein_payment.js +46 -46
- package/src/models/movein_reminder.js +77 -77
- package/src/models/movein_reservation.js +31 -31
- package/src/models/movein_unit.js +59 -59
- package/src/models/movein_user.js +15 -15
- package/src/models/movein_viewing_slot.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 +200 -200
- package/src/models/powerMeterSingleDayReading.js +32 -32
- package/src/models/powerMeters.js +149 -149
- package/src/models/powerMetersManufacturer.js +14 -14
- package/src/models/power_invoice.js +359 -359
- 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/quickbooks_config.js +52 -52
- package/src/models/recipient_group.js +61 -61
- package/src/models/recipient_group_member.js +62 -62
- 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 +79 -79
- 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 +130 -130
- package/src/models/user.js +186 -186
- package/src/models/valueaddedservices.js +21 -21
- package/src/models/vas_invoices_upload.js +50 -50
- package/src/models/vas_payments.js +24 -24
- package/src/models/vasinvoice.js +196 -196
- package/src/models/vasvendor.js +52 -52
- 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 +86 -86
- package/src/models/water_meter_billing.js +58 -58
- package/src/models/water_meter_combined_accounts.js +92 -92
- 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_loan_deduction.js +134 -134
- 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 +290 -290
- 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 +176 -176
- 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/whatsapp_conversation.js +23 -23
- 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
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
const mongoose = require('mongoose');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Admin-managed auto-reply rules. On every inbound email or WhatsApp
|
|
5
|
-
* message, the matcher (utils/auto_reply.js) walks enabled rules ordered by
|
|
6
|
-
* priority and fires the FIRST rule whose keyword appears in the body as a
|
|
7
|
-
* whole word (case-insensitive). Senders from @payserve.co.ke are skipped.
|
|
8
|
-
*
|
|
9
|
-
* Replaces the legacy per-agent immediate / delay UI that used to live in
|
|
10
|
-
* customer_obsession/settings/agent_settings.js (PR4).
|
|
11
|
-
*/
|
|
12
|
-
const autoReplyRuleSchema = new mongoose.Schema({
|
|
13
|
-
channel: {
|
|
14
|
-
type: String,
|
|
15
|
-
enum: ['email', 'whatsapp'],
|
|
16
|
-
required: [true, 'channel is required'],
|
|
17
|
-
index: true,
|
|
18
|
-
},
|
|
19
|
-
keyword: {
|
|
20
|
-
type: String,
|
|
21
|
-
required: [true, 'keyword is required'],
|
|
22
|
-
trim: true,
|
|
23
|
-
maxlength: 100,
|
|
24
|
-
},
|
|
25
|
-
reply: {
|
|
26
|
-
type: String,
|
|
27
|
-
required: [true, 'reply text is required'],
|
|
28
|
-
trim: true,
|
|
29
|
-
maxlength: 1000,
|
|
30
|
-
},
|
|
31
|
-
priority: {
|
|
32
|
-
type: Number,
|
|
33
|
-
default: 0,
|
|
34
|
-
index: true,
|
|
35
|
-
},
|
|
36
|
-
enabled: {
|
|
37
|
-
type: Boolean,
|
|
38
|
-
default: true,
|
|
39
|
-
},
|
|
40
|
-
created_by: {
|
|
41
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
42
|
-
ref: 'User',
|
|
43
|
-
},
|
|
44
|
-
updated_by: {
|
|
45
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
46
|
-
ref: 'User',
|
|
47
|
-
},
|
|
48
|
-
created_at: {
|
|
49
|
-
type: Date,
|
|
50
|
-
default: Date.now,
|
|
51
|
-
},
|
|
52
|
-
updated_at: {
|
|
53
|
-
type: Date,
|
|
54
|
-
default: Date.now,
|
|
55
|
-
},
|
|
56
|
-
}, {
|
|
57
|
-
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// First-match-wins semantics — duplicate (channel, keyword) makes lower-priority
|
|
61
|
-
// rules unreachable. Enforced at the DB level.
|
|
62
|
-
autoReplyRuleSchema.index({ channel: 1, keyword: 1 }, {
|
|
63
|
-
unique: true,
|
|
64
|
-
collation: { locale: 'en', strength: 2 }, // case-insensitive
|
|
65
|
-
});
|
|
66
|
-
autoReplyRuleSchema.index({ channel: 1, priority: 1 });
|
|
67
|
-
|
|
68
|
-
module.exports = mongoose.model('AutoReplyRule', autoReplyRuleSchema);
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Admin-managed auto-reply rules. On every inbound email or WhatsApp
|
|
5
|
+
* message, the matcher (utils/auto_reply.js) walks enabled rules ordered by
|
|
6
|
+
* priority and fires the FIRST rule whose keyword appears in the body as a
|
|
7
|
+
* whole word (case-insensitive). Senders from @payserve.co.ke are skipped.
|
|
8
|
+
*
|
|
9
|
+
* Replaces the legacy per-agent immediate / delay UI that used to live in
|
|
10
|
+
* customer_obsession/settings/agent_settings.js (PR4).
|
|
11
|
+
*/
|
|
12
|
+
const autoReplyRuleSchema = new mongoose.Schema({
|
|
13
|
+
channel: {
|
|
14
|
+
type: String,
|
|
15
|
+
enum: ['email', 'whatsapp'],
|
|
16
|
+
required: [true, 'channel is required'],
|
|
17
|
+
index: true,
|
|
18
|
+
},
|
|
19
|
+
keyword: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: [true, 'keyword is required'],
|
|
22
|
+
trim: true,
|
|
23
|
+
maxlength: 100,
|
|
24
|
+
},
|
|
25
|
+
reply: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: [true, 'reply text is required'],
|
|
28
|
+
trim: true,
|
|
29
|
+
maxlength: 1000,
|
|
30
|
+
},
|
|
31
|
+
priority: {
|
|
32
|
+
type: Number,
|
|
33
|
+
default: 0,
|
|
34
|
+
index: true,
|
|
35
|
+
},
|
|
36
|
+
enabled: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: true,
|
|
39
|
+
},
|
|
40
|
+
created_by: {
|
|
41
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
42
|
+
ref: 'User',
|
|
43
|
+
},
|
|
44
|
+
updated_by: {
|
|
45
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
46
|
+
ref: 'User',
|
|
47
|
+
},
|
|
48
|
+
created_at: {
|
|
49
|
+
type: Date,
|
|
50
|
+
default: Date.now,
|
|
51
|
+
},
|
|
52
|
+
updated_at: {
|
|
53
|
+
type: Date,
|
|
54
|
+
default: Date.now,
|
|
55
|
+
},
|
|
56
|
+
}, {
|
|
57
|
+
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// First-match-wins semantics — duplicate (channel, keyword) makes lower-priority
|
|
61
|
+
// rules unreachable. Enforced at the DB level.
|
|
62
|
+
autoReplyRuleSchema.index({ channel: 1, keyword: 1 }, {
|
|
63
|
+
unique: true,
|
|
64
|
+
collation: { locale: 'en', strength: 2 }, // case-insensitive
|
|
65
|
+
});
|
|
66
|
+
autoReplyRuleSchema.index({ channel: 1, priority: 1 });
|
|
67
|
+
|
|
68
|
+
module.exports = mongoose.model('AutoReplyRule', autoReplyRuleSchema);
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
const mongoose = require('mongoose');
|
|
2
|
-
|
|
3
|
-
const BankDetailsSchema = new mongoose.Schema({
|
|
4
|
-
accountName: {
|
|
5
|
-
type: String,
|
|
6
|
-
required: true
|
|
7
|
-
},
|
|
8
|
-
accountNumber: {
|
|
9
|
-
type: String,
|
|
10
|
-
required: true,
|
|
11
|
-
},
|
|
12
|
-
bankName: {
|
|
13
|
-
type: String,
|
|
14
|
-
required: true,
|
|
15
|
-
},
|
|
16
|
-
branchName: {
|
|
17
|
-
type: String,
|
|
18
|
-
required: true,
|
|
19
|
-
},
|
|
20
|
-
branchCode: {
|
|
21
|
-
type: String,
|
|
22
|
-
required: false,
|
|
23
|
-
},
|
|
24
|
-
bankCode: {
|
|
25
|
-
type: String,
|
|
26
|
-
required: false,
|
|
27
|
-
},
|
|
28
|
-
swiftCode: {
|
|
29
|
-
type: String,
|
|
30
|
-
required: false,
|
|
31
|
-
},
|
|
32
|
-
bankPaybill: {
|
|
33
|
-
type: String,
|
|
34
|
-
required: false,
|
|
35
|
-
},
|
|
36
|
-
isDefault: {
|
|
37
|
-
type: Boolean,
|
|
38
|
-
default: false
|
|
39
|
-
},
|
|
40
|
-
facilityId: {
|
|
41
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
42
|
-
ref: 'Facility'
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const BankDetails = mongoose.model('BankDetails', BankDetailsSchema);
|
|
47
|
-
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const BankDetailsSchema = new mongoose.Schema({
|
|
4
|
+
accountName: {
|
|
5
|
+
type: String,
|
|
6
|
+
required: true
|
|
7
|
+
},
|
|
8
|
+
accountNumber: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: true,
|
|
11
|
+
},
|
|
12
|
+
bankName: {
|
|
13
|
+
type: String,
|
|
14
|
+
required: true,
|
|
15
|
+
},
|
|
16
|
+
branchName: {
|
|
17
|
+
type: String,
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
branchCode: {
|
|
21
|
+
type: String,
|
|
22
|
+
required: false,
|
|
23
|
+
},
|
|
24
|
+
bankCode: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: false,
|
|
27
|
+
},
|
|
28
|
+
swiftCode: {
|
|
29
|
+
type: String,
|
|
30
|
+
required: false,
|
|
31
|
+
},
|
|
32
|
+
bankPaybill: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: false,
|
|
35
|
+
},
|
|
36
|
+
isDefault: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: false
|
|
39
|
+
},
|
|
40
|
+
facilityId: {
|
|
41
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
42
|
+
ref: 'Facility'
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const BankDetails = mongoose.model('BankDetails', BankDetailsSchema);
|
|
47
|
+
|
|
48
48
|
module.exports = BankDetails;
|
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
const mongoose = require("mongoose");
|
|
2
|
-
|
|
3
|
-
// Define the schema for Biller Address
|
|
4
|
-
const billerAddressSchema = new mongoose.Schema(
|
|
5
|
-
{
|
|
6
|
-
name: {
|
|
7
|
-
type: String,
|
|
8
|
-
required: [true, "Address name is required"],
|
|
9
|
-
trim: true,
|
|
10
|
-
minlength: [1, "Address name must be at least 1 character long"],
|
|
11
|
-
},
|
|
12
|
-
companyName: {
|
|
13
|
-
type: String,
|
|
14
|
-
required: [true, "Company name is required"],
|
|
15
|
-
trim: true,
|
|
16
|
-
},
|
|
17
|
-
website: {
|
|
18
|
-
type: String,
|
|
19
|
-
trim: true,
|
|
20
|
-
validate: {
|
|
21
|
-
validator: function (v) {
|
|
22
|
-
// If website is empty or null, it's valid (optional field)
|
|
23
|
-
if (!v || v.trim() === '') return true;
|
|
24
|
-
|
|
25
|
-
// Updated regex pattern that's more flexible for various URL formats
|
|
26
|
-
return /^(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%.\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%\+.~#?&//=]*)$/.test(v);
|
|
27
|
-
},
|
|
28
|
-
message: "Please enter a valid website URL (e.g., https://example.com, www.example.com, or example.com)"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
email: {
|
|
32
|
-
type: String,
|
|
33
|
-
required: [true, "Email is required"],
|
|
34
|
-
trim: true,
|
|
35
|
-
lowercase: true,
|
|
36
|
-
validate: {
|
|
37
|
-
validator: function (v) {
|
|
38
|
-
return /^\w+([\.-]?\w+)@\w+([\.-]?\w+)(\.\w{2,3})+$/.test(v);
|
|
39
|
-
},
|
|
40
|
-
message: "Please enter a valid email address"
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
phone: {
|
|
44
|
-
type: String,
|
|
45
|
-
trim: true,
|
|
46
|
-
},
|
|
47
|
-
address: {
|
|
48
|
-
type: String,
|
|
49
|
-
required: [true, "Address is required"],
|
|
50
|
-
trim: true,
|
|
51
|
-
},
|
|
52
|
-
city: {
|
|
53
|
-
type: String,
|
|
54
|
-
required: [true, "City is required"],
|
|
55
|
-
trim: true,
|
|
56
|
-
},
|
|
57
|
-
state: {
|
|
58
|
-
type: String,
|
|
59
|
-
trim: true,
|
|
60
|
-
},
|
|
61
|
-
country: {
|
|
62
|
-
type: String,
|
|
63
|
-
required: [true, "Country is required"],
|
|
64
|
-
trim: true,
|
|
65
|
-
default: "Kenya"
|
|
66
|
-
},
|
|
67
|
-
postalCode: {
|
|
68
|
-
type: String,
|
|
69
|
-
trim: true,
|
|
70
|
-
},
|
|
71
|
-
logo: {
|
|
72
|
-
type: String, // Will store the file path/URL of the uploaded logo
|
|
73
|
-
required: false,
|
|
74
|
-
},
|
|
75
|
-
digitalSignature: {
|
|
76
|
-
type: String, // Will store the file path/URL of the uploaded digital signature
|
|
77
|
-
required: false,
|
|
78
|
-
},
|
|
79
|
-
isDefault: {
|
|
80
|
-
type: Boolean,
|
|
81
|
-
default: false,
|
|
82
|
-
},
|
|
83
|
-
facilityId: {
|
|
84
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
85
|
-
ref: "Facility",
|
|
86
|
-
required: true,
|
|
87
|
-
},
|
|
88
|
-
createdBy: {
|
|
89
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
90
|
-
ref: "User",
|
|
91
|
-
},
|
|
92
|
-
updatedBy: {
|
|
93
|
-
type: mongoose.Schema.Types.ObjectId,
|
|
94
|
-
ref: "User",
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
timestamps: true,
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
// Index for efficient queries
|
|
103
|
-
billerAddressSchema.index({ facilityId: 1 });
|
|
104
|
-
billerAddressSchema.index({ facilityId: 1, isDefault: 1 });
|
|
105
|
-
|
|
106
|
-
// Pre-save middleware to ensure only one default address per facility
|
|
107
|
-
billerAddressSchema.pre('save', async function (next) {
|
|
108
|
-
if (this.isDefault && this.isModified('isDefault')) {
|
|
109
|
-
// If this address is being set as default, unset all other defaults for this facility
|
|
110
|
-
await this.constructor.updateMany(
|
|
111
|
-
{
|
|
112
|
-
facilityId: this.facilityId,
|
|
113
|
-
_id: { $ne: this._id }
|
|
114
|
-
},
|
|
115
|
-
{ $set: { isDefault: false } }
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
next();
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// Compile the model from the schema
|
|
122
|
-
const BillerAddress = mongoose.model("BillerAddress", billerAddressSchema);
|
|
123
|
-
|
|
124
|
-
module.exports = BillerAddress;
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
|
|
3
|
+
// Define the schema for Biller Address
|
|
4
|
+
const billerAddressSchema = new mongoose.Schema(
|
|
5
|
+
{
|
|
6
|
+
name: {
|
|
7
|
+
type: String,
|
|
8
|
+
required: [true, "Address name is required"],
|
|
9
|
+
trim: true,
|
|
10
|
+
minlength: [1, "Address name must be at least 1 character long"],
|
|
11
|
+
},
|
|
12
|
+
companyName: {
|
|
13
|
+
type: String,
|
|
14
|
+
required: [true, "Company name is required"],
|
|
15
|
+
trim: true,
|
|
16
|
+
},
|
|
17
|
+
website: {
|
|
18
|
+
type: String,
|
|
19
|
+
trim: true,
|
|
20
|
+
validate: {
|
|
21
|
+
validator: function (v) {
|
|
22
|
+
// If website is empty or null, it's valid (optional field)
|
|
23
|
+
if (!v || v.trim() === '') return true;
|
|
24
|
+
|
|
25
|
+
// Updated regex pattern that's more flexible for various URL formats
|
|
26
|
+
return /^(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%.\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%\+.~#?&//=]*)$/.test(v);
|
|
27
|
+
},
|
|
28
|
+
message: "Please enter a valid website URL (e.g., https://example.com, www.example.com, or example.com)"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
email: {
|
|
32
|
+
type: String,
|
|
33
|
+
required: [true, "Email is required"],
|
|
34
|
+
trim: true,
|
|
35
|
+
lowercase: true,
|
|
36
|
+
validate: {
|
|
37
|
+
validator: function (v) {
|
|
38
|
+
return /^\w+([\.-]?\w+)@\w+([\.-]?\w+)(\.\w{2,3})+$/.test(v);
|
|
39
|
+
},
|
|
40
|
+
message: "Please enter a valid email address"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
phone: {
|
|
44
|
+
type: String,
|
|
45
|
+
trim: true,
|
|
46
|
+
},
|
|
47
|
+
address: {
|
|
48
|
+
type: String,
|
|
49
|
+
required: [true, "Address is required"],
|
|
50
|
+
trim: true,
|
|
51
|
+
},
|
|
52
|
+
city: {
|
|
53
|
+
type: String,
|
|
54
|
+
required: [true, "City is required"],
|
|
55
|
+
trim: true,
|
|
56
|
+
},
|
|
57
|
+
state: {
|
|
58
|
+
type: String,
|
|
59
|
+
trim: true,
|
|
60
|
+
},
|
|
61
|
+
country: {
|
|
62
|
+
type: String,
|
|
63
|
+
required: [true, "Country is required"],
|
|
64
|
+
trim: true,
|
|
65
|
+
default: "Kenya"
|
|
66
|
+
},
|
|
67
|
+
postalCode: {
|
|
68
|
+
type: String,
|
|
69
|
+
trim: true,
|
|
70
|
+
},
|
|
71
|
+
logo: {
|
|
72
|
+
type: String, // Will store the file path/URL of the uploaded logo
|
|
73
|
+
required: false,
|
|
74
|
+
},
|
|
75
|
+
digitalSignature: {
|
|
76
|
+
type: String, // Will store the file path/URL of the uploaded digital signature
|
|
77
|
+
required: false,
|
|
78
|
+
},
|
|
79
|
+
isDefault: {
|
|
80
|
+
type: Boolean,
|
|
81
|
+
default: false,
|
|
82
|
+
},
|
|
83
|
+
facilityId: {
|
|
84
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
85
|
+
ref: "Facility",
|
|
86
|
+
required: true,
|
|
87
|
+
},
|
|
88
|
+
createdBy: {
|
|
89
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
90
|
+
ref: "User",
|
|
91
|
+
},
|
|
92
|
+
updatedBy: {
|
|
93
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
94
|
+
ref: "User",
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
timestamps: true,
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Index for efficient queries
|
|
103
|
+
billerAddressSchema.index({ facilityId: 1 });
|
|
104
|
+
billerAddressSchema.index({ facilityId: 1, isDefault: 1 });
|
|
105
|
+
|
|
106
|
+
// Pre-save middleware to ensure only one default address per facility
|
|
107
|
+
billerAddressSchema.pre('save', async function (next) {
|
|
108
|
+
if (this.isDefault && this.isModified('isDefault')) {
|
|
109
|
+
// If this address is being set as default, unset all other defaults for this facility
|
|
110
|
+
await this.constructor.updateMany(
|
|
111
|
+
{
|
|
112
|
+
facilityId: this.facilityId,
|
|
113
|
+
_id: { $ne: this._id }
|
|
114
|
+
},
|
|
115
|
+
{ $set: { isDefault: false } }
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
next();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Compile the model from the schema
|
|
122
|
+
const BillerAddress = mongoose.model("BillerAddress", billerAddressSchema);
|
|
123
|
+
|
|
124
|
+
module.exports = BillerAddress;
|