tango-app-api-audit 1.0.51 → 1.0.52
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 +1 -1
- package/src/controllers/audit.controllers.js +280 -6
- package/src/controllers/auditMetrics.controllers.js +1 -253
- package/src/docs/audit.docs.js +38 -1
- package/src/docs/auditMetrics.docs.js +2 -23
- package/src/dtos/audit.dtos.js +29 -1
- package/src/dtos/auditMetrics.dtos.js +0 -23
- package/src/routes/audit.routes.js +6 -2
- package/src/routes/auditMetrics.routes.js +3 -3
package/package.json
CHANGED
|
@@ -96,6 +96,7 @@ export async function clients( req, res ) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
// store
|
|
99
100
|
export async function auditStoreList( req, res ) {
|
|
100
101
|
try {
|
|
101
102
|
const inputData = req.body;
|
|
@@ -139,6 +140,7 @@ export async function auditStoreList( req, res ) {
|
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
// user
|
|
142
144
|
export async function auditUserList( req, res ) {
|
|
143
145
|
try {
|
|
144
146
|
const inputData = req.query;
|
|
@@ -726,9 +728,9 @@ export const mapFunction = async ( chunk, filter ) => {
|
|
|
726
728
|
export async function workSpace( req, res ) {
|
|
727
729
|
try {
|
|
728
730
|
const inputData = req.query;
|
|
729
|
-
const limit =
|
|
731
|
+
const limit = inputData.limit || 10;
|
|
730
732
|
const offset = inputData.offset ?
|
|
731
|
-
(
|
|
733
|
+
( inputData.offset - 1 ) * limit :
|
|
732
734
|
0;
|
|
733
735
|
const dateRange = await getUTC( new Date(), new Date() );
|
|
734
736
|
|
|
@@ -744,12 +746,13 @@ export async function workSpace( req, res ) {
|
|
|
744
746
|
},
|
|
745
747
|
{
|
|
746
748
|
$project: {
|
|
747
|
-
clientName:
|
|
748
|
-
clientId:
|
|
749
|
+
clientName: 1,
|
|
750
|
+
clientId: 1,
|
|
749
751
|
},
|
|
750
752
|
},
|
|
751
753
|
];
|
|
752
754
|
|
|
755
|
+
|
|
753
756
|
if ( inputData.searchValue && inputData.searchValue !== '' ) {
|
|
754
757
|
clientQuery.push( {
|
|
755
758
|
$match: {
|
|
@@ -760,6 +763,15 @@ export async function workSpace( req, res ) {
|
|
|
760
763
|
},
|
|
761
764
|
} );
|
|
762
765
|
}
|
|
766
|
+
if ( inputData.sortColumnName ) {
|
|
767
|
+
const sortBy = inputData.sortBy || -1;
|
|
768
|
+
logger.info( { sortBy: sortBy } );
|
|
769
|
+
clientQuery.push( {
|
|
770
|
+
$sort: { [inputData.sortColumName]: sortBy },
|
|
771
|
+
},
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
|
|
763
775
|
const count = await aggregateClient( clientQuery );
|
|
764
776
|
if ( count?.length == 0 ) {
|
|
765
777
|
return res.sendError( 'No Data Found', 204 );
|
|
@@ -814,6 +826,7 @@ export async function workSpace( req, res ) {
|
|
|
814
826
|
$and: [
|
|
815
827
|
{ clientId: { $in: clientList } },
|
|
816
828
|
{ fileDate: { $eq: latestDate } },
|
|
829
|
+
{ moduleType: { $eq: inputData.moduleType } },
|
|
817
830
|
],
|
|
818
831
|
},
|
|
819
832
|
},
|
|
@@ -856,6 +869,7 @@ export async function workSpace( req, res ) {
|
|
|
856
869
|
{ clientId: { $in: clientList } },
|
|
857
870
|
{ createdAt: { $gte: dateRange.start } },
|
|
858
871
|
{ createdAt: { $lte: dateRange.end } },
|
|
872
|
+
{ moduleType: { $eq: inputData.moduleType } },
|
|
859
873
|
],
|
|
860
874
|
},
|
|
861
875
|
},
|
|
@@ -894,6 +908,7 @@ export async function workSpace( req, res ) {
|
|
|
894
908
|
$and: [
|
|
895
909
|
{ clientId: { $in: clientList } },
|
|
896
910
|
{ userId: { $eq: req.user._id } },
|
|
911
|
+
{ moduleType: { $eq: inputData.moduleType } },
|
|
897
912
|
{ createdAt: { $gte: dateRange.start } },
|
|
898
913
|
{ createdAt: { $lte: dateRange.end } },
|
|
899
914
|
],
|
|
@@ -934,6 +949,7 @@ export async function workSpace( req, res ) {
|
|
|
934
949
|
{ userId: { $eq: req.user._id } },
|
|
935
950
|
{ isCompleted: false },
|
|
936
951
|
{ clientId: { $in: clientList } },
|
|
952
|
+
{ moduleType: { $eq: inputData.moduleType } },
|
|
937
953
|
],
|
|
938
954
|
},
|
|
939
955
|
},
|
|
@@ -956,7 +972,10 @@ export async function workSpace( req, res ) {
|
|
|
956
972
|
const clientAssign = [
|
|
957
973
|
{
|
|
958
974
|
$match: {
|
|
959
|
-
$and: [ { isCompleted: false },
|
|
975
|
+
$and: [ { isCompleted: false },
|
|
976
|
+
{ clientId: { $in: clientList } },
|
|
977
|
+
{ moduleType: { $eq: inputData.moduleType } },
|
|
978
|
+
],
|
|
960
979
|
},
|
|
961
980
|
},
|
|
962
981
|
{
|
|
@@ -1071,7 +1090,7 @@ export async function workSpace( req, res ) {
|
|
|
1071
1090
|
return;
|
|
1072
1091
|
} else {
|
|
1073
1092
|
return res.sendSuccess( {
|
|
1074
|
-
result: temp
|
|
1093
|
+
result: temp,
|
|
1075
1094
|
count: count.length,
|
|
1076
1095
|
totalStores: totalStores,
|
|
1077
1096
|
} );
|
|
@@ -1386,3 +1405,258 @@ export async function save( req, res ) {
|
|
|
1386
1405
|
return res.sendError( err );
|
|
1387
1406
|
}
|
|
1388
1407
|
}
|
|
1408
|
+
|
|
1409
|
+
/* < -- *** Audit Metrics *** --> */
|
|
1410
|
+
|
|
1411
|
+
export async function userAuditHistory( req, res ) {
|
|
1412
|
+
try {
|
|
1413
|
+
const inputData = req.body;
|
|
1414
|
+
const userId = inputData.userId? new mongoose.Types.ObjectId( inputData.userId ) : req.user._id;
|
|
1415
|
+
const limit = inputData.limit || 10;
|
|
1416
|
+
const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
|
|
1417
|
+
const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
|
|
1418
|
+
|
|
1419
|
+
let filter = [
|
|
1420
|
+
{ userId: { $eq: userId } },
|
|
1421
|
+
];
|
|
1422
|
+
|
|
1423
|
+
if ( inputData.dateType == 'fileDate' ) {
|
|
1424
|
+
filter.push(
|
|
1425
|
+
{ fileDateISO: { $gte: dateRange.start } },
|
|
1426
|
+
{ fileDateISO: { $lte: dateRange.end } },
|
|
1427
|
+
);
|
|
1428
|
+
} else {
|
|
1429
|
+
filter.push(
|
|
1430
|
+
{ createdAt: { $gte: dateRange.start } },
|
|
1431
|
+
{ createdAt: { $lte: dateRange.end } },
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
if ( inputData.filterByModuleType?.length > 0 ) {
|
|
1436
|
+
filter.push( {
|
|
1437
|
+
moduleType: { $in: inputData.filterByModuleType },
|
|
1438
|
+
} );
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
if ( inputData.filterByAuditType?.length > 0 ) {
|
|
1442
|
+
filter.push( {
|
|
1443
|
+
auditType: { $in: inputData.filterByAuditType },
|
|
1444
|
+
} );
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
if ( inputData.filterByStoreId?.length > 0 ) {
|
|
1448
|
+
filter.push( {
|
|
1449
|
+
storeId: { $in: inputData.filterByStoreId },
|
|
1450
|
+
} );
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
if ( inputData.filterByStatus?.length > 0 ) {
|
|
1454
|
+
filter.push( {
|
|
1455
|
+
auditStatus: { $in: inputData.filterByStatus },
|
|
1456
|
+
} );
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
const query = [
|
|
1460
|
+
{
|
|
1461
|
+
$match: {
|
|
1462
|
+
$and: filter,
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
$lookup: {
|
|
1467
|
+
from: 'stores',
|
|
1468
|
+
let: { storeId: '$storeId' },
|
|
1469
|
+
pipeline: [
|
|
1470
|
+
{
|
|
1471
|
+
$match: {
|
|
1472
|
+
$expr: {
|
|
1473
|
+
$eq: [ '$storeId', '$$storeId' ],
|
|
1474
|
+
},
|
|
1475
|
+
},
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
$project: {
|
|
1479
|
+
storeName: 1,
|
|
1480
|
+
},
|
|
1481
|
+
},
|
|
1482
|
+
], as: 'store',
|
|
1483
|
+
},
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
$unwind: {
|
|
1487
|
+
path: '$store', preserveNullAndEmptyArrays: true,
|
|
1488
|
+
},
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
$lookup: {
|
|
1492
|
+
from: 'clients',
|
|
1493
|
+
let: { clientId: '$clientId' },
|
|
1494
|
+
pipeline: [
|
|
1495
|
+
{
|
|
1496
|
+
$match: {
|
|
1497
|
+
$expr: {
|
|
1498
|
+
$eq: [ '$clientId', '$$clientId' ],
|
|
1499
|
+
},
|
|
1500
|
+
},
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
$project: {
|
|
1504
|
+
clientName: 1,
|
|
1505
|
+
},
|
|
1506
|
+
},
|
|
1507
|
+
], as: 'client',
|
|
1508
|
+
},
|
|
1509
|
+
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
$unwind: {
|
|
1513
|
+
path: '$client', preserveNullAndEmptyArrays: true,
|
|
1514
|
+
},
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
$project: {
|
|
1518
|
+
storeId: 1,
|
|
1519
|
+
userId: 1,
|
|
1520
|
+
storeName: '$store.storeName',
|
|
1521
|
+
clientId: 1,
|
|
1522
|
+
clientName: '$client.clientName',
|
|
1523
|
+
fileDate: 1,
|
|
1524
|
+
auditType: 1,
|
|
1525
|
+
zoneName: 1,
|
|
1526
|
+
moduleType: 1,
|
|
1527
|
+
beforeCount: 1,
|
|
1528
|
+
afterCount: 1,
|
|
1529
|
+
accuracy: { $cond: [ { $eq: [ '$auditStatus', 'completed' ] }, { $round: [
|
|
1530
|
+
{
|
|
1531
|
+
$multiply: [ { $divide: [ '$afterCount', '$beforeCount' ] }, 100 ],
|
|
1532
|
+
}, 1,
|
|
1533
|
+
],
|
|
1534
|
+
}, null ] },
|
|
1535
|
+
|
|
1536
|
+
startTime: {
|
|
1537
|
+
$dateToString: {
|
|
1538
|
+
format: '%Y-%m-%d %H:%M:%S',
|
|
1539
|
+
date: '$startTime',
|
|
1540
|
+
timezone: 'Asia/Kolkata',
|
|
1541
|
+
},
|
|
1542
|
+
},
|
|
1543
|
+
endTime: {
|
|
1544
|
+
$dateToString: {
|
|
1545
|
+
format: '%Y-%m-%d %H:%M:%S',
|
|
1546
|
+
date: '$endTime',
|
|
1547
|
+
timezone: 'Asia/Kolkata',
|
|
1548
|
+
},
|
|
1549
|
+
},
|
|
1550
|
+
// timeSpent: { $round: [
|
|
1551
|
+
// { $divide: [ '$timeSpent', 60 ] }, 2,
|
|
1552
|
+
// ] },
|
|
1553
|
+
timeSpent: {
|
|
1554
|
+
|
|
1555
|
+
$cond: [
|
|
1556
|
+
{ $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
|
|
1557
|
+
{ $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
|
|
1558
|
+
{
|
|
1559
|
+
$cond: [
|
|
1560
|
+
{ $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
|
|
1561
|
+
{
|
|
1562
|
+
$concat: [
|
|
1563
|
+
{ $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
|
|
1564
|
+
' min',
|
|
1565
|
+
],
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
$concat: [
|
|
1569
|
+
{ $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
|
|
1570
|
+
' hr',
|
|
1571
|
+
],
|
|
1572
|
+
},
|
|
1573
|
+
],
|
|
1574
|
+
},
|
|
1575
|
+
],
|
|
1576
|
+
|
|
1577
|
+
},
|
|
1578
|
+
auditStatus: 1,
|
|
1579
|
+
createdAt: 1,
|
|
1580
|
+
},
|
|
1581
|
+
},
|
|
1582
|
+
];
|
|
1583
|
+
|
|
1584
|
+
if ( inputData.searchValue && inputData.searchValue!== '' ) {
|
|
1585
|
+
query.push( {
|
|
1586
|
+
$match: {
|
|
1587
|
+
$or: [
|
|
1588
|
+
{ clientName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1589
|
+
{ clientId: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1590
|
+
{ storeId: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1591
|
+
{ storeName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1592
|
+
{ zoneName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1593
|
+
{ moduleType: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1594
|
+
{ auditType: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1595
|
+
{ auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
|
|
1596
|
+
],
|
|
1597
|
+
|
|
1598
|
+
},
|
|
1599
|
+
} );
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
if ( inputData.sortColumnName ) {
|
|
1603
|
+
const sortBy =inputData.sortBy || -1;
|
|
1604
|
+
query.push( {
|
|
1605
|
+
$sort: { [inputData.sortColumName]: sortBy },
|
|
1606
|
+
},
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1609
|
+
const count = await aggregateUserAudit( query );
|
|
1610
|
+
if ( count.length == 0 ) {
|
|
1611
|
+
return res.sendError( 'No Data Found', 204 );
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
if ( inputData.isExport ) {
|
|
1615
|
+
const chunkedMappingData = await chunkArray( count, 10 );
|
|
1616
|
+
const promises = chunkedMappingData.map( async ( chunk ) => {
|
|
1617
|
+
const exportData = [];
|
|
1618
|
+
chunk.forEach( ( element ) => {
|
|
1619
|
+
exportData.push( {
|
|
1620
|
+
|
|
1621
|
+
'Client Id': element.clientId,
|
|
1622
|
+
'Client Name': element.clientName,
|
|
1623
|
+
'Store Id': element.storeId,
|
|
1624
|
+
'Store Name': element.storeName,
|
|
1625
|
+
'Zone Name': element.zoneName,
|
|
1626
|
+
'Audit Type': element.auditType,
|
|
1627
|
+
'Module Type': element.moduleType,
|
|
1628
|
+
'Before Count': element.beforeCount,
|
|
1629
|
+
'After Count': element.afterCount,
|
|
1630
|
+
'Accuracy': element.accuracy,
|
|
1631
|
+
'Start Time': element.startTime,
|
|
1632
|
+
'End Time': element.endTime,
|
|
1633
|
+
'Time Spent': element.timeSpent,
|
|
1634
|
+
'Audit Status': element.auditStatus,
|
|
1635
|
+
'CreatedAt': dayjs( element.createdAt ).format( 'YYYY,MMM D' ),
|
|
1636
|
+
|
|
1637
|
+
} );
|
|
1638
|
+
} );
|
|
1639
|
+
return exportData;
|
|
1640
|
+
} );
|
|
1641
|
+
const mappedArrays = await Promise.all( promises );
|
|
1642
|
+
mappedArrays.flat();
|
|
1643
|
+
|
|
1644
|
+
await download( mappedArrays, res );
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
query.push( {
|
|
1649
|
+
$skip: offset,
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
$limit: limit,
|
|
1653
|
+
} );
|
|
1654
|
+
const result = await aggregateUserAudit( query );
|
|
1655
|
+
|
|
1656
|
+
return res.sendSuccess( { result: result, count: count.length } );
|
|
1657
|
+
} catch ( error ) {
|
|
1658
|
+
const err = error.message || 'Internal Server Error';
|
|
1659
|
+
logger.info( { error: error, message: req.body, function: 'userAuditHistory' } );
|
|
1660
|
+
return res.sendError( err, 500 );
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { download, getUTC, insertOpenSearchData, logger, sendMessageToQueue } from 'tango-app-api-middleware';
|
|
2
2
|
import { aggregateUserAudit, updateOneUserAudit } from '../service/userAudit.service.js';
|
|
3
3
|
import mongoose from 'mongoose';
|
|
4
4
|
import { aggregateStoreAudit, updateOneStoreAudit } from '../service/storeAudit.service.js';
|
|
@@ -11,258 +11,6 @@ import { getAuditFilterData, getAuditImageData, zipDownloadImage } from '../vali
|
|
|
11
11
|
import { getReauditImg } from './audit.controllers.js';
|
|
12
12
|
// import { listQueue } from 'tango-app-api-middleware/src/utils/aws/sqs.js';
|
|
13
13
|
|
|
14
|
-
export async function userAuditHistory( req, res ) {
|
|
15
|
-
try {
|
|
16
|
-
const inputData = req.body;
|
|
17
|
-
const userId = inputData.userId? new mongoose.Types.ObjectId( inputData.userId ) : req.user._id;
|
|
18
|
-
const limit = inputData.limit || 10;
|
|
19
|
-
const offset = inputData.offset ? ( inputData.offset - 1 ) * limit : 0;
|
|
20
|
-
const dateRange = await getUTC( new Date( inputData.fromDate ), new Date( inputData.toDate ) );
|
|
21
|
-
let filter = [
|
|
22
|
-
|
|
23
|
-
{ userId: { $eq: userId } },
|
|
24
|
-
|
|
25
|
-
];
|
|
26
|
-
if ( inputData.fileType == 'fileDate' ) {
|
|
27
|
-
filter.push(
|
|
28
|
-
{ fileDateISO: { $gte: dateRange.start } },
|
|
29
|
-
{ fileDateISO: { $lte: dateRange.end } },
|
|
30
|
-
);
|
|
31
|
-
} else {
|
|
32
|
-
filter.push(
|
|
33
|
-
{ createdAt: { $gte: dateRange.start } },
|
|
34
|
-
{ createdAt: { $lte: dateRange.end } },
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if ( inputData.filterByAuditType?.length > 0 ) {
|
|
39
|
-
filter.push( {
|
|
40
|
-
moduleType: { $in: inputData.filterByAuditType },
|
|
41
|
-
} );
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if ( inputData.filterByStoreId?.length > 0 ) {
|
|
45
|
-
filter.push( {
|
|
46
|
-
storeId: { $in: inputData.filterByStoreId },
|
|
47
|
-
} );
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if ( inputData.filterByStatus?.length > 0 ) {
|
|
51
|
-
filter.push( {
|
|
52
|
-
auditStatus: { $in: inputData.filterByStatus },
|
|
53
|
-
} );
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const query = [
|
|
57
|
-
{
|
|
58
|
-
$match: {
|
|
59
|
-
$and: filter,
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
query.push( {
|
|
66
|
-
$lookup: {
|
|
67
|
-
from: 'stores',
|
|
68
|
-
let: { storeId: '$storeId' },
|
|
69
|
-
pipeline: [
|
|
70
|
-
{
|
|
71
|
-
$match: {
|
|
72
|
-
$expr: {
|
|
73
|
-
$eq: [ '$storeId', '$$storeId' ],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
$project: {
|
|
79
|
-
storeName: 1,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
], as: 'store',
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
} );
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
query.push( {
|
|
89
|
-
$unwind: {
|
|
90
|
-
path: '$store', preserveNullAndEmptyArrays: true,
|
|
91
|
-
},
|
|
92
|
-
} );
|
|
93
|
-
|
|
94
|
-
query.push( {
|
|
95
|
-
$lookup: {
|
|
96
|
-
from: 'clients',
|
|
97
|
-
let: { clientId: '$clientId' },
|
|
98
|
-
pipeline: [
|
|
99
|
-
{
|
|
100
|
-
$match: {
|
|
101
|
-
$expr: {
|
|
102
|
-
$eq: [ '$clientId', '$$clientId' ],
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
$project: {
|
|
108
|
-
clientName: 1,
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
], as: 'client',
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
} );
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
query.push( {
|
|
118
|
-
$unwind: {
|
|
119
|
-
path: '$client', preserveNullAndEmptyArrays: true,
|
|
120
|
-
},
|
|
121
|
-
} );
|
|
122
|
-
|
|
123
|
-
query.push( {
|
|
124
|
-
$project: {
|
|
125
|
-
storeId: 1,
|
|
126
|
-
userId: 1,
|
|
127
|
-
storeName: '$store.storeName',
|
|
128
|
-
clientId: 1,
|
|
129
|
-
clientName: 'client.clientName',
|
|
130
|
-
fileDate: 1,
|
|
131
|
-
auditType: 1,
|
|
132
|
-
zoneName: 1,
|
|
133
|
-
moduleType: 1,
|
|
134
|
-
beforeCount: 1,
|
|
135
|
-
afterCount: 1,
|
|
136
|
-
accuracy: { $round: [
|
|
137
|
-
{
|
|
138
|
-
$divide: [ { $multiply: [ '$beforeCount', { $ifNull: [ '$afterCount', 0 ] } ] }, 100 ],
|
|
139
|
-
}, 1,
|
|
140
|
-
],
|
|
141
|
-
},
|
|
142
|
-
startTime: {
|
|
143
|
-
$dateToString: {
|
|
144
|
-
format: '%Y-%m-%d %H:%M:%S',
|
|
145
|
-
date: '$startTime',
|
|
146
|
-
timezone: 'Asia/Kolkata',
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
endTime: {
|
|
150
|
-
$dateToString: {
|
|
151
|
-
format: '%Y-%m-%d %H:%M:%S',
|
|
152
|
-
date: '$endTime',
|
|
153
|
-
timezone: 'Asia/Kolkata',
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
// timeSpent: { $round: [
|
|
157
|
-
// { $divide: [ '$timeSpent', 60 ] }, 2,
|
|
158
|
-
// ] },
|
|
159
|
-
timeSpent: {
|
|
160
|
-
|
|
161
|
-
$cond: [
|
|
162
|
-
{ $lt: [ '$timeSpent', 60 ] }, // Case 1: If less than 60 seconds
|
|
163
|
-
{ $concat: [ { $toString: '$timeSpent' }, ' sec' ] },
|
|
164
|
-
{
|
|
165
|
-
$cond: [
|
|
166
|
-
{ $lt: [ '$timeSpent', 3600 ] }, // Case 2: If less than 60 minutes (3600 seconds)
|
|
167
|
-
{
|
|
168
|
-
$concat: [
|
|
169
|
-
{ $toString: { $round: [ { $divide: [ '$timeSpent', 60 ] }, 1 ] } }, // Convert to minutes
|
|
170
|
-
' min',
|
|
171
|
-
],
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
$concat: [
|
|
175
|
-
{ $toString: { $round: [ { $divide: [ '$timeSpent', 3600 ] }, 1 ] } }, // Convert to hours
|
|
176
|
-
' hr',
|
|
177
|
-
],
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
},
|
|
181
|
-
],
|
|
182
|
-
|
|
183
|
-
},
|
|
184
|
-
auditStatus: 1,
|
|
185
|
-
createdAt: 1,
|
|
186
|
-
},
|
|
187
|
-
} );
|
|
188
|
-
|
|
189
|
-
if ( inputData.searchValue && inputData.searchValue!== '' ) {
|
|
190
|
-
query.push( {
|
|
191
|
-
$match: {
|
|
192
|
-
$or: [
|
|
193
|
-
{ clientName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
194
|
-
{ clientType: { $regex: inputData.searchValue, $options: 'i' } },
|
|
195
|
-
{ zoneName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
196
|
-
{ storeId: { $regex: inputData.searchValue, $options: 'i' } },
|
|
197
|
-
{ storeName: { $regex: inputData.searchValue, $options: 'i' } },
|
|
198
|
-
{ moduleType: { $regex: inputData.searchValue, $options: 'i' } },
|
|
199
|
-
{ auditStatus: { $regex: inputData.searchValue, $options: 'i' } },
|
|
200
|
-
],
|
|
201
|
-
|
|
202
|
-
},
|
|
203
|
-
} );
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if ( inputData.sortColumnName ) {
|
|
207
|
-
const sortBy = inputData.sortBy || -1;
|
|
208
|
-
query.push( {
|
|
209
|
-
$sort: { [inputData.sortColumName]: sortBy },
|
|
210
|
-
},
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
const count = await aggregateUserAudit( query );
|
|
214
|
-
if ( count.length == 0 ) {
|
|
215
|
-
return res.sendError( 'No Data Found', 204 );
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if ( inputData.isExport ) {
|
|
219
|
-
const chunkedMappingData = await chunkArray( count, 10 );
|
|
220
|
-
const promises = chunkedMappingData.map( async ( chunk ) => {
|
|
221
|
-
const exportData = [];
|
|
222
|
-
chunk.forEach( ( element ) => {
|
|
223
|
-
exportData.push( {
|
|
224
|
-
'Client Id': element.clientId,
|
|
225
|
-
'Client Name': element.clientName,
|
|
226
|
-
'Store Id': element.storeId,
|
|
227
|
-
'Store Name': element.storeName,
|
|
228
|
-
'Type': element.auditType,
|
|
229
|
-
'Before Count': element.beforeCount,
|
|
230
|
-
'After Count': element.afterCount,
|
|
231
|
-
'Accuracy': element.accuracy,
|
|
232
|
-
'Zone Name': element.zoneName,
|
|
233
|
-
'Audit Type': element.moduleType,
|
|
234
|
-
'Start Time': element.startTime,
|
|
235
|
-
'End Time': element.endTime,
|
|
236
|
-
'Time Spent': element.timeSpent,
|
|
237
|
-
'Audit Status': element.auditStatus,
|
|
238
|
-
'CreatedAt': dayjs( element.createdAt ).format( 'YYYY,MMM D' ),
|
|
239
|
-
|
|
240
|
-
} );
|
|
241
|
-
} );
|
|
242
|
-
return exportData;
|
|
243
|
-
} );
|
|
244
|
-
const mappedArrays = await Promise.all( promises );
|
|
245
|
-
mappedArrays.flat();
|
|
246
|
-
|
|
247
|
-
await download( mappedArrays, res );
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
query.push( {
|
|
252
|
-
$skip: offset,
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
$limit: limit,
|
|
256
|
-
} );
|
|
257
|
-
const result = await aggregateUserAudit( query );
|
|
258
|
-
|
|
259
|
-
return res.sendSuccess( { result: result, count: count.length } );
|
|
260
|
-
} catch ( error ) {
|
|
261
|
-
const err = error.message || 'Internal Server Error';
|
|
262
|
-
logger.info( { error: error, message: req.body, function: 'userAuditHistory' } );
|
|
263
|
-
return res.sendError( err, 500 );
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
14
|
|
|
267
15
|
export async function storeMetrics( req, res ) {
|
|
268
16
|
try {
|
package/src/docs/audit.docs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { auditStoreSchema, clientSchema, getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema, userSchema, workSpaceSchema } from '../dtos/audit.dtos.js';
|
|
1
|
+
import { auditStoreSchema, clientSchema, getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema, userAuditHistorySchema, userSchema, workSpaceSchema } from '../dtos/audit.dtos.js';
|
|
2
2
|
import j2s from 'joi-to-swagger';
|
|
3
3
|
|
|
4
4
|
export const auditDocs = {
|
|
@@ -91,6 +91,7 @@ export const auditDocs = {
|
|
|
91
91
|
},
|
|
92
92
|
},
|
|
93
93
|
|
|
94
|
+
/* < -- *** Audit Mapping *** --> */
|
|
94
95
|
'/v3/audit/get-file': {
|
|
95
96
|
get: {
|
|
96
97
|
tags: [ 'Audit Mapping' ],
|
|
@@ -239,6 +240,18 @@ export const auditDocs = {
|
|
|
239
240
|
scema: j2s( workSpaceSchema ).swagger,
|
|
240
241
|
require: false,
|
|
241
242
|
},
|
|
243
|
+
{
|
|
244
|
+
in: 'query',
|
|
245
|
+
name: 'sortColumnName',
|
|
246
|
+
scema: j2s( workSpaceSchema ).swagger,
|
|
247
|
+
require: false,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
in: 'query',
|
|
251
|
+
name: 'sortBy',
|
|
252
|
+
scema: j2s( workSpaceSchema ).swagger,
|
|
253
|
+
require: false,
|
|
254
|
+
},
|
|
242
255
|
],
|
|
243
256
|
responses: {
|
|
244
257
|
200: { description: 'Successful' },
|
|
@@ -249,5 +262,29 @@ export const auditDocs = {
|
|
|
249
262
|
},
|
|
250
263
|
},
|
|
251
264
|
},
|
|
265
|
+
/* < -- *** Audit Metrics *** --> */
|
|
266
|
+
|
|
267
|
+
'/v3/audit/metrics/user-audit-history': {
|
|
268
|
+
post: {
|
|
269
|
+
tags: [ 'Audit Metrics' ],
|
|
270
|
+
description: `Get list of user wise audit user details with date range`,
|
|
271
|
+
operationId: 'user-audit-history',
|
|
272
|
+
parameters: {},
|
|
273
|
+
requestBody: {
|
|
274
|
+
content: {
|
|
275
|
+
'application/json': {
|
|
276
|
+
schema: j2s( userAuditHistorySchema ).swagger,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
responses: {
|
|
281
|
+
200: { description: 'Successful' },
|
|
282
|
+
401: { description: 'Unauthorized User' },
|
|
283
|
+
422: { description: 'Field Error' },
|
|
284
|
+
500: { description: 'Server Error' },
|
|
285
|
+
204: { description: 'Not Found' },
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
252
289
|
|
|
253
290
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import j2s from 'joi-to-swagger';
|
|
2
|
-
import { auditImageValidSchema, clientMetricsSchema, getAuditImagesSchema, overAllAuditSummarySchema, overViewCardSchema, overViewTableSchema, reTriggerValidSchema, storeMetricsSchema, summarySplitSchema,
|
|
2
|
+
import { auditImageValidSchema, clientMetricsSchema, getAuditImagesSchema, overAllAuditSummarySchema, overViewCardSchema, overViewTableSchema, reTriggerValidSchema, storeMetricsSchema, summarySplitSchema, userMetricsSchema } from '../dtos/auditMetrics.dtos.js';
|
|
3
3
|
|
|
4
4
|
export const auditMetricsDocs = {
|
|
5
5
|
|
|
@@ -47,28 +47,7 @@ export const auditMetricsDocs = {
|
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
|
-
|
|
51
|
-
post: {
|
|
52
|
-
tags: [ 'Audit Metrics' ],
|
|
53
|
-
description: `Get list of user wise audit user details with date range`,
|
|
54
|
-
operationId: 'user-audit-history',
|
|
55
|
-
parameters: {},
|
|
56
|
-
requestBody: {
|
|
57
|
-
content: {
|
|
58
|
-
'application/json': {
|
|
59
|
-
schema: j2s( userAuditHistorySchema ).swagger,
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
responses: {
|
|
64
|
-
200: { description: 'Successful' },
|
|
65
|
-
401: { description: 'Unauthorized User' },
|
|
66
|
-
422: { description: 'Field Error' },
|
|
67
|
-
500: { description: 'Server Error' },
|
|
68
|
-
204: { description: 'Not Found' },
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
},
|
|
50
|
+
|
|
72
51
|
'/v3/audit-metrics/store-metrics': {
|
|
73
52
|
post: {
|
|
74
53
|
tags: [ 'Audit Metrics' ],
|
package/src/dtos/audit.dtos.js
CHANGED
|
@@ -125,12 +125,40 @@ export const workSpaceSchema = joi.object(
|
|
|
125
125
|
{
|
|
126
126
|
searchValue: joi.string().optional().allow( '' ),
|
|
127
127
|
moduleType: joi.string().required(),
|
|
128
|
-
offset: joi.
|
|
128
|
+
offset: joi.number().optional(),
|
|
129
129
|
limit: joi.number().optional(),
|
|
130
130
|
isExport: joi.boolean().optional(),
|
|
131
|
+
sortColumnName: joi.string().optional(),
|
|
132
|
+
sortBy: joi.number().optional(),
|
|
131
133
|
},
|
|
132
134
|
);
|
|
133
135
|
|
|
134
136
|
export const workSpaceValid = {
|
|
135
137
|
query: workSpaceSchema,
|
|
136
138
|
};
|
|
139
|
+
|
|
140
|
+
/* < -- *** Audit Metrics *** --> */
|
|
141
|
+
|
|
142
|
+
export const userAuditHistorySchema = joi.object(
|
|
143
|
+
{
|
|
144
|
+
userId: joi.string().optional(),
|
|
145
|
+
fromDate: joi.string().required(),
|
|
146
|
+
toDate: joi.string().required(),
|
|
147
|
+
dateType: joi.string().required(),
|
|
148
|
+
filterByStoreId: joi.array().required(),
|
|
149
|
+
filterByModuleType: joi.array().optional(),
|
|
150
|
+
filterByAuditType: joi.array().optional(),
|
|
151
|
+
filterByStatus: joi.array().optional(),
|
|
152
|
+
searchValue: joi.string().optional().allow( '' ),
|
|
153
|
+
limit: joi.number().optional(),
|
|
154
|
+
offset: joi.number().optional(),
|
|
155
|
+
sortColumnName: joi.string().optional(),
|
|
156
|
+
sortBy: joi.number().optional(),
|
|
157
|
+
isExport: joi.boolean().optional(),
|
|
158
|
+
|
|
159
|
+
},
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
export const userAuditHistoryValid = {
|
|
163
|
+
body: userAuditHistorySchema,
|
|
164
|
+
};
|
|
@@ -13,29 +13,6 @@ export const getAuditImagesValid = {
|
|
|
13
13
|
body: getAuditImagesSchema,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const userAuditHistorySchema = joi.object(
|
|
17
|
-
{
|
|
18
|
-
userId: joi.string().optional(),
|
|
19
|
-
fromDate: joi.string().required(),
|
|
20
|
-
toDate: joi.string().required(),
|
|
21
|
-
fileType: joi.string().required(),
|
|
22
|
-
filterByStoreId: joi.array().required(),
|
|
23
|
-
filterByType: joi.array().optional(),
|
|
24
|
-
filterByAuditType: joi.array().optional(),
|
|
25
|
-
filterByStatus: joi.array().optional(),
|
|
26
|
-
searchValue: joi.string().optional().allow( '' ),
|
|
27
|
-
limit: joi.number().optional(),
|
|
28
|
-
offset: joi.number().optional(),
|
|
29
|
-
sortColumnName: joi.string().optional(),
|
|
30
|
-
sortBy: joi.number().optional(),
|
|
31
|
-
isExport: joi.boolean().optional(),
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
export const userAuditHistoryValid = {
|
|
37
|
-
body: userAuditHistorySchema,
|
|
38
|
-
};
|
|
39
16
|
|
|
40
17
|
export const storeMetricsSchema = joi.object(
|
|
41
18
|
{
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { isExistsQueue, validateUserAudit } from '../validation/audit.validation.js';
|
|
3
3
|
import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
4
|
-
import { auditStoreList, auditUserList, clients, getAuditFile, getDraftedData, save, saveDraft, workSpace } from '../controllers/audit.controllers.js';
|
|
5
|
-
import { auditStoreValid, clientValid, getDraftedDataValid, getFileValid, saveDraftValid, saveValid, workSpaceValid } from '../dtos/audit.dtos.js';
|
|
4
|
+
import { auditStoreList, auditUserList, clients, getAuditFile, getDraftedData, save, saveDraft, userAuditHistory, workSpace } from '../controllers/audit.controllers.js';
|
|
5
|
+
import { auditStoreValid, clientValid, getDraftedDataValid, getFileValid, saveDraftValid, saveValid, userAuditHistoryValid, workSpaceValid } from '../dtos/audit.dtos.js';
|
|
6
6
|
|
|
7
7
|
export const auditRouter = express.Router();
|
|
8
8
|
|
|
@@ -19,4 +19,8 @@ auditRouter.get( '/get-drafted-data', isAllowedSessionHandler, validate( getDraf
|
|
|
19
19
|
auditRouter.post( '/save', isAllowedSessionHandler, validate( saveValid ), validateUserAudit, save );
|
|
20
20
|
auditRouter.get( '/work-space', isAllowedSessionHandler, validate( workSpaceValid ), workSpace );
|
|
21
21
|
|
|
22
|
+
// Audit Metrics
|
|
23
|
+
auditRouter.post( '/metrics/user-audit-history', isAllowedSessionHandler, validate( userAuditHistoryValid ), userAuditHistory );
|
|
24
|
+
|
|
25
|
+
|
|
22
26
|
export default auditRouter;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
import express from 'express';
|
|
3
3
|
import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
4
|
-
import { auditImages, clientMetrics, overAllAuditSummary, overViewCard, overViewTable, reTrigger, storeMetrics, summarySplit,
|
|
5
|
-
import { auditImageValid, clientMetricsValid, overAllAuditSummaryValid, overViewCardValid, overViewTableValid, reTriggerValid, storeMetricsValid, summarySplitValid,
|
|
4
|
+
import { auditImages, clientMetrics, overAllAuditSummary, overViewCard, overViewTable, reTrigger, storeMetrics, summarySplit, userMetrics } from '../controllers/auditMetrics.controllers.js';
|
|
5
|
+
import { auditImageValid, clientMetricsValid, overAllAuditSummaryValid, overViewCardValid, overViewTableValid, reTriggerValid, storeMetricsValid, summarySplitValid, userMetricsValid, viewLogValid } from '../dtos/auditMetrics.dtos.js';
|
|
6
6
|
import { isAuditDocumentExist, isAuditInputFolderExist } from '../validation/audit.validation.js';
|
|
7
7
|
|
|
8
8
|
export const auditMetricsRouter = express.Router();
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
auditMetricsRouter.post( '/store-metrics', isAllowedSessionHandler, validate( storeMetricsValid ), storeMetrics );
|
|
12
12
|
auditMetricsRouter.post( '/client-metrics', isAllowedSessionHandler, validate( clientMetricsValid ), clientMetrics );
|
|
13
13
|
auditMetricsRouter.post( '/user-metrics', isAllowedSessionHandler, validate( userMetricsValid ), userMetrics );
|