tango-app-api-trax 3.9.33 → 3.9.34

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.
Files changed (51) hide show
  1. package/index.js +2 -1
  2. package/package.json +1 -1
  3. package/src/controllers/internalTrax.controller.js +112 -73
  4. package/src/controllers/mobileTrax.controller.js +69 -29
  5. package/src/controllers/trax.controller.js +7 -1
  6. package/src/controllers/traxDashboard.controllers.js +63 -54
  7. package/src/hbs/flag.hbs +1 -1
  8. package/src/hbs/login-otp.hbs +943 -943
  9. package/src/hbs/template.hbs +7 -0
  10. package/src/hbs/visit-checklist.hbs +51 -1
  11. package/src/logging/activityLogFlusher.js +59 -0
  12. package/src/logging/activityLogMiddleware.js +45 -0
  13. package/src/logging/activityLogStore.js +91 -0
  14. package/src/logging/compressBatches.js +83 -0
  15. package/src/logging/config.js +24 -0
  16. package/src/logging/createLoggableService.js +46 -0
  17. package/src/logging/logExternalCall.js +37 -0
  18. package/src/services/app.service.js +15 -9
  19. package/src/services/approver.service.js +23 -15
  20. package/src/services/authentication.service.js +9 -3
  21. package/src/services/camera.service.js +19 -13
  22. package/src/services/checklist.service.js +35 -27
  23. package/src/services/checklistAssign.service.js +43 -38
  24. package/src/services/checklistQuestion.service.js +39 -34
  25. package/src/services/checklistlog.service.js +39 -34
  26. package/src/services/clientRequest.service.js +9 -2
  27. package/src/services/clients.services.js +23 -18
  28. package/src/services/cluster.service.js +31 -23
  29. package/src/services/domain.service.js +23 -18
  30. package/src/services/download.services.js +35 -25
  31. package/src/services/group.service.js +23 -17
  32. package/src/services/lenskartEmployeeMapping.service.js +15 -10
  33. package/src/services/locus.service.js +35 -28
  34. package/src/services/notification.service.js +35 -26
  35. package/src/services/otp.service.js +20 -13
  36. package/src/services/planogram.service.js +9 -2
  37. package/src/services/processedTaskConfig.service.js +35 -27
  38. package/src/services/processedTaskList.service.js +32 -26
  39. package/src/services/processedchecklist.services.js +55 -47
  40. package/src/services/processedchecklistconfig.services.js +39 -34
  41. package/src/services/recurringFlagTracker.service.js +39 -32
  42. package/src/services/runAIFeatures.services.js +32 -27
  43. package/src/services/runAIRequest.services.js +43 -38
  44. package/src/services/store.service.js +32 -27
  45. package/src/services/tagging.service.js +9 -2
  46. package/src/services/taskConfig.service.js +35 -27
  47. package/src/services/teams.service.js +35 -24
  48. package/src/services/ticket.service.js +15 -10
  49. package/src/services/user.service.js +27 -20
  50. package/src/services/userAssignedstores.service.js +12 -5
  51. package/src/utils/visitChecklistPdf.utils.js +114 -11
@@ -1,39 +1,44 @@
1
1
  import model from 'tango-api-schema';
2
-
3
- export const findOne = async ( query={}, field={} ) => {
4
- return model.runAIRequestModel.findOne( query, field );
5
- };
6
-
7
- export const find = async ( query={}, field={} ) => {
8
- return model.runAIRequestModel.find( query, field );
9
- };
10
-
11
- export const create = async ( document = {} ) => {
12
- return model.runAIRequestModel.create( document );
13
- };
14
-
15
- export const insertMany = async ( document = {} ) => {
16
- return model.runAIRequestModel.insertMany( document );
17
- };
18
-
19
- export const deleteMany = async ( query = {} ) => {
20
- return model.runAIRequestModel.deleteMany( query );
21
- };
22
-
23
- export const deleteOne = async ( query = {} ) => {
24
- return model.runAIRequestModel.deleteOne( query );
25
- };
26
-
27
- export const updateOne = async ( query = {}, record={} ) => {
28
- return model.runAIRequestModel.updateOne( query, { $set: record } );
29
- };
30
-
31
- export const aggregate = async ( query = {} ) => {
32
- return model.runAIRequestModel.aggregate( query );
33
- };
34
-
35
- export const count = async ( query = {} ) => {
36
- return model.runAIRequestModel.countDocuments( query );
37
- };
38
-
39
-
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
3
+
4
+ const _methods = {
5
+ async findOne( query={}, field={} ) {
6
+ return model.runAIRequestModel.findOne( query, field );
7
+ },
8
+ async find( query={}, field={} ) {
9
+ return model.runAIRequestModel.find( query, field );
10
+ },
11
+ async create( document = {} ) {
12
+ return model.runAIRequestModel.create( document );
13
+ },
14
+ async insertMany( document = {} ) {
15
+ return model.runAIRequestModel.insertMany( document );
16
+ },
17
+ async deleteMany( query = {} ) {
18
+ return model.runAIRequestModel.deleteMany( query );
19
+ },
20
+ async deleteOne( query = {} ) {
21
+ return model.runAIRequestModel.deleteOne( query );
22
+ },
23
+ async updateOne( query = {}, record={} ) {
24
+ return model.runAIRequestModel.updateOne( query, { $set: record } );
25
+ },
26
+ async aggregate( query = {} ) {
27
+ return model.runAIRequestModel.aggregate( query );
28
+ },
29
+ async count( query = {} ) {
30
+ return model.runAIRequestModel.countDocuments( query );
31
+ },
32
+ };
33
+
34
+ const _svc = createLoggableService( _methods, 'runairequests' );
35
+
36
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
37
+ export const find = ( ...args ) => _svc.find( ...args );
38
+ export const create = ( ...args ) => _svc.create( ...args );
39
+ export const insertMany = ( ...args ) => _svc.insertMany( ...args );
40
+ export const deleteMany = ( ...args ) => _svc.deleteMany( ...args );
41
+ export const deleteOne = ( ...args ) => _svc.deleteOne( ...args );
42
+ export const updateOne = ( ...args ) => _svc.updateOne( ...args );
43
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
44
+ export const count = ( ...args ) => _svc.count( ...args );
@@ -1,31 +1,36 @@
1
1
  import model from 'tango-api-schema';
2
-
3
- export const findOne = async ( query={}, field={} ) => {
4
- return model.storeModel.findOne( query, field );
5
- };
6
-
7
- export const find = async ( query={}, field={} ) => {
8
- return model.storeModel.find( query, field );
9
- };
10
-
11
- export const create = async ( document = {} ) => {
12
- return model.storeModel.create( document );
13
- };
14
-
15
- export const deleteOne = async ( query = {} ) => {
16
- return model.storeModel.deleteOne( query );
17
- };
18
-
19
- export const updateOne = async ( query = {}, record={} ) => {
20
- return model.storeModel.updateOne( query, { $set: record } );
21
- };
22
-
23
- export const aggregate = async ( query = {} ) => {
24
- return model.storeModel.aggregate( query );
25
- };
26
-
27
- export const count = async ( query = {} ) => {
28
- return model.storeModel.countDocuments( query );
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
3
+
4
+ const _methods = {
5
+ async findOne( query={}, field={} ) {
6
+ return model.storeModel.findOne( query, field );
7
+ },
8
+ async find( query={}, field={} ) {
9
+ return model.storeModel.find( query, field );
10
+ },
11
+ async create( document = {} ) {
12
+ return model.storeModel.create( document );
13
+ },
14
+ async deleteOne( query = {} ) {
15
+ return model.storeModel.deleteOne( query );
16
+ },
17
+ async updateOne( query = {}, record={} ) {
18
+ return model.storeModel.updateOne( query, { $set: record } );
19
+ },
20
+ async aggregate( query = {} ) {
21
+ return model.storeModel.aggregate( query );
22
+ },
23
+ async count( query = {} ) {
24
+ return model.storeModel.countDocuments( query );
25
+ },
29
26
  };
30
27
 
28
+ const _svc = createLoggableService( _methods, 'stores' );
31
29
 
30
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
31
+ export const find = ( ...args ) => _svc.find( ...args );
32
+ export const create = ( ...args ) => _svc.create( ...args );
33
+ export const deleteOne = ( ...args ) => _svc.deleteOne( ...args );
34
+ export const updateOne = ( ...args ) => _svc.updateOne( ...args );
35
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
36
+ export const count = ( ...args ) => _svc.count( ...args );
@@ -1,5 +1,12 @@
1
1
  import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
2
3
 
3
- export const aggregate = async ( query={} ) => {
4
- return model.taggingModel.aggregate( query );
4
+ const _methods = {
5
+ async aggregate( query={} ) {
6
+ return model.taggingModel.aggregate( query );
7
+ },
5
8
  };
9
+
10
+ const _svc = createLoggableService( _methods, 'taggings' );
11
+
12
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
@@ -1,32 +1,40 @@
1
1
  import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
2
3
 
3
- export const find = async ( query = {}, field={} ) => {
4
- return model.taskConfigModel.find( query, field );
4
+ const _methods = {
5
+ async find( query = {}, field={} ) {
6
+ return model.taskConfigModel.find( query, field );
7
+ },
8
+ async findOne( query = {}, field={} ) {
9
+ return model.taskConfigModel.findOne( query, field );
10
+ },
11
+ async updateMany( query = {}, record={} ) {
12
+ return model.taskConfigModel.updateMany( query, { $set: record } );
13
+ },
14
+ async updateOne( query = {}, record={} ) {
15
+ return model.taskConfigModel.updateOne( query, { $set: record } );
16
+ },
17
+ async insertMany( data = [] ) {
18
+ return model.taskConfigModel.insertMany( data );
19
+ },
20
+ async deleteMany( query = [] ) {
21
+ return model.taskConfigModel.deleteMany( query );
22
+ },
23
+ async aggregate( query = [] ) {
24
+ return model.taskConfigModel.aggregate( query );
25
+ },
26
+ async insert( data = [] ) {
27
+ return model.taskConfigModel.create( data );
28
+ },
5
29
  };
6
30
 
7
- export const findOne = async ( query = {}, field={} ) => {
8
- return model.taskConfigModel.findOne( query, field );
9
- };
10
-
11
- export const updateMany = async ( query = {}, record={} ) => {
12
- return model.taskConfigModel.updateMany( query, { $set: record } );
13
- };
14
- export const updateOne = async ( query = {}, record={} ) => {
15
- return model.taskConfigModel.updateOne( query, { $set: record } );
16
- };
17
-
18
- export const insertMany = async ( data = [] ) => {
19
- return model.taskConfigModel.insertMany( data );
20
- };
31
+ const _svc = createLoggableService( _methods, 'taskconfigs' );
21
32
 
22
- export const deleteMany = async ( query = [] ) => {
23
- return model.taskConfigModel.deleteMany( query );
24
- };
25
-
26
- export const aggregate = async ( query = [] ) => {
27
- return model.taskConfigModel.aggregate( query );
28
- };
29
-
30
- export const insert = async ( data = [] ) => {
31
- return model.taskConfigModel.create( data );
32
- };
33
+ export const find = ( ...args ) => _svc.find( ...args );
34
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
35
+ export const updateMany = ( ...args ) => _svc.updateMany( ...args );
36
+ export const updateOne = ( ...args ) => _svc.updateOne( ...args );
37
+ export const insertMany = ( ...args ) => _svc.insertMany( ...args );
38
+ export const deleteMany = ( ...args ) => _svc.deleteMany( ...args );
39
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
40
+ export const insert = ( ...args ) => _svc.insert( ...args );
@@ -1,30 +1,41 @@
1
1
  import teamsModel from 'tango-api-schema/schema/teams.model.js';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
2
3
 
3
4
 
4
- export async function createTeamsModel( data ) {
5
- return await teamsModel.create( data );
6
- };
7
- export async function updateOneTeams( query, record ) {
8
- return await teamsModel.updateOne( query, { $set: record }, { upsert: true } );
9
- };
10
-
11
- export async function aggregateTeams( query ) {
12
- return await teamsModel.aggregate( query );
13
- };
14
- export async function deleteTeams( query ={} ) {
15
- return await teamsModel.deleteOne( query );
5
+ const _methods = {
6
+ async createTeamsModel( data ) {
7
+ return await teamsModel.create( data );
8
+ },
9
+ async updateOneTeams( query, record ) {
10
+ return await teamsModel.updateOne( query, { $set: record }, { upsert: true } );
11
+ },
12
+ async aggregateTeams( query ) {
13
+ return await teamsModel.aggregate( query );
14
+ },
15
+ async deleteTeams( query ={} ) {
16
+ return await teamsModel.deleteOne( query );
17
+ },
18
+ async findOneTeams( query ={}, field={} ) {
19
+ return await teamsModel.findOne( query, field );
20
+ },
21
+ async findteams( query ={}, field={} ) {
22
+ return await teamsModel.find( query, field );
23
+ },
24
+ async updateOneTeamModel( query, record ) {
25
+ return await teamsModel.updateOne( query, record );
26
+ },
27
+ countDocumentsTeams( query ) {
28
+ return teamsModel.countDocuments( query );
29
+ },
16
30
  };
17
31
 
18
- export async function findOneTeams( query ={}, field={} ) {
19
- return await teamsModel.findOne( query, field );
20
- };
21
- export async function findteams( query ={}, field={} ) {
22
- return await teamsModel.find( query, field );
23
- };
32
+ const _svc = createLoggableService( _methods, 'teams' );
24
33
 
25
- export async function updateOneTeamModel( query, record ) {
26
- return await teamsModel.updateOne( query, record );
27
- }
28
- export function countDocumentsTeams( query ) {
29
- return teamsModel.countDocuments( query );
30
- }
34
+ export const createTeamsModel = ( ...args ) => _svc.createTeamsModel( ...args );
35
+ export const updateOneTeams = ( ...args ) => _svc.updateOneTeams( ...args );
36
+ export const aggregateTeams = ( ...args ) => _svc.aggregateTeams( ...args );
37
+ export const deleteTeams = ( ...args ) => _svc.deleteTeams( ...args );
38
+ export const findOneTeams = ( ...args ) => _svc.findOneTeams( ...args );
39
+ export const findteams = ( ...args ) => _svc.findteams( ...args );
40
+ export const updateOneTeamModel = ( ...args ) => _svc.updateOneTeamModel( ...args );
41
+ export const countDocumentsTeams = ( ...args ) => _svc.countDocumentsTeams( ...args );
@@ -1,15 +1,20 @@
1
1
  import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
2
3
 
3
- export const findOne = async ( query={}, field={} ) => {
4
- return model.aiTicketConfigModel.findOne( query, field );
5
- };
6
-
7
- export const create = async ( document = {} ) => {
8
- return model.aiTicketConfigModel.create( document );
9
- };
10
-
11
- export const deleteOne = async ( query = {} ) => {
12
- return model.aiTicketConfigModel.deleteOne( query );
4
+ const _methods = {
5
+ async findOne( query={}, field={} ) {
6
+ return model.aiTicketConfigModel.findOne( query, field );
7
+ },
8
+ async create( document = {} ) {
9
+ return model.aiTicketConfigModel.create( document );
10
+ },
11
+ async deleteOne( query = {} ) {
12
+ return model.aiTicketConfigModel.deleteOne( query );
13
+ },
13
14
  };
14
15
 
16
+ const _svc = createLoggableService( _methods, 'tickets' );
15
17
 
18
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
19
+ export const create = ( ...args ) => _svc.create( ...args );
20
+ export const deleteOne = ( ...args ) => _svc.deleteOne( ...args );
@@ -1,25 +1,32 @@
1
1
  import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
2
3
 
3
- export const findOne = async ( query={}, field={} ) => {
4
- return model.userModel.findOne( query, field ).sort( { userName: 1 } );
4
+ const _methods = {
5
+ async findOne( query={}, field={} ) {
6
+ return model.userModel.findOne( query, field ).sort( { userName: 1 } );
7
+ },
8
+ async find( query={}, field={} ) {
9
+ return model.userModel.find( query, field ).sort( { userName: 1 } );
10
+ },
11
+ async create( document = {} ) {
12
+ return model.userModel.create( document );
13
+ },
14
+ async deleteOne( query = {} ) {
15
+ return model.userModel.deleteOne( query );
16
+ },
17
+ async updateOne( query = {}, record={} ) {
18
+ return model.userModel.updateOne( query, { $set: record } );
19
+ },
20
+ async aggregate( query = {} ) {
21
+ return model.userModel.aggregate( query );
22
+ },
5
23
  };
6
24
 
7
- export const find = async ( query={}, field={} ) => {
8
- return model.userModel.find( query, field ).sort( { userName: 1 } );
9
- };
10
-
11
- export const create = async ( document = {} ) => {
12
- return model.userModel.create( document );
13
- };
14
-
15
- export const deleteOne = async ( query = {} ) => {
16
- return model.userModel.deleteOne( query );
17
- };
18
-
19
- export const updateOne = async ( query = {}, record={} ) => {
20
- return model.userModel.updateOne( query, { $set: record } );
21
- };
25
+ const _svc = createLoggableService( _methods, 'users' );
22
26
 
23
- export const aggregate = async ( query = {} ) => {
24
- return model.userModel.aggregate( query );
25
- };
27
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
28
+ export const find = ( ...args ) => _svc.find( ...args );
29
+ export const create = ( ...args ) => _svc.create( ...args );
30
+ export const deleteOne = ( ...args ) => _svc.deleteOne( ...args );
31
+ export const updateOne = ( ...args ) => _svc.updateOne( ...args );
32
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
@@ -1,10 +1,17 @@
1
1
  import userAssignedStoreModel from 'tango-api-schema/schema/userAssignedStore.model.js';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
2
3
 
3
4
 
4
- export async function aggregateUserAssignedStore( query ) {
5
- return await userAssignedStoreModel.aggregate( query );
5
+ const _methods = {
6
+ async aggregateUserAssignedStore( query ) {
7
+ return await userAssignedStoreModel.aggregate( query );
8
+ },
9
+ async findUserAssignedStore( query ) {
10
+ return await userAssignedStoreModel.find( query );
11
+ },
6
12
  };
7
13
 
8
- export async function findUserAssignedStore( query ) {
9
- return await userAssignedStoreModel.find( query );
10
- };
14
+ const _svc = createLoggableService( _methods, 'userassignedstores' );
15
+
16
+ export const aggregateUserAssignedStore = ( ...args ) => _svc.aggregateUserAssignedStore( ...args );
17
+ export const findUserAssignedStore = ( ...args ) => _svc.findUserAssignedStore( ...args );
@@ -180,11 +180,21 @@ function buildQuestionAnswerEntries( question ) {
180
180
  }
181
181
  }
182
182
  const validationImage = flattenImageRefs( userAnswer?.validationImage );
183
+ // Videos captured alongside 'Capture Multiple Image with description' validation (no runAI; shown as links).
184
+ const validationVideo = flattenImageRefs( userAnswer?.validationVideo );
185
+
186
+ const referenceImage = userAnswer?.referenceImage || matchedAnswer?.referenceImage || '';
187
+ // Left column shows a reference image only for non-image/video, non-multipleImage answer types.
188
+ // When there is no reference image, uploaded/validation media is rendered on the left instead of the right.
189
+ const hasReferenceImage = question?.answerType !== 'image/video' &&
190
+ question?.answerType !== 'multipleImage' &&
191
+ Boolean( referenceImage || multiReferenceImage.length );
183
192
 
184
193
  return {
185
194
  answer: userAnswer?.answer || '',
186
195
  answerType: getMediaDisplayType( question?.answerType, userAnswer ),
187
- referenceImage: userAnswer?.referenceImage || matchedAnswer?.referenceImage || '',
196
+ referenceImage,
197
+ hasReferenceImage,
188
198
  multiReferenceImage,
189
199
  remarks: userAnswer?.remarks || '',
190
200
  sopFlag: userAnswer?.sopFlag ?? matchedAnswer?.sopFlag ?? false,
@@ -192,12 +202,40 @@ function buildQuestionAnswerEntries( question ) {
192
202
  validationType,
193
203
  validationAnswer,
194
204
  validationImage,
205
+ validationVideo,
195
206
  validationDisplayType: getValidationDisplayType( validationType ),
196
207
  };
197
208
  } );
198
209
  }
199
210
 
200
211
 
212
+ /**
213
+ * Extracts every 'Matched/Not Matched' value from a userAnswer's runAIData.
214
+ * Handles both shapes:
215
+ * - [ { answerImage, results: [ { featureName, value } ] } ] (per-image nested)
216
+ * - [ { featureName, value } ] (flat)
217
+ * @param {Array} runAIData
218
+ * @return {string[]} list of 'True' / 'False' values (in source order)
219
+ */
220
+ function getRunAIMatchValues( runAIData ) {
221
+ if ( !Array.isArray( runAIData ) ) return [];
222
+
223
+ const values = [];
224
+
225
+ runAIData.forEach( ( item ) => {
226
+ if ( Array.isArray( item?.results ) ) {
227
+ item.results.forEach( ( res ) => {
228
+ if ( res?.featureName === 'Matched/Not Matched' ) values.push( res.value );
229
+ } );
230
+ } else if ( item?.featureName === 'Matched/Not Matched' ) {
231
+ values.push( item.value );
232
+ }
233
+ } );
234
+
235
+ return values;
236
+ }
237
+
238
+
201
239
  /**
202
240
 
203
241
  * Map section array { sectionName, questions[] } (view API or processed checklist) to scores / template sections.
@@ -247,14 +285,18 @@ function mapSectionsFromQuestionAnswer( questionAnswer ) {
247
285
  let score = q.compliance ? Math.max( ...q?.userAnswer?.map( ( o ) => o?.complianceScore ?? 0 ) ) : 0;
248
286
 
249
287
 
250
- if ( q.answerType == 'image' && q.compliance && q.userAnswer?.[0]?.runAIData ) {
251
- let find = q.userAnswer?.[0]?.runAIData?.find( ( run ) => run?.featureName == 'Matched/Not Matched' );
252
- if ( find ) {
253
- if ( find?.value == 'True' ) {
254
- score = q?.answers?.[0]?.matchedCount;
255
- } else {
256
- score = q?.answers?.[0]?.notMatchedCount;
257
- }
288
+ if ( q.compliance && ( q.answerType === 'image' || q.answerType === 'image/video' ) ) {
289
+ // image/video questions mix image + video entries in userAnswer, so only score the images.
290
+ const imageAnswers = q.answerType === 'image/video' ?
291
+ ( q.userAnswer || [] ).filter( ( ua ) => ua?.answerType === 'image' ) :
292
+ ( q.userAnswer || [] );
293
+
294
+ const matchValues = imageAnswers.flatMap( ( ua ) => getRunAIMatchValues( ua?.runAIData ) );
295
+
296
+ if ( matchValues.length ) {
297
+ // All images must be matched ('True'); if any one is not, treat as not matched.
298
+ const allMatched = matchValues.every( ( value ) => value === 'True' );
299
+ score = allMatched ? ( q?.answers?.[0]?.matchedCount ?? 0 ) : ( q?.answers?.[0]?.notMatchedCount ?? 0 );
258
300
  }
259
301
  }
260
302
 
@@ -481,6 +523,9 @@ export function buildVisitChecklistTemplateDataFromProcessed( processedDoc, bran
481
523
 
482
524
  let referenceId = doc.coverage == 'store' ? doc?.storeName : doc?.userName;
483
525
 
526
+ const userImage = doc.userImage || '';
527
+ const userSignature = doc.userSignature || '';
528
+
484
529
  return {
485
530
 
486
531
 
@@ -512,6 +557,12 @@ export function buildVisitChecklistTemplateDataFromProcessed( processedDoc, bran
512
557
 
513
558
  country: doc.country || '--',
514
559
 
560
+ userImage,
561
+
562
+ userSignature,
563
+
564
+ showUserVerification: Boolean( userImage || userSignature ),
565
+
515
566
  hasCompliancePage,
516
567
 
517
568
  detailPageStart,
@@ -622,6 +673,9 @@ function buildFromViewChecklistApi( getchecklistData, viewchecklistData, brandIn
622
673
  } );
623
674
  }
624
675
 
676
+ const userImage = checklistAnswer?.userImage || checklistInfo?.userImage || '';
677
+ const userSignature = checklistAnswer?.userSignature || checklistInfo?.userSignature || '';
678
+
625
679
  return {
626
680
 
627
681
  brandLogo: brandInfo.brandLogo || '',
@@ -656,6 +710,12 @@ function buildFromViewChecklistApi( getchecklistData, viewchecklistData, brandIn
656
710
 
657
711
  country: storeProfile?.Country || '--',
658
712
 
713
+ userImage,
714
+
715
+ userSignature,
716
+
717
+ showUserVerification: Boolean( userImage || userSignature ),
718
+
659
719
  hasCompliancePage,
660
720
 
661
721
  detailPageStart,
@@ -782,6 +842,16 @@ export function createImageCache() {
782
842
  }
783
843
 
784
844
 
845
+ if ( resolvedData.userImage && resolvedData.userImage.startsWith( 'http' ) ) {
846
+ urls.add( resolvedData.userImage );
847
+ }
848
+
849
+
850
+ if ( resolvedData.userSignature && resolvedData.userSignature.startsWith( 'http' ) ) {
851
+ urls.add( resolvedData.userSignature );
852
+ }
853
+
854
+
785
855
  const collectFromSection = ( section ) => {
786
856
  section.questions?.forEach( ( q ) => {
787
857
  if ( q.questionReferenceImage && q.questionReferenceImage.startsWith( 'http' ) ) urls.add( q.questionReferenceImage );
@@ -842,6 +912,16 @@ export function createImageCache() {
842
912
  }
843
913
 
844
914
 
915
+ if ( resolvedData.userImage ) {
916
+ resolvedData.userImage = cache.get( resolvedData.userImage ) || resolvedData.userImage;
917
+ }
918
+
919
+
920
+ if ( resolvedData.userSignature ) {
921
+ resolvedData.userSignature = cache.get( resolvedData.userSignature ) || resolvedData.userSignature;
922
+ }
923
+
924
+
845
925
  const replaceInSection = ( section ) => {
846
926
  section.questions?.forEach( ( q ) => {
847
927
  if ( q.questionReferenceImage && cache.has( q.questionReferenceImage ) ) q.questionReferenceImage = cache.get( q.questionReferenceImage );
@@ -936,6 +1016,10 @@ export function resolveTemplateUrls( templateData, baseUrl = 'https://d1r0hc2ssk
936
1016
  ua.validationImage = ua.validationImage.map( ( ele ) => resolveUrl( ele ) );
937
1017
  }
938
1018
 
1019
+ if ( ua?.validationVideo?.length ) {
1020
+ ua.validationVideo = ua.validationVideo.map( ( ele ) => resolveUrl( ele ) );
1021
+ }
1022
+
939
1023
 
940
1024
  if ( ua.answer && ua.answerType !== 'text' ) {
941
1025
  ua.answer = resolveUrl( ua.answer );
@@ -954,11 +1038,18 @@ export function resolveTemplateUrls( templateData, baseUrl = 'https://d1r0hc2ssk
954
1038
 
955
1039
  resolvedData.sections?.forEach( resolveQuestionMedia );
956
1040
 
957
-
958
- if ( resolvedData.brandLogo && !resolvedData.brandLogo.startsWith( 'http' ) ) {
1041
+ if ( resolvedData?.brandLogo && !resolvedData?.brandLogo?.startsWith( 'http' ) ) {
959
1042
  resolvedData.brandLogo = resolveUrl( resolvedData.brandLogo );
960
1043
  }
961
1044
 
1045
+ if ( resolvedData?.userImage && !resolvedData.userImage.startsWith( 'http' ) && !resolvedData.userImage.startsWith( 'data:' ) ) {
1046
+ resolvedData.userImage = resolveUrl( resolvedData.userImage );
1047
+ }
1048
+
1049
+ if ( resolvedData?.userSignature && !resolvedData.userSignature.startsWith( 'http' ) && !resolvedData.userSignature.startsWith( 'data:' ) ) {
1050
+ resolvedData.userSignature = resolveUrl( resolvedData.userSignature );
1051
+ }
1052
+
962
1053
 
963
1054
  return resolvedData;
964
1055
  }
@@ -1070,6 +1161,10 @@ export async function generateVisitChecklistPDF( templateData, baseUrl = 'https:
1070
1161
  ua.validationImage = ua.validationImage.map( ( ele ) => resolveUrl( ele ) );
1071
1162
  }
1072
1163
 
1164
+ if ( ua.validationVideo?.length ) {
1165
+ ua.validationVideo = ua.validationVideo.map( ( ele ) => resolveUrl( ele ) );
1166
+ }
1167
+
1073
1168
  if ( ua.answer && ua.answerType !== 'text' ) {
1074
1169
  ua.answer = resolveUrl( ua.answer );
1075
1170
  }
@@ -1087,6 +1182,14 @@ export async function generateVisitChecklistPDF( templateData, baseUrl = 'https:
1087
1182
  resolvedData.brandLogo = resolveUrl( resolvedData.brandLogo );
1088
1183
  }
1089
1184
 
1185
+ if ( resolvedData.userImage && !resolvedData.userImage.startsWith( 'http' ) && !resolvedData.userImage.startsWith( 'data:' ) ) {
1186
+ resolvedData.userImage = resolveUrl( resolvedData.userImage );
1187
+ }
1188
+
1189
+ if ( resolvedData.userSignature && !resolvedData.userSignature.startsWith( 'http' ) && !resolvedData.userSignature.startsWith( 'data:' ) ) {
1190
+ resolvedData.userSignature = resolveUrl( resolvedData.userSignature );
1191
+ }
1192
+
1090
1193
 
1091
1194
  const html = template( resolvedData );
1092
1195