tango-app-api-audit 3.4.68-beta.0 → 3.4.68-beta.1

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.4.68-beta.0",
3
+ "version": "3.4.68-beta.1",
4
4
  "description": "audit & audit metrics apis",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,7 +1,13 @@
1
- import { getOpenSearchData, insertOpenSearchData, getOpenSearchById, logger } from 'tango-app-api-middleware';
1
+ import { getOpenSearchData, getOpenSearchById, logger, insertOpenSearchData, updateOpenSearchData } from 'tango-app-api-middleware';
2
2
  import { findOneUser } from '../service/user.service.js';
3
3
  import mongoose from 'mongoose';
4
4
  import dayjs from 'dayjs';
5
+ import utc from 'dayjs/plugin/utc.js';
6
+ import timezone from 'dayjs/plugin/timezone.js';
7
+ import 'dayjs/locale/en.js';
8
+
9
+ dayjs.extend( utc );
10
+ dayjs.extend( timezone );
5
11
 
6
12
  export async function getList( req, res ) {
7
13
  try {
@@ -128,12 +134,256 @@ export async function getList( req, res ) {
128
134
  }
129
135
  }
130
136
 
137
+ export async function viewFile( req, res ) {
138
+ try {
139
+ const inputData = req.params;
140
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
141
+ const url = JSON.parse( process.env.URL );
142
+ let isEnable =true;
143
+
144
+ const getInput = await getOpenSearchById( openSearch.EyeTestInput, inputData.id );
145
+ if ( !getInput || !getInput?.body ) {
146
+ return res.sendError( 'No Data Found', 204 );
147
+ }
148
+ const getData =getInput?.body?._source;
149
+
150
+
151
+ let searchFilter =[
152
+ {
153
+ 'terms': {
154
+ 'queueId.keyword': getData?.queueId,
155
+ },
156
+
157
+ },
158
+ {
159
+ 'terms': {
160
+ 'type.keyword': getData?.type,
161
+ },
162
+
163
+ },
164
+ ];
165
+ if ( getData?.type == 'remote' ) {
166
+ searchFilter =[
167
+ {
168
+ 'terms': {
169
+ 'engagementId.keyword': getData?.engagementId,
170
+ },
171
+
172
+ },
173
+ {
174
+ 'terms': {
175
+ 'type.keyword': getData?.type,
176
+ },
177
+
178
+ },
179
+ ];
180
+ }
181
+
182
+ let searchQuery={
183
+ 'size': 1,
184
+ 'query': {
185
+ 'bool': {
186
+ 'must': searchFilter,
187
+ },
188
+ },
189
+ 'sort': [
190
+ { createdAt: { order: 'desc' } },
191
+ ],
192
+ };
193
+ const searchRes= await getOpenSearchData( openSearch.EyeTestOutput, searchQuery );
194
+ const temp = searchRes?.body?.hits?.hits?.lenght > 0? searchRes?.body?.hits?.hits[0] : [];
195
+ const getUserName = await findOneUser( { _id: new mongoose.Types.ObjectId( temp?.userId ) }, { userName: 1 } );
196
+
197
+ const searchData = temp?
198
+ getData['lastAuditedDetails']= {
199
+ 'auditedBy': getUserName?.userName || '',
200
+ 'completionTime': temp?.startTime? new Date( temp?.startTime ).toLocaleTimeString( 'en-IN', { hour12: false } ): '',
201
+ 'timeZone': temp?.timeZone || '',
202
+ } : null;
203
+ getData['complianceScore'] = getData.complianceScore || getData?.totalSteps>0 ? Math.round( ( getData?.coveredStepsAI/ getData?.totalSteps )*100 ): 0;
204
+ getData['trustScore'] = getData?.trustScore || 0;
205
+ getData['testDuration'] = Math.round( getData?.testDuration/60 ) || 0;
206
+ getData['filePath'] = `${url[getData?.type]}${getData?.filePath}`;
207
+ const response = getData;
208
+ switch ( getData?.auditStatus ) {
209
+ case 'Yet-to-Audit':
210
+ isEnable=true;
211
+ break;
212
+ case 'In-Progress':
213
+ if ( searchData.lenght ==0 ) {
214
+ return res.sendError( 'No saved records found', 400 );
215
+ }
216
+ if ( searchData.userId !== req.user._id ) {
217
+ isEnable=false;
218
+ }
219
+ return res.sendSuccess( { result: result } );
220
+ break;
221
+ case 'Audited':
222
+ case 'Re-Audited':
223
+ isEnable=true;
224
+ }
225
+
226
+ return res.sendSuccess( { result: response, isEnable: isEnable } );
227
+ } catch ( error ) {
228
+ const err = error.message || 'Internal Server Error';
229
+ logger.error( { message: error, data: req.body, function: 'eyetestAudit-controller-viewFile' } );
230
+ return res.sendError( err, 500 );
231
+ }
232
+ }
233
+
131
234
  export async function getFile( req, res ) {
132
235
  try {
133
236
  const inputData = req.params;
237
+ const url = JSON.parse( process.env.URL );
134
238
  const openSearch = JSON.parse( process.env.OPENSEARCH );
135
- const result =await insertOpenSearchData( openSearch.EyeTestOutput, physicalRecord );
136
- return res.sendSuccess( { result: result, inputData: inputData, record: record } );
239
+
240
+ const getInput = await getOpenSearchById( openSearch.EyeTestInput, inputData.id );
241
+ if ( !getInput || !getInput?.body ) {
242
+ return res.sendError( 'No Data Found', 204 );
243
+ }
244
+ const getData =getInput?.body?._source;
245
+
246
+
247
+ let searchFilter =[
248
+ {
249
+ 'terms': {
250
+ 'queueId.keyword': getData?.queueId,
251
+ },
252
+
253
+ },
254
+ {
255
+ 'terms': {
256
+ 'type.keyword': getData?.type,
257
+ },
258
+
259
+ },
260
+ ];
261
+ if ( getData?.type == 'remote' ) {
262
+ searchFilter =[
263
+ {
264
+ 'terms': {
265
+ 'engagementId.keyword': getData?.engagementId,
266
+ },
267
+
268
+ },
269
+ {
270
+ 'terms': {
271
+ 'type.keyword': getData?.type,
272
+ },
273
+
274
+ },
275
+ ];
276
+ }
277
+
278
+ let searchQuery={
279
+ 'size': 1,
280
+ 'query': {
281
+ 'bool': {
282
+ 'must': searchFilter,
283
+ },
284
+ },
285
+ 'sort': [
286
+ { createdAt: { order: 'desc' } },
287
+ ],
288
+ };
289
+ const searchRes= await getOpenSearchData( openSearch.EyeTestOutput, searchQuery );
290
+ const searchData = searchRes?.body?.hits?.hits?.lenght > 0? searchRes?.body?.hits?.hits[0] : null;
291
+ logger.info( { searchData: searchData, getData: getData, messahe: '...........3' } );
292
+ switch ( getData?.auditStatus ) {
293
+ case 'Yet-to-Audit':
294
+ const record= {
295
+ 'date': getData?.date,
296
+ 'fileDate': getData?.fileDate,
297
+ 'storeName': getData?.storeName,
298
+ 'storeId': getData?.storeId,
299
+ 'userId': req?.user?._id,
300
+ 'type': getData?.type,
301
+ 'engagementId': getData?.engagementId,
302
+ 'queueId': getData?.queueId,
303
+ 'optumId': getData?.optumId,
304
+ 'displayName': getData?.displayName,
305
+ 'complianceScore': getData?.totalSteps>0 ? Math.round( ( getData?.coveredStepsAI/ getData?.totalSteps )*100 ): 0,
306
+ 'coveredStepsAI': getData?.coveredStepsAI,
307
+ 'auditedSteps': 0,
308
+ 'overRides': 0,
309
+ 'trustScore': 0,
310
+ 'visitorsType': getData?.visitorsType,
311
+ 'testDuration': Math.round( getData?.testDuration/60 ) || 0,
312
+ 'testStartTime': getData?.testStartTime,
313
+ 'testEndTime': getData?.testEndTime,
314
+ 'timeZone': 'IST',
315
+ 'spokenLanguage': '',
316
+ 'auditStatus': 'In-Progress',
317
+ 'totalSteps': getData?.totalSteps,
318
+ 'inputBucketName': getData?.inputBucketName,
319
+ 'filePath': `${url[getData?.type]}${getData?.filePath}`,
320
+ 'steps': getData?.steps,
321
+ 'startTime': dayjs().tz( 'Asia/Kolkata' ),
322
+ 'createdAt': dayjs().tz( 'Asia/Kolkata' ),
323
+ 'updatedAt': dayjs().tz( 'Asia/Kolkata' ),
324
+
325
+ };
326
+ record?.steps?.map( ( item, i ) => {
327
+ record.steps[i]['auditedStatus']= null, record.steps[i]['reason'] = '', record.steps[i]['startTime'] = '', record.steps[i]['endTime'] = '';
328
+ } );
329
+ if ( !searchData ) {
330
+ const data1 = await insertOpenSearchData( openSearch.EyeTestOutput, record );
331
+ logger.info( { data1: data1 } );
332
+ await updateOpenSearchData( openSearch.EyeTestInput, inputData.id, { doc: { auditStatus: 'In-Progress', userId: req?.user?._id } } );
333
+ }
334
+
335
+ break;
336
+ case 'In-Progress':
337
+
338
+ if ( !searchData ) {
339
+ return res.sendError( 'No saved records found', 400 );
340
+ }
341
+ if ( searchData?.userId !== req.user._id ) {
342
+ return res.sendError( 'Forbidden to this action', 403 );
343
+ }
344
+ break;
345
+ case 'Audited':
346
+ case 'Re-Audited':
347
+ const newRecord= {
348
+ 'date': getData?.date,
349
+ 'fileDate': getData?.fileDate,
350
+ 'storeName': getData?.storeName,
351
+ 'storeId': getData?.storeId,
352
+ 'userId': req?.user?._id,
353
+ 'type': getData?.type,
354
+ 'engagementId': getData?.engagementId,
355
+ 'queueId': getData?.queueId,
356
+ 'optumId': getData?.optumId,
357
+ 'displayName': getData?.displayName,
358
+ 'complianceScore': getData?.totalSteps>0 ? Math.round( ( getData?.coveredStepsAI/ getData?.totalSteps )*100 ): 0,
359
+ 'coveredStepsAI': getData?.coveredStepsAI,
360
+ 'auditedSteps': getData?.auditedSteps || 0,
361
+ 'overRides': getData?.overRides || 0,
362
+ 'trustScore': getData?.trustScore || 0,
363
+ 'visitorsType': getData?.visitorsType,
364
+ 'testDuration': getData?.testDuration,
365
+ 'testStartTime': getData?.testStartTime,
366
+ 'testEndTime': getData?.testEndTime,
367
+ 'timeZone': getData?.timeZone,
368
+ 'spokenLanguage': getData?.spokenLanguage || '',
369
+ 'auditStatus': 'In-Progress',
370
+ 'totalSteps': getData?.totalSteps,
371
+ 'filePath': `${url[getData?.type]}${getData?.filePath}`,
372
+ 'steps': getData?.steps,
373
+ 'startTime': dayjs().tz( 'Asia/Kolkata' ),
374
+ 'createdAt': dayjs().tz( 'Asia/Kolkata' ),
375
+ 'updatedAt': dayjs().tz( 'Asia/Kolkata' ),
376
+
377
+ };
378
+ await insertOpenSearchData( openSearch.EyeTestOutput, newRecord );
379
+ await updateOpenSearchData( openSearch.EyeTestInput, inputData.id, { doc: { auditStatus: 'In-Progress' } } );
380
+
381
+ break;
382
+ default:
383
+ return res.sendError( 'Status must be valid', 400 );
384
+ }
385
+
386
+ return res.sendSuccess( 'The status has been updated' );
137
387
  } catch ( error ) {
138
388
  const err = error.message || 'Internal Server Error';
139
389
  logger.error( { message: error, data: req.body, function: 'eyetestAudit-controller-getFile' } );
@@ -1,5 +1,5 @@
1
1
  import j2s from 'joi-to-swagger';
2
- import { getListSchema, getFileSchema, getFileHistorySchema, userAuditedDataSchema } from '../dtos/eyeTestAudit.dtos.js';
2
+ import { getListSchema, getFileSchema, getFileHistorySchema, userAuditedDataSchema, viewFileSchema } from '../dtos/eyeTestAudit.dtos.js';
3
3
 
4
4
  export const eyeTestAuditDocs = {
5
5
 
@@ -25,21 +25,38 @@ export const eyeTestAuditDocs = {
25
25
  },
26
26
  },
27
27
 
28
- '/v3/eye-test-audit/get-file/{id}/{type}': {
28
+ '/v3/eye-test-audit/view-file/{id}': {
29
29
  get: {
30
30
  tags: [ 'Eye Test Audit' ],
31
- description: 'Get a file via Open Serach',
32
- operationId: 'get-file',
31
+ description: 'View a file via Open Serach',
32
+ operationId: 'view-file',
33
33
  parameters: [
34
34
  {
35
35
  in: 'path',
36
36
  name: 'id',
37
- scema: j2s( getFileSchema ).swagger,
37
+ scema: j2s( viewFileSchema ).swagger,
38
38
  require: true,
39
39
  },
40
+ ],
41
+ responses: {
42
+ 200: { description: 'Successful' },
43
+ 401: { description: 'Unauthorized User' },
44
+ 422: { description: 'Field Error' },
45
+ 500: { description: 'Server Error' },
46
+ 204: { description: 'Not Found' },
47
+ },
48
+ },
49
+ },
50
+
51
+ '/v3/eye-test-audit/get-file/{id}': {
52
+ get: {
53
+ tags: [ 'Eye Test Audit' ],
54
+ description: 'Get a file via Open Serach',
55
+ operationId: 'get-file',
56
+ parameters: [
40
57
  {
41
58
  in: 'path',
42
- name: 'type',
59
+ name: 'id',
43
60
  scema: j2s( getFileSchema ).swagger,
44
61
  require: true,
45
62
  },
@@ -18,10 +18,17 @@ export const getListValid = {
18
18
  body: getListSchema,
19
19
  };
20
20
 
21
+ export const viewFileSchema = joi.object( {
22
+ id: joi.string().required(),
23
+ } );
24
+
25
+ export const viewFileValid = {
26
+ params: viewFileSchema,
27
+ };
28
+
21
29
 
22
30
  export const getFileSchema = joi.object( {
23
31
  id: joi.string().required(),
24
- type: joi.string().required(),
25
32
  } );
26
33
 
27
34
  export const getFileValid = {
@@ -1,13 +1,15 @@
1
1
  import { Router } from 'express';
2
2
  import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
3
3
  import { accessVerification } from 'tango-app-api-middleware';
4
- import { getFileHistoryValid, getFileValid, getListValid, userAuditedDataValid } from '../dtos/eyeTestAudit.dtos.js';
5
- import { getFile, getFileHistory, getList, userAuditedData } from '../controllers/eyeTestAudit.controllers.js';
4
+ import { getFileHistoryValid, getFileValid, getListValid, userAuditedDataValid, viewFileValid } from '../dtos/eyeTestAudit.dtos.js';
5
+ import { getFile, getFileHistory, getList, userAuditedData, viewFile } from '../controllers/eyeTestAudit.controllers.js';
6
6
 
7
7
  export const eyeTestAuditRouter = Router();
8
8
 
9
9
  eyeTestAuditRouter.post( '/get-list', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getListValid ), getList );
10
- eyeTestAuditRouter.get( '/get-file/:id/:type', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getFileValid ), getFile );
10
+ eyeTestAuditRouter.get( '/view-file/:id', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( viewFileValid ), viewFile );
11
+ eyeTestAuditRouter.get( '/get-file/:id', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getFileValid ), getFile );
12
+ eyeTestAuditRouter.post( '/save', isAllowedSessionHandler );
11
13
  eyeTestAuditRouter.get( '/get-file-history/:id/:type', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( getFileHistoryValid ), getFileHistory );
12
14
  eyeTestAuditRouter.get( '/user-audited-data/:id', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ] } ), validate( userAuditedDataValid ), userAuditedData );
13
15