tango-app-api-client 3.6.5-vms.2 → 3.6.5-vms.20

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/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { clientRouter } from './src/routes/client.routes.js';
4
4
  import { clientDocs } from './src/docs/client.docs.js';
5
+ import { vmsauditRouter } from './src/routes/vmsAudit.routes.js';
5
6
 
6
- export { clientRouter, clientDocs };
7
+ export { clientRouter, clientDocs, vmsauditRouter };
7
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-client",
3
- "version": "3.6.5-vms.2",
3
+ "version": "3.6.5-vms.20",
4
4
  "description": "client",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -31,7 +31,7 @@
31
31
  "npm": "^10.9.1",
32
32
  "sharp": "^0.34.3",
33
33
  "swagger-ui-express": "^5.0.0",
34
- "tango-api-schema": "^2.4.19",
34
+ "tango-api-schema": "^2.5.2",
35
35
  "tango-app-api-middleware": "^3.6.0",
36
36
  "winston": "^3.11.0",
37
37
  "winston-daily-rotate-file": "^5.0.0"
@@ -2967,10 +2967,89 @@ export async function updateFDConfig( req, res ) {
2967
2967
  export async function getFDConfig( req, res ) {
2968
2968
  try {
2969
2969
  const inputData = req.query;
2970
- let result = await findOneClient( { clientId: inputData.clientId }, { footfallDirectoryConfigs: 1 } );
2971
- if ( result===null ) {
2970
+ // let result = await findOneClient( { clientId: inputData.clientId }, { footfallDirectoryConfigs: 1 } );
2971
+ const configQuery = [
2972
+ {
2973
+ $match: {
2974
+ clientId: inputData?.clientId,
2975
+ },
2976
+ },
2977
+
2978
+ // Convert all effectiveFrom to proper Date
2979
+ {
2980
+ $addFields: {
2981
+ taggingLimitationWithDate: {
2982
+ $map: {
2983
+ input: '$footfallDirectoryConfigs.taggingLimitation',
2984
+ as: 'item',
2985
+ in: {
2986
+ effectiveFrom: { $toDate: '$$item.effectiveFrom' },
2987
+ values: '$$item.values',
2988
+ },
2989
+ },
2990
+ },
2991
+ },
2992
+ },
2993
+
2994
+ // Filter items <= input date
2995
+ {
2996
+ $addFields: {
2997
+ matchedLimitation: {
2998
+ $filter: {
2999
+ input: '$taggingLimitationWithDate',
3000
+ as: 'item',
3001
+ cond: {
3002
+ $lte: [
3003
+ '$$item.effectiveFrom',
3004
+ { $toDate: inputData.dateString },
3005
+ ],
3006
+ },
3007
+ },
3008
+ },
3009
+ },
3010
+ },
3011
+
3012
+ // Sort DESC and pick ONLY top 1 -> latest effective record
3013
+ {
3014
+ $addFields: {
3015
+ effectiveLimitation: {
3016
+ $arrayElemAt: [
3017
+ {
3018
+ $slice: [
3019
+ {
3020
+ $sortArray: {
3021
+ input: '$matchedLimitation',
3022
+ sortBy: { effectiveFrom: -1 },
3023
+ },
3024
+ },
3025
+ 1,
3026
+ ],
3027
+ },
3028
+ 0,
3029
+ ],
3030
+ },
3031
+ },
3032
+ },
3033
+
3034
+ {
3035
+ $project: {
3036
+ 'config': 1,
3037
+ 'effectiveLimitation': 1,
3038
+ 'footfallDirectoryConfigs': 1,
3039
+
3040
+ },
3041
+ },
3042
+ ];
3043
+
3044
+
3045
+ const getData = await aggregateClient( configQuery );
3046
+ let result = getData[0];
3047
+ if ( !result || result===null ) {
2972
3048
  return res.sendError( 'no data found', 204 );
2973
3049
  }
3050
+ result.footfallDirectoryConfigs.taggingLimitation = result?.effectiveLimitation?.values;
3051
+ delete result.effectiveLimitation;
3052
+
2974
3053
  return res.sendSuccess( result );
2975
3054
  } catch ( error ) {
2976
3055
  const err = error.message || 'Internal Server Error';
@@ -2983,38 +3062,38 @@ export async function getFDConfig( req, res ) {
2983
3062
  export async function updateTaggingType( req, res ) {
2984
3063
  try {
2985
3064
  const inputData = req.body;
2986
-
2987
- const inputQuery = req.query; // up
2988
- const types = inputData?.taggingLimitation?.map( ( x ) => x.type );
2989
- // Step 1: remove existing items with same "type"
2990
- await clientModel.updateOne(
2991
- { clientId: inputQuery.clientId },
3065
+ const newValues = inputData.taggingLimitation;
3066
+ const today = new Date().toISOString().split( 'T' )[0];
3067
+ logger.info( { today, newValues } );
3068
+ const result = await clientModel.updateOne(
2992
3069
  {
2993
- $pull: {
2994
- 'footfallDirectoryConfigs.taggingLimitation': {
2995
- type: { $in: types },
2996
- },
2997
- },
3070
+ 'clientId': inputData?.clientId,
3071
+ 'footfallDirectoryConfigs.taggingLimitation.effectiveFrom': today,
2998
3072
  },
2999
- );
3000
-
3001
- // Remove duplicate entries by type
3002
- const uniqueData = uniqueByType( inputData.taggingLimitation );
3003
-
3004
- // Step 2: insert fresh new items
3005
- let result =await clientModel.updateOne(
3006
- { clientId: inputQuery.clientId },
3007
3073
  {
3008
- $addToSet: {
3009
- 'footfallDirectoryConfigs.taggingLimitation': {
3010
- $each: uniqueData,
3011
- },
3074
+ $set: {
3075
+ 'footfallDirectoryConfigs.taggingLimitation.$.values': newValues,
3012
3076
  },
3013
3077
  },
3014
3078
  );
3079
+ logger.info( { result } );
3080
+ if ( result?.matchedCount === 0 ) {
3081
+ await clientModel.updateOne(
3082
+ { clientId: inputData.clientId },
3083
+ {
3084
+ $push: {
3085
+ 'footfallDirectoryConfigs.taggingLimitation': {
3086
+ effectiveFrom: today,
3087
+ values: newValues,
3088
+ },
3089
+ },
3090
+ },
3091
+ );
3092
+ }
3093
+
3015
3094
 
3016
3095
  if ( result?.acknowledged === true ) {
3017
- return res.sendSuccess( result );
3096
+ return res.sendSuccess( 'Tagging limitation has been updated' );
3018
3097
  } else {
3019
3098
  return res.sendError( 'no data', 204 );
3020
3099
  }
@@ -3025,14 +3104,14 @@ export async function updateTaggingType( req, res ) {
3025
3104
  }
3026
3105
  }
3027
3106
 
3028
- function uniqueByType( arr ) {
3029
- const seen = new Set();
3030
- return arr.filter( ( item ) => {
3031
- if ( seen.has( item.type ) ) return false;
3032
- seen.add( item.type );
3033
- return true;
3034
- } );
3035
- }
3107
+ // function uniqueByType( arr ) {
3108
+ // const seen = new Set();
3109
+ // return arr.filter( ( item ) => {
3110
+ // if ( seen.has( item.type ) ) return false;
3111
+ // seen.add( item.type );
3112
+ // return true;
3113
+ // } );
3114
+ // }
3036
3115
 
3037
3116
  export async function createStoreRequest( req, res ) {
3038
3117
  try {
@@ -3050,11 +3129,11 @@ export async function createStoreRequest( req, res ) {
3050
3129
  const upsertRecord = await updateOneUpsertVmsStoreRequest( { storeId: inputData?.storeId, dateString: inputData?.dateString }, record );
3051
3130
  logger.info( { upsertRecord } );
3052
3131
  if ( upsertRecord?.upsertedCount === 1 ) {
3053
- return res.sendSuccess( 'The Request has been sent Successfully' );
3132
+ return res.sendTemp( 'The Request has been sent Successfully' );
3054
3133
  } else if ( upsertRecord?.matchedCount === 1 && upsertRecord?.modifiedCount === 1 ) {
3055
- return res.sendSuccess( 'The Request has been updated Successfully' );
3134
+ return res.sendTemp( 'The Request has been updated Successfully' );
3056
3135
  } else if ( upsertRecord?.matchedCount === 1 && upsertRecord?.modifiedCount === 0 ) {
3057
- return res.sendSuccess( 'The Request already exists and nothing to update' );
3136
+ return res.sendTemp( 'The Request already exists and nothing to update' );
3058
3137
  } else {
3059
3138
  return res.sendError( 'Internal Server Error', 500 );
3060
3139
  }
@@ -3096,6 +3175,7 @@ export async function listStoreRequest( req, res ) {
3096
3175
  {
3097
3176
  $project: {
3098
3177
  _id: 0,
3178
+ id: { $concat: [ '$storeId', '_', '$dateString' ] },
3099
3179
  storeName: 1,
3100
3180
  storeId: 1,
3101
3181
  dateString: 1,
@@ -0,0 +1,488 @@
1
+ import { logger, searchOpenSearchData, getOpenSearchById, updateOpenSearchData } from 'tango-app-api-middleware';
2
+ import { findOneStore } from '../service/store.service.js';
3
+ import { aggregatevmsUserAudit, createvmsUserAudit, findOnevmsUserAudit, updateOnevmsUserAudit, updatemanyvmsUserAudit } from '../service/vmsuserAudit.service.js';
4
+ import { createvmsAuditLog, findOnevmsAuditLog } from '../service/vmsauditLog.service.js';
5
+ import { insertOpenSearchData, clearScroll, scrollResponse } from 'tango-app-api-middleware';
6
+ import { findOneUser } from '../service/user.service.js';
7
+ import dayjs from 'dayjs';
8
+ import utc from 'dayjs/plugin/utc.js';
9
+ import timezone from 'dayjs/plugin/timezone.js';
10
+
11
+ dayjs.extend( utc );
12
+ dayjs.extend( timezone );
13
+ export async function getAuditFile( req, res ) {
14
+ try {
15
+ // const bucket = JSON.parse( process.env.BUCKET );
16
+ const url = JSON.parse( process.env.URL );
17
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
18
+ const inputData = req.query;
19
+ const files = [];
20
+ const storeQuery = {
21
+ storeId: inputData.storeId,
22
+ };
23
+ const storeFields = {
24
+ storeName: 1,
25
+ clientId: 1,
26
+ address: '$storeProfile.address',
27
+ };
28
+ const storeInfo = await findOneStore( storeQuery, storeFields );
29
+
30
+ const userQuery = [
31
+ {
32
+ $match: {
33
+ $and: [
34
+ { userId: req.user._id },
35
+ { auditStatus: { $nin: [ 'completed', 'skipped' ] } },
36
+ { storeId: inputData.storeId },
37
+ { fileDate: inputData.Date },
38
+ ],
39
+ },
40
+ },
41
+ {
42
+ $sort: { createdAt: -1 },
43
+ },
44
+ {
45
+ $limit: 1,
46
+ },
47
+ ];
48
+
49
+ const userDetails = await aggregatevmsUserAudit( userQuery );
50
+ console.log( '🚀 ~ getAuditFile ~ userDetails:', userDetails );
51
+ const auditStatus = userDetails && userDetails.length > 0 ? userDetails[0].auditStatus : null;
52
+ if ( auditStatus === 'drafted' ) {
53
+ const log = await findOnevmsAuditLog(
54
+ {
55
+ userId: userDetails[0].userId,
56
+ fileDate: userDetails[0].fileDate,
57
+ storeId: userDetails[0].storeId,
58
+ totalCount: userDetails[0].beforeCount,
59
+ },
60
+ {},
61
+ { createdAt: -1 },
62
+ );
63
+ console.log( '🚀 ~ getAuditFile ~ log:', log );
64
+ if ( !log ) {
65
+ await updateOnevmsUserAudit(
66
+ { _id: userDetails[0]._id },
67
+ { $set: { isDraft: false, auditStatus: 'skipped' } },
68
+ );
69
+ logger.info( 'audit update in drafted', {
70
+ _id: userDetails[0]._id,
71
+ isDraft: false,
72
+ auditStatus: 'skipped',
73
+ } );
74
+ return res.sendError( 'User saved data has been deleted', 204 );
75
+ }
76
+
77
+ const file = {
78
+ auditId: userDetails[0]._id,
79
+ storeId: userDetails[0].storeId,
80
+ Date: userDetails[0].fileDate,
81
+ userId: log.userId,
82
+ timeSpent: log.timeSpent,
83
+ clientId: userDetails[0].clientId,
84
+ };
85
+ const userdata = await findOneUser( { _id: log.userId } );
86
+ if (
87
+ !inputData.nextId ||
88
+ inputData.nextId === '' ||
89
+ inputData.nextId == null
90
+ ) {
91
+ const logData = {
92
+ userId: log.userId,
93
+ userName: userdata.userName,
94
+ logType: 'vmsaudit',
95
+ logSubType: 'auditStart',
96
+ logData: {
97
+ fileDate: userDetails[0].fileDate,
98
+ storeId: userDetails[0].storeId,
99
+ auditId: userDetails[0]._id,
100
+ beforeCount: userDetails[0].beforeCount,
101
+ },
102
+ createdAt: new Date(),
103
+ };
104
+ await insertOpenSearchData( openSearch.vmsauditLog, logData );
105
+ }
106
+ const storeQuery = {
107
+ storeId: userDetails[0].storeId,
108
+ };
109
+ const storeFields = {
110
+ storeId: 1,
111
+ storeName: 1,
112
+ address: '$storeProfile.address',
113
+ };
114
+ const storeDetails = await findOneStore( storeQuery, storeFields );
115
+ let docId = `${inputData.storeId}_${inputData.Date}_footfall-directory-tagging`;
116
+ if ( inputData.tickettype === 'internal' ) {
117
+ docId = `${inputData.storeId}_${inputData.Date}_internal_footfall-directory-tagging`;
118
+ }
119
+ console.log( '🚀 ~ getAuditFile ~ docId:draft', docId );
120
+ const existinginternalDoc = await getOpenSearchById( openSearch.footfallDirectory, docId );
121
+ let ticketSource = existinginternalDoc?.body?._source;
122
+ const currentTime = new Date();
123
+ const updatePayload = {
124
+ doc: {
125
+
126
+ updatedAt: currentTime,
127
+ createdByRole: req?.user?.role || '',
128
+ createdByEmail: req?.user?.email || '',
129
+ createdByUserName: req?.user?.userName || '',
130
+ createdByUserId: req?.user?._id || '',
131
+ },
132
+ };
133
+ console.log( '🚀 ~ getAuditFile ~ updatePayload:', updatePayload );
134
+ console.log( '🚀 ~ getAuditFile ~ ticketSource:', ticketSource );
135
+ if ( ticketSource ) {
136
+ ticketSource.mappingInfo.map( ( data ) => {
137
+ if ( data.type === 'tangoreview' ) {
138
+ data.status = 'In-Progress';
139
+ }
140
+ } );
141
+ ticketSource.createdByRole = req?.user?.role || '';
142
+ ticketSource.createdByEmail = req?.user?.email || '';
143
+ ticketSource.createdByUserName = req?.user?.userName || '';
144
+ ticketSource.createdByUserId = req?.user?._id || '';
145
+ console.log( '🚀 ~ getAuditFile ~ ticketSource:', ticketSource );
146
+ await updateOpenSearchData(
147
+ openSearch.footfallDirectory,
148
+ docId,
149
+ { doc: ticketSource },
150
+
151
+ );
152
+ } else if ( ticketSource && inputData.tickettype === 'internal' ) {
153
+ await updateOpenSearchData(
154
+ openSearch.footfallDirectory,
155
+ docId,
156
+ updatePayload,
157
+ );
158
+ }
159
+ return res.sendSuccess( {
160
+ result: log.draftedData,
161
+ storeId: storeDetails?.storeId,
162
+ storeName: storeDetails?.storeName,
163
+ address: storeDetails?.address || '',
164
+ count: log.totalCount,
165
+ timeSpent: log.timeSpent,
166
+ file: file,
167
+ isDraft: userDetails[0].isDraft,
168
+ } );
169
+ }
170
+ console.log( inputData );
171
+
172
+ const query = {
173
+ size: inputData?.limit || 2,
174
+ _source: [ 'module', 'status', 'date', 'store_id', 'outputCluster', 'personPath', 'REIDCluster', 'isEmployee', 'isJunk', 'EmployeeStatusFinal' ], // Only fetch necessary fields
175
+
176
+ query: {
177
+ bool: {
178
+ 'must': [
179
+ {
180
+ term: { 'store_id.keyword': inputData.storeId },
181
+ },
182
+ {
183
+ term: { 'date.keyword': dayjs( inputData.Date ).format( 'DD-MM-YYYY' ) },
184
+ },
185
+ {
186
+ term: { 'module.keyword': 'CUSTOMER' },
187
+ },
188
+ {
189
+ term: { 'status.keyword': 'PP_CLUSTER_FORMED' },
190
+ },
191
+ {
192
+ terms: { EmployeeStatusFinal: [ 1, 2 ] },
193
+ },
194
+ ],
195
+ 'should': [
196
+ { 'term': { 'isJunk': false } },
197
+ { 'bool': { 'must_not': { 'exists': { 'field': 'isJunk' } } } },
198
+ ],
199
+ 'minimum_should_match': 1,
200
+ },
201
+ },
202
+
203
+ };
204
+ console.log( openSearch.vmsAudit );
205
+ let list = inputData.nextId ? await scrollResponse( inputData.nextId ) : await searchOpenSearchData( openSearch.vmsAudit, query );
206
+
207
+ let docId = `${inputData.storeId}_${inputData.Date}_footfall-directory-tagging`;
208
+ if ( inputData.tickettype === 'internal' ) {
209
+ docId = `${inputData.storeId}_${inputData.Date}_internal_footfall-directory-tagging`;
210
+ }
211
+ console.log( '🚀 ~ getAuditFile ~ docId:draft', docId );
212
+ const existinginternalDoc = await getOpenSearchById( openSearch.footfallDirectory, docId );
213
+ let ticketSource = existinginternalDoc?.body?._source;
214
+ const currentTime = new Date();
215
+ const updatePayload = {
216
+ doc: {
217
+
218
+ updatedAt: currentTime,
219
+ createdByRole: req?.user?.role || '',
220
+ createdByEmail: req?.user?.email || '',
221
+ createdByUserName: req?.user?.userName || '',
222
+ createdByUserId: req?.user?._id || '',
223
+ },
224
+ };
225
+ console.log( '🚀 ~ getAuditFile ~ updatePayload:', updatePayload );
226
+ console.log( '🚀 ~ getAuditFile ~ ticketSource:', ticketSource );
227
+ if ( ticketSource ) {
228
+ ticketSource.mappingInfo.map( ( data ) => {
229
+ if ( data.type === 'tangoreview' ) {
230
+ data.status = 'In-Progress';
231
+ console.log( '🚀 ~ getAuditFile ~ data.status:', data.status );
232
+ }
233
+ } );
234
+ ticketSource.createdByRole = req?.user?.role || '';
235
+ ticketSource.createdByEmail = req?.user?.email || '';
236
+ ticketSource.createdByUserName = req?.user?.userName || '';
237
+ ticketSource.createdByUserId = req?.user?._id || '';
238
+ console.log( '🚀 ~ getAuditFile ~ ticketSource:', ticketSource );
239
+ await updateOpenSearchData(
240
+ openSearch.footfallDirectory,
241
+ docId,
242
+ { doc: ticketSource },
243
+ );
244
+ } else if ( ticketSource && inputData.tickettype === 'internal' ) {
245
+ await updateOpenSearchData(
246
+ openSearch.footfallDirectory,
247
+ docId,
248
+ updatePayload,
249
+ );
250
+ }
251
+ const folderPath = list?.body?.hits?.hits;
252
+ if ( list?.body?.hits?.hits?.length == 0 ) {
253
+ await clearScroll( list?.body?._scroll_id );
254
+ }
255
+ if ( folderPath?.length > 0 ) {
256
+ for ( let i = 0; i < folderPath.length; i++ ) {
257
+ const img = folderPath[i]?._source?.personPath?.split( '/' );
258
+ const image = img[3]?.split( '.' );
259
+ const indexes = folderPath[i]?._source?.outputCluster === 50000 ? folderPath[i]?._source?.REIDCluster : folderPath[i]?._source?.outputCluster;
260
+ // fetchData.file_path = folderPath[i]?._source?.personPath;
261
+ const data = `${url.trackInput}${folderPath[i]?._source?.personPath}`;
262
+ const mapimg = {
263
+ img_path: data,
264
+ img_name: indexes,
265
+ img_id: image[0],
266
+ };
267
+ addUniqueFile( files, {
268
+ img_path: data,
269
+ img_name: indexes,
270
+ img_id: image[0],
271
+ selected: false,
272
+ dropped: false,
273
+ demographic: '',
274
+ count: 1,
275
+ mappedid: [ mapimg ],
276
+ } );
277
+ }
278
+ } else if ( inputData.nextId !== '' && inputData.nextId !== null && inputData.nextId !== undefined ) {
279
+ if ( !list ) {
280
+ return res.sendError( 'token expired', 404 );
281
+ }
282
+ list.body._scroll_id = '';
283
+ // insertData = userDetails[0];
284
+ } else {
285
+ logger.error( {
286
+ error: { folderPath: folderPath, nextQuery: inputData.nextId },
287
+ function: 'getAuditFile',
288
+ message: 'Bucket image data not availale',
289
+ } );
290
+ return res.sendError( 'Bucket is Empty', 204 );
291
+ }
292
+ const [ year, month, day ] = inputData.Date.split( '-' );
293
+ const temp = `${year}-${month}-${day}`;
294
+ console.log( temp );
295
+ let start = new Date( temp );
296
+ const userTimezoneOffset = start.getTimezoneOffset() * 60000;
297
+ start = new Date( start.getTime() - userTimezoneOffset );
298
+ start.setUTCHours( 0, 0, 0, 0 );
299
+ console.log( start );
300
+ const record = {
301
+ userId: req.user._id,
302
+ storeId: inputData.storeId,
303
+ clientId: storeInfo?.clientId,
304
+ fileDate: inputData.Date,
305
+ beforeCount: inputData.count,
306
+ auditStatus: 'inprogress',
307
+ fileDateISO: start,
308
+ timeSpent: 0,
309
+ startTime: new Date(),
310
+ };
311
+ const insertData = await createvmsUserAudit( record );
312
+ if ( inputData.nextId !== '' && inputData.nextId !== null && inputData.nextId !== undefined && inputData.moduleType === 'track' ) {
313
+ if ( !list ) {
314
+ return res.sendError( 'token expired', 404 );
315
+ }
316
+ list.body._scroll_id = '';
317
+ }
318
+ return res.sendSuccess( {
319
+ result: files,
320
+ count: inputData.count,
321
+ storeId: inputData.storeId,
322
+ storeName: storeInfo?.storeName,
323
+ address: storeInfo?.address,
324
+ file: {
325
+ clientId: storeInfo?.clientId,
326
+ storeId: inputData.storeId,
327
+ Date: inputData.Date,
328
+ auditId: insertData._id,
329
+ userId: insertData.userId,
330
+ nextToken: list?.body?._scroll_id ? list?.body?._scroll_id : null,
331
+
332
+ },
333
+ isDraft: insertData.isDraft,
334
+ } );
335
+ } catch ( error ) {
336
+ const err = error.message || 'Internal Server Error';
337
+ logger.error( {
338
+ error: error,
339
+ message: req.query,
340
+ function: 'getAuditFile',
341
+ } );
342
+ return res.sendError( err, 500 );
343
+ }
344
+ }
345
+ function addUniqueFile( files, newFile ) {
346
+ const exists = files.some( ( file ) => file.img_name === newFile.img_name );
347
+ if ( !exists ) {
348
+ files.push( newFile );
349
+ }
350
+ }
351
+ export async function saveDraft( req, res ) {
352
+ try {
353
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
354
+ const inputData = req.body;
355
+ inputData.userId = req.user._id;
356
+ const getUserAuditData = await findOnevmsUserAudit( { _id: inputData.auditId } );
357
+ if ( !getUserAuditData ) {
358
+ return res.sendError( 'No Data Found', 204 );
359
+ }
360
+ if ( getUserAuditData.auditStatus == 'skipped' ) {
361
+ return res.sendError( 'File Assigned to Someone else', 203 );
362
+ }
363
+
364
+ const userQuery = {
365
+ _id: inputData.auditId,
366
+ };
367
+ let userRecord = {
368
+ isDraft: true,
369
+ auditStatus: 'drafted',
370
+ };
371
+
372
+
373
+ if ( getUserAuditData?.startTime ) {
374
+ userRecord.timeSpent = inputData.timeSpent;
375
+ }
376
+
377
+ if ( inputData.userCommands ) {
378
+ userRecord.userCommands = inputData.userCommands;
379
+ const logData = {
380
+ userId: req.user._id,
381
+ userName: req.user.userName,
382
+ logType: 'vmsaudit',
383
+ logSubType: 'auditDraft',
384
+ logData: {
385
+ fileDate: inputData.fileDate,
386
+ storeId: inputData.storeId,
387
+ beforeCount: inputData.totalCount,
388
+ afterCount: inputData.customerCount,
389
+ timeSpent: inputData.timeSpent,
390
+ auditId: inputData.auditId,
391
+ },
392
+ createdAt: new Date(),
393
+ };
394
+ await insertOpenSearchData( openSearch.vmsauditLog, logData );
395
+ }
396
+ await createvmsAuditLog( inputData );
397
+ await updateOnevmsUserAudit( userQuery, userRecord );
398
+ console.log( '🚀 ~ saveDraft ~ userRecord:', userRecord );
399
+ return res.sendSuccess( {
400
+ result: 'The file has been drafted successfully',
401
+ } );
402
+ } catch ( error ) {
403
+ const err = error.message || 'Internal Server Error';
404
+ logger.error( { error: error, message: req.body, function: 'saveDraft' } );
405
+ return res.sendError( err, 500 );
406
+ }
407
+ }
408
+ export async function getDraftedData( req, res ) {
409
+ try {
410
+ const inputData = req.query;
411
+ const userId = inputData.userId || req.user._id;
412
+ const query = {
413
+ fileDate: inputData.fileDate,
414
+ storeId: inputData.storeId,
415
+ userId: userId,
416
+ auditId: inputData.auditId,
417
+ };
418
+ console.log( query );
419
+ const result = await findOnevmsAuditLog( query, {}, { createdAt: -1 }, 1 );
420
+
421
+ if ( !result ) {
422
+ return res.sendError( 'No Data Found', 204 );
423
+ }
424
+ return res.sendSuccess( { result: result } );
425
+ } catch ( error ) {
426
+ const err = error.message || 'Internal Server Error';
427
+ logger.error( {
428
+ error: error,
429
+ message: req.query,
430
+ function: 'getDraftedData',
431
+ } );
432
+ return res.sendError( err, 500 );
433
+ }
434
+ }
435
+
436
+
437
+ export async function reAssignAudit( req, res ) {
438
+ try {
439
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
440
+ let inputData = req.body;
441
+ let docId = `${inputData.storeId}_${inputData.dateString}_internal_footfall-directory-tagging`;
442
+ if ( inputData.tickettype ==='store' ) {
443
+ docId = `${inputData.storeId}_${inputData.dateString}_footfall-directory-tagging`;
444
+ }
445
+ console.log( '🚀 ~ getAuditFile ~ docId:draft', docId );
446
+ const existingDoc = await getOpenSearchById( openSearch.footfallDirectory, docId );
447
+ const ticketSource = existingDoc?.body?._source;
448
+ const currentTime = new Date();
449
+ const userdata = await findOneUser( { email: inputData.email } );
450
+ const updatePayload = {
451
+ doc: {
452
+ status: 'In-Progress',
453
+ updatedAt: currentTime,
454
+ createdByRole: userdata?.role || '',
455
+ createdByEmail: userdata?.email || '',
456
+ createdByUserName: userdata?.userName || '',
457
+ createdByUserId: userdata?._id || '',
458
+ },
459
+ };
460
+ console.log( '🚀 ~ getAuditFile ~ updatePayload:', updatePayload );
461
+ console.log( '🚀 ~ getAuditFile ~ ticketSource:', ticketSource );
462
+ if ( ticketSource ) {
463
+ await updateOpenSearchData(
464
+ openSearch.footfallDirectory,
465
+ docId,
466
+ updatePayload,
467
+ );
468
+ }
469
+
470
+ console.log( '🚀 ~ reAssignAudit ~ inputData.dateString:', inputData.dateString );
471
+ await updatemanyvmsUserAudit(
472
+ { auditStatus: { $ne: 'completed' }, storeId: inputData.storeId, fileDate: inputData.dateString },
473
+ { status: 'skipped' } );
474
+
475
+
476
+ return res.sendSuccess( 'Ticket Reassigned Successfully' );
477
+ } catch ( error ) {
478
+ const err = error.message || 'Internal Server Error';
479
+ logger.error( {
480
+ error: error,
481
+ message: req.query,
482
+ function: 'reAssignAudit',
483
+ } );
484
+ return res.sendError( err, 500 );
485
+ }
486
+ }
487
+
488
+
@@ -360,12 +360,15 @@ export const updateFDConfigBodySchema = joi.object( {
360
360
  tangoReview: joi.string().optional(),
361
361
  revision: joi.array().items( joi.object( {
362
362
  actionType: joi.string().required(),
363
- isChecked: joi.boolean().required(),
363
+ isChecked: joi.boolean().optional().default( false ),
364
364
  } ) ).optional(),
365
365
  taggingLimitation: joi.array().items( joi.object( {
366
+ iconName: joi.string().optional(),
367
+ name: joi.string().optional(),
366
368
  type: joi.string().required(),
367
369
  value: joi.number().required(),
368
370
  unit: joi.string().required(),
371
+ key: joi.string().required(),
369
372
  } ) ).optional(),
370
373
 
371
374
  } );
@@ -374,8 +377,12 @@ export const updateFDConfigQuerySchema = joi.object( {
374
377
  clientId: joi.string().required(),
375
378
  } );
376
379
 
380
+
381
+ const todayDate = () => new Date().toISOString().split( 'T' )[0];
382
+
377
383
  export const getFDConfigSchema = joi.object( {
378
384
  clientId: joi.string().required(),
385
+ dateString: joi.string().optional().default( () => todayDate() ),
379
386
  } );
380
387
 
381
388
  export const updateFDConfigValid = {
@@ -392,6 +399,9 @@ export const updateTaggingTypeSchema = joi.object( {
392
399
  type: joi.string().required(),
393
400
  value: joi.number().required(),
394
401
  unit: joi.string().required(),
402
+ name: joi.string().required(),
403
+ iconName: joi.string().required(),
404
+ key: joi.string().required(),
395
405
  } ) ).required(),
396
406
 
397
407
  } );
@@ -0,0 +1,25 @@
1
+
2
+ import joi from 'joi';
3
+ export const getDraftedDataSchema = joi.object( {
4
+ storeId: joi.string().required(),
5
+ fileDate: joi.string().required(),
6
+ userId: joi.string().optional(),
7
+ auditId: joi.string().required(),
8
+ } );
9
+ export const getFileSchema = joi.object( {
10
+ nextId: joi.string().optional().allow( '' ),
11
+ limit: joi.number().optional(),
12
+ storeId: joi.string().required(),
13
+ Date: joi.string().required(),
14
+ count: joi.string().required(),
15
+ tickettype: joi.string().required(),
16
+ } );
17
+
18
+
19
+ export const getDraftedDataValid = {
20
+ query: getDraftedDataSchema,
21
+ };
22
+
23
+ export const getFileValid = {
24
+ query: getFileSchema,
25
+ };
@@ -0,0 +1,11 @@
1
+ import express from 'express';
2
+ import { accessVerification, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
3
+ import { getDraftedDataValid, getFileValid } from '../dtos/vmsAudit.dtos.js';
4
+ import { getAuditFile, getDraftedData, saveDraft, reAssignAudit } from '../controllers/vmsAudit.controller.js';
5
+ export const vmsauditRouter = express.Router();
6
+
7
+
8
+ vmsauditRouter.get( '/get-file', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ] } ), validate( getFileValid ), getAuditFile );
9
+ vmsauditRouter.post( '/save-draft', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ] } ), saveDraft );
10
+ vmsauditRouter.get( '/get-drafted-data', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ] } ), validate( getDraftedDataValid ), getDraftedData );
11
+ vmsauditRouter.post( '/reAssign-audit', isAllowedSessionHandler, accessVerification( { userType: [ 'tango' ] } ), reAssignAudit );
@@ -0,0 +1,10 @@
1
+ import vmsauditLogsModel from 'tango-api-schema/schema/vmsauditLogs.model.js';
2
+
3
+
4
+ export function createvmsAuditLog( record ) {
5
+ return vmsauditLogsModel.create( record );
6
+ }
7
+
8
+ export function findOnevmsAuditLog( query, fields={}, sort={ createdAt: -1 }, limit=10 ) {
9
+ return vmsauditLogsModel.findOne( query, fields ).sort( sort ).limit( limit );
10
+ }
@@ -0,0 +1,25 @@
1
+ import vmsuserAuditModel from 'tango-api-schema/schema/vmsuserAudit.model.js';
2
+
3
+
4
+ export function aggregatevmsUserAudit( query ) {
5
+ return vmsuserAuditModel.aggregate( query, { collation: { locale: 'en', strength: 2 } } );
6
+ }
7
+
8
+ export function updateOnevmsUserAudit( query, record ) {
9
+ return vmsuserAuditModel.updateOne( query, { $set: record } );
10
+ }
11
+ export function updatemanyvmsUserAudit( query, record ) {
12
+ return vmsuserAuditModel.updateMany( query, { $set: record } );
13
+ }
14
+
15
+ export function createvmsUserAudit( record ) {
16
+ return vmsuserAuditModel.create( record );
17
+ }
18
+
19
+ export function findOnevmsUserAudit( query, fields ) {
20
+ return vmsuserAuditModel.findOne( query, fields );
21
+ }
22
+
23
+ export function aggregatevmsUserAuditCount( query ) {
24
+ return vmsuserAuditModel.aggregate( query );
25
+ }