tango-app-api-analysis-traffic 3.8.7-vms.31 → 3.8.7-vms.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-analysis-traffic",
|
|
3
|
-
"version": "3.8.7-vms.
|
|
3
|
+
"version": "3.8.7-vms.33",
|
|
4
4
|
"description": "Traffic Analysis",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"mongodb": "^6.8.0",
|
|
24
24
|
"nodemon": "^3.1.4",
|
|
25
25
|
"swagger-ui-express": "^5.0.1",
|
|
26
|
-
"tango-api-schema": "^2.5.
|
|
26
|
+
"tango-api-schema": "^2.5.14",
|
|
27
27
|
"tango-app-api-middleware": "^3.6.5",
|
|
28
28
|
"winston": "^3.13.1",
|
|
29
29
|
"winston-daily-rotate-file": "^5.0.0"
|
|
@@ -3,6 +3,7 @@ import { aggregateStore } from '../services/stores.service.js';
|
|
|
3
3
|
import { findOneNobBilling, updateOneNobBilling } from '../services/nob.service.js';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import { findOne } from '../services/clients.services.js';
|
|
6
|
+
import { find } from '../services/tagging.service.js';
|
|
6
7
|
|
|
7
8
|
export async function storeList( req, res ) {
|
|
8
9
|
try {
|
|
@@ -27,7 +28,7 @@ export async function storeList( req, res ) {
|
|
|
27
28
|
);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const query =[
|
|
31
|
+
const query = [
|
|
31
32
|
{
|
|
32
33
|
$match: {
|
|
33
34
|
$and: filter,
|
|
@@ -59,11 +60,12 @@ export async function storeList( req, res ) {
|
|
|
59
60
|
|
|
60
61
|
export async function addBills( req, res ) {
|
|
61
62
|
try {
|
|
62
|
-
let resData=[];
|
|
63
|
+
let resData = [];
|
|
63
64
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
64
65
|
const inputData = req.tempInserData;
|
|
66
|
+
console.log( '🚀 ~ addBills ~ inputData:', inputData );
|
|
65
67
|
|
|
66
|
-
for ( let i=0; i<inputData?.length; i++ ) {
|
|
68
|
+
for ( let i = 0; i < inputData?.length; i++ ) {
|
|
67
69
|
await updateOneNobBilling( inputData[i]?.query, inputData[i]?.data );
|
|
68
70
|
const getData = await findOneNobBilling( inputData[i]?.query, { _id: 0 } );
|
|
69
71
|
if ( !inputData[i]?.isUpdated ) {
|
|
@@ -77,7 +79,7 @@ export async function addBills( req, res ) {
|
|
|
77
79
|
logger.info( { resData: resData } );
|
|
78
80
|
return res.sendSuccess( 'Data has been inserted/updated successfully' );
|
|
79
81
|
} catch ( error ) {
|
|
80
|
-
const err= error.message || 'Internal Server Error';
|
|
82
|
+
const err = error.message || 'Internal Server Error';
|
|
81
83
|
logger.error( { error: error, message: req.body, function: 'nob-addBills' } );
|
|
82
84
|
return res.sendError( err, 500 );
|
|
83
85
|
}
|
|
@@ -91,7 +93,7 @@ export async function getNobData( req, res ) {
|
|
|
91
93
|
return res.sendError( 'No data found', 204 );
|
|
92
94
|
}
|
|
93
95
|
const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( new Date( inputData.toDate ) ) );
|
|
94
|
-
let temp ={};
|
|
96
|
+
let temp = {};
|
|
95
97
|
let filter = [
|
|
96
98
|
{
|
|
97
99
|
'terms': {
|
|
@@ -99,8 +101,12 @@ export async function getNobData( req, res ) {
|
|
|
99
101
|
},
|
|
100
102
|
},
|
|
101
103
|
{
|
|
102
|
-
range: {
|
|
103
|
-
|
|
104
|
+
range: {
|
|
105
|
+
nobDate: {
|
|
106
|
+
gte: dateRange.start,
|
|
107
|
+
lte: dateRange.end,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
104
110
|
},
|
|
105
111
|
];
|
|
106
112
|
if ( req.user.role !== 'superadmin' && req.user.userType !== 'tango' ) {
|
|
@@ -116,7 +122,7 @@ export async function getNobData( req, res ) {
|
|
|
116
122
|
'must': filter,
|
|
117
123
|
};
|
|
118
124
|
|
|
119
|
-
if ( inputData.searchValue && inputData.searchValue!== '' ) {
|
|
125
|
+
if ( inputData.searchValue && inputData.searchValue !== '' ) {
|
|
120
126
|
const searchValue = escapeSpecialChars( inputData.searchValue );
|
|
121
127
|
temp = {
|
|
122
128
|
|
|
@@ -149,9 +155,9 @@ export async function getNobData( req, res ) {
|
|
|
149
155
|
}
|
|
150
156
|
const getClient = await findOne( { clientId: req.clientId }, { featureConfigs: 1 } );
|
|
151
157
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
152
|
-
const limit = inputData.isExport? 10000 : inputData.limit || 200;
|
|
153
|
-
const skip = inputData.offset? ( inputData.offset - 1 ) * limit : 0;
|
|
154
|
-
const nobQuery={
|
|
158
|
+
const limit = inputData.isExport ? 10000 : inputData.limit || 200;
|
|
159
|
+
const skip = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
|
|
160
|
+
const nobQuery = {
|
|
155
161
|
'from': skip,
|
|
156
162
|
'size': limit,
|
|
157
163
|
'query': {
|
|
@@ -159,17 +165,17 @@ export async function getNobData( req, res ) {
|
|
|
159
165
|
},
|
|
160
166
|
};
|
|
161
167
|
|
|
162
|
-
const getNobData=await getOpenSearchData( openSearch.nob, nobQuery );
|
|
168
|
+
const getNobData = await getOpenSearchData( openSearch.nob, nobQuery );
|
|
163
169
|
const nobData = getNobData?.body?.hits?.hits;
|
|
164
|
-
if ( !nobData ||nobData?.length == 0 ) {
|
|
165
|
-
if ( inputData.searchValue && inputData.searchValue!== '' || inputData.offset> 1 ) {
|
|
170
|
+
if ( !nobData || nobData?.length == 0 ) {
|
|
171
|
+
if ( inputData.searchValue && inputData.searchValue !== '' || inputData.offset > 1 ) {
|
|
166
172
|
return res.sendError( 'No Data Found', 204 );
|
|
167
173
|
} else {
|
|
168
174
|
return res.sendSuccess( { initialInsert: false } );
|
|
169
175
|
}
|
|
170
176
|
}
|
|
171
177
|
|
|
172
|
-
const footfallQuery={
|
|
178
|
+
const footfallQuery = {
|
|
173
179
|
'size': 10000,
|
|
174
180
|
'query': {
|
|
175
181
|
'bool': {
|
|
@@ -180,29 +186,33 @@ export async function getNobData( req, res ) {
|
|
|
180
186
|
},
|
|
181
187
|
},
|
|
182
188
|
{
|
|
183
|
-
range: {
|
|
184
|
-
|
|
189
|
+
range: {
|
|
190
|
+
date_iso: {
|
|
191
|
+
gte: `${inputData.fromDate}T00:00:00`,
|
|
192
|
+
lte: `${inputData.toDate}T00:00:00`,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
185
195
|
},
|
|
186
196
|
],
|
|
187
197
|
},
|
|
188
198
|
},
|
|
189
199
|
};
|
|
190
200
|
|
|
191
|
-
const getFootfall= await getOpenSearchData( openSearch.footfall, footfallQuery );
|
|
201
|
+
const getFootfall = await getOpenSearchData( openSearch.footfall, footfallQuery );
|
|
192
202
|
const footfall = getFootfall?.body?.hits?.hits;
|
|
193
203
|
logger.info( { footfall: getFootfall, nobData: nobData } );
|
|
194
|
-
let result=[];
|
|
204
|
+
let result = [];
|
|
195
205
|
nobData.map( async ( data ) => {
|
|
196
206
|
let count = 0;
|
|
197
|
-
let temp=[];
|
|
207
|
+
let temp = [];
|
|
198
208
|
|
|
199
|
-
data._source.isUpdated = data._source.createdAt !== data._source.updatedAt? true : false;
|
|
200
|
-
!data._source.isUpdated ? isEdit = true: null;
|
|
209
|
+
data._source.isUpdated = data._source.createdAt !== data._source.updatedAt ? true : false;
|
|
210
|
+
!data._source.isUpdated ? isEdit = true : null;
|
|
201
211
|
|
|
202
212
|
footfall.map( ( item ) => {
|
|
203
213
|
if ( ( data._source.dateString === item._source.date_string ) && ( data._source.storeId === item._source.store_id ) ) {
|
|
204
214
|
count = 1;
|
|
205
|
-
temp =[
|
|
215
|
+
temp = [
|
|
206
216
|
{
|
|
207
217
|
storeName: item._source.store_name,
|
|
208
218
|
footfallCount: item._source.footfall_count,
|
|
@@ -217,16 +227,16 @@ export async function getNobData( req, res ) {
|
|
|
217
227
|
if ( count === 1 ) {
|
|
218
228
|
switch ( getClient?.featureConfigs?.conversionCalculation ) {
|
|
219
229
|
case 'footfall-count':
|
|
220
|
-
conversionCount = temp[0]?.footfallCount? ( data?._source?.nobCount/temp[0]?.footfallCount )*100 : null;
|
|
230
|
+
conversionCount = temp[0]?.footfallCount ? ( data?._source?.nobCount / temp[0]?.footfallCount ) * 100 : null;
|
|
221
231
|
break;
|
|
222
232
|
case 'billable-entities':
|
|
223
|
-
conversionCount = temp[0]?.potentialBuyers? ( data?._source?.nobCount/temp[0]?.potentialBuyers )*100 : null;
|
|
233
|
+
conversionCount = temp[0]?.potentialBuyers ? ( data?._source?.nobCount / temp[0]?.potentialBuyers ) * 100 : null;
|
|
224
234
|
break;
|
|
225
235
|
case 'engagers-count':
|
|
226
|
-
conversionCount = temp[0]?.engagersCount? ( data?._source?.nobCount/temp[0]?.engagersCount )*100 : null;
|
|
236
|
+
conversionCount = temp[0]?.engagersCount ? ( data?._source?.nobCount / temp[0]?.engagersCount ) * 100 : null;
|
|
227
237
|
break;
|
|
228
238
|
default:
|
|
229
|
-
conversionCount = temp[0]?.engagersCount? ( data?._source?.nobCount/temp[0]?.engagersCount )*100 : null;
|
|
239
|
+
conversionCount = temp[0]?.engagersCount ? ( data?._source?.nobCount / temp[0]?.engagersCount ) * 100 : null;
|
|
230
240
|
}
|
|
231
241
|
result.push( {
|
|
232
242
|
|
|
@@ -235,7 +245,7 @@ export async function getNobData( req, res ) {
|
|
|
235
245
|
footfallCount: temp[0]?.footfallCount || null,
|
|
236
246
|
engagersCount: temp[0]?.engagersCount || null,
|
|
237
247
|
potentialBuyers: temp[0]?.potentialBuyers || null,
|
|
238
|
-
conversionRate: conversionCount == null ? null
|
|
248
|
+
conversionRate: conversionCount == null ? null : `${Math.round( conversionCount )} %`,
|
|
239
249
|
|
|
240
250
|
} );
|
|
241
251
|
} else {
|
|
@@ -279,7 +289,7 @@ export async function getNobData( req, res ) {
|
|
|
279
289
|
default:
|
|
280
290
|
exportData[index]['Engagers Count'] = element.engagersCount;
|
|
281
291
|
}
|
|
282
|
-
element.conversionRate? exportData[index]['Conversion Rate'] = `${element.conversionRate}` : exportData[index]['Conversion Rate'] =null;
|
|
292
|
+
element.conversionRate ? exportData[index]['Conversion Rate'] = `${element.conversionRate}` : exportData[index]['Conversion Rate'] = null;
|
|
283
293
|
} );
|
|
284
294
|
return exportData;
|
|
285
295
|
} );
|
|
@@ -301,3 +311,66 @@ export async function getNobData( req, res ) {
|
|
|
301
311
|
function escapeSpecialChars( str ) {
|
|
302
312
|
return str.replace( /[-[\]{}()*+?.,\\^$|#]/g, '\\$&' );
|
|
303
313
|
}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
export async function zonelist( req, res ) {
|
|
317
|
+
try {
|
|
318
|
+
let zonelist = await find( { storeId: { $in: req.body.storeId }, productName: 'tangoZone' }, { tagName: 1 } );
|
|
319
|
+
return res.sendSuccess( zonelist );
|
|
320
|
+
} catch ( error ) {
|
|
321
|
+
const err = error.message || 'Internal Server Error';
|
|
322
|
+
logger.error( { error: error, message: req.body, function: 'nob-getNobData' } );
|
|
323
|
+
return res.sendError( err, 500 );
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
export async function zonetemplate( req, res ) {
|
|
327
|
+
try {
|
|
328
|
+
if ( req.user.userType === 'tango'||req.user.userType === 'client'&&req.user.role==='superadmin' ) {
|
|
329
|
+
let storeList = await aggregateStore(
|
|
330
|
+
[
|
|
331
|
+
{
|
|
332
|
+
$match: {
|
|
333
|
+
clientId: req.body.clientId,
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
let stores = storeList.map( ( data ) => data.storeId );
|
|
341
|
+
|
|
342
|
+
req.body.assignedStores = stores;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
let exportData = [];
|
|
347
|
+
const zonelist = await find(
|
|
348
|
+
{ storeId: { $in: req.body.assignedStores }, productName: 'tangoZone' },
|
|
349
|
+
{ tagName: 1, storeId: 1 },
|
|
350
|
+
);
|
|
351
|
+
let uniqueZone = zonelist.map( ( data ) => data.tagName );
|
|
352
|
+
|
|
353
|
+
for ( const element of req.body.assignedStores ) {
|
|
354
|
+
const row = {
|
|
355
|
+
'Store Id': element,
|
|
356
|
+
'NoB Date': '',
|
|
357
|
+
'Overall NoB Count': '',
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// make tagName as key
|
|
361
|
+
uniqueZone.forEach( ( zone ) => {
|
|
362
|
+
row[zone] = ''; // or 0 / true / any value you want
|
|
363
|
+
} );
|
|
364
|
+
|
|
365
|
+
exportData.push( row );
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
await download( exportData, res );
|
|
370
|
+
return;
|
|
371
|
+
} catch ( error ) {
|
|
372
|
+
const err = error.message || 'Internal Server Error';
|
|
373
|
+
logger.error( { error: error, message: req.body, function: 'nob-getNobData' } );
|
|
374
|
+
return res.sendError( err, 500 );
|
|
375
|
+
}
|
|
376
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { logger, insertOpenSearchData, getOpenSearchData, updateOpenSearchData } from 'tango-app-api-middleware';
|
|
2
2
|
import { findOnerevopConfig } from '../services/revopConfig.service.js';
|
|
3
3
|
import * as clientService from '../services/clients.services.js';
|
|
4
|
-
import { bulkUpdate, insertWithId,
|
|
4
|
+
import { bulkUpdate, insertWithId, scrollResponse, searchOpenSearchData, upsertWithScript } from 'tango-app-api-middleware/src/utils/openSearch.js';
|
|
5
5
|
import { findOneVmsStoreRequest } from '../services/vmsStoreRequest.service.js';
|
|
6
6
|
// import dayjs from 'dayjs';
|
|
7
7
|
// Lamda Service Call //
|
|
@@ -70,7 +70,7 @@ export async function revoptagging( req, res ) {
|
|
|
70
70
|
|
|
71
71
|
let respo= await getOpenSearchData( openSearch.revops, searchQuery );
|
|
72
72
|
const revopData = respo?.body?.hits?.hits;
|
|
73
|
-
if ( revopData&& revopData.length>0 ) {
|
|
73
|
+
if ( revopData && revopData.length>0 ) {
|
|
74
74
|
await updateOpenSearchData( openSearch.revops, revopData[0]._id, { doc: item } );
|
|
75
75
|
} else {
|
|
76
76
|
item.createdAt = new Date();
|
|
@@ -140,14 +140,29 @@ export async function getrevoptagging( req, res ) {
|
|
|
140
140
|
|
|
141
141
|
export async function migrateRevopIndex( req, res ) {
|
|
142
142
|
try {
|
|
143
|
-
const { storeId, dateString, size =
|
|
143
|
+
const { storeId, dateString, size = 100 } = req.body;
|
|
144
144
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
145
145
|
|
|
146
146
|
const query = {
|
|
147
147
|
size: size,
|
|
148
148
|
query: {
|
|
149
149
|
bool: {
|
|
150
|
-
must: [
|
|
150
|
+
must: [
|
|
151
|
+
// {
|
|
152
|
+
// range: {
|
|
153
|
+
// createdAt: {
|
|
154
|
+
// gte: '2025-10-01T00:00:00.000Z',
|
|
155
|
+
// lte: '2025-10-31T23:59:59.000Z',
|
|
156
|
+
// },
|
|
157
|
+
// },
|
|
158
|
+
// },
|
|
159
|
+
{
|
|
160
|
+
term: {
|
|
161
|
+
'type.keyword': 'tagging-reflect',
|
|
162
|
+
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
],
|
|
151
166
|
},
|
|
152
167
|
},
|
|
153
168
|
};
|
|
@@ -168,21 +183,80 @@ export async function migrateRevopIndex( req, res ) {
|
|
|
168
183
|
} );
|
|
169
184
|
}
|
|
170
185
|
|
|
171
|
-
const response = await getOpenSearchData( openSearch.revop, query );
|
|
172
|
-
const hits = response?.body?.hits?.hits || [];
|
|
186
|
+
// const response = await getOpenSearchData( openSearch.revop, query );
|
|
187
|
+
// const hits = response?.body?.hits?.hits || [];
|
|
173
188
|
|
|
174
|
-
|
|
175
|
-
|
|
189
|
+
// Use OpenSearch scroll API to retrieve up to 60000 records efficiently
|
|
190
|
+
let allHits = [];
|
|
191
|
+
let scrollId = null;
|
|
192
|
+
let totalFetched = 0;
|
|
193
|
+
let firstResponse = await searchOpenSearchData( openSearch.revop, query );
|
|
194
|
+
// Collect first batch
|
|
195
|
+
let hitsBatch = firstResponse?.body?.hits?.hits || [];
|
|
196
|
+
if ( hitsBatch.length > 0 ) {
|
|
197
|
+
allHits.push( ...hitsBatch );
|
|
198
|
+
totalFetched += hitsBatch.length;
|
|
199
|
+
scrollId = firstResponse.body._scroll_id;
|
|
176
200
|
}
|
|
177
201
|
|
|
178
202
|
const bulkBody = [];
|
|
179
|
-
|
|
180
|
-
for ( const hit of hits ) {
|
|
203
|
+
for ( const hit of hitsBatch ) {
|
|
181
204
|
const src = hit._source || {};
|
|
182
205
|
const statusValue = ( src.status || '' ).toLowerCase();
|
|
183
|
-
const parentValue = src.parent;
|
|
184
|
-
|
|
206
|
+
// const parentValue = src.parent;
|
|
207
|
+
|
|
208
|
+
// Get ticket sattasu from the footfalldirectory index matching src.storeId and src.dateString
|
|
209
|
+
let ticketStatus = null;
|
|
210
|
+
|
|
211
|
+
const footfallQuery = {
|
|
212
|
+
size: 1,
|
|
213
|
+
query: {
|
|
214
|
+
bool: {
|
|
215
|
+
must: [
|
|
216
|
+
{ term: { 'storeId.keyword': src.storeId } },
|
|
217
|
+
{ term: { 'dateString': src.dateString } },
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
const footfallResp = await getOpenSearchData( openSearch.oldFootfallDirectory, footfallQuery );
|
|
223
|
+
ticketStatus = footfallResp?.body?.hits?.hits?.[0]?._source?.status || null;
|
|
224
|
+
if ( src?.duplicateImage?.length > 0 ) {
|
|
225
|
+
src.duplicateImage = src.duplicateImage.map( ( item ) => ( {
|
|
226
|
+
...item,
|
|
227
|
+
id: `${src.storeId || ''}_${src.dateString || src.dteString || ''}_${item.tempId || ''}`,
|
|
228
|
+
actions: ( ticketStatus === 'closed' && item.isChecked === true ) ? [
|
|
229
|
+
{
|
|
230
|
+
actionType: 'tagging',
|
|
231
|
+
action: 'submitted',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
actionType: 'review',
|
|
235
|
+
action: 'approved',
|
|
236
|
+
},
|
|
237
|
+
]: ( ticketStatus === 'closed' && item.isChecked === false )?
|
|
238
|
+
[
|
|
239
|
+
{
|
|
240
|
+
actionType: 'tagging',
|
|
241
|
+
action: 'submitted',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
actionType: 'review',
|
|
245
|
+
action: 'rejected',
|
|
246
|
+
},
|
|
247
|
+
]:
|
|
248
|
+
[
|
|
249
|
+
{
|
|
250
|
+
actionType: 'tagging',
|
|
251
|
+
action: 'submitted',
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
// Include relevant action, assuming 'actions' will be determined below
|
|
255
|
+
} ) );
|
|
256
|
+
}
|
|
257
|
+
|
|
185
258
|
|
|
259
|
+
const idValue = `${src.storeId || ''}_${src.dateString || src.dteString || ''}_${src.tempId || ''}`;
|
|
186
260
|
let actions = [
|
|
187
261
|
{
|
|
188
262
|
actionType: 'tagging',
|
|
@@ -214,12 +288,15 @@ export async function migrateRevopIndex( req, res ) {
|
|
|
214
288
|
];
|
|
215
289
|
}
|
|
216
290
|
|
|
291
|
+
|
|
217
292
|
const doc = {
|
|
293
|
+
...src,
|
|
218
294
|
id: idValue,
|
|
219
|
-
|
|
295
|
+
revopsType: src?.revopsType === 'house-keeping'? 'houseKeeping' : src?.revopsType,
|
|
296
|
+
isParent: src?.duplicateImage?.length > 0? true : false,
|
|
220
297
|
actions,
|
|
221
298
|
ticketStatus: src.status,
|
|
222
|
-
|
|
299
|
+
// updatedAt: new Date(),
|
|
223
300
|
};
|
|
224
301
|
|
|
225
302
|
bulkBody.push(
|
|
@@ -229,11 +306,274 @@ export async function migrateRevopIndex( req, res ) {
|
|
|
229
306
|
}
|
|
230
307
|
|
|
231
308
|
const bulkRes = await bulkUpdate( bulkBody );
|
|
309
|
+
|
|
232
310
|
if ( bulkRes?.errors ) {
|
|
233
311
|
logger.error( 'Bulk migration errors:', bulkRes.items );
|
|
234
312
|
return res.sendError( 'Failed to migrate some records', 500 );
|
|
235
313
|
}
|
|
236
314
|
|
|
315
|
+
while ( hitsBatch.length > 0 && scrollId ) {
|
|
316
|
+
// Fetch next batch using scroll_id
|
|
317
|
+
const nextScrollRes = await scrollResponse( scrollId );
|
|
318
|
+
|
|
319
|
+
hitsBatch = nextScrollRes?.body?.hits?.hits || [];
|
|
320
|
+
if ( hitsBatch.length === 0 ) break;
|
|
321
|
+
logger.info( { hitsBatch: hitsBatch?.length } );
|
|
322
|
+
const bulkBody = [];
|
|
323
|
+
for ( const hit of hitsBatch ) {
|
|
324
|
+
const src = hit._source || {};
|
|
325
|
+
const statusValue = ( src.status || '' ).toLowerCase();
|
|
326
|
+
// const parentValue = src.parent;
|
|
327
|
+
|
|
328
|
+
// Get ticket sattasu from the footfalldirectory index matching src.storeId and src.dateString
|
|
329
|
+
let ticketStatus = null;
|
|
330
|
+
|
|
331
|
+
const footfallQuery = {
|
|
332
|
+
size: 1,
|
|
333
|
+
query: {
|
|
334
|
+
bool: {
|
|
335
|
+
must: [
|
|
336
|
+
{ term: { 'storeId.keyword': src.storeId } },
|
|
337
|
+
{ term: { 'dateString': src.dateString } },
|
|
338
|
+
],
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
const footfallResp = await getOpenSearchData( openSearch.oldFootfallDirectory, footfallQuery );
|
|
343
|
+
ticketStatus = footfallResp?.body?.hits?.hits?.[0]?._source?.status || null;
|
|
344
|
+
if ( src?.duplicateImage?.length > 0 ) {
|
|
345
|
+
src.duplicateImage = src.duplicateImage.map( ( item ) => ( {
|
|
346
|
+
...item,
|
|
347
|
+
id: `${src.storeId || ''}_${src.dateString || src.dteString || ''}_${item.tempId || ''}`,
|
|
348
|
+
actions: ( ticketStatus === 'closed' && item.isChecked === true ) ? [
|
|
349
|
+
{
|
|
350
|
+
actionType: 'tagging',
|
|
351
|
+
action: 'submitted',
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
actionType: 'review',
|
|
355
|
+
action: 'approved',
|
|
356
|
+
},
|
|
357
|
+
]: ( ticketStatus === 'closed' && item.isChecked === false )?
|
|
358
|
+
[
|
|
359
|
+
{
|
|
360
|
+
actionType: 'tagging',
|
|
361
|
+
action: 'submitted',
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
actionType: 'review',
|
|
365
|
+
action: 'rejected',
|
|
366
|
+
},
|
|
367
|
+
]:
|
|
368
|
+
[
|
|
369
|
+
{
|
|
370
|
+
actionType: 'tagging',
|
|
371
|
+
action: 'submitted',
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
// Include relevant action, assuming 'actions' will be determined below
|
|
375
|
+
} ) );
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
const idValue = `${src.storeId || ''}_${src.dateString || src.dteString || ''}_${src.tempId || ''}`;
|
|
380
|
+
logger.info( { idValue } );
|
|
381
|
+
let actions = [
|
|
382
|
+
{
|
|
383
|
+
actionType: 'tagging',
|
|
384
|
+
action: 'submitted',
|
|
385
|
+
},
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
if ( statusValue === 'approved' ) {
|
|
389
|
+
actions = [
|
|
390
|
+
{
|
|
391
|
+
actionType: 'tagging',
|
|
392
|
+
action: 'submitted',
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
actionType: 'review',
|
|
396
|
+
action: 'approved',
|
|
397
|
+
},
|
|
398
|
+
];
|
|
399
|
+
} else if ( statusValue === 'rejected' ) {
|
|
400
|
+
actions = [
|
|
401
|
+
{
|
|
402
|
+
actionType: 'tagging',
|
|
403
|
+
action: 'submitted',
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
actionType: 'review',
|
|
407
|
+
action: 'rejected',
|
|
408
|
+
},
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
const doc = {
|
|
414
|
+
...src,
|
|
415
|
+
id: idValue,
|
|
416
|
+
revopsType: src?.revopsType === 'house-keeping'? 'houseKeeping' : src?.revopsType,
|
|
417
|
+
isParent: src?.duplicateImage?.length > 0? true : false,
|
|
418
|
+
actions,
|
|
419
|
+
ticketStatus: src.status,
|
|
420
|
+
// updatedAt: new Date(),
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
bulkBody.push(
|
|
424
|
+
{ update: { _index: openSearch.newRevop, _id: hit._id } },
|
|
425
|
+
{ doc: doc, doc_as_upsert: true },
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const bulkRes = await bulkUpdate( bulkBody );
|
|
430
|
+
|
|
431
|
+
if ( bulkRes?.errors ) {
|
|
432
|
+
logger.error( 'Bulk migration errors:', bulkRes.items );
|
|
433
|
+
return res.sendError( 'Failed to migrate some records', 500 );
|
|
434
|
+
}
|
|
435
|
+
allHits.push( ...hitsBatch );
|
|
436
|
+
totalFetched += hitsBatch.length;
|
|
437
|
+
logger.info( { totalFetched } );
|
|
438
|
+
// Protect against exceeding limit
|
|
439
|
+
|
|
440
|
+
scrollId = nextScrollRes.body._scroll_id;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// For downstream logic, use allHits instead of hits
|
|
444
|
+
const hits = allHits;
|
|
445
|
+
|
|
446
|
+
if ( hits.length === 0 ) {
|
|
447
|
+
return res.sendSuccess( { message: 'No records found for migration', updated: 0 } );
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
// for ( const hit of hits ) {
|
|
452
|
+
// const src = hit._source || {};
|
|
453
|
+
// const statusValue = ( src.status || '' ).toLowerCase();
|
|
454
|
+
// // const parentValue = src.parent;
|
|
455
|
+
|
|
456
|
+
// // Get ticket sattasu from the footfalldirectory index matching src.storeId and src.dateString
|
|
457
|
+
// let ticketStatus = null;
|
|
458
|
+
|
|
459
|
+
// const footfallQuery = {
|
|
460
|
+
// size: 1,
|
|
461
|
+
// query: {
|
|
462
|
+
// bool: {
|
|
463
|
+
// must: [
|
|
464
|
+
// { term: { 'storeId.keyword': src.storeId } },
|
|
465
|
+
// { term: { 'dateString': src.dateString } },
|
|
466
|
+
// ],
|
|
467
|
+
// },
|
|
468
|
+
// },
|
|
469
|
+
// };
|
|
470
|
+
// const footfallResp = await getOpenSearchData( openSearch.oldFootfallDirectory, footfallQuery );
|
|
471
|
+
// ticketStatus = footfallResp?.body?.hits?.hits?.[0]?._source?.status || null;
|
|
472
|
+
// if ( src?.duplicateImage?.length > 0 ) {
|
|
473
|
+
// src.duplicateImage = src.duplicateImage.map( ( item ) => ( {
|
|
474
|
+
// ...item,
|
|
475
|
+
// id: `${src.storeId || ''}_${src.dateString || src.dteString || ''}_${item.tempId || ''}`,
|
|
476
|
+
// actions: ( ticketStatus === 'closed' && item.isChecked === true ) ? [
|
|
477
|
+
// {
|
|
478
|
+
// actionType: 'tagging',
|
|
479
|
+
// action: 'submitted',
|
|
480
|
+
// },
|
|
481
|
+
// {
|
|
482
|
+
// actionType: 'review',
|
|
483
|
+
// action: 'approved',
|
|
484
|
+
// },
|
|
485
|
+
// ]: ( ticketStatus === 'closed' && item.isChecked === false )?
|
|
486
|
+
// [
|
|
487
|
+
// {
|
|
488
|
+
// actionType: 'tagging',
|
|
489
|
+
// action: 'submitted',
|
|
490
|
+
// },
|
|
491
|
+
// {
|
|
492
|
+
// actionType: 'review',
|
|
493
|
+
// action: 'rejected',
|
|
494
|
+
// },
|
|
495
|
+
// ]:
|
|
496
|
+
// [
|
|
497
|
+
// {
|
|
498
|
+
// actionType: 'tagging',
|
|
499
|
+
// action: 'submitted',
|
|
500
|
+
// },
|
|
501
|
+
// ],
|
|
502
|
+
// // Include relevant action, assuming 'actions' will be determined below
|
|
503
|
+
// } ) );
|
|
504
|
+
// }
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
// const idValue = `${src.storeId || ''}_${src.dateString || src.dteString || ''}_${src.tempId || ''}`;
|
|
508
|
+
|
|
509
|
+
// let actions = [
|
|
510
|
+
// {
|
|
511
|
+
// actionType: 'tagging',
|
|
512
|
+
// action: 'submitted',
|
|
513
|
+
// },
|
|
514
|
+
// ];
|
|
515
|
+
|
|
516
|
+
// if ( statusValue === 'approved' ) {
|
|
517
|
+
// actions = [
|
|
518
|
+
// {
|
|
519
|
+
// actionType: 'tagging',
|
|
520
|
+
// action: 'submitted',
|
|
521
|
+
// },
|
|
522
|
+
// {
|
|
523
|
+
// actionType: 'review',
|
|
524
|
+
// action: 'approved',
|
|
525
|
+
// },
|
|
526
|
+
// ];
|
|
527
|
+
// } else if ( statusValue === 'rejected' ) {
|
|
528
|
+
// actions = [
|
|
529
|
+
// {
|
|
530
|
+
// actionType: 'tagging',
|
|
531
|
+
// action: 'submitted',
|
|
532
|
+
// },
|
|
533
|
+
// {
|
|
534
|
+
// actionType: 'review',
|
|
535
|
+
// action: 'rejected',
|
|
536
|
+
// },
|
|
537
|
+
// ];
|
|
538
|
+
// }
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
// const doc = {
|
|
542
|
+
// ...src,
|
|
543
|
+
// id: idValue,
|
|
544
|
+
// revopsType: src?.revopsType === 'house-keeping'? 'houseKeeping' : src?.revopsType,
|
|
545
|
+
// isParent: src?.duplicateImage?.length > 0? true : false,
|
|
546
|
+
// actions,
|
|
547
|
+
// ticketStatus: src.status,
|
|
548
|
+
// // updatedAt: new Date(),
|
|
549
|
+
// };
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
// bulkBody.push(
|
|
553
|
+
// { update: { _index: openSearch.newRevop, _id: hit._id } },
|
|
554
|
+
// { doc: doc, doc_as_upsert: true },
|
|
555
|
+
// );
|
|
556
|
+
// }
|
|
557
|
+
// Implement batch by batch update
|
|
558
|
+
// const BATCH_SIZE = 10000; // You can adjust the batch size as needed
|
|
559
|
+
|
|
560
|
+
// for ( let i = 0; i < bulkBody.length; i += BATCH_SIZE ) {
|
|
561
|
+
// const batch = bulkBody.slice( i, i + BATCH_SIZE );
|
|
562
|
+
// const bulkRes = await bulkUpdate( batch );
|
|
563
|
+
|
|
564
|
+
// if ( bulkRes?.errors ) {
|
|
565
|
+
// logger.error( 'Bulk migration errors:', bulkRes.items );
|
|
566
|
+
// return res.sendError( 'Failed to migrate some records', 500 );
|
|
567
|
+
// }
|
|
568
|
+
// }
|
|
569
|
+
|
|
570
|
+
// const bulkRes = await bulkUpdate( bulkBody );
|
|
571
|
+
|
|
572
|
+
// if ( bulkRes?.errors ) {
|
|
573
|
+
// logger.error( 'Bulk migration errors:', bulkRes.items );
|
|
574
|
+
// return res.sendError( 'Failed to migrate some records', 500 );
|
|
575
|
+
// }
|
|
576
|
+
|
|
237
577
|
return res.sendSuccess( { message: 'Migration completed', updated: hits.length } );
|
|
238
578
|
} catch ( error ) {
|
|
239
579
|
logger.error( { error: error, message: req.body, function: 'migrateRevopIndex' } );
|
|
@@ -1002,7 +1342,7 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1002
1342
|
try {
|
|
1003
1343
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
1004
1344
|
const inputData = req.body;
|
|
1005
|
-
const { storeId, dateString, limit =
|
|
1345
|
+
const { storeId, dateString, limit = 10000 } = inputData;
|
|
1006
1346
|
|
|
1007
1347
|
// Build query to fetch old structure documents
|
|
1008
1348
|
const query = {
|
|
@@ -1014,6 +1354,14 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1014
1354
|
'ticketName.keyword': 'footfall-directory',
|
|
1015
1355
|
},
|
|
1016
1356
|
},
|
|
1357
|
+
// {
|
|
1358
|
+
// range: {
|
|
1359
|
+
// createdAt: {
|
|
1360
|
+
// gte: '2025-12-01T00:00:00.000Z',
|
|
1361
|
+
// lte: '2025-12-03T00:00:00.000Z',
|
|
1362
|
+
// },
|
|
1363
|
+
// },
|
|
1364
|
+
// },
|
|
1017
1365
|
],
|
|
1018
1366
|
},
|
|
1019
1367
|
},
|
|
@@ -1069,17 +1417,22 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1069
1417
|
const documentId = hit._id;
|
|
1070
1418
|
|
|
1071
1419
|
// Calculate revicedFootfall (sum of AC counts)
|
|
1072
|
-
const
|
|
1420
|
+
const tempFootfall =oldSource?.status === 'open' ?
|
|
1421
|
+
( oldSource.duplicateCount || 0 ) +
|
|
1422
|
+
( oldSource.employeeCount || 0 ) +
|
|
1423
|
+
( oldSource.houseKeepingCount || 0 ) +
|
|
1424
|
+
( oldSource.junkCount || 0 ):
|
|
1425
|
+
( oldSource.duplicateACCount || 0 ) +
|
|
1073
1426
|
( oldSource.employeeACCount || 0 ) +
|
|
1074
1427
|
( oldSource.houseKeepingACCount || 0 ) +
|
|
1075
1428
|
( oldSource.junkACCount || 0 );
|
|
1076
1429
|
|
|
1077
1430
|
// Calculate revicedPerc
|
|
1078
1431
|
const footfallCount = oldSource.footfallCount || 0;
|
|
1432
|
+
const revicedFootfall = footfallCount - tempFootfall;
|
|
1079
1433
|
const revicedPerc = footfallCount > 0 ?
|
|
1080
1434
|
Math.round( ( revicedFootfall / footfallCount ) * 100 ) :
|
|
1081
1435
|
0;
|
|
1082
|
-
|
|
1083
1436
|
// Calculate reviced
|
|
1084
1437
|
const reviced = parseInt( revicedPerc );
|
|
1085
1438
|
|
|
@@ -1269,7 +1622,8 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1269
1622
|
];
|
|
1270
1623
|
|
|
1271
1624
|
// Create mappingInfo array
|
|
1272
|
-
const mappingInfo =
|
|
1625
|
+
const mappingInfo = oldSource.status === 'open' ?
|
|
1626
|
+
[
|
|
1273
1627
|
{
|
|
1274
1628
|
type: 'tagging',
|
|
1275
1629
|
mode: 'mobile',
|
|
@@ -1290,9 +1644,41 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1290
1644
|
revisedDetail,
|
|
1291
1645
|
status: oldSource.status === 'open' ? 'Open' : oldSource.status || 'Open',
|
|
1292
1646
|
dueDate: oldSource.updatedAt ? new Date( new Date( oldSource.updatedAt ).getTime() + 3 * 24 * 60 * 60 * 1000 ) : new Date( Date.now() + 3 * 24 * 60 * 60 * 1000 ),
|
|
1647
|
+
createdAt: oldSource.createdAt || new Date(),
|
|
1293
1648
|
},
|
|
1294
|
-
]
|
|
1295
|
-
|
|
1649
|
+
]:
|
|
1650
|
+
|
|
1651
|
+
[
|
|
1652
|
+
{
|
|
1653
|
+
type: 'tagging',
|
|
1654
|
+
mode: 'web',
|
|
1655
|
+
revicedFootfall,
|
|
1656
|
+
revicedPerc: `${revicedPerc}%`,
|
|
1657
|
+
reviced,
|
|
1658
|
+
count,
|
|
1659
|
+
revisedDetail,
|
|
1660
|
+
status: oldSource.status === 'closed' ? 'Closed' : oldSource.status || 'Closed',
|
|
1661
|
+
createdByEmail: oldSource.email || '',
|
|
1662
|
+
createdByUserName: oldSource.userName || '',
|
|
1663
|
+
createdByRole: oldSource.role || 'user',
|
|
1664
|
+
createdAt: oldSource.createdAt || new Date(),
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
type: 'review',
|
|
1668
|
+
mode: 'web',
|
|
1669
|
+
revicedFootfall,
|
|
1670
|
+
revicedPerc: `${revicedPerc}%`,
|
|
1671
|
+
reviced,
|
|
1672
|
+
count,
|
|
1673
|
+
revisedDetail,
|
|
1674
|
+
status: oldSource.status === 'closed' ? 'Closed' : oldSource.status || 'Closed',
|
|
1675
|
+
dueDate: oldSource.createdAt ? new Date( new Date( oldSource.createdAt ).getTime() + 3 * 24 * 60 * 60 * 1000 ) : new Date( Date.now() + 3 * 24 * 60 * 60 * 1000 ),
|
|
1676
|
+
createdAt: oldSource.createdAt || new Date(),
|
|
1677
|
+
createdByEmail: oldSource.approverEmail || '',
|
|
1678
|
+
createdByUserName: oldSource.approverUserName || '',
|
|
1679
|
+
createdByRole: oldSource.approverRole || 'user',
|
|
1680
|
+
},
|
|
1681
|
+
];
|
|
1296
1682
|
// Create new structure
|
|
1297
1683
|
const newSource = {
|
|
1298
1684
|
storeId: oldSource.storeId,
|
|
@@ -1305,7 +1691,7 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1305
1691
|
ticketId: oldSource.ticketId,
|
|
1306
1692
|
createdAt: oldSource.createdAt,
|
|
1307
1693
|
updatedAt: oldSource.updatedAt,
|
|
1308
|
-
status: oldSource.status === 'open' ? 'Raised' :
|
|
1694
|
+
status: oldSource.status === 'open' ? 'Raised' : 'Closed' || 'Raised',
|
|
1309
1695
|
comments: oldSource.comments || '',
|
|
1310
1696
|
revicedFootfall,
|
|
1311
1697
|
revicedPerc: `${revicedPerc}%`,
|
|
@@ -1314,8 +1700,9 @@ export async function vmsDataMigration( req, res ) {
|
|
|
1314
1700
|
};
|
|
1315
1701
|
|
|
1316
1702
|
// Update document in OpenSearch
|
|
1317
|
-
|
|
1318
|
-
|
|
1703
|
+
const updatedData = await updateOpenSearchData( openSearch.footfallDirectory, documentId, { doc: newSource, doc_as_upsert: true } );
|
|
1704
|
+
logger.info( { updatedData } );
|
|
1705
|
+
migratedCount++;
|
|
1319
1706
|
|
|
1320
1707
|
logger.info( { message: 'Document migrated successfully', newSource, documentId, storeId: oldSource.storeId, dateString: oldSource.dateString } );
|
|
1321
1708
|
} catch ( error ) {
|
package/src/dtos/nob.dtos.js
CHANGED
|
@@ -21,6 +21,19 @@ export const addBillsSchema = joi.object( {
|
|
|
21
21
|
'string.empty': 'Please enter a valid NOB Count',
|
|
22
22
|
'any.required': 'NOB Count is required',
|
|
23
23
|
} ).allow( null ),
|
|
24
|
+
zonewisenob: joi.array().items(
|
|
25
|
+
joi.object( {
|
|
26
|
+
zoneName: joi.string().required().messages( {
|
|
27
|
+
'string.empty': 'Zone name is required',
|
|
28
|
+
'any.required': 'Zone name is required',
|
|
29
|
+
} ),
|
|
30
|
+
|
|
31
|
+
nobCount: joi.number().required().messages( {
|
|
32
|
+
'number.base': 'Please enter a valid Zone NOB Count',
|
|
33
|
+
'any.required': 'Zone NOB Count is required',
|
|
34
|
+
} ),
|
|
35
|
+
} ),
|
|
36
|
+
).optional(),
|
|
24
37
|
} ),
|
|
25
38
|
).required(),
|
|
26
39
|
|
package/src/routes/nob.routes.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { accessVerification, bulkValidate, getAssinedStore, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
3
3
|
import { addBillsValid, getNobDataValid, storeListValid } from '../dtos/nob.dtos.js';
|
|
4
|
-
import { addBills, getNobData, storeList } from '../controllers/nob.controllers.js';
|
|
4
|
+
import { addBills, getNobData, storeList, zonelist, zonetemplate } from '../controllers/nob.controllers.js';
|
|
5
5
|
import { clientValidations, fieldValidation, roleVerification } from '../validations/nob.validations.js';
|
|
6
6
|
|
|
7
7
|
const nobRouter=express.Router();
|
|
@@ -13,4 +13,8 @@ nobRouter.post( '/add-bills', isAllowedSessionHandler, accessVerification( { use
|
|
|
13
13
|
|
|
14
14
|
nobRouter.post( '/get-nob-data', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), validate( getNobDataValid ), clientValidations, getAssinedStore, getNobData );
|
|
15
15
|
|
|
16
|
+
nobRouter.post( '/zonelist', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), zonelist );
|
|
17
|
+
|
|
18
|
+
nobRouter.post( '/zonetemplate', isAllowedSessionHandler, accessVerification( { userType: [ 'client', 'tango' ] } ), getAssinedStore, zonetemplate );
|
|
19
|
+
|
|
16
20
|
export default nobRouter;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import nobBillingModel from 'tango-api-schema/schema/nobBilling.model.js';
|
|
2
2
|
|
|
3
3
|
export async function updateOneNobBilling( query, record ) {
|
|
4
|
+
console.log( '🚀 ~ updateOneNobBilling ~ record:', record );
|
|
4
5
|
return await nobBillingModel.updateOne( query, { $set: record }, { upsert: true } );
|
|
5
6
|
}
|
|
6
7
|
|
|
@@ -121,6 +121,7 @@ export async function fieldValidation( req, res, next ) {
|
|
|
121
121
|
nobDate: nobDateIso,
|
|
122
122
|
nobCount: inputFilter[i]?.nobCount,
|
|
123
123
|
dateString: inputFilter[i]?.nobDate,
|
|
124
|
+
zonewisenob: inputFilter[i]?.zonewisenob?inputFilter[i]?.zonewisenob:[],
|
|
124
125
|
};
|
|
125
126
|
const query ={ storeId: storeData[0]?.storeId, nobDate: inputFilter[i]?.nobDate };
|
|
126
127
|
|