@7365admin1/core 2.14.0 → 2.15.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 +79 -16
- package/dist/index.js +952 -181
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +945 -179
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -3
package/dist/index.mjs
CHANGED
|
@@ -1388,7 +1388,9 @@ var schemaOccurrenceEntry = Joi5.object({
|
|
|
1388
1388
|
subject: Joi5.string().hex().optional().allow(null, ""),
|
|
1389
1389
|
occurrence: Joi5.string().optional().allow(null, ""),
|
|
1390
1390
|
signature: Joi5.string().hex().optional().allow(null, ""),
|
|
1391
|
-
incidentReportId: Joi5.string().hex().optional().allow(null, "")
|
|
1391
|
+
incidentReportId: Joi5.string().hex().optional().allow(null, ""),
|
|
1392
|
+
eSignature: Joi5.string().required(),
|
|
1393
|
+
createdByName: Joi5.string().optional().allow(null, "")
|
|
1392
1394
|
});
|
|
1393
1395
|
var schemaUpdateOccurrenceEntry = Joi5.object({
|
|
1394
1396
|
_id: Joi5.string().hex().required(),
|
|
@@ -1397,7 +1399,9 @@ var schemaUpdateOccurrenceEntry = Joi5.object({
|
|
|
1397
1399
|
subject: Joi5.string().hex().optional().allow(null, ""),
|
|
1398
1400
|
occurrence: Joi5.string().optional().allow(null, ""),
|
|
1399
1401
|
signature: Joi5.string().hex().optional().allow(null, ""),
|
|
1400
|
-
incidentReportId: Joi5.string().hex().optional().allow(null, "")
|
|
1402
|
+
incidentReportId: Joi5.string().hex().optional().allow(null, ""),
|
|
1403
|
+
eSignature: Joi5.string().required(),
|
|
1404
|
+
createdByName: Joi5.string().optional().allow(null, "")
|
|
1401
1405
|
});
|
|
1402
1406
|
function MOccurrenceEntry(value) {
|
|
1403
1407
|
if (value._id && typeof value._id === "string") {
|
|
@@ -1454,6 +1458,8 @@ function MOccurrenceEntry(value) {
|
|
|
1454
1458
|
incidentReportId: value.incidentReportId,
|
|
1455
1459
|
signature: value.signature,
|
|
1456
1460
|
userName: value.userName,
|
|
1461
|
+
eSignature: value.eSignature,
|
|
1462
|
+
createdByName: value.createdByName,
|
|
1457
1463
|
date: value.date,
|
|
1458
1464
|
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1459
1465
|
updatedAt: value.updatedAt,
|
|
@@ -6424,12 +6430,12 @@ function useUserController() {
|
|
|
6424
6430
|
}
|
|
6425
6431
|
}
|
|
6426
6432
|
async function createUserByVerification(req, res, next) {
|
|
6427
|
-
const
|
|
6433
|
+
const allowedTypes = ["user-sign-up", "user-invite"];
|
|
6428
6434
|
const validation = Joi14.object({
|
|
6429
6435
|
id: Joi14.string().hex().required(),
|
|
6430
6436
|
name: Joi14.string().required(),
|
|
6431
6437
|
password: Joi14.string().required(),
|
|
6432
|
-
type: Joi14.string().required().valid(...
|
|
6438
|
+
type: Joi14.string().required().valid(...allowedTypes)
|
|
6433
6439
|
});
|
|
6434
6440
|
const id = req.params.id;
|
|
6435
6441
|
const payload = { ...req.body };
|
|
@@ -15493,12 +15499,37 @@ import {
|
|
|
15493
15499
|
import { BadRequestError as BadRequestError77, logger as logger61 } from "@7365admin1/node-server-utils";
|
|
15494
15500
|
import Joi43 from "joi";
|
|
15495
15501
|
import { ObjectId as ObjectId45 } from "mongodb";
|
|
15496
|
-
var
|
|
15497
|
-
|
|
15502
|
+
var VehicleType = /* @__PURE__ */ ((VehicleType2) => {
|
|
15503
|
+
VehicleType2["WHITELIST"] = "whitelist";
|
|
15504
|
+
VehicleType2["BLOCKLIST"] = "blocklist";
|
|
15505
|
+
return VehicleType2;
|
|
15506
|
+
})(VehicleType || {});
|
|
15507
|
+
var VehicleCategory = /* @__PURE__ */ ((VehicleCategory2) => {
|
|
15508
|
+
VehicleCategory2["RESIDENT"] = "resident";
|
|
15509
|
+
VehicleCategory2["VISITOR"] = "visitor";
|
|
15510
|
+
return VehicleCategory2;
|
|
15511
|
+
})(VehicleCategory || {});
|
|
15512
|
+
var VehicleStatus = /* @__PURE__ */ ((VehicleStatus2) => {
|
|
15513
|
+
VehicleStatus2["PENDING"] = "pending";
|
|
15514
|
+
VehicleStatus2["ACTIVE"] = "active";
|
|
15515
|
+
VehicleStatus2["INACTIVE"] = "inactive";
|
|
15516
|
+
VehicleStatus2["DELETED"] = "deleted";
|
|
15517
|
+
return VehicleStatus2;
|
|
15518
|
+
})(VehicleStatus || {});
|
|
15519
|
+
var OrgNature = /* @__PURE__ */ ((OrgNature2) => {
|
|
15520
|
+
OrgNature2["PROPERTY_MANAGEMENT_AGENCY"] = "property_management_agency";
|
|
15521
|
+
OrgNature2["SECURITY_AGENCY"] = "security_agency";
|
|
15522
|
+
return OrgNature2;
|
|
15523
|
+
})(OrgNature || {});
|
|
15524
|
+
var ANPRMode = /* @__PURE__ */ ((ANPRMode2) => {
|
|
15525
|
+
ANPRMode2["TRAFFIC_REDLIST"] = "TrafficRedList";
|
|
15526
|
+
ANPRMode2["TRAFFIC_BLACKLIST"] = "TrafficBlackList";
|
|
15527
|
+
return ANPRMode2;
|
|
15528
|
+
})(ANPRMode || {});
|
|
15498
15529
|
var vehicleSchema = Joi43.object({
|
|
15499
15530
|
plateNumber: Joi43.string().required(),
|
|
15500
|
-
type: Joi43.string().required().
|
|
15501
|
-
category: Joi43.string().required().
|
|
15531
|
+
type: Joi43.string().required().valid(...Object.values(VehicleType)),
|
|
15532
|
+
category: Joi43.string().required().valid(...Object.values(VehicleCategory)),
|
|
15502
15533
|
name: Joi43.string().required(),
|
|
15503
15534
|
phoneNumber: Joi43.string().optional().allow("", null),
|
|
15504
15535
|
recNo: Joi43.string().optional().allow("", null),
|
|
@@ -15512,7 +15543,8 @@ var vehicleSchema = Joi43.object({
|
|
|
15512
15543
|
seasonPassType: Joi43.string().optional().allow("", null),
|
|
15513
15544
|
start: Joi43.date().optional().allow("", null),
|
|
15514
15545
|
end: Joi43.date().optional().allow("", null),
|
|
15515
|
-
unitName: Joi43.string().optional().allow("", null)
|
|
15546
|
+
unitName: Joi43.string().optional().allow("", null),
|
|
15547
|
+
status: Joi43.string().optional().valid(...Object.values(VehicleStatus)).allow("")
|
|
15516
15548
|
});
|
|
15517
15549
|
function MVehicle(value) {
|
|
15518
15550
|
const { error } = vehicleSchema.validate(value);
|
|
@@ -15541,6 +15573,11 @@ function MVehicle(value) {
|
|
|
15541
15573
|
throw new BadRequestError77("Invalid building unit ID format.");
|
|
15542
15574
|
}
|
|
15543
15575
|
}
|
|
15576
|
+
const createdAtDate = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
|
|
15577
|
+
const expiredDate = new Date(createdAtDate);
|
|
15578
|
+
expiredDate.setFullYear(expiredDate.getFullYear() + 10);
|
|
15579
|
+
const createdAt = createdAtDate.toISOString();
|
|
15580
|
+
const expiredAt = value.end ?? expiredDate.toISOString();
|
|
15544
15581
|
return {
|
|
15545
15582
|
plateNumber: value.plateNumber ?? "",
|
|
15546
15583
|
type: value.type ?? "",
|
|
@@ -15556,11 +15593,11 @@ function MVehicle(value) {
|
|
|
15556
15593
|
nric: value.nric ?? "",
|
|
15557
15594
|
remarks: value.remarks ?? "",
|
|
15558
15595
|
seasonPassType: value.seasonPassType ?? "",
|
|
15559
|
-
start: value.start ??
|
|
15560
|
-
end: value.end ??
|
|
15561
|
-
status: value.status ?? "active"
|
|
15596
|
+
start: value.start ?? createdAt,
|
|
15597
|
+
end: value.end ?? expiredAt,
|
|
15598
|
+
status: value.status ?? "active" /* ACTIVE */,
|
|
15562
15599
|
unitName: value.unitName ?? "",
|
|
15563
|
-
createdAt
|
|
15600
|
+
createdAt,
|
|
15564
15601
|
updatedAt: value.updatedAt ?? "",
|
|
15565
15602
|
deletedAt: value.deletedAt ?? ""
|
|
15566
15603
|
};
|
|
@@ -15618,18 +15655,44 @@ function useVehicleRepo() {
|
|
|
15618
15655
|
}
|
|
15619
15656
|
const namespace_collection = "vehicles";
|
|
15620
15657
|
const collection = db.collection(namespace_collection);
|
|
15621
|
-
const { delNamespace, setCache, getCache
|
|
15658
|
+
const { delNamespace, setCache, getCache } = useCache28(namespace_collection);
|
|
15622
15659
|
async function createIndex() {
|
|
15623
15660
|
try {
|
|
15624
15661
|
await collection.createIndexes([
|
|
15625
15662
|
{ key: { status: 1 } },
|
|
15626
15663
|
{ key: { type: 1 } },
|
|
15627
|
-
{ key: { category: 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
|
+
}
|
|
15628
15674
|
]);
|
|
15629
15675
|
} catch (error) {
|
|
15676
|
+
console.error("createIndexes error:", error);
|
|
15630
15677
|
throw new InternalServerError28("Failed to create index on vehicle.");
|
|
15631
15678
|
}
|
|
15632
15679
|
}
|
|
15680
|
+
async function createTextIndex() {
|
|
15681
|
+
try {
|
|
15682
|
+
await collection.createIndex({
|
|
15683
|
+
name: "text",
|
|
15684
|
+
plateNumber: "text",
|
|
15685
|
+
level: "text",
|
|
15686
|
+
unitName: "text",
|
|
15687
|
+
phoneNumber: "text",
|
|
15688
|
+
nric: "text"
|
|
15689
|
+
});
|
|
15690
|
+
} catch (error) {
|
|
15691
|
+
throw new InternalServerError28(
|
|
15692
|
+
"Failed to create text index on visitor transaction."
|
|
15693
|
+
);
|
|
15694
|
+
}
|
|
15695
|
+
}
|
|
15633
15696
|
async function add(value, session) {
|
|
15634
15697
|
try {
|
|
15635
15698
|
value = MVehicle(value);
|
|
@@ -15661,37 +15724,40 @@ function useVehicleRepo() {
|
|
|
15661
15724
|
search = "",
|
|
15662
15725
|
sort = {},
|
|
15663
15726
|
type = "",
|
|
15664
|
-
category = ""
|
|
15727
|
+
category = "",
|
|
15728
|
+
status = ""
|
|
15665
15729
|
}) {
|
|
15666
15730
|
page = page > 0 ? page - 1 : 0;
|
|
15667
|
-
const
|
|
15731
|
+
const baseQuery = {
|
|
15732
|
+
...status && { status },
|
|
15733
|
+
...type && { type },
|
|
15734
|
+
...type && { type }
|
|
15735
|
+
};
|
|
15736
|
+
let query = { ...baseQuery };
|
|
15737
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15668
15738
|
const cacheOptions = {
|
|
15669
|
-
status
|
|
15739
|
+
...status && { status },
|
|
15740
|
+
...type && { type },
|
|
15741
|
+
...type && { type },
|
|
15670
15742
|
page: String(page),
|
|
15671
|
-
limit: String(limit)
|
|
15743
|
+
limit: String(limit),
|
|
15744
|
+
sort: JSON.stringify(sort)
|
|
15672
15745
|
};
|
|
15673
|
-
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15674
|
-
cacheOptions.sort = JSON.stringify(sort);
|
|
15675
15746
|
if (search) {
|
|
15676
|
-
query.$
|
|
15747
|
+
query.$text = { $search: search };
|
|
15677
15748
|
cacheOptions.search = search;
|
|
15678
15749
|
}
|
|
15679
|
-
if (type) {
|
|
15680
|
-
query.type = type;
|
|
15681
|
-
cacheOptions.type = type;
|
|
15682
|
-
}
|
|
15683
|
-
if (category) {
|
|
15684
|
-
query.category = category;
|
|
15685
|
-
cacheOptions.category = category;
|
|
15686
|
-
}
|
|
15687
15750
|
const cacheKey = makeCacheKey26(namespace_collection, cacheOptions);
|
|
15688
15751
|
const cachedData = await getCache(cacheKey);
|
|
15689
15752
|
if (cachedData) {
|
|
15690
15753
|
logger62.info(`Cache hit for key: ${cacheKey}`);
|
|
15691
15754
|
return cachedData;
|
|
15692
15755
|
}
|
|
15756
|
+
const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15693
15757
|
try {
|
|
15694
|
-
|
|
15758
|
+
let items = [];
|
|
15759
|
+
let length = 0;
|
|
15760
|
+
items = await collection.aggregate([
|
|
15695
15761
|
{ $match: query },
|
|
15696
15762
|
{ $sort: sort },
|
|
15697
15763
|
{ $skip: page * limit },
|
|
@@ -15717,17 +15783,65 @@ function useVehicleRepo() {
|
|
|
15717
15783
|
level: 1,
|
|
15718
15784
|
unit: "$units.name",
|
|
15719
15785
|
plateNumber: 1,
|
|
15720
|
-
recNo: 1
|
|
15786
|
+
recNo: 1,
|
|
15787
|
+
nric: 1
|
|
15721
15788
|
}
|
|
15722
15789
|
}
|
|
15723
15790
|
]).toArray();
|
|
15724
|
-
|
|
15791
|
+
length = await collection.countDocuments(query);
|
|
15792
|
+
if ((!items || items.length === 0) && search) {
|
|
15793
|
+
const escaped = escapeRegex(search);
|
|
15794
|
+
const regexQuery = {
|
|
15795
|
+
...baseQuery,
|
|
15796
|
+
...type && { type },
|
|
15797
|
+
...category && { category },
|
|
15798
|
+
$or: [
|
|
15799
|
+
{ name: { $regex: escaped, $options: "i" } },
|
|
15800
|
+
{ plateNumber: { $regex: escaped, $options: "i" } },
|
|
15801
|
+
{ company: { $regex: escaped, $options: "i" } },
|
|
15802
|
+
{ level: { $regex: escaped, $options: "i" } },
|
|
15803
|
+
{ unitName: { $regex: escaped, $options: "i" } },
|
|
15804
|
+
{ contact: { $regex: escaped, $options: "i" } },
|
|
15805
|
+
{ nric: { $regex: escaped, $options: "i" } }
|
|
15806
|
+
]
|
|
15807
|
+
};
|
|
15808
|
+
items = await collection.aggregate([
|
|
15809
|
+
{ $match: regexQuery },
|
|
15810
|
+
{ $sort: sort },
|
|
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);
|
|
15840
|
+
}
|
|
15725
15841
|
const data = paginate21(items, page, limit, length);
|
|
15726
|
-
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
15727
|
-
logger62.
|
|
15728
|
-
|
|
15729
|
-
logger62.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
15730
|
-
});
|
|
15842
|
+
setCache(cacheKey, data, 15 * 60).then(() => logger62.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
15843
|
+
(err) => logger62.error(`Failed to set cache for key: ${cacheKey}`, err)
|
|
15844
|
+
);
|
|
15731
15845
|
return data;
|
|
15732
15846
|
} catch (error) {
|
|
15733
15847
|
throw error;
|
|
@@ -15821,7 +15935,10 @@ function useVehicleRepo() {
|
|
|
15821
15935
|
type: 1,
|
|
15822
15936
|
category: 1,
|
|
15823
15937
|
status: 1,
|
|
15824
|
-
recNo: 1
|
|
15938
|
+
recNo: 1,
|
|
15939
|
+
start: 1,
|
|
15940
|
+
end: 1,
|
|
15941
|
+
seasonPassType: 1
|
|
15825
15942
|
}
|
|
15826
15943
|
}
|
|
15827
15944
|
]).toArray();
|
|
@@ -15870,7 +15987,7 @@ function useVehicleRepo() {
|
|
|
15870
15987
|
throw error2;
|
|
15871
15988
|
}
|
|
15872
15989
|
}
|
|
15873
|
-
async function updateVehicle(_id, value) {
|
|
15990
|
+
async function updateVehicle(_id, value, session) {
|
|
15874
15991
|
try {
|
|
15875
15992
|
_id = new ObjectId46(_id);
|
|
15876
15993
|
} catch (error) {
|
|
@@ -15881,7 +15998,11 @@ function useVehicleRepo() {
|
|
|
15881
15998
|
...value,
|
|
15882
15999
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15883
16000
|
};
|
|
15884
|
-
const res = await collection.updateOne(
|
|
16001
|
+
const res = await collection.updateOne(
|
|
16002
|
+
{ _id },
|
|
16003
|
+
{ $set: updateValue },
|
|
16004
|
+
{ session }
|
|
16005
|
+
);
|
|
15885
16006
|
if (res.modifiedCount === 0) {
|
|
15886
16007
|
throw new InternalServerError28("Unable to update vehicle.");
|
|
15887
16008
|
}
|
|
@@ -15960,8 +16081,126 @@ function useVehicleRepo() {
|
|
|
15960
16081
|
);
|
|
15961
16082
|
}
|
|
15962
16083
|
}
|
|
16084
|
+
async function getVehiclesByNRIC({
|
|
16085
|
+
page = 1,
|
|
16086
|
+
limit = 10,
|
|
16087
|
+
search = "",
|
|
16088
|
+
sort = {}
|
|
16089
|
+
}) {
|
|
16090
|
+
page = page > 0 ? page - 1 : 0;
|
|
16091
|
+
const baseQuery = {
|
|
16092
|
+
deletedAt: ""
|
|
16093
|
+
};
|
|
16094
|
+
let query = { ...baseQuery };
|
|
16095
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
16096
|
+
const cacheOptions = {
|
|
16097
|
+
deletedAt: "",
|
|
16098
|
+
page: String(page),
|
|
16099
|
+
limit: String(limit),
|
|
16100
|
+
sort: JSON.stringify(sort)
|
|
16101
|
+
};
|
|
16102
|
+
if (search) {
|
|
16103
|
+
query.$text = { $search: search };
|
|
16104
|
+
cacheOptions.search = search;
|
|
16105
|
+
}
|
|
16106
|
+
const cacheKey = makeCacheKey26(namespace_collection, cacheOptions);
|
|
16107
|
+
const cachedData = await getCache(cacheKey);
|
|
16108
|
+
if (cachedData) {
|
|
16109
|
+
logger62.info(`Cache hit for key: ${cacheKey}`);
|
|
16110
|
+
return cachedData;
|
|
16111
|
+
}
|
|
16112
|
+
const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16113
|
+
try {
|
|
16114
|
+
let items = [];
|
|
16115
|
+
let length = 0;
|
|
16116
|
+
items = await collection.aggregate([
|
|
16117
|
+
{ $match: query },
|
|
16118
|
+
{ $sort: sort },
|
|
16119
|
+
{ $skip: page * limit },
|
|
16120
|
+
{ $limit: limit },
|
|
16121
|
+
{
|
|
16122
|
+
$project: {
|
|
16123
|
+
name: 1,
|
|
16124
|
+
phoneNumber: 1,
|
|
16125
|
+
plateNumber: 1,
|
|
16126
|
+
recNo: 1,
|
|
16127
|
+
nric: 1,
|
|
16128
|
+
status: 1,
|
|
16129
|
+
type: 1
|
|
16130
|
+
}
|
|
16131
|
+
}
|
|
16132
|
+
]).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
|
+
}
|
|
16164
|
+
const data = paginate21(items, page, limit, length);
|
|
16165
|
+
setCache(cacheKey, data, 15 * 60).then(() => logger62.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
16166
|
+
(err) => logger62.error(`Failed to set cache for key: ${cacheKey}`, err)
|
|
16167
|
+
);
|
|
16168
|
+
return data;
|
|
16169
|
+
} catch (error) {
|
|
16170
|
+
throw error;
|
|
16171
|
+
}
|
|
16172
|
+
}
|
|
16173
|
+
async function deleteExpiredVehicles(session) {
|
|
16174
|
+
try {
|
|
16175
|
+
const tenYearsAgo = /* @__PURE__ */ new Date();
|
|
16176
|
+
tenYearsAgo.setFullYear(tenYearsAgo.getFullYear() - 10);
|
|
16177
|
+
const res = await collection.updateMany(
|
|
16178
|
+
{
|
|
16179
|
+
status: { $ne: "deleted" },
|
|
16180
|
+
end: { $exists: true, $lte: tenYearsAgo }
|
|
16181
|
+
// check only end
|
|
16182
|
+
},
|
|
16183
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } },
|
|
16184
|
+
{ session }
|
|
16185
|
+
);
|
|
16186
|
+
if (res.modifiedCount === 0)
|
|
16187
|
+
throw new InternalServerError28("Unable to delete vehicle.");
|
|
16188
|
+
delNamespace().then(() => {
|
|
16189
|
+
logger62.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
16190
|
+
}).catch((err) => {
|
|
16191
|
+
logger62.error(
|
|
16192
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
16193
|
+
err
|
|
16194
|
+
);
|
|
16195
|
+
});
|
|
16196
|
+
return res.modifiedCount;
|
|
16197
|
+
} catch (error) {
|
|
16198
|
+
throw error;
|
|
16199
|
+
}
|
|
16200
|
+
}
|
|
15963
16201
|
return {
|
|
15964
16202
|
createIndex,
|
|
16203
|
+
createTextIndex,
|
|
15965
16204
|
add,
|
|
15966
16205
|
getVehicles,
|
|
15967
16206
|
getSeasonPassTypes,
|
|
@@ -15969,7 +16208,9 @@ function useVehicleRepo() {
|
|
|
15969
16208
|
updateVehicle,
|
|
15970
16209
|
deleteVehicle,
|
|
15971
16210
|
getByPlaceNumber,
|
|
15972
|
-
getVehicleByPlateNumber
|
|
16211
|
+
getVehicleByPlateNumber,
|
|
16212
|
+
getVehiclesByNRIC,
|
|
16213
|
+
deleteExpiredVehicles
|
|
15973
16214
|
};
|
|
15974
16215
|
}
|
|
15975
16216
|
|
|
@@ -16355,7 +16596,7 @@ function useDahuaService() {
|
|
|
16355
16596
|
username: Joi45.string().required(),
|
|
16356
16597
|
password: Joi45.string().required(),
|
|
16357
16598
|
plateNumber: Joi45.string().required(),
|
|
16358
|
-
mode: Joi45.string().valid(
|
|
16599
|
+
mode: Joi45.string().valid(...Object.values(ANPRMode)).required(),
|
|
16359
16600
|
start: Joi45.string().isoDate().optional().allow("", null),
|
|
16360
16601
|
end: Joi45.string().isoDate().optional().allow("", null),
|
|
16361
16602
|
owner: Joi45.string().optional().allow("", null)
|
|
@@ -16379,7 +16620,7 @@ function useDahuaService() {
|
|
|
16379
16620
|
host: value.host,
|
|
16380
16621
|
username: value.username,
|
|
16381
16622
|
password: value.password,
|
|
16382
|
-
endpoint: `/cgi-bin/recordUpdater.cgi?action=insert&name=${value.mode}&PlateNumber=${value.plateNumber}&BeginTime=${value.start}&CancelTime=${value.end}
|
|
16623
|
+
endpoint: `/cgi-bin/recordUpdater.cgi?action=insert&name=${value.mode}&PlateNumber=${value.plateNumber}&BeginTime=${value.start}&CancelTime=${value.end}&OpenGate=true&MasterOfCar=${value.owner}`
|
|
16383
16624
|
});
|
|
16384
16625
|
return response;
|
|
16385
16626
|
} catch (error2) {
|
|
@@ -16427,18 +16668,148 @@ import {
|
|
|
16427
16668
|
logger as logger64,
|
|
16428
16669
|
useAtlas as useAtlas39
|
|
16429
16670
|
} from "@7365admin1/node-server-utils";
|
|
16671
|
+
function formatDahuaDate(date) {
|
|
16672
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
16673
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
|
|
16674
|
+
date.getDate()
|
|
16675
|
+
)} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(
|
|
16676
|
+
date.getSeconds()
|
|
16677
|
+
)}`;
|
|
16678
|
+
}
|
|
16430
16679
|
function useVehicleService() {
|
|
16431
|
-
const {
|
|
16680
|
+
const {
|
|
16681
|
+
add: _add,
|
|
16682
|
+
deleteVehicle: _deleteVehicle,
|
|
16683
|
+
updateVehicle: _updateVehicle,
|
|
16684
|
+
getVehicleById: _getVehicleById,
|
|
16685
|
+
deleteExpiredVehicles: _deleteExpiredVehicles
|
|
16686
|
+
} = useVehicleRepo();
|
|
16432
16687
|
const {
|
|
16433
16688
|
addPlateNumber: _addPlateNumber,
|
|
16434
16689
|
removePlateNumber: _removePlateNumber
|
|
16435
16690
|
} = useDahuaService();
|
|
16436
16691
|
const { getAllCameraWithPassword: _getAllSiteCameras } = useSiteCameraRepo();
|
|
16692
|
+
const { getById: _getById } = useOrgRepo();
|
|
16437
16693
|
async function add(value) {
|
|
16694
|
+
const session = useAtlas39.getClient()?.startSession();
|
|
16695
|
+
if (!session)
|
|
16696
|
+
throw new Error("Unable to start session for vehicle service.");
|
|
16697
|
+
const org = await _getById(value.org);
|
|
16698
|
+
if (!org)
|
|
16699
|
+
throw new BadRequestError80("Org not found");
|
|
16700
|
+
if (!Object.values(OrgNature).includes(org.nature)) {
|
|
16701
|
+
throw new BadRequestError80(
|
|
16702
|
+
"This organization is not allowed to add vehicles."
|
|
16703
|
+
);
|
|
16704
|
+
}
|
|
16705
|
+
value.status = "active" /* ACTIVE */;
|
|
16706
|
+
const addedBySecurity = org.nature === "security_agency" /* SECURITY_AGENCY */;
|
|
16707
|
+
const addedByPM = org.nature === "property_management_agency" /* PROPERTY_MANAGEMENT_AGENCY */;
|
|
16708
|
+
if (addedBySecurity)
|
|
16709
|
+
value.status = "pending" /* PENDING */;
|
|
16710
|
+
const isBlocklist = value.type === "blocklist" /* BLOCKLIST */;
|
|
16711
|
+
if (isBlocklist)
|
|
16712
|
+
value.status = "inactive" /* INACTIVE */;
|
|
16713
|
+
const _type = value.type;
|
|
16714
|
+
const _mode = isBlocklist ? "TrafficBlackList" /* TRAFFIC_BLACKLIST */ : "TrafficRedList" /* TRAFFIC_REDLIST */;
|
|
16715
|
+
const hasStart = typeof value.start === "string" ? value.start.trim() !== "" : !!value.start;
|
|
16716
|
+
const hasEnd = typeof value.end === "string" ? value.end.trim() !== "" : !!value.end;
|
|
16717
|
+
let startDate = null;
|
|
16718
|
+
let endDate = null;
|
|
16719
|
+
let start = "";
|
|
16720
|
+
let end = "";
|
|
16721
|
+
let startDateDahua;
|
|
16722
|
+
let endDateDahua;
|
|
16723
|
+
if (addedByPM && !hasStart && !hasEnd) {
|
|
16724
|
+
startDate = /* @__PURE__ */ new Date();
|
|
16725
|
+
endDate = new Date(startDate);
|
|
16726
|
+
endDate.setFullYear(endDate.getFullYear() + 10);
|
|
16727
|
+
start = startDate.toISOString();
|
|
16728
|
+
end = endDate.toISOString();
|
|
16729
|
+
startDateDahua = formatDahuaDate(startDate);
|
|
16730
|
+
endDateDahua = formatDahuaDate(endDate);
|
|
16731
|
+
} else {
|
|
16732
|
+
if (hasStart) {
|
|
16733
|
+
startDate = new Date(value.start);
|
|
16734
|
+
start = startDate.toISOString();
|
|
16735
|
+
startDateDahua = formatDahuaDate(startDate);
|
|
16736
|
+
}
|
|
16737
|
+
if (hasEnd) {
|
|
16738
|
+
endDate = new Date(value.end);
|
|
16739
|
+
end = endDate.toISOString();
|
|
16740
|
+
endDateDahua = formatDahuaDate(endDate);
|
|
16741
|
+
}
|
|
16742
|
+
}
|
|
16743
|
+
const owner = String(value.name ?? "").substring(0, 15);
|
|
16744
|
+
try {
|
|
16745
|
+
session.startTransaction();
|
|
16746
|
+
let message = "Vehicle plate number needs approval from property management.";
|
|
16747
|
+
if (value.status && value.status !== "pending" /* PENDING */) {
|
|
16748
|
+
const siteCameras = [];
|
|
16749
|
+
let page = 1;
|
|
16750
|
+
let pages = 1;
|
|
16751
|
+
const limit = 20;
|
|
16752
|
+
do {
|
|
16753
|
+
const siteCameraReq = await _getAllSiteCameras({
|
|
16754
|
+
site: value.site,
|
|
16755
|
+
type: "anpr",
|
|
16756
|
+
direction: ["both", "entry"],
|
|
16757
|
+
page,
|
|
16758
|
+
limit
|
|
16759
|
+
});
|
|
16760
|
+
pages = siteCameraReq.pages || 1;
|
|
16761
|
+
siteCameras.push(...siteCameraReq.items);
|
|
16762
|
+
page++;
|
|
16763
|
+
} while (page < pages);
|
|
16764
|
+
if (!siteCameras.length)
|
|
16765
|
+
throw new BadRequestError80("No site cameras found.");
|
|
16766
|
+
for (const camera of siteCameras) {
|
|
16767
|
+
const { host, username, password } = camera;
|
|
16768
|
+
const dahuaPayload = {
|
|
16769
|
+
host,
|
|
16770
|
+
username,
|
|
16771
|
+
password,
|
|
16772
|
+
plateNumber: value.plateNumber,
|
|
16773
|
+
mode: _mode,
|
|
16774
|
+
owner,
|
|
16775
|
+
...startDateDahua ? { start: startDateDahua } : "",
|
|
16776
|
+
...endDateDahua ? { end: endDateDahua } : ""
|
|
16777
|
+
};
|
|
16778
|
+
const dahuaResponse = await _addPlateNumber(dahuaPayload);
|
|
16779
|
+
if (dahuaResponse?.statusCode !== 200) {
|
|
16780
|
+
throw new BadRequestError80(
|
|
16781
|
+
`Failed to add plate number to ANPR ${_type}`
|
|
16782
|
+
);
|
|
16783
|
+
}
|
|
16784
|
+
const responseData = dahuaResponse?.data.toString("utf-8");
|
|
16785
|
+
value.recNo = responseData.split("=")[1]?.trim();
|
|
16786
|
+
message = `Vehicle plate number added to ${_type} successfully.`;
|
|
16787
|
+
}
|
|
16788
|
+
}
|
|
16789
|
+
const formattedValue = {
|
|
16790
|
+
...value,
|
|
16791
|
+
start,
|
|
16792
|
+
// ISO string or ""
|
|
16793
|
+
end
|
|
16794
|
+
// ISO string or ""
|
|
16795
|
+
};
|
|
16796
|
+
await _add(formattedValue, session);
|
|
16797
|
+
await session.commitTransaction();
|
|
16798
|
+
return message;
|
|
16799
|
+
} catch (error) {
|
|
16800
|
+
logger64.error("Error in vehicle service add:", error);
|
|
16801
|
+
await session.abortTransaction();
|
|
16802
|
+
throw error;
|
|
16803
|
+
} finally {
|
|
16804
|
+
session.endSession();
|
|
16805
|
+
}
|
|
16806
|
+
}
|
|
16807
|
+
async function deleteVehicle(_id, recno, site, type, bypass = false) {
|
|
16438
16808
|
const session = useAtlas39.getClient()?.startSession();
|
|
16439
16809
|
if (!session) {
|
|
16440
16810
|
throw new Error("Unable to start session for vehicle service.");
|
|
16441
16811
|
}
|
|
16812
|
+
const _mode = type !== "whitelist" /* WHITELIST */ ? "TrafficBlackList" /* TRAFFIC_BLACKLIST */ : "TrafficRedList" /* TRAFFIC_REDLIST */;
|
|
16442
16813
|
try {
|
|
16443
16814
|
session.startTransaction();
|
|
16444
16815
|
const siteCameras = [];
|
|
@@ -16447,9 +16818,8 @@ function useVehicleService() {
|
|
|
16447
16818
|
const limit = 20;
|
|
16448
16819
|
do {
|
|
16449
16820
|
const siteCameraReq = await _getAllSiteCameras({
|
|
16450
|
-
site
|
|
16821
|
+
site,
|
|
16451
16822
|
type: "anpr",
|
|
16452
|
-
direction: ["both", "entry"],
|
|
16453
16823
|
page,
|
|
16454
16824
|
limit
|
|
16455
16825
|
});
|
|
@@ -16461,55 +16831,82 @@ function useVehicleService() {
|
|
|
16461
16831
|
throw new BadRequestError80("No site cameras found.");
|
|
16462
16832
|
}
|
|
16463
16833
|
for (const camera of siteCameras) {
|
|
16464
|
-
const
|
|
16834
|
+
const host = camera.host;
|
|
16835
|
+
const username = camera.username;
|
|
16836
|
+
const password = camera.password;
|
|
16465
16837
|
const dahuaPayload = {
|
|
16466
16838
|
host,
|
|
16467
16839
|
username,
|
|
16468
16840
|
password,
|
|
16469
|
-
|
|
16470
|
-
mode:
|
|
16471
|
-
start: value.start ? new Date(value.start).toISOString() : "",
|
|
16472
|
-
end: value.end ? new Date(value.end).toISOString() : "",
|
|
16473
|
-
owner: value.name
|
|
16841
|
+
recno,
|
|
16842
|
+
mode: _mode
|
|
16474
16843
|
};
|
|
16475
|
-
const dahuaResponse = await
|
|
16476
|
-
if (dahuaResponse?.statusCode !== 200) {
|
|
16477
|
-
throw new BadRequestError80(
|
|
16844
|
+
const dahuaResponse = await _removePlateNumber(dahuaPayload);
|
|
16845
|
+
if (!bypass && dahuaResponse?.statusCode !== 200) {
|
|
16846
|
+
throw new BadRequestError80(
|
|
16847
|
+
`Failed to remove plate number to ANPR from ${type}`
|
|
16848
|
+
);
|
|
16478
16849
|
}
|
|
16479
|
-
const responseData = dahuaResponse?.data.toString("utf-8");
|
|
16480
|
-
value.recNo = responseData.split("=")[1]?.trim();
|
|
16481
|
-
const formattedValue = {
|
|
16482
|
-
...value,
|
|
16483
|
-
start: value.start ? new Date(value.start).toISOString() : "",
|
|
16484
|
-
end: value.end ? new Date(value.end).toISOString() : ""
|
|
16485
|
-
};
|
|
16486
|
-
await _add(formattedValue, session);
|
|
16487
16850
|
}
|
|
16851
|
+
await _deleteVehicle(_id, session);
|
|
16488
16852
|
await session.commitTransaction();
|
|
16489
|
-
return
|
|
16853
|
+
return `Vehicle plate number deleted from ${type} record successfully.`;
|
|
16490
16854
|
} catch (error) {
|
|
16491
|
-
logger64.error("Error in vehicle service add:", error);
|
|
16492
16855
|
await session.abortTransaction();
|
|
16493
|
-
|
|
16856
|
+
if (error instanceof AppError14)
|
|
16857
|
+
throw error;
|
|
16858
|
+
throw new InternalServerError29("Failed to delete vehicle");
|
|
16494
16859
|
} finally {
|
|
16495
16860
|
session.endSession();
|
|
16496
16861
|
}
|
|
16497
16862
|
}
|
|
16498
|
-
async function
|
|
16863
|
+
async function approveVehicleById(id, orgId, siteId) {
|
|
16499
16864
|
const session = useAtlas39.getClient()?.startSession();
|
|
16500
16865
|
if (!session) {
|
|
16501
16866
|
throw new Error("Unable to start session for vehicle service.");
|
|
16502
16867
|
}
|
|
16868
|
+
const org = await _getById(orgId);
|
|
16869
|
+
if (!org)
|
|
16870
|
+
throw new BadRequestError80("Org not found");
|
|
16871
|
+
const allowedNatures2 = ["property_management_agency"];
|
|
16872
|
+
if (!allowedNatures2.includes(org.nature)) {
|
|
16873
|
+
throw new BadRequestError80(
|
|
16874
|
+
"Only property management can approve vehicles."
|
|
16875
|
+
);
|
|
16876
|
+
}
|
|
16877
|
+
const vehicle = await _getVehicleById(id);
|
|
16878
|
+
if (!vehicle) {
|
|
16879
|
+
throw new BadRequestError80("Vehicle not found");
|
|
16880
|
+
}
|
|
16881
|
+
const owner = vehicle.name.substring(0, 15);
|
|
16882
|
+
const hasStart = typeof vehicle.start === "string" ? vehicle.start.trim() !== "" : !!vehicle.start;
|
|
16883
|
+
const hasEnd = typeof vehicle.end === "string" ? vehicle.end.trim() !== "" : !!vehicle.end;
|
|
16884
|
+
let startDate = null;
|
|
16885
|
+
let endDate = null;
|
|
16886
|
+
if (!hasStart && !hasEnd) {
|
|
16887
|
+
startDate = /* @__PURE__ */ new Date();
|
|
16888
|
+
endDate = new Date(startDate);
|
|
16889
|
+
endDate.setFullYear(endDate.getFullYear() + 10);
|
|
16890
|
+
} else {
|
|
16891
|
+
startDate = hasStart ? new Date(vehicle.start) : null;
|
|
16892
|
+
endDate = hasEnd ? new Date(vehicle.end) : null;
|
|
16893
|
+
}
|
|
16894
|
+
const startIso = startDate ? startDate.toISOString() : "";
|
|
16895
|
+
const endIso = endDate ? endDate.toISOString() : "";
|
|
16896
|
+
const startDahua = startDate ? formatDahuaDate(startDate) : "";
|
|
16897
|
+
const endDahua = endDate ? formatDahuaDate(endDate) : "";
|
|
16503
16898
|
try {
|
|
16504
16899
|
session.startTransaction();
|
|
16505
16900
|
const siteCameras = [];
|
|
16506
16901
|
let page = 1;
|
|
16507
16902
|
let pages = 1;
|
|
16508
16903
|
const limit = 20;
|
|
16904
|
+
let value = {};
|
|
16509
16905
|
do {
|
|
16510
16906
|
const siteCameraReq = await _getAllSiteCameras({
|
|
16511
|
-
site,
|
|
16907
|
+
site: siteId,
|
|
16512
16908
|
type: "anpr",
|
|
16909
|
+
direction: ["both", "entry"],
|
|
16513
16910
|
page,
|
|
16514
16911
|
limit
|
|
16515
16912
|
});
|
|
@@ -16521,24 +16918,51 @@ function useVehicleService() {
|
|
|
16521
16918
|
throw new BadRequestError80("No site cameras found.");
|
|
16522
16919
|
}
|
|
16523
16920
|
for (const camera of siteCameras) {
|
|
16524
|
-
const host = camera
|
|
16525
|
-
const username = camera.username;
|
|
16526
|
-
const password = camera.password;
|
|
16921
|
+
const { host, username, password } = camera;
|
|
16527
16922
|
const dahuaPayload = {
|
|
16528
16923
|
host,
|
|
16529
16924
|
username,
|
|
16530
16925
|
password,
|
|
16531
|
-
|
|
16532
|
-
mode: "TrafficRedList"
|
|
16926
|
+
plateNumber: vehicle.plateNumber,
|
|
16927
|
+
mode: "TrafficRedList" /* TRAFFIC_REDLIST */,
|
|
16928
|
+
start: startDahua,
|
|
16929
|
+
end: endDahua,
|
|
16930
|
+
owner
|
|
16533
16931
|
};
|
|
16534
|
-
const dahuaResponse = await
|
|
16535
|
-
if (
|
|
16536
|
-
throw new BadRequestError80("Failed to
|
|
16932
|
+
const dahuaResponse = await _addPlateNumber(dahuaPayload);
|
|
16933
|
+
if (dahuaResponse?.statusCode !== 200) {
|
|
16934
|
+
throw new BadRequestError80("Failed to add plate number to ANPR");
|
|
16537
16935
|
}
|
|
16936
|
+
const responseData = dahuaResponse?.data.toString("utf-8");
|
|
16937
|
+
value.recNo = responseData.split("=")[1]?.trim();
|
|
16538
16938
|
}
|
|
16539
|
-
|
|
16939
|
+
value.status = "active";
|
|
16940
|
+
const formattedValue = {
|
|
16941
|
+
...value,
|
|
16942
|
+
start: startIso,
|
|
16943
|
+
end: endIso
|
|
16944
|
+
};
|
|
16945
|
+
await _updateVehicle(id, formattedValue, session);
|
|
16946
|
+
await session.commitTransaction();
|
|
16947
|
+
return "Vehicle plate number approved and added successfully.";
|
|
16948
|
+
} catch (error) {
|
|
16949
|
+
logger64.error("Error in vehicle service add:", error);
|
|
16950
|
+
await session.abortTransaction();
|
|
16951
|
+
throw error;
|
|
16952
|
+
} finally {
|
|
16953
|
+
session.endSession();
|
|
16954
|
+
}
|
|
16955
|
+
}
|
|
16956
|
+
async function processDeletingExpiredVehicles() {
|
|
16957
|
+
const session = useAtlas39.getClient()?.startSession();
|
|
16958
|
+
if (!session) {
|
|
16959
|
+
throw new Error("Unable to start session for vehicle service.");
|
|
16960
|
+
}
|
|
16961
|
+
try {
|
|
16962
|
+
session.startTransaction();
|
|
16963
|
+
await _deleteExpiredVehicles();
|
|
16540
16964
|
await session.commitTransaction();
|
|
16541
|
-
return
|
|
16965
|
+
return `Expired Vehicle plate numbers deleted successfully.`;
|
|
16542
16966
|
} catch (error) {
|
|
16543
16967
|
await session.abortTransaction();
|
|
16544
16968
|
if (error instanceof AppError14)
|
|
@@ -16550,7 +16974,9 @@ function useVehicleService() {
|
|
|
16550
16974
|
}
|
|
16551
16975
|
return {
|
|
16552
16976
|
add,
|
|
16553
|
-
deleteVehicle
|
|
16977
|
+
deleteVehicle,
|
|
16978
|
+
approveVehicleById,
|
|
16979
|
+
processDeletingExpiredVehicles
|
|
16554
16980
|
};
|
|
16555
16981
|
}
|
|
16556
16982
|
|
|
@@ -16558,12 +16984,17 @@ function useVehicleService() {
|
|
|
16558
16984
|
import { BadRequestError as BadRequestError81, logger as logger65 } from "@7365admin1/node-server-utils";
|
|
16559
16985
|
import Joi46 from "joi";
|
|
16560
16986
|
function useVehicleController() {
|
|
16561
|
-
const {
|
|
16987
|
+
const {
|
|
16988
|
+
add: _add,
|
|
16989
|
+
deleteVehicle: _deleteVehicle,
|
|
16990
|
+
approveVehicleById: _approveVehicleById
|
|
16991
|
+
} = useVehicleService();
|
|
16562
16992
|
const {
|
|
16563
16993
|
getSeasonPassTypes: _getSeasonPassTypes,
|
|
16564
16994
|
getVehicles: _getVehicles,
|
|
16565
16995
|
getVehicleById: _getVehicleById,
|
|
16566
|
-
updateVehicle: _updateVehicle
|
|
16996
|
+
updateVehicle: _updateVehicle,
|
|
16997
|
+
getVehiclesByNRIC: _getVehiclesByNRIC
|
|
16567
16998
|
} = useVehicleRepo();
|
|
16568
16999
|
async function add(req, res, next) {
|
|
16569
17000
|
const payload = req.body;
|
|
@@ -16594,8 +17025,9 @@ function useVehicleController() {
|
|
|
16594
17025
|
limit: Joi46.number().integer().min(1).max(100).allow("", null).default(10),
|
|
16595
17026
|
sort: Joi46.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
16596
17027
|
order: Joi46.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
16597
|
-
type: Joi46.string().optional().
|
|
16598
|
-
category: Joi46.string().optional().
|
|
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("")
|
|
16599
17031
|
});
|
|
16600
17032
|
const query = { ...req.query };
|
|
16601
17033
|
const { error } = validation.validate(query);
|
|
@@ -16609,6 +17041,7 @@ function useVehicleController() {
|
|
|
16609
17041
|
const limit = parseInt(req.query.limit ?? "10");
|
|
16610
17042
|
const type = req.query.type ?? "";
|
|
16611
17043
|
const category = req.query.category ?? "";
|
|
17044
|
+
const status = req.query.status ?? "";
|
|
16612
17045
|
const sortObj = {};
|
|
16613
17046
|
const sortFields = String(req.query.sort).split(",");
|
|
16614
17047
|
const sortOrders = String(req.query.order).split(",");
|
|
@@ -16625,7 +17058,8 @@ function useVehicleController() {
|
|
|
16625
17058
|
limit,
|
|
16626
17059
|
sort: sortObj,
|
|
16627
17060
|
type,
|
|
16628
|
-
category
|
|
17061
|
+
category,
|
|
17062
|
+
status
|
|
16629
17063
|
});
|
|
16630
17064
|
res.json(data);
|
|
16631
17065
|
return;
|
|
@@ -16681,7 +17115,8 @@ function useVehicleController() {
|
|
|
16681
17115
|
block: Joi46.number().integer().optional().allow(0, null),
|
|
16682
17116
|
level: Joi46.string().optional().allow("", null),
|
|
16683
17117
|
unit: Joi46.string().optional().allow("", null),
|
|
16684
|
-
plateNumber: Joi46.string().optional().allow("", null)
|
|
17118
|
+
plateNumber: Joi46.string().optional().allow("", null),
|
|
17119
|
+
nric: Joi46.string().optional().allow("", null)
|
|
16685
17120
|
});
|
|
16686
17121
|
const _id = req.params.id;
|
|
16687
17122
|
const payload = { ...req.body };
|
|
@@ -16702,23 +17137,23 @@ function useVehicleController() {
|
|
|
16702
17137
|
}
|
|
16703
17138
|
}
|
|
16704
17139
|
async function deleteVehicle(req, res, next) {
|
|
16705
|
-
const
|
|
16706
|
-
const _id = req.params.id ?? "";
|
|
16707
|
-
const recno = req.params.recno ?? "";
|
|
16708
|
-
const bypass = req.query.bypass === "true";
|
|
17140
|
+
const _id = req.params.id;
|
|
16709
17141
|
const deleteVehicleSchema = Joi46.object({
|
|
16710
|
-
_id: Joi46.string().hex().required(),
|
|
17142
|
+
_id: Joi46.string().hex().length(24).required(),
|
|
16711
17143
|
recno: Joi46.string().required(),
|
|
16712
|
-
|
|
17144
|
+
site: Joi46.string().hex().length(24).required(),
|
|
17145
|
+
type: Joi46.string().valid("whitelist", "blocklist").required(),
|
|
17146
|
+
bypass: Joi46.boolean().optional().default(true)
|
|
16713
17147
|
});
|
|
16714
|
-
const { error } = deleteVehicleSchema.validate({ _id,
|
|
17148
|
+
const { error, value } = deleteVehicleSchema.validate({ _id, ...req.body });
|
|
16715
17149
|
if (error) {
|
|
16716
17150
|
logger65.log({ level: "error", message: error.message });
|
|
16717
17151
|
next(new BadRequestError81(error.message));
|
|
16718
17152
|
return;
|
|
16719
17153
|
}
|
|
17154
|
+
const { recno, site, type, bypass } = value;
|
|
16720
17155
|
try {
|
|
16721
|
-
const data = await _deleteVehicle(_id, recno, site, bypass);
|
|
17156
|
+
const data = await _deleteVehicle(_id, recno, site, type, bypass);
|
|
16722
17157
|
res.json({
|
|
16723
17158
|
message: "Vehicle deleted successfully.",
|
|
16724
17159
|
data
|
|
@@ -16729,13 +17164,83 @@ function useVehicleController() {
|
|
|
16729
17164
|
return;
|
|
16730
17165
|
}
|
|
16731
17166
|
}
|
|
17167
|
+
async function approveVehicleById(req, res, next) {
|
|
17168
|
+
const validation = Joi46.object({
|
|
17169
|
+
_id: Joi46.string().hex().length(24).required(),
|
|
17170
|
+
org: Joi46.string().hex().length(24).required(),
|
|
17171
|
+
site: Joi46.string().hex().length(24).required()
|
|
17172
|
+
});
|
|
17173
|
+
const _id = req.params.id;
|
|
17174
|
+
const payload = { ...req.body };
|
|
17175
|
+
const { error, value } = validation.validate({ _id, ...payload });
|
|
17176
|
+
if (error) {
|
|
17177
|
+
logger65.log({ level: "error", message: error.message });
|
|
17178
|
+
next(new BadRequestError81(error.message));
|
|
17179
|
+
return;
|
|
17180
|
+
}
|
|
17181
|
+
try {
|
|
17182
|
+
await _approveVehicleById(value._id, value.org, value.site);
|
|
17183
|
+
res.json({ message: "Successfully approved and updated vehicle." });
|
|
17184
|
+
return;
|
|
17185
|
+
} catch (error2) {
|
|
17186
|
+
logger65.log({ level: "error", message: error2.message });
|
|
17187
|
+
next(error2);
|
|
17188
|
+
return;
|
|
17189
|
+
}
|
|
17190
|
+
}
|
|
17191
|
+
async function getVehiclesByNRIC(req, res, next) {
|
|
17192
|
+
const allowedFields = ["start", "end"];
|
|
17193
|
+
const allowedOrder = ["asc", "desc"];
|
|
17194
|
+
const validation = Joi46.object({
|
|
17195
|
+
search: Joi46.string().optional().allow("", null),
|
|
17196
|
+
page: Joi46.number().integer().min(1).allow("", null).default(1),
|
|
17197
|
+
limit: Joi46.number().integer().min(1).max(100).allow("", null).default(10),
|
|
17198
|
+
sort: Joi46.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
17199
|
+
order: Joi46.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder)
|
|
17200
|
+
});
|
|
17201
|
+
const query = { ...req.query };
|
|
17202
|
+
const { error } = validation.validate(query);
|
|
17203
|
+
if (error) {
|
|
17204
|
+
logger65.log({ level: "error", message: error.message });
|
|
17205
|
+
next(new BadRequestError81(error.message));
|
|
17206
|
+
return;
|
|
17207
|
+
}
|
|
17208
|
+
const search = req.query.search ?? "";
|
|
17209
|
+
const page = parseInt(req.query.page ?? "1");
|
|
17210
|
+
const limit = parseInt(req.query.limit ?? "10");
|
|
17211
|
+
const sortObj = {};
|
|
17212
|
+
const sortFields = String(req.query.sort).split(",");
|
|
17213
|
+
const sortOrders = String(req.query.order).split(",");
|
|
17214
|
+
sortFields.forEach((field, index) => {
|
|
17215
|
+
if (allowedFields.includes(field)) {
|
|
17216
|
+
const order = sortOrders[index] === "asc" ? 1 : -1;
|
|
17217
|
+
sortObj[field] = order;
|
|
17218
|
+
}
|
|
17219
|
+
});
|
|
17220
|
+
try {
|
|
17221
|
+
const data = await _getVehiclesByNRIC({
|
|
17222
|
+
search,
|
|
17223
|
+
page,
|
|
17224
|
+
limit,
|
|
17225
|
+
sort: sortObj
|
|
17226
|
+
});
|
|
17227
|
+
res.json(data);
|
|
17228
|
+
return;
|
|
17229
|
+
} catch (error2) {
|
|
17230
|
+
logger65.log({ level: "error", message: error2.message });
|
|
17231
|
+
next(error2);
|
|
17232
|
+
return;
|
|
17233
|
+
}
|
|
17234
|
+
}
|
|
16732
17235
|
return {
|
|
16733
17236
|
add,
|
|
16734
17237
|
getVehicles,
|
|
16735
17238
|
getSeasonPassTypes,
|
|
16736
17239
|
getVehicleById,
|
|
16737
17240
|
updateVehicle,
|
|
16738
|
-
deleteVehicle
|
|
17241
|
+
deleteVehicle,
|
|
17242
|
+
approveVehicleById,
|
|
17243
|
+
getVehiclesByNRIC
|
|
16739
17244
|
};
|
|
16740
17245
|
}
|
|
16741
17246
|
|
|
@@ -16837,7 +17342,7 @@ function useSiteCameraController() {
|
|
|
16837
17342
|
}
|
|
16838
17343
|
async function getAll(req, res, next) {
|
|
16839
17344
|
const query = req.query;
|
|
16840
|
-
const
|
|
17345
|
+
const allowedTypes = ["ip", "exit", "entry", "both"];
|
|
16841
17346
|
const validation = Joi47.object({
|
|
16842
17347
|
type: Joi47.string().optional(),
|
|
16843
17348
|
site: Joi47.string().optional(),
|
|
@@ -24322,20 +24827,19 @@ function useDocumentManagementController() {
|
|
|
24322
24827
|
// src/models/bulletin-board.model.ts
|
|
24323
24828
|
import Joi75 from "joi";
|
|
24324
24829
|
import { ObjectId as ObjectId71 } from "mongodb";
|
|
24830
|
+
var BULLETIN_RECIPIENTS = [
|
|
24831
|
+
"resident",
|
|
24832
|
+
"security_agency",
|
|
24833
|
+
"cleaning_services",
|
|
24834
|
+
"mechanical_electrical",
|
|
24835
|
+
"property_management_agency"
|
|
24836
|
+
];
|
|
24837
|
+
var STATUS_VALUES = ["active", "expired", "deleted"];
|
|
24325
24838
|
var schemaBulletinBoard = Joi75.object({
|
|
24326
24839
|
_id: Joi75.string().hex().optional().allow("", null),
|
|
24327
24840
|
site: Joi75.string().hex().optional().allow("", null),
|
|
24328
24841
|
orgId: Joi75.string().hex().optional().allow("", null),
|
|
24329
|
-
recipients: Joi75.array().items(
|
|
24330
|
-
Joi75.string().valid(
|
|
24331
|
-
"admin",
|
|
24332
|
-
"organization",
|
|
24333
|
-
"site",
|
|
24334
|
-
"service-provider",
|
|
24335
|
-
"service-provider-member",
|
|
24336
|
-
"resident"
|
|
24337
|
-
)
|
|
24338
|
-
).optional(),
|
|
24842
|
+
recipients: Joi75.array().items(Joi75.string().valid(...BULLETIN_RECIPIENTS)).unique().optional(),
|
|
24339
24843
|
title: Joi75.string().optional().allow("", null),
|
|
24340
24844
|
content: Joi75.string().optional().allow("", null),
|
|
24341
24845
|
file: Joi75.array().items(
|
|
@@ -24348,23 +24852,14 @@ var schemaBulletinBoard = Joi75.object({
|
|
|
24348
24852
|
noExpiration: Joi75.boolean().optional(),
|
|
24349
24853
|
startDate: Joi75.date().optional().allow("", null),
|
|
24350
24854
|
endDate: Joi75.date().optional().allow("", null),
|
|
24351
|
-
status: Joi75.string().
|
|
24855
|
+
status: Joi75.string().valid(...STATUS_VALUES).optional(),
|
|
24352
24856
|
createdAt: Joi75.date().optional().allow(null),
|
|
24353
24857
|
updatedAt: Joi75.date().optional().allow(null),
|
|
24354
24858
|
deletedAt: Joi75.date().optional().allow(null)
|
|
24355
24859
|
});
|
|
24356
24860
|
var schemaUpdateBulletinBoard = Joi75.object({
|
|
24357
24861
|
_id: Joi75.string().hex().required(),
|
|
24358
|
-
recipients: Joi75.array().items(
|
|
24359
|
-
Joi75.string().valid(
|
|
24360
|
-
"admin",
|
|
24361
|
-
"organization",
|
|
24362
|
-
"site",
|
|
24363
|
-
"service-provider",
|
|
24364
|
-
"service-provider-member",
|
|
24365
|
-
"resident"
|
|
24366
|
-
)
|
|
24367
|
-
).optional(),
|
|
24862
|
+
recipients: Joi75.array().items(Joi75.string().valid(...BULLETIN_RECIPIENTS)).unique().optional(),
|
|
24368
24863
|
title: Joi75.string().optional().allow("", null),
|
|
24369
24864
|
content: Joi75.string().optional().allow("", null),
|
|
24370
24865
|
file: Joi75.array().items(
|
|
@@ -24377,7 +24872,7 @@ var schemaUpdateBulletinBoard = Joi75.object({
|
|
|
24377
24872
|
noExpiration: Joi75.boolean().optional(),
|
|
24378
24873
|
startDate: Joi75.date().optional().allow("", null),
|
|
24379
24874
|
endDate: Joi75.date().optional().allow("", null),
|
|
24380
|
-
status: Joi75.string().
|
|
24875
|
+
status: Joi75.string().valid(...STATUS_VALUES).optional()
|
|
24381
24876
|
});
|
|
24382
24877
|
function MBulletinBoard(value) {
|
|
24383
24878
|
const { error } = schemaBulletinBoard.validate(value);
|
|
@@ -24477,7 +24972,8 @@ function useBulletinBoardRepo() {
|
|
|
24477
24972
|
limit = 10,
|
|
24478
24973
|
sort = {},
|
|
24479
24974
|
site = "",
|
|
24480
|
-
status = "active"
|
|
24975
|
+
status = "active",
|
|
24976
|
+
recipients = []
|
|
24481
24977
|
}, session) {
|
|
24482
24978
|
page = page > 0 ? page - 1 : 0;
|
|
24483
24979
|
try {
|
|
@@ -24487,7 +24983,9 @@ function useBulletinBoardRepo() {
|
|
|
24487
24983
|
}
|
|
24488
24984
|
const query = {
|
|
24489
24985
|
site,
|
|
24490
|
-
status
|
|
24986
|
+
status,
|
|
24987
|
+
...search && { $text: { $search: search } },
|
|
24988
|
+
...recipients?.length && { recipients: { $in: recipients } }
|
|
24491
24989
|
};
|
|
24492
24990
|
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
24493
24991
|
const cacheOptions = {
|
|
@@ -24495,12 +24993,10 @@ function useBulletinBoardRepo() {
|
|
|
24495
24993
|
status,
|
|
24496
24994
|
sort: JSON.stringify(sort),
|
|
24497
24995
|
page,
|
|
24498
|
-
limit
|
|
24996
|
+
limit,
|
|
24997
|
+
...search && { search },
|
|
24998
|
+
...recipients?.length && { recipients: recipients.sort().join(",") }
|
|
24499
24999
|
};
|
|
24500
|
-
if (search) {
|
|
24501
|
-
query.$text = { $search: search };
|
|
24502
|
-
cacheOptions.search = search;
|
|
24503
|
-
}
|
|
24504
25000
|
const cacheKey = makeCacheKey39(namespace_collection, cacheOptions);
|
|
24505
25001
|
const cachedData = await getCache(cacheKey);
|
|
24506
25002
|
if (cachedData) {
|
|
@@ -24592,7 +25088,7 @@ function useBulletinBoardRepo() {
|
|
|
24592
25088
|
throw error;
|
|
24593
25089
|
}
|
|
24594
25090
|
}
|
|
24595
|
-
async function deleteBulletinBoardById(_id) {
|
|
25091
|
+
async function deleteBulletinBoardById(_id, session) {
|
|
24596
25092
|
try {
|
|
24597
25093
|
_id = new ObjectId72(_id);
|
|
24598
25094
|
} catch (error) {
|
|
@@ -24604,7 +25100,11 @@ function useBulletinBoardRepo() {
|
|
|
24604
25100
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24605
25101
|
deletedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24606
25102
|
};
|
|
24607
|
-
const res = await collection.updateOne(
|
|
25103
|
+
const res = await collection.updateOne(
|
|
25104
|
+
{ _id },
|
|
25105
|
+
{ $set: updateValue },
|
|
25106
|
+
{ session }
|
|
25107
|
+
);
|
|
24608
25108
|
if (res.modifiedCount === 0) {
|
|
24609
25109
|
throw new InternalServerError42("Unable to delete bulletin board.");
|
|
24610
25110
|
}
|
|
@@ -24670,8 +25170,11 @@ function useBulletinBoardService() {
|
|
|
24670
25170
|
const {
|
|
24671
25171
|
add: _add,
|
|
24672
25172
|
updateBulletinBoardById: _updateBulletinBoardById,
|
|
24673
|
-
processExpiredBulletinBoards: _processExpiredBulletinBoards
|
|
25173
|
+
processExpiredBulletinBoards: _processExpiredBulletinBoards,
|
|
25174
|
+
deleteBulletinBoardById: _deleteBulletinBoardById,
|
|
25175
|
+
getBulletinBoardById: _getBulletinBoardById
|
|
24674
25176
|
} = useBulletinBoardRepo();
|
|
25177
|
+
const { deleteFileById: _deleteFileById } = useFileRepo();
|
|
24675
25178
|
async function add(value) {
|
|
24676
25179
|
const session = useAtlas65.getClient()?.startSession();
|
|
24677
25180
|
session?.startTransaction();
|
|
@@ -24714,10 +25217,31 @@ function useBulletinBoardService() {
|
|
|
24714
25217
|
session?.endSession();
|
|
24715
25218
|
}
|
|
24716
25219
|
}
|
|
25220
|
+
async function deleteBulletinBoardById(id) {
|
|
25221
|
+
const session = useAtlas65.getClient()?.startSession();
|
|
25222
|
+
session?.startTransaction();
|
|
25223
|
+
try {
|
|
25224
|
+
const existingBulletinBoard = await _getBulletinBoardById(id);
|
|
25225
|
+
if (Array.isArray(existingBulletinBoard.file)) {
|
|
25226
|
+
for (const file of existingBulletinBoard.file) {
|
|
25227
|
+
await _deleteFileById(file, session);
|
|
25228
|
+
}
|
|
25229
|
+
}
|
|
25230
|
+
await _deleteBulletinBoardById(id, session);
|
|
25231
|
+
await session?.commitTransaction();
|
|
25232
|
+
return "Successfully deleted bulletin board.";
|
|
25233
|
+
} catch (error) {
|
|
25234
|
+
await session?.abortTransaction();
|
|
25235
|
+
throw error;
|
|
25236
|
+
} finally {
|
|
25237
|
+
session?.endSession();
|
|
25238
|
+
}
|
|
25239
|
+
}
|
|
24717
25240
|
return {
|
|
24718
25241
|
add,
|
|
24719
25242
|
updateBulletinBoardById,
|
|
24720
|
-
processExpiredBulletinBoards
|
|
25243
|
+
processExpiredBulletinBoards,
|
|
25244
|
+
deleteBulletinBoardById
|
|
24721
25245
|
};
|
|
24722
25246
|
}
|
|
24723
25247
|
|
|
@@ -24725,12 +25249,12 @@ function useBulletinBoardService() {
|
|
|
24725
25249
|
import { BadRequestError as BadRequestError123, logger as logger104 } from "@7365admin1/node-server-utils";
|
|
24726
25250
|
import Joi76 from "joi";
|
|
24727
25251
|
function useBulletinBoardController() {
|
|
24728
|
-
const { add: _add, updateBulletinBoardById: _updateBulletinBoardById } = useBulletinBoardService();
|
|
24729
25252
|
const {
|
|
24730
|
-
|
|
24731
|
-
|
|
25253
|
+
add: _add,
|
|
25254
|
+
updateBulletinBoardById: _updateBulletinBoardById,
|
|
24732
25255
|
deleteBulletinBoardById: _deleteBulletinBoardById
|
|
24733
|
-
} =
|
|
25256
|
+
} = useBulletinBoardService();
|
|
25257
|
+
const { getAll: _getAll, getBulletinBoardById: _getBulletinBoardById } = useBulletinBoardRepo();
|
|
24734
25258
|
async function add(req, res, next) {
|
|
24735
25259
|
const payload = { ...req.body };
|
|
24736
25260
|
const { error } = schemaBulletinBoard.validate(payload, {
|
|
@@ -24762,12 +25286,23 @@ function useBulletinBoardController() {
|
|
|
24762
25286
|
sort: Joi76.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
24763
25287
|
order: Joi76.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
24764
25288
|
site: Joi76.string().hex().required(),
|
|
24765
|
-
status: Joi76.string().optional().allow(null, "")
|
|
25289
|
+
status: Joi76.string().optional().allow(null, ""),
|
|
25290
|
+
recipients: Joi76.string().optional().allow("", null).custom((value, helpers) => {
|
|
25291
|
+
const parsed = value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
25292
|
+
for (const r of parsed) {
|
|
25293
|
+
if (!BULLETIN_RECIPIENTS.includes(r)) {
|
|
25294
|
+
return helpers.error("any.only");
|
|
25295
|
+
}
|
|
25296
|
+
}
|
|
25297
|
+
return value;
|
|
25298
|
+
}).messages({
|
|
25299
|
+
"any.only": `Recipients must be one of: ${BULLETIN_RECIPIENTS.join(
|
|
25300
|
+
", "
|
|
25301
|
+
)}`
|
|
25302
|
+
})
|
|
24766
25303
|
});
|
|
24767
25304
|
const query = { ...req.query };
|
|
24768
|
-
const { error } = validation.validate(query, {
|
|
24769
|
-
abortEarly: false
|
|
24770
|
-
});
|
|
25305
|
+
const { error } = validation.validate(query, { abortEarly: false });
|
|
24771
25306
|
if (error) {
|
|
24772
25307
|
const messages = error.details.map((d) => d.message).join(", ");
|
|
24773
25308
|
logger104.log({ level: "error", message: messages });
|
|
@@ -24779,9 +25314,15 @@ function useBulletinBoardController() {
|
|
|
24779
25314
|
const limit = parseInt(req.query.limit ?? "10");
|
|
24780
25315
|
const site = req.query.site ?? "";
|
|
24781
25316
|
const status = req.query.status ?? "active";
|
|
25317
|
+
const recipientsRaw = req.query.recipients ?? "";
|
|
25318
|
+
const recipients = recipientsRaw && typeof recipientsRaw === "string" ? Array.from(
|
|
25319
|
+
new Set(
|
|
25320
|
+
recipientsRaw.split(",").map((r) => r.trim()).filter(Boolean)
|
|
25321
|
+
)
|
|
25322
|
+
) : [];
|
|
24782
25323
|
const sortObj = {};
|
|
24783
|
-
const sortFields = String(req.query.sort).split(",");
|
|
24784
|
-
const sortOrders = String(req.query.order).split(",");
|
|
25324
|
+
const sortFields = String(req.query.sort ?? "").split(",").filter(Boolean);
|
|
25325
|
+
const sortOrders = String(req.query.order ?? "").split(",").filter(Boolean);
|
|
24785
25326
|
sortFields.forEach((field, index) => {
|
|
24786
25327
|
if (allowedFields.includes(field)) {
|
|
24787
25328
|
const order = sortOrders[index] === "asc" ? 1 : -1;
|
|
@@ -24795,7 +25336,8 @@ function useBulletinBoardController() {
|
|
|
24795
25336
|
limit,
|
|
24796
25337
|
sort: sortObj,
|
|
24797
25338
|
site,
|
|
24798
|
-
status
|
|
25339
|
+
status,
|
|
25340
|
+
recipients
|
|
24799
25341
|
});
|
|
24800
25342
|
res.status(200).json(data);
|
|
24801
25343
|
return;
|
|
@@ -24878,6 +25420,16 @@ function useBulletinBoardController() {
|
|
|
24878
25420
|
import { BadRequestError as BadRequestError124, logger as logger105 } from "@7365admin1/node-server-utils";
|
|
24879
25421
|
import { ObjectId as ObjectId73 } from "mongodb";
|
|
24880
25422
|
import Joi77 from "joi";
|
|
25423
|
+
|
|
25424
|
+
// src/types/enums/billing-frequency.enum.ts
|
|
25425
|
+
var EBillingFrequency = /* @__PURE__ */ ((EBillingFrequency2) => {
|
|
25426
|
+
EBillingFrequency2["MONTHLY"] = "monthly";
|
|
25427
|
+
EBillingFrequency2["QAURTERLY"] = "quarterly";
|
|
25428
|
+
EBillingFrequency2["ANNUALLY"] = "annually";
|
|
25429
|
+
return EBillingFrequency2;
|
|
25430
|
+
})(EBillingFrequency || {});
|
|
25431
|
+
|
|
25432
|
+
// src/models/site-billing-item.model.ts
|
|
24881
25433
|
var schemaUnits = Joi77.object({
|
|
24882
25434
|
_id: Joi77.string().hex().optional(),
|
|
24883
25435
|
name: Joi77.string().optional()
|
|
@@ -24888,7 +25440,7 @@ var schemaBillingItem = Joi77.object({
|
|
|
24888
25440
|
org: Joi77.string().hex().required(),
|
|
24889
25441
|
name: Joi77.string().required(),
|
|
24890
25442
|
amount: Joi77.number().required(),
|
|
24891
|
-
frequency: Joi77.string().valid(
|
|
25443
|
+
frequency: Joi77.string().valid(...Object.values(EBillingFrequency)).required(),
|
|
24892
25444
|
billingType: Joi77.string().valid("recurring", "non-recurring").required(),
|
|
24893
25445
|
dueInDays: Joi77.number().optional().allow(null, ""),
|
|
24894
25446
|
date: Joi77.string().required(),
|
|
@@ -24913,7 +25465,7 @@ var schemaUpdateSiteBillingItem = Joi77.object({
|
|
|
24913
25465
|
org: Joi77.string().hex().optional().allow(null, ""),
|
|
24914
25466
|
name: Joi77.string().optional().allow(null, ""),
|
|
24915
25467
|
amount: Joi77.number().optional().allow(null, ""),
|
|
24916
|
-
frequency: Joi77.string().valid(
|
|
25468
|
+
frequency: Joi77.string().valid(...Object.values(EBillingFrequency)).optional().allow(null, ""),
|
|
24917
25469
|
billingType: Joi77.string().valid("recurring", "non-recurring").optional().allow(null, ""),
|
|
24918
25470
|
dueInDays: Joi77.number().optional().allow(null, ""),
|
|
24919
25471
|
date: Joi77.string().optional().allow(null, ""),
|
|
@@ -25067,7 +25619,16 @@ function useSiteBillingItemRepo() {
|
|
|
25067
25619
|
...search && {
|
|
25068
25620
|
$or: [
|
|
25069
25621
|
{ name: { $regex: search, $options: "i" } },
|
|
25070
|
-
{ frequency: { $regex: search, $options: "i" } }
|
|
25622
|
+
{ frequency: { $regex: search, $options: "i" } },
|
|
25623
|
+
{
|
|
25624
|
+
$expr: {
|
|
25625
|
+
$regexMatch: {
|
|
25626
|
+
input: { $toString: "$totalAmount" },
|
|
25627
|
+
regex: search,
|
|
25628
|
+
options: "i"
|
|
25629
|
+
}
|
|
25630
|
+
}
|
|
25631
|
+
}
|
|
25071
25632
|
]
|
|
25072
25633
|
},
|
|
25073
25634
|
...ObjectId74.isValid(site) && { site: new ObjectId74(site) }
|
|
@@ -26243,7 +26804,8 @@ function useEventManagementRepo() {
|
|
|
26243
26804
|
sort = {},
|
|
26244
26805
|
site = "",
|
|
26245
26806
|
status = "",
|
|
26246
|
-
type = ""
|
|
26807
|
+
type = "",
|
|
26808
|
+
date = ""
|
|
26247
26809
|
}, session) {
|
|
26248
26810
|
page = page > 0 ? page - 1 : 0;
|
|
26249
26811
|
try {
|
|
@@ -26254,7 +26816,13 @@ function useEventManagementRepo() {
|
|
|
26254
26816
|
const baseQuery = {
|
|
26255
26817
|
site,
|
|
26256
26818
|
status: status ? status : { $ne: "deleted" },
|
|
26257
|
-
...type && { type }
|
|
26819
|
+
...type && { type },
|
|
26820
|
+
...date && {
|
|
26821
|
+
dateTime: {
|
|
26822
|
+
$gte: `${date}T00:00:00.000Z`,
|
|
26823
|
+
$lt: `${date}T23:59:59.999Z`
|
|
26824
|
+
}
|
|
26825
|
+
}
|
|
26258
26826
|
};
|
|
26259
26827
|
let query = { ...baseQuery };
|
|
26260
26828
|
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
@@ -26552,7 +27120,8 @@ function useEventManagementController() {
|
|
|
26552
27120
|
order: Joi82.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
26553
27121
|
site: Joi82.string().hex().required(),
|
|
26554
27122
|
status: Joi82.string().optional(),
|
|
26555
|
-
type: Joi82.string().optional().valid("TASK", "EVENT").allow(null, "")
|
|
27123
|
+
type: Joi82.string().optional().valid("TASK", "EVENT").allow(null, ""),
|
|
27124
|
+
date: Joi82.string().optional().allow(null, "")
|
|
26556
27125
|
});
|
|
26557
27126
|
const query = { ...req.query };
|
|
26558
27127
|
const { error } = validation.validate(query, {
|
|
@@ -26570,6 +27139,7 @@ function useEventManagementController() {
|
|
|
26570
27139
|
const site = req.query.site ?? "";
|
|
26571
27140
|
const status = req.query.status ?? "";
|
|
26572
27141
|
const type = req.query.type ?? "";
|
|
27142
|
+
const date = req.query.date ?? "";
|
|
26573
27143
|
const sortObj = {};
|
|
26574
27144
|
const sortFields = String(req.query.sort).split(",");
|
|
26575
27145
|
const sortOrders = String(req.query.order).split(",");
|
|
@@ -26587,7 +27157,8 @@ function useEventManagementController() {
|
|
|
26587
27157
|
sort: sortObj,
|
|
26588
27158
|
site,
|
|
26589
27159
|
status,
|
|
26590
|
-
type
|
|
27160
|
+
type,
|
|
27161
|
+
date
|
|
26591
27162
|
});
|
|
26592
27163
|
res.status(200).json(data);
|
|
26593
27164
|
return;
|
|
@@ -26913,6 +27484,7 @@ function useSiteUnitBillingRepo() {
|
|
|
26913
27484
|
}
|
|
26914
27485
|
};
|
|
26915
27486
|
}
|
|
27487
|
+
const unitSearchRegex = search ? search.trim().replace(/\s+/g, "").replace(/\//g, "\\s*/\\s*") : null;
|
|
26916
27488
|
const query = {
|
|
26917
27489
|
paymentStatus,
|
|
26918
27490
|
status,
|
|
@@ -26920,7 +27492,16 @@ function useSiteUnitBillingRepo() {
|
|
|
26920
27492
|
$or: [
|
|
26921
27493
|
{ unitOwner: { $regex: search, $options: "i" } },
|
|
26922
27494
|
{ billName: { $regex: search, $options: "i" } },
|
|
26923
|
-
{ unit: { $regex:
|
|
27495
|
+
{ unit: { $regex: unitSearchRegex, $options: "i" } },
|
|
27496
|
+
{
|
|
27497
|
+
$expr: {
|
|
27498
|
+
$regexMatch: {
|
|
27499
|
+
input: { $toString: "$amountPaid" },
|
|
27500
|
+
regex: search,
|
|
27501
|
+
options: "i"
|
|
27502
|
+
}
|
|
27503
|
+
}
|
|
27504
|
+
}
|
|
26924
27505
|
]
|
|
26925
27506
|
},
|
|
26926
27507
|
...ObjectId80.isValid(site) && { site: new ObjectId80(site) },
|
|
@@ -27347,14 +27928,14 @@ function useSiteUnitBillingService() {
|
|
|
27347
27928
|
function isBillingChecker(billing_item, todayMonth, todayDate) {
|
|
27348
27929
|
const billingMonth = Number(billing_item.month);
|
|
27349
27930
|
const billingDay = Number(billing_item.date);
|
|
27350
|
-
if (billing_item.frequency === "
|
|
27931
|
+
if (billing_item.frequency === "monthly" /* MONTHLY */) {
|
|
27351
27932
|
return todayDate === billingDay;
|
|
27352
27933
|
}
|
|
27353
|
-
if (billing_item.frequency === "
|
|
27934
|
+
if (billing_item.frequency === "quarterly" /* QAURTERLY */) {
|
|
27354
27935
|
const monthDiff = todayMonth - billingMonth;
|
|
27355
27936
|
return monthDiff % 3 === 0 && todayDate === billingDay;
|
|
27356
27937
|
}
|
|
27357
|
-
if (billing_item.frequency === "
|
|
27938
|
+
if (billing_item.frequency === "annually" /* ANNUALLY */) {
|
|
27358
27939
|
return todayMonth === billingMonth && todayDate === billingDay;
|
|
27359
27940
|
}
|
|
27360
27941
|
return false;
|
|
@@ -28150,7 +28731,7 @@ function UseAccessManagementRepo() {
|
|
|
28150
28731
|
{
|
|
28151
28732
|
$match: {
|
|
28152
28733
|
...defaultQuery,
|
|
28153
|
-
status: { $
|
|
28734
|
+
status: { $eq: "active" }
|
|
28154
28735
|
}
|
|
28155
28736
|
},
|
|
28156
28737
|
// ✅ Only project needed fields before heavy lookups
|
|
@@ -28270,7 +28851,7 @@ function UseAccessManagementRepo() {
|
|
|
28270
28851
|
userType
|
|
28271
28852
|
}
|
|
28272
28853
|
},
|
|
28273
|
-
{ $project: { _id: 1, userId: 1, type: 1, cardNo: 1, isActivated: 1 } }
|
|
28854
|
+
{ $project: { _id: 1, userId: 1, type: 1, cardNo: 1, isActivated: 1, replacementStatus: 1 } }
|
|
28274
28855
|
],
|
|
28275
28856
|
as: "accessCards"
|
|
28276
28857
|
}
|
|
@@ -28289,7 +28870,21 @@ function UseAccessManagementRepo() {
|
|
|
28289
28870
|
$filter: {
|
|
28290
28871
|
input: "$accessCards",
|
|
28291
28872
|
as: "card",
|
|
28292
|
-
cond: { $ne: ["$$card.userId", null] }
|
|
28873
|
+
cond: { $and: [{ $ne: ["$$card.userId", null] }, { $eq: ["$$card.isActivated", true] }] }
|
|
28874
|
+
}
|
|
28875
|
+
},
|
|
28876
|
+
f_replaced: {
|
|
28877
|
+
$filter: {
|
|
28878
|
+
input: "$accessCards",
|
|
28879
|
+
as: "card",
|
|
28880
|
+
cond: { $and: [{ $eq: ["$$card.isActivated", false] }, { $ne: ["$$card.replacementStatus", null] }] }
|
|
28881
|
+
}
|
|
28882
|
+
},
|
|
28883
|
+
f_deleted: {
|
|
28884
|
+
$filter: {
|
|
28885
|
+
input: "$accessCards",
|
|
28886
|
+
as: "card",
|
|
28887
|
+
cond: { $and: [{ $eq: ["$$card.isActivated", false] }, { $eq: ["$$card.replacementStatus", null] }] }
|
|
28293
28888
|
}
|
|
28294
28889
|
}
|
|
28295
28890
|
}
|
|
@@ -28321,6 +28916,14 @@ function UseAccessManagementRepo() {
|
|
|
28321
28916
|
non_physical: { $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } }
|
|
28322
28917
|
}
|
|
28323
28918
|
},
|
|
28919
|
+
replaced: {
|
|
28920
|
+
physical: { $filter: { input: "$f_replaced", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
28921
|
+
non_physical: { $filter: { input: "$f_replaced", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
28922
|
+
},
|
|
28923
|
+
deleted: {
|
|
28924
|
+
physical: { $filter: { input: "$f_deleted", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
28925
|
+
non_physical: { $filter: { input: "$f_deleted", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
28926
|
+
},
|
|
28324
28927
|
totalCardCount: {
|
|
28325
28928
|
$add: [
|
|
28326
28929
|
{ $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
|
|
@@ -28777,16 +29380,26 @@ function UseAccessManagementRepo() {
|
|
|
28777
29380
|
async function cardReplacementRepo(params) {
|
|
28778
29381
|
const session = useAtlas74.getClient()?.startSession();
|
|
28779
29382
|
try {
|
|
28780
|
-
const { cardId, remarks } = params;
|
|
29383
|
+
const { cardId, remarks, issuedCardId, unitId, userId } = params;
|
|
28781
29384
|
const id = new ObjectId83(cardId);
|
|
29385
|
+
const newCardId = new ObjectId83(issuedCardId);
|
|
29386
|
+
const unit = new ObjectId83(unitId);
|
|
29387
|
+
const user = new ObjectId83(userId);
|
|
28782
29388
|
session?.startTransaction();
|
|
28783
|
-
const
|
|
28784
|
-
|
|
28785
|
-
|
|
28786
|
-
|
|
28787
|
-
|
|
29389
|
+
const sessionResult = await Promise.all([
|
|
29390
|
+
await collection().findOneAndUpdate(
|
|
29391
|
+
{ _id: id },
|
|
29392
|
+
{ $set: { remarks, replacementStatus: "Complete", requestDate: /* @__PURE__ */ new Date(), isActivated: false } },
|
|
29393
|
+
{ returnDocument: "after", session }
|
|
29394
|
+
),
|
|
29395
|
+
await collection().findOneAndUpdate(
|
|
29396
|
+
{ _id: newCardId },
|
|
29397
|
+
{ $set: { updatedAt: /* @__PURE__ */ new Date(), assignedUnit: unit, userId: user } },
|
|
29398
|
+
{ returnDocument: "after", session }
|
|
29399
|
+
)
|
|
29400
|
+
]);
|
|
28788
29401
|
await session?.commitTransaction();
|
|
28789
|
-
return
|
|
29402
|
+
return sessionResult;
|
|
28790
29403
|
} catch (error) {
|
|
28791
29404
|
await session?.abortTransaction();
|
|
28792
29405
|
throw new Error(error.message);
|
|
@@ -29035,7 +29648,8 @@ function UseAccessManagementRepo() {
|
|
|
29035
29648
|
rawItems.map(async (item) => {
|
|
29036
29649
|
const date = new Date(item["startDate (format MM/DD/YYYY)"]);
|
|
29037
29650
|
const endDate = new Date(date.setFullYear(date.getFullYear() + 10));
|
|
29038
|
-
const cardNumber = item["cardNo (number 0-65535 ex. 301)"]
|
|
29651
|
+
const cardNumber = String(Number(item["cardNo (number 0-65535 ex. 301)"] || 0)).padStart(6, "0");
|
|
29652
|
+
const facilityCode = String(Number(item["facilityCode (number 0-255 ex. 11)"] || 0)).padStart(4, "0");
|
|
29039
29653
|
const pin = item["pin (number 6 digits only)"] ? item["pin (number 6 digits only)"].toString().padStart(6, "0") : "123456";
|
|
29040
29654
|
const match = item["accessLevel (number ex. 1)"];
|
|
29041
29655
|
const accessLevel = match ? match : null;
|
|
@@ -29049,9 +29663,9 @@ function UseAccessManagementRepo() {
|
|
|
29049
29663
|
accessLevel,
|
|
29050
29664
|
accessGroup,
|
|
29051
29665
|
accessType: "Normal" /* NORMAL */,
|
|
29052
|
-
cardNo: cardNumber
|
|
29666
|
+
cardNo: `${facilityCode}${cardNumber}`,
|
|
29053
29667
|
pin,
|
|
29054
|
-
qrData: await createQrData({ cardNumber }),
|
|
29668
|
+
qrData: await createQrData({ cardNumber: `${facilityCode}${cardNumber}` }),
|
|
29055
29669
|
startDate: new Date(item["startDate (format MM/DD/YYYY)"]),
|
|
29056
29670
|
endDate: new Date(item["endDate (format MM/DD/YYYY)"] || endDate),
|
|
29057
29671
|
isActivated: true,
|
|
@@ -29125,6 +29739,66 @@ function UseAccessManagementRepo() {
|
|
|
29125
29739
|
session?.endSession();
|
|
29126
29740
|
}
|
|
29127
29741
|
}
|
|
29742
|
+
async function deleteCardRepo(params) {
|
|
29743
|
+
try {
|
|
29744
|
+
const { cardId, remarks } = params;
|
|
29745
|
+
const id = new ObjectId83(cardId);
|
|
29746
|
+
const result = await collection().findOneAndUpdate({ _id: id }, { $set: { isActivated: false, updatedAt: /* @__PURE__ */ new Date(), remarks, requestDate: /* @__PURE__ */ new Date() } }, { returnDocument: "after" });
|
|
29747
|
+
return result;
|
|
29748
|
+
} catch (error) {
|
|
29749
|
+
throw new Error(error.message);
|
|
29750
|
+
}
|
|
29751
|
+
}
|
|
29752
|
+
async function getCardDetailsRepo(params) {
|
|
29753
|
+
try {
|
|
29754
|
+
const { siteId, cardId } = params;
|
|
29755
|
+
const convertedSiteId = new ObjectId83(siteId);
|
|
29756
|
+
const convertedCardId = new ObjectId83(cardId);
|
|
29757
|
+
const card = await collection().findOne(
|
|
29758
|
+
{
|
|
29759
|
+
_id: convertedCardId,
|
|
29760
|
+
site: convertedSiteId,
|
|
29761
|
+
type: "NFC" /* NFC */,
|
|
29762
|
+
userType: "Visitor/Resident" /* DEFAULT */
|
|
29763
|
+
},
|
|
29764
|
+
{
|
|
29765
|
+
projection: {
|
|
29766
|
+
userId: 1,
|
|
29767
|
+
site: 1,
|
|
29768
|
+
type: 1,
|
|
29769
|
+
userType: 1,
|
|
29770
|
+
cardNo: 1,
|
|
29771
|
+
isActivated: 1,
|
|
29772
|
+
replacementStatus: 1,
|
|
29773
|
+
vmsRemarks: 1,
|
|
29774
|
+
remarks: 1,
|
|
29775
|
+
requestDate: 1,
|
|
29776
|
+
createdAt: 1,
|
|
29777
|
+
updatedAt: 1
|
|
29778
|
+
}
|
|
29779
|
+
}
|
|
29780
|
+
);
|
|
29781
|
+
if (!card)
|
|
29782
|
+
return null;
|
|
29783
|
+
const site = await collectionName("sites").findOne(
|
|
29784
|
+
{ _id: card.site },
|
|
29785
|
+
{ projection: { name: 1, status: 1 } }
|
|
29786
|
+
);
|
|
29787
|
+
const user = card.userId ? await collectionName("users").findOne(
|
|
29788
|
+
{ _id: card.userId },
|
|
29789
|
+
{ projection: { name: 1, email: 1 } }
|
|
29790
|
+
) : null;
|
|
29791
|
+
const status = card.userId === null && card.isActivated === true ? "available" : card.userId !== null && card.isActivated === true ? "assigned" : card.isActivated === false && card.replacementStatus !== null ? "replaced" : "deleted";
|
|
29792
|
+
return {
|
|
29793
|
+
...card,
|
|
29794
|
+
status,
|
|
29795
|
+
site,
|
|
29796
|
+
user
|
|
29797
|
+
};
|
|
29798
|
+
} catch (error) {
|
|
29799
|
+
throw new Error(error.message);
|
|
29800
|
+
}
|
|
29801
|
+
}
|
|
29128
29802
|
return {
|
|
29129
29803
|
createIndexes,
|
|
29130
29804
|
createIndexForEntrypass,
|
|
@@ -29145,7 +29819,9 @@ function UseAccessManagementRepo() {
|
|
|
29145
29819
|
getCardReplacementRepo,
|
|
29146
29820
|
getAccessManagementSettingsRepo,
|
|
29147
29821
|
bulkPhysicalAccessCardRepo,
|
|
29148
|
-
assignAccessCardToUnitRepo
|
|
29822
|
+
assignAccessCardToUnitRepo,
|
|
29823
|
+
deleteCardRepo,
|
|
29824
|
+
getCardDetailsRepo
|
|
29149
29825
|
};
|
|
29150
29826
|
}
|
|
29151
29827
|
|
|
@@ -29177,7 +29853,9 @@ function useAccessManagementSvc() {
|
|
|
29177
29853
|
getCardReplacementRepo,
|
|
29178
29854
|
getAccessManagementSettingsRepo,
|
|
29179
29855
|
bulkPhysicalAccessCardRepo,
|
|
29180
|
-
assignAccessCardToUnitRepo
|
|
29856
|
+
assignAccessCardToUnitRepo,
|
|
29857
|
+
deleteCardRepo,
|
|
29858
|
+
getCardDetailsRepo
|
|
29181
29859
|
} = UseAccessManagementRepo();
|
|
29182
29860
|
const addPhysicalCardSvc = async (payload) => {
|
|
29183
29861
|
try {
|
|
@@ -29425,6 +30103,22 @@ function useAccessManagementSvc() {
|
|
|
29425
30103
|
throw new Error(err.message);
|
|
29426
30104
|
}
|
|
29427
30105
|
};
|
|
30106
|
+
const deleteCardSvc = async (params) => {
|
|
30107
|
+
try {
|
|
30108
|
+
const response = await deleteCardRepo({ ...params });
|
|
30109
|
+
return response;
|
|
30110
|
+
} catch (err) {
|
|
30111
|
+
throw new Error(err.message);
|
|
30112
|
+
}
|
|
30113
|
+
};
|
|
30114
|
+
const getCardDetailsSvc = async (params) => {
|
|
30115
|
+
try {
|
|
30116
|
+
const response = await getCardDetailsRepo({ ...params });
|
|
30117
|
+
return response;
|
|
30118
|
+
} catch (err) {
|
|
30119
|
+
throw new Error(err.message);
|
|
30120
|
+
}
|
|
30121
|
+
};
|
|
29428
30122
|
return {
|
|
29429
30123
|
addPhysicalCardSvc,
|
|
29430
30124
|
addNonPhysicalCardSvc,
|
|
@@ -29449,7 +30143,9 @@ function useAccessManagementSvc() {
|
|
|
29449
30143
|
getAccessManagementSettingsSvc,
|
|
29450
30144
|
convertBufferFile,
|
|
29451
30145
|
bulkPhysicalAccessCardSvc,
|
|
29452
|
-
assignAccessCardToUnitSvc
|
|
30146
|
+
assignAccessCardToUnitSvc,
|
|
30147
|
+
deleteCardSvc,
|
|
30148
|
+
getCardDetailsSvc
|
|
29453
30149
|
};
|
|
29454
30150
|
}
|
|
29455
30151
|
|
|
@@ -29481,7 +30177,9 @@ function useAccessManagementController() {
|
|
|
29481
30177
|
getAccessManagementSettingsSvc,
|
|
29482
30178
|
convertBufferFile,
|
|
29483
30179
|
bulkPhysicalAccessCardSvc,
|
|
29484
|
-
assignAccessCardToUnitSvc
|
|
30180
|
+
assignAccessCardToUnitSvc,
|
|
30181
|
+
deleteCardSvc,
|
|
30182
|
+
getCardDetailsSvc
|
|
29485
30183
|
} = useAccessManagementSvc();
|
|
29486
30184
|
const addPhysicalCard = async (req, res) => {
|
|
29487
30185
|
try {
|
|
@@ -29710,11 +30408,24 @@ function useAccessManagementController() {
|
|
|
29710
30408
|
userType: Joi85.string().optional().allow("", null),
|
|
29711
30409
|
type: Joi85.string().optional().allow("", null)
|
|
29712
30410
|
});
|
|
30411
|
+
const user = req.cookies?.sid;
|
|
29713
30412
|
const { error } = schema2.validate({ site, userType, type });
|
|
29714
30413
|
if (error) {
|
|
29715
30414
|
return res.status(400).json({ message: error.message });
|
|
29716
30415
|
}
|
|
30416
|
+
const key = `${namespace2}:${user}:available-access-cards`;
|
|
30417
|
+
const listKey = `${namespace2}:${user}:list`;
|
|
30418
|
+
const { redis } = useCache48(key);
|
|
30419
|
+
const cachedData = await getCache({ key, redis });
|
|
30420
|
+
if (cachedData) {
|
|
30421
|
+
console.log("\u26A1 Cache hit:", key);
|
|
30422
|
+
redis.expire(key, 60).catch(console.error);
|
|
30423
|
+
redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
|
|
30424
|
+
return res.status(200).json({ message: "Success", data: cachedData });
|
|
30425
|
+
}
|
|
29717
30426
|
const result = await availableAccessCardsSvc({ site, userType, type });
|
|
30427
|
+
await setCache({ key, data: result, ttlSeconds: 60, redis });
|
|
30428
|
+
redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
|
|
29718
30429
|
return res.status(200).json({ message: "Success", data: result });
|
|
29719
30430
|
} catch (error) {
|
|
29720
30431
|
return res.status(400).json({
|
|
@@ -29896,16 +30607,19 @@ function useAccessManagementController() {
|
|
|
29896
30607
|
};
|
|
29897
30608
|
const cardReplacement = async (req, res) => {
|
|
29898
30609
|
try {
|
|
29899
|
-
const { cardId, remarks } = req.body;
|
|
30610
|
+
const { cardId, remarks, unitId, issuedCardId, userId } = req.body;
|
|
29900
30611
|
const schema2 = Joi85.object({
|
|
29901
30612
|
cardId: Joi85.string().required(),
|
|
29902
|
-
remarks: Joi85.string().optional().allow("", null)
|
|
30613
|
+
remarks: Joi85.string().optional().allow("", null),
|
|
30614
|
+
unitId: Joi85.string().hex().required(),
|
|
30615
|
+
issuedCardId: Joi85.string().required(),
|
|
30616
|
+
userId: Joi85.string().hex().required()
|
|
29903
30617
|
});
|
|
29904
|
-
const { error } = schema2.validate({ cardId, remarks });
|
|
30618
|
+
const { error } = schema2.validate({ cardId, remarks, unitId, issuedCardId, userId });
|
|
29905
30619
|
if (error) {
|
|
29906
30620
|
return res.status(400).json({ message: error.message });
|
|
29907
30621
|
}
|
|
29908
|
-
const result = await cardReplacementSvc({ cardId, remarks });
|
|
30622
|
+
const result = await cardReplacementSvc({ cardId, remarks, unitId, issuedCardId, userId });
|
|
29909
30623
|
return res.status(200).json({ message: "Success", data: result });
|
|
29910
30624
|
} catch (error) {
|
|
29911
30625
|
return res.status(500).json({
|
|
@@ -30036,6 +30750,46 @@ function useAccessManagementController() {
|
|
|
30036
30750
|
});
|
|
30037
30751
|
}
|
|
30038
30752
|
};
|
|
30753
|
+
const deleteCard = async (req, res) => {
|
|
30754
|
+
try {
|
|
30755
|
+
const { cardId, remarks } = req.body;
|
|
30756
|
+
const schema2 = Joi85.object({
|
|
30757
|
+
cardId: Joi85.string().hex().required(),
|
|
30758
|
+
remarks: Joi85.string().optional().allow("", null)
|
|
30759
|
+
});
|
|
30760
|
+
const { error } = schema2.validate({ cardId, remarks });
|
|
30761
|
+
if (error) {
|
|
30762
|
+
return res.status(400).json({ message: error.message });
|
|
30763
|
+
}
|
|
30764
|
+
const result = await deleteCardSvc({ cardId, remarks });
|
|
30765
|
+
return res.status(200).json({ message: "Success", data: result });
|
|
30766
|
+
} catch (error) {
|
|
30767
|
+
return res.status(500).json({
|
|
30768
|
+
data: null,
|
|
30769
|
+
message: error.message
|
|
30770
|
+
});
|
|
30771
|
+
}
|
|
30772
|
+
};
|
|
30773
|
+
const getCardDetails = async (req, res) => {
|
|
30774
|
+
try {
|
|
30775
|
+
const { siteId, cardId } = req.query;
|
|
30776
|
+
const schema2 = Joi85.object({
|
|
30777
|
+
siteId: Joi85.string().hex().required(),
|
|
30778
|
+
cardId: Joi85.string().hex().required()
|
|
30779
|
+
});
|
|
30780
|
+
const { error } = schema2.validate({ siteId, cardId });
|
|
30781
|
+
if (error) {
|
|
30782
|
+
return res.status(400).json({ message: error.message });
|
|
30783
|
+
}
|
|
30784
|
+
const result = await getCardDetailsSvc({ siteId, cardId });
|
|
30785
|
+
return res.status(200).json({ message: "Success", data: result });
|
|
30786
|
+
} catch (error) {
|
|
30787
|
+
return res.status(500).json({
|
|
30788
|
+
data: null,
|
|
30789
|
+
message: error.message
|
|
30790
|
+
});
|
|
30791
|
+
}
|
|
30792
|
+
};
|
|
30039
30793
|
return {
|
|
30040
30794
|
addPhysicalCard,
|
|
30041
30795
|
addNonPhysicalCard,
|
|
@@ -30057,7 +30811,9 @@ function useAccessManagementController() {
|
|
|
30057
30811
|
getCardReplacement,
|
|
30058
30812
|
getAccessManagementSettings,
|
|
30059
30813
|
bulkPhysicalAccessCard,
|
|
30060
|
-
assignAccessCardToUnit
|
|
30814
|
+
assignAccessCardToUnit,
|
|
30815
|
+
deleteCard,
|
|
30816
|
+
getCardDetails
|
|
30061
30817
|
};
|
|
30062
30818
|
}
|
|
30063
30819
|
|
|
@@ -31809,9 +32565,9 @@ function useStatementOfAccountRepo() {
|
|
|
31809
32565
|
page = page > 0 ? page - 1 : 0;
|
|
31810
32566
|
let dateExpr = {};
|
|
31811
32567
|
if (dateFrom && dateTo) {
|
|
31812
|
-
|
|
32568
|
+
let startDate = new Date(dateFrom);
|
|
31813
32569
|
startDate.setHours(0, 0, 0, 0);
|
|
31814
|
-
|
|
32570
|
+
let endDate = new Date(dateTo);
|
|
31815
32571
|
endDate.setHours(23, 59, 59, 999);
|
|
31816
32572
|
dateExpr = {
|
|
31817
32573
|
$expr: {
|
|
@@ -31822,13 +32578,15 @@ function useStatementOfAccountRepo() {
|
|
|
31822
32578
|
}
|
|
31823
32579
|
};
|
|
31824
32580
|
}
|
|
32581
|
+
const unitSearchRegex = search ? search.trim().replace(/\s+/g, "").replace(/\//g, "\\s*/\\s*") : null;
|
|
31825
32582
|
const query = {
|
|
31826
32583
|
...status && status !== "all" && { status },
|
|
31827
32584
|
...search && {
|
|
31828
32585
|
$or: [
|
|
31829
32586
|
{ unitOwner: { $regex: search, $options: "i" } },
|
|
31830
|
-
{ unit: { $regex:
|
|
31831
|
-
{ email: { $regex: search, $options: "i" } }
|
|
32587
|
+
{ unit: { $regex: unitSearchRegex, $options: "i" } },
|
|
32588
|
+
{ email: { $regex: search, $options: "i" } },
|
|
32589
|
+
{ category: { $regex: search, $options: "i" } }
|
|
31832
32590
|
]
|
|
31833
32591
|
},
|
|
31834
32592
|
...ObjectId91.isValid(site) && { site: new ObjectId91(site) },
|
|
@@ -34122,6 +34880,9 @@ function useIncidentReportRepo() {
|
|
|
34122
34880
|
$regex: search,
|
|
34123
34881
|
$options: "i"
|
|
34124
34882
|
}
|
|
34883
|
+
},
|
|
34884
|
+
{
|
|
34885
|
+
approvedByName: { $regex: search, $options: "i" }
|
|
34125
34886
|
}
|
|
34126
34887
|
]
|
|
34127
34888
|
},
|
|
@@ -36677,7 +37438,9 @@ function useNfcPatrolLogController() {
|
|
|
36677
37438
|
};
|
|
36678
37439
|
}
|
|
36679
37440
|
export {
|
|
37441
|
+
ANPRMode,
|
|
36680
37442
|
AccessTypeProps,
|
|
37443
|
+
BULLETIN_RECIPIENTS,
|
|
36681
37444
|
DEVICE_STATUS,
|
|
36682
37445
|
EAccessCardTypes,
|
|
36683
37446
|
EAccessCardUserTypes,
|
|
@@ -36736,12 +37499,15 @@ export {
|
|
|
36736
37499
|
MVerification,
|
|
36737
37500
|
MVisitorTransaction,
|
|
36738
37501
|
MWorkOrder,
|
|
37502
|
+
OrgNature,
|
|
36739
37503
|
PERSON_TYPES,
|
|
37504
|
+
STATUS_VALUES,
|
|
36740
37505
|
UseAccessManagementRepo,
|
|
36741
|
-
|
|
37506
|
+
VehicleCategory,
|
|
37507
|
+
VehicleStatus,
|
|
37508
|
+
VehicleType,
|
|
36742
37509
|
allowedFieldsSite,
|
|
36743
37510
|
allowedNatures,
|
|
36744
|
-
allowedTypes,
|
|
36745
37511
|
attendanceSchema,
|
|
36746
37512
|
attendanceSettingsSchema,
|
|
36747
37513
|
chatSchema,
|