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 +1 -3
- package/src/controllers/audit.controllers.js +8 -8
- package/src/controllers/eyeTestAudit.controllers.js +25 -225
- package/src/controllers/traxAudit.controllers.js +3 -2
- package/src/dtos/eyeTestAudit.dtos.js +8 -6
- package/src/routes/eyeTestAudit.routes.js +2 -2
- package/src/validation/eyeTest.validation.js +1 -132
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-audit",
|
|
3
|
-
"version": "3.6.
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
{
|
|
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 &&
|
|
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=
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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', '
|
|
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
|
-
|
|
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':
|
|
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:
|
|
2639
|
-
|
|
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
|
|
2457
|
+
'RM Email': element.RMEmail,
|
|
2656
2458
|
'Cluster Name': element.cluster,
|
|
2657
|
-
'Optom
|
|
2658
|
-
'Optom Email': element.optomEmailId || '--',
|
|
2459
|
+
'Optom Id': element.optumId,
|
|
2659
2460
|
'Store Name': element.storeName,
|
|
2660
|
-
'
|
|
2661
|
-
'
|
|
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:
|
|
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
|
-
|
|
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( ''
|
|
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( ''
|
|
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().
|
|
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() ).
|
|
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
|
|
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 ),
|
|
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 {
|
|
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
|
-
|