Rakshitjan commited on
Commit
bdf99f3
·
verified ·
1 Parent(s): 07e234d

Changed the structure of cases

Browse files
Files changed (8) hide show
  1. Dockerfile.txt +14 -0
  2. data.json +138 -0
  3. gitattributes.txt +35 -0
  4. index.js +54 -323
  5. models.js +27 -99
  6. package-lock.json +0 -0
  7. readme-2.md +611 -0
  8. verify_refactor.js +682 -0
Dockerfile.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:18-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ COPY package*.json ./
6
+
7
+ RUN npm install --production
8
+
9
+ COPY . .
10
+
11
+ # Expose the port that Hugging Face expects (default is 7860)
12
+ EXPOSE 7860
13
+
14
+ CMD ["npm", "start"]
data.json ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "applicantDetail": {
3
+ "userId": 135860,
4
+ "panNumber": null,
5
+ "dob": "24-11-1990",
6
+ "voterId": "ABC1234567",
7
+ "email": "parvej@gmail.com",
8
+ "mobile": "8000051783",
9
+ "alternateMobile": "8000051784",
10
+ "socialCategoryId": 1,
11
+ "aadharRefNumber": "800180018019",
12
+ "urnNumber": null,
13
+ "isFromLsp": null,
14
+ "name": "Parvez mansuri",
15
+ "genderId": 1,
16
+ "maritalStatus": 1,
17
+ "qualification": 4,
18
+ "religion": 6,
19
+ "womanEntrepreneur": 0,
20
+ "divyang": 0,
21
+ "serviceman": 0,
22
+ "fatherName": "fname",
23
+ "motherName": "mname",
24
+ "spouseName": "sname",
25
+ "spouseDob": "24-11-1992",
26
+ "numOfDependent": 4,
27
+ "illness": 7,
28
+ "primaryId": 2,
29
+ "secodaryId": 1,
30
+ "primaryDoc": 95988,
31
+ "secodaryDoc": 95989,
32
+ "applicantImg": 95990,
33
+ "urnFound": 0,
34
+ "daId": 1,
35
+ "numEarFamiMemb": 1,
36
+ "primaryFileDetail": "certificate_1758545662.pdf | 192kb | 24/11/2025",
37
+ "secondaryFileDetail": "certificate_1758545658.pdf | 192kb | 24/11/2025",
38
+ "applicantFileDetail": "certificate_1758545652.pdf | 192kb | 24/11/2025",
39
+ "addresProofDetail": "certificate_1758545631.pdf | 192kb | 24-11-2025",
40
+ "updateResiAddrss": true,
41
+ "profileId": 24306
42
+ },
43
+ "residenceDetail": {
44
+ "id": 18431,
45
+ "ownershipStatus": 2,
46
+ "address1": "test1",
47
+ "address2": "test2",
48
+ "address3": "test3",
49
+ "cityId": 783,
50
+ "districtId": 134,
51
+ "stateId": 24,
52
+ "pincode": "380001",
53
+ "addressProofType": 2,
54
+ "addressProofId": 95992,
55
+ "addresProofDetail": "certificate_1758545631.pdf | 192kb | 24-11-2025",
56
+ "updateResiAddrss": null
57
+ },
58
+ "coApplicantDetail": {
59
+ "name": "OPL",
60
+ "panNumber": null,
61
+ "email": null,
62
+ "dob": "24-11-1991",
63
+ "mobile": "8000051785",
64
+ "gender": 1,
65
+ "maritalStatus": 2,
66
+ "relationshipWithApplicantId": 6,
67
+ "occupationId": 2,
68
+ "primaryId": 2,
69
+ "secondaryId": 1,
70
+ "primaryDoc": 96005,
71
+ "secondaryDoc": 96006,
72
+ "voterId": "ABC1234567",
73
+ "applicantImg": 96007,
74
+ "sameAsResidential": false,
75
+ "ownership": null,
76
+ "address1": "test7",
77
+ "address2": null,
78
+ "address3": null,
79
+ "landmark": null,
80
+ "cityId": 783,
81
+ "districtId": 134,
82
+ "stateId": 24,
83
+ "pincode": "380001",
84
+ "applicantImgDetail": "certificate_1758545652.pdf | 192kb | 24/11/2025",
85
+ "primaryFileDetail": "certificate_1758545662.pdf | 192kb | 24/11/2025",
86
+ "secondaryFileDetail": "certificate_1758545658.pdf | 192kb | 24/11/2025"
87
+ },
88
+ "businessDetail": {
89
+ "businessName": "parvez enterprise",
90
+ "businessType": 4,
91
+ "natureActivity": 1,
92
+ "areaType": 3,
93
+ "organizationType": 1,
94
+ "establishDate": "1970-01-01",
95
+ "panNumber": "NEMPM0285K",
96
+ "businessLocation": 1,
97
+ "workExperienceInYears": 5,
98
+ "addressId": 18432,
99
+ "ownershipStatus": 1,
100
+ "address1": "test4",
101
+ "address2": null,
102
+ "landmark": null,
103
+ "cityId": 783,
104
+ "districtId": 134,
105
+ "stateId": 24,
106
+ "pincode": "380001",
107
+ "businessProofType": 1,
108
+ "businessProofDoc": 95993,
109
+ "businessProofDetail": "certificate_1758545662.pdf | 192kb | 24/11/2025",
110
+ "updateBusinessAddrss": true
111
+ },
112
+ "incomeExpenditure": {
113
+ "monthlyIncome": 60000.00,
114
+ "freqOfIncome": 2,
115
+ "incomeDays": 30,
116
+ "avgIncomeDailyBasis": 2000.00,
117
+ "yearlyIncome": 750000.00,
118
+ "incomeFromOtherSource": 0.00,
119
+ "rationCard": 0,
120
+ "totalIncome": 750000.00,
121
+ "appType": 1
122
+ },
123
+ "familyExpenses": {
124
+ "householdExp": 100000.00,
125
+ "utilityExp": 10000.00,
126
+ "eduExp": 11000.00,
127
+ "mediExp": 12000.00,
128
+ "mediExpCritical": 13000.00,
129
+ "foodExp": 14000.00,
130
+ "grocExp": 15000.00,
131
+ "cookingExp": 16000.00,
132
+ "otherExp": 17000.00,
133
+ "clothing": 18000.00,
134
+ "transpExp": 19000.00,
135
+ "otherBusiExp": 20000.00,
136
+ "totalExp": 265000.00
137
+ }
138
+ }
gitattributes.txt ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
index.js CHANGED
@@ -1236,80 +1236,7 @@ app.put('/api/cases/:case_id', authenticateToken, requireAgentOrAdmin, async (re
1236
  }
1237
  if (req.body.remarks) updateData.remarks = req.body.remarks;
1238
 
1239
- if (req.body.demographic_details) {
1240
- const demo = req.body.demographic_details;
1241
- const currentDemo = caseDoc.demographic_details || {};
1242
-
1243
- updateData.demographic_details = {
1244
- ...currentDemo,
1245
- ...(demo.aadhaar_photo_match !== undefined && { aadhaar_photo_match: demo.aadhaar_photo_match }),
1246
- contact_information: {
1247
- ...(currentDemo.contact_information || {}),
1248
- ...(demo.contact_information || {})
1249
- },
1250
- personal_details: {
1251
- ...(currentDemo.personal_details || {}),
1252
- ...(demo.personal_details || {})
1253
- },
1254
- ...(demo.customer_photo_id && { customer_photo_id: demo.customer_photo_id }),
1255
- address_details: {
1256
- ...(currentDemo.address_details || {}),
1257
- ...(demo.address_details || {})
1258
- },
1259
- ...(demo.residence_photo_id && { residence_photo_id: demo.residence_photo_id })
1260
- };
1261
- }
1262
-
1263
- if (req.body.business_details) {
1264
- const biz = req.body.business_details;
1265
- const currentBiz = caseDoc.business_details || {};
1266
-
1267
- updateData.business_details = {
1268
- ...currentBiz,
1269
- enterprise_information: {
1270
- ...(currentBiz.enterprise_information || {}),
1271
- ...(biz.enterprise_information || {})
1272
- },
1273
- business_location_details: {
1274
- ...(currentBiz.business_location_details || {}),
1275
- ...(biz.business_location_details || {})
1276
- },
1277
- business_address: {
1278
- ...(currentBiz.business_address || {}),
1279
- ...(biz.business_address || {})
1280
- },
1281
- ...(biz.business_address_photo_id && { business_address_photo_id: biz.business_address_photo_id }),
1282
- business_activity: {
1283
- ...(currentBiz.business_activity || {}),
1284
- ...(biz.business_activity || {})
1285
- },
1286
- business_info: {
1287
- ...(currentBiz.business_info || {}),
1288
- ...(biz.business_info || {})
1289
- }
1290
- };
1291
- }
1292
-
1293
- if (req.body.financial_details) {
1294
- const fin = req.body.financial_details;
1295
- const currentFin = caseDoc.financial_details || {};
1296
-
1297
- updateData.financial_details = {
1298
- ...currentFin,
1299
- business_financial_information: {
1300
- ...(currentFin.business_financial_information || {}),
1301
- ...(fin.business_financial_information || {})
1302
- },
1303
- loans_and_emis: {
1304
- ...(currentFin.loans_and_emis || {}),
1305
- ...(fin.loans_and_emis || {})
1306
- },
1307
- family_financial_information: {
1308
- ...(currentFin.family_financial_information || {}),
1309
- ...(fin.family_financial_information || {})
1310
- }
1311
- };
1312
- }
1313
 
1314
  const updatedCase = await Case.findOneAndUpdate(
1315
  { case_id: req.params.case_id },
@@ -1327,66 +1254,7 @@ app.put('/api/cases/:case_id', authenticateToken, requireAgentOrAdmin, async (re
1327
  });
1328
 
1329
  // Update specific section of case
1330
- app.patch('/api/cases/:case_id/:section', authenticateToken, requireAgentOrAdmin, async (req, res) => {
1331
- try {
1332
- const { case_id, section } = req.params;
1333
-
1334
- const caseDoc = await Case.findOne({ case_id });
1335
-
1336
- if (!caseDoc) {
1337
- return res.status(404).json({ error: 'Case not found' });
1338
- }
1339
-
1340
- if (req.user.role === 'agent' && caseDoc.assigned_agent !== req.user.userId) {
1341
- return res.status(403).json({ error: 'Access denied to this case' });
1342
- }
1343
-
1344
- const updateData = { updated_at: new Date() };
1345
- const validSections = ['demographic_details', 'business_details', 'financial_details'];
1346
-
1347
- if (!validSections.includes(section)) {
1348
- return res.status(400).json({ error: 'Invalid section. Must be: demographic_details, business_details, or financial_details' });
1349
- }
1350
-
1351
- const currentSection = caseDoc[section] || {};
1352
- updateData[section] = deepMerge(currentSection, req.body);
1353
-
1354
- const updatedCase = await Case.findOneAndUpdate(
1355
- { case_id },
1356
- updateData,
1357
- { new: true }
1358
- );
1359
-
1360
- res.json({
1361
- message: `${section} updated successfully`,
1362
- case: updatedCase
1363
- });
1364
- } catch (error) {
1365
- res.status(400).json({ error: error.message });
1366
- }
1367
- });
1368
-
1369
- function deepMerge(target, source) {
1370
- const output = { ...target };
1371
- if (isObject(target) && isObject(source)) {
1372
- Object.keys(source).forEach(key => {
1373
- if (isObject(source[key])) {
1374
- if (!(key in target)) {
1375
- output[key] = source[key];
1376
- } else {
1377
- output[key] = deepMerge(target[key], source[key]);
1378
- }
1379
- } else {
1380
- output[key] = source[key];
1381
- }
1382
- });
1383
- }
1384
- return output;
1385
- }
1386
-
1387
- function isObject(item) {
1388
- return item && typeof item === 'object' && !Array.isArray(item);
1389
- }
1390
 
1391
  // Delete Case (Admin only)
1392
  app.delete('/api/cases/:case_id', authenticateToken, requireAdmin, async (req, res) => {
@@ -1577,10 +1445,10 @@ app.post('/api/webhook/case-creation', validateWebhookApiKey, async (req, res) =
1577
  // Check if this is an automation webhook (has applicationId and status)
1578
  if (requestData.applicationId && requestData.status === 'New') {
1579
  console.log(`🚀 Starting automation for App ID: ${requestData.applicationId}`);
1580
-
1581
  try {
1582
  const automationResult = await processAutomation(requestData.applicationId);
1583
-
1584
  res.status(200).json({
1585
  success: true,
1586
  message: 'Webhook data received and automation completed successfully',
@@ -1625,34 +1493,30 @@ async function processAutomation(applicationId) {
1625
  try {
1626
  console.log(`Processing automation for Application ID: ${applicationId}`);
1627
 
1628
- // 1. Encrypt applicationId
1629
- // Using the specific key "appIicationid" as requested by user
1630
- const dataToEncrypt = JSON.stringify({ appIicationid: applicationId });
1631
- const encryptedData = encryptStringB2C(dataToEncrypt);
1632
-
1633
- // 2. Call external API
1634
  const externalApiUrl = 'https://qa-uapmp.instantmseloans.in/gateway/loans/msme/uapmp/v1/getBorrowerdetails';
 
1635
  const response = await axios.post(externalApiUrl, {
1636
- data: encryptedData
1637
  }, {
1638
  headers: {
1639
  'Content-Type': 'application/json',
1640
- 'User-name': '0fc6acd2675fece320be288e84cf2365',
1641
- 'api-key': 'f08f1a49-f567-4f12-bcac-10d2ae9f1bb9',
1642
- 'isCPV': 'true',
1643
- 'is_decrypt': 'true',
1644
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
1645
  }
1646
  });
1647
 
1648
- const { encData } = response.data;
 
1649
 
1650
- if (!encData) {
1651
- throw new Error('External API did not return encData');
1652
  }
1653
 
1654
- // 3. Decrypt and Save
1655
- const result = await processAndSaveBorrowerData(encData, applicationId);
1656
 
1657
  return {
1658
  success: true,
@@ -1730,32 +1594,33 @@ app.post('/api/decrypt', async (req, res) => {
1730
 
1731
  // Decrypt and Parse B2C encrypted string to JSON and Save directly to Cases
1732
  // Helper function to process and save borrower data
1733
- async function processAndSaveBorrowerData(encData, appId) {
1734
- // Decrypt the encrypted string
1735
- const decryptedString = decryptStringB2C(encData);
1736
-
1737
- // Parse to JSON
1738
- const jsonData = JSON.parse(decryptedString);
1739
-
1740
- // Transform the new API structure to match your exact backend schema
1741
- const transformedData = transformToBackendStructure(jsonData);
1742
 
1743
  // Create case data with your exact schema using the main Case model
1744
  const caseData = {
1745
  case_id: uuidv4(),
1746
- application_id: appId || jsonData.applicationId,
1747
- case_applicant_name: transformedData.case_applicant_name,
1748
- case_applicant_contact: transformedData.case_applicant_contact,
1749
- address: transformedData.address,
1750
- case_type: transformedData.case_type,
1751
- loan_amount: transformedData.loan_amount,
1752
- priority: transformedData.priority,
1753
- assigned_agent: "", // keep empty initially as per your requirement
1754
- status: "Pending", // default status
1755
- demographic_details: transformedData.demographic_details,
1756
- business_details: transformedData.business_details,
1757
- financial_details: transformedData.financial_details,
1758
- remarks: transformedData.remarks,
 
 
 
 
 
 
 
1759
  created_at: new Date(),
1760
  updated_at: new Date()
1761
  };
@@ -1765,7 +1630,7 @@ async function processAndSaveBorrowerData(encData, appId) {
1765
 
1766
  return {
1767
  case_id: newCase.case_id,
1768
- application_id: jsonData.applicationId,
1769
  saved_data: caseData
1770
  };
1771
  }
@@ -1809,6 +1674,7 @@ app.post('/api/decrypt-json-save', async (req, res) => {
1809
  }
1810
  });
1811
 
 
1812
  // Webhook Automation Endpoint
1813
  app.post('/api/webhook/automation', async (req, res) => {
1814
  try {
@@ -1823,34 +1689,28 @@ app.post('/api/webhook/automation', async (req, res) => {
1823
  });
1824
  }
1825
 
1826
- // 1. Encrypt applicationId
1827
- // Using the specific key "appIicationid" as requested by user
1828
- const dataToEncrypt = JSON.stringify({ appIicationid: applicationId });
1829
- const encryptedData = encryptStringB2C(dataToEncrypt);
1830
-
1831
- // 2. Call external API
1832
  const externalApiUrl = 'https://qa-uapmp.instantmseloans.in/gateway/loans/msme/uapmp/v1/getBorrowerdetails';
 
1833
  const response = await axios.post(externalApiUrl, {
1834
- data: encryptedData
1835
  }, {
1836
  headers: {
1837
  'Content-Type': 'application/json',
1838
- 'User-name': '0fc6acd2675fece320be288e84cf2365',
1839
- 'api-key': 'f08f1a49-f567-4f12-bcac-10d2ae9f1bb9',
1840
- 'isCPV': 'true',
1841
- 'is_decrypt': 'true',
1842
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
1843
  }
1844
  });
1845
 
1846
- const { encData } = response.data;
1847
 
1848
- if (!encData) {
1849
- throw new Error('External API did not return encData');
1850
  }
1851
 
1852
- // 3. Decrypt and Save
1853
- const result = await processAndSaveBorrowerData(encData, applicationId);
1854
 
1855
  res.json({
1856
  success: true,
@@ -1868,136 +1728,7 @@ app.post('/api/webhook/automation', async (req, res) => {
1868
  }
1869
  });
1870
 
1871
- // Mapping function to transform new API structure to your exact backend schema
1872
- function transformToBackendStructure(newData) {
1873
- const { data, metaData } = newData;
1874
- const { applicantDetail, residenceDetail, businessDetail, coApplicantDetail, incomeExpenditure, familyExpenses } = data;
1875
-
1876
- // Helper function to get display value from metaData
1877
- const getDisplayValue = (metaArray, id) => {
1878
- if (!metaArray || !id) return '';
1879
- const item = metaArray.find(item => item.id === id);
1880
- return item ? item.value : '';
1881
- };
1882
-
1883
- // Helper function to handle empty values
1884
- const handleEmptyValue = (value, defaultValue = '') => {
1885
- if (value === null || value === undefined || value === '') {
1886
- return defaultValue;
1887
- }
1888
- return value;
1889
- };
1890
-
1891
- const handleEmptyNumber = (value, defaultValue = 0) => {
1892
- if (value === null || value === undefined || value === '') {
1893
- return defaultValue;
1894
- }
1895
- return Number(value) || defaultValue;
1896
- };
1897
-
1898
- // Build address from residence details
1899
- const buildAddress = () => {
1900
- const parts = [
1901
- residenceDetail?.address1,
1902
- residenceDetail?.address2,
1903
- residenceDetail?.address3,
1904
- getDisplayValue(metaData.residenceDetail?.cityId, residenceDetail?.cityId),
1905
- getDisplayValue(metaData.residenceDetail?.stateId, residenceDetail?.stateId),
1906
- residenceDetail?.pincode
1907
- ].filter(part => part && part !== '');
1908
-
1909
- return parts.join(', ');
1910
- };
1911
-
1912
- // Transform to your exact backend structure
1913
- return {
1914
- // Root level fields matching your schema
1915
- case_applicant_name: handleEmptyValue(applicantDetail?.name),
1916
- case_applicant_contact: handleEmptyValue(applicantDetail?.mobile),
1917
- address: buildAddress(),
1918
- case_type: "Business Loan", // Default as per your example
1919
- loan_amount: handleEmptyNumber(incomeExpenditure?.yearlyIncome),
1920
- priority: "MED", // Default priority
1921
-
1922
- // Demographic Details - exact structure as in your image
1923
- demographic_details: {
1924
- aadhaar_photo_match: null,
1925
- contact_information: {
1926
- email_id: handleEmptyValue(applicantDetail?.email),
1927
- mobile_number: handleEmptyValue(applicantDetail?.mobile)
1928
- },
1929
- personal_details: {
1930
- gender: getDisplayValue(metaData.genderId, applicantDetail?.genderId),
1931
- education: getDisplayValue(metaData.qualification, applicantDetail?.qualification),
1932
- number_of_family_members: handleEmptyNumber(applicantDetail?.numOfDependent)
1933
- },
1934
- customer_photo_id: handleEmptyValue(applicantDetail?.applicantFileDetail),
1935
- address_details: {
1936
- residence_address_type: getDisplayValue(metaData.ownershipStatus, residenceDetail?.ownershipStatus),
1937
- residential_address: buildAddress(),
1938
- city: getDisplayValue(metaData.residenceDetail?.cityId, residenceDetail?.cityId),
1939
- state: getDisplayValue(metaData.residenceDetail?.stateId, residenceDetail?.stateId),
1940
- district: getDisplayValue(metaData.residenceDetail?.districtId, residenceDetail?.districtId),
1941
- pincode: handleEmptyValue(residenceDetail?.pincode)
1942
- },
1943
- residence_photo_id: handleEmptyValue(residenceDetail?.addresProofDetail)
1944
- },
1945
-
1946
- // Business Details - exact structure as in your image
1947
- business_details: {
1948
- enterprise_information: {
1949
- enterprise_name: handleEmptyValue(businessDetail?.businessName),
1950
- type_of_organization: getDisplayValue(metaData.organizationType, businessDetail?.organizationType)
1951
- },
1952
- business_location_details: {
1953
- business_address_type: getDisplayValue(metaData.businessLocation, businessDetail?.businessLocation),
1954
- business_location: `${handleEmptyValue(businessDetail?.address1)} ${handleEmptyValue(businessDetail?.address2)}`.trim()
1955
- },
1956
- business_address: {
1957
- address: `${handleEmptyValue(businessDetail?.address1)} ${handleEmptyValue(businessDetail?.address2)}`.trim(),
1958
- city: getDisplayValue(metaData.businessDetail?.cityId, businessDetail?.cityId),
1959
- district: getDisplayValue(metaData.businessDetail?.districtId, businessDetail?.districtId),
1960
- state: getDisplayValue(metaData.businessDetail?.stateId, businessDetail?.stateId),
1961
- pincode: handleEmptyValue(businessDetail?.pincode),
1962
- landmark: handleEmptyValue(businessDetail?.landmark)
1963
- },
1964
- business_address_photo_id: handleEmptyValue(businessDetail?.businessProofDetail),
1965
- business_activity: {
1966
- business_activity: getDisplayValue(metaData.businessDetail?.natureActivity, businessDetail?.natureActivity),
1967
- activity_type: getDisplayValue(metaData.businessType, businessDetail?.businessType)
1968
- },
1969
- business_info: {
1970
- employee_count: 0, // Default as not available in new API
1971
- years_of_running_business: handleEmptyNumber(businessDetail?.workExperienceInYears),
1972
- additional_business: '' // Default as not available in new API
1973
- }
1974
- },
1975
-
1976
- // Financial Details - exact structure as in your image
1977
- financial_details: {
1978
- monthly_income: handleEmptyNumber(incomeExpenditure?.monthlyIncome),
1979
- yearly_income: handleEmptyNumber(incomeExpenditure?.yearlyIncome),
1980
- total_income: handleEmptyNumber(incomeExpenditure?.totalIncome),
1981
- income_from_other_sources: handleEmptyNumber(incomeExpenditure?.incomeFromOtherSource),
1982
- frequency_of_income: getDisplayValue([
1983
- { id: 1, value: 'Daily' },
1984
- { id: 2, value: 'Monthly' },
1985
- { id: 3, value: 'Yearly' }
1986
- ], incomeExpenditure?.freqOfIncome),
1987
- household_expenses: handleEmptyNumber(familyExpenses?.householdExp),
1988
- utility_expenses: handleEmptyNumber(familyExpenses?.utilityExp),
1989
- education_expenses: handleEmptyNumber(familyExpenses?.eduExp),
1990
- medical_expenses: handleEmptyNumber(familyExpenses?.mediExp),
1991
- food_expenses: handleEmptyNumber(familyExpenses?.foodExp),
1992
- grocery_expenses: handleEmptyNumber(familyExpenses?.grocExp),
1993
- transportation_expenses: handleEmptyNumber(familyExpenses?.transpExp),
1994
- other_expenses: handleEmptyNumber(familyExpenses?.otherExp),
1995
- total_expenses: handleEmptyNumber(familyExpenses?.totalExp)
1996
- },
1997
-
1998
- remarks: `Application ID: ${newData.applicationId} - Auto imported`
1999
- };
2000
- }
2001
 
2002
 
2003
 
 
1236
  }
1237
  if (req.body.remarks) updateData.remarks = req.body.remarks;
1238
 
1239
+ // Legacy update logic for demographic_details, business_details, financial_details removed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1240
 
1241
  const updatedCase = await Case.findOneAndUpdate(
1242
  { case_id: req.params.case_id },
 
1254
  });
1255
 
1256
  // Update specific section of case
1257
+ // PATCH endpoint removed as it handled legacy sections
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1258
 
1259
  // Delete Case (Admin only)
1260
  app.delete('/api/cases/:case_id', authenticateToken, requireAdmin, async (req, res) => {
 
1445
  // Check if this is an automation webhook (has applicationId and status)
1446
  if (requestData.applicationId && requestData.status === 'New') {
1447
  console.log(`🚀 Starting automation for App ID: ${requestData.applicationId}`);
1448
+
1449
  try {
1450
  const automationResult = await processAutomation(requestData.applicationId);
1451
+
1452
  res.status(200).json({
1453
  success: true,
1454
  message: 'Webhook data received and automation completed successfully',
 
1493
  try {
1494
  console.log(`Processing automation for Application ID: ${applicationId}`);
1495
 
1496
+ // 1. Call external API directly (no encryption of request body needed as per new spec)
1497
+ // User said: Request{ "appIicationid": 38789 }
 
 
 
 
1498
  const externalApiUrl = 'https://qa-uapmp.instantmseloans.in/gateway/loans/msme/uapmp/v1/getBorrowerdetails';
1499
+
1500
  const response = await axios.post(externalApiUrl, {
1501
+ appIicationid: applicationId
1502
  }, {
1503
  headers: {
1504
  'Content-Type': 'application/json',
1505
+ 'User-name': 'Biz2x',
1506
+ 'api-key': process.env.OPL_API_KEY || 'PLACEHOLDER_API_KEY_WILL_BE_SHARED_BY_OPL',
1507
+ 'Request-type': 'POST'
 
 
1508
  }
1509
  });
1510
 
1511
+ // User said Response structure: { "appIicationid": ..., "message": ..., "data": { ... } }
1512
+ const { data } = response.data;
1513
 
1514
+ if (!data) {
1515
+ throw new Error('External API did not return data');
1516
  }
1517
 
1518
+ // 3. Save Data directly
1519
+ const result = await processAndSaveBorrowerData(data, applicationId);
1520
 
1521
  return {
1522
  success: true,
 
1594
 
1595
  // Decrypt and Parse B2C encrypted string to JSON and Save directly to Cases
1596
  // Helper function to process and save borrower data
1597
+ // Helper function to process and save borrower data
1598
+ async function processAndSaveBorrowerData(jsonData, appId) {
1599
+ // No transformation needed, save directly to new fields
 
 
 
 
 
 
1600
 
1601
  // Create case data with your exact schema using the main Case model
1602
  const caseData = {
1603
  case_id: uuidv4(),
1604
+ application_id: appId || jsonData.applicationId || jsonData.appIicationid, // Handle both spellings
1605
+ case_applicant_name: jsonData.applicantDetail?.name || '',
1606
+ case_applicant_contact: jsonData.applicantDetail?.mobile || '',
1607
+ address: jsonData.residenceDetail ? `${jsonData.residenceDetail.address1}, ${jsonData.residenceDetail.cityId}` : '', // Simplified address for main field
1608
+ case_type: "Business Loan", // Default
1609
+ loan_amount: jsonData.incomeExpenditure?.yearlyIncome || 0,
1610
+ priority: "MED",
1611
+ assigned_agent: "",
1612
+ status: "Pending",
1613
+
1614
+ // Save the full detailed structures
1615
+ applicantDetail: jsonData.applicantDetail,
1616
+ residenceDetail: jsonData.residenceDetail,
1617
+ coApplicantDetail: jsonData.coApplicantDetail,
1618
+ businessDetail: jsonData.businessDetail,
1619
+ incomeExpenditure: jsonData.incomeExpenditure,
1620
+ familyExpenses: jsonData.familyExpenses,
1621
+ metaData: jsonData.metaData,
1622
+
1623
+ remarks: `Application ID: ${appId || jsonData.applicationId || jsonData.appIicationid} - Auto imported`,
1624
  created_at: new Date(),
1625
  updated_at: new Date()
1626
  };
 
1630
 
1631
  return {
1632
  case_id: newCase.case_id,
1633
+ application_id: appId || jsonData.applicationId || jsonData.appIicationid,
1634
  saved_data: caseData
1635
  };
1636
  }
 
1674
  }
1675
  });
1676
 
1677
+ // Webhook Automation Endpoint
1678
  // Webhook Automation Endpoint
1679
  app.post('/api/webhook/automation', async (req, res) => {
1680
  try {
 
1689
  });
1690
  }
1691
 
1692
+ // 1. Call external API directly
 
 
 
 
 
1693
  const externalApiUrl = 'https://qa-uapmp.instantmseloans.in/gateway/loans/msme/uapmp/v1/getBorrowerdetails';
1694
+
1695
  const response = await axios.post(externalApiUrl, {
1696
+ appIicationid: applicationId
1697
  }, {
1698
  headers: {
1699
  'Content-Type': 'application/json',
1700
+ 'User-name': 'Biz2x',
1701
+ 'api-key': process.env.OPL_API_KEY || 'PLACEHOLDER_API_KEY_WILL_BE_SHARED_BY_OPL',
1702
+ 'Request-type': 'POST'
 
 
1703
  }
1704
  });
1705
 
1706
+ const { data } = response.data;
1707
 
1708
+ if (!data) {
1709
+ throw new Error('External API did not return data');
1710
  }
1711
 
1712
+ // 3. Save Data directly
1713
+ const result = await processAndSaveBorrowerData(data, applicationId);
1714
 
1715
  res.json({
1716
  success: true,
 
1728
  }
1729
  });
1730
 
1731
+ // Removed transformToBackendStructure as it is no longer needed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1732
 
1733
 
1734
 
models.js CHANGED
@@ -56,7 +56,7 @@
56
  // // default: 'Unassigned',
57
  // // enum: ['Completed', 'In Progress', 'Pending', 'Unassigned']
58
  // // },
59
-
60
  // // // Demographic Details
61
  // // demographic_details: {
62
  // // aadhaar_photo_match: { type: Boolean, default: null },
@@ -80,7 +80,7 @@
80
  // // },
81
  // // residence_photo_id: String
82
  // // },
83
-
84
  // // // Business Details
85
  // // business_details: {
86
  // // enterprise_information: {
@@ -110,7 +110,7 @@
110
  // // additional_business: { type: String, enum: ['Yes', 'No'] }
111
  // // }
112
  // // },
113
-
114
  // // // Financial Details
115
  // // financial_details: {
116
  // // business_financial_information: {
@@ -126,7 +126,7 @@
126
  // // monthly_family_expense: Number
127
  // // }
128
  // // },
129
-
130
  // // created_at: { type: Date, default: Date.now },
131
  // // assigned_at: Date,
132
  // // accepted_at: Date,
@@ -219,7 +219,7 @@
219
  // default: 'Unassigned',
220
  // enum: ['Completed', 'In Progress', 'Pending', 'Unassigned']
221
  // },
222
-
223
  // // Demographic Details
224
  // demographic_details: {
225
  // aadhaar_photo_match: { type: Boolean, default: null },
@@ -243,7 +243,7 @@
243
  // },
244
  // residence_photo_id: String
245
  // },
246
-
247
  // // Business Details
248
  // business_details: {
249
  // enterprise_information: {
@@ -273,7 +273,7 @@
273
  // additional_business: { type: String, enum: ['Yes', 'No'] }
274
  // }
275
  // },
276
-
277
  // // Financial Details
278
  // financial_details: {
279
  // business_financial_information: {
@@ -289,7 +289,7 @@
289
  // monthly_family_expense: Number
290
  // }
291
  // },
292
-
293
  // created_at: { type: Date, default: Date.now },
294
  // assigned_at: Date,
295
  // accepted_at: Date,
@@ -371,12 +371,12 @@ const agentSchema = new mongoose.Schema({
371
  // Case Schema with all sections
372
  const caseSchema = new mongoose.Schema({
373
  case_id: { type: String, required: true, unique: true },
374
- application_id : { type: String, required: true },
375
  case_applicant_name: { type: String, required: true },
376
  case_applicant_contact: { type: String, required: true },
377
  address: { type: String, required: true },
378
- case_type: {
379
- type: String,
380
  required: true
381
  },
382
  loan_amount: { type: Number, default: 0 },
@@ -386,88 +386,29 @@ const caseSchema = new mongoose.Schema({
386
  enum: ['LOW', 'MED', 'HIGH']
387
  },
388
  assigned_agent: { type: String, default: null },
389
- status: {
390
- type: String,
391
  default: 'Unassigned',
392
  enum: ['Completed', 'In Progress', 'Pending', 'Unassigned']
393
  },
394
-
395
- // Demographic Details
396
- demographic_details: {
397
- aadhaar_photo_match: { type: Boolean, default: null },
398
- contact_information: {
399
- email_id: String,
400
- mobile_number: String
401
- },
402
- personal_details: {
403
- gender: String,
404
- education: String,
405
- number_of_family_members: Number
406
- },
407
- customer_photo_id: String,
408
- address_details: {
409
- residence_address_type: String,
410
- residential_address: String,
411
- city: String,
412
- state: String,
413
- district: String,
414
- pincode: String
415
- },
416
- residence_photo_id: String
417
- },
418
-
419
- // Business Details
420
- business_details: {
421
- enterprise_information: {
422
- enterprise_name: String,
423
- type_of_organization: String
424
- },
425
- business_location_details: {
426
- business_address_type: String,
427
- business_location: String
428
- },
429
- business_address: {
430
- address: String,
431
- city: String,
432
- district: String,
433
- state: String,
434
- pincode: String,
435
- landmark: String
436
- },
437
- business_address_photo_id: String,
438
- business_activity: {
439
- business_activity: String,
440
- activity_type: String
441
- },
442
- business_info: {
443
- employee_count: Number,
444
- years_of_running_business: Number,
445
- additional_business: String
446
- }
447
- },
448
-
449
- // Financial Details
450
- financial_details: {
451
- business_financial_information: {
452
- monthly_income_from_business: Number,
453
- monthly_expense_of_business: Number
454
- },
455
- loans_and_emis: {
456
- current_loans_emis: String
457
- },
458
- family_financial_information: {
459
- monthly_family_income: Number,
460
- number_of_working_members: Number,
461
- monthly_family_expense: Number
462
- }
463
- },
464
-
465
  created_at: { type: Date, default: Date.now },
466
  assigned_at: Date,
467
  accepted_at: Date,
468
  completed_at: Date,
469
  updated_at: { type: Date, default: Date.now },
470
- remarks: String
 
 
 
 
 
 
 
 
 
471
  });
472
 
473
  // File Schema
@@ -497,23 +438,10 @@ const caseCreationWebhookSchema = new mongoose.Schema({
497
  user_agent: String
498
  });
499
 
500
- // NEW: Borrower Case Schema - Simplified schema for storing API data directly
501
- const borrowerCaseSchema = new mongoose.Schema({
502
- case_id: { type: String, required: true, unique: true },
503
- application_id: { type: Number, required: true },
504
- borrower_data: { type: mongoose.Schema.Types.Mixed, required: true }, // Stores the entire 'data' JSON
505
- created_at: { type: Date, default: Date.now },
506
- updated_at: { type: Date, default: Date.now }
507
- }, {
508
- collection: 'cases', // This will use the same 'cases' collection
509
- strict: false // Allows storing any JSON structure
510
- });
511
-
512
  const CaseCreationWebhook = mongoose.model('CaseCreationWebhook', caseCreationWebhookSchema);
513
  const Admin = mongoose.model('Admin', adminSchema);
514
  const Agent = mongoose.model('Agent', agentSchema);
515
  const Case = mongoose.model('Case', caseSchema);
516
  const File = mongoose.model('File', fileSchema);
517
- const BorrowerCase = mongoose.model('BorrowerCase', borrowerCaseSchema);
518
 
519
- module.exports = { connectDB, Admin, Agent, Case, File, CaseCreationWebhook, BorrowerCase };
 
56
  // // default: 'Unassigned',
57
  // // enum: ['Completed', 'In Progress', 'Pending', 'Unassigned']
58
  // // },
59
+
60
  // // // Demographic Details
61
  // // demographic_details: {
62
  // // aadhaar_photo_match: { type: Boolean, default: null },
 
80
  // // },
81
  // // residence_photo_id: String
82
  // // },
83
+
84
  // // // Business Details
85
  // // business_details: {
86
  // // enterprise_information: {
 
110
  // // additional_business: { type: String, enum: ['Yes', 'No'] }
111
  // // }
112
  // // },
113
+
114
  // // // Financial Details
115
  // // financial_details: {
116
  // // business_financial_information: {
 
126
  // // monthly_family_expense: Number
127
  // // }
128
  // // },
129
+
130
  // // created_at: { type: Date, default: Date.now },
131
  // // assigned_at: Date,
132
  // // accepted_at: Date,
 
219
  // default: 'Unassigned',
220
  // enum: ['Completed', 'In Progress', 'Pending', 'Unassigned']
221
  // },
222
+
223
  // // Demographic Details
224
  // demographic_details: {
225
  // aadhaar_photo_match: { type: Boolean, default: null },
 
243
  // },
244
  // residence_photo_id: String
245
  // },
246
+
247
  // // Business Details
248
  // business_details: {
249
  // enterprise_information: {
 
273
  // additional_business: { type: String, enum: ['Yes', 'No'] }
274
  // }
275
  // },
276
+
277
  // // Financial Details
278
  // financial_details: {
279
  // business_financial_information: {
 
289
  // monthly_family_expense: Number
290
  // }
291
  // },
292
+
293
  // created_at: { type: Date, default: Date.now },
294
  // assigned_at: Date,
295
  // accepted_at: Date,
 
371
  // Case Schema with all sections
372
  const caseSchema = new mongoose.Schema({
373
  case_id: { type: String, required: true, unique: true },
374
+ application_id: { type: String, required: true },
375
  case_applicant_name: { type: String, required: true },
376
  case_applicant_contact: { type: String, required: true },
377
  address: { type: String, required: true },
378
+ case_type: {
379
+ type: String,
380
  required: true
381
  },
382
  loan_amount: { type: Number, default: 0 },
 
386
  enum: ['LOW', 'MED', 'HIGH']
387
  },
388
  assigned_agent: { type: String, default: null },
389
+ status: {
390
+ type: String,
391
  default: 'Unassigned',
392
  enum: ['Completed', 'In Progress', 'Pending', 'Unassigned']
393
  },
394
+
395
+ // Legacy fields removed: demographic_details, business_details, financial_details
396
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  created_at: { type: Date, default: Date.now },
398
  assigned_at: Date,
399
  accepted_at: Date,
400
  completed_at: Date,
401
  updated_at: { type: Date, default: Date.now },
402
+ remarks: String,
403
+
404
+ // New fields for UAPMP API integration
405
+ applicantDetail: { type: mongoose.Schema.Types.Mixed },
406
+ residenceDetail: { type: mongoose.Schema.Types.Mixed },
407
+ coApplicantDetail: { type: mongoose.Schema.Types.Mixed },
408
+ businessDetail: { type: mongoose.Schema.Types.Mixed },
409
+ incomeExpenditure: { type: mongoose.Schema.Types.Mixed },
410
+ familyExpenses: { type: mongoose.Schema.Types.Mixed },
411
+ metaData: { type: mongoose.Schema.Types.Mixed }
412
  });
413
 
414
  // File Schema
 
438
  user_agent: String
439
  });
440
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  const CaseCreationWebhook = mongoose.model('CaseCreationWebhook', caseCreationWebhookSchema);
442
  const Admin = mongoose.model('Admin', adminSchema);
443
  const Agent = mongoose.model('Agent', agentSchema);
444
  const Case = mongoose.model('Case', caseSchema);
445
  const File = mongoose.model('File', fileSchema);
 
446
 
447
+ module.exports = { connectDB, Admin, Agent, Case, File, CaseCreationWebhook };
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
readme-2.md ADDED
@@ -0,0 +1,611 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CPV Platform API Documentation
2
+
3
+ **Base URL:** `https://cpv-b2c-apis-117274959277.asia-south1.run.app`
4
+
5
+ **Authentication:** JWT Token in Authorization header: `Bearer <token>`
6
+
7
+ ---
8
+
9
+ ## 1. Admin Endpoints
10
+
11
+ ### 1.1 Create Admin
12
+ - **Endpoint:** `/api/admin/create`
13
+ - **Method:** `POST`
14
+ - **Auth Required:** No
15
+ - **Request Body:**
16
+ ```json
17
+ {
18
+ "name": "Admin Name",
19
+ "email": "admin@example.com",
20
+ "password": "SecurePass123"
21
+ }
22
+ ```
23
+ - **Response:**
24
+ ```json
25
+ {
26
+ "message": "Admin created successfully",
27
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
28
+ "admin": {
29
+ "admin_id": "uuid-here",
30
+ "name": "Admin Name",
31
+ "email": "admin@example.com"
32
+ }
33
+ }
34
+ ```
35
+
36
+ ### 1.2 Admin Login
37
+ - **Endpoint:** `/api/admin/login`
38
+ - **Method:** `POST`
39
+ - **Auth Required:** No
40
+ - **Request Body:**
41
+ ```json
42
+ {
43
+ "email": "admin@example.com",
44
+ "password": "SecurePass123"
45
+ }
46
+ ```
47
+ - **Response:**
48
+ ```json
49
+ {
50
+ "message": "Login successful",
51
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
52
+ "admin": {
53
+ "admin_id": "uuid-here",
54
+ "name": "Admin Name",
55
+ "email": "admin@example.com"
56
+ }
57
+ }
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 2. Agent Endpoints
63
+
64
+ ### 2.1 Create Agent (Admin Only)
65
+ - **Endpoint:** `/api/agents`
66
+ - **Method:** `POST`
67
+ - **Auth Required:** Yes (Admin)
68
+ - **Request Body:**
69
+ ```json
70
+ {
71
+ "agent_name": "Agent Name",
72
+ "agent_email": "agent@example.com",
73
+ "contact_number": "9876543210",
74
+ "password": "AgentPass123"
75
+ }
76
+ ```
77
+ - **Response:**
78
+ ```json
79
+ {
80
+ "message": "Agent created successfully",
81
+ "agent": {
82
+ "agent_id": "uuid-here",
83
+ "agent_name": "Agent Name",
84
+ "agent_email": "agent@example.com",
85
+ "contact_number": "9876543210"
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### 2.2 Agent Login
91
+ - **Endpoint:** `/api/agents/login`
92
+ - **Method:** `POST`
93
+ - **Auth Required:** No
94
+ - **Request Body:**
95
+ ```json
96
+ {
97
+ "email": "agent@example.com",
98
+ "password": "AgentPass123"
99
+ }
100
+ ```
101
+ - **Response:**
102
+ ```json
103
+ {
104
+ "message": "Login successful",
105
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
106
+ "agent": {
107
+ "agent_id": "uuid-here",
108
+ "agent_name": "Agent Name",
109
+ "agent_email": "agent@example.com",
110
+ "contact_number": "9876543210"
111
+ }
112
+ }
113
+ ```
114
+
115
+ ### 2.3 Get All Agents (Admin Only)
116
+ - **Endpoint:** `/api/agents`
117
+ - **Method:** `GET`
118
+ - **Auth Required:** Yes (Admin)
119
+ - **Response:**
120
+ ```json
121
+ {
122
+ "agents": [
123
+ {
124
+ "agent_id": "uuid-here",
125
+ "agent_name": "Agent Name",
126
+ "agent_email": "agent@example.com",
127
+ "contact_number": "9876543210",
128
+ "status": "active",
129
+ "created_at": "2024-01-15T10:30:00.000Z"
130
+ }
131
+ ]
132
+ }
133
+ ```
134
+
135
+ ### 2.4 Get Single Agent
136
+ - **Endpoint:** `/api/agents/:agent_id`
137
+ - **Method:** `GET`
138
+ - **Auth Required:** Yes
139
+ - **Response:**
140
+ ```json
141
+ {
142
+ "agent_id": "uuid-here",
143
+ "agent_name": "Agent Name",
144
+ "agent_email": "agent@example.com",
145
+ "contact_number": "9876543210",
146
+ "status": "active",
147
+ "created_at": "2024-01-15T10:30:00.000Z"
148
+ }
149
+ ```
150
+
151
+ ### 2.5 Update Agent (Admin Only)
152
+ - **Endpoint:** `/api/agents/:agent_id`
153
+ - **Method:** `PUT`
154
+ - **Auth Required:** Yes (Admin)
155
+ - **Request Body:**
156
+ ```json
157
+ {
158
+ "agent_name": "Updated Name",
159
+ "contact_number": "9988776655",
160
+ "status": "active"
161
+ }
162
+ ```
163
+ - **Response:**
164
+ ```json
165
+ {
166
+ "message": "Agent updated",
167
+ "agent": {
168
+ "agent_id": "uuid-here",
169
+ "agent_name": "Updated Name",
170
+ "contact_number": "9988776655",
171
+ "status": "active"
172
+ }
173
+ }
174
+ ```
175
+
176
+ ### 2.6 Delete Agent (Admin Only)
177
+ - **Endpoint:** `/api/agents/:agent_id`
178
+ - **Method:** `DELETE`
179
+ - **Auth Required:** Yes (Admin)
180
+ - **Response:**
181
+ ```json
182
+ {
183
+ "message": "Agent deleted"
184
+ }
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 3. Case Endpoints
190
+
191
+ ### 3.1 Create Case
192
+ - **Endpoint:** `/api/cases`
193
+ - **Method:** `POST`
194
+ - **Auth Required:** Yes (Agent or Admin)
195
+ - **Request Body:**
196
+ ```json
197
+ {
198
+ "case_applicant_name": "John Doe",
199
+ "case_applicant_contact": "9876543210",
200
+ "address": "123 Main Street, Mumbai",
201
+ "case_type": "Business Loan",
202
+ "priority": "MED",
203
+ "loan_amount": 500000
204
+ }
205
+ ```
206
+ - **Response:**
207
+ ```json
208
+ {
209
+ "message": "Case created successfully",
210
+ "case_id": "case-uuid-here"
211
+ }
212
+ ```
213
+
214
+ ### 3.2 Get All Cases
215
+ - **Endpoint:** `/api/cases`
216
+ - **Method:** `GET`
217
+ - **Auth Required:** Yes
218
+ - **Query Params:** `?status=In Progress&case_type=Business Loan&priority=HIGH`
219
+ - **Response:**
220
+ ```json
221
+ {
222
+ "cases": [
223
+ {
224
+ "case_id": "case-uuid-here",
225
+ "case_applicant_name": "John Doe",
226
+ "case_applicant_contact": "9876543210",
227
+ "address": "123 Main Street, Mumbai",
228
+ "case_type": "Business Loan",
229
+ "loan_amount": 500000,
230
+ "priority": "MED",
231
+ "status": "In Progress",
232
+ "assigned_agent": "agent-uuid",
233
+ "created_at": "2024-01-15T10:30:00.000Z",
234
+ "updated_at": "2024-01-15T14:20:00.000Z"
235
+ }
236
+ ]
237
+ }
238
+ ```
239
+
240
+ ### 3.3 Get Single Case
241
+ - **Endpoint:** `/api/cases/:case_id`
242
+ - **Method:** `GET`
243
+ - **Auth Required:** Yes
244
+ - **Response:**
245
+ ```json
246
+ {
247
+ "case_id": "case-uuid-here",
248
+ "case_applicant_name": "John Doe",
249
+ "case_applicant_contact": "9876543210",
250
+ "address": "123 Main Street, Mumbai",
251
+ "case_type": "Business Loan",
252
+ "loan_amount": 500000,
253
+ "priority": "MED",
254
+ "status": "Pending",
255
+ "assigned_agent": "agent-uuid",
256
+ "remarks": "Verification in progress",
257
+ "demographic_details": {},
258
+ "business_details": {},
259
+ "financial_details": {},
260
+ "created_at": "2024-01-15T10:30:00.000Z",
261
+ "assigned_at": "2024-01-15T11:00:00.000Z",
262
+ "accepted_at": "2024-01-15T11:30:00.000Z",
263
+ "updated_at": "2024-01-15T14:20:00.000Z"
264
+ }
265
+ ```
266
+
267
+ ### 3.4 Assign Case to Agent (Admin Only)
268
+ - **Endpoint:** `/api/cases/:case_id/assign`
269
+ - **Method:** `PUT`
270
+ - **Auth Required:** Yes (Admin)
271
+ - **Request Body:**
272
+ ```json
273
+ {
274
+ "agent_id": "agent-uuid-here"
275
+ }
276
+ ```
277
+ - **Response:**
278
+ ```json
279
+ {
280
+ "message": "Case assigned successfully",
281
+ "case": {
282
+ "case_id": "case-uuid-here",
283
+ "assigned_agent": "agent-uuid-here",
284
+ "status": "In Progress",
285
+ "assigned_at": "2024-01-15T11:00:00.000Z"
286
+ }
287
+ }
288
+ ```
289
+
290
+ ### 3.5 Accept Case (Agent Only) ⭐ NEW
291
+ - **Endpoint:** `/api/cases/:case_id/accept`
292
+ - **Method:** `PUT`
293
+ - **Auth Required:** Yes (Agent)
294
+ - **Request Body:** None
295
+ - **Response:**
296
+ ```json
297
+ {
298
+ "message": "Case accepted successfully",
299
+ "case": {
300
+ "case_id": "case-uuid-here",
301
+ "case_applicant_name": "John Doe",
302
+ "status": "Pending",
303
+ "assigned_agent": "agent-uuid-here",
304
+ "accepted_at": "2024-01-15T11:30:00.000Z",
305
+ "updated_at": "2024-01-15T11:30:00.000Z"
306
+ }
307
+ }
308
+ ```
309
+
310
+ ### 3.6 Update Case (Complete or Partial)
311
+ - **Endpoint:** `/api/cases/:case_id`
312
+ - **Method:** `PUT`
313
+ - **Auth Required:** Yes (Agent or Admin)
314
+ - **Request Body (Example - Update Demographics):**
315
+ ```json
316
+ {
317
+ "demographic_details": {
318
+ "aadhaar_photo_match": true,
319
+ "contact_information": {
320
+ "email_id": "john@example.com",
321
+ "mobile_number": "9876543210"
322
+ },
323
+ "personal_details": {
324
+ "gender": "Male",
325
+ "education": "Graduate",
326
+ "number_of_family_members": 4
327
+ },
328
+ "address_details": {
329
+ "residence_address_type": "Own",
330
+ "residential_address": "123 Main Street",
331
+ "city": "Mumbai",
332
+ "state": "Maharashtra",
333
+ "district": "Mumbai Suburban",
334
+ "pincode": "400001"
335
+ }
336
+ }
337
+ }
338
+ ```
339
+ - **Response:**
340
+ ```json
341
+ {
342
+ "message": "Case updated successfully",
343
+ "case": {
344
+ "case_id": "case-uuid-here",
345
+ "status": "Pending",
346
+ "updated_at": "2024-01-15T15:00:00.000Z"
347
+ }
348
+ }
349
+ ```
350
+
351
+ ### 3.7 Update Case Section
352
+ - **Endpoint:** `/api/cases/:case_id/:section`
353
+ - **Method:** `PATCH`
354
+ - **Auth Required:** Yes (Agent or Admin)
355
+ - **Sections:** `demographic_details`, `business_details`, `financial_details`
356
+ - **Request Body:**
357
+ ```json
358
+ {
359
+ "business_financial_information": {
360
+ "monthly_income_from_business": 50000,
361
+ "monthly_expense_of_business": 30000
362
+ }
363
+ }
364
+ ```
365
+ - **Response:**
366
+ ```json
367
+ {
368
+ "message": "financial_details updated successfully",
369
+ "case": {
370
+ "case_id": "case-uuid-here",
371
+ "financial_details": {
372
+ "business_financial_information": {
373
+ "monthly_income_from_business": 50000,
374
+ "monthly_expense_of_business": 30000
375
+ }
376
+ }
377
+ }
378
+ }
379
+ ```
380
+
381
+ ### 3.8 Delete Case (Admin Only)
382
+ - **Endpoint:** `/api/cases/:case_id`
383
+ - **Method:** `DELETE`
384
+ - **Auth Required:** Yes (Admin)
385
+ - **Response:**
386
+ ```json
387
+ {
388
+ "message": "Case and associated files deleted"
389
+ }
390
+ ```
391
+
392
+ ---
393
+
394
+ ## 4. File Endpoints
395
+
396
+ ### 4.1 Upload File
397
+ - **Endpoint:** `/api/cases/:case_id/files`
398
+ - **Method:** `POST`
399
+ - **Auth Required:** Yes (Agent or Admin)
400
+ - **Content-Type:** `multipart/form-data`
401
+ - **Form Data:**
402
+ - `file`: File to upload
403
+ - `file_type`: `customer_photo`, `residence_photo`, `business_photo`, `document`
404
+ - `geo_lat`: Optional latitude
405
+ - `geo_lng`: Optional longitude
406
+ - **Response:**
407
+ ```json
408
+ {
409
+ "message": "File uploaded successfully",
410
+ "file_id": "file-uuid-here",
411
+ "filename": "photo.jpg",
412
+ "file_size": 204800,
413
+ "file_type": "customer_photo",
414
+ "uploaded_at": "2024-01-15T11:30:00.000Z"
415
+ }
416
+ ```
417
+
418
+ ### 4.2 Get All Files for Case
419
+ - **Endpoint:** `/api/cases/:case_id/files`
420
+ - **Method:** `GET`
421
+ - **Auth Required:** Yes
422
+ - **Response:**
423
+ ```json
424
+ {
425
+ "files": [
426
+ {
427
+ "file_id": "file-uuid-here",
428
+ "filename": "file-uuid_photo.jpg",
429
+ "original_name": "photo.jpg",
430
+ "file_type": "customer_photo",
431
+ "mime_type": "image/jpeg",
432
+ "file_size": 204800,
433
+ "geo_location": {
434
+ "lat": 19.0760,
435
+ "lng": 72.8777
436
+ },
437
+ "uploaded_at": "2024-01-15T11:30:00.000Z",
438
+ "uploaded_by": "agent-uuid"
439
+ }
440
+ ]
441
+ }
442
+ ```
443
+
444
+ ### 4.3 Download File
445
+ - **Endpoint:** `/api/files/:file_id`
446
+ - **Method:** `GET`
447
+ - **Auth Required:** Yes
448
+ - **Response:** Binary file data with appropriate headers
449
+
450
+ ### 4.4 Delete File
451
+ - **Endpoint:** `/api/files/:file_id`
452
+ - **Method:** `DELETE`
453
+ - **Auth Required:** Yes (Agent or Admin)
454
+ - **Response:**
455
+ ```json
456
+ {
457
+ "message": "File deleted successfully"
458
+ }
459
+ ```
460
+
461
+ ---
462
+
463
+ ## 5. Dashboard Endpoints
464
+
465
+ ### 5.1 Get Statistics
466
+ - **Endpoint:** `/api/dashboard/stats`
467
+ - **Method:** `GET`
468
+ - **Auth Required:** Yes
469
+ - **Query Params:** `?agent_id=uuid` (Admin only)
470
+ - **Response:**
471
+ ```json
472
+ {
473
+ "total": 150,
474
+ "unassigned": 20,
475
+ "in_progress": 30,
476
+ "pending": 50,
477
+ "completed": 50,
478
+ "by_case_type": {
479
+ "business_loan": 60,
480
+ "personal_loan": 40,
481
+ "credit_card": 30,
482
+ "home_loan": 20
483
+ },
484
+ "by_priority": {
485
+ "low": 40,
486
+ "med": 80,
487
+ "high": 30
488
+ },
489
+ "total_loan_amount": 75000000,
490
+ "average_loan_amount": 500000
491
+ }
492
+ ```
493
+
494
+ ### 5.2 Get Agent Performance (Admin Only)
495
+ - **Endpoint:** `/api/dashboard/agent-performance`
496
+ - **Method:** `GET`
497
+ - **Auth Required:** Yes (Admin)
498
+ - **Response:**
499
+ ```json
500
+ {
501
+ "agent_performance": [
502
+ {
503
+ "agent_id": "agent-uuid",
504
+ "agent_name": "Agent Name",
505
+ "agent_email": "agent@example.com",
506
+ "total_cases": 25,
507
+ "completed": 15,
508
+ "in_progress": 5,
509
+ "pending": 5,
510
+ "total_loan_amount": 12500000,
511
+ "average_loan_amount": 500000,
512
+ "priority_breakdown": {
513
+ "low": 5,
514
+ "med": 15,
515
+ "high": 5
516
+ }
517
+ }
518
+ ]
519
+ }
520
+ ```
521
+
522
+ ---
523
+
524
+ ## 6. Public Endpoints
525
+
526
+ ### 6.1 Health Check
527
+ - **Endpoint:** `/health`
528
+ - **Method:** `GET`
529
+ - **Auth Required:** No
530
+ - **Response:**
531
+ ```json
532
+ {
533
+ "status": "healthy",
534
+ "database": "connected",
535
+ "timestamp": "2024-01-15T12:00:00.000Z"
536
+ }
537
+ ```
538
+
539
+ ### 6.2 API Status
540
+ - **Endpoint:** `/`
541
+ - **Method:** `GET`
542
+ - **Auth Required:** No
543
+ - **Response:**
544
+ ```json
545
+ {
546
+ "status": "CPV API Running - Biz2Credit",
547
+ "timestamp": "2024-01-15T12:00:00.000Z",
548
+ "version": "2.0.0",
549
+ "authentication": "JWT Token Required for Protected Routes",
550
+ "endpoints": {
551
+ "admin": "/api/admin/*",
552
+ "agents": "/api/agents/*",
553
+ "cases": "/api/cases/*",
554
+ "files": "/api/files/*",
555
+ "dashboard": "/api/dashboard/*"
556
+ }
557
+ }
558
+ ```
559
+
560
+ ---
561
+
562
+ ## Status Flow
563
+
564
+ 1. **Unassigned** → Case created, no agent assigned
565
+ 2. **In Progress** → Admin assigns case to agent
566
+ 3. **Pending** → Agent accepts the case ⭐ NEW
567
+ 4. **Completed** → Agent marks case as completed
568
+
569
+ ## Case Types
570
+
571
+ - `Business Loan`
572
+ - `Personal Loan`
573
+ - `Credit Card`
574
+ - `Home Loan`
575
+
576
+ ## Priority Levels
577
+
578
+ - `LOW`
579
+ - `MED`
580
+ - `HIGH`
581
+
582
+ ## Error Responses
583
+
584
+ **401 Unauthorized:**
585
+ ```json
586
+ {
587
+ "error": "Access token required"
588
+ }
589
+ ```
590
+
591
+ **403 Forbidden:**
592
+ ```json
593
+ {
594
+ "error": "Admin access required"
595
+ }
596
+ ```
597
+
598
+ **404 Not Found:**
599
+ ```json
600
+ {
601
+ "error": "Case not found"
602
+ }
603
+ ```
604
+
605
+ **400 Bad Request:**
606
+ ```json
607
+ {
608
+ "error": "Validation failed",
609
+ "message": "Invalid case type"
610
+ }
611
+ ```
verify_refactor.js ADDED
@@ -0,0 +1,682 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ require('dotenv').config();
2
+ const mongoose = require('mongoose');
3
+ const { connectDB, Case } = require('./models');
4
+ const { v4: uuidv4 } = require('uuid');
5
+
6
+ async function verifyModel() {
7
+ try {
8
+ await connectDB();
9
+ console.log('Connected to DB');
10
+
11
+ // Full JSON payload from the new API
12
+ const apiResponse = {
13
+ "applicationId": 39295,
14
+ "message": "Successfully get Details !!",
15
+ "data": {
16
+ "applicantDetail": {
17
+ "userId": 135860,
18
+ "panNumber": null,
19
+ "dob": "24-11-1990",
20
+ "voterId": "ABC1234567",
21
+ "email": "parvej@gmail.com",
22
+ "mobile": "8000051783",
23
+ "alternateMobile": "8000051784",
24
+ "socialCategoryId": 1,
25
+ "aadharRefNumber": "800180018019",
26
+ "urnNumber": null,
27
+ "isFromLsp": null,
28
+ "name": "Parvez mansuri",
29
+ "genderId": 1,
30
+ "maritalStatus": 1,
31
+ "qualification": 4,
32
+ "religion": 6,
33
+ "womanEntrepreneur": 0,
34
+ "divyang": 0,
35
+ "serviceman": 0,
36
+ "fatherName": "fname",
37
+ "motherName": "mname",
38
+ "spouseName": "sname",
39
+ "spouseDob": "24-11-1992",
40
+ "numOfDependent": 4,
41
+ "illness": 7,
42
+ "primaryId": 2,
43
+ "secodaryId": 1,
44
+ "primaryDoc": 95988,
45
+ "secodaryDoc": 95989,
46
+ "applicantImg": 95990,
47
+ "urnFound": 0,
48
+ "daId": 1,
49
+ "numEarFamiMemb": 1,
50
+ "primaryFileDetail": "certificate_1758545662.pdf | 192kb | 24/11/2025",
51
+ "secondaryFileDetail": "certificate_1758545658.pdf | 192kb | 24/11/2025",
52
+ "applicantFileDetail": "certificate_1758545652.pdf | 192kb | 24/11/2025",
53
+ "addresProofDetail": "certificate_1758545631.pdf | 192kb | 24-11-2025",
54
+ "updateResiAddrss": true,
55
+ "profileId": 24306
56
+ },
57
+ "residenceDetail": {
58
+ "id": 18431,
59
+ "ownershipStatus": 2,
60
+ "address1": "test1",
61
+ "address2": "test2",
62
+ "address3": "test3",
63
+ "cityId": 783,
64
+ "districtId": 134,
65
+ "stateId": 24,
66
+ "pincode": "380001",
67
+ "addressProofType": 2,
68
+ "addressProofId": 95992,
69
+ "addresProofDetail": "certificate_1758545631.pdf | 192kb | 24-11-2025",
70
+ "updateResiAddrss": null
71
+ },
72
+ "coApplicantDetail": {
73
+ "name": "OPL",
74
+ "panNumber": null,
75
+ "email": null,
76
+ "dob": "24-11-1991",
77
+ "mobile": "8000051785",
78
+ "gender": 1,
79
+ "maritalStatus": 2,
80
+ "relationshipWithApplicantId": 6,
81
+ "occupationId": 2,
82
+ "primaryId": 2,
83
+ "secondaryId": 1,
84
+ "primaryDoc": 96005,
85
+ "secondaryDoc": 96006,
86
+ "voterId": "ABC1234567",
87
+ "applicantImg": 96007,
88
+ "sameAsResidential": false,
89
+ "ownership": null,
90
+ "address1": "test7",
91
+ "address2": null,
92
+ "address3": null,
93
+ "landmark": null,
94
+ "cityId": 783,
95
+ "districtId": 134,
96
+ "stateId": 24,
97
+ "pincode": "380001",
98
+ "applicantImgDetail": "certificate_1758545652.pdf | 192kb | 24/11/2025",
99
+ "primaryFileDetail": "certificate_1758545662.pdf | 192kb | 24/11/2025",
100
+ "secondaryFileDetail": "certificate_1758545658.pdf | 192kb | 24/11/2025"
101
+ },
102
+ "businessDetail": {
103
+ "businessName": "parvez enterprise",
104
+ "businessType": 4,
105
+ "natureActivity": 1,
106
+ "areaType": 3,
107
+ "organizationType": 1,
108
+ "establishDate": "1970-01-01",
109
+ "panNumber": "NEMPM0285K",
110
+ "businessLocation": 1,
111
+ "workExperienceInYears": 5,
112
+ "addressId": 18432,
113
+ "ownershipStatus": 1,
114
+ "address1": "test4",
115
+ "address2": null,
116
+ "landmark": null,
117
+ "cityId": 783,
118
+ "districtId": 134,
119
+ "stateId": 24,
120
+ "pincode": "380001",
121
+ "businessProofType": 1,
122
+ "businessProofDoc": 95993,
123
+ "businessProofDetail": "certificate_1758545662.pdf | 192kb | 24/11/2025",
124
+ "updateBusinessAddrss": true
125
+ },
126
+ "incomeExpenditure": {
127
+ "monthlyIncome": 60000.00,
128
+ "freqOfIncome": 2,
129
+ "incomeDays": 30,
130
+ "avgIncomeDailyBasis": 2000.00,
131
+ "yearlyIncome": 750000.00,
132
+ "incomeFromOtherSource": 0.00,
133
+ "rationCard": 0,
134
+ "totalIncome": 750000.00,
135
+ "appType": 1
136
+ },
137
+ "familyExpenses": {
138
+ "householdExp": 100000.00,
139
+ "utilityExp": 10000.00,
140
+ "eduExp": 11000.00,
141
+ "mediExp": 12000.00,
142
+ "mediExpCritical": 13000.00,
143
+ "foodExp": 14000.00,
144
+ "grocExp": 15000.00,
145
+ "cookingExp": 16000.00,
146
+ "otherExp": 17000.00,
147
+ "clothing": 18000.00,
148
+ "transpExp": 19000.00,
149
+ "otherBusiExp": 20000.00,
150
+ "totalExp": 265000.00
151
+ }
152
+ },
153
+ "metaData": {
154
+ "genderId": [
155
+ {
156
+ "id": 1,
157
+ "value": "Male"
158
+ },
159
+ {
160
+ "id": 2,
161
+ "value": "Female"
162
+ },
163
+ {
164
+ "id": 3,
165
+ "value": "Other"
166
+ }
167
+ ],
168
+ "maritalStatus": [
169
+ {
170
+ "id": 1,
171
+ "value": "Married "
172
+ },
173
+ {
174
+ "id": 2,
175
+ "value": "Unmarried"
176
+ },
177
+ {
178
+ "id": 3,
179
+ "value": "Others"
180
+ }
181
+ ],
182
+ "qualification": [
183
+ {
184
+ "id": 1,
185
+ "value": "illiterate"
186
+ },
187
+ {
188
+ "id": 2,
189
+ "value": "Upto 10"
190
+ },
191
+ {
192
+ "id": 3,
193
+ "value": "11 to 12"
194
+ },
195
+ {
196
+ "id": 4,
197
+ "value": "Graduate and Above"
198
+ }
199
+ ],
200
+ "religion": [
201
+ {
202
+ "id": 1,
203
+ "value": "Shikh"
204
+ },
205
+ {
206
+ "id": 2,
207
+ "value": "Muslim"
208
+ },
209
+ {
210
+ "id": 3,
211
+ "value": "Christian"
212
+ },
213
+ {
214
+ "id": 4,
215
+ "value": "Zoroastrian"
216
+ },
217
+ {
218
+ "id": 5,
219
+ "value": "Buddhist"
220
+ },
221
+ {
222
+ "id": 6,
223
+ "value": "Jain"
224
+ },
225
+ {
226
+ "id": 7,
227
+ "value": "Hindu"
228
+ },
229
+ {
230
+ "id": 8,
231
+ "value": "Other"
232
+ }
233
+ ],
234
+ "socialCategoryId": [
235
+ {
236
+ "id": 1,
237
+ "value": "General"
238
+ },
239
+ {
240
+ "id": 2,
241
+ "value": "SC"
242
+ },
243
+ {
244
+ "id": 3,
245
+ "value": "ST"
246
+ },
247
+ {
248
+ "id": 4,
249
+ "value": "OBC"
250
+ }
251
+ ],
252
+ "addressProofType": [
253
+ {
254
+ "id": 1,
255
+ "value": "Rent Agreement"
256
+ },
257
+ {
258
+ "id": 2,
259
+ "value": "Electricity Bill"
260
+ }
261
+ ],
262
+ "occupationId": [
263
+ {
264
+ "id": 1,
265
+ "value": "Service"
266
+ },
267
+ {
268
+ "id": 2,
269
+ "value": "Business"
270
+ },
271
+ {
272
+ "id": 3,
273
+ "value": "Other"
274
+ }
275
+ ],
276
+ "relationshipWithApplicantId": [
277
+ {
278
+ "id": 1,
279
+ "value": "Father"
280
+ },
281
+ {
282
+ "id": 2,
283
+ "value": "Mother"
284
+ },
285
+ {
286
+ "id": 3,
287
+ "value": "Brother"
288
+ },
289
+ {
290
+ "id": 4,
291
+ "value": "Sister"
292
+ },
293
+ {
294
+ "id": 5,
295
+ "value": "Spouse"
296
+ },
297
+ {
298
+ "id": 6,
299
+ "value": "Brother-in-law"
300
+ },
301
+ {
302
+ "id": 7,
303
+ "value": "Son"
304
+ },
305
+ {
306
+ "id": 8,
307
+ "value": "Daughter"
308
+ },
309
+ {
310
+ "id": 9,
311
+ "value": "Daughter-in-law"
312
+ },
313
+ {
314
+ "id": 10,
315
+ "value": "Father-in-Law"
316
+ },
317
+ {
318
+ "id": 11,
319
+ "value": "Grand daughter"
320
+ },
321
+ {
322
+ "id": 12,
323
+ "value": "Grand Father"
324
+ },
325
+ {
326
+ "id": 13,
327
+ "value": "Grand Mother"
328
+ },
329
+ {
330
+ "id": 14,
331
+ "value": "Grand Son"
332
+ },
333
+ {
334
+ "id": 15,
335
+ "value": "Mother-in-law"
336
+ },
337
+ {
338
+ "id": 16,
339
+ "value": "Sister-in law"
340
+ },
341
+ {
342
+ "id": 17,
343
+ "value": "Son-in-law"
344
+ },
345
+ {
346
+ "id": 18,
347
+ "value": "Others"
348
+ }
349
+ ],
350
+ "primaryId": [
351
+ {
352
+ "id": 1,
353
+ "value": "PAN Card"
354
+ },
355
+ {
356
+ "id": 2,
357
+ "value": "Form-60"
358
+ }
359
+ ],
360
+ "secondaryId": [
361
+ {
362
+ "id": 1,
363
+ "value": "Voter ID"
364
+ },
365
+ {
366
+ "id": 2,
367
+ "value": "PAN"
368
+ },
369
+ {
370
+ "id": 3,
371
+ "value": "Passport"
372
+ },
373
+ {
374
+ "id": 4,
375
+ "value": "Driving License"
376
+ },
377
+ {
378
+ "id": 5,
379
+ "value": "Job Card"
380
+ },
381
+ {
382
+ "id": 6,
383
+ "value": "Letter by NPR"
384
+ },
385
+ {
386
+ "id": 7,
387
+ "value": "Form-16"
388
+ }
389
+ ],
390
+ "illness": [
391
+ {
392
+ "id": 1,
393
+ "value": "Severe Organ Failure"
394
+ },
395
+ {
396
+ "id": 2,
397
+ "value": "Heart Attack"
398
+ },
399
+ {
400
+ "id": 3,
401
+ "value": "Stroke"
402
+ },
403
+ {
404
+ "id": 4,
405
+ "value": "Cancer"
406
+ },
407
+ {
408
+ "id": 5,
409
+ "value": "Kidney Failure"
410
+ },
411
+ {
412
+ "id": 6,
413
+ "value": "Organ Transplants"
414
+ },
415
+ {
416
+ "id": 7,
417
+ "value": "N/A"
418
+ }
419
+ ],
420
+ "organizationType": [
421
+ {
422
+ "id": 1,
423
+ "value": "Proprietory"
424
+ }
425
+ ],
426
+ "businessLocation": [
427
+ {
428
+ "id": 1,
429
+ "value": "Fixed"
430
+ },
431
+ {
432
+ "id": 2,
433
+ "value": "Mobile"
434
+ }
435
+ ],
436
+ "ownershipStatus": [
437
+ {
438
+ "id": 1,
439
+ "value": "Rented"
440
+ },
441
+ {
442
+ "id": 2,
443
+ "value": "Owned"
444
+ }
445
+ ],
446
+ "areaType": [
447
+ {
448
+ "id": 1,
449
+ "value": "Rural"
450
+ },
451
+ {
452
+ "id": 3,
453
+ "value": "Semi Urban"
454
+ },
455
+ {
456
+ "id": 2,
457
+ "value": "Urban"
458
+ }
459
+ ],
460
+ "businessType": [
461
+ {
462
+ "id": 1,
463
+ "value": "Manufacturing"
464
+ },
465
+ {
466
+ "id": 2,
467
+ "value": "Services"
468
+ },
469
+ {
470
+ "id": 3,
471
+ "value": "Services-Trading"
472
+ },
473
+ {
474
+ "id": 4,
475
+ "value": "Other"
476
+ }
477
+ ],
478
+ "workExperienceInYears": [
479
+ {
480
+ "id": 1,
481
+ "value": "1"
482
+ },
483
+ {
484
+ "id": 2,
485
+ "value": "2"
486
+ },
487
+ {
488
+ "id": 3,
489
+ "value": "3"
490
+ },
491
+ {
492
+ "id": 4,
493
+ "value": "4"
494
+ },
495
+ {
496
+ "id": 5,
497
+ "value": "5"
498
+ },
499
+ {
500
+ "id": 6,
501
+ "value": "6"
502
+ },
503
+ {
504
+ "id": 7,
505
+ "value": "7"
506
+ },
507
+ {
508
+ "id": 8,
509
+ "value": "8"
510
+ },
511
+ {
512
+ "id": 9,
513
+ "value": "9"
514
+ },
515
+ {
516
+ "id": 10,
517
+ "value": "10"
518
+ },
519
+ {
520
+ "id": 11,
521
+ "value": "11"
522
+ },
523
+ {
524
+ "id": 12,
525
+ "value": "12"
526
+ },
527
+ {
528
+ "id": 13,
529
+ "value": "13"
530
+ },
531
+ {
532
+ "id": 14,
533
+ "value": "14"
534
+ },
535
+ {
536
+ "id": 15,
537
+ "value": "More than 15"
538
+ }
539
+ ],
540
+ "applicantDetail": {
541
+ "daId": [
542
+ {
543
+ "id": null,
544
+ "value": null
545
+ }
546
+ ]
547
+ },
548
+ "businessDetail": {
549
+ "districtId": [
550
+ {
551
+ "id": 134,
552
+ "value": "AHMADABAD"
553
+ }
554
+ ],
555
+ "stateId": [
556
+ {
557
+ "id": 24,
558
+ "value": "Meghalaya"
559
+ }
560
+ ],
561
+ "natureActivity": [
562
+ {
563
+ "id": 1,
564
+ "value": "Retail sale of seeds, fertilisers, pesticides, machinery equipments and hand tools"
565
+ }
566
+ ],
567
+ "cityId": [
568
+ {
569
+ "id": 783,
570
+ "value": "Ahmedabad"
571
+ }
572
+ ]
573
+ },
574
+ "coApplicantDetail": {
575
+ "districtId": [
576
+ {
577
+ "id": 134,
578
+ "value": "AHMADABAD"
579
+ }
580
+ ],
581
+ "stateId": [
582
+ {
583
+ "id": 24,
584
+ "value": "Meghalaya"
585
+ }
586
+ ],
587
+ "cityId": [
588
+ {
589
+ "id": 783,
590
+ "value": "Ahmedabad"
591
+ }
592
+ ]
593
+ },
594
+ "residenceDetail": {
595
+ "districtId": [
596
+ {
597
+ "id": 134,
598
+ "value": "AHMADABAD"
599
+ }
600
+ ],
601
+ "stateId": [
602
+ {
603
+ "id": 24,
604
+ "value": "Meghalaya"
605
+ }
606
+ ],
607
+ "cityId": [
608
+ {
609
+ "id": 783,
610
+ "value": "Ahmedabad"
611
+ }
612
+ ]
613
+ }
614
+ },
615
+ "status": 200,
616
+ "success": true
617
+ };
618
+
619
+ const jsonData = apiResponse.data;
620
+ const appId = apiResponse.applicationId || apiResponse.appIicationid;
621
+
622
+ // Simulate the logic from index.js processAndSaveBorrowerData
623
+ const caseData = {
624
+ case_id: uuidv4(),
625
+ application_id: appId,
626
+ case_applicant_name: jsonData.applicantDetail?.name || '',
627
+ case_applicant_contact: jsonData.applicantDetail?.mobile || '',
628
+ address: jsonData.residenceDetail ? `${jsonData.residenceDetail.address1}, ${jsonData.residenceDetail.cityId}` : '',
629
+ case_type: "Business Loan",
630
+ loan_amount: jsonData.incomeExpenditure?.yearlyIncome || 0,
631
+ priority: "MED",
632
+ assigned_agent: "",
633
+ status: "Pending",
634
+
635
+ // Save the full detailed structures
636
+ applicantDetail: jsonData.applicantDetail,
637
+ residenceDetail: jsonData.residenceDetail,
638
+ coApplicantDetail: jsonData.coApplicantDetail,
639
+ businessDetail: jsonData.businessDetail,
640
+ incomeExpenditure: jsonData.incomeExpenditure,
641
+ familyExpenses: jsonData.familyExpenses,
642
+ metaData: jsonData.metaData,
643
+
644
+ remarks: `Application ID: ${appId} - Verification Test`,
645
+ created_at: new Date(),
646
+ updated_at: new Date()
647
+ };
648
+
649
+ console.log('Attempting to save case with full API payload...');
650
+ const newCase = new Case(caseData);
651
+ await newCase.save();
652
+ console.log('✅ Case saved successfully!');
653
+ console.log('Saved Case ID:', newCase.case_id);
654
+
655
+ // Verify retrieval
656
+ const savedCase = await Case.findOne({ case_id: newCase.case_id });
657
+
658
+ // Verify specific fields
659
+ if (savedCase.applicantDetail && savedCase.applicantDetail.name === "Parvez mansuri") {
660
+ console.log('✅ Data retrieval verified: applicantDetail.name is correct.');
661
+ } else {
662
+ console.error(`❌ Data retrieval failed: applicantDetail.name mismatch. Expected "Parvez mansuri", got "${savedCase.applicantDetail?.name}"`);
663
+ }
664
+
665
+ if (savedCase.businessDetail && savedCase.businessDetail.businessName === "parvez enterprise") {
666
+ console.log('✅ Data retrieval verified: businessDetail.businessName is correct.');
667
+ } else {
668
+ console.error(`❌ Data retrieval failed: businessDetail.businessName mismatch. Expected "parvez enterprise", got "${savedCase.businessDetail?.businessName}"`);
669
+ }
670
+
671
+ // Cleanup
672
+ await Case.deleteOne({ case_id: newCase.case_id });
673
+ console.log('Cleanup done.');
674
+
675
+ process.exit(0);
676
+ } catch (error) {
677
+ console.error('❌ Verification failed:', error);
678
+ process.exit(1);
679
+ }
680
+ }
681
+
682
+ verifyModel();