tango-app-api-client 3.1.14 → 3.1.16

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.
@@ -1,21 +1,23 @@
1
- import { billingDetailsUpdate, brandInfoUpdate, domainDetailsConfigurationUpdate, featureConfigurationUpdate, getClientData, signatoryDetailsUpdate, ticketConfigurationUpdate, documentsUpdate, getUserData, auditConfigurationUpdate, auditConfigurationGet, CsmUsersGet, OpsUsersGet, userConfigurationUpdate, findClient, aggregateClient, createAuditQueue, findOne, insert, update, findOneClient } from '../service/client.service.js';
2
- import { checkFileExist, fileUpload, signedUrl, chunkArray, download, logger, getOpenSearchData, insertOpenSearchData, appConfig, sendEmailWithSES } from 'tango-app-api-middleware';
1
+ import { billingDetailsUpdate, brandInfoUpdate, domainDetailsConfigurationUpdate, featureConfigurationUpdate, getClientData, signatoryDetailsUpdate, ticketConfigurationUpdate, documentsUpdate, getUserData, auditConfigurationUpdate, auditConfigurationGet, CsmUsersGet, OpsUsersGet, userConfigurationUpdate, findClient, aggregateClient, createAuditQueue, findOne, insert, update, findOneClient, updateOneClient } from '../service/client.service.js';
2
+ import { checkFileExist, fileUpload, signedUrl, chunkArray, download, logger, getOpenSearchData, insertOpenSearchData, sendEmailWithSES } from 'tango-app-api-middleware';
3
3
  import { countDocumentsUser, findOneAndUpdateUser, findOneUser, getUserNameEmailById, updateManyUser } from '../service/user.service.js';
4
- import { aggregateStore, countDocumentsStore, updateManyStore } from '../service/store.service.js';
5
- import { aggregateCamera, countDocumentsCamera, updateManyCamera } from '../service/camera.service.js';
4
+ import { aggregateStore, countDocumentsStore, findStore, findOneStore, updateManyStore } from '../service/store.service.js';
5
+ import { aggregateCamera, countDocumentsCamera } from '../service/camera.service.js';
6
6
  import _ from 'lodash';
7
7
  import { findOneStandaredRole } from '../service/standaredRole.service.js';
8
- import { aggregateUserAssignedStore } from '../service/userAssignedStore.service.js';
8
+ import { aggregateUserAssignedStore, deleteOneAssignedStore, updateOneUserAssignedStore } from '../service/userAssignedStore.service.js';
9
9
  import { aggregateTickets } from '../service/tangoticket.service.js';
10
10
  import { join } from 'path';
11
11
  import { readFileSync } from 'fs';
12
12
  import handlebars from 'handlebars';
13
- import { countDocumentsGroup } from '../service/group.service.js';
13
+ import { countDocumentsGroup, createGroupModel, findOneGroup } from '../service/group.service.js';
14
14
  import { deleteOneAuthentication } from '../service/authentication.service.js';
15
15
 
16
16
 
17
17
  export async function create( req, res ) {
18
18
  try {
19
+ const url = JSON.parse( process.env.URL );
20
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
19
21
  const inputData = req.body;
20
22
  const countQuery = [
21
23
  {
@@ -71,9 +73,33 @@ export async function create( req, res ) {
71
73
 
72
74
  const insertClient = await insert( record );
73
75
 
76
+ const insertedClientRecord = await findOneClient( { clientId: record.clientId }, {} );
77
+
78
+ const defaultGroup = {
79
+ 'groupName': 'All stores',
80
+ 'description': 'Contains all the onboarded stores',
81
+ 'storeList': [],
82
+ 'clientId': insertedClientRecord.clientId,
83
+ 'isDefault': true,
84
+ };
85
+
86
+ await createGroupModel( defaultGroup );
87
+
88
+ const createdGroup = await findOneGroup( { clientId: insertedClientRecord.clientId, isDefault: true }, {} );
89
+
90
+ let oldGroup = {
91
+ '_id': createdGroup._id,
92
+ 'client_id': createdGroup.clientId,
93
+ 'groupName': createdGroup.groupName,
94
+ 'description': createdGroup.description,
95
+ 'storeList': createdGroup.storeList,
96
+ };
97
+
98
+
99
+ await postApi( `${url.oldapidomain}/oldGroupAdd`, [ oldGroup ] );
100
+
74
101
  // For old dashboard insert
75
102
 
76
- const insertedClientRecord = await findOneClient( { clientId: record.clientId }, {} );
77
103
 
78
104
  const oldBrandInsertData = {
79
105
  '_id': insertedClientRecord._id,
@@ -93,9 +119,7 @@ export async function create( req, res ) {
93
119
  'birdsEye',
94
120
  'tangoZone',
95
121
  'tangoTraffic',
96
- 'Support',
97
- 'footFallDirectory',
98
- 'tangoSOP',
122
+ 'support',
99
123
  ],
100
124
  'planType': insertedClientRecord.planDetails.subscriptionPeriod,
101
125
  'storeCount': insertedClientRecord.planDetails.totalStores,
@@ -176,9 +200,47 @@ export async function create( req, res ) {
176
200
  'role': 'storesuperadmin',
177
201
  };
178
202
 
179
- await postApi( `${appConfig.url.oldapidomain}/oldBrandAdd`, oldBrandInsertData );
203
+ await postApi( `${url.oldapidomain}/oldBrandAdd`, oldBrandInsertData );
204
+
205
+ await postApi( `${url.oldapidomain}/oldDefaultRoleInsert`, oldDefaultRolesInsertData );
206
+
207
+ const logObj = {
208
+ clientId: insertedClientRecord.clientId,
209
+ userName: req.user?.userName,
210
+ email: req.user?.email,
211
+ date: new Date(),
212
+ logType: 'brandDetails',
213
+ logSubType: 'brandApproval',
214
+ changes: [ insertedClientRecord.clientName ],
215
+ showTo: [],
216
+ eventType: 'approve',
217
+ showTo: [ 'client', 'tango' ],
218
+ };
219
+
220
+ await insertOpenSearchData( openSearch.activityLog, logObj );
221
+
222
+ for ( let index = 0; index < leadRecord?.planDetails?.product?.length; index++ ) {
223
+ const logObj = {
224
+ userName: req.user?.userName,
225
+ email: req.user?.email,
226
+ clientId: insertedClientRecord.clientId,
227
+ clientNotification: false,
228
+ adminNotification: true,
229
+ logSubType: 'startTrial',
230
+ description: 'Subscription - Your 14 Days free trial has been started',
231
+ title: 'Subscription',
232
+ alertCta: [],
233
+ markasRead: false,
234
+ logType: 'subscription',
235
+ showPushNotification: true,
236
+ date: new Date(),
237
+ changes: [ `${convertTitleCase( leadRecord?.planDetails?.product[index] )} trial started` ],
238
+ eventType: '',
239
+ showTo: [ 'client', 'tango' ],
240
+ };
180
241
 
181
- await postApi( `${appConfig.url.oldapidomain}/oldDefaultRoleInsert`, oldDefaultRolesInsertData );
242
+ await insertOpenSearchData( openSearch.activityLog, logObj );
243
+ }
182
244
 
183
245
 
184
246
  if ( insertClient ) {
@@ -200,14 +262,23 @@ export async function create( req, res ) {
200
262
  }
201
263
  }
202
264
 
265
+ function convertTitleCase( data ) {
266
+ let [ firstWord, secondWord ] = data.replace( /([a-z])([A-Z])/g, '$1 $2' ).split( ' ' );
267
+ firstWord = firstWord.charAt( 0 ).toUpperCase() + firstWord.slice( 1 );
268
+ data = firstWord + ' ' + secondWord;
269
+ return data;
270
+ }
271
+
203
272
  export const sendEmail = ( data ) => {
204
273
  try {
274
+ const url = JSON.parse( process.env.URL );
275
+ const ses = JSON.parse( process.env.SES );
205
276
  const attachments = null;
206
277
  const subject = data.subject;
207
278
  const fileContent = readFileSync( join() + data.path, 'utf8' );
208
279
  const htmlContent = handlebars.compile( fileContent );
209
- const html = htmlContent( { url: appConfig.url.store, logo: `${appConfig.url.domain}/logo.png` } );
210
- return sendEmailWithSES( data.email, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
280
+ const html = htmlContent( { url: url.store, logo: `${url.apiDomain}/logo.png` } );
281
+ return sendEmailWithSES( data.email, subject, html, attachments, ses.adminEmail );
211
282
  } catch ( error ) {
212
283
  return error;
213
284
  }
@@ -249,6 +320,18 @@ export async function getClients( req, res ) {
249
320
  $match: {
250
321
  userEmail: req?.user?.email,
251
322
  assignedType: { $eq: 'client' },
323
+ $expr: {
324
+ $cond: {
325
+ if: {
326
+ $and: [
327
+ { $eq: [ '$userType', 'tango' ] },
328
+ { $eq: [ '$tangoUserType', 'csm' ] },
329
+ ],
330
+ },
331
+ then: { $eq: [ '$isClientApproved', true ] },
332
+ else: true,
333
+ },
334
+ },
252
335
  },
253
336
  },
254
337
  {
@@ -302,61 +385,62 @@ export async function getClients( req, res ) {
302
385
 
303
386
  export async function clientDetails( req, res ) {
304
387
  try {
388
+ const bucket = JSON.parse( process.env.BUCKET );
305
389
  const client = await getClientData( { id: req.params.id } );
306
390
  if ( client ) {
307
- const isLogoExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
308
- const isGstCertificateExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `${client.clientId}/documents/${client.document?.gst?.path}` } );
309
- const isAddressCertificateExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `${client.clientId}/documents/${client.document?.addressProof?.path}` } );
310
- const isPanCertificateExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `${client.clientId}/documents/${client.document?.pan?.path}` } );
311
- const isCinCertificateExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `${client.clientId}/documents/${client.document?.cin?.path}` } );
312
- const isContractCertificateExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `documents/contract.pdf` } );
313
- const isTermsAndConditionsExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `documents/terms&conditions.pdf` } );
391
+ const isLogoExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
392
+ const isGstCertificateExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/documents/${client.document?.gst?.path}` } );
393
+ const isAddressCertificateExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/documents/${client.document?.addressProof?.path}` } );
394
+ const isPanCertificateExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/documents/${client.document?.pan?.path}` } );
395
+ const isCinCertificateExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/documents/${client.document?.cin?.path}` } );
396
+ const isContractCertificateExist = await checkFileExist( { Bucket: bucket.assets, Key: `documents/contract.pdf` } );
397
+ const isTermsAndConditionsExist = await checkFileExist( { Bucket: bucket.assets, Key: `documents/terms&conditions.pdf` } );
314
398
 
315
399
 
316
400
  if ( isLogoExist ) {
317
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
401
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
318
402
  client.profileDetails.logo = signedFilUrl;
319
403
  } else {
320
404
  client.profileDetails.logo = '';
321
405
  }
322
406
 
323
407
  if ( isGstCertificateExist ) {
324
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `${client.clientId}/documents/${client.document?.gst?.path}` } );
408
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/documents/${client.document?.gst?.path}` } );
325
409
  client.document.gst.path = signedFilUrl;
326
410
  } else {
327
411
  client.document.gst.path = '';
328
412
  }
329
413
 
330
414
  if ( isAddressCertificateExist ) {
331
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `${client.clientId}/documents/${client.document?.addressProof?.path}` } );
415
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/documents/${client.document?.addressProof?.path}` } );
332
416
  client.document.addressProof.path = signedFilUrl;
333
417
  } else {
334
418
  client.document.addressProof.path = '';
335
419
  }
336
420
 
337
421
  if ( isPanCertificateExist ) {
338
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `${client.clientId}/documents/${client.document?.pan?.path}` } );
422
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/documents/${client.document?.pan?.path}` } );
339
423
  client.document.pan.path = signedFilUrl;
340
424
  } else {
341
425
  client.document.pan.path = '';
342
426
  }
343
427
 
344
428
  if ( isCinCertificateExist ) {
345
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `${client.clientId}/documents/${client.document?.cin?.path}` } );
429
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/documents/${client.document?.cin?.path}` } );
346
430
  client.document.cin.path = signedFilUrl;
347
431
  } else {
348
432
  client.document.cin.path = '';
349
433
  }
350
434
 
351
435
  if ( isContractCertificateExist ) {
352
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `documents/contract.pdf` } );
436
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `documents/contract.pdf` } );
353
437
  client._doc.document.contract = signedFilUrl;
354
438
  } else {
355
439
  client._doc.document.contract = '';
356
440
  }
357
441
 
358
442
  if ( isTermsAndConditionsExist ) {
359
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `documents/terms&conditions.pdf` } );
443
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `documents/terms&conditions.pdf` } );
360
444
  client._doc.document.termsAndconditions = signedFilUrl;
361
445
  } else {
362
446
  client._doc.document.termsAndconditions = '';
@@ -382,18 +466,30 @@ export async function detailedAllClientCount( req, res ) {
382
466
  {
383
467
  $project: {
384
468
  activeClient: { $cond: [ { $eq: [ '$status', 'active' ] }, 1, 0 ] },
385
- paidClient: { $cond: [ { $and: [
386
- { $eq: [ '$status', 'active' ] },
387
- { $in: [ '$planDetails.paymentStatus', [ 'paid', 'unbilled', 'due' ] ] },
388
- ] }, 1, 0 ] },
389
- trialClient: { $cond: [ { $and: [
390
- { $eq: [ '$status', 'active' ] },
391
- { $eq: [ '$planDetails.paymentStatus', 'trial' ] },
392
- ] }, 1, 0 ] },
393
-
394
- freeClient: { $cond: [ { $and: [
395
- { $eq: [ '$status', 'active' ] }, { $eq: [ '$planDetails.paymentStatus', 'free' ] },
396
- ] }, 1, 0 ] },
469
+ paidClient: {
470
+ $cond: [ {
471
+ $and: [
472
+ { $eq: [ '$status', 'active' ] },
473
+ { $in: [ '$planDetails.paymentStatus', [ 'paid', 'unbilled', 'due' ] ] },
474
+ ],
475
+ }, 1, 0 ],
476
+ },
477
+ trialClient: {
478
+ $cond: [ {
479
+ $and: [
480
+ { $eq: [ '$status', 'active' ] },
481
+ { $eq: [ '$planDetails.paymentStatus', 'trial' ] },
482
+ ],
483
+ }, 1, 0 ],
484
+ },
485
+
486
+ freeClient: {
487
+ $cond: [ {
488
+ $and: [
489
+ { $eq: [ '$status', 'active' ] }, { $eq: [ '$planDetails.paymentStatus', 'free' ] },
490
+ ],
491
+ }, 1, 0 ],
492
+ },
397
493
  holdClient: { $cond: [ { $eq: [ '$status', 'hold' ] }, 1, 0 ] },
398
494
  suspendClient: { $cond: [ { $eq: [ '$status', 'suspended' ] }, 1, 0 ] },
399
495
  deactiveClient: { $cond: [ { $eq: [ '$status', 'deactive' ] }, 1, 0 ] },
@@ -413,11 +509,34 @@ export async function detailedAllClientCount( req, res ) {
413
509
 
414
510
  },
415
511
  },
512
+ {
513
+ $project: {
514
+ _id: 0,
515
+ totalCount: 1,
516
+ activeClient: 1,
517
+ paidClient: 1,
518
+ trialClient: 1,
519
+ freeClient: 1,
520
+ holdClient: 1,
521
+ suspendClient: 1,
522
+ deactiveClient: 1,
523
+ activeStoresCount: { $ifNull: [ 0, 0 ] },
524
+ activeCameraCount: { $ifNull: [ 0, 0 ] },
525
+ },
526
+ },
416
527
  ];
417
528
  const result = await aggregateClient( query );
418
- if ( result == 0 ) {
529
+ const activeStores = await findStore( { 'status': 'active', 'edge.firstFile': true }, { storeId: 1 } );
530
+ let storesList = [];
531
+ for ( let store of activeStores ) {
532
+ storesList.push( store.storeId );
533
+ }
534
+ const activeCameras = await countDocumentsCamera( { storeId: { $in: storesList }, isUp: true, isActivated: true } );
535
+ if ( result.length == 0 ) {
419
536
  return res.sendError( 'No Data Found', 204 );
420
537
  }
538
+ result[0].activeStoresCount = activeStores.length;
539
+ result[0].activeCameraCount = activeCameras;
421
540
  return res.sendSuccess( { result: result } );
422
541
  } catch ( error ) {
423
542
  logger.error( { error: error, function: 'detailedAllClientCount' } );
@@ -433,11 +552,14 @@ function camelCaseToWords( camelCaseString ) {
433
552
 
434
553
  export async function updateBrandInfo( req, res ) {
435
554
  try {
555
+ const bucket = JSON.parse( process.env.BUCKET );
556
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
557
+ const url = JSON.parse( process.env.URL );
436
558
  let updateKeys = [];
437
559
 
438
560
  if ( req.files?.logo ) {
439
561
  const uploadDataParams = {
440
- Bucket: appConfig.cloud.aws.bucket.assets,
562
+ Bucket: bucket.assets,
441
563
  Key: `${req.params.id}/logo/`,
442
564
  fileName: `brandLogo.${req.files.logo.name.split( '.' )[1]}`,
443
565
  ContentType: req.files.logo.mimetype,
@@ -465,9 +587,12 @@ export async function updateBrandInfo( req, res ) {
465
587
  logSubType: 'brandInfo',
466
588
  changes: updateKeys,
467
589
  eventType: 'update',
590
+ showTo: [ 'client', 'tango' ],
468
591
  };
469
592
 
470
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
593
+ if ( updateKeys.length ) {
594
+ await insertOpenSearchData( openSearch.activityLog, logObj );
595
+ }
471
596
 
472
597
 
473
598
  const updateAck = await brandInfoUpdate( {
@@ -492,11 +617,11 @@ export async function updateBrandInfo( req, res ) {
492
617
 
493
618
  if ( req.body?.status === 'deactive' ) {
494
619
  await updateManyStore( { clientId: req.params?.id }, { status: 'deactive' } );
495
- await updateManyCamera( { clientId: req.params?.id }, { isUp: false, isActivated: false } );
620
+ // await updateManyCamera( { clientId: req.params?.id }, { isUp: false, isActivated: false } );
496
621
  await updateManyUser( { clientId: req.params?.id }, { isActive: false } );
497
622
  }
498
623
 
499
- const { data } = await getApi( `${appConfig.url.oldapidomain}/oldBrandGet/${req.params?.id}` );
624
+ const { data } = await getApi( `${url.oldapidomain}/oldBrandGet/${req.params?.id}` );
500
625
 
501
626
  switch ( req.body?.status ) {
502
627
  case 'active':
@@ -515,7 +640,7 @@ export async function updateBrandInfo( req, res ) {
515
640
  data.clientStatus = 'live';
516
641
  }
517
642
 
518
- await postApi( `${appConfig.url.oldapidomain}/oldBrandUpdate/${data?._id}`, { clientStatus: data.clientStatus } );
643
+ await postApi( `${url.oldapidomain}/oldBrandUpdate/${data?._id}`, { clientStatus: data.clientStatus } );
519
644
 
520
645
  if ( updateAck ) {
521
646
  res.sendSuccess( { result: 'Updated Successfully' } );
@@ -528,11 +653,13 @@ export async function updateBrandInfo( req, res ) {
528
653
 
529
654
  export async function updateBillingDetails( req, res ) {
530
655
  try {
656
+ const bucket = JSON.parse( process.env.BUCKET );
657
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
531
658
  let updateKeys = [];
532
659
 
533
660
  if ( req.files?.gstCertificate ) {
534
661
  const uploadDataParams = {
535
- Bucket: appConfig.cloud.aws.bucket.assets,
662
+ Bucket: bucket.assets,
536
663
  Key: `${req.params.id}/documents/`,
537
664
  fileName: `gstCertificate.${req.files.gstCertificate.name.split( '.' )[1]}`,
538
665
  ContentType: req.files.gstCertificate.mimetype,
@@ -559,9 +686,13 @@ export async function updateBillingDetails( req, res ) {
559
686
  logSubType: 'billingDetails',
560
687
  changes: updateKeys,
561
688
  eventType: 'update',
689
+ showTo: [ 'client', 'tango' ],
562
690
  };
563
691
 
564
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
692
+ if ( updateKeys.length ) {
693
+ await insertOpenSearchData( openSearch.activityLog, logObj );
694
+ }
695
+
565
696
 
566
697
  const updateAck = await billingDetailsUpdate( {
567
698
  clientId: req.params?.id, tradeName: req.body?.tradeName, gstNumber: req.body?.gstNumber,
@@ -579,6 +710,7 @@ export async function updateBillingDetails( req, res ) {
579
710
 
580
711
  export async function updateSignatoryDetails( req, res ) {
581
712
  try {
713
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
582
714
  let updateKeys = [];
583
715
  if ( Object.keys( req.body ).length > 0 ) {
584
716
  Object.keys( req.body ).forEach( ( element ) => {
@@ -597,9 +729,13 @@ export async function updateSignatoryDetails( req, res ) {
597
729
  logSubType: 'signatoryDetails',
598
730
  changes: updateKeys,
599
731
  eventType: 'update',
732
+ showTo: [ 'client', 'tango' ],
600
733
  };
601
734
 
602
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
735
+ if ( updateKeys.length ) {
736
+ await insertOpenSearchData( openSearch.activityLog, logObj );
737
+ }
738
+
603
739
  const updateAck = await signatoryDetailsUpdate( {
604
740
  clientId: req.params?.id, name: req.body?.name, email: req.body?.email,
605
741
  number: req.body?.number, designation: req.body?.designation,
@@ -615,6 +751,7 @@ export async function updateSignatoryDetails( req, res ) {
615
751
 
616
752
  export async function updateTicketConfiguration( req, res ) {
617
753
  try {
754
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
618
755
  const updateAck = await ticketConfigurationUpdate( {
619
756
  clientId: req.params?.id, MinFilesCount: req.body?.MinFilesCount, accuracyPercentage: req.body?.accuracyPercentage, downTimeType: req.body?.downTimeType,
620
757
  infraDownTime: req.body?.infraDownTime, installationReAssign: req.body?.installationReAssign, isRcaTicketAssign: req.body?.isRcaTicketAssign,
@@ -640,8 +777,12 @@ export async function updateTicketConfiguration( req, res ) {
640
777
  logSubType: 'ticketConfig',
641
778
  changes: updateKeys,
642
779
  eventType: 'update',
780
+ showTo: [ 'tango' ],
643
781
  };
644
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
782
+
783
+ if ( updateKeys.length ) {
784
+ await insertOpenSearchData( openSearch.activityLog, logObj );
785
+ }
645
786
 
646
787
  if ( updateAck ) {
647
788
  res.sendSuccess( { result: 'Updated Successfully' } );
@@ -654,11 +795,14 @@ export async function updateTicketConfiguration( req, res ) {
654
795
 
655
796
  export async function updateFeatureConfiguration( req, res ) {
656
797
  try {
798
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
799
+ const url = JSON.parse( process.env.URL );
657
800
  const updateAck = await featureConfigurationUpdate( {
658
801
  clientId: req.params?.id, billableCalculation: req.body?.billableCalculation, bouncedLimitCondition: req.body?.bouncedLimitCondition, bouncedLimitValue: req.body?.bouncedLimitValue,
659
802
  close: req.body?.close, conversionCalculation: req.body?.conversionCalculation, conversionCondition: req.body?.conversionCondition,
660
803
  conversionValue: req.body?.conversionValue, infraAlertCondition: req.body?.infraAlertCondition, infraAlertValue: req.body?.infraAlertValue, isFootfallDirectory: req.body?.isFootfallDirectory,
661
804
  isNormalized: req.body?.isNormalized, isPasserByData: req.body?.isPasserByData, missedOpportunityCalculation: req.body?.missedOpportunityCalculation, open: req.body?.open,
805
+ isExcludedArea: req.body?.isExcludedArea,
662
806
  } );
663
807
 
664
808
  let updateKeys = [];
@@ -671,7 +815,7 @@ export async function updateFeatureConfiguration( req, res ) {
671
815
 
672
816
  const user = await getUserNameEmailById( req.userId );
673
817
 
674
- const { data } = await getApi( `${appConfig.url.oldapidomain}/oldBrandGet/${req.params?.id}` );
818
+ const { data } = await getApi( `${url.oldapidomain}/oldBrandGet/${req.params?.id}` );
675
819
 
676
820
  if ( req.body?.open ) {
677
821
  data.brandConfigs.storeOpenTime = req.body?.open;
@@ -713,7 +857,7 @@ export async function updateFeatureConfiguration( req, res ) {
713
857
  data.brandConfigs.missedOpportunityEndTime = data.brandConfigs.missedOpportunityEndTime.replace( /\d+/, req.body?.conversionValue );
714
858
  }
715
859
 
716
- await postApi( `${appConfig.url.oldapidomain}/oldBrandUpdate/${data?._id}`, { brandConfigs: data.brandConfigs } );
860
+ await postApi( `${url.oldapidomain}/oldBrandUpdate/${data?._id}`, { brandConfigs: data.brandConfigs } );
717
861
 
718
862
 
719
863
  const logObj = {
@@ -725,8 +869,11 @@ export async function updateFeatureConfiguration( req, res ) {
725
869
  logSubType: 'featureConfig',
726
870
  changes: updateKeys,
727
871
  eventType: 'update',
872
+ showTo: [ 'client', 'tango' ],
728
873
  };
729
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
874
+ if ( updateKeys.length ) {
875
+ await insertOpenSearchData( openSearch.activityLog, logObj );
876
+ }
730
877
 
731
878
  if ( updateAck ) {
732
879
  res.sendSuccess( { result: 'Updated Successfully' } );
@@ -739,6 +886,7 @@ export async function updateFeatureConfiguration( req, res ) {
739
886
 
740
887
  export async function domainDetailsConfiguration( req, res ) {
741
888
  try {
889
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
742
890
  const updateAck = await domainDetailsConfigurationUpdate( {
743
891
  clientId: req.params?.id, domainName: req.body?.domainName, isEnable: req.body?.isEnable,
744
892
  } );
@@ -764,9 +912,13 @@ export async function domainDetailsConfiguration( req, res ) {
764
912
  logSubType: 'domainDetails',
765
913
  changes: updateKeys,
766
914
  eventType: 'update',
915
+ showTo: [ 'client', 'tango' ],
767
916
  };
768
917
 
769
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
918
+ if ( updateKeys.length ) {
919
+ await insertOpenSearchData( openSearch.activityLog, logObj );
920
+ }
921
+
770
922
  if ( updateAck ) {
771
923
  res.sendSuccess( { result: 'Updated Successfully' } );
772
924
  }
@@ -792,11 +944,13 @@ export async function userConfiguration( req, res ) {
792
944
 
793
945
  export async function updateDocuments( req, res ) {
794
946
  try {
947
+ const bucket = JSON.parse( process.env.BUCKET );
948
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
795
949
  let updateKeys = [];
796
950
 
797
951
  if ( req.files?.addressDoc ) {
798
952
  const uploadDataParams = {
799
- Bucket: appConfig.cloud.aws.bucket.assets,
953
+ Bucket: bucket.assets,
800
954
  Key: `${req.params.id}/documents/`,
801
955
  fileName: `addressCertificate.${req.files.addressDoc.name.split( '.' )[1]}`,
802
956
  ContentType: req.files.addressDoc.mimetype,
@@ -809,7 +963,7 @@ export async function updateDocuments( req, res ) {
809
963
  }
810
964
  if ( req.files?.gstDoc ) {
811
965
  const uploadDataParams = {
812
- Bucket: appConfig.cloud.aws.bucket.assets,
966
+ Bucket: bucket.assets,
813
967
  Key: `${req.params.id}/documents/`,
814
968
  fileName: `gstCertificate.${req.files.gstDoc.name.split( '.' )[1]}`,
815
969
  ContentType: req.files.gstDoc.mimetype,
@@ -822,7 +976,7 @@ export async function updateDocuments( req, res ) {
822
976
  }
823
977
  if ( req.files?.panDoc ) {
824
978
  const uploadDataParams = {
825
- Bucket: appConfig.cloud.aws.bucket.assets,
979
+ Bucket: bucket.assets,
826
980
  Key: `${req.params.id}/documents/`,
827
981
  fileName: `panCertificate.${req.files.panDoc.name.split( '.' )[1]}`,
828
982
  ContentType: req.files.panDoc.mimetype,
@@ -835,7 +989,7 @@ export async function updateDocuments( req, res ) {
835
989
  }
836
990
  if ( req.files?.cinDoc ) {
837
991
  const uploadDataParams = {
838
- Bucket: appConfig.cloud.aws.bucket.assets,
992
+ Bucket: bucket.assets,
839
993
  Key: `${req.params.id}/documents/`,
840
994
  fileName: `cinCertificate.${req.files.cinDoc.name.split( '.' )[1]}`,
841
995
  ContentType: req.files.cinDoc.mimetype,
@@ -874,9 +1028,12 @@ export async function updateDocuments( req, res ) {
874
1028
  logSubType: 'documentUpload',
875
1029
  changes: updateKeys,
876
1030
  eventType: 'update',
1031
+ showTo: [ 'client', 'tango' ],
877
1032
  };
878
1033
 
879
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
1034
+ if ( updateKeys.length ) {
1035
+ await insertOpenSearchData( openSearch.activityLog, logObj );
1036
+ }
880
1037
 
881
1038
  if ( updateAck ) {
882
1039
  res.sendSuccess( { result: 'Updated Successfully' } );
@@ -889,11 +1046,12 @@ export async function updateDocuments( req, res ) {
889
1046
 
890
1047
  export async function getAuditConfiguration( req, res ) {
891
1048
  try {
1049
+ const bucket = JSON.parse( process.env.BUCKET );
892
1050
  const auditConfig = await auditConfigurationGet( { storeId: req.params?.id } );
893
1051
  if ( auditConfig ) {
894
- const isDocExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `templates/audit_bulk_update.xlsx` } );
1052
+ const isDocExist = await checkFileExist( { Bucket: bucket.assets, Key: `templates/audit_bulk_update.xlsx` } );
895
1053
  if ( isDocExist ) {
896
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `templates/audit_bulk_update.xlsx` } );
1054
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `templates/audit_bulk_update.xlsx` } );
897
1055
  auditConfig._doc.templateUrl = signedFilUrl;
898
1056
  } else {
899
1057
  auditConfig._doc.templateUrl = '';
@@ -911,36 +1069,39 @@ export async function getAuditConfiguration( req, res ) {
911
1069
 
912
1070
  export async function auditConfiguration( req, res ) {
913
1071
  try {
1072
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
914
1073
  for ( let i = 0; i < req.body?.length; i++ ) {
1074
+ const previousStore = await findOneStore( { storeId: req.body[i].storeId }, { auditConfigs: 1, _id: 0 } );
915
1075
  await auditConfigurationUpdate( {
916
1076
  storeId: req.body[i].storeId,
917
1077
  count: req.body[i].count,
918
1078
  iteration: req.body[i].iteration,
919
1079
  ratio: normalizeNumber( req.body[i].ratio, 0, 100 ),
920
1080
  } );
921
- }
922
-
923
- const user = await getUserNameEmailById( req.userId );
924
1081
 
925
- const logObj = {
926
- clientId: req.params?.id,
927
- userName: user.userName,
928
- email: user.email,
929
- date: new Date(),
930
- logType: 'configuration',
931
- logSubType: 'auditConfig',
932
- eventType: 'update',
933
- };
934
-
935
- if ( req.body?.length === 1 ) {
936
- logObj.changes = [ `Audit config for store id ${req.body[0].storeId}` ];
937
- }
1082
+ const logObj = {
1083
+ clientId: req.params?.id,
1084
+ userName: req.user?.userName,
1085
+ email: req.user?.email,
1086
+ date: new Date(),
1087
+ logType: 'configuration',
1088
+ logSubType: 'auditConfig',
1089
+ eventType: 'update',
1090
+ showTo: [ 'tango' ],
1091
+ changes: [ `Audit config for store id ${req.body[i].storeId}` ],
1092
+ storeId: req.body[i].storeId,
1093
+ previous: previousStore,
1094
+ current: {
1095
+ storeId: req.body[i].storeId,
1096
+ count: req.body[i].count,
1097
+ iteration: req.body[i].iteration,
1098
+ ratio: normalizeNumber( req.body[i].ratio, 0, 100 ),
1099
+ },
1100
+ };
938
1101
 
939
- if ( req.body?.length > 1 ) {
940
- logObj.changes = [ `Audit config bulk` ];
1102
+ await insertOpenSearchData( openSearch.activityLog, logObj );
941
1103
  }
942
1104
 
943
- await insertOpenSearchData( 'tango-retail-activity-logs', logObj );
944
1105
 
945
1106
  res.sendSuccess( { result: 'Updated Successfully' } );
946
1107
  } catch ( error ) {
@@ -978,6 +1139,17 @@ export async function clientList( req, res ) {
978
1139
  $match: {
979
1140
  userEmail: { $eq: req?.user?.email },
980
1141
  userType: 'tango',
1142
+ $expr: {
1143
+ $cond: {
1144
+ if: {
1145
+ $and: [
1146
+ { $eq: [ '$tangoUserType', 'csm' ] },
1147
+ ],
1148
+ },
1149
+ then: { $eq: [ '$isClientApproved', true ] },
1150
+ else: true,
1151
+ },
1152
+ },
981
1153
 
982
1154
  },
983
1155
  }, {
@@ -990,7 +1162,7 @@ export async function clientList( req, res ) {
990
1162
  ];
991
1163
  const clientIdList = await aggregateUserAssignedStore( query );
992
1164
  logger.info( { message: clientIdList, value: 'clientIdList' } );
993
- if ( clientIdList.length ==0 ) {
1165
+ if ( clientIdList.length == 0 ) {
994
1166
  return res.sendError( 'No Data Found', 204 );
995
1167
  }
996
1168
 
@@ -1003,6 +1175,10 @@ export async function clientList( req, res ) {
1003
1175
  );
1004
1176
  }
1005
1177
  if ( inputData.filterByPaymentStatus ) {
1178
+ if ( inputData.filterByPaymentStatus.includes( 'paid' ) ) {
1179
+ inputData.filterByPaymentStatus.push( ...[ 'unbilled', 'due' ] );
1180
+ }
1181
+
1006
1182
  clientQuery.push(
1007
1183
  {
1008
1184
  $match: {
@@ -1253,8 +1429,13 @@ export async function clientList( req, res ) {
1253
1429
  list.push( {
1254
1430
  'client Name': chunk[i]?.clientName,
1255
1431
  'client Id': chunk[i]?.clientId,
1432
+ 'Installation Stores Count': chunk[i]?.installedStores || 0,
1433
+ 'Onboarded Stores Count': chunk[i]?.totalStores,
1434
+ 'Store Progress': chunk[i]?.installedStores ? `${( ( chunk[i]?.installedStores / chunk[i]?.totalStores ) * 100 ).toFixed( 0 )}%` : '0%',
1256
1435
  'Active Store': chunk[i]?.activeStoreCount || 0,
1257
1436
  'Active Camera': chunk[i]?.activeCameraCount && chunk[i]?.activeCameraCount != undefined ? chunk[i]?.activeCameraCount : 0,
1437
+ 'Pending Stores': chunk[i]?.pendingStores || 0,
1438
+ 'Failed Stores': chunk[i]?.failedStores || 0,
1258
1439
  'Payment Status': chunk[i]?.paymentStatus,
1259
1440
  'Subs Plan': chunk[i]?.subscriptionType,
1260
1441
  'Status': chunk[i]?.status,
@@ -1273,7 +1454,344 @@ export async function clientList( req, res ) {
1273
1454
  return res.sendError( 'Internal Server Error', 500 );
1274
1455
  }
1275
1456
  }
1457
+ export async function clientListV1( req, res ) {
1458
+ try {
1459
+ const inputData = req.body;
1460
+ let clientQuery = [];
1461
+ logger.info( { message: req?.user?.role } );
1462
+ if ( req?.user?.role !== 'superadmin' ) {
1463
+ const query = [
1464
+ {
1465
+ $match: {
1466
+ userEmail: { $eq: req?.user?.email },
1467
+ userType: 'tango',
1468
+ $expr: {
1469
+ $cond: {
1470
+ if: {
1471
+ $and: [
1472
+ { $eq: [ '$tangoUserType', 'csm' ] },
1473
+ ],
1474
+ },
1475
+ then: { $eq: [ '$isClientApproved', true ] },
1476
+ else: true,
1477
+ },
1478
+ },
1479
+
1480
+ },
1481
+ },
1482
+ {
1483
+ $group: {
1484
+ _id: null,
1485
+ clientList: { $push: '$assignedValue' },
1486
+ },
1487
+ },
1488
+ ];
1489
+ const clientIdList = await aggregateUserAssignedStore( query );
1490
+ logger.info( { message: clientIdList, value: 'clientIdList' } );
1491
+ if ( clientIdList.length == 0 ) {
1492
+ return res.sendError( 'No Data Found', 204 );
1493
+ }
1494
+ clientQuery.push(
1495
+ {
1496
+ $match: {
1497
+ clientId: { $in: clientIdList[0].clientList },
1498
+ },
1499
+ },
1500
+ );
1501
+ }
1502
+ clientQuery.push(
1503
+ {
1504
+ $project: {
1505
+ status: 1,
1506
+ clientName: 1,
1507
+ clientId: 1,
1508
+ subscriptionType: '$planDetails.subscriptionType',
1509
+ PaymentPlan: '$planDetails.paymentStatus',
1510
+ },
1511
+ },
1512
+ );
1513
+ if ( inputData.filterByPaymentStatus ) {
1514
+ if ( inputData.filterByPaymentStatus.includes( 'paid' ) ) {
1515
+ inputData.filterByPaymentStatus.push( ...[ 'unbilled', 'due' ] );
1516
+ }
1517
+
1518
+ clientQuery.push(
1519
+ {
1520
+ $match: {
1521
+ 'PaymentPlan': { $in: inputData.filterByPaymentStatus },
1522
+ },
1523
+ },
1524
+ );
1525
+ }
1526
+ if ( inputData.filterBySubscription ) {
1527
+ clientQuery.push(
1528
+ {
1529
+ $match: {
1530
+ 'subscriptionType': { $in: inputData.filterBySubscription },
1531
+ },
1532
+ },
1533
+ );
1534
+ }
1535
+ if ( inputData.filterByStatus ) {
1536
+ clientQuery.push(
1537
+ {
1538
+ $match: {
1539
+ status: { $in: inputData.filterByStatus },
1540
+ },
1541
+ },
1542
+ );
1543
+ }
1544
+ if ( inputData.searchValue && inputData.searchValue != '' ) {
1545
+ clientQuery.push( {
1546
+ $match: {
1547
+ $or: [
1548
+ { clientId: { $regex: inputData.searchValue, $options: 'i' } },
1549
+ { clientName: { $regex: inputData.searchValue, $options: 'i' } },
1550
+ { subscriptionType: { $regex: inputData.searchValue, $options: 'i' } },
1551
+ { status: { $regex: inputData.searchValue, $options: 'i' } },
1552
+ ],
1553
+ },
1554
+ } );
1555
+ }
1556
+ clientQuery.push( {
1557
+ $lookup: {
1558
+ from: 'stores',
1559
+ let: { clientId: '$clientId' },
1560
+ pipeline: [
1561
+ {
1562
+ $match: {
1563
+ $expr: {
1564
+ $and: [
1565
+ { $eq: [ '$clientId', '$$clientId' ] },
1566
+ ],
1567
+ },
1568
+ },
1569
+ },
1570
+ {
1571
+ $project: {
1572
+ edge: 1,
1573
+ status: 1,
1574
+ clientId: 1,
1575
+ storeId: 1,
1576
+ },
1577
+ },
1578
+ ], as: 'stores',
1579
+ },
1580
+ },
1581
+
1582
+ {
1583
+ $unwind: { path: '$stores', preserveNullAndEmptyArrays: true },
1584
+ },
1585
+ {
1586
+ $project: {
1587
+ clientId: 1,
1588
+ status: 1,
1589
+ clientName: 1,
1590
+ subscriptionType: 1,
1591
+ PaymentPlan: 1,
1592
+ installed: {
1593
+ $cond: [ { $or: [ { $eq: [ '$stores.edge.firstFile', true ] } ] }, 1, 0,
1594
+ ],
1595
+ },
1596
+ activeStores: {
1597
+ $cond: [ { $and: [ { $eq: [ '$stores.status', 'active' ] } ] }, 1, 0,
1598
+ ],
1599
+ },
1600
+ InactiveStores: {
1601
+ $cond: [ { $and: [ { $ne: [ '$stores.status', 'active' ] } ] }, 1, 0,
1602
+ ],
1603
+ },
1604
+ },
1605
+ },
1606
+ {
1607
+ $group: {
1608
+ _id: '$clientId',
1609
+ clientId: { $first: '$clientId' },
1610
+ onboardedStores: { $sum: 1 },
1611
+ installedStore: { $sum: '$installed' },
1612
+ activeStores: { $sum: '$activeStores' },
1613
+ InactiveStores: { $sum: '$InactiveStores' },
1614
+ ProcessingStatus: { $first: '$status' },
1615
+ clientName: { $first: '$clientName' },
1616
+ subscriptionPlan: { $first: '$subscriptionType' },
1617
+ PaymentPlan: { $first: '$PaymentPlan' },
1618
+ },
1619
+ },
1620
+ {
1621
+ $lookup: {
1622
+ from: 'tangoTicket',
1623
+ let: { clientId: '$clientId' },
1624
+ pipeline: [
1625
+ {
1626
+ $match: {
1627
+ $expr: {
1628
+ $and: [
1629
+ { $eq: [ '$issueType', 'installation' ] },
1630
+ { $eq: [ '$basicDetails.clientId', '$$clientId' ] },
1631
+ ],
1632
+ },
1633
+ },
1634
+
1635
+ },
1636
+ {
1637
+ $project: {
1638
+ ticketDetails: 1,
1639
+ status: 1,
1640
+ basicDetails: 1,
1641
+ },
1642
+ },
1643
+ ], as: 'ticket',
1644
+ },
1645
+ },
1646
+ {
1647
+ $unwind: { path: '$ticket', preserveNullAndEmptyArrays: true },
1648
+ },
1649
+ {
1650
+ $project: {
1651
+ clientId: 1,
1652
+ ProcessingStatus: 1,
1653
+ onboardedStores: 1,
1654
+ clientName: 1,
1655
+ PaymentPlan: 1,
1656
+ subscriptionPlan: 1,
1657
+ installedStore: 1,
1658
+ activeStores: 1,
1659
+ InactiveStores: 1,
1660
+ installedPending: {
1661
+ $cond: [ { $and: [ { $ne: [ '$ticket.status', 'closed' ] } ] }, 1, 0 ],
1662
+ },
1663
+ installedFailed: {
1664
+ $cond: [ { $and: [ { $ne: [ '$ticket.status', 'closed' ] }, { $eq: [ '$ticket.ticketDetails.issueStatus', 'identified' ] } ] }, 1, 0 ],
1665
+ },
1666
+ },
1667
+ },
1668
+ {
1669
+ $group: {
1670
+ _id: '$clientId',
1671
+ clientId: { $first: '$clientId' },
1672
+ onboardedStores: { $first: '$onboardedStores' },
1673
+ installedStore: { $first: '$installedStore' },
1674
+ activeStores: { $first: '$activeStores' },
1675
+ InactiveStores: { $first: '$InactiveStores' },
1676
+ ProcessingStatus: { $first: '$ProcessingStatus' },
1677
+ clientName: { $first: '$clientName' },
1678
+ subscriptionPlan: { $first: '$subscriptionPlan' },
1679
+ PaymentPlan: { $first: '$PaymentPlan' },
1680
+ installedPending: { $sum: '$installedPending' },
1681
+ installedFailed: { $sum: '$installedFailed' },
1682
+ },
1683
+ },
1684
+ {
1685
+ $project: {
1686
+ clientId: { $toInt: '$clientId' },
1687
+ onboardedStores: 1,
1688
+ installedStore: 1,
1689
+ activeStores: { $max: [
1690
+ { $subtract: [ '$activeStores', '$installedPending' ] },
1691
+ 0,
1692
+ ] },
1693
+ InactiveStores: 1,
1694
+ ProcessingStatus: 1,
1695
+ clientName: 1,
1696
+ subscriptionPlan: 1,
1697
+ PaymentPlan: 1,
1698
+ PaymentPlan: {
1699
+ $cond: {
1700
+ if: { $eq: [ '$PaymentPlan', 'unbilled' ] },
1701
+ then: 'paid',
1702
+ else: {
1703
+ $cond: {
1704
+ if: { $eq: [ '$PaymentPlan', 'due' ] },
1705
+ then: 'paid',
1706
+ else: '$PaymentPlan',
1707
+ },
1708
+ },
1709
+ },
1710
+ },
1711
+ installedPending: 1,
1712
+ installedFailed: 1,
1713
+ ProgressBar: {
1714
+ $cond: {
1715
+ if: { $eq: [ '$onboardedStores', 0 ] },
1716
+ then: 0,
1717
+ else: {
1718
+ $round: [
1719
+ { $multiply: [ { $divide: [ '$installedStore', '$onboardedStores' ] }, 100 ] },
1720
+ 0,
1721
+ ],
1722
+ },
1723
+ },
1724
+ },
1725
+ },
1726
+ },
1727
+ );
1276
1728
 
1729
+ const clientCount = await aggregateClient( clientQuery );
1730
+ if ( clientCount.length == 0 ) {
1731
+ return res.sendError( 'No Data Found', 204 );
1732
+ }
1733
+
1734
+ if ( inputData.sortColumName&&inputData.sortColumName!=''&& req.body.sortBy&&req.body.sortBy!='' ) {
1735
+ clientQuery.push( {
1736
+ $sort: { [req.body.sortColumName]: req.body.sortBy },
1737
+ },
1738
+ );
1739
+ } else {
1740
+ clientQuery.push( {
1741
+ $sort: { activeStores: -1 },
1742
+ },
1743
+ );
1744
+ }
1745
+ clientQuery.push( {
1746
+ $project: {
1747
+ clientId: { $toString: '$clientId' },
1748
+ onboardedStores: 1,
1749
+ installedStore: 1,
1750
+ activeStores: 1,
1751
+ InactiveStores: 1,
1752
+ ProcessingStatus: 1,
1753
+ clientName: 1,
1754
+ subscriptionPlan: 1,
1755
+ PaymentPlan: 1,
1756
+ installedPending: 1,
1757
+ installedFailed: 1,
1758
+ ProgressBar: 1,
1759
+ },
1760
+ } );
1761
+ if ( req.body.limit && req.body.offset && !req.body.isExport ) {
1762
+ clientQuery.push(
1763
+ { $skip: ( req.body.offset - 1 ) * req.body.limit },
1764
+ { $limit: Number( req.body.limit ) },
1765
+ );
1766
+ }
1767
+ const clientList = await aggregateClient( clientQuery );
1768
+
1769
+ if ( inputData.isExport ) {
1770
+ const exportResult = [];
1771
+ for ( let client of clientList ) {
1772
+ exportResult.push( {
1773
+ 'Brand Name': client.clientName,
1774
+ 'Brand ID': client.clientId,
1775
+ 'Onboarded Stores': client.onboardedStores||0,
1776
+ 'Installed Stores': client.installedStore || 0,
1777
+ 'Progress Status': client.ProgressBar||0,
1778
+ 'Active Stores': client.activeStores || 0,
1779
+ 'In-Active Stores': client.InactiveStores || 0,
1780
+ 'Pending Configuration': client.installedPending || 0,
1781
+ 'Payment Plan': client.PaymentPlan == 'free'?'Lifetime Free':client.PaymentPlan,
1782
+ 'Subscription Plan': client.subscriptionPlan,
1783
+ 'Processing Status': client.ProcessingStatus=='active'?'Activated':client.ProcessingStatus=='deactive'?'Deactivated':client.ProcessingStatus,
1784
+ } );
1785
+ }
1786
+ await download( exportResult, res );
1787
+ return;
1788
+ }
1789
+ return res.sendSuccess( { result: clientList, count: clientCount.length } );
1790
+ } catch ( error ) {
1791
+ logger.error( { error: error, function: 'clientList' } );
1792
+ return res.sendError( 'Internal Server Error', 500 );
1793
+ }
1794
+ }
1277
1795
  export async function getOpsUsers( req, res ) {
1278
1796
  try {
1279
1797
  const users = await OpsUsersGet();
@@ -1291,6 +1809,7 @@ export async function getOpsUsers( req, res ) {
1291
1809
 
1292
1810
  export async function detailedClientCount( req, res ) {
1293
1811
  try {
1812
+ const bucket = JSON.parse( process.env.BUCKET );
1294
1813
  const inputData = req.query;
1295
1814
  let result = {
1296
1815
  clientName: inputData.clientName,
@@ -1304,10 +1823,10 @@ export async function detailedClientCount( req, res ) {
1304
1823
  const client = await findOneClient( { clientId: inputData.clientId }, { userId: 1, clientId: 1, profileDetails: 1 } );
1305
1824
  const user = await findOneUser( { _id: client.userId }, { userName: 1, email: 1 } );
1306
1825
 
1307
- const isLogoExist = await checkFileExist( { Bucket: appConfig.cloud.aws.bucket.assets, Key: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
1826
+ const isLogoExist = await checkFileExist( { Bucket: bucket.assets, Key: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
1308
1827
 
1309
1828
  if ( isLogoExist ) {
1310
- const signedFilUrl = await signedUrl( { Bucket: appConfig.cloud.aws.bucket.assets, file_path: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
1829
+ const signedFilUrl = await signedUrl( { Bucket: bucket.assets, file_path: `${client.clientId}/logo/${client.profileDetails?.logo}` } );
1311
1830
  result['logo'] = signedFilUrl;
1312
1831
  } else {
1313
1832
  result['logo'] = '';
@@ -1315,6 +1834,19 @@ export async function detailedClientCount( req, res ) {
1315
1834
  result['userName'] = user?.userName;
1316
1835
  result['email'] = user?.email;
1317
1836
  result['profileCompletion'] = 70;
1837
+ let findCsm = await aggregateUserAssignedStore( [
1838
+ {
1839
+ $match: {
1840
+ clientId: inputData.clientId,
1841
+ tangoUserType: 'csm',
1842
+ },
1843
+ },
1844
+ ] );
1845
+
1846
+ if ( findCsm&&findCsm.length>0 ) {
1847
+ let finduser = await findOneUser( { email: findCsm[0].userEmail }, { userName: 1, email: 1, countryCode: 1, mobileNumber: 1 } );
1848
+ result['csm'] = finduser;
1849
+ }
1318
1850
 
1319
1851
  return res.sendSuccess( { result: result } );
1320
1852
  } catch ( error ) {
@@ -1325,8 +1857,12 @@ export async function detailedClientCount( req, res ) {
1325
1857
 
1326
1858
  export async function getActivityLogs( req, res ) {
1327
1859
  try {
1860
+ const openSearch = JSON.parse( process.env.OPENSEARCH );
1328
1861
  const query = {
1329
- '_source': [ 'userId', 'userName', 'email', 'date', 'logType', 'logSubType', 'changes', 'eventType' ],
1862
+ '_source': [
1863
+ 'userId', 'userName', 'email', 'date', 'logType', 'logSubType',
1864
+ 'changes', 'eventType',
1865
+ ],
1330
1866
  'query': {
1331
1867
  'bool': {
1332
1868
  'must': [
@@ -1340,6 +1876,13 @@ export async function getActivityLogs( req, res ) {
1340
1876
  },
1341
1877
  'from': ( req.body.offset - 1 ) * req.body.limit,
1342
1878
  'size': req.body.limit,
1879
+ 'sort': [
1880
+ {
1881
+ 'date': {
1882
+ 'order': 'desc',
1883
+ },
1884
+ },
1885
+ ],
1343
1886
  };
1344
1887
 
1345
1888
  if ( req.body?.logTypeFilters?.length ) {
@@ -1363,7 +1906,15 @@ export async function getActivityLogs( req, res ) {
1363
1906
  } );
1364
1907
  }
1365
1908
 
1366
- const logs = await getOpenSearchData( 'tango-retail-activity-logs', query );
1909
+ query.query.bool.must.push(
1910
+ {
1911
+ 'terms': {
1912
+ 'showTo.keyword': [ req.user.userType ],
1913
+ },
1914
+ },
1915
+ );
1916
+
1917
+ const logs = await getOpenSearchData( openSearch.activityLog, query );
1367
1918
 
1368
1919
  const hits = logs?.body?.hits?.hits;
1369
1920
  const totalDocuments = logs?.body?.hits?.total?.value;
@@ -1379,6 +1930,7 @@ export async function getActivityLogs( req, res ) {
1379
1930
  }
1380
1931
  }
1381
1932
 
1933
+
1382
1934
  async function postApi( url, data ) {
1383
1935
  const requestOptions = {
1384
1936
  method: 'POST',
@@ -1415,3 +1967,34 @@ async function getApi( url ) {
1415
1967
  }
1416
1968
  }
1417
1969
 
1970
+
1971
+ export async function csmAssignConfirmation( req, res ) {
1972
+ try {
1973
+ const client = await findOneClient( { clientId: req.query.clientId }, { notifyCsmAssign: 1, _id: 0 } );
1974
+ if ( !client ) {
1975
+ res.sendError( 'No data found', 204 );
1976
+ }
1977
+ res.sendSuccess( client );
1978
+ } catch ( error ) {
1979
+ logger.error( { error: error, message: req.params, function: 'csmAssignConfirmation' } );
1980
+ return res.sendError( 'Internal Server Error', 500 );
1981
+ }
1982
+ }
1983
+
1984
+ export async function clientCsmAssignAction( req, res ) {
1985
+ try {
1986
+ await updateOneClient( { clientId: req.query.clientId }, { notifyCsmAssign: false } );
1987
+ if ( req.body.action === 'approve' ) {
1988
+ await updateOneUserAssignedStore( { clientId: req.query.clientId, tangoUserType: 'csm', assignedType: 'client' }, { isClientApproved: true } );
1989
+ }
1990
+
1991
+ if ( req.body.action === 'decline' ) {
1992
+ await deleteOneAssignedStore( { clientId: req.query.clientId, tangoUserType: 'csm', assignedType: 'client' } );
1993
+ }
1994
+
1995
+ res.sendSuccess( 'Updated Succesfully' );
1996
+ } catch ( error ) {
1997
+ logger.error( { error: error, message: req.params, function: 'csmAssignConfirmation' } );
1998
+ return res.sendError( 'Internal Server Error', 500 );
1999
+ }
2000
+ }