@7365admin1/core 2.15.0 → 2.16.0
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/CHANGELOG.md +6 -0
- package/dist/index.d.ts +18 -5
- package/dist/index.js +548 -218
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +548 -218
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -10906,7 +10906,7 @@ function useFeedbackController() {
|
|
|
10906
10906
|
}
|
|
10907
10907
|
async function deleteFeedback(req, res, next) {
|
|
10908
10908
|
const validation = Joi28.string().hex().required();
|
|
10909
|
-
const _id = req.
|
|
10909
|
+
const _id = req.params.id;
|
|
10910
10910
|
const { error } = validation.validate(_id);
|
|
10911
10911
|
if (error) {
|
|
10912
10912
|
logger39.log({ level: "error", message: error.message });
|
|
@@ -11270,8 +11270,7 @@ function useWorkOrderController() {
|
|
|
11270
11270
|
}
|
|
11271
11271
|
async function deleteWorkOrder(req, res, next) {
|
|
11272
11272
|
const validation = Joi29.string().hex().required();
|
|
11273
|
-
const _id = req.
|
|
11274
|
-
console.log(_id);
|
|
11273
|
+
const _id = req.params.id;
|
|
11275
11274
|
const { error } = validation.validate(_id);
|
|
11276
11275
|
if (error) {
|
|
11277
11276
|
logger40.log({ level: "error", message: error.message });
|
|
@@ -15071,11 +15070,14 @@ function usePersonRepo() {
|
|
|
15071
15070
|
const namespace_collection = "site.people";
|
|
15072
15071
|
const collection = db.collection(namespace_collection);
|
|
15073
15072
|
const { delNamespace, getCache, setCache } = useCache27(namespace_collection);
|
|
15074
|
-
async function
|
|
15073
|
+
async function createIndexes() {
|
|
15075
15074
|
try {
|
|
15076
|
-
await collection.
|
|
15075
|
+
await collection.createIndexes([
|
|
15076
|
+
{ key: { contact: 1 } },
|
|
15077
|
+
{ key: { nric: 1 } }
|
|
15078
|
+
]);
|
|
15077
15079
|
} catch (error) {
|
|
15078
|
-
throw new InternalServerError27("Failed to create index.");
|
|
15080
|
+
throw new InternalServerError27("Failed to create index on site people.");
|
|
15079
15081
|
}
|
|
15080
15082
|
}
|
|
15081
15083
|
async function createTextIndex() {
|
|
@@ -15465,6 +15467,47 @@ function usePersonRepo() {
|
|
|
15465
15467
|
throw new InternalServerError27("Failed to fetch people by plate number.");
|
|
15466
15468
|
}
|
|
15467
15469
|
}
|
|
15470
|
+
async function getPeopleByNRIC({
|
|
15471
|
+
page = 1,
|
|
15472
|
+
limit = 10,
|
|
15473
|
+
nric = "",
|
|
15474
|
+
sort = {},
|
|
15475
|
+
site = ""
|
|
15476
|
+
}) {
|
|
15477
|
+
page = page > 0 ? page - 1 : 0;
|
|
15478
|
+
const normalizedNric = nric.trim();
|
|
15479
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15480
|
+
const query = {
|
|
15481
|
+
...nric && { nric: normalizedNric },
|
|
15482
|
+
site: typeof site === "string" ? new ObjectId44(site) : site
|
|
15483
|
+
};
|
|
15484
|
+
const cacheOptions = {
|
|
15485
|
+
site,
|
|
15486
|
+
...nric && { nric: normalizedNric },
|
|
15487
|
+
page: String(page),
|
|
15488
|
+
limit: String(limit),
|
|
15489
|
+
sort: JSON.stringify(sort)
|
|
15490
|
+
};
|
|
15491
|
+
try {
|
|
15492
|
+
const cacheKey = makeCacheKey25(namespace_collection, cacheOptions);
|
|
15493
|
+
const cachedData = await getCache(cacheKey);
|
|
15494
|
+
if (cachedData) {
|
|
15495
|
+
logger60.info(`Cache hit for key: ${cacheKey}`);
|
|
15496
|
+
return cachedData;
|
|
15497
|
+
}
|
|
15498
|
+
const items = await collection.find(query).sort(sort).skip(page * limit).limit(limit).toArray();
|
|
15499
|
+
const length = await collection.countDocuments(query);
|
|
15500
|
+
const data = paginate20(items, page, limit, length);
|
|
15501
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
15502
|
+
logger60.info(`Cache set for key: ${cacheKey}`);
|
|
15503
|
+
}).catch((err) => {
|
|
15504
|
+
logger60.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
15505
|
+
});
|
|
15506
|
+
return data;
|
|
15507
|
+
} catch (error) {
|
|
15508
|
+
throw new InternalServerError27("Failed to retrieve person by NRIC.");
|
|
15509
|
+
}
|
|
15510
|
+
}
|
|
15468
15511
|
return {
|
|
15469
15512
|
add,
|
|
15470
15513
|
getAll,
|
|
@@ -15474,11 +15517,12 @@ function usePersonRepo() {
|
|
|
15474
15517
|
createTextIndex,
|
|
15475
15518
|
getPersonByPlateNumber,
|
|
15476
15519
|
getByNRIC,
|
|
15477
|
-
|
|
15520
|
+
createIndexes,
|
|
15478
15521
|
getPersonByPhoneNumber,
|
|
15479
15522
|
getPeopleByUnit,
|
|
15480
15523
|
getCompany,
|
|
15481
|
-
getPeopleByPlateNumber
|
|
15524
|
+
getPeopleByPlateNumber,
|
|
15525
|
+
getPeopleByNRIC
|
|
15482
15526
|
};
|
|
15483
15527
|
}
|
|
15484
15528
|
|
|
@@ -15527,7 +15571,15 @@ var ANPRMode = /* @__PURE__ */ ((ANPRMode2) => {
|
|
|
15527
15571
|
return ANPRMode2;
|
|
15528
15572
|
})(ANPRMode || {});
|
|
15529
15573
|
var vehicleSchema = Joi43.object({
|
|
15530
|
-
plateNumber: Joi43.
|
|
15574
|
+
plateNumber: Joi43.alternatives().try(
|
|
15575
|
+
Joi43.array().items(Joi43.string().trim().min(1)).min(1),
|
|
15576
|
+
Joi43.string().trim().min(1)
|
|
15577
|
+
).custom((value) => {
|
|
15578
|
+
if (typeof value === "string") {
|
|
15579
|
+
return value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
15580
|
+
}
|
|
15581
|
+
return value;
|
|
15582
|
+
}).required(),
|
|
15531
15583
|
type: Joi43.string().required().valid(...Object.values(VehicleType)),
|
|
15532
15584
|
category: Joi43.string().required().valid(...Object.values(VehicleCategory)),
|
|
15533
15585
|
name: Joi43.string().required(),
|
|
@@ -15661,19 +15713,9 @@ function useVehicleRepo() {
|
|
|
15661
15713
|
await collection.createIndexes([
|
|
15662
15714
|
{ key: { status: 1 } },
|
|
15663
15715
|
{ key: { type: 1 } },
|
|
15664
|
-
{ key: { category: 1 } }
|
|
15665
|
-
{
|
|
15666
|
-
key: { nric: 1 },
|
|
15667
|
-
name: "uniq_nric_not_deleted_nonempty",
|
|
15668
|
-
unique: true,
|
|
15669
|
-
partialFilterExpression: {
|
|
15670
|
-
nric: { $type: "string", $gt: "" },
|
|
15671
|
-
deletedAt: ""
|
|
15672
|
-
}
|
|
15673
|
-
}
|
|
15716
|
+
{ key: { category: 1 } }
|
|
15674
15717
|
]);
|
|
15675
15718
|
} catch (error) {
|
|
15676
|
-
console.error("createIndexes error:", error);
|
|
15677
15719
|
throw new InternalServerError28("Failed to create index on vehicle.");
|
|
15678
15720
|
}
|
|
15679
15721
|
}
|
|
@@ -15731,14 +15773,14 @@ function useVehicleRepo() {
|
|
|
15731
15773
|
const baseQuery = {
|
|
15732
15774
|
...status && { status },
|
|
15733
15775
|
...type && { type },
|
|
15734
|
-
...
|
|
15776
|
+
...category && { category }
|
|
15735
15777
|
};
|
|
15736
15778
|
let query = { ...baseQuery };
|
|
15737
15779
|
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15738
15780
|
const cacheOptions = {
|
|
15739
15781
|
...status && { status },
|
|
15740
15782
|
...type && { type },
|
|
15741
|
-
...
|
|
15783
|
+
...category && { category },
|
|
15742
15784
|
page: String(page),
|
|
15743
15785
|
limit: String(limit),
|
|
15744
15786
|
sort: JSON.stringify(sort)
|
|
@@ -15754,47 +15796,130 @@ function useVehicleRepo() {
|
|
|
15754
15796
|
return cachedData;
|
|
15755
15797
|
}
|
|
15756
15798
|
const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15799
|
+
const buildGroupedPipeline = (matchQuery) => [
|
|
15800
|
+
{ $match: matchQuery },
|
|
15801
|
+
{
|
|
15802
|
+
$lookup: {
|
|
15803
|
+
from: "building-units",
|
|
15804
|
+
localField: "unit",
|
|
15805
|
+
foreignField: "_id",
|
|
15806
|
+
as: "units",
|
|
15807
|
+
pipeline: [{ $project: { name: 1 } }]
|
|
15808
|
+
}
|
|
15809
|
+
},
|
|
15810
|
+
{ $unwind: { path: "$units", preserveNullAndEmptyArrays: true } },
|
|
15811
|
+
{
|
|
15812
|
+
$project: {
|
|
15813
|
+
_id: 1,
|
|
15814
|
+
name: 1,
|
|
15815
|
+
type: 1,
|
|
15816
|
+
category: 1,
|
|
15817
|
+
status: 1,
|
|
15818
|
+
phoneNumber: 1,
|
|
15819
|
+
block: 1,
|
|
15820
|
+
level: 1,
|
|
15821
|
+
unit: "$units.name",
|
|
15822
|
+
recNo: 1,
|
|
15823
|
+
nric: 1,
|
|
15824
|
+
plateNumber: 1
|
|
15825
|
+
}
|
|
15826
|
+
},
|
|
15827
|
+
{
|
|
15828
|
+
$group: {
|
|
15829
|
+
_id: {
|
|
15830
|
+
$cond: [
|
|
15831
|
+
{
|
|
15832
|
+
$and: [{ $ne: ["$nric", null] }, { $ne: ["$nric", ""] }]
|
|
15833
|
+
},
|
|
15834
|
+
{
|
|
15835
|
+
nric: "$nric",
|
|
15836
|
+
block: "$block",
|
|
15837
|
+
level: "$level",
|
|
15838
|
+
unit: "$unit"
|
|
15839
|
+
},
|
|
15840
|
+
"$_id"
|
|
15841
|
+
]
|
|
15842
|
+
},
|
|
15843
|
+
vehicleId: { $first: "$_id" },
|
|
15844
|
+
name: { $first: "$name" },
|
|
15845
|
+
category: { $first: "$category" },
|
|
15846
|
+
phoneNumber: { $first: "$phoneNumber" },
|
|
15847
|
+
block: { $first: "$block" },
|
|
15848
|
+
level: { $first: "$level" },
|
|
15849
|
+
unit: { $first: "$unit" },
|
|
15850
|
+
nric: { $first: "$nric" },
|
|
15851
|
+
plates: {
|
|
15852
|
+
$addToSet: {
|
|
15853
|
+
plateNumber: "$plateNumber",
|
|
15854
|
+
recNo: "$recNo",
|
|
15855
|
+
status: "$status",
|
|
15856
|
+
type: "$type"
|
|
15857
|
+
}
|
|
15772
15858
|
}
|
|
15773
|
-
}
|
|
15774
|
-
|
|
15775
|
-
|
|
15776
|
-
|
|
15777
|
-
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
15859
|
+
}
|
|
15860
|
+
},
|
|
15861
|
+
{
|
|
15862
|
+
$project: {
|
|
15863
|
+
_id: "$vehicleId",
|
|
15864
|
+
name: 1,
|
|
15865
|
+
type: 1,
|
|
15866
|
+
category: 1,
|
|
15867
|
+
status: 1,
|
|
15868
|
+
phoneNumber: 1,
|
|
15869
|
+
block: 1,
|
|
15870
|
+
level: 1,
|
|
15871
|
+
unit: 1,
|
|
15872
|
+
nric: 1,
|
|
15873
|
+
plates: {
|
|
15874
|
+
$filter: {
|
|
15875
|
+
input: "$plates",
|
|
15876
|
+
as: "plate",
|
|
15877
|
+
cond: {
|
|
15878
|
+
$and: [
|
|
15879
|
+
{ $ne: ["$$plate.plateNumber", null] },
|
|
15880
|
+
{ $ne: ["$$plate.plateNumber", ""] }
|
|
15881
|
+
]
|
|
15882
|
+
}
|
|
15883
|
+
}
|
|
15788
15884
|
}
|
|
15789
15885
|
}
|
|
15790
|
-
|
|
15791
|
-
|
|
15886
|
+
},
|
|
15887
|
+
{ $sort: sort },
|
|
15888
|
+
{ $skip: page * limit },
|
|
15889
|
+
{ $limit: limit }
|
|
15890
|
+
];
|
|
15891
|
+
const buildGroupedCountPipeline = (matchQuery) => [
|
|
15892
|
+
{ $match: matchQuery },
|
|
15893
|
+
{
|
|
15894
|
+
$group: {
|
|
15895
|
+
_id: {
|
|
15896
|
+
$cond: [
|
|
15897
|
+
{
|
|
15898
|
+
$and: [{ $ne: ["$nric", null] }, { $ne: ["$nric", ""] }]
|
|
15899
|
+
},
|
|
15900
|
+
{
|
|
15901
|
+
nric: "$nric",
|
|
15902
|
+
block: "$block",
|
|
15903
|
+
level: "$level",
|
|
15904
|
+
unit: "$unit"
|
|
15905
|
+
},
|
|
15906
|
+
"$_id"
|
|
15907
|
+
]
|
|
15908
|
+
}
|
|
15909
|
+
}
|
|
15910
|
+
},
|
|
15911
|
+
{ $count: "total" }
|
|
15912
|
+
];
|
|
15913
|
+
try {
|
|
15914
|
+
let items = [];
|
|
15915
|
+
let length = 0;
|
|
15916
|
+
items = await collection.aggregate(buildGroupedPipeline(query)).toArray();
|
|
15917
|
+
const countResult = await collection.aggregate(buildGroupedCountPipeline(query)).toArray();
|
|
15918
|
+
length = countResult[0]?.total || 0;
|
|
15792
15919
|
if ((!items || items.length === 0) && search) {
|
|
15793
15920
|
const escaped = escapeRegex(search);
|
|
15794
15921
|
const regexQuery = {
|
|
15795
15922
|
...baseQuery,
|
|
15796
|
-
...type && { type },
|
|
15797
|
-
...category && { category },
|
|
15798
15923
|
$or: [
|
|
15799
15924
|
{ name: { $regex: escaped, $options: "i" } },
|
|
15800
15925
|
{ plateNumber: { $regex: escaped, $options: "i" } },
|
|
@@ -15805,38 +15930,9 @@ function useVehicleRepo() {
|
|
|
15805
15930
|
{ nric: { $regex: escaped, $options: "i" } }
|
|
15806
15931
|
]
|
|
15807
15932
|
};
|
|
15808
|
-
items = await collection.aggregate(
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
{ $skip: page * limit },
|
|
15812
|
-
{ $limit: limit },
|
|
15813
|
-
{
|
|
15814
|
-
$lookup: {
|
|
15815
|
-
from: "building-units",
|
|
15816
|
-
localField: "unit",
|
|
15817
|
-
foreignField: "_id",
|
|
15818
|
-
as: "units",
|
|
15819
|
-
pipeline: [{ $project: { name: 1 } }]
|
|
15820
|
-
}
|
|
15821
|
-
},
|
|
15822
|
-
{ $unwind: { path: "$units", preserveNullAndEmptyArrays: true } },
|
|
15823
|
-
{
|
|
15824
|
-
$project: {
|
|
15825
|
-
name: 1,
|
|
15826
|
-
type: 1,
|
|
15827
|
-
category: 1,
|
|
15828
|
-
status: 1,
|
|
15829
|
-
phoneNumber: 1,
|
|
15830
|
-
block: 1,
|
|
15831
|
-
level: 1,
|
|
15832
|
-
unit: "$units.name",
|
|
15833
|
-
plateNumber: 1,
|
|
15834
|
-
recNo: 1,
|
|
15835
|
-
nric: 1
|
|
15836
|
-
}
|
|
15837
|
-
}
|
|
15838
|
-
]).toArray();
|
|
15839
|
-
length = await collection.countDocuments(regexQuery);
|
|
15933
|
+
items = await collection.aggregate(buildGroupedPipeline(regexQuery)).toArray();
|
|
15934
|
+
const regexCountResult = await collection.aggregate(buildGroupedCountPipeline(regexQuery)).toArray();
|
|
15935
|
+
length = regexCountResult[0]?.total || 0;
|
|
15840
15936
|
}
|
|
15841
15937
|
const data = paginate21(items, page, limit, length);
|
|
15842
15938
|
setCache(cacheKey, data, 15 * 60).then(() => logger62.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
@@ -15914,43 +16010,176 @@ function useVehicleRepo() {
|
|
|
15914
16010
|
}
|
|
15915
16011
|
const data = await collection.aggregate([
|
|
15916
16012
|
{ $match: { _id } },
|
|
16013
|
+
{ $limit: 1 },
|
|
16014
|
+
{
|
|
16015
|
+
$project: {
|
|
16016
|
+
_id: 1,
|
|
16017
|
+
nric: 1,
|
|
16018
|
+
block: 1,
|
|
16019
|
+
level: 1,
|
|
16020
|
+
unit: 1
|
|
16021
|
+
}
|
|
16022
|
+
},
|
|
15917
16023
|
{
|
|
15918
16024
|
$lookup: {
|
|
15919
|
-
from:
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
16025
|
+
from: collection.collectionName,
|
|
16026
|
+
let: {
|
|
16027
|
+
vehicleId: "$_id",
|
|
16028
|
+
vehicleNric: "$nric",
|
|
16029
|
+
vehicleBlock: "$block",
|
|
16030
|
+
vehicleLevel: "$level",
|
|
16031
|
+
vehicleUnit: "$unit"
|
|
16032
|
+
},
|
|
16033
|
+
pipeline: [
|
|
16034
|
+
{
|
|
16035
|
+
$match: {
|
|
16036
|
+
$expr: {
|
|
16037
|
+
$cond: [
|
|
16038
|
+
{
|
|
16039
|
+
$and: [
|
|
16040
|
+
{ $ne: ["$$vehicleNric", null] },
|
|
16041
|
+
{ $ne: ["$$vehicleNric", ""] }
|
|
16042
|
+
]
|
|
16043
|
+
},
|
|
16044
|
+
{
|
|
16045
|
+
$and: [
|
|
16046
|
+
{ $eq: ["$nric", "$$vehicleNric"] },
|
|
16047
|
+
{ $eq: ["$block", "$$vehicleBlock"] },
|
|
16048
|
+
{ $eq: ["$level", "$$vehicleLevel"] },
|
|
16049
|
+
{ $eq: ["$unit", "$$vehicleUnit"] }
|
|
16050
|
+
]
|
|
16051
|
+
},
|
|
16052
|
+
{ $eq: ["$_id", "$$vehicleId"] }
|
|
16053
|
+
]
|
|
16054
|
+
}
|
|
16055
|
+
}
|
|
16056
|
+
},
|
|
16057
|
+
{
|
|
16058
|
+
$lookup: {
|
|
16059
|
+
from: "building-units",
|
|
16060
|
+
localField: "unit",
|
|
16061
|
+
foreignField: "_id",
|
|
16062
|
+
as: "units",
|
|
16063
|
+
pipeline: [{ $project: { name: 1 } }]
|
|
16064
|
+
}
|
|
16065
|
+
},
|
|
16066
|
+
{
|
|
16067
|
+
$unwind: { path: "$units", preserveNullAndEmptyArrays: true }
|
|
16068
|
+
},
|
|
16069
|
+
{
|
|
16070
|
+
$project: {
|
|
16071
|
+
_id: 1,
|
|
16072
|
+
name: 1,
|
|
16073
|
+
phoneNumber: 1,
|
|
16074
|
+
plateNumber: 1,
|
|
16075
|
+
nric: 1,
|
|
16076
|
+
block: 1,
|
|
16077
|
+
level: 1,
|
|
16078
|
+
rawUnit: "$unit",
|
|
16079
|
+
unit: "$units.name",
|
|
16080
|
+
type: 1,
|
|
16081
|
+
category: 1,
|
|
16082
|
+
status: 1,
|
|
16083
|
+
recNo: 1,
|
|
16084
|
+
start: 1,
|
|
16085
|
+
end: 1,
|
|
16086
|
+
seasonPassType: 1
|
|
16087
|
+
}
|
|
16088
|
+
},
|
|
16089
|
+
{
|
|
16090
|
+
$group: {
|
|
16091
|
+
_id: {
|
|
16092
|
+
$cond: [
|
|
16093
|
+
{
|
|
16094
|
+
$and: [
|
|
16095
|
+
{ $ne: ["$nric", null] },
|
|
16096
|
+
{ $ne: ["$nric", ""] }
|
|
16097
|
+
]
|
|
16098
|
+
},
|
|
16099
|
+
{
|
|
16100
|
+
nric: "$nric",
|
|
16101
|
+
block: "$block",
|
|
16102
|
+
level: "$level",
|
|
16103
|
+
unit: "$unit"
|
|
16104
|
+
},
|
|
16105
|
+
"$_id"
|
|
16106
|
+
]
|
|
16107
|
+
},
|
|
16108
|
+
vehicleId: { $first: "$_id" },
|
|
16109
|
+
name: { $first: "$name" },
|
|
16110
|
+
category: { $first: "$category" },
|
|
16111
|
+
phoneNumber: { $first: "$phoneNumber" },
|
|
16112
|
+
block: { $first: "$block" },
|
|
16113
|
+
level: { $first: "$level" },
|
|
16114
|
+
unit: { $first: "$unit" },
|
|
16115
|
+
nric: { $first: "$nric" },
|
|
16116
|
+
start: { $first: "$start" },
|
|
16117
|
+
end: { $first: "$end" },
|
|
16118
|
+
seasonPassType: { $first: "$seasonPassType" },
|
|
16119
|
+
plates: {
|
|
16120
|
+
$addToSet: {
|
|
16121
|
+
plateNumber: "$plateNumber",
|
|
16122
|
+
recNo: "$recNo",
|
|
16123
|
+
status: "$status",
|
|
16124
|
+
type: "$type"
|
|
16125
|
+
}
|
|
16126
|
+
}
|
|
16127
|
+
}
|
|
16128
|
+
},
|
|
16129
|
+
{
|
|
16130
|
+
$project: {
|
|
16131
|
+
_id: "$vehicleId",
|
|
16132
|
+
name: 1,
|
|
16133
|
+
phoneNumber: 1,
|
|
16134
|
+
nric: 1,
|
|
16135
|
+
block: 1,
|
|
16136
|
+
level: 1,
|
|
16137
|
+
unit: 1,
|
|
16138
|
+
type: 1,
|
|
16139
|
+
category: 1,
|
|
16140
|
+
status: 1,
|
|
16141
|
+
start: 1,
|
|
16142
|
+
end: 1,
|
|
16143
|
+
seasonPassType: 1,
|
|
16144
|
+
plates: {
|
|
16145
|
+
$filter: {
|
|
16146
|
+
input: "$plates",
|
|
16147
|
+
as: "plate",
|
|
16148
|
+
cond: {
|
|
16149
|
+
$and: [
|
|
16150
|
+
{ $ne: ["$$plate.plateNumber", null] },
|
|
16151
|
+
{ $ne: ["$$plate.plateNumber", ""] }
|
|
16152
|
+
]
|
|
16153
|
+
}
|
|
16154
|
+
}
|
|
16155
|
+
}
|
|
16156
|
+
}
|
|
16157
|
+
}
|
|
16158
|
+
],
|
|
16159
|
+
as: "vehicle"
|
|
15924
16160
|
}
|
|
15925
16161
|
},
|
|
15926
|
-
{ $unwind: { path: "$units", preserveNullAndEmptyArrays: true } },
|
|
15927
16162
|
{
|
|
15928
16163
|
$project: {
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
type: 1,
|
|
15936
|
-
category: 1,
|
|
15937
|
-
status: 1,
|
|
15938
|
-
recNo: 1,
|
|
15939
|
-
start: 1,
|
|
15940
|
-
end: 1,
|
|
15941
|
-
seasonPassType: 1
|
|
16164
|
+
vehicle: { $arrayElemAt: ["$vehicle", 0] }
|
|
16165
|
+
}
|
|
16166
|
+
},
|
|
16167
|
+
{
|
|
16168
|
+
$replaceRoot: {
|
|
16169
|
+
newRoot: "$vehicle"
|
|
15942
16170
|
}
|
|
15943
16171
|
}
|
|
15944
16172
|
]).toArray();
|
|
15945
16173
|
if (!data || !data.length) {
|
|
15946
16174
|
throw new NotFoundError19("Vehicle not found.");
|
|
15947
16175
|
}
|
|
15948
|
-
|
|
16176
|
+
const result = data[0];
|
|
16177
|
+
setCache(cacheKey, result, 15 * 60).then(() => {
|
|
15949
16178
|
logger62.info(`Cache set for key: ${cacheKey}`);
|
|
15950
16179
|
}).catch((err) => {
|
|
15951
16180
|
logger62.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
15952
16181
|
});
|
|
15953
|
-
return
|
|
16182
|
+
return result;
|
|
15954
16183
|
} catch (error) {
|
|
15955
16184
|
throw error;
|
|
15956
16185
|
}
|
|
@@ -16084,36 +16313,34 @@ function useVehicleRepo() {
|
|
|
16084
16313
|
async function getVehiclesByNRIC({
|
|
16085
16314
|
page = 1,
|
|
16086
16315
|
limit = 10,
|
|
16087
|
-
|
|
16316
|
+
nric = "",
|
|
16088
16317
|
sort = {}
|
|
16089
16318
|
}) {
|
|
16090
16319
|
page = page > 0 ? page - 1 : 0;
|
|
16091
|
-
|
|
16092
|
-
|
|
16320
|
+
if (!nric) {
|
|
16321
|
+
throw new BadRequestError78("NRIC is required.");
|
|
16322
|
+
}
|
|
16323
|
+
const _nric = nric.trim();
|
|
16324
|
+
const query = {
|
|
16325
|
+
deletedAt: "",
|
|
16326
|
+
nric: _nric
|
|
16093
16327
|
};
|
|
16094
|
-
let query = { ...baseQuery };
|
|
16095
16328
|
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
16096
16329
|
const cacheOptions = {
|
|
16097
16330
|
deletedAt: "",
|
|
16331
|
+
nric: _nric,
|
|
16098
16332
|
page: String(page),
|
|
16099
16333
|
limit: String(limit),
|
|
16100
16334
|
sort: JSON.stringify(sort)
|
|
16101
16335
|
};
|
|
16102
|
-
if (search) {
|
|
16103
|
-
query.$text = { $search: search };
|
|
16104
|
-
cacheOptions.search = search;
|
|
16105
|
-
}
|
|
16106
16336
|
const cacheKey = makeCacheKey26(namespace_collection, cacheOptions);
|
|
16107
16337
|
const cachedData = await getCache(cacheKey);
|
|
16108
16338
|
if (cachedData) {
|
|
16109
16339
|
logger62.info(`Cache hit for key: ${cacheKey}`);
|
|
16110
16340
|
return cachedData;
|
|
16111
16341
|
}
|
|
16112
|
-
const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16113
16342
|
try {
|
|
16114
|
-
|
|
16115
|
-
let length = 0;
|
|
16116
|
-
items = await collection.aggregate([
|
|
16343
|
+
const items = await collection.aggregate([
|
|
16117
16344
|
{ $match: query },
|
|
16118
16345
|
{ $sort: sort },
|
|
16119
16346
|
{ $skip: page * limit },
|
|
@@ -16130,37 +16357,7 @@ function useVehicleRepo() {
|
|
|
16130
16357
|
}
|
|
16131
16358
|
}
|
|
16132
16359
|
]).toArray();
|
|
16133
|
-
length = await collection.countDocuments(query);
|
|
16134
|
-
if ((!items || items.length === 0) && search) {
|
|
16135
|
-
const escaped = escapeRegex(search);
|
|
16136
|
-
const regexQuery = {
|
|
16137
|
-
...baseQuery,
|
|
16138
|
-
$or: [
|
|
16139
|
-
{ name: { $regex: escaped, $options: "i" } },
|
|
16140
|
-
{ plateNumber: { $regex: escaped, $options: "i" } },
|
|
16141
|
-
{ level: { $regex: escaped, $options: "i" } },
|
|
16142
|
-
{ nric: { $regex: escaped, $options: "i" } }
|
|
16143
|
-
]
|
|
16144
|
-
};
|
|
16145
|
-
items = await collection.aggregate([
|
|
16146
|
-
{ $match: regexQuery },
|
|
16147
|
-
{ $sort: sort },
|
|
16148
|
-
{ $skip: page * limit },
|
|
16149
|
-
{ $limit: limit },
|
|
16150
|
-
{
|
|
16151
|
-
$project: {
|
|
16152
|
-
name: 1,
|
|
16153
|
-
phoneNumber: 1,
|
|
16154
|
-
plateNumber: 1,
|
|
16155
|
-
recNo: 1,
|
|
16156
|
-
nric: 1,
|
|
16157
|
-
status: 1,
|
|
16158
|
-
type: 1
|
|
16159
|
-
}
|
|
16160
|
-
}
|
|
16161
|
-
]).toArray();
|
|
16162
|
-
length = await collection.countDocuments(regexQuery);
|
|
16163
|
-
}
|
|
16360
|
+
const length = await collection.countDocuments(query);
|
|
16164
16361
|
const data = paginate21(items, page, limit, length);
|
|
16165
16362
|
setCache(cacheKey, data, 15 * 60).then(() => logger62.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
16166
16363
|
(err) => logger62.error(`Failed to set cache for key: ${cacheKey}`, err)
|
|
@@ -16620,7 +16817,7 @@ function useDahuaService() {
|
|
|
16620
16817
|
host: value.host,
|
|
16621
16818
|
username: value.username,
|
|
16622
16819
|
password: value.password,
|
|
16623
|
-
endpoint: `/cgi-bin/recordUpdater.cgi?action=insert&name=${value.mode}&PlateNumber=${value.plateNumber}&BeginTime=${value.start}&CancelTime=${value.end}
|
|
16820
|
+
endpoint: `/cgi-bin/recordUpdater.cgi?action=insert&name=${value.mode}&PlateNumber=${value.plateNumber}&BeginTime=${value.start}&CancelTime=${value.end}&+OpenGate=true&MasterOfCar=${value.owner}`
|
|
16624
16821
|
});
|
|
16625
16822
|
return response;
|
|
16626
16823
|
} catch (error2) {
|
|
@@ -16692,8 +16889,9 @@ function useVehicleService() {
|
|
|
16692
16889
|
const { getById: _getById } = useOrgRepo();
|
|
16693
16890
|
async function add(value) {
|
|
16694
16891
|
const session = useAtlas39.getClient()?.startSession();
|
|
16695
|
-
if (!session)
|
|
16892
|
+
if (!session) {
|
|
16696
16893
|
throw new Error("Unable to start session for vehicle service.");
|
|
16894
|
+
}
|
|
16697
16895
|
const org = await _getById(value.org);
|
|
16698
16896
|
if (!org)
|
|
16699
16897
|
throw new BadRequestError80("Org not found");
|
|
@@ -16741,11 +16939,12 @@ function useVehicleService() {
|
|
|
16741
16939
|
}
|
|
16742
16940
|
}
|
|
16743
16941
|
const owner = String(value.name ?? "").substring(0, 15);
|
|
16942
|
+
const plateNumbers = value.plateNumber;
|
|
16744
16943
|
try {
|
|
16745
16944
|
session.startTransaction();
|
|
16746
16945
|
let message = "Vehicle plate number needs approval from property management.";
|
|
16946
|
+
let siteCameras = [];
|
|
16747
16947
|
if (value.status && value.status !== "pending" /* PENDING */) {
|
|
16748
|
-
const siteCameras = [];
|
|
16749
16948
|
let page = 1;
|
|
16750
16949
|
let pages = 1;
|
|
16751
16950
|
const limit = 20;
|
|
@@ -16760,40 +16959,44 @@ function useVehicleService() {
|
|
|
16760
16959
|
pages = siteCameraReq.pages || 1;
|
|
16761
16960
|
siteCameras.push(...siteCameraReq.items);
|
|
16762
16961
|
page++;
|
|
16763
|
-
} while (page
|
|
16764
|
-
if (!siteCameras.length)
|
|
16962
|
+
} while (page <= pages);
|
|
16963
|
+
if (!siteCameras.length) {
|
|
16765
16964
|
throw new BadRequestError80("No site cameras found.");
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
16769
|
-
|
|
16770
|
-
|
|
16771
|
-
|
|
16772
|
-
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
16965
|
+
}
|
|
16966
|
+
}
|
|
16967
|
+
for (const plateNumber of plateNumbers) {
|
|
16968
|
+
const vehicleValue = {
|
|
16969
|
+
...value,
|
|
16970
|
+
plateNumber,
|
|
16971
|
+
start,
|
|
16972
|
+
end
|
|
16973
|
+
};
|
|
16974
|
+
if (vehicleValue.status && vehicleValue.status !== "pending" /* PENDING */) {
|
|
16975
|
+
for (const camera of siteCameras) {
|
|
16976
|
+
const { host, username, password } = camera;
|
|
16977
|
+
const dahuaPayload = {
|
|
16978
|
+
host,
|
|
16979
|
+
username,
|
|
16980
|
+
password,
|
|
16981
|
+
plateNumber,
|
|
16982
|
+
mode: _mode,
|
|
16983
|
+
owner,
|
|
16984
|
+
...startDateDahua ? { start: startDateDahua } : {},
|
|
16985
|
+
...endDateDahua ? { end: endDateDahua } : {}
|
|
16986
|
+
};
|
|
16987
|
+
const dahuaResponse = await _addPlateNumber(dahuaPayload);
|
|
16988
|
+
if (dahuaResponse?.statusCode !== 200) {
|
|
16989
|
+
throw new BadRequestError80(
|
|
16990
|
+
`Failed to add plate number to ANPR ${_type}`
|
|
16991
|
+
);
|
|
16992
|
+
}
|
|
16993
|
+
const responseData = dahuaResponse?.data?.toString("utf-8") ?? "";
|
|
16994
|
+
vehicleValue.recNo = responseData.split("=")[1]?.trim();
|
|
16783
16995
|
}
|
|
16784
|
-
const responseData = dahuaResponse?.data.toString("utf-8");
|
|
16785
|
-
value.recNo = responseData.split("=")[1]?.trim();
|
|
16786
16996
|
message = `Vehicle plate number added to ${_type} successfully.`;
|
|
16787
16997
|
}
|
|
16998
|
+
await _add(vehicleValue, session);
|
|
16788
16999
|
}
|
|
16789
|
-
const formattedValue = {
|
|
16790
|
-
...value,
|
|
16791
|
-
start,
|
|
16792
|
-
// ISO string or ""
|
|
16793
|
-
end
|
|
16794
|
-
// ISO string or ""
|
|
16795
|
-
};
|
|
16796
|
-
await _add(formattedValue, session);
|
|
16797
17000
|
await session.commitTransaction();
|
|
16798
17001
|
return message;
|
|
16799
17002
|
} catch (error) {
|
|
@@ -16998,14 +17201,14 @@ function useVehicleController() {
|
|
|
16998
17201
|
} = useVehicleRepo();
|
|
16999
17202
|
async function add(req, res, next) {
|
|
17000
17203
|
const payload = req.body;
|
|
17001
|
-
const { error } = vehicleSchema.validate(payload);
|
|
17204
|
+
const { error, value } = vehicleSchema.validate(payload);
|
|
17002
17205
|
if (error) {
|
|
17003
17206
|
logger65.log({ level: "error", message: error.message });
|
|
17004
17207
|
next(new BadRequestError81(error.message));
|
|
17005
17208
|
return;
|
|
17006
17209
|
}
|
|
17007
17210
|
try {
|
|
17008
|
-
const data = await _add(
|
|
17211
|
+
const data = await _add(value);
|
|
17009
17212
|
res.status(201).json({
|
|
17010
17213
|
message: "Vehicle added successfully.",
|
|
17011
17214
|
data
|
|
@@ -17025,9 +17228,9 @@ function useVehicleController() {
|
|
|
17025
17228
|
limit: Joi46.number().integer().min(1).max(100).allow("", null).default(10),
|
|
17026
17229
|
sort: Joi46.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
17027
17230
|
order: Joi46.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
17028
|
-
type: Joi46.string().optional().valid(...Object.values(VehicleType)),
|
|
17029
|
-
category: Joi46.string().optional().valid(...Object.values(VehicleCategory)),
|
|
17030
|
-
status: Joi46.string().optional().valid(...Object.values(VehicleStatus)).allow("")
|
|
17231
|
+
type: Joi46.string().optional().valid(...Object.values(VehicleType)).allow(null, ""),
|
|
17232
|
+
category: Joi46.string().optional().valid(...Object.values(VehicleCategory)).allow(null, ""),
|
|
17233
|
+
status: Joi46.string().optional().valid(...Object.values(VehicleStatus)).allow(null, "")
|
|
17031
17234
|
});
|
|
17032
17235
|
const query = { ...req.query };
|
|
17033
17236
|
const { error } = validation.validate(query);
|
|
@@ -17192,7 +17395,7 @@ function useVehicleController() {
|
|
|
17192
17395
|
const allowedFields = ["start", "end"];
|
|
17193
17396
|
const allowedOrder = ["asc", "desc"];
|
|
17194
17397
|
const validation = Joi46.object({
|
|
17195
|
-
|
|
17398
|
+
nric: Joi46.string().optional().allow("", null),
|
|
17196
17399
|
page: Joi46.number().integer().min(1).allow("", null).default(1),
|
|
17197
17400
|
limit: Joi46.number().integer().min(1).max(100).allow("", null).default(10),
|
|
17198
17401
|
sort: Joi46.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
@@ -17205,7 +17408,7 @@ function useVehicleController() {
|
|
|
17205
17408
|
next(new BadRequestError81(error.message));
|
|
17206
17409
|
return;
|
|
17207
17410
|
}
|
|
17208
|
-
const
|
|
17411
|
+
const nric = req.query.nric ?? "";
|
|
17209
17412
|
const page = parseInt(req.query.page ?? "1");
|
|
17210
17413
|
const limit = parseInt(req.query.limit ?? "10");
|
|
17211
17414
|
const sortObj = {};
|
|
@@ -17219,7 +17422,7 @@ function useVehicleController() {
|
|
|
17219
17422
|
});
|
|
17220
17423
|
try {
|
|
17221
17424
|
const data = await _getVehiclesByNRIC({
|
|
17222
|
-
|
|
17425
|
+
nric,
|
|
17223
17426
|
page,
|
|
17224
17427
|
limit,
|
|
17225
17428
|
sort: sortObj
|
|
@@ -19868,25 +20071,15 @@ function usePersonService() {
|
|
|
19868
20071
|
}
|
|
19869
20072
|
async function plateValidity(value) {
|
|
19870
20073
|
const now = /* @__PURE__ */ new Date();
|
|
19871
|
-
if (
|
|
19872
|
-
|
|
19873
|
-
|
|
19874
|
-
if (value.type === "resident") {
|
|
20074
|
+
if (["resident" /* RESIDENT */, "tenant" /* TENANT */].includes(
|
|
20075
|
+
value?.type
|
|
20076
|
+
)) {
|
|
19875
20077
|
const end = new Date(now);
|
|
19876
20078
|
end.setFullYear(end.getFullYear() + 10);
|
|
19877
|
-
return {
|
|
19878
|
-
|
|
19879
|
-
|
|
19880
|
-
|
|
19881
|
-
if (!unit) {
|
|
19882
|
-
throw new BadRequestError97("Building unit not found for tenant.");
|
|
19883
|
-
}
|
|
19884
|
-
if (unit.leaseStart && unit.leaseEnd) {
|
|
19885
|
-
return {
|
|
19886
|
-
start: new Date(unit.leaseStart).toISOString(),
|
|
19887
|
-
end: new Date(unit.leaseEnd).toISOString()
|
|
19888
|
-
};
|
|
19889
|
-
}
|
|
20079
|
+
return {
|
|
20080
|
+
start: now.toISOString(),
|
|
20081
|
+
end: end.toISOString()
|
|
20082
|
+
};
|
|
19890
20083
|
}
|
|
19891
20084
|
return { start: "", end: "" };
|
|
19892
20085
|
}
|
|
@@ -19905,7 +20098,8 @@ function usePersonController() {
|
|
|
19905
20098
|
getPersonByPhoneNumber: _getPersonByPhoneNumber,
|
|
19906
20099
|
getPeopleByUnit: _getPeopleByUnit,
|
|
19907
20100
|
getCompany: _getCompany,
|
|
19908
|
-
getPeopleByPlateNumber: _getPeopleByPlateNumber
|
|
20101
|
+
getPeopleByPlateNumber: _getPeopleByPlateNumber,
|
|
20102
|
+
getPeopleByNRIC: _getPeopleByNRIC
|
|
19909
20103
|
} = usePersonRepo();
|
|
19910
20104
|
const { add: _add, updateById: _updateById } = usePersonService();
|
|
19911
20105
|
async function add(req, res, next) {
|
|
@@ -20140,6 +20334,53 @@ function usePersonController() {
|
|
|
20140
20334
|
return;
|
|
20141
20335
|
}
|
|
20142
20336
|
}
|
|
20337
|
+
async function getPeopleByNRIC(req, res, next) {
|
|
20338
|
+
const allowedFields = ["start", "end"];
|
|
20339
|
+
const allowedOrder = ["asc", "desc"];
|
|
20340
|
+
const validation = Joi58.object({
|
|
20341
|
+
nric: Joi58.string().optional().allow("", null),
|
|
20342
|
+
page: Joi58.number().integer().min(1).allow("", null).default(1),
|
|
20343
|
+
limit: Joi58.number().integer().min(1).max(100).allow("", null).default(10),
|
|
20344
|
+
sort: Joi58.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
20345
|
+
order: Joi58.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
20346
|
+
site: Joi58.string().hex().length(24).required()
|
|
20347
|
+
});
|
|
20348
|
+
const query = { ...req.query };
|
|
20349
|
+
const { error } = validation.validate(query);
|
|
20350
|
+
if (error) {
|
|
20351
|
+
logger81.log({ level: "error", message: error.message });
|
|
20352
|
+
next(new BadRequestError98(error.message));
|
|
20353
|
+
return;
|
|
20354
|
+
}
|
|
20355
|
+
const nric = req.query.nric ?? "";
|
|
20356
|
+
const page = parseInt(req.query.page ?? "1");
|
|
20357
|
+
const limit = parseInt(req.query.limit ?? "10");
|
|
20358
|
+
const site = req.query.site ?? "";
|
|
20359
|
+
const sortObj = {};
|
|
20360
|
+
const sortFields = String(req.query.sort).split(",");
|
|
20361
|
+
const sortOrders = String(req.query.order).split(",");
|
|
20362
|
+
sortFields.forEach((field, index) => {
|
|
20363
|
+
if (allowedFields.includes(field)) {
|
|
20364
|
+
const order = sortOrders[index] === "asc" ? 1 : -1;
|
|
20365
|
+
sortObj[field] = order;
|
|
20366
|
+
}
|
|
20367
|
+
});
|
|
20368
|
+
try {
|
|
20369
|
+
const data = await _getPeopleByNRIC({
|
|
20370
|
+
nric,
|
|
20371
|
+
page,
|
|
20372
|
+
limit,
|
|
20373
|
+
sort: sortObj,
|
|
20374
|
+
site
|
|
20375
|
+
});
|
|
20376
|
+
res.json(data);
|
|
20377
|
+
return;
|
|
20378
|
+
} catch (error2) {
|
|
20379
|
+
logger81.log({ level: "error", message: error2.message });
|
|
20380
|
+
next(error2);
|
|
20381
|
+
return;
|
|
20382
|
+
}
|
|
20383
|
+
}
|
|
20143
20384
|
return {
|
|
20144
20385
|
add,
|
|
20145
20386
|
getAll,
|
|
@@ -20149,7 +20390,8 @@ function usePersonController() {
|
|
|
20149
20390
|
getPersonByPhoneNumber,
|
|
20150
20391
|
getPeopleByUnit,
|
|
20151
20392
|
getCompany,
|
|
20152
|
-
getPeopleByPlateNumber
|
|
20393
|
+
getPeopleByPlateNumber,
|
|
20394
|
+
getPeopleByNRIC
|
|
20153
20395
|
};
|
|
20154
20396
|
}
|
|
20155
20397
|
|
|
@@ -29417,7 +29659,8 @@ function UseAccessManagementRepo() {
|
|
|
29417
29659
|
const query = {
|
|
29418
29660
|
site: siteId,
|
|
29419
29661
|
assignedUnit: { $ne: null },
|
|
29420
|
-
type: "NFC" /* NFC
|
|
29662
|
+
type: "NFC" /* NFC */,
|
|
29663
|
+
isActivated: true
|
|
29421
29664
|
};
|
|
29422
29665
|
if (search) {
|
|
29423
29666
|
query.$or = [{ accessLevel: { $regex: search, $options: "i" } }, { cardNo: { $regex: search, $options: "i" } }];
|
|
@@ -29425,7 +29668,7 @@ function UseAccessManagementRepo() {
|
|
|
29425
29668
|
if (type) {
|
|
29426
29669
|
query.userType = type;
|
|
29427
29670
|
} else {
|
|
29428
|
-
query.userType = { $ne: "Resident
|
|
29671
|
+
query.userType = { $ne: "Visitor/Resident" /* DEFAULT */ };
|
|
29429
29672
|
}
|
|
29430
29673
|
const res = await collection().aggregate([
|
|
29431
29674
|
{
|
|
@@ -29799,6 +30042,52 @@ function UseAccessManagementRepo() {
|
|
|
29799
30042
|
throw new Error(error.message);
|
|
29800
30043
|
}
|
|
29801
30044
|
}
|
|
30045
|
+
async function addQrTagRepo(params) {
|
|
30046
|
+
try {
|
|
30047
|
+
const { site, payload } = params;
|
|
30048
|
+
const id = new ObjectId83(site);
|
|
30049
|
+
const highestCardNo = await collection().aggregate([
|
|
30050
|
+
{ $match: { site: id, type: "NFC" /* NFC */, userType: "Visitor/Resident" /* DEFAULT */ } },
|
|
30051
|
+
{
|
|
30052
|
+
$addFields: {
|
|
30053
|
+
qrTagCardNoNumeric: { $toInt: "$qrTagCardNo" }
|
|
30054
|
+
// Convert string to integer
|
|
30055
|
+
}
|
|
30056
|
+
},
|
|
30057
|
+
{
|
|
30058
|
+
$sort: { qrTagCardNoNumeric: -1 }
|
|
30059
|
+
// Sort in descending order
|
|
30060
|
+
},
|
|
30061
|
+
{
|
|
30062
|
+
$limit: 1
|
|
30063
|
+
// Get the highest
|
|
30064
|
+
}
|
|
30065
|
+
]).toArray();
|
|
30066
|
+
let start = 0;
|
|
30067
|
+
if (highestCardNo.length > 0) {
|
|
30068
|
+
start = highestCardNo[0].qrTagCardNoNumeric || 0;
|
|
30069
|
+
}
|
|
30070
|
+
const nextCardNumbers = Array.from({ length: payload.length }, (_, i) => String(start + i + 1).padStart(5, "0"));
|
|
30071
|
+
const bulkOps = await Promise.all(
|
|
30072
|
+
payload.map(async (doc, index) => {
|
|
30073
|
+
const id2 = new ObjectId83(doc._id);
|
|
30074
|
+
return {
|
|
30075
|
+
updateOne: {
|
|
30076
|
+
filter: { _id: id2 },
|
|
30077
|
+
update: { $set: { qrTag: doc.qrTag, qrTagCardNo: nextCardNumbers[index] } }
|
|
30078
|
+
}
|
|
30079
|
+
};
|
|
30080
|
+
})
|
|
30081
|
+
);
|
|
30082
|
+
let result;
|
|
30083
|
+
if (bulkOps.length > 0) {
|
|
30084
|
+
result = await collection().bulkWrite(bulkOps);
|
|
30085
|
+
}
|
|
30086
|
+
return result;
|
|
30087
|
+
} catch (error) {
|
|
30088
|
+
throw new Error(error.message);
|
|
30089
|
+
}
|
|
30090
|
+
}
|
|
29802
30091
|
return {
|
|
29803
30092
|
createIndexes,
|
|
29804
30093
|
createIndexForEntrypass,
|
|
@@ -29821,7 +30110,8 @@ function UseAccessManagementRepo() {
|
|
|
29821
30110
|
bulkPhysicalAccessCardRepo,
|
|
29822
30111
|
assignAccessCardToUnitRepo,
|
|
29823
30112
|
deleteCardRepo,
|
|
29824
|
-
getCardDetailsRepo
|
|
30113
|
+
getCardDetailsRepo,
|
|
30114
|
+
addQrTagRepo
|
|
29825
30115
|
};
|
|
29826
30116
|
}
|
|
29827
30117
|
|
|
@@ -29855,7 +30145,8 @@ function useAccessManagementSvc() {
|
|
|
29855
30145
|
bulkPhysicalAccessCardRepo,
|
|
29856
30146
|
assignAccessCardToUnitRepo,
|
|
29857
30147
|
deleteCardRepo,
|
|
29858
|
-
getCardDetailsRepo
|
|
30148
|
+
getCardDetailsRepo,
|
|
30149
|
+
addQrTagRepo
|
|
29859
30150
|
} = UseAccessManagementRepo();
|
|
29860
30151
|
const addPhysicalCardSvc = async (payload) => {
|
|
29861
30152
|
try {
|
|
@@ -30119,6 +30410,14 @@ function useAccessManagementSvc() {
|
|
|
30119
30410
|
throw new Error(err.message);
|
|
30120
30411
|
}
|
|
30121
30412
|
};
|
|
30413
|
+
const addQrTagSvc = async (params) => {
|
|
30414
|
+
try {
|
|
30415
|
+
const response = await addQrTagRepo({ ...params });
|
|
30416
|
+
return response;
|
|
30417
|
+
} catch (err) {
|
|
30418
|
+
throw new Error(err.message);
|
|
30419
|
+
}
|
|
30420
|
+
};
|
|
30122
30421
|
return {
|
|
30123
30422
|
addPhysicalCardSvc,
|
|
30124
30423
|
addNonPhysicalCardSvc,
|
|
@@ -30145,7 +30444,8 @@ function useAccessManagementSvc() {
|
|
|
30145
30444
|
bulkPhysicalAccessCardSvc,
|
|
30146
30445
|
assignAccessCardToUnitSvc,
|
|
30147
30446
|
deleteCardSvc,
|
|
30148
|
-
getCardDetailsSvc
|
|
30447
|
+
getCardDetailsSvc,
|
|
30448
|
+
addQrTagSvc
|
|
30149
30449
|
};
|
|
30150
30450
|
}
|
|
30151
30451
|
|
|
@@ -30179,7 +30479,8 @@ function useAccessManagementController() {
|
|
|
30179
30479
|
bulkPhysicalAccessCardSvc,
|
|
30180
30480
|
assignAccessCardToUnitSvc,
|
|
30181
30481
|
deleteCardSvc,
|
|
30182
|
-
getCardDetailsSvc
|
|
30482
|
+
getCardDetailsSvc,
|
|
30483
|
+
addQrTagSvc
|
|
30183
30484
|
} = useAccessManagementSvc();
|
|
30184
30485
|
const addPhysicalCard = async (req, res) => {
|
|
30185
30486
|
try {
|
|
@@ -30790,6 +31091,34 @@ function useAccessManagementController() {
|
|
|
30790
31091
|
});
|
|
30791
31092
|
}
|
|
30792
31093
|
};
|
|
31094
|
+
const addQrTag = async (req, res) => {
|
|
31095
|
+
try {
|
|
31096
|
+
const payload = req.body;
|
|
31097
|
+
const site = req.params.site;
|
|
31098
|
+
const schema2 = Joi85.object({
|
|
31099
|
+
site: Joi85.string().hex().required(),
|
|
31100
|
+
payload: Joi85.array().items(
|
|
31101
|
+
Joi85.object({
|
|
31102
|
+
_id: Joi85.string().hex().required(),
|
|
31103
|
+
cardNo: Joi85.string().required(),
|
|
31104
|
+
qrTag: Joi85.string().required(),
|
|
31105
|
+
qrTagCardNo: Joi85.string().required()
|
|
31106
|
+
})
|
|
31107
|
+
).required()
|
|
31108
|
+
});
|
|
31109
|
+
const { error } = schema2.validate({ site, payload });
|
|
31110
|
+
if (error) {
|
|
31111
|
+
return res.status(400).json({ message: error.message });
|
|
31112
|
+
}
|
|
31113
|
+
const result = await addQrTagSvc({ payload, site });
|
|
31114
|
+
return res.status(200).json({ message: "Success", data: result });
|
|
31115
|
+
} catch (error) {
|
|
31116
|
+
return res.status(500).json({
|
|
31117
|
+
data: null,
|
|
31118
|
+
message: error.message
|
|
31119
|
+
});
|
|
31120
|
+
}
|
|
31121
|
+
};
|
|
30793
31122
|
return {
|
|
30794
31123
|
addPhysicalCard,
|
|
30795
31124
|
addNonPhysicalCard,
|
|
@@ -30813,7 +31142,8 @@ function useAccessManagementController() {
|
|
|
30813
31142
|
bulkPhysicalAccessCard,
|
|
30814
31143
|
assignAccessCardToUnit,
|
|
30815
31144
|
deleteCard,
|
|
30816
|
-
getCardDetails
|
|
31145
|
+
getCardDetails,
|
|
31146
|
+
addQrTag
|
|
30817
31147
|
};
|
|
30818
31148
|
}
|
|
30819
31149
|
|