tango-app-api-audit 3.6.26 → 3.6.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-audit",
3
- "version": "3.6.26",
3
+ "version": "3.6.27",
4
4
  "description": "audit & audit metrics apis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -13,7 +13,6 @@
13
13
  "author": "praveenraj",
14
14
  "license": "ISC",
15
15
  "dependencies": {
16
- "@aws-sdk/client-ses": "^3.918.0",
17
16
  "adm-zip": "^0.5.15",
18
17
  "aws-sdk": "^2.1643.0",
19
18
  "axios": "^1.7.9",
@@ -25,7 +24,6 @@
25
24
  "joi-to-swagger": "^6.2.0",
26
25
  "lodash": "^4.17.21",
27
26
  "mongodb": "^6.7.0",
28
- "nodemailer": "^7.0.10",
29
27
  "nodemon": "^3.1.3",
30
28
  "swagger-ui-express": "^5.0.1",
31
29
  "tango-api-schema": "^2.3.28",
@@ -609,7 +609,7 @@ export async function getAuditFile( req, res ) {
609
609
  const getQuery = msg.audit_type =='ReAudit'?
610
610
  {
611
611
  size: inputData?.limit || 500,
612
- _source: [ 'module', 'status', 'date', 'store_id', 'outputCluster', 'personPath', 'REIDCluster', 'isEmployee', 'isJunk', 'EmployeeStatusFinal' ], // Only fetch necessary fields
612
+ _source: [ 'module', 'status', 'date', 'store_id', 'outputCluster', 'personPath', 'REIDCluster', 'isEmployee', 'isJunk', 'EmployeeStatusFinal', 'entry_time' ], // Only fetch necessary fields
613
613
 
614
614
  query: {
615
615
  bool: {
@@ -638,13 +638,13 @@ export async function getAuditFile( req, res ) {
638
638
  },
639
639
  },
640
640
  sort: [
641
- { timestamp: { order: 'desc' } },
641
+ { entry_time: { order: 'desc' } },
642
642
  ],
643
643
 
644
644
  }:
645
645
  {
646
646
  size: inputData?.limit || 500,
647
- _source: [ 'module', 'status', 'date', 'store_id', 'personPath', 'REIDCluster', 'EmployeeStatusProposed', 'isJunk', 'EmployeeStatusFinal' ], // Only fetch necessary fields
647
+ _source: [ 'module', 'status', 'date', 'store_id', 'personPath', 'REIDCluster', 'EmployeeStatusProposed', 'isJunk', 'EmployeeStatusFinal', 'entry_time' ], // Only fetch necessary fields
648
648
 
649
649
  query: {
650
650
  bool: {
@@ -668,7 +668,7 @@ export async function getAuditFile( req, res ) {
668
668
  },
669
669
  },
670
670
  sort: [
671
- { timestamp: { order: 'desc' } },
671
+ { entry_time: { order: 'desc' } },
672
672
  ],
673
673
 
674
674
  };
@@ -4490,7 +4490,7 @@ export async function auditImages( req, res ) {
4490
4490
  case 'BC':
4491
4491
  const getQuery = {
4492
4492
  size: 10000,
4493
- _source: [ 'module', 'status', 'date', 'store_id', 'personPath', 'REIDCluster', 'EmployeeStatusProposed', 'isJunk', 'EmployeeStatusFinal' ], // Only fetch necessary fields
4493
+ _source: [ 'module', 'status', 'date', 'store_id', 'personPath', 'REIDCluster', 'EmployeeStatusProposed', 'isJunk', 'EmployeeStatusFinal', 'entry_time' ], // Only fetch necessary fields
4494
4494
 
4495
4495
  query: {
4496
4496
  bool: {
@@ -4515,7 +4515,7 @@ export async function auditImages( req, res ) {
4515
4515
  },
4516
4516
 
4517
4517
  sort: [
4518
- { timestamp: { order: 'desc' } },
4518
+ { entry_time: { order: 'desc' } },
4519
4519
  ],
4520
4520
  };
4521
4521
  const files = [];
@@ -4565,7 +4565,7 @@ export async function auditImages( req, res ) {
4565
4565
 
4566
4566
  const getACQuery = {
4567
4567
  size: 10000,
4568
- _source: [ 'module', 'status', 'date', 'store_id', 'outputCluster', 'personPath', 'REIDCluster', 'isEmployee', 'isJunk', 'EmployeeStatusFinal' ], // Only fetch necessary fields
4568
+ _source: [ 'module', 'status', 'date', 'store_id', 'outputCluster', 'personPath', 'REIDCluster', 'isEmployee', 'isJunk', 'EmployeeStatusFinal', 'entry_time' ], // Only fetch necessary fields
4569
4569
 
4570
4570
  query: {
4571
4571
  bool: {
@@ -4594,7 +4594,7 @@ export async function auditImages( req, res ) {
4594
4594
  },
4595
4595
  },
4596
4596
  sort: [
4597
- { timestamp: { order: 'desc' } },
4597
+ { entry_time: { order: 'desc' } },
4598
4598
  ],
4599
4599
 
4600
4600
  };
@@ -8,7 +8,6 @@ import 'dayjs/locale/en.js';
8
8
  import { aggregateEyeTestConfig, findOneEyeTestConfig, updateOneEyeTestConfig } from '../service/eyeTestConfiguration.service.js';
9
9
  import { ObjectId } from 'mongodb';
10
10
  import { aggregateClusters } from '../service/clusters.service.js';
11
- import { sendComplianceEmail } from '../validation/eyeTest.validation.js';
12
11
 
13
12
  dayjs.extend( utc );
14
13
  dayjs.extend( timezone );
@@ -751,7 +750,6 @@ export async function save( req, res ) {
751
750
  try {
752
751
  const inputData = req.body;
753
752
  const openSearch = JSON.parse( process.env.OPENSEARCH );
754
- const ses = JSON.parse( process.env.SES );
755
753
 
756
754
  let searchFilter =[
757
755
  {
@@ -813,6 +811,7 @@ export async function save( req, res ) {
813
811
  },
814
812
  };
815
813
  const getOutput = await getOpenSearchData( openSearch.EyeTestOutput, searchQuery );
814
+ logger.info( { getOutput: getOutput } );
816
815
  const output = getOutput?.body?.hits?.hits?.length > 0 ? getOutput?.body?.hits?.hits[0] : null;
817
816
  if ( !output ) {
818
817
  return res.sendError( 'This file is currently being audited by another user. Any actions you perform will not be saved.', 400 );
@@ -846,46 +845,19 @@ export async function save( req, res ) {
846
845
 
847
846
  const getEyetestConfig = await findOneEyeTestConfig( { clientId: req?.user.userType == 'tango'? inputData?.clientId : req.user.clientId, configureType: 'email' }, { complianceThreshold: 1 } );
848
847
 
849
- if ( getEyetestConfig &&( inputData.auditStatus == 'Audited' ||inputData.auditStatus == 'Re-Audited' ) && inputUpdatedData && inputData.type === 'physical' && inputData?.isReSend !== false ) {
848
+ if ( getEyetestConfig && inputData.auditStatus == 'Audited' && inputUpdatedData ) {
850
849
  const trustScore = Math.round( 100-( ( inputData?.overRides / inputData?.steps?.length ) * 100 ) );
851
850
  const value = Number( getEyetestConfig?.complianceThreshold?.value?.split( '%' )[0] );
852
851
  const condition = getEyetestConfig?.complianceThreshold?.condition;
853
- const id= inputData?.isReSend === true ?`${inputData.id}_${inputUpdatedData?._source?.optumId}_${inputData?.fileId}_${Date.now()}` : `${inputData.id}_${inputUpdatedData?._source?.optumId}_${inputData?.fileId}`;
854
- const humanScore = Math.round( ( inputUpdatedData?._source?.auditedSteps /inputUpdatedData?._source?.totalSteps ) * 100 );
855
- const userName = await findOneUser( { _id: new mongoose.Types.ObjectId( inputUpdatedData?._source?.userId ) }, { userName: 1 } );
856
- const order = [
857
- 'Distance-VA-Check',
858
- 'Torchlight Check',
859
- 'JCC Check',
860
- 'Duochrome Check',
861
- 'Near Addition Check',
862
- 'Prescription Verification Check',
863
- ];
864
- const steps = inputData?.steps
865
- .filter( ( step ) =>
866
- step.hasOwnProperty( 'auditedStatus' ) ?
867
- step.auditedStatus === false :
868
- step.AIStatus === false,
869
- )
870
- .map( ( step ) => ( {
871
- stepName: step.processName,
872
- comment: step?.reason === 'others'? step.otherReason:step?.reason,
873
- } ) );
874
- steps.sort(
875
- ( a, b ) => order.indexOf( a.processName ) - order.indexOf( b.processName ),
876
- );
852
+ const id= `${inputData?.RMEmail}_${inputData?.cluster}_${inputUpdatedData?._source?.optumId}_${inputData?.fileId}`;
877
853
  switch ( condition ) {
878
854
  case '>': if ( trustScore > value ) {
879
855
  const record1 = {
880
856
  RMEmail: inputData.RMEmail,
881
- RMName: inputData.RMEmail,
882
857
  cluster: inputData.cluster,
883
858
  optumId: inputUpdatedData?._source?.optumId,
884
- optomEmailId: inputUpdatedData?._source?.salesmanEmailId,
885
859
  storeName: inputUpdatedData?._source?.storeName,
886
860
  complianceScore: inputUpdatedData?._source?.ComplianceScore,
887
- humanScore: humanScore,
888
- auditedBy: userName?.userName || '',
889
861
  trustScore: inputUpdatedData?._source?.trustScore,
890
862
  auditedId: inputUpdatedData?._id,
891
863
  queueId: inputUpdatedData?._source?.queueId,
@@ -894,26 +866,15 @@ export async function save( req, res ) {
894
866
 
895
867
  };
896
868
  await insertWithId( openSearch.eyeTestEmailAlert, id, record1 );
897
- sendComplianceEmail( {
898
- toEmail: inputUpdatedData?._source?.salesmanEmailId,
899
- fromEmail: ses.eyeTestAlertEmail,
900
- userName: 'User',
901
- compliancePercentage: humanScore,
902
- steps: steps,
903
- } );
904
869
  }
905
870
  break;
906
871
  case '<': if ( trustScore < value ) {
907
872
  const record2 = {
908
873
  RMEmail: inputData.RMEmail,
909
- RMName: inputData.RMEmail,
910
874
  cluster: inputData.cluster,
911
875
  optumId: inputUpdatedData?._source?.optumId,
912
- optomEmailId: inputUpdatedData?._source?.salesmanEmailId,
913
876
  storeName: inputUpdatedData?._source?.storeName,
914
877
  complianceScore: inputUpdatedData?._source?.ComplianceScore,
915
- humanScore: humanScore,
916
- auditedBy: userName?.userName || '',
917
878
  trustScore: inputUpdatedData?._source?.trustScore,
918
879
  auditedId: inputUpdatedData?._id,
919
880
  queueId: inputUpdatedData?._source?.queueId,
@@ -922,26 +883,15 @@ export async function save( req, res ) {
922
883
 
923
884
  };
924
885
  await insertWithId( openSearch.eyeTestEmailAlert, id, record2 );
925
- sendComplianceEmail( {
926
- toEmail: inputUpdatedData?._source?.salesmanEmailId,
927
- fromEmail: ses.eyeTestAlertEmail,
928
- userName: 'User',
929
- compliancePercentage: humanScore,
930
- steps: steps,
931
- } );
932
886
  };
933
887
  break;
934
888
  case '>=': if ( trustScore >= value ) {
935
889
  const record3 = {
936
890
  RMEmail: inputData.RMEmail,
937
- RMName: inputData.RMEmail,
938
891
  cluster: inputData.cluster,
939
892
  optumId: inputUpdatedData?._source?.optumId,
940
- optomEmailId: inputUpdatedData?._source?.salesmanEmailId,
941
893
  storeName: inputUpdatedData?._source?.storeName,
942
894
  complianceScore: inputUpdatedData?._source?.ComplianceScore,
943
- humanScore: humanScore,
944
- auditedBy: userName?.userName || '',
945
895
  trustScore: inputUpdatedData?._source?.trustScore,
946
896
  auditedId: inputUpdatedData?._id,
947
897
  queueId: inputUpdatedData?._source?.queueId,
@@ -950,26 +900,15 @@ export async function save( req, res ) {
950
900
 
951
901
  };
952
902
  await insertWithId( openSearch.eyeTestEmailAlert, id, record3 );
953
- sendComplianceEmail( {
954
- toEmail: inputUpdatedData?._source?.salesmanEmailId,
955
- fromEmail: ses.eyeTestAlertEmail,
956
- userName: 'User',
957
- compliancePercentage: humanScore,
958
- steps: steps,
959
- } );
960
903
  }
961
904
  break;
962
905
  case '<=': if ( trustScore <= value ) {
963
906
  const record4 = {
964
907
  RMEmail: inputData.RMEmail,
965
- RMName: inputData.RMEmail,
966
908
  cluster: inputData.cluster,
967
909
  optumId: inputUpdatedData?._source?.optumId,
968
- optomEmailId: inputUpdatedData?._source?.salesmanEmailId,
969
910
  storeName: inputUpdatedData?._source?.storeName,
970
911
  complianceScore: inputUpdatedData?._source?.ComplianceScore,
971
- humanScore: humanScore,
972
- auditedBy: userName?.userName || '',
973
912
  trustScore: inputUpdatedData?._source?.trustScore,
974
913
  auditedId: inputUpdatedData?._id,
975
914
  queueId: inputUpdatedData?._source?.queueId,
@@ -978,27 +917,16 @@ export async function save( req, res ) {
978
917
 
979
918
  };
980
919
  await insertWithId( openSearch.eyeTestEmailAlert, id, record4 );
981
- sendComplianceEmail( {
982
- toEmail: inputUpdatedData?._source?.salesmanEmailId,
983
- fromEmail: ses.eyeTestAlertEmail,
984
- userName: 'User',
985
- compliancePercentage: humanScore,
986
- steps: steps,
987
- } );
988
920
  }
989
921
  break;
990
922
  case '=':
991
923
  case '==': if ( trustScore == value ) {
992
924
  const record5 = {
993
925
  RMEmail: inputData.RMEmail,
994
- RMName: inputData.RMEmail,
995
926
  cluster: inputData.cluster,
996
927
  optumId: inputUpdatedData?._source?.optumId,
997
- optomEmailId: inputUpdatedData?._source?.salesmanEmailId,
998
928
  storeName: inputUpdatedData?._source?.storeName,
999
929
  complianceScore: inputUpdatedData?._source?.ComplianceScore,
1000
- humanScore: humanScore,
1001
- auditedBy: userName?.userName || '',
1002
930
  trustScore: inputUpdatedData?._source?.trustScore,
1003
931
  auditedId: inputUpdatedData?._id,
1004
932
  queueId: inputUpdatedData?._source?.queueId,
@@ -1007,26 +935,15 @@ export async function save( req, res ) {
1007
935
 
1008
936
  };
1009
937
  await insertWithId( openSearch.eyeTestEmailAlert, id, record5 );
1010
- sendComplianceEmail( {
1011
- toEmail: inputUpdatedData?._source?.salesmanEmailId,
1012
- fromEmail: ses.eyeTestAlertEmail,
1013
- userName: 'User',
1014
- compliancePercentage: humanScore,
1015
- steps: steps,
1016
- } );
1017
938
  }
1018
939
  break;
1019
940
  case '===': if ( trustScore === value ) {
1020
941
  const record6 = {
1021
942
  RMEmail: inputData.RMEmail,
1022
- RMName: inputData.RMEmail,
1023
943
  cluster: inputData.cluster,
1024
944
  optumId: inputUpdatedData?._source?.optumId,
1025
- optomEmailId: inputUpdatedData?._source?.salesmanEmailId,
1026
945
  storeName: inputUpdatedData?._source?.storeName,
1027
946
  complianceScore: inputUpdatedData?._source?.ComplianceScore,
1028
- humanScore: humanScore,
1029
- auditedBy: userName?.userName || '',
1030
947
  trustScore: inputUpdatedData?._source?.trustScore,
1031
948
  auditedId: inputUpdatedData?._id,
1032
949
  queueId: inputUpdatedData?._source?.queueId,
@@ -1034,19 +951,12 @@ export async function save( req, res ) {
1034
951
  updatedAt: new Date(),
1035
952
  };
1036
953
  await insertWithId( openSearch.eyeTestEmailAlert, id, record6 );
1037
- sendComplianceEmail( {
1038
- toEmail: inputUpdatedData?._source?.salesmanEmailId,
1039
- fromEmail: ses.eyeTestAlertEmail,
1040
- userName: 'User',
1041
- compliancePercentage: humanScore,
1042
- steps: steps,
1043
- } );
1044
954
  }
1045
955
  break;
1046
956
  default: throw new Error( `Unknown condition: ${condition}` );
1047
957
  }
1048
958
  }
1049
- return res.sendSuccess( 'The file has been submitted successfully' );
959
+ return res.sendSuccess( 'The file has been submited successfully' );
1050
960
  } catch ( error ) {
1051
961
  const err = error.message || 'Internal Server Error';
1052
962
  logger.error( { message: error, data: req.params, function: 'eyetestAudit-controller-save' } );
@@ -1288,25 +1198,18 @@ export async function userAuditedData( req, res ) {
1288
1198
 
1289
1199
  export async function summaryList( req, res ) {
1290
1200
  try {
1291
- // declare inputData and get request body
1292
1201
  const inputData = req.body;
1293
-
1294
- // throw 204 if client id is not 11
1295
1202
  if ( inputData.clientId !== '11' ) {
1296
1203
  return res.sendError( 'No data found', 204 );
1297
1204
  }
1298
1205
 
1299
- // declare openSearch and get data form the .env/secret manager
1300
1206
  const openSearch = JSON.parse( process.env.OPENSEARCH );
1301
-
1302
- // set limit, offset, sortBy, sortOrder value if not set default value
1303
1207
  const limit = inputData.limit || 10;
1304
1208
  const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
1305
1209
 
1306
1210
  const sortBy = inputData?.sortBy ? [ 'coveredStepsAI', 'trustScore', 'date', 'ComplianceScore', 'auditedSteps' ].includes( inputData.sortBy ) ? inputData.sortBy :`${inputData.sortBy}.keyword` : 'storeName.keyword';
1307
1211
  const order = inputData?.sortOrder || -1;
1308
1212
 
1309
- // declare filter and assign range values from inputData
1310
1213
  let filter= [
1311
1214
  {
1312
1215
  'range': {
@@ -1319,7 +1222,6 @@ export async function summaryList( req, res ) {
1319
1222
 
1320
1223
  ];
1321
1224
 
1322
- // filter by Audit Status if key has minimum one element
1323
1225
  if ( inputData?.auditStatus && inputData?.auditStatus?.length > 0 ) {
1324
1226
  filter.push( {
1325
1227
  'terms': {
@@ -1327,8 +1229,6 @@ export async function summaryList( req, res ) {
1327
1229
  },
1328
1230
  } );
1329
1231
  }
1330
-
1331
- // filter by Visitors Type if key has minimum one element
1332
1232
  if ( inputData?.demographics && inputData?.demographics?.length > 0 ) {
1333
1233
  filter.push( {
1334
1234
  'terms': {
@@ -1336,8 +1236,6 @@ export async function summaryList( req, res ) {
1336
1236
  },
1337
1237
  } );
1338
1238
  }
1339
-
1340
- // filter by Eye test Type if key has string value one element
1341
1239
  if ( inputData.type && inputData.type!='' ) {
1342
1240
  filter.push( {
1343
1241
  'term': {
@@ -1347,17 +1245,6 @@ export async function summaryList( req, res ) {
1347
1245
  } );
1348
1246
  }
1349
1247
 
1350
- // filter by near addition if value != "" and eye test must be a physical
1351
- if ( inputData.nearAddition && inputData.nearAddition!='' && inputData.type ==='physical' ) {
1352
- filter.push( {
1353
- 'term': {
1354
- 'nearAddition.keyword': inputData.nearAddition,
1355
- },
1356
-
1357
- } );
1358
- }
1359
-
1360
- // filter by stores if key has minimum one element else throw an error
1361
1248
  if ( inputData.storeId && inputData.storeId.length > 0 ) {
1362
1249
  filter.push( {
1363
1250
 
@@ -1370,14 +1257,11 @@ export async function summaryList( req, res ) {
1370
1257
  return res.sendError( 'No data found', 204 );
1371
1258
  }
1372
1259
 
1373
- // Declare mustQuery as an array and include all elements from the filter array
1374
1260
  let mustQuery = [
1375
1261
  ...filter,
1376
1262
  ];
1377
1263
 
1378
- // filter by complianceScore/tango score if key has minimum one element
1379
- if ( inputData.complianceScore && inputData.complianceScore?.length > 0 ) {
1380
- // If the key type is not 'store', split the compliance score ranges
1264
+ if ( inputData.complianceScore && inputData.complianceScore?.length > null ) {
1381
1265
  if ( inputData.keyType !== 'store' ) {
1382
1266
  const rangeShould = inputData?.complianceScore?.map( ( r ) => {
1383
1267
  const [ gte, lte ] = r.split( '-' ).map( Number );
@@ -1387,7 +1271,7 @@ export async function summaryList( req, res ) {
1387
1271
  },
1388
1272
  };
1389
1273
  } );
1390
- // Add the range conditions to mustQuery (any one of the ranges should match)
1274
+
1391
1275
  mustQuery.push(
1392
1276
  {
1393
1277
  bool: {
@@ -1396,7 +1280,7 @@ export async function summaryList( req, res ) {
1396
1280
  },
1397
1281
  },
1398
1282
  );
1399
- } else { // If-else condition: use 'terms' filter to match records by Compliance Score / Tango Score
1283
+ } else {
1400
1284
  const values = Array.isArray( inputData.complianceScore ) ?
1401
1285
  inputData.complianceScore.map( Number ) :
1402
1286
  [ Number( inputData.complianceScore ) ];
@@ -1409,7 +1293,6 @@ export async function summaryList( req, res ) {
1409
1293
  }
1410
1294
  }
1411
1295
 
1412
- // filter by category if key exist allow "fake, genuine" else throw valid category
1413
1296
  if ( inputData?.category ) {
1414
1297
  switch ( inputData?.category ) {
1415
1298
  case 'fake':
@@ -2235,15 +2118,6 @@ export async function summaryCard( req, res ) {
2235
2118
  },
2236
2119
  } );
2237
2120
  }
2238
-
2239
- if ( inputData.nearAddition && inputData.nearAddition!='' && inputData.type ==='physical' ) {
2240
- filter.push( {
2241
- 'term': {
2242
- 'nearAddition.keyword': inputData.nearAddition,
2243
- },
2244
-
2245
- } );
2246
- }
2247
2121
  let mustQuery = [
2248
2122
  ...filter,
2249
2123
  ];
@@ -2397,7 +2271,7 @@ export async function summaryCard( req, res ) {
2397
2271
  'humanScore': {
2398
2272
  filter: {
2399
2273
  terms: {
2400
- 'auditStatus.keyword': [ 'Audited', 'Re-Audited' ],
2274
+ 'auditStatus.keyword': [ 'Audited', 'ReAudited' ],
2401
2275
  },
2402
2276
  },
2403
2277
  aggs: {
@@ -2512,7 +2386,7 @@ export async function emailAlertLog( req, res ) {
2512
2386
  inputData.clientId = req.user.userType == 'tango'? inputData?.clientId : req?.user?.clientId;
2513
2387
  // get openserach name form the env file
2514
2388
  const openSearch = JSON.parse( process.env.OPENSEARCH );
2515
- const sortBy = inputData?.sortBy ? [ 'complianceScore', 'humanScore', 'trustScore', 'updatedAt', 'createdAt' ].includes( inputData.sortBy ) ? inputData.sortBy :`${inputData.sortBy}.keyword` : 'RMName.keyword';
2389
+
2516
2390
 
2517
2391
  let filter =[
2518
2392
  {
@@ -2525,7 +2399,7 @@ export async function emailAlertLog( req, res ) {
2525
2399
  },
2526
2400
  ];
2527
2401
  let sort =[
2528
- { [sortBy]: { order: inputData.sortOrder === 1 ? 'asc' : 'desc' } },
2402
+ { [inputData?.sortBy]: { order: inputData.sortOrder === 1 ? 'asc' : 'desc' } },
2529
2403
  ];
2530
2404
  if ( inputData.RmList && inputData.RmList?.lenght > 0 ) {
2531
2405
  filter.push( {
@@ -2542,86 +2416,19 @@ export async function emailAlertLog( req, res ) {
2542
2416
  },
2543
2417
  } );
2544
2418
  }
2545
- let search = {
2546
- must: filter,
2547
- };
2548
- if ( inputData.searchValue && inputData.searchValue !== '' ) {
2549
- search ={
2550
- 'must': filter,
2551
- 'should': [
2552
- {
2553
- 'wildcard': {
2554
- 'RMEmail.keyword': {
2555
- 'value': `*${inputData.searchValue}*`,
2556
- },
2557
- },
2558
- },
2559
- {
2560
- 'wildcard': {
2561
- 'RMName.keyword': {
2562
- 'value': `*${inputData.searchValue}*`,
2563
- },
2564
- },
2565
- },
2566
- {
2567
- 'wildcard': {
2568
- 'cluster.keyword': {
2569
- 'value': `*${inputData.searchValue}*`,
2570
- },
2571
- },
2572
- },
2573
- {
2574
- 'wildcard': {
2575
- 'optumId.keyword': {
2576
- 'value': `*${inputData.searchValue}*`,
2577
- },
2578
- },
2579
- },
2580
- {
2581
- 'wildcard': {
2582
- 'queueId.keyword': {
2583
- 'value': `*${inputData.searchValue}*`,
2584
- },
2585
- },
2586
- },
2587
- {
2588
- 'wildcard': {
2589
- 'storeName.keyword': {
2590
- 'value': `*${inputData.searchValue}*`,
2591
- },
2592
- },
2593
- },
2594
- {
2595
- 'wildcard': {
2596
- 'auditedBy.keyword': {
2597
- 'value': `*${inputData.searchValue}*`,
2598
- },
2599
- },
2600
- },
2601
- {
2602
- 'wildcard': {
2603
- 'optomEmailId.keyword': {
2604
- 'value': `*${inputData.searchValue}*`,
2605
- },
2606
- },
2607
- },
2608
- ],
2609
- 'minimum_should_match': 1,
2610
- };
2611
- }
2612
2419
  const getQuery = {
2613
2420
  'size': inputData.isExport == true? 50000 : inputData?.limit || 10,
2614
2421
  'from': offset || 0,
2615
2422
  'query': {
2616
- 'bool': search,
2423
+ 'bool': {
2424
+ 'must': filter,
2425
+ },
2617
2426
  },
2618
2427
  'sort': sort,
2619
2428
  };
2620
2429
 
2621
-
2622
2430
  // get query result from the open saerch
2623
2431
  const getData= await getOpenSearchData( openSearch.eyeTestEmailAlert, getQuery );
2624
- const count = getData?.body?.hits?.total?.value;
2625
2432
  // throw error if got null or empty array
2626
2433
  if ( !getData || getData?.body?.hits?.hits?.length == 0 ) {
2627
2434
  return res.sendError( 'No records found', 204 );
@@ -2629,40 +2436,30 @@ export async function emailAlertLog( req, res ) {
2629
2436
  let response =[];
2630
2437
  for ( let item of getData?.body?.hits?.hits ) {
2631
2438
  response.push( {
2632
- RMEmail: item?._source?.RMEmail || '',
2633
- RMName: item?._source?.RMName || '',
2439
+ RMEmail: item?._source?.RMEmail,
2634
2440
  cluster: item?._source?.cluster,
2635
2441
  optumId: item?._source?.optumId,
2636
- optomEmailId: item?._source?.optomEmailId,
2637
2442
  storeName: item?._source?.storeName,
2638
- complianceScore: Math.round( item?._source?.complianceScore || 0 ),
2639
- humanScore: Math.round( item?._source?.humanScore || 0 ),
2640
- trustScore: item?._source?.trustScore || '--',
2443
+ complianceScore: item?._source?.complianceScore,
2444
+ trustScore: item?._source?.trustScore,
2641
2445
  auditedId: item?._source?.auditedId,
2642
2446
  queueId: item?._source?.queueId,
2643
- auditedBy: item?._source?.auditedBy || '--',
2644
2447
 
2645
2448
  } );
2646
2449
  }
2647
2450
 
2648
2451
  if ( inputData.isExport == true ) {
2649
- logger.info( { response: response } );
2650
2452
  const chunkedMappingData = await chunkArray( response, 10 );
2651
2453
  const promises = chunkedMappingData.map( async ( chunk ) => {
2652
2454
  const exportData = [];
2653
2455
  for ( const element of chunk ) {
2654
2456
  exportData.push( {
2655
- 'RM Name': element.RMEmail,
2457
+ 'RM Email': element.RMEmail,
2656
2458
  'Cluster Name': element.cluster,
2657
- 'Optom ID': element.optumId,
2658
- 'Optom Email': element.optomEmailId || '--',
2459
+ 'Optom Id': element.optumId,
2659
2460
  'Store Name': element.storeName,
2660
- 'Audited By': element.auditedBy || '--',
2661
- 'Tango Score': Math.round( element.complianceScore || 0 ),
2662
-
2663
- 'Trust Score': element.trustScore || '--',
2664
- 'Human Audited Score': Math.round( element.humanScore || 0 ),
2665
-
2461
+ 'Tango Score': element.complianceScore || 0,
2462
+ 'Trust Score': element.trustScore || 0,
2666
2463
 
2667
2464
  } );
2668
2465
  }
@@ -2671,7 +2468,6 @@ export async function emailAlertLog( req, res ) {
2671
2468
  } );
2672
2469
  const mappedArrays = await Promise.all( promises );
2673
2470
  const result = mappedArrays.flat();
2674
- logger.info( { result: result } );
2675
2471
  await download( result, res );
2676
2472
  return;
2677
2473
  }
@@ -2681,7 +2477,7 @@ export async function emailAlertLog( req, res ) {
2681
2477
 
2682
2478
 
2683
2479
  logger.info( { inputData: inputData, getData: response } );
2684
- return res.sendSuccess( { result: response, count: count } );
2480
+ return res.sendSuccess( { result: response, count: response.length } );
2685
2481
  } catch ( error ) {
2686
2482
  const err = error.message || 'Internal Server Error';
2687
2483
  logger.error( { message: error, data: req.body, function: 'eyetestAudit-controller-emailAlertLog' } );
@@ -2841,6 +2637,10 @@ export async function getEmailConfig( req, res ) {
2841
2637
  configureType: 'email',
2842
2638
  };
2843
2639
  const getOne = await findOneEyeTestConfig( query, { complianceThreshold: 1, _id: 1 } );
2640
+ logger.info( { getOne: getOne, message: 'getEmailConfig' } );
2641
+ // if ( !getOne?.complianceThreshold ) {
2642
+ // return res.sendError( 'No data found', 204 );
2643
+ // }
2844
2644
  if ( !getOne ) {
2845
2645
  return res.sendError( ' No data found', 204 );
2846
2646
  }
@@ -1,4 +1,4 @@
1
- import { checkFileExist, chunkArray, download, getDate, getDateWithCustomizeTime, getJsonFileData, getObject, getOpenSearchData, getUTC, insertOpenSearchData, listFileByPath, logger, signedUrl, sqsReceive, updateOpenSearchData, sendMessageToQueue, listQueue, copyImage } from 'tango-app-api-middleware';
1
+ import { checkFileExist, chunkArray, download, getDate, getDateWithCustomizeTime, getJsonFileData, getObject, getOpenSearchData, getUTC, insertOpenSearchData, listFileByPath, logger, signedUrl, sqsReceive, updateOpenSearchData, sendMessageToQueue, listQueue, copyImage, upsertOpenSearchData } from 'tango-app-api-middleware';
2
2
  import { aggregateBinaryAudit, findOneBinaryAudit, updateOneBinaryAuditModel, updateOneUpsertBinaryAudit } from '../service/binaryAudit.service.js';
3
3
  import { countDocumentsStore, findOneStore } from '../service/store.service.js';
4
4
  import { findOneUser } from '../service/user.service.js';
@@ -1149,7 +1149,8 @@ export async function saveBinary( req, res ) {
1149
1149
  fileDetails: getTraxInsertData?.sqs?.Body?.fileDetails,
1150
1150
  createdAt: new Date(),
1151
1151
  };
1152
- await insertOpenSearchData( openSearch.traxDetectionOutput, OpenSearchOutput );
1152
+ const customerId = `${inputData.storeId}_${inputData.fileDate}_${inputData.moduleType}_${inputData.tempId}`;
1153
+ await upsertOpenSearchData( openSearch.traxDetectionOutput, customerId, { doc: OpenSearchOutput } );
1153
1154
  const logData2 = {
1154
1155
  userId: req.user._id,
1155
1156
  userName: req.user.userName,
@@ -64,7 +64,6 @@ export const saveSchema = joi.object( {
64
64
  spokenLanguage: joi.string().optional(),
65
65
  cluster: joi.string().required().allow( '' ),
66
66
  RMEmail: joi.string().required().allow( '' ),
67
- isReSend: joi.boolean().optional(),
68
67
  } );
69
68
 
70
69
  export const saveValid = {
@@ -157,7 +156,7 @@ export const summaryListSchema = joi.object( {
157
156
  ).optional(),
158
157
  storeId: joi.array().items( joi.string().required() ).required(),
159
158
  complianceScore: joi.array().items( joi.string().required() ).optional(),
160
- nearAddition: joi.string().optional().allow( '', 'true', 'false' ),
159
+ nearAddition: joi.string().optional().allow( '' ),
161
160
  isExport: joi.boolean().optional(),
162
161
  searchValue: joi.string().optional().allow( '' ),
163
162
  sortBy: joi.string().optional(),
@@ -235,7 +234,7 @@ export const summaryCardSchema = joi.object( {
235
234
  ).optional(),
236
235
  storeId: joi.array().items( joi.string().required() ).required(),
237
236
  complianceScore: joi.array().items( joi.string().required() ).optional(),
238
- nearAddition: joi.string().optional().allow( '', 'true', 'false' ),
237
+ nearAddition: joi.string().optional().allow( '' ),
239
238
  category: joi.string().optional() .valid( 'fake', 'genuine' ),
240
239
  } );
241
240
 
@@ -280,8 +279,12 @@ export const emailAlertLogSchema = joi.object( {
280
279
 
281
280
  return value;
282
281
  } ),
282
+ type: joi.string().required().messages( {
283
+ 'any.required': 'Type is required',
284
+ 'string.empty': 'Type cannot be empty',
285
+ } ),
283
286
  RMList: joi.array().items(
284
- joi.string().required(),
287
+ joi.string().optional(),
285
288
  ).optional(),
286
289
  clientId: joi.string().when( '$userType', {
287
290
  is: 'tango',
@@ -291,7 +294,7 @@ export const emailAlertLogSchema = joi.object( {
291
294
  } ),
292
295
  otherwise: joi.optional(),
293
296
  } ),
294
- cluster: joi.array().items( joi.string().required() ).optional(),
297
+ cluster: joi.array().items( joi.string().required() ).required(),
295
298
  isExport: joi.boolean().optional(),
296
299
  searchValue: joi.string().optional().allow( '' ),
297
300
  sortBy: joi.string().optional(),
@@ -410,7 +413,6 @@ export const getEmailConfigSchema = joi.object( {
410
413
  } ),
411
414
  otherwise: joi.optional(),
412
415
  } ),
413
-
414
416
  } );
415
417
 
416
418
  export const getEmailConfigValid = {
@@ -3,14 +3,14 @@ import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
3
3
  import { accessVerification } from 'tango-app-api-middleware';
4
4
  import { cancelValid, clusterListValid, emailAlertLogValid, getEmailConfigValid, getFileHistoryValid, getFileValid, getListValid, getUserConfigValid, rmListValid, saveValid, summaryCardValid, summaryListValid, updateEmailConfigValid, updateUserConfigValid, userAuditedDataValid, viewFileValid } from '../dtos/eyeTestAudit.dtos.js';
5
5
  import { addUserConfig, cancel, clusterList, emailAlertLog, getEmailConfig, getFile, getFileHistory, getList, getUserConfig, rmList, save, summaryCard, summaryList, updateEmailConfig, updateEmailConfig1, updateUserConfig, userAuditedData, viewFile } from '../controllers/eyeTestAudit.controllers.js';
6
- import { isSuperAdmin, roleValidation, sendAlert } from '../validation/eyeTest.validation.js';
6
+ import { isSuperAdmin, roleValidation } from '../validation/eyeTest.validation.js';
7
7
 
8
8
  export const eyeTestAuditRouter = Router();
9
9
 
10
10
  eyeTestAuditRouter.post( '/get-list', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getListValid ), getList );
11
11
  eyeTestAuditRouter.get( '/view-file/:id', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( viewFileValid ), viewFile );
12
12
  eyeTestAuditRouter.get( '/get-file/:id', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getFileValid ), getFile );
13
- eyeTestAuditRouter.post( '/save', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( saveValid ), sendAlert, save );
13
+ eyeTestAuditRouter.post( '/save', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( saveValid ), save );
14
14
  eyeTestAuditRouter.post( '/cancel', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( cancelValid ), cancel );
15
15
  eyeTestAuditRouter.get( '/get-file-history/:id/:type', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getFileHistoryValid ), getFileHistory );
16
16
  eyeTestAuditRouter.get( '/user-audited-data/:id', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( userAuditedDataValid ), userAuditedData );
@@ -1,5 +1,4 @@
1
- import { getOpenSearchById, logger } from 'tango-app-api-middleware';
2
- import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';
1
+ import { logger } from 'tango-app-api-middleware';
3
2
 
4
3
  export async function roleValidation( req, res, next ) {
5
4
  try {
@@ -40,133 +39,3 @@ export async function isSuperAdmin( req, res, next ) {
40
39
  }
41
40
  }
42
41
 
43
- export async function sendAlert( req, res, next ) {
44
- try {
45
- const inputData = req.body;
46
- const openSearch = JSON.parse( process.env.OPENSEARCH );
47
- if ( inputData.auditStatus == 'Re-Audited' && inputData.type == 'physical' && inputData?.isReSend == undefined ) {
48
- const getOne = await getOpenSearchById( openSearch.EyeTestInput, inputData.id );
49
- const id = `${inputData.id}_${getOne?.body?._source?.optumId}_${inputData.fileId}`;
50
- const getId = await getOpenSearchById( openSearch.eyeTestEmailAlert, id );
51
- logger.info( { getId: getId, id: id } );
52
- const inputUpdatedData = getId?.body;
53
- if ( inputUpdatedData ) {
54
- return res.sendSuccess( 'Do you want resend mail?', 202 );
55
- } else {
56
- return next();
57
- }
58
- } else {
59
- return next();
60
- }
61
- } catch ( error ) {
62
- const err = error.message;
63
- return res.sendError( err, 500 );
64
- }
65
- }
66
-
67
- /**
68
- * Send HTML Email using AWS SES
69
- * @param {Object} params
70
- * @param {string} params.toEmail - Recipient email address
71
- * @param {string} params.userName - Recipient name
72
- * @param {number} params.compliancePercentage - Compliance score
73
- */
74
- export async function sendComplianceEmail( {
75
- toEmail,
76
- fromEmail, // sender email added here
77
- userName,
78
- compliancePercentage,
79
- steps,
80
- } ) {
81
- // Initialize AWS SES client
82
- logger.info( { steps: steps } );
83
- const sesClient = new SESClient( {
84
- region: 'ap-south-1', // Change to your AWS region
85
- credentials: {
86
- accessKeyId: process.env.AWS_ACCESS_KEY_ID_SIGNED_URL,
87
- secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY__SIGNED_URL,
88
- },
89
- } );
90
- const htmlBody = ( userName, steps, compliancePercentage ) => {
91
- const tableRows = steps
92
- .map(
93
- ( item ) => `
94
- <tr>
95
- <td>${item.stepName}</td>
96
- <td>${item.comment?? '--'}</td>
97
- </tr>
98
- `,
99
- )
100
- .join( '' );
101
-
102
- return `
103
- <!DOCTYPE html>
104
- <html>
105
- <head>
106
- <meta charset="UTF-8" />
107
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
108
- <title>Non Compliance Report</title>
109
- <style>
110
- body { font-family: 'Inter', sans-serif; margin: 0; padding: 24px; background: #f9fafb; color: #121a26; }
111
- .container { max-width: 700px; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
112
- .title { font-size: 24px; font-weight: 700; color: #121a26; }
113
- .subtitle { font-size: 16px; color: #384860; line-height: 1.5; margin-top: 8px; }
114
- .table { width: 100%; border-collapse: collapse; margin-top: 16px; }
115
- .table th, .table td { text-align: left; padding: 12px 16px; border-bottom: 1px solid #eaeef0; color: #667085; }
116
- .footer { margin-top: 32px; font-size: 14px; color: #384860; }
117
- .compliance { font-size: 18px; font-weight: 700; color: #f04438; margin-top: 16px; }
118
- </style>
119
- </head>
120
- <body>
121
- <div class="container">
122
- <p class="title">Non Compliance on Eye Test Procedures</p>
123
- <p class="subtitle">
124
- Dear ${userName},<br><br>
125
- Please ensure that all conducted eye tests meet the required compliance standards.<br>
126
- Your prompt attention to this matter will help us maintain the highest standards and avoid any discrepancies.<br>
127
- Please take a look at the below findings.
128
- </p>
129
-
130
- <table class="table">
131
- <thead>
132
- <tr>
133
- <th>Step Name</th>
134
- <th>Comments</th>
135
- </tr>
136
- </thead>
137
- <tbody>
138
- ${tableRows}
139
- </tbody>
140
- </table>
141
-
142
- <p class="compliance">Compliance Percentage: ${compliancePercentage}%</p>
143
- <p class="footer">Regards,<br>Team Tango</p>
144
- </div>
145
- </body>
146
- </html>`;
147
- };
148
-
149
- const emailHTML = htmlBody( userName, steps, compliancePercentage );
150
-
151
- const params = {
152
- Source: fromEmail, // sender email (must be verified in SES)
153
- Destination: {
154
- ToAddresses: [ toEmail ],
155
- },
156
- Message: {
157
- Subject: { Data: 'Non Compliance on Eye Test Procedures' },
158
- Body: { Html: { Data: emailHTML } },
159
- },
160
- };
161
-
162
- try {
163
- const response = await sesClient.send( new SendEmailCommand( params ) );
164
- // console.log( 'Email sent successfully:', response.MessageId );
165
- return response;
166
- } catch ( error ) {
167
- // console.error( 'Error sending email:', error );
168
- throw error;
169
- }
170
- }
171
-
172
-