payservedb 8.3.7 → 8.3.9

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.
Files changed (179) hide show
  1. package/.env +2 -2
  2. package/ZOHO_INTEGRATION_SCHEMA.md +644 -0
  3. package/index.js +307 -306
  4. package/package.json +17 -17
  5. package/src/models/account.js +52 -52
  6. package/src/models/agent_departments.js +59 -59
  7. package/src/models/agent_notifications.js +53 -53
  8. package/src/models/agent_performance.js +127 -127
  9. package/src/models/agent_roles.js +77 -77
  10. package/src/models/agents.js +154 -154
  11. package/src/models/apilog.js +18 -18
  12. package/src/models/approvalsWorkflows.js +49 -49
  13. package/src/models/archivedapilog.js +18 -18
  14. package/src/models/asset.js +92 -92
  15. package/src/models/assetsAssignment.js +64 -64
  16. package/src/models/auditTrail.js +346 -346
  17. package/src/models/bankdetails.js +47 -47
  18. package/src/models/billerAddress.js +124 -124
  19. package/src/models/booking_invoice.js +151 -151
  20. package/src/models/bookinganalytics.js +63 -63
  21. package/src/models/bookingconfig.js +45 -45
  22. package/src/models/bookingproperty.js +122 -122
  23. package/src/models/bookingreservation.js +192 -192
  24. package/src/models/bookingrevenuerecord.js +84 -84
  25. package/src/models/budget.js +95 -95
  26. package/src/models/budgetCategory.js +19 -19
  27. package/src/models/campaigns.js +108 -108
  28. package/src/models/cashpayment.js +264 -264
  29. package/src/models/combinedUnits.js +62 -62
  30. package/src/models/common_area_electricity.js +38 -38
  31. package/src/models/common_area_generator.js +41 -41
  32. package/src/models/common_area_utility_alert.js +37 -37
  33. package/src/models/common_area_water.js +39 -39
  34. package/src/models/communication_status.js +33 -33
  35. package/src/models/communication_user_opt.js +32 -32
  36. package/src/models/company.js +53 -53
  37. package/src/models/coreBaseSettings.js +16 -16
  38. package/src/models/coreInvoiceSettings.js +100 -100
  39. package/src/models/counter_schema.js +21 -21
  40. package/src/models/country_tax.js +42 -42
  41. package/src/models/currency_settings.js +39 -39
  42. package/src/models/customer.js +210 -210
  43. package/src/models/customer_satisfaction_survey.js +278 -278
  44. package/src/models/customer_surveys.js +139 -139
  45. package/src/models/customer_tickets.js +239 -239
  46. package/src/models/dailyChecklist.js +312 -312
  47. package/src/models/default_payment_details.js +17 -17
  48. package/src/models/deliveryTimeMarks.js +18 -18
  49. package/src/models/document_type.js +19 -19
  50. package/src/models/dutyRosterChecklist.js +250 -250
  51. package/src/models/dutyroster.js +136 -136
  52. package/src/models/email.js +37 -37
  53. package/src/models/email_sms_queue.js +61 -61
  54. package/src/models/entry_exit.js +53 -53
  55. package/src/models/expense.js +99 -99
  56. package/src/models/expense_category.js +45 -45
  57. package/src/models/facility.js +62 -62
  58. package/src/models/facilityBillingPrices.js +29 -29
  59. package/src/models/facilityInvoice.js +240 -223
  60. package/src/models/facilityInvoicePayment.js +52 -47
  61. package/src/models/facilityInvoiceRecipient.js +32 -32
  62. package/src/models/facilityWalletTransactionsMetadata.js +236 -236
  63. package/src/models/facility_departements.js +20 -20
  64. package/src/models/facility_payment_details.js +20 -20
  65. package/src/models/facilityasset.js +25 -25
  66. package/src/models/faq.js +14 -14
  67. package/src/models/gl_account_double_entries.js +25 -25
  68. package/src/models/gl_accounts.js +56 -56
  69. package/src/models/gl_entries.js +49 -49
  70. package/src/models/goodsReceivedNotes.js +115 -115
  71. package/src/models/guard.js +47 -47
  72. package/src/models/handover.js +247 -247
  73. package/src/models/inspection_category.js +38 -38
  74. package/src/models/invoice.js +387 -387
  75. package/src/models/invoicing_schedule.js +36 -36
  76. package/src/models/item_inspection.js +96 -96
  77. package/src/models/knowledge_base.js +109 -109
  78. package/src/models/knowledge_base_rating.js +44 -44
  79. package/src/models/leaseagreement.js +236 -236
  80. package/src/models/leasetemplate.js +17 -17
  81. package/src/models/levy.js +223 -223
  82. package/src/models/levy_invoice_settings.js +26 -26
  83. package/src/models/levycontract.js +177 -177
  84. package/src/models/levytype.js +23 -23
  85. package/src/models/maintenance_service_vendor.js +38 -38
  86. package/src/models/maintenance_services.js +17 -17
  87. package/src/models/maintenancerequisition.js +31 -31
  88. package/src/models/master_workplan.js +32 -32
  89. package/src/models/master_workplan_child.js +34 -34
  90. package/src/models/message.js +38 -38
  91. package/src/models/module.js +21 -21
  92. package/src/models/notification.js +44 -44
  93. package/src/models/paymentTermsMarks.js +19 -19
  94. package/src/models/penalty.js +76 -76
  95. package/src/models/pendingCredentials.js +32 -32
  96. package/src/models/powerMeterCommunicationProtocol.js +17 -17
  97. package/src/models/powerMeterCustomerAccount.js +78 -78
  98. package/src/models/powerMeterCustomerBand.js +14 -14
  99. package/src/models/powerMeterDailyReading.js +30 -30
  100. package/src/models/powerMeterGateways.js +40 -40
  101. package/src/models/powerMeterMonthlyReading.js +34 -34
  102. package/src/models/powerMeterPowerCharges.js +85 -85
  103. package/src/models/powerMeterSettings.js +159 -159
  104. package/src/models/powerMeterSingleDayReading.js +32 -32
  105. package/src/models/powerMeters.js +116 -116
  106. package/src/models/powerMetersManufacturer.js +14 -14
  107. package/src/models/power_meter_account.js +81 -81
  108. package/src/models/power_meter_command_logs.js +30 -30
  109. package/src/models/power_meter_command_queue.js +33 -33
  110. package/src/models/power_meter_negative_balance.js +44 -44
  111. package/src/models/power_prepaid_credits.js +47 -47
  112. package/src/models/power_prepaid_debits.js +53 -53
  113. package/src/models/power_prepaid_orders.js +78 -78
  114. package/src/models/power_sms_notification.js +26 -26
  115. package/src/models/propertyManagerContract.js +556 -556
  116. package/src/models/propertyManagerRevenue.js +195 -195
  117. package/src/models/purchaseOrderInvoice.js +74 -74
  118. package/src/models/purchase_order.js +213 -213
  119. package/src/models/purchase_request.js +110 -110
  120. package/src/models/refresh_token.js +23 -23
  121. package/src/models/reminder.js +197 -197
  122. package/src/models/report.js +13 -13
  123. package/src/models/resident.js +121 -121
  124. package/src/models/rfq_details.js +131 -131
  125. package/src/models/rfq_response.js +153 -153
  126. package/src/models/service_charge_invoice_upload.js +42 -42
  127. package/src/models/service_charge_payments.js +27 -27
  128. package/src/models/servicerequest.js +55 -55
  129. package/src/models/settings.js +62 -62
  130. package/src/models/short_urls.js +21 -21
  131. package/src/models/smart_meter_daily_consumption.js +44 -44
  132. package/src/models/sms_africastalking.js +20 -20
  133. package/src/models/sms_balance_notification.js +26 -26
  134. package/src/models/sms_meliora.js +20 -20
  135. package/src/models/staff.js +36 -36
  136. package/src/models/stocksandspare.js +161 -161
  137. package/src/models/suppliers.js +74 -74
  138. package/src/models/tickets.js +173 -173
  139. package/src/models/tickets_category.js +72 -72
  140. package/src/models/unitManagementTemplate.js +44 -44
  141. package/src/models/unitasset.js +25 -25
  142. package/src/models/units.js +118 -118
  143. package/src/models/user.js +186 -186
  144. package/src/models/valueaddedservices.js +79 -79
  145. package/src/models/vas_invoices_upload.js +50 -50
  146. package/src/models/vas_payments.js +24 -24
  147. package/src/models/vasinvoice.js +192 -192
  148. package/src/models/vasvendor.js +57 -57
  149. package/src/models/visitLog.js +95 -95
  150. package/src/models/visitor.js +67 -67
  151. package/src/models/waitlist.js +45 -45
  152. package/src/models/wallet.js +44 -44
  153. package/src/models/wallet_transactions.js +50 -50
  154. package/src/models/water_invoice.js +351 -351
  155. package/src/models/water_meter_Command_Queue.js +33 -33
  156. package/src/models/water_meter_account.js +82 -82
  157. package/src/models/water_meter_billing.js +58 -58
  158. package/src/models/water_meter_communication.js +17 -17
  159. package/src/models/water_meter_communication_logs.js +39 -39
  160. package/src/models/water_meter_concentrator.js +70 -70
  161. package/src/models/water_meter_daily_history.js +32 -32
  162. package/src/models/water_meter_high_risk.js +36 -36
  163. package/src/models/water_meter_iot_cards.js +34 -34
  164. package/src/models/water_meter_manufacturer.js +35 -35
  165. package/src/models/water_meter_monthly_history.js +36 -36
  166. package/src/models/water_meter_negative_amounts.js +44 -44
  167. package/src/models/water_meter_settings.js +283 -283
  168. package/src/models/water_meter_single_day_history.js +34 -34
  169. package/src/models/water_meter_size.js +15 -15
  170. package/src/models/water_meters.js +133 -133
  171. package/src/models/water_meters_delivery.js +76 -76
  172. package/src/models/water_prepaid_credit.js +47 -47
  173. package/src/models/water_prepaid_debit.js +50 -50
  174. package/src/models/workorder.js +49 -49
  175. package/src/models/zohoIntegration.js +262 -0
  176. package/.idea/material_theme_project_new.xml +0 -12
  177. package/.idea/modules.xml +0 -8
  178. package/.idea/psdb.iml +0 -12
  179. package/.idea/vcs.xml +0 -6
package/.env CHANGED
@@ -1,3 +1,3 @@
1
- User=Ps
2
- Password=Letmein987
1
+ User=Ps
2
+ Password=Letmein987
3
3
  source=?authSource=admin
@@ -0,0 +1,644 @@
1
+ # Zoho Integration Schema - Implementation Summary
2
+
3
+ ## 📋 Overview
4
+
5
+ The `ZohoIntegration` schema has been successfully created and added to the PayServe database package (psdb). This schema stores Zoho Books API credentials and synchronization data on a per-facility basis.
6
+
7
+ **Package Version:** `8.3.8` (updated from 8.3.7)
8
+
9
+ ---
10
+
11
+ ## 🗄️ Schema Structure
12
+
13
+ ### Location
14
+ - **File:** `psdb/src/models/zohoIntegration.js`
15
+ - **Model Name:** `ZohoIntegration`
16
+ - **Collection:** `zohointegrations`
17
+
18
+ ### Key Features
19
+ - ✅ One integration per facility (unique constraint on `facilityId`)
20
+ - ✅ Encrypted sensitive fields (clientSecret, refreshToken, accessToken)
21
+ - ✅ Automatic sync tracking and statistics
22
+ - ✅ Token expiry management
23
+ - ✅ Connection status monitoring
24
+ - ✅ Audit trail support
25
+ - ✅ Built-in helper methods
26
+
27
+ ---
28
+
29
+ ## 📊 Schema Fields
30
+
31
+ ### Core Identification
32
+ ```javascript
33
+ {
34
+ facilityId: ObjectId (required, unique, indexed)
35
+ - Links to Facility collection
36
+ - One Zoho config per facility
37
+ }
38
+ ```
39
+
40
+ ### Zoho API Credentials
41
+ ```javascript
42
+ {
43
+ clientId: String (required)
44
+ - Zoho OAuth client ID
45
+ - Example: "1000.XXXXXXXXXXXXX"
46
+
47
+ clientSecret: String (required, encrypted)
48
+ - Zoho OAuth client secret
49
+ - MUST be encrypted before storage
50
+
51
+ refreshToken: String (required, encrypted)
52
+ - Zoho OAuth refresh token
53
+ - MUST be encrypted before storage
54
+ - Example: "1000.XXXXXXXXXXXXX"
55
+
56
+ accessToken: String (encrypted, nullable)
57
+ - Current access token
58
+ - Auto-refreshed by system
59
+ - MUST be encrypted before storage
60
+
61
+ organizationId: String (required)
62
+ - Zoho Books organization ID
63
+ - Example: "902250663"
64
+ }
65
+ ```
66
+
67
+ ### Integration Status
68
+ ```javascript
69
+ {
70
+ isActive: Boolean (default: true)
71
+ - Whether integration is active
72
+
73
+ connectionStatus: Enum (default: "pending")
74
+ - Values: "connected", "disconnected", "error", "pending"
75
+ - Current connection state
76
+
77
+ connectionError: String (nullable)
78
+ - Last connection error message
79
+
80
+ lastConnectionTest: Date (nullable)
81
+ - Timestamp of last connection test
82
+ }
83
+ ```
84
+
85
+ ### Token Management
86
+ ```javascript
87
+ {
88
+ tokenExpiresAt: Date (nullable)
89
+ - When current access token expires
90
+
91
+ lastTokenRefreshAt: Date (nullable)
92
+ - Last successful token refresh
93
+
94
+ tokenRefreshCount: Number (default: 0)
95
+ - Total token refreshes performed
96
+ }
97
+ ```
98
+
99
+ ### Sync Statistics
100
+ ```javascript
101
+ {
102
+ lastSyncedAt: Date (nullable)
103
+ - Last successful sync timestamp
104
+
105
+ totalInvoicesSynced: Number (default: 0)
106
+ - Total invoices synced to Zoho
107
+
108
+ totalPaymentsSynced: Number (default: 0)
109
+ - Total payments synced to Zoho
110
+
111
+ totalCustomersSynced: Number (default: 0)
112
+ - Total customers synced to Zoho
113
+
114
+ successfulSyncs: Number (default: 0)
115
+ - Count of successful sync operations
116
+
117
+ failedSyncs: Number (default: 0)
118
+ - Count of failed sync operations
119
+ }
120
+ ```
121
+
122
+ ### Sync Configuration
123
+ ```javascript
124
+ {
125
+ autoSyncEnabled: Boolean (default: true)
126
+ - Enable automatic synchronization
127
+
128
+ syncFrequency: Enum (default: "realtime")
129
+ - Values: "realtime", "hourly", "daily", "manual"
130
+ - How often to sync
131
+
132
+ lastSyncError: String (nullable)
133
+ - Last sync error message
134
+
135
+ syncInvoicesOnCreation: Boolean (default: true)
136
+ - Auto-sync when invoice created
137
+
138
+ syncPaymentsOnReceipt: Boolean (default: true)
139
+ - Auto-sync when payment received
140
+
141
+ markInvoicesAsSent: Boolean (default: true)
142
+ - Mark invoices as "sent" in Zoho
143
+ }
144
+ ```
145
+
146
+ ### API Configuration
147
+ ```javascript
148
+ {
149
+ apiBaseUrl: String (default: "https://www.zohoapis.com/books/v3")
150
+ - Zoho API base URL
151
+
152
+ requestTimeout: Number (default: 30000)
153
+ - API request timeout in milliseconds
154
+ - Min: 1000ms
155
+
156
+ maxRetries: Number (default: 3)
157
+ - Max retry attempts for failed requests
158
+ - Min: 0, Max: 10
159
+ }
160
+ ```
161
+
162
+ ### Audit Fields
163
+ ```javascript
164
+ {
165
+ createdBy: ObjectId (nullable)
166
+ - User who created configuration
167
+
168
+ updatedBy: ObjectId (nullable)
169
+ - User who last updated configuration
170
+
171
+ lastModifiedBy: ObjectId (nullable)
172
+ - User who last modified configuration
173
+
174
+ createdAt: Date (auto)
175
+ - Creation timestamp
176
+
177
+ updatedAt: Date (auto)
178
+ - Last update timestamp
179
+ }
180
+ ```
181
+
182
+ ### Metadata
183
+ ```javascript
184
+ {
185
+ notes: String (nullable)
186
+ - Admin notes about integration
187
+
188
+ metadata: Mixed (default: {})
189
+ - Additional custom data
190
+ }
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 🔐 Security Considerations
196
+
197
+ ### Fields That MUST Be Encrypted
198
+
199
+ ⚠️ **CRITICAL:** These fields contain sensitive data and MUST be encrypted before storage:
200
+
201
+ 1. `clientSecret`
202
+ 2. `refreshToken`
203
+ 3. `accessToken`
204
+
205
+ ### Recommended Encryption Approach
206
+
207
+ ```javascript
208
+ const crypto = require('crypto');
209
+
210
+ // Encryption function (use environment variable for key)
211
+ function encrypt(text) {
212
+ const algorithm = 'aes-256-cbc';
213
+ const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
214
+ const iv = crypto.randomBytes(16);
215
+
216
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
217
+ let encrypted = cipher.update(text, 'utf8', 'hex');
218
+ encrypted += cipher.final('hex');
219
+
220
+ return iv.toString('hex') + ':' + encrypted;
221
+ }
222
+
223
+ // Decryption function
224
+ function decrypt(text) {
225
+ const algorithm = 'aes-256-cbc';
226
+ const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
227
+
228
+ const parts = text.split(':');
229
+ const iv = Buffer.from(parts[0], 'hex');
230
+ const encryptedText = parts[1];
231
+
232
+ const decipher = crypto.createDecipheriv(algorithm, key, iv);
233
+ let decrypted = decipher.update(encryptedText, 'hex', 'utf8');
234
+ decrypted += decipher.final('utf8');
235
+
236
+ return decrypted;
237
+ }
238
+ ```
239
+
240
+ ---
241
+
242
+ ## 🛠️ Built-in Methods
243
+
244
+ ### 1. `toSafeObject()`
245
+ Returns a safe version of the document with masked sensitive fields.
246
+
247
+ ```javascript
248
+ const config = await ZohoIntegration.findOne({ facilityId });
249
+ const safeConfig = config.toSafeObject();
250
+
251
+ // Output:
252
+ // {
253
+ // clientSecret: "••••••••7e7d",
254
+ // refreshToken: "••••••••54d",
255
+ // accessToken: "••••••••xyz",
256
+ // ...other fields
257
+ // }
258
+ ```
259
+
260
+ ### 2. `needsTokenRefresh()`
261
+ Checks if the access token needs refreshing (5-minute buffer).
262
+
263
+ ```javascript
264
+ const config = await ZohoIntegration.findOne({ facilityId });
265
+
266
+ if (config.needsTokenRefresh()) {
267
+ // Refresh the token
268
+ const newToken = await refreshZohoToken(config);
269
+ config.accessToken = encrypt(newToken);
270
+ config.tokenExpiresAt = new Date(Date.now() + 3600000);
271
+ await config.save();
272
+ }
273
+ ```
274
+
275
+ ### 3. `incrementSyncCounters(type, success)`
276
+ Increments sync statistics after each operation.
277
+
278
+ ```javascript
279
+ const config = await ZohoIntegration.findOne({ facilityId });
280
+
281
+ // After successful invoice sync
282
+ await config.incrementSyncCounters('invoice', true);
283
+
284
+ // After failed payment sync
285
+ await config.incrementSyncCounters('payment', false);
286
+ ```
287
+
288
+ ---
289
+
290
+ ## 📈 Virtual Properties
291
+
292
+ ### `syncSuccessRate`
293
+ Calculates success rate as a percentage.
294
+
295
+ ```javascript
296
+ const config = await ZohoIntegration.findOne({ facilityId });
297
+ console.log(`Success Rate: ${config.syncSuccessRate}%`);
298
+ // Output: "Success Rate: 98.50%"
299
+ ```
300
+
301
+ ---
302
+
303
+ ## 🔍 Indexes
304
+
305
+ The schema includes optimized indexes for common queries:
306
+
307
+ ```javascript
308
+ // Compound index for facility + active status
309
+ { facilityId: 1, isActive: 1 }
310
+
311
+ // Index for connection status queries
312
+ { connectionStatus: 1 }
313
+
314
+ // Index for sorting by last sync
315
+ { lastSyncedAt: -1 }
316
+ ```
317
+
318
+ ---
319
+
320
+ ## 💻 Usage Examples
321
+
322
+ ### Example 1: Create New Configuration
323
+
324
+ ```javascript
325
+ const { ZohoIntegration } = require('payservedb');
326
+
327
+ async function createZohoConfig(facilityId, credentials, userId) {
328
+ try {
329
+ const config = new ZohoIntegration({
330
+ facilityId,
331
+ clientId: credentials.clientId,
332
+ clientSecret: encrypt(credentials.clientSecret),
333
+ refreshToken: encrypt(credentials.refreshToken),
334
+ organizationId: credentials.organizationId,
335
+ connectionStatus: 'pending',
336
+ createdBy: userId,
337
+ updatedBy: userId
338
+ });
339
+
340
+ await config.save();
341
+ return config.toSafeObject();
342
+ } catch (error) {
343
+ if (error.code === 11000) {
344
+ throw new Error('Zoho integration already exists for this facility');
345
+ }
346
+ throw error;
347
+ }
348
+ }
349
+ ```
350
+
351
+ ### Example 2: Get Configuration (Safe)
352
+
353
+ ```javascript
354
+ async function getZohoConfig(facilityId) {
355
+ const config = await ZohoIntegration.findOne({
356
+ facilityId,
357
+ isActive: true
358
+ });
359
+
360
+ if (!config) {
361
+ return null;
362
+ }
363
+
364
+ // Return safe version (masked secrets)
365
+ return config.toSafeObject();
366
+ }
367
+ ```
368
+
369
+ ### Example 3: Update Configuration
370
+
371
+ ```javascript
372
+ async function updateZohoConfig(facilityId, updates, userId) {
373
+ const config = await ZohoIntegration.findOne({ facilityId });
374
+
375
+ if (!config) {
376
+ throw new Error('Configuration not found');
377
+ }
378
+
379
+ // Encrypt sensitive fields if provided
380
+ if (updates.clientSecret) {
381
+ updates.clientSecret = encrypt(updates.clientSecret);
382
+ }
383
+ if (updates.refreshToken) {
384
+ updates.refreshToken = encrypt(updates.refreshToken);
385
+ }
386
+
387
+ updates.updatedBy = userId;
388
+ updates.lastModifiedBy = userId;
389
+
390
+ Object.assign(config, updates);
391
+ await config.save();
392
+
393
+ return config.toSafeObject();
394
+ }
395
+ ```
396
+
397
+ ### Example 4: Test Connection
398
+
399
+ ```javascript
400
+ async function testZohoConnection(facilityId) {
401
+ const config = await ZohoIntegration.findOne({ facilityId });
402
+
403
+ if (!config) {
404
+ throw new Error('Configuration not found');
405
+ }
406
+
407
+ try {
408
+ // Test connection to Zoho API
409
+ const response = await axios.get(
410
+ `${config.apiBaseUrl}/organizations`,
411
+ {
412
+ headers: {
413
+ 'Authorization': `Zoho-oauthtoken ${decrypt(config.accessToken)}`
414
+ }
415
+ }
416
+ );
417
+
418
+ // Update status
419
+ config.connectionStatus = 'connected';
420
+ config.lastConnectionTest = new Date();
421
+ config.connectionError = null;
422
+ await config.save();
423
+
424
+ return { success: true };
425
+ } catch (error) {
426
+ config.connectionStatus = 'error';
427
+ config.connectionError = error.message;
428
+ config.lastConnectionTest = new Date();
429
+ await config.save();
430
+
431
+ return { success: false, error: error.message };
432
+ }
433
+ }
434
+ ```
435
+
436
+ ### Example 5: Disconnect Integration
437
+
438
+ ```javascript
439
+ async function disconnectZoho(facilityId, userId) {
440
+ const config = await ZohoIntegration.findOne({ facilityId });
441
+
442
+ if (!config) {
443
+ throw new Error('Configuration not found');
444
+ }
445
+
446
+ config.isActive = false;
447
+ config.connectionStatus = 'disconnected';
448
+ config.updatedBy = userId;
449
+ await config.save();
450
+
451
+ return { success: true };
452
+ }
453
+ ```
454
+
455
+ ### Example 6: Get Integration Statistics
456
+
457
+ ```javascript
458
+ async function getZohoStats(facilityId) {
459
+ const config = await ZohoIntegration.findOne({ facilityId });
460
+
461
+ if (!config) {
462
+ return null;
463
+ }
464
+
465
+ return {
466
+ totalInvoicesSynced: config.totalInvoicesSynced,
467
+ totalPaymentsSynced: config.totalPaymentsSynced,
468
+ totalCustomersSynced: config.totalCustomersSynced,
469
+ successfulSyncs: config.successfulSyncs,
470
+ failedSyncs: config.failedSyncs,
471
+ successRate: config.syncSuccessRate,
472
+ lastSyncedAt: config.lastSyncedAt,
473
+ connectionStatus: config.connectionStatus,
474
+ isActive: config.isActive
475
+ };
476
+ }
477
+ ```
478
+
479
+ ---
480
+
481
+ ## 🚀 Next Steps
482
+
483
+ ### 1. Update Backend Package
484
+
485
+ ```bash
486
+ cd backend_main
487
+ npm install payservedb@8.3.8
488
+ # or
489
+ npm update payservedb
490
+ ```
491
+
492
+ ### 2. Create Controllers
493
+
494
+ Create the following files in `backend_main`:
495
+ - `src/controllers/integrations/zohoIntegrationController.js`
496
+ - `src/routes/integrations/zohoIntegrationRoutes.js`
497
+
498
+ ### 3. Implement Encryption
499
+
500
+ Add encryption utilities:
501
+ - `src/utils/encryption.js`
502
+
503
+ Generate encryption key:
504
+ ```bash
505
+ node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
506
+ ```
507
+
508
+ Add to `.env`:
509
+ ```env
510
+ ENCRYPTION_KEY=your_generated_key_here
511
+ ```
512
+
513
+ ### 4. API Endpoints to Create
514
+
515
+ ```
516
+ GET /api/facility/:facilityId/integrations/zoho/config
517
+ POST /api/facility/:facilityId/integrations/zoho/config
518
+ PUT /api/facility/:facilityId/integrations/zoho/config
519
+ DELETE /api/facility/:facilityId/integrations/zoho/config
520
+ POST /api/facility/:facilityId/integrations/zoho/test
521
+ GET /api/facility/:facilityId/integrations/zoho/stats
522
+ ```
523
+
524
+ ### 5. Frontend Integration
525
+
526
+ Update the `IntegrationsTab.js` component to:
527
+ - Call the new API endpoints
528
+ - Display real configuration data
529
+ - Handle encryption (send plain, receive masked)
530
+ - Update UI based on connection status
531
+
532
+ ---
533
+
534
+ ## 📝 Migration Notes
535
+
536
+ ### For Existing Facilities
537
+
538
+ If you need to migrate existing Zoho configurations:
539
+
540
+ ```javascript
541
+ async function migrateExistingConfigs() {
542
+ // If you have configs stored elsewhere
543
+ const oldConfigs = await OldModel.find({});
544
+
545
+ for (const old of oldConfigs) {
546
+ await ZohoIntegration.create({
547
+ facilityId: old.facilityId,
548
+ clientId: old.clientId,
549
+ clientSecret: encrypt(old.clientSecret),
550
+ refreshToken: encrypt(old.refreshToken),
551
+ organizationId: old.organizationId,
552
+ connectionStatus: 'pending',
553
+ createdAt: old.createdAt || new Date()
554
+ });
555
+ }
556
+ }
557
+ ```
558
+
559
+ ---
560
+
561
+ ## 🧪 Testing
562
+
563
+ ### Unit Test Example
564
+
565
+ ```javascript
566
+ const { ZohoIntegration } = require('payservedb');
567
+
568
+ describe('ZohoIntegration Model', () => {
569
+ it('should create config with unique facilityId', async () => {
570
+ const config = await ZohoIntegration.create({
571
+ facilityId: mongoose.Types.ObjectId(),
572
+ clientId: '1000.TEST123',
573
+ clientSecret: encrypt('secret123'),
574
+ refreshToken: encrypt('refresh123'),
575
+ organizationId: '123456'
576
+ });
577
+
578
+ expect(config).toBeDefined();
579
+ expect(config.isActive).toBe(true);
580
+ expect(config.connectionStatus).toBe('pending');
581
+ });
582
+
583
+ it('should mask sensitive fields in toSafeObject', () => {
584
+ const config = new ZohoIntegration({
585
+ clientSecret: 'very_secret_key',
586
+ refreshToken: 'refresh_token_123'
587
+ });
588
+
589
+ const safe = config.toSafeObject();
590
+ expect(safe.clientSecret).toContain('••••••••');
591
+ expect(safe.refreshToken).toContain('••••••••');
592
+ });
593
+
594
+ it('should calculate sync success rate', () => {
595
+ const config = new ZohoIntegration({
596
+ successfulSyncs: 95,
597
+ failedSyncs: 5
598
+ });
599
+
600
+ expect(config.syncSuccessRate).toBe('95.00');
601
+ });
602
+ });
603
+ ```
604
+
605
+ ---
606
+
607
+ ## ⚠️ Important Warnings
608
+
609
+ 1. **NEVER** return decrypted secrets to the frontend
610
+ 2. **ALWAYS** use `toSafeObject()` when sending to API responses
611
+ 3. **ENCRYPT** sensitive fields before saving to database
612
+ 4. **VALIDATE** all inputs before storing
613
+ 5. **AUDIT** all configuration changes
614
+ 6. **MONITOR** connection status regularly
615
+ 7. **ROTATE** tokens periodically for security
616
+
617
+ ---
618
+
619
+ ## 📚 Related Documentation
620
+
621
+ - **Zoho API Documentation:** [https://www.zoho.com/books/api/v3/](https://www.zoho.com/books/api/v3/)
622
+ - **OAuth 2.0 Guide:** `backend_main/src/services/integrations/zoho/README.md`
623
+ - **Frontend Component:** `app_main/src/components/facility/settings_management/IntegrationsTab.js`
624
+ - **Payment Integration:** `backend_main/src/controllers/integrations/zoho/PAYMENT_GUIDE.md`
625
+
626
+ ---
627
+
628
+ ## ✅ Status
629
+
630
+ - ✅ Schema created and validated
631
+ - ✅ Model exported in payservedb package
632
+ - ✅ Package version bumped to 8.3.8
633
+ - ✅ Indexes defined for performance
634
+ - ✅ Helper methods implemented
635
+ - ✅ Security considerations documented
636
+ - ⏳ Controllers and routes (pending)
637
+ - ⏳ Encryption utilities (pending)
638
+ - ⏳ Frontend integration (pending)
639
+
640
+ ---
641
+
642
+ **Last Updated:** 2025-10-28
643
+ **Schema Version:** 1.0.0
644
+ **Package Version:** 8.3.8