tango-app-api-infra 3.9.5-vms.81 → 3.9.5-vms.83
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-infra",
|
|
3
|
-
"version": "3.9.5-vms.
|
|
3
|
+
"version": "3.9.5-vms.83",
|
|
4
4
|
"description": "infra",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"mongodb": "^6.4.0",
|
|
28
28
|
"nodemon": "^3.1.0",
|
|
29
29
|
"swagger-ui-express": "^5.0.0",
|
|
30
|
-
"tango-api-schema": "^2.5.
|
|
30
|
+
"tango-api-schema": "^2.5.2",
|
|
31
31
|
"tango-app-api-infra": "^3.9.5-vms.56",
|
|
32
32
|
"tango-app-api-middleware": "^3.1.93",
|
|
33
33
|
"winston": "^3.12.0",
|
|
@@ -2,7 +2,7 @@ import { bulkUpdate, getOpenSearchCount, getOpenSearchData, insertWithId, logger
|
|
|
2
2
|
import { aggregateCluster } from '../services/cluster.service.js';
|
|
3
3
|
import { findOneRevopDownload } from '../services/revopDownload.service.js';
|
|
4
4
|
import { findOneStore } from '../services/store.service.js';
|
|
5
|
-
import { findOneClient } from '../services/client.service.js';
|
|
5
|
+
import { aggregateClient, findOneClient } from '../services/client.service.js';
|
|
6
6
|
import { updateOneUpsertVmsStoreRequest } from '../services/vmsStoreRequest.service.js';
|
|
7
7
|
import { findOneUser, aggregateUser } from '../services/user.service.js';
|
|
8
8
|
import { findteams } from '../services/teams.service.js';
|
|
@@ -277,16 +277,90 @@ export async function ticketCreation( req, res, next ) {
|
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
// get category details from the client level configuration
|
|
280
|
-
const
|
|
280
|
+
const configQuery = [
|
|
281
|
+
{
|
|
282
|
+
$match: {
|
|
283
|
+
clientId: getstoreName?.clientId,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
// Convert all effectiveFrom to proper Date
|
|
288
|
+
{
|
|
289
|
+
$addFields: {
|
|
290
|
+
taggingLimitationWithDate: {
|
|
291
|
+
$map: {
|
|
292
|
+
input: '$footfallDirectoryConfigs.taggingLimitation',
|
|
293
|
+
as: 'item',
|
|
294
|
+
in: {
|
|
295
|
+
effectiveFrom: { $toDate: '$$item.effectiveFrom' },
|
|
296
|
+
values: '$$item.values',
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
// Filter items <= input date
|
|
304
|
+
{
|
|
305
|
+
$addFields: {
|
|
306
|
+
matchedLimitation: {
|
|
307
|
+
$filter: {
|
|
308
|
+
input: '$taggingLimitationWithDate',
|
|
309
|
+
as: 'item',
|
|
310
|
+
cond: {
|
|
311
|
+
$lte: [
|
|
312
|
+
'$$item.effectiveFrom',
|
|
313
|
+
{ $toDate: inputData.dateString },
|
|
314
|
+
],
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
// Sort DESC and pick ONLY top 1 -> latest effective record
|
|
322
|
+
{
|
|
323
|
+
$addFields: {
|
|
324
|
+
effectiveLimitation: {
|
|
325
|
+
$arrayElemAt: [
|
|
326
|
+
{
|
|
327
|
+
$slice: [
|
|
328
|
+
{
|
|
329
|
+
$sortArray: {
|
|
330
|
+
input: '$matchedLimitation',
|
|
331
|
+
sortBy: { effectiveFrom: -1 },
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
1,
|
|
335
|
+
],
|
|
336
|
+
},
|
|
337
|
+
0,
|
|
338
|
+
],
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
{
|
|
344
|
+
$project: {
|
|
345
|
+
config: 1,
|
|
346
|
+
effectiveLimitation: 1,
|
|
347
|
+
footfallDirectoryConfigs: 1,
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
const config = await aggregateClient( configQuery );
|
|
354
|
+
const getConfig = config[0];
|
|
281
355
|
if ( !getConfig || getConfig == null ) {
|
|
282
356
|
return res.sendError( 'The Client ID is either not configured or not found', 400 );
|
|
283
357
|
}
|
|
284
358
|
|
|
285
359
|
// Get taggingLimitation from config (check both possible paths)
|
|
286
|
-
const taggingLimitation = getConfig?.
|
|
360
|
+
const taggingLimitation = getConfig?.effectiveLimitation?.values;
|
|
287
361
|
// Initialize count object from taggingLimitation
|
|
288
362
|
const tempAcc = [];
|
|
289
|
-
taggingLimitation
|
|
363
|
+
taggingLimitation.reduce( ( acc, item ) => {
|
|
290
364
|
if ( item?.type ) {
|
|
291
365
|
// Convert type to camelCase with "Count" suffix
|
|
292
366
|
// e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
|
|
@@ -384,6 +458,7 @@ export async function ticketCreation( req, res, next ) {
|
|
|
384
458
|
const totalCount = Array.isArray( tempAcc ) ?
|
|
385
459
|
tempAcc.reduce( ( sum, acc ) => sum + ( acc.value || 0 ), 0 ) :
|
|
386
460
|
0;
|
|
461
|
+
|
|
387
462
|
const footfallCount = hits?.[0]?._source?.footfall_count || 0;
|
|
388
463
|
const revisedFootfall = Math.max( 0, footfallCount - totalCount );
|
|
389
464
|
if ( footfallCount - revisedFootfall == 0 ) {
|
|
@@ -920,16 +995,90 @@ export async function ticketReview( req, res, next ) {
|
|
|
920
995
|
}
|
|
921
996
|
|
|
922
997
|
// get category details from the client level configuration
|
|
923
|
-
const
|
|
998
|
+
const configQuery = [
|
|
999
|
+
{
|
|
1000
|
+
$match: {
|
|
1001
|
+
clientId: getstoreName?.clientId,
|
|
1002
|
+
},
|
|
1003
|
+
},
|
|
1004
|
+
|
|
1005
|
+
// Convert all effectiveFrom to proper Date
|
|
1006
|
+
{
|
|
1007
|
+
$addFields: {
|
|
1008
|
+
taggingLimitationWithDate: {
|
|
1009
|
+
$map: {
|
|
1010
|
+
input: '$footfallDirectoryConfigs.taggingLimitation',
|
|
1011
|
+
as: 'item',
|
|
1012
|
+
in: {
|
|
1013
|
+
effectiveFrom: { $toDate: '$$item.effectiveFrom' },
|
|
1014
|
+
values: '$$item.values',
|
|
1015
|
+
},
|
|
1016
|
+
},
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
},
|
|
1020
|
+
|
|
1021
|
+
// Filter items <= input date
|
|
1022
|
+
{
|
|
1023
|
+
$addFields: {
|
|
1024
|
+
matchedLimitation: {
|
|
1025
|
+
$filter: {
|
|
1026
|
+
input: '$taggingLimitationWithDate',
|
|
1027
|
+
as: 'item',
|
|
1028
|
+
cond: {
|
|
1029
|
+
$lte: [
|
|
1030
|
+
'$$item.effectiveFrom',
|
|
1031
|
+
{ $toDate: inputData.dateString },
|
|
1032
|
+
],
|
|
1033
|
+
},
|
|
1034
|
+
},
|
|
1035
|
+
},
|
|
1036
|
+
},
|
|
1037
|
+
},
|
|
1038
|
+
|
|
1039
|
+
// Sort DESC and pick ONLY top 1 -> latest effective record
|
|
1040
|
+
{
|
|
1041
|
+
$addFields: {
|
|
1042
|
+
effectiveLimitation: {
|
|
1043
|
+
$arrayElemAt: [
|
|
1044
|
+
{
|
|
1045
|
+
$slice: [
|
|
1046
|
+
{
|
|
1047
|
+
$sortArray: {
|
|
1048
|
+
input: '$matchedLimitation',
|
|
1049
|
+
sortBy: { effectiveFrom: -1 },
|
|
1050
|
+
},
|
|
1051
|
+
},
|
|
1052
|
+
1,
|
|
1053
|
+
],
|
|
1054
|
+
},
|
|
1055
|
+
0,
|
|
1056
|
+
],
|
|
1057
|
+
},
|
|
1058
|
+
},
|
|
1059
|
+
},
|
|
1060
|
+
|
|
1061
|
+
{
|
|
1062
|
+
$project: {
|
|
1063
|
+
config: 1,
|
|
1064
|
+
effectiveLimitation: 1,
|
|
1065
|
+
footfallDirectoryConfigs: 1,
|
|
1066
|
+
},
|
|
1067
|
+
},
|
|
1068
|
+
];
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
const config = await aggregateClient( configQuery );
|
|
1072
|
+
const getConfig = config[0];
|
|
924
1073
|
if ( !getConfig || getConfig == null ) {
|
|
925
1074
|
return res.sendError( 'The Client ID is either not configured or not found', 400 );
|
|
926
1075
|
}
|
|
927
1076
|
|
|
928
1077
|
// Get taggingLimitation from config (check both possible paths)
|
|
929
|
-
const taggingLimitation = getConfig?.
|
|
1078
|
+
const taggingLimitation = getConfig?.effectiveLimitation?.values;
|
|
930
1079
|
// Initialize count object from taggingLimitation
|
|
931
1080
|
const tempAcc = [];
|
|
932
|
-
taggingLimitation
|
|
1081
|
+
taggingLimitation.reduce( ( acc, item ) => {
|
|
933
1082
|
if ( item?.type ) {
|
|
934
1083
|
// Convert type to camelCase with "Count" suffix
|
|
935
1084
|
// e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
|
|
@@ -1454,16 +1603,90 @@ export async function ticketApprove( req, res, next ) {
|
|
|
1454
1603
|
}
|
|
1455
1604
|
|
|
1456
1605
|
// get category details from the client level configuration
|
|
1457
|
-
const
|
|
1606
|
+
const configQuery = [
|
|
1607
|
+
{
|
|
1608
|
+
$match: {
|
|
1609
|
+
clientId: getstoreName?.clientId,
|
|
1610
|
+
},
|
|
1611
|
+
},
|
|
1612
|
+
|
|
1613
|
+
// Convert all effectiveFrom to proper Date
|
|
1614
|
+
{
|
|
1615
|
+
$addFields: {
|
|
1616
|
+
taggingLimitationWithDate: {
|
|
1617
|
+
$map: {
|
|
1618
|
+
input: '$footfallDirectoryConfigs.taggingLimitation',
|
|
1619
|
+
as: 'item',
|
|
1620
|
+
in: {
|
|
1621
|
+
effectiveFrom: { $toDate: '$$item.effectiveFrom' },
|
|
1622
|
+
values: '$$item.values',
|
|
1623
|
+
},
|
|
1624
|
+
},
|
|
1625
|
+
},
|
|
1626
|
+
},
|
|
1627
|
+
},
|
|
1628
|
+
|
|
1629
|
+
// Filter items <= input date
|
|
1630
|
+
{
|
|
1631
|
+
$addFields: {
|
|
1632
|
+
matchedLimitation: {
|
|
1633
|
+
$filter: {
|
|
1634
|
+
input: '$taggingLimitationWithDate',
|
|
1635
|
+
as: 'item',
|
|
1636
|
+
cond: {
|
|
1637
|
+
$lte: [
|
|
1638
|
+
'$$item.effectiveFrom',
|
|
1639
|
+
{ $toDate: inputData.dateString },
|
|
1640
|
+
],
|
|
1641
|
+
},
|
|
1642
|
+
},
|
|
1643
|
+
},
|
|
1644
|
+
},
|
|
1645
|
+
},
|
|
1646
|
+
|
|
1647
|
+
// Sort DESC and pick ONLY top 1 -> latest effective record
|
|
1648
|
+
{
|
|
1649
|
+
$addFields: {
|
|
1650
|
+
effectiveLimitation: {
|
|
1651
|
+
$arrayElemAt: [
|
|
1652
|
+
{
|
|
1653
|
+
$slice: [
|
|
1654
|
+
{
|
|
1655
|
+
$sortArray: {
|
|
1656
|
+
input: '$matchedLimitation',
|
|
1657
|
+
sortBy: { effectiveFrom: -1 },
|
|
1658
|
+
},
|
|
1659
|
+
},
|
|
1660
|
+
1,
|
|
1661
|
+
],
|
|
1662
|
+
},
|
|
1663
|
+
0,
|
|
1664
|
+
],
|
|
1665
|
+
},
|
|
1666
|
+
},
|
|
1667
|
+
},
|
|
1668
|
+
|
|
1669
|
+
{
|
|
1670
|
+
$project: {
|
|
1671
|
+
config: 1,
|
|
1672
|
+
effectiveLimitation: 1,
|
|
1673
|
+
footfallDirectoryConfigs: 1,
|
|
1674
|
+
},
|
|
1675
|
+
},
|
|
1676
|
+
];
|
|
1677
|
+
|
|
1678
|
+
|
|
1679
|
+
const config = await aggregateClient( configQuery );
|
|
1680
|
+
const getConfig = config[0];
|
|
1458
1681
|
if ( !getConfig || getConfig == null ) {
|
|
1459
1682
|
return res.sendError( 'The Client ID is either not configured or not found', 400 );
|
|
1460
1683
|
}
|
|
1461
1684
|
|
|
1462
1685
|
// Get taggingLimitation from config (check both possible paths)
|
|
1463
|
-
const taggingLimitation = getConfig?.
|
|
1686
|
+
const taggingLimitation = getConfig?.effectiveLimitation?.values;
|
|
1464
1687
|
// Initialize count object from taggingLimitation
|
|
1465
1688
|
const tempAcc = [];
|
|
1466
|
-
taggingLimitation
|
|
1689
|
+
taggingLimitation.reduce( ( acc, item ) => {
|
|
1467
1690
|
if ( item?.type ) {
|
|
1468
1691
|
// Convert type to camelCase with "Count" suffix
|
|
1469
1692
|
// e.g., "duplicate" -> "duplicateCount", "housekeeping" -> "houseKeepingCount"
|
|
@@ -1553,9 +1776,9 @@ export async function ticketApprove( req, res, next ) {
|
|
|
1553
1776
|
0;
|
|
1554
1777
|
const footfallCount = hits?.[0]?._source?.footfall_count || 0;
|
|
1555
1778
|
const revisedFootfall = Math.max( 0, footfallCount - totalCount );
|
|
1556
|
-
|
|
1779
|
+
|
|
1557
1780
|
if ( footfallCount - revisedFootfall == 0 ) {
|
|
1558
|
-
return res.sendError( 'Cannot
|
|
1781
|
+
return res.sendError( 'Cannot approve a ticket because footfall hasn’t changed', 400 );
|
|
1559
1782
|
}
|
|
1560
1783
|
|
|
1561
1784
|
const taggingData = {
|
|
@@ -1621,7 +1844,7 @@ export async function ticketApprove( req, res, next ) {
|
|
|
1621
1844
|
if ( !ticketData || ticketData?.length == 0 ) {
|
|
1622
1845
|
return res.sendError( 'You don’t have any tagged images right now', 400 );
|
|
1623
1846
|
}
|
|
1624
|
-
|
|
1847
|
+
|
|
1625
1848
|
const record = {
|
|
1626
1849
|
|
|
1627
1850
|
status: 'Approver-Closed',
|
|
@@ -1641,12 +1864,10 @@ export async function ticketApprove( req, res, next ) {
|
|
|
1641
1864
|
let autoCloseAccuracy = getConfig?.footfallDirectoryConfigs?.autoCloseAccuracy;
|
|
1642
1865
|
|
|
1643
1866
|
const getNumber = autoCloseAccuracy.split( '%' )[0];
|
|
1644
|
-
logger.info( { getNumber } );
|
|
1645
1867
|
let autoCloseAccuracyValue = parseFloat( ( autoCloseAccuracy || getNumber ).replace( '%', '' ) );
|
|
1646
1868
|
let revisedPercentage = Math.round( ( revisedFootfall / footfallCount ) * 100 || 0 );
|
|
1647
1869
|
const revised = Number( Math.round( ( revisedFootfall / footfallCount ) * 100 || 0 ) );
|
|
1648
1870
|
const tangoReview = Number( getConfig?.footfallDirectoryConfigs?.tangoReview?.split( '%' )[0] );
|
|
1649
|
-
logger.info( { tangoReview, revised } );
|
|
1650
1871
|
// If autoclose enabled and revisedPercentage meets/exceeds threshold, close ticket and skip revision
|
|
1651
1872
|
if (
|
|
1652
1873
|
isAutoCloseEnable === true &&
|