tango-app-api-infra 3.1.11 → 3.1.13

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
@@ -6,9 +6,10 @@ import { userInfraRouter } from './src/routes/userInfra.routes.js';
6
6
  import { storeInfraRouter } from './src/routes/storeInfra.routes.js';
7
7
  import { clientInfraRouter } from './src/routes/clientInfra.routes.js';
8
8
  import { employeeTrainigRouter } from './src/routes/employeetrainig.routes.js';
9
- import { dataMismatchRouter } from './src/routes/dataMismatch.routes.js';
9
+ import { dataMismatchTicketRouter } from './src/routes/dataMismatch.routes.js';
10
+ import { infraDocs } from './src/docs/infra.docs.js';
10
11
 
11
12
 
12
- export { infraRouter, internalInfraRouter, userInfraRouter, storeInfraRouter, dataMismatchRouter, clientInfraRouter, employeeTrainigRouter };
13
+ export { infraRouter, internalInfraRouter, userInfraRouter, storeInfraRouter, dataMismatchTicketRouter, clientInfraRouter, employeeTrainigRouter, infraDocs };
13
14
 
14
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-infra",
3
- "version": "3.1.11",
3
+ "version": "3.1.13",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -22,10 +22,12 @@
22
22
  "express-fileupload": "^1.5.0",
23
23
  "handlebars": "^4.7.8",
24
24
  "html-pdf-node": "^1.0.8",
25
+ "joi-to-swagger": "^6.2.0",
25
26
  "mongodb": "^6.4.0",
26
27
  "nodemon": "^3.1.0",
27
- "tango-api-schema": "^2.0.94",
28
- "tango-app-api-middleware": "^3.1.7",
28
+ "swagger-ui-express": "^5.0.0",
29
+ "tango-api-schema": "^2.0.103",
30
+ "tango-app-api-middleware": "^3.1.10",
29
31
  "winston": "^3.12.0",
30
32
  "winston-daily-rotate-file": "^5.0.0"
31
33
  },
@@ -156,7 +156,8 @@ export async function installationCard( req, res ) {
156
156
  } );
157
157
  let installedCount = await countDocumentsStore( { 'clientId': { $in: req.body.clientId },
158
158
  'edge.firstFile': true, 'status': 'active' } );
159
-
159
+ let deactiveCount = await countDocumentsStore( { 'clientId': { $in: req.body.clientId },
160
+ 'status': 'deactive' } );
160
161
  let yettoInstallCount = await aggregateTangoTicket( [
161
162
  {
162
163
  $match: {
@@ -250,6 +251,7 @@ export async function installationCard( req, res ) {
250
251
  }
251
252
  res.sendSuccess( {
252
253
  onboardedStoresCount: onboardedCount,
254
+ inactiveStoresCount: deactiveCount,
253
255
  installedStoresCount: installedCount,
254
256
  yettoInstallCount: yettoInstallCount.length,
255
257
  installFailedCount: installFailedCount.length,
@@ -1,14 +1,234 @@
1
1
 
2
+ import { findOneTangoTicket, createTangoTicket, updateOneTangoTicket, aggregateTangoTicket, countDocumentsTangoTicket } from '../services/tangoTicket.service.js';
3
+ import { logger, getUTC, appConfig, fileUpload, signedUrl, sendMessageToQueue } from 'tango-app-api-middleware';
4
+ import dayjs from 'dayjs';
2
5
 
3
- export async function createTicket() {
6
+ export async function createTicket( req, res ) {
4
7
  try {
5
- let ticketExist = await findOneTangoTicket( { 'issueType': req.body.issueType, 'basicDetails.storeId': req.body.storeId } );
8
+ let ticketExist = await findOneTangoTicket( { 'issueType': req.body.issueType, 'issueDate': ( new Date( req.body.Date ) ), 'basicDetails.storeId': req.body.storeId } );
6
9
 
7
10
  if ( ticketExist ) {
8
11
  return res.sendSuccess( 'MAT Ticket Already Exists for the store' );
9
12
  }
13
+ let actionBy = '';
14
+ if ( req.user.userType == 'tango' ) {
15
+ actionBy = 'Tango';
16
+ } else if ( req.user.userType == 'client' ) {
17
+ actionBy = 'User';
18
+ }
19
+ req.body.ticketDetails = {};
20
+ req.body.dataMismatch ={
21
+ actualCount: req.body.actualCount,
22
+ expectedCount: req.body.expectedCount,
23
+ contactEmail: req.body.contactEmail,
24
+ };
25
+ req.body.issueDate = new Date( req.body.Date );
26
+ req.body.ticketId = 'TE_DM_' + new Date().valueOf();
27
+ let create = await createTangoTicket( req.body );
28
+ let getObject = {};
29
+ if ( req.files ) {
30
+ let params = {
31
+ Bucket: appConfig.cloud.aws.bucket.ticket,
32
+ Key: create.ticketId + '/',
33
+ ContentType: 'multipart/form-data',
34
+ body: req.files.img.data,
35
+ fileName: req.files.img.name,
36
+ };
37
+ let upload = await fileUpload( params );
38
+ if ( upload ) {
39
+ getObject = {
40
+ fileName: req.files.img.name,
41
+ filePath: create.ticketId + '/' + req.files.img.name,
42
+ };
43
+ }
44
+ }
45
+ req.body.ticketActivity = [ {
46
+ actionType: 'Created',
47
+ timeStamp: new Date(),
48
+ actionBy: actionBy,
49
+ IdentifiedBy: req.user.userName,
50
+ description: req.body.description,
51
+ attachments: [ getObject ],
52
+ } ];
53
+ await updateOneTangoTicket( { ticketId: create.ticketId }, { ticketActivity: req.body.ticketActivity } );
54
+
55
+ const ticket = await findOneTangoTicket( { ticketId: req.body.ticketId }, { 'issueDate': 1, 'basicDetails': 1, 'issueType': 1, 'dataMismatch.contactEmail': 1, '_id': 0 } );
56
+
57
+ const obj = {
58
+ storeId: ticket.basicDetails.storeId,
59
+ issueDate: dayjs( ticket.issueDate ).format( 'DD-MM-YYYY' ),
60
+ };
61
+
62
+ if ( req.body.issueType === 'highcount' ) {
63
+ await sendMessageToQueue( `${appConfig.cloud.aws.sqs.url}${appConfig.cloud.aws.sqs.highcountTopic}`, JSON.stringify( obj ) );
64
+ }
65
+ if ( create ) {
66
+ res.sendSuccess( 'Ticket Created Successfully' );
67
+ }
10
68
  } catch ( error ) {
11
69
  logger.error( { error: error, function: 'createTicket Data Mismatch' } );
12
70
  return res.sendError( error, 500 );
13
71
  }
14
72
  }
73
+
74
+ export async function updateMat( req, res ) {
75
+ try {
76
+ let updateValue = {};
77
+ if ( req.body.actionType && req.body.actionType != '' ) {
78
+ let actionBy = '';
79
+ if ( req.user.userType == 'tango' ) {
80
+ actionBy = 'Tango';
81
+ } else if ( req.user.userType == 'client' ) {
82
+ actionBy = 'User';
83
+ }
84
+ req.body.ticketActivity.push( {
85
+ actionType: req.body.actionType,
86
+ actionBy: actionBy,
87
+ timeStamp: new Date(),
88
+ IdentifiedBy: req.user.userName,
89
+ description: req.body.description,
90
+ attachments: req.body.attachments,
91
+ } );
92
+ updateValue = { ticketActivity: req.body.ticketActivity };
93
+ }
94
+
95
+ let updateTicket = await updateOneTangoTicket( { ticketId: req.body.ticketId }, updateValue );
96
+ if ( updateTicket ) {
97
+ res.sendSuccess( 'Ticket Updated Successfully' );
98
+ }
99
+ } catch ( error ) {
100
+ logger.error( { error: error, function: 'updateMat' } );
101
+ return res.sendError( error, 500 );
102
+ }
103
+ }
104
+
105
+
106
+ export async function activityList( req, res ) {
107
+ try {
108
+ let date = await getUTC( new Date( req.body.fromDate ), new Date( req.body.toDate ) );
109
+ let query = [ {
110
+ $match: {
111
+ $and: [
112
+ { 'basicDetails.storeId': req.body.storeId },
113
+ { issueType: { $in: [ 'lowcount', 'highcount' ] } },
114
+ { createdAt: { $gte: date.start } },
115
+ { createdAt: { $lte: date.end } },
116
+ ],
117
+ },
118
+ },
119
+ {
120
+ $project: {
121
+ storeId: '$basicDetails.storeId',
122
+ status: 1,
123
+ issueDate: '$issueDate',
124
+ Date: { $dateToString: { format: '%d-%m-%Y', date: '$createdAt' } },
125
+ issueClosedDate: 1,
126
+ ticketId: 1,
127
+ issueType: 1,
128
+ ticketActivity: 1,
129
+ comments: { $size: '$ticketActivity' },
130
+ },
131
+ },
132
+ {
133
+ $unwind: {
134
+ path: '$ticketActivity', preserveNullAndEmptyArrays: true,
135
+ },
136
+ },
137
+ {
138
+ $group: {
139
+ _id: '$ticketId',
140
+ storeId: { $first: '$storeId' },
141
+ Date: { $first: '$Date' },
142
+ issueClosedDate: { $first: '$issueClosedDate' },
143
+ status: { $first: '$status' },
144
+ issueDate: { $first: '$issueDate' },
145
+ ticketId: { $first: '$ticketId' },
146
+ issueType: { $first: '$issueType' },
147
+ comments: { $first: '$comments' },
148
+ description: { $last: '$ticketActivity.description' },
149
+ },
150
+ },
151
+ {
152
+ $sort: {
153
+ issueDate: -1,
154
+ },
155
+ },
156
+ ];
157
+
158
+ if ( req.body.filter && req.body.filter !== '' ) {
159
+ query.push( {
160
+ $match: {
161
+ issueType: req.body.filter,
162
+ },
163
+ } );
164
+ }
165
+ let ticketList = await aggregateTangoTicket( query );
166
+ if ( req.body.export && ticketList.length > 0 ) {
167
+ const exportdata = [];
168
+ ticketList.forEach( ( element ) => {
169
+ exportdata.push( {
170
+ 'STORE ID': element.storeId,
171
+ 'TICKET ID': element.ticketId,
172
+ 'DATE': element.Date,
173
+ 'ISSUE CLOSED DATE': element.issueClosedDate,
174
+ 'STATUS': element.status,
175
+ 'COMMENT': element.description,
176
+ } );
177
+ } );
178
+ await download( exportdata, res );
179
+ return;
180
+ }
181
+ if ( ticketList.length ) {
182
+ let highCount = await countDocumentsTangoTicket( {
183
+ $and: [
184
+ { 'basicDetails.storeId': req.body.storeId },
185
+ { issueType: 'highcount' },
186
+ { createdAt: { $gte: date.start } },
187
+ { createdAt: { $lte: date.end } },
188
+ ],
189
+ } );
190
+ let lowCount = await countDocumentsTangoTicket( {
191
+ $and: [
192
+ { 'basicDetails.storeId': req.body.storeId },
193
+ { issueType: 'lowcount' },
194
+ { createdAt: { $gte: date.start } },
195
+ { createdAt: { $lte: date.end } },
196
+ ],
197
+ } );
198
+
199
+ res.sendSuccess( {
200
+ count: ticketList.length,
201
+ data: ticketList,
202
+ highCount: highCount,
203
+ lowCount: lowCount,
204
+ } );
205
+ } else {
206
+ return res.sendError( 'NO data', 204 );
207
+ }
208
+ } catch ( error ) {
209
+ logger.error( { error: error, function: 'activityList' } );
210
+ return res.sendError( error, 500 );
211
+ }
212
+ }
213
+
214
+
215
+ export async function showActivity( req, res ) {
216
+ try {
217
+ for ( let activity of req.body.ticketActivity ) {
218
+ if ( activity.attachments&&activity.attachments.length>0 ) {
219
+ for ( let attchment of activity.attachments ) {
220
+ let params = {
221
+ Bucket: appConfig.cloud.aws.bucket.ticket,
222
+ file_path: attchment.filePath,
223
+ };
224
+ let attachments = await signedUrl( params );
225
+ attchment.signedUrl = attachments;
226
+ }
227
+ }
228
+ }
229
+ res.sendSuccess( req.body );
230
+ } catch ( error ) {
231
+ logger.error( { error: error, function: 'showActivity' } );
232
+ return res.sendError( error, 500 );
233
+ }
234
+ }
@@ -48,3 +48,16 @@ export async function activityLog( req, res ) {
48
48
  return res.sendError( error, 500 );
49
49
  }
50
50
  }
51
+
52
+
53
+ export async function updateMatStatus( req, res ) {
54
+ try {
55
+ let update = await updateOneTangoTicket( { ticketId: req.body.ticketId }, { 'ticketDetails.matStatus': req.body.matStatus } );
56
+ if ( update ) {
57
+ res.sendSuccess( 'Updated Successfully' );
58
+ }
59
+ } catch ( error ) {
60
+ logger.error( { error: error, function: 'updateMatStatus' } );
61
+ return res.sendError( error, 500 );
62
+ }
63
+ }
@@ -13,10 +13,11 @@ import handlebars from 'handlebars';
13
13
  import { findOneGroup } from '../services/group.service.js';
14
14
  import htmlpdf from 'html-pdf-node';
15
15
  import mongoose from 'mongoose';
16
+ import _ from 'lodash';
17
+ import { aggregateCamera } from '../services/camera.service.js';
16
18
  export async function createTicket( req, res ) {
17
19
  try {
18
20
  req.body.issueDate = new Date( req.body.Date );
19
- req.body.ticketDetails.filesCount = req.body.filesCount;
20
21
  if ( req.body.issueType == 'infra' ) {
21
22
  req.body.ticketId = 'TE_INF_' + new Date().valueOf();
22
23
  req.body.ticketActivity = [ {
@@ -126,28 +127,27 @@ export async function bulkcreateTicket( req, res ) {
126
127
  export async function updateStatus( req, res ) {
127
128
  try {
128
129
  if ( req.user.userType == 'tango' ) {
129
- if ( req.body.status == 'inprogress' ) {
130
- req.body.ticketActivity.push( {
131
- actionType: 'statusChange',
132
- timeStamp: new Date(),
133
- actionBy: 'Tango',
134
- IdentifiedBy: req.user.userName,
135
- } );
136
- }
130
+ req.body.ticketActivity.push( {
131
+ actionType: 'statusChange',
132
+ timeStamp: new Date(),
133
+ actionBy: 'Tango',
134
+ IdentifiedBy: req.user.userName,
135
+ } );
136
+ req.body.status = 'inprogress';
137
137
  req.body.ticketDetails.addressingUser = req.user._id;
138
138
  let updateTicket = await updateOneTangoTicket( { ticketId: req.body.ticketId }, req.body );
139
139
  if ( updateTicket ) {
140
140
  res.sendSuccess( 'Ticket Updated Successfully' );
141
141
  }
142
142
  } else if ( req.user.userType == 'client' ) {
143
- if ( req.body.status == 'inprogress' ) {
144
- req.body.ticketActivity.push( {
145
- actionType: 'statusChange',
146
- timeStamp: new Date(),
147
- actionBy: 'User',
148
- IdentifiedBy: req.user.userName,
149
- } );
150
- }
143
+ req.body.ticketActivity.push( {
144
+ actionType: 'statusChange',
145
+ timeStamp: new Date(),
146
+ actionBy: 'User',
147
+ IdentifiedBy: req.user.userName,
148
+ } );
149
+ req.body.status = 'inprogress';
150
+
151
151
  req.body.ticketDetails.addressingClient = req.user._id;
152
152
  let updateTicket = await updateOneTangoTicket( { ticketId: req.body.ticketId }, req.body );
153
153
  if ( updateTicket ) {
@@ -607,6 +607,217 @@ export async function invoice( req, res ) {
607
607
  } );
608
608
  }
609
609
 
610
+ export async function getInfraIssues( req, res ) {
611
+ try {
612
+ const inputData = req.body;
613
+ const query=[
614
+ {
615
+ $match: {
616
+ $and: [
617
+ {
618
+ 'issueType': { $eq: 'infra' },
619
+
620
+ },
621
+ {
622
+ 'basicDetails.storeId': { $eq: inputData.storeId },
623
+
624
+ },
625
+ {
626
+ 'issueDate': { $gte: new Date( inputData.fromDate ) },
627
+
628
+ },
629
+ {
630
+ 'issueDate': { $lte: new Date( inputData.toDate ) },
631
+
632
+ },
633
+ {
634
+ 'ticketDetails.issueStatus': { $eq: 'identified' },
635
+
636
+ },
637
+
638
+ ],
639
+ },
640
+ },
641
+ {
642
+ $project: {
643
+ issueType: 1,
644
+ issueDate: { $dateToString: { format: '%Y-%m-%d', date: '$issueDate' } },
645
+ ticketActivity: {
646
+ $filter: {
647
+ input: '$ticketActivity',
648
+ as: 'item',
649
+ cond: { $eq: [ '$$item.actionType', 'issueUpdate' ] },
650
+ },
651
+ },
652
+ },
653
+ },
654
+
655
+ {
656
+ $unwind: {
657
+ path: '$ticketActivity', preserveNullAndEmptyArrays: true,
658
+ },
659
+ },
660
+ {
661
+ $unwind: {
662
+ path: '$ticketActivity.reasons', preserveNullAndEmptyArrays: true,
663
+ },
664
+ },
665
+ {
666
+ $group: {
667
+ _id: { reason: '$ticketActivity.reasons', issueDate: '$issueDate' },
668
+ issueDate: { $first: '$issueDate' },
669
+ primaryIssue: { $last: '$ticketActivity.reasons.primaryIssue' },
670
+ secondaryIssue: { $last: '$ticketActivity.reasons.secondaryIssue' },
671
+
672
+ },
673
+ },
674
+ {
675
+ $unwind: {
676
+ path: '$secondaryIssue', preserveNullAndEmptyArrays: true,
677
+ },
678
+ },
679
+ {
680
+ $group: {
681
+ _id: { issue: '$primaryIssue', issueDate: '$issueDate' },
682
+ issueDate: { $first: '$issueDate' },
683
+ primaryIssue: { $last: '$primaryIssue' },
684
+ secondaryReason: { $push: '$secondaryIssue.name' },
685
+
686
+ },
687
+ },
688
+ {
689
+ $project: {
690
+ _id: 0,
691
+ issueDate: 1,
692
+ primaryIssue: 1,
693
+ secondaryReason: 1,
694
+ downTime: { $ifNull: [ 0, 0 ] },
695
+ speedTest: { $ifNull: [ 0.5, 0.5 ] },
696
+ },
697
+
698
+ },
699
+ ];
700
+
701
+
702
+ let retVal = [];
703
+ let current = new Date( inputData.fromDate );
704
+ let end = new Date( inputData.toDate );
705
+
706
+ while ( current <= end ) {
707
+ retVal.push( { issueDate: dayjs( current ).format( 'YYYY-MM-DD' ), downTime: 0, speedTest: 0.6 } );
708
+ current.setDate( current.getDate() + 1 );
709
+ }
710
+
711
+ const result = await aggregateTangoTicket( query );
712
+
713
+ const mergeValue =_.values(
714
+ _.merge(
715
+ _.keyBy( retVal, 'issueDate' ),
716
+ _.keyBy( result, 'issueDate' ),
717
+ ),
718
+ );
719
+ logger.info( { message: mergeValue, value1: result } );
720
+
721
+ if ( mergeValue.length == 0 ) {
722
+ return res.sendError( 'NO Data Found', 204 );
723
+ }
724
+ for ( let i =0; i< mergeValue.length; i++ ) {
725
+ const downTime = await getOpenSearchData( 'live_downtime_hourly',
726
+ {
727
+ 'size': 100,
728
+ 'query': {
729
+ 'bool': {
730
+ 'must': [
731
+ {
732
+ 'term': {
733
+ 'doc.date.keyword': dayjs( mergeValue[i].issueDate ).format( 'DD-MM-YYYY' ),
734
+ },
735
+ },
736
+ {
737
+ 'term': {
738
+ 'doc.store_id.keyword': inputData.storeId,
739
+ },
740
+ },
741
+
742
+ ],
743
+
744
+ },
745
+ },
746
+
747
+ } );
748
+ let streamwiseDowntime = [];
749
+ logger.info( { streamwiseDowntime: downTime.body.hits.hits.length } );
750
+ if ( downTime.body.hits.hits.length > 0 ) {
751
+ for ( let i = 0; i< downTime.body.hits.hits.length; i++ ) {
752
+ const sum = streamwiseDowntime.reduce( ( accumulator, currentValue ) => {
753
+ return accumulator + currentValue.down_time;
754
+ }, 0 );
755
+ const average = sum / streamwiseDowntime.length;
756
+ mergeValue.downTime = Math.round( average );
757
+ // streamwiseDowntime.push( ...downTime.body.hits.hits[i]._source.doc.streamwise_downtime );
758
+ }
759
+ }
760
+ }
761
+ const camQuery = [
762
+ {
763
+ $match: {
764
+ $and: [
765
+ { isUp: { $eq: true } },
766
+ { isActivated: { $eq: true } },
767
+ { storeId: inputData.storeId },
768
+ ],
769
+ },
770
+ },
771
+ {
772
+ $project: {
773
+ _id: 0,
774
+ streamName: 1,
775
+ cameraNumber: 1,
776
+ thumbnailImage: await signedUrl( { Bucket: appConfig.cloud.aws.bucket.baseImage, file_path: '$thumbnailImage' } ),
777
+ },
778
+ },
779
+ ];
780
+
781
+ const highCountQuery =[
782
+ {
783
+ $match: {
784
+ $and: [
785
+ { 'basicDetails.storeId': inputData.storeId },
786
+ { issueType: { $in: [ 'highcount', 'lowcount' ] } },
787
+
788
+ ],
789
+ },
790
+ },
791
+ {
792
+ $group: {
793
+ _id: null,
794
+ total: { $sum: 1 },
795
+ successRate: { $avg: '$dataMismatch.successPercentage' },
796
+ },
797
+ },
798
+ {
799
+ $project: {
800
+ _id: 0,
801
+ total: 1,
802
+ successRate: 1,
803
+ },
804
+ },
805
+ ];
806
+ const defaultValue= {
807
+ total: 0,
808
+ successRate: 0,
809
+ };
810
+ const getHighCountTicket = await aggregateTangoTicket( highCountQuery );
811
+ logger.info( { getHighCountTicket: getHighCountTicket } );
812
+ const camera = await aggregateCamera( camQuery );
813
+ logger.info( { message: camera } );
814
+ return res.sendSuccess( { result: mergeValue, streams: camera, highCountTicketDetails: getHighCountTicket[0] || defaultValue } );
815
+ } catch ( error ) {
816
+ logger.error( { error: error, function: 'getInfraIssues' } );
817
+ return res.sendError( error, 500 );
818
+ }
819
+ }
820
+
610
821
 
611
822
  function inWords( num ) {
612
823
  let a = [ '', 'one ', 'two ', 'three ', 'four ', 'five ', 'six ', 'seven ', 'eight ', 'nine ', 'ten ', 'eleven ', 'twelve ', 'thirteen ', 'fourteen ', 'fifteen ', 'sixteen ', 'seventeen ', 'eighteen ', 'nineteen ' ]; let b = [ '', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' ];
@@ -1233,14 +1444,14 @@ export async function matTable( req, res ) {
1233
1444
  result.forEach( ( element ) => {
1234
1445
  exportdata.push( {
1235
1446
  'ticketId': element.ticketId,
1236
- 'issueDate': dayjs( element.issueDate ).format( 'DD-MM-YYYY' ),
1447
+ 'Date': dayjs( element.issueDate ).format( 'DD-MM-YYYY' ),
1237
1448
  'storeId': element.storeId,
1238
1449
  'storeName': element.storeName,
1239
1450
  'clientId': element.clientId,
1240
1451
  'clientName': element.clientName,
1241
1452
  'userName': element.userName,
1242
1453
  'userEmail': element.userEmail,
1243
- 'Status': element.installationStatus,
1454
+ 'Status': element.status,
1244
1455
  } );
1245
1456
  } );
1246
1457
  await download( exportdata, res );
@@ -1272,18 +1483,25 @@ export async function assignTicket( req, res ) {
1272
1483
  }
1273
1484
  export async function storeFilter( req, res ) {
1274
1485
  try {
1275
- let stores = await findTangoTicket( { 'issueType': req.body.issueType, 'basicDetails.clientId': req.body.clientId, 'basicDetails.storeId': { $exists: true } }, { 'basicDetails.storeId': 1 } );
1486
+ const inputData = req.body;
1487
+ let query = { 'issueType': inputData.issueType, 'basicDetails.clientId': inputData.clientId, 'basicDetails.storeId': { $exists: true } };
1488
+ if ( inputData.issueType == 'dataMismatch' ) {
1489
+ query ={
1490
+ 'issueType': { '$in': [ 'highcount', 'lowcount' ] }, 'basicDetails.clientId': inputData.clientId, 'basicDetails.storeId': { $exists: true },
1491
+ };
1492
+ }
1493
+ let stores = await findTangoTicket( query, { 'basicDetails.storeId': 1 } );
1276
1494
  const uniqueStoreIds = [ ...new Set( stores.map( ( store ) => store.basicDetails.storeId ) ) ];
1277
1495
  const uniqueStoreObjects = uniqueStoreIds.map( ( storeId ) => ( { 'storeId': storeId } ) );
1278
1496
 
1279
- if ( uniqueStoreObjects.length>0 ) {
1497
+ if ( uniqueStoreObjects.length > 0 ) {
1280
1498
  res.sendSuccess( { count: uniqueStoreObjects.length, data: uniqueStoreObjects } );
1281
1499
  } else {
1282
1500
  res.sendError( 'No data', 204 );
1283
1501
  }
1284
1502
  } catch ( error ) {
1285
- // console.log( error );
1286
1503
  logger.error( { error: error, function: 'storeFilter' } );
1287
1504
  return res.sendError( error, 500 );
1288
1505
  }
1289
1506
  }
1507
+
@@ -445,11 +445,10 @@ export async function emailUserList( req, res ) {
445
445
  }
446
446
  export async function infraReportSent( req, res ) {
447
447
  try {
448
- let date;
449
448
  // if ( req.body.type == 'start' ) {
450
449
  // date = dayjs().subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
451
450
  // } else if ( req.body.type == 'end' ) {
452
- date = dayjs().format( 'YYYY-MM-DD' );
451
+ let date = dayjs( ).format( 'YYYY-MM-DD' );
453
452
  // };
454
453
  let query = [ {
455
454
  $match: {
@@ -468,6 +467,13 @@ export async function infraReportSent( req, res ) {
468
467
  status: 1,
469
468
  ticketDetails: 1,
470
469
  issueClosedDate: 1,
470
+ otherscomment: {
471
+ $filter: {
472
+ input: '$ticketActivity',
473
+ as: 'item',
474
+ cond: { $eq: [ '$$item.actionType', 'comment' ] },
475
+ },
476
+ },
471
477
  primaryIssue: {
472
478
  $filter: {
473
479
  input: '$ticketActivity',
@@ -477,6 +483,11 @@ export async function infraReportSent( req, res ) {
477
483
  },
478
484
  },
479
485
  },
486
+ {
487
+ $unwind: {
488
+ path: '$otherscomment', preserveNullAndEmptyArrays: true,
489
+ },
490
+ },
480
491
  {
481
492
  $unwind: {
482
493
  path: '$primaryIssue', preserveNullAndEmptyArrays: true,
@@ -500,6 +511,8 @@ export async function infraReportSent( req, res ) {
500
511
  status: 1,
501
512
  ticketDetails: 1,
502
513
  issueClosedDate: 1,
514
+ ommentText: { $ifNull: [ '$primaryIssue.comment', '-' ] },
515
+ otherscomment: { $ifNull: [ '$otherscomment.comment', '-' ] },
503
516
  primaryIssue: { $ifNull: [ '$primaryIssue.reasons.primaryIssue', '-' ] },
504
517
  secondaryIssue: { $ifNull: [ '$primaryIssue.reasons.secondaryIssue.name', '-' ] },
505
518
  },
@@ -510,11 +523,12 @@ export async function infraReportSent( req, res ) {
510
523
  ticketDetails: { $first: '$ticketDetails' },
511
524
  issueClosedDate: { $first: '$issueClosedDate' },
512
525
  basicDetails: { $first: '$basicDetails' },
526
+ commentText: { $last: '$commentText' },
513
527
  primaryIssue: { $last: '$primaryIssue' },
514
528
  secondaryIssue: { $last: '$secondaryIssue' },
529
+ otherscomment: { $last: '$otherscomment' },
515
530
  createdAt: { $first: '$createdAt' },
516
531
  status: { $last: '$status' },
517
-
518
532
  },
519
533
  },
520
534
  ];
@@ -527,7 +541,7 @@ export async function infraReportSent( req, res ) {
527
541
  exportdata.push( {
528
542
  'Client ID': element.basicDetails.clientId,
529
543
  'Client Name': element.basicDetails.clientName,
530
- 'Ticket Created Date & Time': dayjs( element.createdAt ).format( 'YYYY-MM-DD HH:mm A' ),
544
+ 'Ticket Created Date & Time': dayjs( element.createdAt ).tz( 'Asia/Kolkata' ).format( 'YYYY-MM-DD HH:mm A' ),
531
545
  'Store ID': element.basicDetails.storeId,
532
546
  'Store Name': element.basicDetails.storeName,
533
547
  'Issue ': element.primaryIssue,
@@ -535,9 +549,12 @@ export async function infraReportSent( req, res ) {
535
549
  'Status ': element.status,
536
550
  'Responded By': clientuser && clientuser.userName ? clientuser.userName : '-',
537
551
  'Resolved By': tangouser && tangouser.userName ? tangouser.userName : '-',
538
- 'Ticket Closed Date & Time': element.issueClosedDate ? dayjs( element.issueClosedDate ).format( 'YYYY-MM-DD HH:mm A' ) : '-',
539
- 'Latest Comment': '',
540
- 'Activity Log': `${appConfig.url.domain+'/manage/stores/infra-ticket?storeId='+element.basicDetails.storeId}`,
552
+ 'Ticket Closed Date & Time': element.issueClosedDate ? dayjs( element.issueClosedDate ).tz( 'Asia/Kolkata' ).format( 'YYYY-MM-DD HH:mm A' ) : '-',
553
+ 'Latest Comment': element.otherscomment?element.otherscomment:element.commentText,
554
+ 'Activity Log': {
555
+ label: 'Link',
556
+ url: `${appConfig.url.domain+'/manage/stores/infra-ticket?storeId='+element.basicDetails.storeId}`,
557
+ },
541
558
  } );
542
559
  }
543
560
 
@@ -572,40 +589,23 @@ export async function infraReportSent( req, res ) {
572
589
  count: 0,
573
590
  } ) );
574
591
  }
575
- let reportdate = dayjs().format( 'YYYY-MM-DD' );
592
+
576
593
  let attachments = null;
577
- if ( exportdata.length > 0 ) {
578
- const wb = new xl.Workbook();
579
- const ws = wb.addWorksheet( 'Daily report' );
580
- const headers = Object.keys( exportdata[0] );
594
+ let buffer = await download( exportdata );
595
+ attachments = {
596
+ filename: `dailyInfraReport- ${date}.xlsx`,
597
+ content: buffer,
598
+ contentType: 'application/xlsx', // e.g., 'application/pdf'
599
+ };
581
600
 
582
- for ( let i = 0; i < headers.length; i++ ) {
583
- ws.cell( 1, i + 1 ).string( headers[i] );
584
- };
585
- for ( let i = 0; i < exportdata.length; i++ ) {
586
- const dataRow = exportdata[i];
587
- for ( let j = 0; j < headers.length; j++ ) {
588
- const header = headers[j];
589
- const value = dataRow[header];
590
- ws.cell( i + 2, j + 1 ).string( value?.toString() );
591
- }
592
- }
593
- let buffer = await wb.writeToBuffer();
594
601
 
595
- attachments = {
596
- filename: `dailyInfraReport- ${reportdate}.xlsx`,
597
- content: buffer,
598
- contentType: 'application/xlsx', // e.g., 'application/pdf'
599
- };
600
- }
601
-
602
- const subject = `Daily Digest - Infra Downtime Report - ${reportdate}`;
602
+ const subject = `Daily Digest - Infra Downtime Report - ${date}`;
603
603
  const fileContent = readFileSync( join() + '/src/hbs/dailyInfraReport.hbs', 'utf8' );
604
604
  const htmlContent = handlebars.compile( fileContent );
605
605
  let Uidomain = `${appConfig.url.domain}`;
606
606
 
607
607
 
608
- const html = htmlContent( { ...req.body, Uidomain: Uidomain, issueCount: issueCount, avgDownTime: avgDownTime, reportdate: reportdate, content: response, date: date, domain: appConfig.url.apiDomain } );
608
+ const html = htmlContent( { ...req.body, Uidomain: Uidomain, issueCount: issueCount, avgDownTime: avgDownTime, reportdate: date, content: response, date: date, domain: appConfig.url.apiDomain } );
609
609
  if ( isValidEmail( req.body.email ) ) {
610
610
  const result = await sendEmailWithSES( req.body.email, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
611
611
  res.sendSuccess( result );
@@ -724,8 +724,7 @@ export async function download( data ) {
724
724
  for ( let j = 0; j < headers.length; j++ ) {
725
725
  const header = headers[j];
726
726
  const value = dataRow[header];
727
-
728
- if ( typeof value === 'object' && value.hasOwnProperty( 'label' ) && value.hasOwnProperty( 'url' ) ) {
727
+ if ( value&& typeof value === 'object' && value.hasOwnProperty( 'label' ) && value.hasOwnProperty( 'url' ) ) {
729
728
  ws.cell( i + 2, j + 1 ).link( value.url );
730
729
  ws.cell( i + 2, j + 1 ).string( value.label );
731
730
  } else {
@@ -884,11 +883,9 @@ export async function edgeApplogsCheck( req, res ) {
884
883
  let findissueEdgeApp = {};
885
884
  if ( result.length>0 ) {
886
885
  for ( let findissue of result ) {
887
- // console.log( ticket.ticketId );
888
886
  const istTimestamp = dayjs.utc( ticket.createdAt ).tz( 'Asia/Kolkata' ).format( 'HH:mm:ss' );
889
887
 
890
888
  if ( findissue.code == '1003' ) {
891
- // Compare the times
892
889
  const occurringTimeParsed = dayjs( `${req.body.date} ${findissue.edgelog.occuringTime}` );
893
890
  const ticketCreatedParsed = dayjs( `${req.body.date} ${istTimestamp}` );
894
891
  const isOccurringTimeEarlier = occurringTimeParsed.isBefore( ticketCreatedParsed );
@@ -902,7 +899,6 @@ export async function edgeApplogsCheck( req, res ) {
902
899
  };
903
900
  updateIssue( findissueEdgeApp );
904
901
  finalresult.push( findissueEdgeApp );
905
- // console.log( findissueEdgeApp );
906
902
  }
907
903
  } else if ( findissue.code == '1024' ) {
908
904
  const occurringTimeParsed = dayjs( `${req.body.date} ${findissue.edgelog.data.occuringTime}` );
@@ -938,7 +934,6 @@ export async function edgeApplogsCheck( req, res ) {
938
934
  };
939
935
  updateIssue( findissueEdgeApp );
940
936
  finalresult.push( findissueEdgeApp );
941
- // console.log( findissueEdgeApp );
942
937
  }
943
938
  } else if ( findissue.code ==='1005' ) {
944
939
  const occurringTimeParsed = dayjs( `${req.body.date} ${findissue.edgelog.occuringTime}` );
@@ -954,7 +949,6 @@ export async function edgeApplogsCheck( req, res ) {
954
949
  };
955
950
  updateIssue( findissueEdgeApp );
956
951
  finalresult.push( findissueEdgeApp );
957
- // console.log( findissueEdgeApp );
958
952
  }
959
953
  }
960
954
  }
@@ -1054,7 +1048,6 @@ export async function updateIssue( data ) {
1054
1048
  'status': 'inprogress',
1055
1049
  };
1056
1050
  await updateOneTangoTicket( { ticketId: data.ticketId }, query );
1057
- // console.log( data );
1058
1051
  } catch ( error ) {
1059
1052
  logger.error( { error: error, function: 'updateAutomaticIssue' } );
1060
1053
  res.sendError( error, 500 );
@@ -28,7 +28,20 @@ export async function storeTicketList( req, res ) {
28
28
  ticketId: 1,
29
29
  issueStatus: '$ticketDetails.issueStatus',
30
30
  ticketType: '$ticketDetails.ticketType',
31
- comments: { $size: '$ticketActivity' },
31
+ otherscomment: {
32
+ $filter: {
33
+ input: '$ticketActivity',
34
+ as: 'item',
35
+ cond: { $eq: [ '$$item.actionType', 'comment' ] },
36
+ },
37
+ },
38
+ comments: {
39
+ $filter: {
40
+ input: '$ticketActivity',
41
+ as: 'item',
42
+ cond: { $ne: [ '$$item.actionType', 'statusChange' ] },
43
+ },
44
+ },
32
45
  primaryIssue: {
33
46
  $filter: {
34
47
  input: '$ticketActivity',
@@ -43,11 +56,21 @@ export async function storeTicketList( req, res ) {
43
56
  path: '$primaryIssue', preserveNullAndEmptyArrays: true,
44
57
  },
45
58
  },
59
+ {
60
+ $unwind: {
61
+ path: '$otherscomment', preserveNullAndEmptyArrays: true,
62
+ },
63
+ },
46
64
  {
47
65
  $unwind: {
48
66
  path: '$primaryIssue.reasons', preserveNullAndEmptyArrays: true,
49
67
  },
50
68
  },
69
+ {
70
+ $unwind: {
71
+ path: '$primaryIssue.reasons.secondaryIssue', preserveNullAndEmptyArrays: true,
72
+ },
73
+ },
51
74
  {
52
75
  $project: {
53
76
  storeId: 1,
@@ -57,10 +80,12 @@ export async function storeTicketList( req, res ) {
57
80
  ticketId: 1,
58
81
  issueStatus: 1,
59
82
  ticketType: 1,
60
- comments: 1,
83
+ comments: { $size: '$comments' },
61
84
  issueDate: 1,
85
+ commentText: '$primaryIssue.comment',
62
86
  primaryIssue: '$primaryIssue.reasons.primaryIssue',
63
- secondaryIssue: '$primaryIssue.reasons.secondaryIssue',
87
+ secondaryIssue: '$primaryIssue.reasons.secondaryIssue.name',
88
+ otherscomment: '$otherscomment.comment',
64
89
  },
65
90
  },
66
91
  {
@@ -75,8 +100,11 @@ export async function storeTicketList( req, res ) {
75
100
  issueStatus: { $first: '$issueStatus' },
76
101
  ticketType: { $first: '$ticketType' },
77
102
  comments: { $first: '$comments' },
103
+ commentText: { $last: '$commentText' },
78
104
  primaryIssue: { $last: '$primaryIssue' },
79
105
  secondaryIssue: { $last: '$secondaryIssue' },
106
+ otherscomment: { $last: '$otherscomment' },
107
+
80
108
  },
81
109
  },
82
110
  {
@@ -102,8 +130,10 @@ export async function storeTicketList( req, res ) {
102
130
  'TICKET ID': element.ticketId,
103
131
  'DATE': element.Date,
104
132
  'ISSUE CLOSED DATE': element.issueClosedDate,
105
- 'ISSUE': element.primaryIssue,
133
+ 'PRIMARY ISSUE': element.primaryIssue,
134
+ 'SECONDARY ISSUE': element.secondaryIssue,
106
135
  'STATUS': element.status,
136
+ 'COMMENT': element.otherscomment?element.otherscomment:element.commentText,
107
137
  } );
108
138
  } );
109
139
  await download( exportdata, res );
@@ -330,7 +360,6 @@ export async function edgeAppLogTable( req, res ) {
330
360
  };
331
361
  const downtime = await getOpenSearchData( 'live_downtime_hourly', downTimeQuery );
332
362
  let streamwiseDowntime = downtime.body.hits.hits.length > 0 ? downtime.body.hits.hits[0]._source.doc.streamwise_downtime : [];
333
- // console.log( obj.hour, streamwiseDowntime );
334
363
  if ( streamwiseDowntime.length > 0 ) {
335
364
  const sum = streamwiseDowntime.reduce( ( accumulator, currentValue ) => {
336
365
  return accumulator + currentValue.down_time;
@@ -75,13 +75,24 @@ export async function userTakeTicket( req, res ) {
75
75
  let query = {
76
76
  'status': { $ne: 'closed' },
77
77
  'issueType': 'mat',
78
+ 'ticketDetails.addressingUser': { $exists: false },
79
+ };
80
+ if ( assignedClients.length > 0 ) {
81
+ query =( { ...query, ...{ 'basicDetails.clientId': { $in: assignedClients } } } );
82
+ }
83
+ userTicket = await findOneTangoTicket( query );
84
+ } else if ( req.body.issueType == 'dataMismatch' ) {
85
+ let query = {
86
+ 'status': { $ne: 'closed' },
87
+ 'issueType': { $in: [ 'highcount', 'lowcount' ] },
88
+ 'ticketDetails.addressingUser': { $exists: false },
78
89
  };
79
90
  if ( assignedClients.length > 0 ) {
80
91
  query =( { ...query, ...{ 'basicDetails.clientId': { $in: assignedClients } } } );
81
92
  }
82
93
  userTicket = await findOneTangoTicket( query );
83
94
  }
84
- if ( userTicket ) {
95
+ if ( userTicket&&userTicket.ticketId ) {
85
96
  let assignTicket = await updateOneTangoTicket( { ticketId: userTicket.ticketId }, { 'ticketDetails.addressingUser': req.body.userId } );
86
97
  if ( assignTicket ) {
87
98
  res.sendSuccess( 'Ticket Assigned Successfully' );
@@ -97,15 +108,28 @@ export async function userTakeTicket( req, res ) {
97
108
  export async function userTicketList( req, res ) {
98
109
  try {
99
110
  let date = await getUTC( new Date( req.body.fromDate ), new Date( req.body.toDate ) );
100
- let query = [ {
101
- $match: {
102
- $and: [
103
-
104
- { issueType: req.body.issueType },
105
- { 'ticketDetails.addressingUser': new mongoose.Types.ObjectId( req.body.userId ) },
106
- ],
107
- },
108
- } ];
111
+ let query = [];
112
+ if ( req.body.issueType!='dataMismatch' ) {
113
+ query.push( {
114
+ $match: {
115
+ $and: [
116
+ { 'basicDetails.clientId': { $in: req.body.clientId } },
117
+ { issueType: req.body.issueType },
118
+ { 'ticketDetails.addressingUser': new mongoose.Types.ObjectId( req.body.userId ) },
119
+ ],
120
+ },
121
+ } );
122
+ } else {
123
+ query.push( {
124
+ $match: {
125
+ $and: [
126
+ { 'basicDetails.clientId': { $in: req.body.clientId } },
127
+ { issueType: { $in: [ 'highcount', 'lowcount' ] } },
128
+ { 'ticketDetails.addressingUser': new mongoose.Types.ObjectId( req.body.userId ) },
129
+ ],
130
+ },
131
+ } );
132
+ }
109
133
  if ( req.body.status != 'closed' || req.body.export ) {
110
134
  query.push( {
111
135
  $match: {
@@ -132,6 +156,7 @@ export async function userTicketList( req, res ) {
132
156
  query.push( {
133
157
  $project: {
134
158
  storeId: '$basicDetails.storeId',
159
+ storeName: '$basicDetails.storeName',
135
160
  Date: { $dateToString: { format: '%d-%m-%Y', date: '$issueDate' } },
136
161
  updatedAt: 1,
137
162
  ticketId: 1,
@@ -140,6 +165,7 @@ export async function userTicketList( req, res ) {
140
165
  issueStatus: '$ticketDetails.issueStatus',
141
166
  ticketType: '$ticketDetails.ticketType',
142
167
  installationStatus: '$ticketDetails.installationStatus',
168
+ matStatus: '$ticketDetails.matStatus',
143
169
  primaryIssue: {
144
170
  $filter: {
145
171
  input: '$ticketActivity',
@@ -162,6 +188,7 @@ export async function userTicketList( req, res ) {
162
188
  {
163
189
  $project: {
164
190
  storeId: 1,
191
+ storeName: 1,
165
192
  updatedAt: 1,
166
193
  Date: 1,
167
194
  ticketId: 1,
@@ -170,6 +197,7 @@ export async function userTicketList( req, res ) {
170
197
  status: 1,
171
198
  issueType: 1,
172
199
  installationStatus: 1,
200
+ matStatus: 1,
173
201
  infraIssue: '$primaryIssue.reasons.primaryIssue',
174
202
  },
175
203
  },
@@ -177,12 +205,14 @@ export async function userTicketList( req, res ) {
177
205
  $group: {
178
206
  _id: '$ticketId',
179
207
  storeId: { $first: '$storeId' },
208
+ storeName: { $first: '$storeName' },
180
209
  updatedAt: { $first: '$updatedAt' },
181
210
  Date: { $first: '$Date' },
182
211
  ticketId: { $first: '$ticketId' },
183
212
  issueType: { $first: '$issueType' },
184
213
  status: { $first: '$status' },
185
214
  installationStatus: { $first: '$installationStatus' },
215
+ matStatus: { $first: '$matStatus' },
186
216
  issueStatus: { $first: '$issueStatus' },
187
217
  ticketType: { $first: '$ticketType' },
188
218
  infraIssue: { $last: '$infraIssue' },
@@ -196,6 +226,7 @@ export async function userTicketList( req, res ) {
196
226
  $or: [
197
227
  { storeId: { $regex: req.body.searchValue, $options: 'i' } },
198
228
  { infraIssue: { $regex: req.body.searchValue, $options: 'i' } },
229
+ { storeName: { $regex: req.body.searchValue, $options: 'i' } },
199
230
  ],
200
231
  },
201
232
  } );
@@ -206,6 +237,7 @@ export async function userTicketList( req, res ) {
206
237
  $or: [
207
238
  { issueStatus: req.body.filter },
208
239
  { infraIssue: req.body.filter },
240
+ { issueType: req.body.filter },
209
241
  ],
210
242
  },
211
243
  } );
@@ -214,13 +246,23 @@ export async function userTicketList( req, res ) {
214
246
  if ( req.body.export ) {
215
247
  const exportdata = [];
216
248
  ticketList.forEach( ( element ) => {
217
- exportdata.push( {
249
+ let data = {
218
250
  'DATE': element.Date,
219
251
  'TICKET ID': element.ticketId,
220
252
  'STORE ID': element.storeId,
221
- 'ISSUE': element.issueStatus,
253
+ 'STORE NAME': element.storeName,
222
254
  'STATUS': element.status,
223
- } );
255
+ };
256
+ if ( req.body.issueType ==='infra' ) {
257
+ data = { ...data, ...{ 'ISSUE': element.issueStatus } };
258
+ }
259
+ if ( req.body.issueType ==='installation' ) {
260
+ data = { ...data, ...{ 'ISSUE': element.issueStatus } };
261
+ }
262
+ if ( req.body.issueType ==='dataMismatch' ) {
263
+ data = { ...data, ...{ 'ISSUE TYPE': element.issueType } };
264
+ }
265
+ exportdata.push( data );
224
266
  } );
225
267
  await download( exportdata, res );
226
268
  return;
@@ -303,16 +345,30 @@ export async function basicDetails( req, res ) {
303
345
  export async function workHistory( req, res ) {
304
346
  try {
305
347
  let date = await getUTC( new Date( req.body.fromDate ), new Date( req.body.toDate ) );
306
- let query = [ {
307
- $match: {
308
- $and: [
309
- { 'status': 'closed' },
310
- { issueType: req.body.issueType },
311
- { 'ticketDetails.addressingUser': new mongoose.Types.ObjectId( req.body.userId ) },
312
- ],
313
- },
314
- } ];
315
-
348
+ let query = [ ];
349
+ if ( req.body.issueType!='dataMismatch' ) {
350
+ query.push( {
351
+ $match: {
352
+ $and: [
353
+ { 'basicDetails.clientId': { $in: req.body.clientId } },
354
+ { 'status': 'closed' },
355
+ { issueType: req.body.issueType },
356
+ { 'ticketDetails.addressingUser': new mongoose.Types.ObjectId( req.body.userId ) },
357
+ ],
358
+ },
359
+ } );
360
+ } else {
361
+ query.push( {
362
+ $match: {
363
+ $and: [
364
+ { 'basicDetails.clientId': { $in: req.body.clientId } },
365
+ { 'status': 'closed' },
366
+ { issueType: { $in: [ 'highcount', 'lowcount' ] } },
367
+ { 'ticketDetails.addressingUser': new mongoose.Types.ObjectId( req.body.userId ) },
368
+ ],
369
+ },
370
+ } );
371
+ }
316
372
  if ( req.body.dateFilter && req.body.dateFilter != '' ) {
317
373
  if ( req.body.dateFilter === 'issueIdentifiedDate' ) {
318
374
  query.push(
@@ -335,6 +391,18 @@ export async function workHistory( req, res ) {
335
391
  { 'issueClosedDate': { $lte: date.end } },
336
392
  ],
337
393
 
394
+ },
395
+ },
396
+ );
397
+ } else if ( req.body.dateFilter === 'issueDate' ) {
398
+ query.push(
399
+ {
400
+ $match: {
401
+ $and: [
402
+ { 'issueDate': { $gte: date.start } },
403
+ { 'issueDate': { $lte: date.end } },
404
+ ],
405
+
338
406
  },
339
407
  },
340
408
  );
@@ -369,6 +437,7 @@ export async function workHistory( req, res ) {
369
437
  storeName: '$basicDetails.storeName',
370
438
  clientId: '$basicDetails.clientId',
371
439
  clientName: '$basicDetails.clientName',
440
+ issueType: 1,
372
441
  issueDate: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } },
373
442
  issueClosedDate: { $dateToString: { format: '%Y-%m-%d', date: '$issueClosedDate' } },
374
443
  issueIdentifiedDate: { $dateToString: { format: '%Y-%m-%d', date: '$ticketDetails.issueIdentifiedDate' } },
@@ -398,6 +467,7 @@ export async function workHistory( req, res ) {
398
467
  $project: {
399
468
  storeId: 1,
400
469
  storeName: 1,
470
+ issueType: 1,
401
471
  clientId: 1,
402
472
  clientName: 1,
403
473
  issueDate: 1,
@@ -405,17 +475,25 @@ export async function workHistory( req, res ) {
405
475
  issueClosedDate: 1,
406
476
  ticketId: 1,
407
477
  issueStatus: 1,
478
+ status: 1,
408
479
  ticketType: 1,
409
480
  infraIssue: { $ifNull: [ '$primaryIssue.reasons.primaryIssue', '' ] },
410
481
  },
411
482
  } );
412
- if ( req.body.issueFilter && req.body.issueFilter.length>0 ) {
483
+ if ( req.body.issueFilter && req.body.issueFilter.length>0&&req.body.issueType!='dataMismatch' ) {
413
484
  query.push( {
414
485
  $match: {
415
486
  infraIssue: { $in: req.body.issueFilter },
416
487
  },
417
488
  } );
418
489
  }
490
+ if ( req.body.issueFilter && req.body.issueFilter.length>0&&req.body.issueType==='dataMismatch' ) {
491
+ query.push( {
492
+ $match: {
493
+ issueType: { $in: req.body.issueFilter },
494
+ },
495
+ } );
496
+ }
419
497
  if ( req.body.searchValue && req.body.searchValue !== '' ) {
420
498
  query.push( {
421
499
  $match: {
@@ -446,19 +524,25 @@ export async function workHistory( req, res ) {
446
524
  if ( req.body.export ) {
447
525
  const exportdata = [];
448
526
  result.forEach( ( element ) => {
449
- exportdata.push( {
527
+ let data ={
450
528
  'CREATED ON': dayjs( element.issueDate ).format( 'DD-MM-YYYY' ),
451
529
  'TICKET ID': element.ticketId,
452
530
  'STORE ID': element.storeId,
453
531
  'STORE NAME': element.storeName,
454
532
  'CLIENT ID': element.clientId,
455
533
  'CLIENT NAME': element.clientName,
456
- 'ISSUE IDENTIFIED DATE': element.issueIdentifiedDate,
457
534
  'CLOSED ON': element.issueClosedDate,
458
- 'ISSUE': element.infraIssue?element.infraIssue:'-',
459
535
  'STATUS': element.status,
460
- } );
536
+ };
537
+ if ( req.body.issueType==='infra'||req.body.issueType==='installation' ) {
538
+ data = { ...data, ...{ 'ISSUE': element.infraIssue?element.infraIssue:'-', 'ISSUE IDENTIFIED DATE': element.issueIdentifiedDate } };
539
+ }
540
+ if ( req.body.issueType==='dataMismatch' ) {
541
+ data = { ...data, ...{ 'issueType': element.issueType?element.issueType:'-' } };
542
+ }
543
+ exportdata.push( data );
461
544
  } );
545
+
462
546
  await download( exportdata, res );
463
547
  return;
464
548
  }
@@ -0,0 +1,28 @@
1
+ import j2s from 'joi-to-swagger';
2
+ import { getInfraIssueSchema } from '../dtos/infra.dtos.js';
3
+
4
+ export const infraDocs = {
5
+
6
+ '/v3/infra/get-infra-issues': {
7
+ post: {
8
+ tags: [ 'infra' ],
9
+ description: `Get infra issues against store`,
10
+ operationId: 'get-infra-issues',
11
+ parameters: {},
12
+ requestBody: {
13
+ content: {
14
+ 'application/json': {
15
+ schema: j2s( getInfraIssueSchema ).swagger,
16
+ },
17
+ },
18
+ },
19
+ responses: {
20
+ 200: { description: 'Group has been created successfully' },
21
+ 401: { description: 'Unauthorized User' },
22
+ 422: { description: 'Field Error' },
23
+ 500: { description: 'Server Error' },
24
+ 204: { description: 'Not Found' },
25
+ },
26
+ },
27
+ },
28
+ };
@@ -0,0 +1,12 @@
1
+ import Joi from 'joi';
2
+
3
+ export const getInfraIssueSchema = Joi.object().keys( {
4
+ fromDate: Joi.string().required(),
5
+ toDate: Joi.string().required(),
6
+ storeId: Joi.string().required(),
7
+
8
+ } );
9
+
10
+ export const getInfraIssueValid = {
11
+ body: getInfraIssueSchema,
12
+ };
@@ -1,10 +1,22 @@
1
1
  import express from 'express';
2
2
  import { isAllowedSessionHandler, authorize } from 'tango-app-api-middleware';
3
- import { createTicket } from '../controllers/dataMismatch.controller.js';
4
- import { validateDetails } from '../validations/infra.validation.js';
5
- export const dataMismatchRouter = express.Router();
3
+ import { createTicket, updateMat, activityList, showActivity } from '../controllers/dataMismatch.controller.js';
4
+ import { ticketExists, validateDetails } from '../validations/infra.validation.js';
5
+ export const dataMismatchTicketRouter = express.Router();
6
6
 
7
- dataMismatchRouter.post( '/createTicket', isAllowedSessionHandler, authorize( {
7
+ dataMismatchTicketRouter.post( '/createTicket', isAllowedSessionHandler, authorize( {
8
8
  userType: [ 'client', 'tango' ], access: [
9
9
  { featureName: 'manage', name: 'tickets', permissions: [ 'isView', 'isEdit' ] } ],
10
10
  } ), validateDetails, createTicket );
11
+ dataMismatchTicketRouter.post( '/updateMat', isAllowedSessionHandler, authorize( {
12
+ userType: [ 'client', 'tango' ], access: [
13
+ { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
14
+ } ), ticketExists, updateMat );
15
+ dataMismatchTicketRouter.post( '/activityList', isAllowedSessionHandler, authorize( {
16
+ userType: [ 'client', 'tango' ], access: [
17
+ { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
18
+ } ), activityList );
19
+ dataMismatchTicketRouter.post( '/showActivity', isAllowedSessionHandler, authorize( {
20
+ userType: [ 'client', 'tango' ], access: [
21
+ { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
22
+ } ), ticketExists, showActivity );
@@ -1,4 +1,4 @@
1
- import { createTicket, updatecomment, activityLog } from '../controllers/employeeTraning.controller.js';
1
+ import { createTicket, updatecomment, activityLog, updateMatStatus } from '../controllers/employeeTraning.controller.js';
2
2
  import { ticketExists, validateDetails } from '../validations/infra.validation.js';
3
3
  import express from 'express';
4
4
  import { isAllowedSessionHandler, authorize } from 'tango-app-api-middleware';
@@ -15,3 +15,7 @@ employeeTrainigRouter.post( '/activityLog', isAllowedSessionHandler, authorize(
15
15
  userType: [ 'tango' ], access: [
16
16
  { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
17
17
  } ), ticketExists, activityLog );
18
+ employeeTrainigRouter.post( '/updateMatStatus', isAllowedSessionHandler, authorize( {
19
+ userType: [ 'tango' ], access: [
20
+ { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
21
+ } ), ticketExists, updateMatStatus );
@@ -1,10 +1,11 @@
1
1
 
2
2
  import express from 'express';
3
- import { isAllowedSessionHandler, authorize } from 'tango-app-api-middleware';
3
+ import { isAllowedSessionHandler, authorize, validate } from 'tango-app-api-middleware';
4
4
  import { validateDetails, bulkvalidateDetails, validateTicket, bulkvalidateTicket, validateTicketstatus, ticketExists, infraReasonExists, InfrastepstoResolve, InfraAlert } from '../validations/infra.validation.js';
5
5
  import { createTicket, bulkcreateTicket, updateStatus, createReason, PrimaryReasons, matTable,
6
- secondaryReason, updateTicketIssue, viewTicket, AlertTicketReply, uploadAttachments,
6
+ secondaryReason, updateTicketIssue, viewTicket, AlertTicketReply, uploadAttachments, getInfraIssues,
7
7
  updateInstallationTicket, emailUserList, saveInfraEmailConfig, invoice, infraTable, storeFilter, assignTicket, installationTable } from '../controllers/infra.controllers.js';
8
+ import { getInfraIssueValid } from '../dtos/infra.dtos.js';
8
9
 
9
10
 
10
11
  export const infraRouter = express.Router();
@@ -75,3 +76,8 @@ infraRouter.post( '/storeFilter', isAllowedSessionHandler, authorize( {
75
76
  userType: [ 'client', 'tango' ], access: [
76
77
  { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
77
78
  } ), storeFilter );
79
+ infraRouter.post( '/get-infra-issues', isAllowedSessionHandler, authorize( {
80
+ userType: [ 'client', 'tango' ], access: [
81
+ { featureName: 'manage', name: 'tickets', permissions: [ 'isView' ] } ],
82
+ } ), validate( getInfraIssueValid ), getInfraIssues );
83
+
@@ -0,0 +1,5 @@
1
+ import cameraModel from 'tango-api-schema/schema/camera.model.js';
2
+
3
+ export async function aggregateCamera( query ) {
4
+ return await cameraModel.aggregate( query );
5
+ }
@@ -9,11 +9,11 @@ export async function validateDetails( req, res, next ) {
9
9
  try {
10
10
  let store = await findOneStore( { storeId: req.body.storeId } );
11
11
  if ( !store ) {
12
- return res.sendError( 'Store Not Available' );
12
+ return res.sendError( 'Store Not Available', 500 );
13
13
  }
14
14
  let client = await findOneClient( { clientId: store.clientId } );
15
15
  if ( !client ) {
16
- return res.sendError( 'Client Not Available' );
16
+ return res.sendError( 'Client Not Available', 500 );
17
17
  }
18
18
 
19
19
  if ( store.spocDetails && store.spocDetails.length > 0 ) {
@@ -186,7 +186,7 @@ export async function ticketExists( req, res, next ) {
186
186
  req.body.ticketActivity = Ticket.ticketActivity;
187
187
  req.body.status = Ticket.status;
188
188
  req.body.issueDate = Ticket.issueDate;
189
-
189
+ req.body.dataMismatch = Ticket.dataMismatch;
190
190
 
191
191
  next();
192
192
  } catch ( error ) {
@@ -202,8 +202,6 @@ export async function validateTicketstatus( req, res, next ) {
202
202
  if ( req.body.status == 'closed' ) {
203
203
  return res.sendSuccess( 'Ticket already closed' );
204
204
  }
205
- console.log( req.body.ticketDetails );
206
-
207
205
  if ( req.body.ticketDetails.ticketType==='firsttimeticket'&&req.body.ticketDetails.issueStatus==='identified' ) {
208
206
  return res.sendSuccess( 'Ticket already Addressed' );
209
207
  }