@7365admin1/core 2.14.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 +12 -0
- package/dist/index.d.ts +95 -19
- package/dist/index.js +1355 -254
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1348 -252
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -3
package/dist/index.js
CHANGED
|
@@ -30,7 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
|
+
ANPRMode: () => ANPRMode,
|
|
33
34
|
AccessTypeProps: () => AccessTypeProps,
|
|
35
|
+
BULLETIN_RECIPIENTS: () => BULLETIN_RECIPIENTS,
|
|
34
36
|
DEVICE_STATUS: () => DEVICE_STATUS,
|
|
35
37
|
EAccessCardTypes: () => EAccessCardTypes,
|
|
36
38
|
EAccessCardUserTypes: () => EAccessCardUserTypes,
|
|
@@ -89,12 +91,15 @@ __export(src_exports, {
|
|
|
89
91
|
MVerification: () => MVerification,
|
|
90
92
|
MVisitorTransaction: () => MVisitorTransaction,
|
|
91
93
|
MWorkOrder: () => MWorkOrder,
|
|
94
|
+
OrgNature: () => OrgNature,
|
|
92
95
|
PERSON_TYPES: () => PERSON_TYPES,
|
|
96
|
+
STATUS_VALUES: () => STATUS_VALUES,
|
|
93
97
|
UseAccessManagementRepo: () => UseAccessManagementRepo,
|
|
94
|
-
|
|
98
|
+
VehicleCategory: () => VehicleCategory,
|
|
99
|
+
VehicleStatus: () => VehicleStatus,
|
|
100
|
+
VehicleType: () => VehicleType,
|
|
95
101
|
allowedFieldsSite: () => allowedFieldsSite,
|
|
96
102
|
allowedNatures: () => allowedNatures,
|
|
97
|
-
allowedTypes: () => allowedTypes,
|
|
98
103
|
attendanceSchema: () => attendanceSchema,
|
|
99
104
|
attendanceSettingsSchema: () => attendanceSettingsSchema,
|
|
100
105
|
chatSchema: () => chatSchema,
|
|
@@ -1669,7 +1674,9 @@ var schemaOccurrenceEntry = import_joi5.default.object({
|
|
|
1669
1674
|
subject: import_joi5.default.string().hex().optional().allow(null, ""),
|
|
1670
1675
|
occurrence: import_joi5.default.string().optional().allow(null, ""),
|
|
1671
1676
|
signature: import_joi5.default.string().hex().optional().allow(null, ""),
|
|
1672
|
-
incidentReportId: import_joi5.default.string().hex().optional().allow(null, "")
|
|
1677
|
+
incidentReportId: import_joi5.default.string().hex().optional().allow(null, ""),
|
|
1678
|
+
eSignature: import_joi5.default.string().required(),
|
|
1679
|
+
createdByName: import_joi5.default.string().optional().allow(null, "")
|
|
1673
1680
|
});
|
|
1674
1681
|
var schemaUpdateOccurrenceEntry = import_joi5.default.object({
|
|
1675
1682
|
_id: import_joi5.default.string().hex().required(),
|
|
@@ -1678,7 +1685,9 @@ var schemaUpdateOccurrenceEntry = import_joi5.default.object({
|
|
|
1678
1685
|
subject: import_joi5.default.string().hex().optional().allow(null, ""),
|
|
1679
1686
|
occurrence: import_joi5.default.string().optional().allow(null, ""),
|
|
1680
1687
|
signature: import_joi5.default.string().hex().optional().allow(null, ""),
|
|
1681
|
-
incidentReportId: import_joi5.default.string().hex().optional().allow(null, "")
|
|
1688
|
+
incidentReportId: import_joi5.default.string().hex().optional().allow(null, ""),
|
|
1689
|
+
eSignature: import_joi5.default.string().required(),
|
|
1690
|
+
createdByName: import_joi5.default.string().optional().allow(null, "")
|
|
1682
1691
|
});
|
|
1683
1692
|
function MOccurrenceEntry(value) {
|
|
1684
1693
|
if (value._id && typeof value._id === "string") {
|
|
@@ -1735,6 +1744,8 @@ function MOccurrenceEntry(value) {
|
|
|
1735
1744
|
incidentReportId: value.incidentReportId,
|
|
1736
1745
|
signature: value.signature,
|
|
1737
1746
|
userName: value.userName,
|
|
1747
|
+
eSignature: value.eSignature,
|
|
1748
|
+
createdByName: value.createdByName,
|
|
1738
1749
|
date: value.date,
|
|
1739
1750
|
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1740
1751
|
updatedAt: value.updatedAt,
|
|
@@ -6617,12 +6628,12 @@ function useUserController() {
|
|
|
6617
6628
|
}
|
|
6618
6629
|
}
|
|
6619
6630
|
async function createUserByVerification(req, res, next) {
|
|
6620
|
-
const
|
|
6631
|
+
const allowedTypes = ["user-sign-up", "user-invite"];
|
|
6621
6632
|
const validation = import_joi14.default.object({
|
|
6622
6633
|
id: import_joi14.default.string().hex().required(),
|
|
6623
6634
|
name: import_joi14.default.string().required(),
|
|
6624
6635
|
password: import_joi14.default.string().required(),
|
|
6625
|
-
type: import_joi14.default.string().required().valid(...
|
|
6636
|
+
type: import_joi14.default.string().required().valid(...allowedTypes)
|
|
6626
6637
|
});
|
|
6627
6638
|
const id = req.params.id;
|
|
6628
6639
|
const payload = { ...req.body };
|
|
@@ -11029,7 +11040,7 @@ function useFeedbackController() {
|
|
|
11029
11040
|
}
|
|
11030
11041
|
async function deleteFeedback(req, res, next) {
|
|
11031
11042
|
const validation = import_joi28.default.string().hex().required();
|
|
11032
|
-
const _id = req.
|
|
11043
|
+
const _id = req.params.id;
|
|
11033
11044
|
const { error } = validation.validate(_id);
|
|
11034
11045
|
if (error) {
|
|
11035
11046
|
import_node_server_utils55.logger.log({ level: "error", message: error.message });
|
|
@@ -11393,8 +11404,7 @@ function useWorkOrderController() {
|
|
|
11393
11404
|
}
|
|
11394
11405
|
async function deleteWorkOrder(req, res, next) {
|
|
11395
11406
|
const validation = import_joi29.default.string().hex().required();
|
|
11396
|
-
const _id = req.
|
|
11397
|
-
console.log(_id);
|
|
11407
|
+
const _id = req.params.id;
|
|
11398
11408
|
const { error } = validation.validate(_id);
|
|
11399
11409
|
if (error) {
|
|
11400
11410
|
import_node_server_utils57.logger.log({ level: "error", message: error.message });
|
|
@@ -15115,11 +15125,14 @@ function usePersonRepo() {
|
|
|
15115
15125
|
const namespace_collection = "site.people";
|
|
15116
15126
|
const collection = db.collection(namespace_collection);
|
|
15117
15127
|
const { delNamespace, getCache, setCache } = (0, import_node_server_utils79.useCache)(namespace_collection);
|
|
15118
|
-
async function
|
|
15128
|
+
async function createIndexes() {
|
|
15119
15129
|
try {
|
|
15120
|
-
await collection.
|
|
15130
|
+
await collection.createIndexes([
|
|
15131
|
+
{ key: { contact: 1 } },
|
|
15132
|
+
{ key: { nric: 1 } }
|
|
15133
|
+
]);
|
|
15121
15134
|
} catch (error) {
|
|
15122
|
-
throw new import_node_server_utils79.InternalServerError("Failed to create index.");
|
|
15135
|
+
throw new import_node_server_utils79.InternalServerError("Failed to create index on site people.");
|
|
15123
15136
|
}
|
|
15124
15137
|
}
|
|
15125
15138
|
async function createTextIndex() {
|
|
@@ -15509,6 +15522,47 @@ function usePersonRepo() {
|
|
|
15509
15522
|
throw new import_node_server_utils79.InternalServerError("Failed to fetch people by plate number.");
|
|
15510
15523
|
}
|
|
15511
15524
|
}
|
|
15525
|
+
async function getPeopleByNRIC({
|
|
15526
|
+
page = 1,
|
|
15527
|
+
limit = 10,
|
|
15528
|
+
nric = "",
|
|
15529
|
+
sort = {},
|
|
15530
|
+
site = ""
|
|
15531
|
+
}) {
|
|
15532
|
+
page = page > 0 ? page - 1 : 0;
|
|
15533
|
+
const normalizedNric = nric.trim();
|
|
15534
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15535
|
+
const query = {
|
|
15536
|
+
...nric && { nric: normalizedNric },
|
|
15537
|
+
site: typeof site === "string" ? new import_mongodb44.ObjectId(site) : site
|
|
15538
|
+
};
|
|
15539
|
+
const cacheOptions = {
|
|
15540
|
+
site,
|
|
15541
|
+
...nric && { nric: normalizedNric },
|
|
15542
|
+
page: String(page),
|
|
15543
|
+
limit: String(limit),
|
|
15544
|
+
sort: JSON.stringify(sort)
|
|
15545
|
+
};
|
|
15546
|
+
try {
|
|
15547
|
+
const cacheKey = (0, import_node_server_utils79.makeCacheKey)(namespace_collection, cacheOptions);
|
|
15548
|
+
const cachedData = await getCache(cacheKey);
|
|
15549
|
+
if (cachedData) {
|
|
15550
|
+
import_node_server_utils79.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
15551
|
+
return cachedData;
|
|
15552
|
+
}
|
|
15553
|
+
const items = await collection.find(query).sort(sort).skip(page * limit).limit(limit).toArray();
|
|
15554
|
+
const length = await collection.countDocuments(query);
|
|
15555
|
+
const data = (0, import_node_server_utils79.paginate)(items, page, limit, length);
|
|
15556
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
15557
|
+
import_node_server_utils79.logger.info(`Cache set for key: ${cacheKey}`);
|
|
15558
|
+
}).catch((err) => {
|
|
15559
|
+
import_node_server_utils79.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
15560
|
+
});
|
|
15561
|
+
return data;
|
|
15562
|
+
} catch (error) {
|
|
15563
|
+
throw new import_node_server_utils79.InternalServerError("Failed to retrieve person by NRIC.");
|
|
15564
|
+
}
|
|
15565
|
+
}
|
|
15512
15566
|
return {
|
|
15513
15567
|
add,
|
|
15514
15568
|
getAll,
|
|
@@ -15518,11 +15572,12 @@ function usePersonRepo() {
|
|
|
15518
15572
|
createTextIndex,
|
|
15519
15573
|
getPersonByPlateNumber,
|
|
15520
15574
|
getByNRIC,
|
|
15521
|
-
|
|
15575
|
+
createIndexes,
|
|
15522
15576
|
getPersonByPhoneNumber,
|
|
15523
15577
|
getPeopleByUnit,
|
|
15524
15578
|
getCompany,
|
|
15525
|
-
getPeopleByPlateNumber
|
|
15579
|
+
getPeopleByPlateNumber,
|
|
15580
|
+
getPeopleByNRIC
|
|
15526
15581
|
};
|
|
15527
15582
|
}
|
|
15528
15583
|
|
|
@@ -15533,12 +15588,45 @@ var import_node_server_utils81 = require("@7365admin1/node-server-utils");
|
|
|
15533
15588
|
var import_node_server_utils80 = require("@7365admin1/node-server-utils");
|
|
15534
15589
|
var import_joi43 = __toESM(require("joi"));
|
|
15535
15590
|
var import_mongodb45 = require("mongodb");
|
|
15536
|
-
var
|
|
15537
|
-
|
|
15591
|
+
var VehicleType = /* @__PURE__ */ ((VehicleType2) => {
|
|
15592
|
+
VehicleType2["WHITELIST"] = "whitelist";
|
|
15593
|
+
VehicleType2["BLOCKLIST"] = "blocklist";
|
|
15594
|
+
return VehicleType2;
|
|
15595
|
+
})(VehicleType || {});
|
|
15596
|
+
var VehicleCategory = /* @__PURE__ */ ((VehicleCategory2) => {
|
|
15597
|
+
VehicleCategory2["RESIDENT"] = "resident";
|
|
15598
|
+
VehicleCategory2["VISITOR"] = "visitor";
|
|
15599
|
+
return VehicleCategory2;
|
|
15600
|
+
})(VehicleCategory || {});
|
|
15601
|
+
var VehicleStatus = /* @__PURE__ */ ((VehicleStatus2) => {
|
|
15602
|
+
VehicleStatus2["PENDING"] = "pending";
|
|
15603
|
+
VehicleStatus2["ACTIVE"] = "active";
|
|
15604
|
+
VehicleStatus2["INACTIVE"] = "inactive";
|
|
15605
|
+
VehicleStatus2["DELETED"] = "deleted";
|
|
15606
|
+
return VehicleStatus2;
|
|
15607
|
+
})(VehicleStatus || {});
|
|
15608
|
+
var OrgNature = /* @__PURE__ */ ((OrgNature2) => {
|
|
15609
|
+
OrgNature2["PROPERTY_MANAGEMENT_AGENCY"] = "property_management_agency";
|
|
15610
|
+
OrgNature2["SECURITY_AGENCY"] = "security_agency";
|
|
15611
|
+
return OrgNature2;
|
|
15612
|
+
})(OrgNature || {});
|
|
15613
|
+
var ANPRMode = /* @__PURE__ */ ((ANPRMode2) => {
|
|
15614
|
+
ANPRMode2["TRAFFIC_REDLIST"] = "TrafficRedList";
|
|
15615
|
+
ANPRMode2["TRAFFIC_BLACKLIST"] = "TrafficBlackList";
|
|
15616
|
+
return ANPRMode2;
|
|
15617
|
+
})(ANPRMode || {});
|
|
15538
15618
|
var vehicleSchema = import_joi43.default.object({
|
|
15539
|
-
plateNumber: import_joi43.default.
|
|
15540
|
-
|
|
15541
|
-
|
|
15619
|
+
plateNumber: import_joi43.default.alternatives().try(
|
|
15620
|
+
import_joi43.default.array().items(import_joi43.default.string().trim().min(1)).min(1),
|
|
15621
|
+
import_joi43.default.string().trim().min(1)
|
|
15622
|
+
).custom((value) => {
|
|
15623
|
+
if (typeof value === "string") {
|
|
15624
|
+
return value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
15625
|
+
}
|
|
15626
|
+
return value;
|
|
15627
|
+
}).required(),
|
|
15628
|
+
type: import_joi43.default.string().required().valid(...Object.values(VehicleType)),
|
|
15629
|
+
category: import_joi43.default.string().required().valid(...Object.values(VehicleCategory)),
|
|
15542
15630
|
name: import_joi43.default.string().required(),
|
|
15543
15631
|
phoneNumber: import_joi43.default.string().optional().allow("", null),
|
|
15544
15632
|
recNo: import_joi43.default.string().optional().allow("", null),
|
|
@@ -15552,7 +15640,8 @@ var vehicleSchema = import_joi43.default.object({
|
|
|
15552
15640
|
seasonPassType: import_joi43.default.string().optional().allow("", null),
|
|
15553
15641
|
start: import_joi43.default.date().optional().allow("", null),
|
|
15554
15642
|
end: import_joi43.default.date().optional().allow("", null),
|
|
15555
|
-
unitName: import_joi43.default.string().optional().allow("", null)
|
|
15643
|
+
unitName: import_joi43.default.string().optional().allow("", null),
|
|
15644
|
+
status: import_joi43.default.string().optional().valid(...Object.values(VehicleStatus)).allow("")
|
|
15556
15645
|
});
|
|
15557
15646
|
function MVehicle(value) {
|
|
15558
15647
|
const { error } = vehicleSchema.validate(value);
|
|
@@ -15581,6 +15670,11 @@ function MVehicle(value) {
|
|
|
15581
15670
|
throw new import_node_server_utils80.BadRequestError("Invalid building unit ID format.");
|
|
15582
15671
|
}
|
|
15583
15672
|
}
|
|
15673
|
+
const createdAtDate = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
|
|
15674
|
+
const expiredDate = new Date(createdAtDate);
|
|
15675
|
+
expiredDate.setFullYear(expiredDate.getFullYear() + 10);
|
|
15676
|
+
const createdAt = createdAtDate.toISOString();
|
|
15677
|
+
const expiredAt = value.end ?? expiredDate.toISOString();
|
|
15584
15678
|
return {
|
|
15585
15679
|
plateNumber: value.plateNumber ?? "",
|
|
15586
15680
|
type: value.type ?? "",
|
|
@@ -15596,11 +15690,11 @@ function MVehicle(value) {
|
|
|
15596
15690
|
nric: value.nric ?? "",
|
|
15597
15691
|
remarks: value.remarks ?? "",
|
|
15598
15692
|
seasonPassType: value.seasonPassType ?? "",
|
|
15599
|
-
start: value.start ??
|
|
15600
|
-
end: value.end ??
|
|
15601
|
-
status: value.status ?? "active"
|
|
15693
|
+
start: value.start ?? createdAt,
|
|
15694
|
+
end: value.end ?? expiredAt,
|
|
15695
|
+
status: value.status ?? "active" /* ACTIVE */,
|
|
15602
15696
|
unitName: value.unitName ?? "",
|
|
15603
|
-
createdAt
|
|
15697
|
+
createdAt,
|
|
15604
15698
|
updatedAt: value.updatedAt ?? "",
|
|
15605
15699
|
deletedAt: value.deletedAt ?? ""
|
|
15606
15700
|
};
|
|
@@ -15658,7 +15752,7 @@ function useVehicleRepo() {
|
|
|
15658
15752
|
}
|
|
15659
15753
|
const namespace_collection = "vehicles";
|
|
15660
15754
|
const collection = db.collection(namespace_collection);
|
|
15661
|
-
const { delNamespace, setCache, getCache
|
|
15755
|
+
const { delNamespace, setCache, getCache } = (0, import_node_server_utils81.useCache)(namespace_collection);
|
|
15662
15756
|
async function createIndex() {
|
|
15663
15757
|
try {
|
|
15664
15758
|
await collection.createIndexes([
|
|
@@ -15670,6 +15764,22 @@ function useVehicleRepo() {
|
|
|
15670
15764
|
throw new import_node_server_utils81.InternalServerError("Failed to create index on vehicle.");
|
|
15671
15765
|
}
|
|
15672
15766
|
}
|
|
15767
|
+
async function createTextIndex() {
|
|
15768
|
+
try {
|
|
15769
|
+
await collection.createIndex({
|
|
15770
|
+
name: "text",
|
|
15771
|
+
plateNumber: "text",
|
|
15772
|
+
level: "text",
|
|
15773
|
+
unitName: "text",
|
|
15774
|
+
phoneNumber: "text",
|
|
15775
|
+
nric: "text"
|
|
15776
|
+
});
|
|
15777
|
+
} catch (error) {
|
|
15778
|
+
throw new import_node_server_utils81.InternalServerError(
|
|
15779
|
+
"Failed to create text index on visitor transaction."
|
|
15780
|
+
);
|
|
15781
|
+
}
|
|
15782
|
+
}
|
|
15673
15783
|
async function add(value, session) {
|
|
15674
15784
|
try {
|
|
15675
15785
|
value = MVehicle(value);
|
|
@@ -15701,73 +15811,178 @@ function useVehicleRepo() {
|
|
|
15701
15811
|
search = "",
|
|
15702
15812
|
sort = {},
|
|
15703
15813
|
type = "",
|
|
15704
|
-
category = ""
|
|
15814
|
+
category = "",
|
|
15815
|
+
status = ""
|
|
15705
15816
|
}) {
|
|
15706
15817
|
page = page > 0 ? page - 1 : 0;
|
|
15707
|
-
const
|
|
15818
|
+
const baseQuery = {
|
|
15819
|
+
...status && { status },
|
|
15820
|
+
...type && { type },
|
|
15821
|
+
...category && { category }
|
|
15822
|
+
};
|
|
15823
|
+
let query = { ...baseQuery };
|
|
15824
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15708
15825
|
const cacheOptions = {
|
|
15709
|
-
status
|
|
15826
|
+
...status && { status },
|
|
15827
|
+
...type && { type },
|
|
15828
|
+
...category && { category },
|
|
15710
15829
|
page: String(page),
|
|
15711
|
-
limit: String(limit)
|
|
15830
|
+
limit: String(limit),
|
|
15831
|
+
sort: JSON.stringify(sort)
|
|
15712
15832
|
};
|
|
15713
|
-
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
15714
|
-
cacheOptions.sort = JSON.stringify(sort);
|
|
15715
15833
|
if (search) {
|
|
15716
|
-
query.$
|
|
15834
|
+
query.$text = { $search: search };
|
|
15717
15835
|
cacheOptions.search = search;
|
|
15718
15836
|
}
|
|
15719
|
-
if (type) {
|
|
15720
|
-
query.type = type;
|
|
15721
|
-
cacheOptions.type = type;
|
|
15722
|
-
}
|
|
15723
|
-
if (category) {
|
|
15724
|
-
query.category = category;
|
|
15725
|
-
cacheOptions.category = category;
|
|
15726
|
-
}
|
|
15727
15837
|
const cacheKey = (0, import_node_server_utils81.makeCacheKey)(namespace_collection, cacheOptions);
|
|
15728
15838
|
const cachedData = await getCache(cacheKey);
|
|
15729
15839
|
if (cachedData) {
|
|
15730
15840
|
import_node_server_utils81.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
15731
15841
|
return cachedData;
|
|
15732
15842
|
}
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15843
|
+
const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15844
|
+
const buildGroupedPipeline = (matchQuery) => [
|
|
15845
|
+
{ $match: matchQuery },
|
|
15846
|
+
{
|
|
15847
|
+
$lookup: {
|
|
15848
|
+
from: "building-units",
|
|
15849
|
+
localField: "unit",
|
|
15850
|
+
foreignField: "_id",
|
|
15851
|
+
as: "units",
|
|
15852
|
+
pipeline: [{ $project: { name: 1 } }]
|
|
15853
|
+
}
|
|
15854
|
+
},
|
|
15855
|
+
{ $unwind: { path: "$units", preserveNullAndEmptyArrays: true } },
|
|
15856
|
+
{
|
|
15857
|
+
$project: {
|
|
15858
|
+
_id: 1,
|
|
15859
|
+
name: 1,
|
|
15860
|
+
type: 1,
|
|
15861
|
+
category: 1,
|
|
15862
|
+
status: 1,
|
|
15863
|
+
phoneNumber: 1,
|
|
15864
|
+
block: 1,
|
|
15865
|
+
level: 1,
|
|
15866
|
+
unit: "$units.name",
|
|
15867
|
+
recNo: 1,
|
|
15868
|
+
nric: 1,
|
|
15869
|
+
plateNumber: 1
|
|
15870
|
+
}
|
|
15871
|
+
},
|
|
15872
|
+
{
|
|
15873
|
+
$group: {
|
|
15874
|
+
_id: {
|
|
15875
|
+
$cond: [
|
|
15876
|
+
{
|
|
15877
|
+
$and: [{ $ne: ["$nric", null] }, { $ne: ["$nric", ""] }]
|
|
15878
|
+
},
|
|
15879
|
+
{
|
|
15880
|
+
nric: "$nric",
|
|
15881
|
+
block: "$block",
|
|
15882
|
+
level: "$level",
|
|
15883
|
+
unit: "$unit"
|
|
15884
|
+
},
|
|
15885
|
+
"$_id"
|
|
15886
|
+
]
|
|
15887
|
+
},
|
|
15888
|
+
vehicleId: { $first: "$_id" },
|
|
15889
|
+
name: { $first: "$name" },
|
|
15890
|
+
category: { $first: "$category" },
|
|
15891
|
+
phoneNumber: { $first: "$phoneNumber" },
|
|
15892
|
+
block: { $first: "$block" },
|
|
15893
|
+
level: { $first: "$level" },
|
|
15894
|
+
unit: { $first: "$unit" },
|
|
15895
|
+
nric: { $first: "$nric" },
|
|
15896
|
+
plates: {
|
|
15897
|
+
$addToSet: {
|
|
15898
|
+
plateNumber: "$plateNumber",
|
|
15899
|
+
recNo: "$recNo",
|
|
15900
|
+
status: "$status",
|
|
15901
|
+
type: "$type"
|
|
15902
|
+
}
|
|
15746
15903
|
}
|
|
15747
|
-
}
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15904
|
+
}
|
|
15905
|
+
},
|
|
15906
|
+
{
|
|
15907
|
+
$project: {
|
|
15908
|
+
_id: "$vehicleId",
|
|
15909
|
+
name: 1,
|
|
15910
|
+
type: 1,
|
|
15911
|
+
category: 1,
|
|
15912
|
+
status: 1,
|
|
15913
|
+
phoneNumber: 1,
|
|
15914
|
+
block: 1,
|
|
15915
|
+
level: 1,
|
|
15916
|
+
unit: 1,
|
|
15917
|
+
nric: 1,
|
|
15918
|
+
plates: {
|
|
15919
|
+
$filter: {
|
|
15920
|
+
input: "$plates",
|
|
15921
|
+
as: "plate",
|
|
15922
|
+
cond: {
|
|
15923
|
+
$and: [
|
|
15924
|
+
{ $ne: ["$$plate.plateNumber", null] },
|
|
15925
|
+
{ $ne: ["$$plate.plateNumber", ""] }
|
|
15926
|
+
]
|
|
15927
|
+
}
|
|
15928
|
+
}
|
|
15761
15929
|
}
|
|
15762
15930
|
}
|
|
15763
|
-
|
|
15764
|
-
|
|
15931
|
+
},
|
|
15932
|
+
{ $sort: sort },
|
|
15933
|
+
{ $skip: page * limit },
|
|
15934
|
+
{ $limit: limit }
|
|
15935
|
+
];
|
|
15936
|
+
const buildGroupedCountPipeline = (matchQuery) => [
|
|
15937
|
+
{ $match: matchQuery },
|
|
15938
|
+
{
|
|
15939
|
+
$group: {
|
|
15940
|
+
_id: {
|
|
15941
|
+
$cond: [
|
|
15942
|
+
{
|
|
15943
|
+
$and: [{ $ne: ["$nric", null] }, { $ne: ["$nric", ""] }]
|
|
15944
|
+
},
|
|
15945
|
+
{
|
|
15946
|
+
nric: "$nric",
|
|
15947
|
+
block: "$block",
|
|
15948
|
+
level: "$level",
|
|
15949
|
+
unit: "$unit"
|
|
15950
|
+
},
|
|
15951
|
+
"$_id"
|
|
15952
|
+
]
|
|
15953
|
+
}
|
|
15954
|
+
}
|
|
15955
|
+
},
|
|
15956
|
+
{ $count: "total" }
|
|
15957
|
+
];
|
|
15958
|
+
try {
|
|
15959
|
+
let items = [];
|
|
15960
|
+
let length = 0;
|
|
15961
|
+
items = await collection.aggregate(buildGroupedPipeline(query)).toArray();
|
|
15962
|
+
const countResult = await collection.aggregate(buildGroupedCountPipeline(query)).toArray();
|
|
15963
|
+
length = countResult[0]?.total || 0;
|
|
15964
|
+
if ((!items || items.length === 0) && search) {
|
|
15965
|
+
const escaped = escapeRegex(search);
|
|
15966
|
+
const regexQuery = {
|
|
15967
|
+
...baseQuery,
|
|
15968
|
+
$or: [
|
|
15969
|
+
{ name: { $regex: escaped, $options: "i" } },
|
|
15970
|
+
{ plateNumber: { $regex: escaped, $options: "i" } },
|
|
15971
|
+
{ company: { $regex: escaped, $options: "i" } },
|
|
15972
|
+
{ level: { $regex: escaped, $options: "i" } },
|
|
15973
|
+
{ unitName: { $regex: escaped, $options: "i" } },
|
|
15974
|
+
{ contact: { $regex: escaped, $options: "i" } },
|
|
15975
|
+
{ nric: { $regex: escaped, $options: "i" } }
|
|
15976
|
+
]
|
|
15977
|
+
};
|
|
15978
|
+
items = await collection.aggregate(buildGroupedPipeline(regexQuery)).toArray();
|
|
15979
|
+
const regexCountResult = await collection.aggregate(buildGroupedCountPipeline(regexQuery)).toArray();
|
|
15980
|
+
length = regexCountResult[0]?.total || 0;
|
|
15981
|
+
}
|
|
15765
15982
|
const data = (0, import_node_server_utils81.paginate)(items, page, limit, length);
|
|
15766
|
-
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
15767
|
-
import_node_server_utils81.logger.
|
|
15768
|
-
|
|
15769
|
-
import_node_server_utils81.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
15770
|
-
});
|
|
15983
|
+
setCache(cacheKey, data, 15 * 60).then(() => import_node_server_utils81.logger.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
15984
|
+
(err) => import_node_server_utils81.logger.error(`Failed to set cache for key: ${cacheKey}`, err)
|
|
15985
|
+
);
|
|
15771
15986
|
return data;
|
|
15772
15987
|
} catch (error) {
|
|
15773
15988
|
throw error;
|
|
@@ -15840,40 +16055,176 @@ function useVehicleRepo() {
|
|
|
15840
16055
|
}
|
|
15841
16056
|
const data = await collection.aggregate([
|
|
15842
16057
|
{ $match: { _id } },
|
|
16058
|
+
{ $limit: 1 },
|
|
16059
|
+
{
|
|
16060
|
+
$project: {
|
|
16061
|
+
_id: 1,
|
|
16062
|
+
nric: 1,
|
|
16063
|
+
block: 1,
|
|
16064
|
+
level: 1,
|
|
16065
|
+
unit: 1
|
|
16066
|
+
}
|
|
16067
|
+
},
|
|
15843
16068
|
{
|
|
15844
16069
|
$lookup: {
|
|
15845
|
-
from:
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
16070
|
+
from: collection.collectionName,
|
|
16071
|
+
let: {
|
|
16072
|
+
vehicleId: "$_id",
|
|
16073
|
+
vehicleNric: "$nric",
|
|
16074
|
+
vehicleBlock: "$block",
|
|
16075
|
+
vehicleLevel: "$level",
|
|
16076
|
+
vehicleUnit: "$unit"
|
|
16077
|
+
},
|
|
16078
|
+
pipeline: [
|
|
16079
|
+
{
|
|
16080
|
+
$match: {
|
|
16081
|
+
$expr: {
|
|
16082
|
+
$cond: [
|
|
16083
|
+
{
|
|
16084
|
+
$and: [
|
|
16085
|
+
{ $ne: ["$$vehicleNric", null] },
|
|
16086
|
+
{ $ne: ["$$vehicleNric", ""] }
|
|
16087
|
+
]
|
|
16088
|
+
},
|
|
16089
|
+
{
|
|
16090
|
+
$and: [
|
|
16091
|
+
{ $eq: ["$nric", "$$vehicleNric"] },
|
|
16092
|
+
{ $eq: ["$block", "$$vehicleBlock"] },
|
|
16093
|
+
{ $eq: ["$level", "$$vehicleLevel"] },
|
|
16094
|
+
{ $eq: ["$unit", "$$vehicleUnit"] }
|
|
16095
|
+
]
|
|
16096
|
+
},
|
|
16097
|
+
{ $eq: ["$_id", "$$vehicleId"] }
|
|
16098
|
+
]
|
|
16099
|
+
}
|
|
16100
|
+
}
|
|
16101
|
+
},
|
|
16102
|
+
{
|
|
16103
|
+
$lookup: {
|
|
16104
|
+
from: "building-units",
|
|
16105
|
+
localField: "unit",
|
|
16106
|
+
foreignField: "_id",
|
|
16107
|
+
as: "units",
|
|
16108
|
+
pipeline: [{ $project: { name: 1 } }]
|
|
16109
|
+
}
|
|
16110
|
+
},
|
|
16111
|
+
{
|
|
16112
|
+
$unwind: { path: "$units", preserveNullAndEmptyArrays: true }
|
|
16113
|
+
},
|
|
16114
|
+
{
|
|
16115
|
+
$project: {
|
|
16116
|
+
_id: 1,
|
|
16117
|
+
name: 1,
|
|
16118
|
+
phoneNumber: 1,
|
|
16119
|
+
plateNumber: 1,
|
|
16120
|
+
nric: 1,
|
|
16121
|
+
block: 1,
|
|
16122
|
+
level: 1,
|
|
16123
|
+
rawUnit: "$unit",
|
|
16124
|
+
unit: "$units.name",
|
|
16125
|
+
type: 1,
|
|
16126
|
+
category: 1,
|
|
16127
|
+
status: 1,
|
|
16128
|
+
recNo: 1,
|
|
16129
|
+
start: 1,
|
|
16130
|
+
end: 1,
|
|
16131
|
+
seasonPassType: 1
|
|
16132
|
+
}
|
|
16133
|
+
},
|
|
16134
|
+
{
|
|
16135
|
+
$group: {
|
|
16136
|
+
_id: {
|
|
16137
|
+
$cond: [
|
|
16138
|
+
{
|
|
16139
|
+
$and: [
|
|
16140
|
+
{ $ne: ["$nric", null] },
|
|
16141
|
+
{ $ne: ["$nric", ""] }
|
|
16142
|
+
]
|
|
16143
|
+
},
|
|
16144
|
+
{
|
|
16145
|
+
nric: "$nric",
|
|
16146
|
+
block: "$block",
|
|
16147
|
+
level: "$level",
|
|
16148
|
+
unit: "$unit"
|
|
16149
|
+
},
|
|
16150
|
+
"$_id"
|
|
16151
|
+
]
|
|
16152
|
+
},
|
|
16153
|
+
vehicleId: { $first: "$_id" },
|
|
16154
|
+
name: { $first: "$name" },
|
|
16155
|
+
category: { $first: "$category" },
|
|
16156
|
+
phoneNumber: { $first: "$phoneNumber" },
|
|
16157
|
+
block: { $first: "$block" },
|
|
16158
|
+
level: { $first: "$level" },
|
|
16159
|
+
unit: { $first: "$unit" },
|
|
16160
|
+
nric: { $first: "$nric" },
|
|
16161
|
+
start: { $first: "$start" },
|
|
16162
|
+
end: { $first: "$end" },
|
|
16163
|
+
seasonPassType: { $first: "$seasonPassType" },
|
|
16164
|
+
plates: {
|
|
16165
|
+
$addToSet: {
|
|
16166
|
+
plateNumber: "$plateNumber",
|
|
16167
|
+
recNo: "$recNo",
|
|
16168
|
+
status: "$status",
|
|
16169
|
+
type: "$type"
|
|
16170
|
+
}
|
|
16171
|
+
}
|
|
16172
|
+
}
|
|
16173
|
+
},
|
|
16174
|
+
{
|
|
16175
|
+
$project: {
|
|
16176
|
+
_id: "$vehicleId",
|
|
16177
|
+
name: 1,
|
|
16178
|
+
phoneNumber: 1,
|
|
16179
|
+
nric: 1,
|
|
16180
|
+
block: 1,
|
|
16181
|
+
level: 1,
|
|
16182
|
+
unit: 1,
|
|
16183
|
+
type: 1,
|
|
16184
|
+
category: 1,
|
|
16185
|
+
status: 1,
|
|
16186
|
+
start: 1,
|
|
16187
|
+
end: 1,
|
|
16188
|
+
seasonPassType: 1,
|
|
16189
|
+
plates: {
|
|
16190
|
+
$filter: {
|
|
16191
|
+
input: "$plates",
|
|
16192
|
+
as: "plate",
|
|
16193
|
+
cond: {
|
|
16194
|
+
$and: [
|
|
16195
|
+
{ $ne: ["$$plate.plateNumber", null] },
|
|
16196
|
+
{ $ne: ["$$plate.plateNumber", ""] }
|
|
16197
|
+
]
|
|
16198
|
+
}
|
|
16199
|
+
}
|
|
16200
|
+
}
|
|
16201
|
+
}
|
|
16202
|
+
}
|
|
16203
|
+
],
|
|
16204
|
+
as: "vehicle"
|
|
15850
16205
|
}
|
|
15851
16206
|
},
|
|
15852
|
-
{ $unwind: { path: "$units", preserveNullAndEmptyArrays: true } },
|
|
15853
16207
|
{
|
|
15854
16208
|
$project: {
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
type: 1,
|
|
15862
|
-
category: 1,
|
|
15863
|
-
status: 1,
|
|
15864
|
-
recNo: 1
|
|
16209
|
+
vehicle: { $arrayElemAt: ["$vehicle", 0] }
|
|
16210
|
+
}
|
|
16211
|
+
},
|
|
16212
|
+
{
|
|
16213
|
+
$replaceRoot: {
|
|
16214
|
+
newRoot: "$vehicle"
|
|
15865
16215
|
}
|
|
15866
16216
|
}
|
|
15867
16217
|
]).toArray();
|
|
15868
16218
|
if (!data || !data.length) {
|
|
15869
16219
|
throw new import_node_server_utils81.NotFoundError("Vehicle not found.");
|
|
15870
16220
|
}
|
|
15871
|
-
|
|
16221
|
+
const result = data[0];
|
|
16222
|
+
setCache(cacheKey, result, 15 * 60).then(() => {
|
|
15872
16223
|
import_node_server_utils81.logger.info(`Cache set for key: ${cacheKey}`);
|
|
15873
16224
|
}).catch((err) => {
|
|
15874
16225
|
import_node_server_utils81.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
15875
16226
|
});
|
|
15876
|
-
return
|
|
16227
|
+
return result;
|
|
15877
16228
|
} catch (error) {
|
|
15878
16229
|
throw error;
|
|
15879
16230
|
}
|
|
@@ -15910,7 +16261,7 @@ function useVehicleRepo() {
|
|
|
15910
16261
|
throw error2;
|
|
15911
16262
|
}
|
|
15912
16263
|
}
|
|
15913
|
-
async function updateVehicle(_id, value) {
|
|
16264
|
+
async function updateVehicle(_id, value, session) {
|
|
15914
16265
|
try {
|
|
15915
16266
|
_id = new import_mongodb46.ObjectId(_id);
|
|
15916
16267
|
} catch (error) {
|
|
@@ -15921,7 +16272,11 @@ function useVehicleRepo() {
|
|
|
15921
16272
|
...value,
|
|
15922
16273
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15923
16274
|
};
|
|
15924
|
-
const res = await collection.updateOne(
|
|
16275
|
+
const res = await collection.updateOne(
|
|
16276
|
+
{ _id },
|
|
16277
|
+
{ $set: updateValue },
|
|
16278
|
+
{ session }
|
|
16279
|
+
);
|
|
15925
16280
|
if (res.modifiedCount === 0) {
|
|
15926
16281
|
throw new import_node_server_utils81.InternalServerError("Unable to update vehicle.");
|
|
15927
16282
|
}
|
|
@@ -16000,8 +16355,94 @@ function useVehicleRepo() {
|
|
|
16000
16355
|
);
|
|
16001
16356
|
}
|
|
16002
16357
|
}
|
|
16358
|
+
async function getVehiclesByNRIC({
|
|
16359
|
+
page = 1,
|
|
16360
|
+
limit = 10,
|
|
16361
|
+
nric = "",
|
|
16362
|
+
sort = {}
|
|
16363
|
+
}) {
|
|
16364
|
+
page = page > 0 ? page - 1 : 0;
|
|
16365
|
+
if (!nric) {
|
|
16366
|
+
throw new import_node_server_utils81.BadRequestError("NRIC is required.");
|
|
16367
|
+
}
|
|
16368
|
+
const _nric = nric.trim();
|
|
16369
|
+
const query = {
|
|
16370
|
+
deletedAt: "",
|
|
16371
|
+
nric: _nric
|
|
16372
|
+
};
|
|
16373
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
16374
|
+
const cacheOptions = {
|
|
16375
|
+
deletedAt: "",
|
|
16376
|
+
nric: _nric,
|
|
16377
|
+
page: String(page),
|
|
16378
|
+
limit: String(limit),
|
|
16379
|
+
sort: JSON.stringify(sort)
|
|
16380
|
+
};
|
|
16381
|
+
const cacheKey = (0, import_node_server_utils81.makeCacheKey)(namespace_collection, cacheOptions);
|
|
16382
|
+
const cachedData = await getCache(cacheKey);
|
|
16383
|
+
if (cachedData) {
|
|
16384
|
+
import_node_server_utils81.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
16385
|
+
return cachedData;
|
|
16386
|
+
}
|
|
16387
|
+
try {
|
|
16388
|
+
const items = await collection.aggregate([
|
|
16389
|
+
{ $match: query },
|
|
16390
|
+
{ $sort: sort },
|
|
16391
|
+
{ $skip: page * limit },
|
|
16392
|
+
{ $limit: limit },
|
|
16393
|
+
{
|
|
16394
|
+
$project: {
|
|
16395
|
+
name: 1,
|
|
16396
|
+
phoneNumber: 1,
|
|
16397
|
+
plateNumber: 1,
|
|
16398
|
+
recNo: 1,
|
|
16399
|
+
nric: 1,
|
|
16400
|
+
status: 1,
|
|
16401
|
+
type: 1
|
|
16402
|
+
}
|
|
16403
|
+
}
|
|
16404
|
+
]).toArray();
|
|
16405
|
+
const length = await collection.countDocuments(query);
|
|
16406
|
+
const data = (0, import_node_server_utils81.paginate)(items, page, limit, length);
|
|
16407
|
+
setCache(cacheKey, data, 15 * 60).then(() => import_node_server_utils81.logger.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
16408
|
+
(err) => import_node_server_utils81.logger.error(`Failed to set cache for key: ${cacheKey}`, err)
|
|
16409
|
+
);
|
|
16410
|
+
return data;
|
|
16411
|
+
} catch (error) {
|
|
16412
|
+
throw error;
|
|
16413
|
+
}
|
|
16414
|
+
}
|
|
16415
|
+
async function deleteExpiredVehicles(session) {
|
|
16416
|
+
try {
|
|
16417
|
+
const tenYearsAgo = /* @__PURE__ */ new Date();
|
|
16418
|
+
tenYearsAgo.setFullYear(tenYearsAgo.getFullYear() - 10);
|
|
16419
|
+
const res = await collection.updateMany(
|
|
16420
|
+
{
|
|
16421
|
+
status: { $ne: "deleted" },
|
|
16422
|
+
end: { $exists: true, $lte: tenYearsAgo }
|
|
16423
|
+
// check only end
|
|
16424
|
+
},
|
|
16425
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } },
|
|
16426
|
+
{ session }
|
|
16427
|
+
);
|
|
16428
|
+
if (res.modifiedCount === 0)
|
|
16429
|
+
throw new import_node_server_utils81.InternalServerError("Unable to delete vehicle.");
|
|
16430
|
+
delNamespace().then(() => {
|
|
16431
|
+
import_node_server_utils81.logger.info(`Cache cleared for namespace: ${namespace_collection}`);
|
|
16432
|
+
}).catch((err) => {
|
|
16433
|
+
import_node_server_utils81.logger.error(
|
|
16434
|
+
`Failed to clear cache for namespace: ${namespace_collection}`,
|
|
16435
|
+
err
|
|
16436
|
+
);
|
|
16437
|
+
});
|
|
16438
|
+
return res.modifiedCount;
|
|
16439
|
+
} catch (error) {
|
|
16440
|
+
throw error;
|
|
16441
|
+
}
|
|
16442
|
+
}
|
|
16003
16443
|
return {
|
|
16004
16444
|
createIndex,
|
|
16445
|
+
createTextIndex,
|
|
16005
16446
|
add,
|
|
16006
16447
|
getVehicles,
|
|
16007
16448
|
getSeasonPassTypes,
|
|
@@ -16009,7 +16450,9 @@ function useVehicleRepo() {
|
|
|
16009
16450
|
updateVehicle,
|
|
16010
16451
|
deleteVehicle,
|
|
16011
16452
|
getByPlaceNumber,
|
|
16012
|
-
getVehicleByPlateNumber
|
|
16453
|
+
getVehicleByPlateNumber,
|
|
16454
|
+
getVehiclesByNRIC,
|
|
16455
|
+
deleteExpiredVehicles
|
|
16013
16456
|
};
|
|
16014
16457
|
}
|
|
16015
16458
|
|
|
@@ -16395,7 +16838,7 @@ function useDahuaService() {
|
|
|
16395
16838
|
username: import_joi45.default.string().required(),
|
|
16396
16839
|
password: import_joi45.default.string().required(),
|
|
16397
16840
|
plateNumber: import_joi45.default.string().required(),
|
|
16398
|
-
mode: import_joi45.default.string().valid(
|
|
16841
|
+
mode: import_joi45.default.string().valid(...Object.values(ANPRMode)).required(),
|
|
16399
16842
|
start: import_joi45.default.string().isoDate().optional().allow("", null),
|
|
16400
16843
|
end: import_joi45.default.string().isoDate().optional().allow("", null),
|
|
16401
16844
|
owner: import_joi45.default.string().optional().allow("", null)
|
|
@@ -16461,18 +16904,154 @@ function useDahuaService() {
|
|
|
16461
16904
|
|
|
16462
16905
|
// src/services/vehicle.service.ts
|
|
16463
16906
|
var import_node_server_utils83 = require("@7365admin1/node-server-utils");
|
|
16907
|
+
function formatDahuaDate(date) {
|
|
16908
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
16909
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
|
|
16910
|
+
date.getDate()
|
|
16911
|
+
)} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(
|
|
16912
|
+
date.getSeconds()
|
|
16913
|
+
)}`;
|
|
16914
|
+
}
|
|
16464
16915
|
function useVehicleService() {
|
|
16465
|
-
const {
|
|
16916
|
+
const {
|
|
16917
|
+
add: _add,
|
|
16918
|
+
deleteVehicle: _deleteVehicle,
|
|
16919
|
+
updateVehicle: _updateVehicle,
|
|
16920
|
+
getVehicleById: _getVehicleById,
|
|
16921
|
+
deleteExpiredVehicles: _deleteExpiredVehicles
|
|
16922
|
+
} = useVehicleRepo();
|
|
16466
16923
|
const {
|
|
16467
16924
|
addPlateNumber: _addPlateNumber,
|
|
16468
16925
|
removePlateNumber: _removePlateNumber
|
|
16469
16926
|
} = useDahuaService();
|
|
16470
16927
|
const { getAllCameraWithPassword: _getAllSiteCameras } = useSiteCameraRepo();
|
|
16928
|
+
const { getById: _getById } = useOrgRepo();
|
|
16471
16929
|
async function add(value) {
|
|
16472
16930
|
const session = import_node_server_utils83.useAtlas.getClient()?.startSession();
|
|
16473
16931
|
if (!session) {
|
|
16474
16932
|
throw new Error("Unable to start session for vehicle service.");
|
|
16475
16933
|
}
|
|
16934
|
+
const org = await _getById(value.org);
|
|
16935
|
+
if (!org)
|
|
16936
|
+
throw new import_node_server_utils83.BadRequestError("Org not found");
|
|
16937
|
+
if (!Object.values(OrgNature).includes(org.nature)) {
|
|
16938
|
+
throw new import_node_server_utils83.BadRequestError(
|
|
16939
|
+
"This organization is not allowed to add vehicles."
|
|
16940
|
+
);
|
|
16941
|
+
}
|
|
16942
|
+
value.status = "active" /* ACTIVE */;
|
|
16943
|
+
const addedBySecurity = org.nature === "security_agency" /* SECURITY_AGENCY */;
|
|
16944
|
+
const addedByPM = org.nature === "property_management_agency" /* PROPERTY_MANAGEMENT_AGENCY */;
|
|
16945
|
+
if (addedBySecurity)
|
|
16946
|
+
value.status = "pending" /* PENDING */;
|
|
16947
|
+
const isBlocklist = value.type === "blocklist" /* BLOCKLIST */;
|
|
16948
|
+
if (isBlocklist)
|
|
16949
|
+
value.status = "inactive" /* INACTIVE */;
|
|
16950
|
+
const _type = value.type;
|
|
16951
|
+
const _mode = isBlocklist ? "TrafficBlackList" /* TRAFFIC_BLACKLIST */ : "TrafficRedList" /* TRAFFIC_REDLIST */;
|
|
16952
|
+
const hasStart = typeof value.start === "string" ? value.start.trim() !== "" : !!value.start;
|
|
16953
|
+
const hasEnd = typeof value.end === "string" ? value.end.trim() !== "" : !!value.end;
|
|
16954
|
+
let startDate = null;
|
|
16955
|
+
let endDate = null;
|
|
16956
|
+
let start = "";
|
|
16957
|
+
let end = "";
|
|
16958
|
+
let startDateDahua;
|
|
16959
|
+
let endDateDahua;
|
|
16960
|
+
if (addedByPM && !hasStart && !hasEnd) {
|
|
16961
|
+
startDate = /* @__PURE__ */ new Date();
|
|
16962
|
+
endDate = new Date(startDate);
|
|
16963
|
+
endDate.setFullYear(endDate.getFullYear() + 10);
|
|
16964
|
+
start = startDate.toISOString();
|
|
16965
|
+
end = endDate.toISOString();
|
|
16966
|
+
startDateDahua = formatDahuaDate(startDate);
|
|
16967
|
+
endDateDahua = formatDahuaDate(endDate);
|
|
16968
|
+
} else {
|
|
16969
|
+
if (hasStart) {
|
|
16970
|
+
startDate = new Date(value.start);
|
|
16971
|
+
start = startDate.toISOString();
|
|
16972
|
+
startDateDahua = formatDahuaDate(startDate);
|
|
16973
|
+
}
|
|
16974
|
+
if (hasEnd) {
|
|
16975
|
+
endDate = new Date(value.end);
|
|
16976
|
+
end = endDate.toISOString();
|
|
16977
|
+
endDateDahua = formatDahuaDate(endDate);
|
|
16978
|
+
}
|
|
16979
|
+
}
|
|
16980
|
+
const owner = String(value.name ?? "").substring(0, 15);
|
|
16981
|
+
const plateNumbers = value.plateNumber;
|
|
16982
|
+
try {
|
|
16983
|
+
session.startTransaction();
|
|
16984
|
+
let message = "Vehicle plate number needs approval from property management.";
|
|
16985
|
+
let siteCameras = [];
|
|
16986
|
+
if (value.status && value.status !== "pending" /* PENDING */) {
|
|
16987
|
+
let page = 1;
|
|
16988
|
+
let pages = 1;
|
|
16989
|
+
const limit = 20;
|
|
16990
|
+
do {
|
|
16991
|
+
const siteCameraReq = await _getAllSiteCameras({
|
|
16992
|
+
site: value.site,
|
|
16993
|
+
type: "anpr",
|
|
16994
|
+
direction: ["both", "entry"],
|
|
16995
|
+
page,
|
|
16996
|
+
limit
|
|
16997
|
+
});
|
|
16998
|
+
pages = siteCameraReq.pages || 1;
|
|
16999
|
+
siteCameras.push(...siteCameraReq.items);
|
|
17000
|
+
page++;
|
|
17001
|
+
} while (page <= pages);
|
|
17002
|
+
if (!siteCameras.length) {
|
|
17003
|
+
throw new import_node_server_utils83.BadRequestError("No site cameras found.");
|
|
17004
|
+
}
|
|
17005
|
+
}
|
|
17006
|
+
for (const plateNumber of plateNumbers) {
|
|
17007
|
+
const vehicleValue = {
|
|
17008
|
+
...value,
|
|
17009
|
+
plateNumber,
|
|
17010
|
+
start,
|
|
17011
|
+
end
|
|
17012
|
+
};
|
|
17013
|
+
if (vehicleValue.status && vehicleValue.status !== "pending" /* PENDING */) {
|
|
17014
|
+
for (const camera of siteCameras) {
|
|
17015
|
+
const { host, username, password } = camera;
|
|
17016
|
+
const dahuaPayload = {
|
|
17017
|
+
host,
|
|
17018
|
+
username,
|
|
17019
|
+
password,
|
|
17020
|
+
plateNumber,
|
|
17021
|
+
mode: _mode,
|
|
17022
|
+
owner,
|
|
17023
|
+
...startDateDahua ? { start: startDateDahua } : {},
|
|
17024
|
+
...endDateDahua ? { end: endDateDahua } : {}
|
|
17025
|
+
};
|
|
17026
|
+
const dahuaResponse = await _addPlateNumber(dahuaPayload);
|
|
17027
|
+
if (dahuaResponse?.statusCode !== 200) {
|
|
17028
|
+
throw new import_node_server_utils83.BadRequestError(
|
|
17029
|
+
`Failed to add plate number to ANPR ${_type}`
|
|
17030
|
+
);
|
|
17031
|
+
}
|
|
17032
|
+
const responseData = dahuaResponse?.data?.toString("utf-8") ?? "";
|
|
17033
|
+
vehicleValue.recNo = responseData.split("=")[1]?.trim();
|
|
17034
|
+
}
|
|
17035
|
+
message = `Vehicle plate number added to ${_type} successfully.`;
|
|
17036
|
+
}
|
|
17037
|
+
await _add(vehicleValue, session);
|
|
17038
|
+
}
|
|
17039
|
+
await session.commitTransaction();
|
|
17040
|
+
return message;
|
|
17041
|
+
} catch (error) {
|
|
17042
|
+
import_node_server_utils83.logger.error("Error in vehicle service add:", error);
|
|
17043
|
+
await session.abortTransaction();
|
|
17044
|
+
throw error;
|
|
17045
|
+
} finally {
|
|
17046
|
+
session.endSession();
|
|
17047
|
+
}
|
|
17048
|
+
}
|
|
17049
|
+
async function deleteVehicle(_id, recno, site, type, bypass = false) {
|
|
17050
|
+
const session = import_node_server_utils83.useAtlas.getClient()?.startSession();
|
|
17051
|
+
if (!session) {
|
|
17052
|
+
throw new Error("Unable to start session for vehicle service.");
|
|
17053
|
+
}
|
|
17054
|
+
const _mode = type !== "whitelist" /* WHITELIST */ ? "TrafficBlackList" /* TRAFFIC_BLACKLIST */ : "TrafficRedList" /* TRAFFIC_REDLIST */;
|
|
16476
17055
|
try {
|
|
16477
17056
|
session.startTransaction();
|
|
16478
17057
|
const siteCameras = [];
|
|
@@ -16481,9 +17060,8 @@ function useVehicleService() {
|
|
|
16481
17060
|
const limit = 20;
|
|
16482
17061
|
do {
|
|
16483
17062
|
const siteCameraReq = await _getAllSiteCameras({
|
|
16484
|
-
site
|
|
17063
|
+
site,
|
|
16485
17064
|
type: "anpr",
|
|
16486
|
-
direction: ["both", "entry"],
|
|
16487
17065
|
page,
|
|
16488
17066
|
limit
|
|
16489
17067
|
});
|
|
@@ -16495,55 +17073,82 @@ function useVehicleService() {
|
|
|
16495
17073
|
throw new import_node_server_utils83.BadRequestError("No site cameras found.");
|
|
16496
17074
|
}
|
|
16497
17075
|
for (const camera of siteCameras) {
|
|
16498
|
-
const
|
|
17076
|
+
const host = camera.host;
|
|
17077
|
+
const username = camera.username;
|
|
17078
|
+
const password = camera.password;
|
|
16499
17079
|
const dahuaPayload = {
|
|
16500
17080
|
host,
|
|
16501
17081
|
username,
|
|
16502
17082
|
password,
|
|
16503
|
-
|
|
16504
|
-
mode:
|
|
16505
|
-
start: value.start ? new Date(value.start).toISOString() : "",
|
|
16506
|
-
end: value.end ? new Date(value.end).toISOString() : "",
|
|
16507
|
-
owner: value.name
|
|
17083
|
+
recno,
|
|
17084
|
+
mode: _mode
|
|
16508
17085
|
};
|
|
16509
|
-
const dahuaResponse = await
|
|
16510
|
-
if (dahuaResponse?.statusCode !== 200) {
|
|
16511
|
-
throw new import_node_server_utils83.BadRequestError(
|
|
17086
|
+
const dahuaResponse = await _removePlateNumber(dahuaPayload);
|
|
17087
|
+
if (!bypass && dahuaResponse?.statusCode !== 200) {
|
|
17088
|
+
throw new import_node_server_utils83.BadRequestError(
|
|
17089
|
+
`Failed to remove plate number to ANPR from ${type}`
|
|
17090
|
+
);
|
|
16512
17091
|
}
|
|
16513
|
-
const responseData = dahuaResponse?.data.toString("utf-8");
|
|
16514
|
-
value.recNo = responseData.split("=")[1]?.trim();
|
|
16515
|
-
const formattedValue = {
|
|
16516
|
-
...value,
|
|
16517
|
-
start: value.start ? new Date(value.start).toISOString() : "",
|
|
16518
|
-
end: value.end ? new Date(value.end).toISOString() : ""
|
|
16519
|
-
};
|
|
16520
|
-
await _add(formattedValue, session);
|
|
16521
17092
|
}
|
|
17093
|
+
await _deleteVehicle(_id, session);
|
|
16522
17094
|
await session.commitTransaction();
|
|
16523
|
-
return
|
|
17095
|
+
return `Vehicle plate number deleted from ${type} record successfully.`;
|
|
16524
17096
|
} catch (error) {
|
|
16525
|
-
import_node_server_utils83.logger.error("Error in vehicle service add:", error);
|
|
16526
17097
|
await session.abortTransaction();
|
|
16527
|
-
|
|
17098
|
+
if (error instanceof import_node_server_utils83.AppError)
|
|
17099
|
+
throw error;
|
|
17100
|
+
throw new import_node_server_utils83.InternalServerError("Failed to delete vehicle");
|
|
16528
17101
|
} finally {
|
|
16529
17102
|
session.endSession();
|
|
16530
17103
|
}
|
|
16531
17104
|
}
|
|
16532
|
-
async function
|
|
17105
|
+
async function approveVehicleById(id, orgId, siteId) {
|
|
16533
17106
|
const session = import_node_server_utils83.useAtlas.getClient()?.startSession();
|
|
16534
17107
|
if (!session) {
|
|
16535
17108
|
throw new Error("Unable to start session for vehicle service.");
|
|
16536
17109
|
}
|
|
17110
|
+
const org = await _getById(orgId);
|
|
17111
|
+
if (!org)
|
|
17112
|
+
throw new import_node_server_utils83.BadRequestError("Org not found");
|
|
17113
|
+
const allowedNatures2 = ["property_management_agency"];
|
|
17114
|
+
if (!allowedNatures2.includes(org.nature)) {
|
|
17115
|
+
throw new import_node_server_utils83.BadRequestError(
|
|
17116
|
+
"Only property management can approve vehicles."
|
|
17117
|
+
);
|
|
17118
|
+
}
|
|
17119
|
+
const vehicle = await _getVehicleById(id);
|
|
17120
|
+
if (!vehicle) {
|
|
17121
|
+
throw new import_node_server_utils83.BadRequestError("Vehicle not found");
|
|
17122
|
+
}
|
|
17123
|
+
const owner = vehicle.name.substring(0, 15);
|
|
17124
|
+
const hasStart = typeof vehicle.start === "string" ? vehicle.start.trim() !== "" : !!vehicle.start;
|
|
17125
|
+
const hasEnd = typeof vehicle.end === "string" ? vehicle.end.trim() !== "" : !!vehicle.end;
|
|
17126
|
+
let startDate = null;
|
|
17127
|
+
let endDate = null;
|
|
17128
|
+
if (!hasStart && !hasEnd) {
|
|
17129
|
+
startDate = /* @__PURE__ */ new Date();
|
|
17130
|
+
endDate = new Date(startDate);
|
|
17131
|
+
endDate.setFullYear(endDate.getFullYear() + 10);
|
|
17132
|
+
} else {
|
|
17133
|
+
startDate = hasStart ? new Date(vehicle.start) : null;
|
|
17134
|
+
endDate = hasEnd ? new Date(vehicle.end) : null;
|
|
17135
|
+
}
|
|
17136
|
+
const startIso = startDate ? startDate.toISOString() : "";
|
|
17137
|
+
const endIso = endDate ? endDate.toISOString() : "";
|
|
17138
|
+
const startDahua = startDate ? formatDahuaDate(startDate) : "";
|
|
17139
|
+
const endDahua = endDate ? formatDahuaDate(endDate) : "";
|
|
16537
17140
|
try {
|
|
16538
17141
|
session.startTransaction();
|
|
16539
17142
|
const siteCameras = [];
|
|
16540
17143
|
let page = 1;
|
|
16541
17144
|
let pages = 1;
|
|
16542
17145
|
const limit = 20;
|
|
17146
|
+
let value = {};
|
|
16543
17147
|
do {
|
|
16544
17148
|
const siteCameraReq = await _getAllSiteCameras({
|
|
16545
|
-
site,
|
|
17149
|
+
site: siteId,
|
|
16546
17150
|
type: "anpr",
|
|
17151
|
+
direction: ["both", "entry"],
|
|
16547
17152
|
page,
|
|
16548
17153
|
limit
|
|
16549
17154
|
});
|
|
@@ -16555,24 +17160,51 @@ function useVehicleService() {
|
|
|
16555
17160
|
throw new import_node_server_utils83.BadRequestError("No site cameras found.");
|
|
16556
17161
|
}
|
|
16557
17162
|
for (const camera of siteCameras) {
|
|
16558
|
-
const host = camera
|
|
16559
|
-
const username = camera.username;
|
|
16560
|
-
const password = camera.password;
|
|
17163
|
+
const { host, username, password } = camera;
|
|
16561
17164
|
const dahuaPayload = {
|
|
16562
17165
|
host,
|
|
16563
17166
|
username,
|
|
16564
17167
|
password,
|
|
16565
|
-
|
|
16566
|
-
mode: "TrafficRedList"
|
|
17168
|
+
plateNumber: vehicle.plateNumber,
|
|
17169
|
+
mode: "TrafficRedList" /* TRAFFIC_REDLIST */,
|
|
17170
|
+
start: startDahua,
|
|
17171
|
+
end: endDahua,
|
|
17172
|
+
owner
|
|
16567
17173
|
};
|
|
16568
|
-
const dahuaResponse = await
|
|
16569
|
-
if (
|
|
16570
|
-
throw new import_node_server_utils83.BadRequestError("Failed to
|
|
17174
|
+
const dahuaResponse = await _addPlateNumber(dahuaPayload);
|
|
17175
|
+
if (dahuaResponse?.statusCode !== 200) {
|
|
17176
|
+
throw new import_node_server_utils83.BadRequestError("Failed to add plate number to ANPR");
|
|
16571
17177
|
}
|
|
17178
|
+
const responseData = dahuaResponse?.data.toString("utf-8");
|
|
17179
|
+
value.recNo = responseData.split("=")[1]?.trim();
|
|
16572
17180
|
}
|
|
16573
|
-
|
|
17181
|
+
value.status = "active";
|
|
17182
|
+
const formattedValue = {
|
|
17183
|
+
...value,
|
|
17184
|
+
start: startIso,
|
|
17185
|
+
end: endIso
|
|
17186
|
+
};
|
|
17187
|
+
await _updateVehicle(id, formattedValue, session);
|
|
16574
17188
|
await session.commitTransaction();
|
|
16575
|
-
return "Vehicle plate number
|
|
17189
|
+
return "Vehicle plate number approved and added successfully.";
|
|
17190
|
+
} catch (error) {
|
|
17191
|
+
import_node_server_utils83.logger.error("Error in vehicle service add:", error);
|
|
17192
|
+
await session.abortTransaction();
|
|
17193
|
+
throw error;
|
|
17194
|
+
} finally {
|
|
17195
|
+
session.endSession();
|
|
17196
|
+
}
|
|
17197
|
+
}
|
|
17198
|
+
async function processDeletingExpiredVehicles() {
|
|
17199
|
+
const session = import_node_server_utils83.useAtlas.getClient()?.startSession();
|
|
17200
|
+
if (!session) {
|
|
17201
|
+
throw new Error("Unable to start session for vehicle service.");
|
|
17202
|
+
}
|
|
17203
|
+
try {
|
|
17204
|
+
session.startTransaction();
|
|
17205
|
+
await _deleteExpiredVehicles();
|
|
17206
|
+
await session.commitTransaction();
|
|
17207
|
+
return `Expired Vehicle plate numbers deleted successfully.`;
|
|
16576
17208
|
} catch (error) {
|
|
16577
17209
|
await session.abortTransaction();
|
|
16578
17210
|
if (error instanceof import_node_server_utils83.AppError)
|
|
@@ -16584,7 +17216,9 @@ function useVehicleService() {
|
|
|
16584
17216
|
}
|
|
16585
17217
|
return {
|
|
16586
17218
|
add,
|
|
16587
|
-
deleteVehicle
|
|
17219
|
+
deleteVehicle,
|
|
17220
|
+
approveVehicleById,
|
|
17221
|
+
processDeletingExpiredVehicles
|
|
16588
17222
|
};
|
|
16589
17223
|
}
|
|
16590
17224
|
|
|
@@ -16592,23 +17226,28 @@ function useVehicleService() {
|
|
|
16592
17226
|
var import_node_server_utils84 = require("@7365admin1/node-server-utils");
|
|
16593
17227
|
var import_joi46 = __toESM(require("joi"));
|
|
16594
17228
|
function useVehicleController() {
|
|
16595
|
-
const {
|
|
17229
|
+
const {
|
|
17230
|
+
add: _add,
|
|
17231
|
+
deleteVehicle: _deleteVehicle,
|
|
17232
|
+
approveVehicleById: _approveVehicleById
|
|
17233
|
+
} = useVehicleService();
|
|
16596
17234
|
const {
|
|
16597
17235
|
getSeasonPassTypes: _getSeasonPassTypes,
|
|
16598
17236
|
getVehicles: _getVehicles,
|
|
16599
17237
|
getVehicleById: _getVehicleById,
|
|
16600
|
-
updateVehicle: _updateVehicle
|
|
17238
|
+
updateVehicle: _updateVehicle,
|
|
17239
|
+
getVehiclesByNRIC: _getVehiclesByNRIC
|
|
16601
17240
|
} = useVehicleRepo();
|
|
16602
17241
|
async function add(req, res, next) {
|
|
16603
17242
|
const payload = req.body;
|
|
16604
|
-
const { error } = vehicleSchema.validate(payload);
|
|
17243
|
+
const { error, value } = vehicleSchema.validate(payload);
|
|
16605
17244
|
if (error) {
|
|
16606
17245
|
import_node_server_utils84.logger.log({ level: "error", message: error.message });
|
|
16607
17246
|
next(new import_node_server_utils84.BadRequestError(error.message));
|
|
16608
17247
|
return;
|
|
16609
17248
|
}
|
|
16610
17249
|
try {
|
|
16611
|
-
const data = await _add(
|
|
17250
|
+
const data = await _add(value);
|
|
16612
17251
|
res.status(201).json({
|
|
16613
17252
|
message: "Vehicle added successfully.",
|
|
16614
17253
|
data
|
|
@@ -16628,8 +17267,9 @@ function useVehicleController() {
|
|
|
16628
17267
|
limit: import_joi46.default.number().integer().min(1).max(100).allow("", null).default(10),
|
|
16629
17268
|
sort: import_joi46.default.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
16630
17269
|
order: import_joi46.default.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
16631
|
-
type: import_joi46.default.string().optional().allow(""
|
|
16632
|
-
category: import_joi46.default.string().optional().allow("",
|
|
17270
|
+
type: import_joi46.default.string().optional().valid(...Object.values(VehicleType)).allow(null, ""),
|
|
17271
|
+
category: import_joi46.default.string().optional().valid(...Object.values(VehicleCategory)).allow(null, ""),
|
|
17272
|
+
status: import_joi46.default.string().optional().valid(...Object.values(VehicleStatus)).allow(null, "")
|
|
16633
17273
|
});
|
|
16634
17274
|
const query = { ...req.query };
|
|
16635
17275
|
const { error } = validation.validate(query);
|
|
@@ -16643,6 +17283,7 @@ function useVehicleController() {
|
|
|
16643
17283
|
const limit = parseInt(req.query.limit ?? "10");
|
|
16644
17284
|
const type = req.query.type ?? "";
|
|
16645
17285
|
const category = req.query.category ?? "";
|
|
17286
|
+
const status = req.query.status ?? "";
|
|
16646
17287
|
const sortObj = {};
|
|
16647
17288
|
const sortFields = String(req.query.sort).split(",");
|
|
16648
17289
|
const sortOrders = String(req.query.order).split(",");
|
|
@@ -16659,7 +17300,8 @@ function useVehicleController() {
|
|
|
16659
17300
|
limit,
|
|
16660
17301
|
sort: sortObj,
|
|
16661
17302
|
type,
|
|
16662
|
-
category
|
|
17303
|
+
category,
|
|
17304
|
+
status
|
|
16663
17305
|
});
|
|
16664
17306
|
res.json(data);
|
|
16665
17307
|
return;
|
|
@@ -16715,7 +17357,8 @@ function useVehicleController() {
|
|
|
16715
17357
|
block: import_joi46.default.number().integer().optional().allow(0, null),
|
|
16716
17358
|
level: import_joi46.default.string().optional().allow("", null),
|
|
16717
17359
|
unit: import_joi46.default.string().optional().allow("", null),
|
|
16718
|
-
plateNumber: import_joi46.default.string().optional().allow("", null)
|
|
17360
|
+
plateNumber: import_joi46.default.string().optional().allow("", null),
|
|
17361
|
+
nric: import_joi46.default.string().optional().allow("", null)
|
|
16719
17362
|
});
|
|
16720
17363
|
const _id = req.params.id;
|
|
16721
17364
|
const payload = { ...req.body };
|
|
@@ -16736,23 +17379,23 @@ function useVehicleController() {
|
|
|
16736
17379
|
}
|
|
16737
17380
|
}
|
|
16738
17381
|
async function deleteVehicle(req, res, next) {
|
|
16739
|
-
const
|
|
16740
|
-
const _id = req.params.id ?? "";
|
|
16741
|
-
const recno = req.params.recno ?? "";
|
|
16742
|
-
const bypass = req.query.bypass === "true";
|
|
17382
|
+
const _id = req.params.id;
|
|
16743
17383
|
const deleteVehicleSchema = import_joi46.default.object({
|
|
16744
|
-
_id: import_joi46.default.string().hex().required(),
|
|
17384
|
+
_id: import_joi46.default.string().hex().length(24).required(),
|
|
16745
17385
|
recno: import_joi46.default.string().required(),
|
|
16746
|
-
|
|
17386
|
+
site: import_joi46.default.string().hex().length(24).required(),
|
|
17387
|
+
type: import_joi46.default.string().valid("whitelist", "blocklist").required(),
|
|
17388
|
+
bypass: import_joi46.default.boolean().optional().default(true)
|
|
16747
17389
|
});
|
|
16748
|
-
const { error } = deleteVehicleSchema.validate({ _id,
|
|
17390
|
+
const { error, value } = deleteVehicleSchema.validate({ _id, ...req.body });
|
|
16749
17391
|
if (error) {
|
|
16750
17392
|
import_node_server_utils84.logger.log({ level: "error", message: error.message });
|
|
16751
17393
|
next(new import_node_server_utils84.BadRequestError(error.message));
|
|
16752
17394
|
return;
|
|
16753
17395
|
}
|
|
17396
|
+
const { recno, site, type, bypass } = value;
|
|
16754
17397
|
try {
|
|
16755
|
-
const data = await _deleteVehicle(_id, recno, site, bypass);
|
|
17398
|
+
const data = await _deleteVehicle(_id, recno, site, type, bypass);
|
|
16756
17399
|
res.json({
|
|
16757
17400
|
message: "Vehicle deleted successfully.",
|
|
16758
17401
|
data
|
|
@@ -16763,13 +17406,83 @@ function useVehicleController() {
|
|
|
16763
17406
|
return;
|
|
16764
17407
|
}
|
|
16765
17408
|
}
|
|
17409
|
+
async function approveVehicleById(req, res, next) {
|
|
17410
|
+
const validation = import_joi46.default.object({
|
|
17411
|
+
_id: import_joi46.default.string().hex().length(24).required(),
|
|
17412
|
+
org: import_joi46.default.string().hex().length(24).required(),
|
|
17413
|
+
site: import_joi46.default.string().hex().length(24).required()
|
|
17414
|
+
});
|
|
17415
|
+
const _id = req.params.id;
|
|
17416
|
+
const payload = { ...req.body };
|
|
17417
|
+
const { error, value } = validation.validate({ _id, ...payload });
|
|
17418
|
+
if (error) {
|
|
17419
|
+
import_node_server_utils84.logger.log({ level: "error", message: error.message });
|
|
17420
|
+
next(new import_node_server_utils84.BadRequestError(error.message));
|
|
17421
|
+
return;
|
|
17422
|
+
}
|
|
17423
|
+
try {
|
|
17424
|
+
await _approveVehicleById(value._id, value.org, value.site);
|
|
17425
|
+
res.json({ message: "Successfully approved and updated vehicle." });
|
|
17426
|
+
return;
|
|
17427
|
+
} catch (error2) {
|
|
17428
|
+
import_node_server_utils84.logger.log({ level: "error", message: error2.message });
|
|
17429
|
+
next(error2);
|
|
17430
|
+
return;
|
|
17431
|
+
}
|
|
17432
|
+
}
|
|
17433
|
+
async function getVehiclesByNRIC(req, res, next) {
|
|
17434
|
+
const allowedFields = ["start", "end"];
|
|
17435
|
+
const allowedOrder = ["asc", "desc"];
|
|
17436
|
+
const validation = import_joi46.default.object({
|
|
17437
|
+
nric: import_joi46.default.string().optional().allow("", null),
|
|
17438
|
+
page: import_joi46.default.number().integer().min(1).allow("", null).default(1),
|
|
17439
|
+
limit: import_joi46.default.number().integer().min(1).max(100).allow("", null).default(10),
|
|
17440
|
+
sort: import_joi46.default.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
17441
|
+
order: import_joi46.default.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder)
|
|
17442
|
+
});
|
|
17443
|
+
const query = { ...req.query };
|
|
17444
|
+
const { error } = validation.validate(query);
|
|
17445
|
+
if (error) {
|
|
17446
|
+
import_node_server_utils84.logger.log({ level: "error", message: error.message });
|
|
17447
|
+
next(new import_node_server_utils84.BadRequestError(error.message));
|
|
17448
|
+
return;
|
|
17449
|
+
}
|
|
17450
|
+
const nric = req.query.nric ?? "";
|
|
17451
|
+
const page = parseInt(req.query.page ?? "1");
|
|
17452
|
+
const limit = parseInt(req.query.limit ?? "10");
|
|
17453
|
+
const sortObj = {};
|
|
17454
|
+
const sortFields = String(req.query.sort).split(",");
|
|
17455
|
+
const sortOrders = String(req.query.order).split(",");
|
|
17456
|
+
sortFields.forEach((field, index) => {
|
|
17457
|
+
if (allowedFields.includes(field)) {
|
|
17458
|
+
const order = sortOrders[index] === "asc" ? 1 : -1;
|
|
17459
|
+
sortObj[field] = order;
|
|
17460
|
+
}
|
|
17461
|
+
});
|
|
17462
|
+
try {
|
|
17463
|
+
const data = await _getVehiclesByNRIC({
|
|
17464
|
+
nric,
|
|
17465
|
+
page,
|
|
17466
|
+
limit,
|
|
17467
|
+
sort: sortObj
|
|
17468
|
+
});
|
|
17469
|
+
res.json(data);
|
|
17470
|
+
return;
|
|
17471
|
+
} catch (error2) {
|
|
17472
|
+
import_node_server_utils84.logger.log({ level: "error", message: error2.message });
|
|
17473
|
+
next(error2);
|
|
17474
|
+
return;
|
|
17475
|
+
}
|
|
17476
|
+
}
|
|
16766
17477
|
return {
|
|
16767
17478
|
add,
|
|
16768
17479
|
getVehicles,
|
|
16769
17480
|
getSeasonPassTypes,
|
|
16770
17481
|
getVehicleById,
|
|
16771
17482
|
updateVehicle,
|
|
16772
|
-
deleteVehicle
|
|
17483
|
+
deleteVehicle,
|
|
17484
|
+
approveVehicleById,
|
|
17485
|
+
getVehiclesByNRIC
|
|
16773
17486
|
};
|
|
16774
17487
|
}
|
|
16775
17488
|
|
|
@@ -16868,7 +17581,7 @@ function useSiteCameraController() {
|
|
|
16868
17581
|
}
|
|
16869
17582
|
async function getAll(req, res, next) {
|
|
16870
17583
|
const query = req.query;
|
|
16871
|
-
const
|
|
17584
|
+
const allowedTypes = ["ip", "exit", "entry", "both"];
|
|
16872
17585
|
const validation = import_joi47.default.object({
|
|
16873
17586
|
type: import_joi47.default.string().optional(),
|
|
16874
17587
|
site: import_joi47.default.string().optional(),
|
|
@@ -19349,25 +20062,15 @@ function usePersonService() {
|
|
|
19349
20062
|
}
|
|
19350
20063
|
async function plateValidity(value) {
|
|
19351
20064
|
const now = /* @__PURE__ */ new Date();
|
|
19352
|
-
if (
|
|
19353
|
-
|
|
19354
|
-
|
|
19355
|
-
if (value.type === "resident") {
|
|
20065
|
+
if (["resident" /* RESIDENT */, "tenant" /* TENANT */].includes(
|
|
20066
|
+
value?.type
|
|
20067
|
+
)) {
|
|
19356
20068
|
const end = new Date(now);
|
|
19357
20069
|
end.setFullYear(end.getFullYear() + 10);
|
|
19358
|
-
return {
|
|
19359
|
-
|
|
19360
|
-
|
|
19361
|
-
|
|
19362
|
-
if (!unit) {
|
|
19363
|
-
throw new import_node_server_utils103.BadRequestError("Building unit not found for tenant.");
|
|
19364
|
-
}
|
|
19365
|
-
if (unit.leaseStart && unit.leaseEnd) {
|
|
19366
|
-
return {
|
|
19367
|
-
start: new Date(unit.leaseStart).toISOString(),
|
|
19368
|
-
end: new Date(unit.leaseEnd).toISOString()
|
|
19369
|
-
};
|
|
19370
|
-
}
|
|
20070
|
+
return {
|
|
20071
|
+
start: now.toISOString(),
|
|
20072
|
+
end: end.toISOString()
|
|
20073
|
+
};
|
|
19371
20074
|
}
|
|
19372
20075
|
return { start: "", end: "" };
|
|
19373
20076
|
}
|
|
@@ -19386,7 +20089,8 @@ function usePersonController() {
|
|
|
19386
20089
|
getPersonByPhoneNumber: _getPersonByPhoneNumber,
|
|
19387
20090
|
getPeopleByUnit: _getPeopleByUnit,
|
|
19388
20091
|
getCompany: _getCompany,
|
|
19389
|
-
getPeopleByPlateNumber: _getPeopleByPlateNumber
|
|
20092
|
+
getPeopleByPlateNumber: _getPeopleByPlateNumber,
|
|
20093
|
+
getPeopleByNRIC: _getPeopleByNRIC
|
|
19390
20094
|
} = usePersonRepo();
|
|
19391
20095
|
const { add: _add, updateById: _updateById } = usePersonService();
|
|
19392
20096
|
async function add(req, res, next) {
|
|
@@ -19621,6 +20325,53 @@ function usePersonController() {
|
|
|
19621
20325
|
return;
|
|
19622
20326
|
}
|
|
19623
20327
|
}
|
|
20328
|
+
async function getPeopleByNRIC(req, res, next) {
|
|
20329
|
+
const allowedFields = ["start", "end"];
|
|
20330
|
+
const allowedOrder = ["asc", "desc"];
|
|
20331
|
+
const validation = import_joi58.default.object({
|
|
20332
|
+
nric: import_joi58.default.string().optional().allow("", null),
|
|
20333
|
+
page: import_joi58.default.number().integer().min(1).allow("", null).default(1),
|
|
20334
|
+
limit: import_joi58.default.number().integer().min(1).max(100).allow("", null).default(10),
|
|
20335
|
+
sort: import_joi58.default.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
20336
|
+
order: import_joi58.default.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
20337
|
+
site: import_joi58.default.string().hex().length(24).required()
|
|
20338
|
+
});
|
|
20339
|
+
const query = { ...req.query };
|
|
20340
|
+
const { error } = validation.validate(query);
|
|
20341
|
+
if (error) {
|
|
20342
|
+
import_node_server_utils104.logger.log({ level: "error", message: error.message });
|
|
20343
|
+
next(new import_node_server_utils104.BadRequestError(error.message));
|
|
20344
|
+
return;
|
|
20345
|
+
}
|
|
20346
|
+
const nric = req.query.nric ?? "";
|
|
20347
|
+
const page = parseInt(req.query.page ?? "1");
|
|
20348
|
+
const limit = parseInt(req.query.limit ?? "10");
|
|
20349
|
+
const site = req.query.site ?? "";
|
|
20350
|
+
const sortObj = {};
|
|
20351
|
+
const sortFields = String(req.query.sort).split(",");
|
|
20352
|
+
const sortOrders = String(req.query.order).split(",");
|
|
20353
|
+
sortFields.forEach((field, index) => {
|
|
20354
|
+
if (allowedFields.includes(field)) {
|
|
20355
|
+
const order = sortOrders[index] === "asc" ? 1 : -1;
|
|
20356
|
+
sortObj[field] = order;
|
|
20357
|
+
}
|
|
20358
|
+
});
|
|
20359
|
+
try {
|
|
20360
|
+
const data = await _getPeopleByNRIC({
|
|
20361
|
+
nric,
|
|
20362
|
+
page,
|
|
20363
|
+
limit,
|
|
20364
|
+
sort: sortObj,
|
|
20365
|
+
site
|
|
20366
|
+
});
|
|
20367
|
+
res.json(data);
|
|
20368
|
+
return;
|
|
20369
|
+
} catch (error2) {
|
|
20370
|
+
import_node_server_utils104.logger.log({ level: "error", message: error2.message });
|
|
20371
|
+
next(error2);
|
|
20372
|
+
return;
|
|
20373
|
+
}
|
|
20374
|
+
}
|
|
19624
20375
|
return {
|
|
19625
20376
|
add,
|
|
19626
20377
|
getAll,
|
|
@@ -19630,7 +20381,8 @@ function usePersonController() {
|
|
|
19630
20381
|
getPersonByPhoneNumber,
|
|
19631
20382
|
getPeopleByUnit,
|
|
19632
20383
|
getCompany,
|
|
19633
|
-
getPeopleByPlateNumber
|
|
20384
|
+
getPeopleByPlateNumber,
|
|
20385
|
+
getPeopleByNRIC
|
|
19634
20386
|
};
|
|
19635
20387
|
}
|
|
19636
20388
|
|
|
@@ -24228,20 +24980,19 @@ function useDocumentManagementController() {
|
|
|
24228
24980
|
// src/models/bulletin-board.model.ts
|
|
24229
24981
|
var import_joi75 = __toESM(require("joi"));
|
|
24230
24982
|
var import_mongodb71 = require("mongodb");
|
|
24983
|
+
var BULLETIN_RECIPIENTS = [
|
|
24984
|
+
"resident",
|
|
24985
|
+
"security_agency",
|
|
24986
|
+
"cleaning_services",
|
|
24987
|
+
"mechanical_electrical",
|
|
24988
|
+
"property_management_agency"
|
|
24989
|
+
];
|
|
24990
|
+
var STATUS_VALUES = ["active", "expired", "deleted"];
|
|
24231
24991
|
var schemaBulletinBoard = import_joi75.default.object({
|
|
24232
24992
|
_id: import_joi75.default.string().hex().optional().allow("", null),
|
|
24233
24993
|
site: import_joi75.default.string().hex().optional().allow("", null),
|
|
24234
24994
|
orgId: import_joi75.default.string().hex().optional().allow("", null),
|
|
24235
|
-
recipients: import_joi75.default.array().items(
|
|
24236
|
-
import_joi75.default.string().valid(
|
|
24237
|
-
"admin",
|
|
24238
|
-
"organization",
|
|
24239
|
-
"site",
|
|
24240
|
-
"service-provider",
|
|
24241
|
-
"service-provider-member",
|
|
24242
|
-
"resident"
|
|
24243
|
-
)
|
|
24244
|
-
).optional(),
|
|
24995
|
+
recipients: import_joi75.default.array().items(import_joi75.default.string().valid(...BULLETIN_RECIPIENTS)).unique().optional(),
|
|
24245
24996
|
title: import_joi75.default.string().optional().allow("", null),
|
|
24246
24997
|
content: import_joi75.default.string().optional().allow("", null),
|
|
24247
24998
|
file: import_joi75.default.array().items(
|
|
@@ -24254,23 +25005,14 @@ var schemaBulletinBoard = import_joi75.default.object({
|
|
|
24254
25005
|
noExpiration: import_joi75.default.boolean().optional(),
|
|
24255
25006
|
startDate: import_joi75.default.date().optional().allow("", null),
|
|
24256
25007
|
endDate: import_joi75.default.date().optional().allow("", null),
|
|
24257
|
-
status: import_joi75.default.string().
|
|
25008
|
+
status: import_joi75.default.string().valid(...STATUS_VALUES).optional(),
|
|
24258
25009
|
createdAt: import_joi75.default.date().optional().allow(null),
|
|
24259
25010
|
updatedAt: import_joi75.default.date().optional().allow(null),
|
|
24260
25011
|
deletedAt: import_joi75.default.date().optional().allow(null)
|
|
24261
25012
|
});
|
|
24262
25013
|
var schemaUpdateBulletinBoard = import_joi75.default.object({
|
|
24263
25014
|
_id: import_joi75.default.string().hex().required(),
|
|
24264
|
-
recipients: import_joi75.default.array().items(
|
|
24265
|
-
import_joi75.default.string().valid(
|
|
24266
|
-
"admin",
|
|
24267
|
-
"organization",
|
|
24268
|
-
"site",
|
|
24269
|
-
"service-provider",
|
|
24270
|
-
"service-provider-member",
|
|
24271
|
-
"resident"
|
|
24272
|
-
)
|
|
24273
|
-
).optional(),
|
|
25015
|
+
recipients: import_joi75.default.array().items(import_joi75.default.string().valid(...BULLETIN_RECIPIENTS)).unique().optional(),
|
|
24274
25016
|
title: import_joi75.default.string().optional().allow("", null),
|
|
24275
25017
|
content: import_joi75.default.string().optional().allow("", null),
|
|
24276
25018
|
file: import_joi75.default.array().items(
|
|
@@ -24283,7 +25025,7 @@ var schemaUpdateBulletinBoard = import_joi75.default.object({
|
|
|
24283
25025
|
noExpiration: import_joi75.default.boolean().optional(),
|
|
24284
25026
|
startDate: import_joi75.default.date().optional().allow("", null),
|
|
24285
25027
|
endDate: import_joi75.default.date().optional().allow("", null),
|
|
24286
|
-
status: import_joi75.default.string().
|
|
25028
|
+
status: import_joi75.default.string().valid(...STATUS_VALUES).optional()
|
|
24287
25029
|
});
|
|
24288
25030
|
function MBulletinBoard(value) {
|
|
24289
25031
|
const { error } = schemaBulletinBoard.validate(value);
|
|
@@ -24374,7 +25116,8 @@ function useBulletinBoardRepo() {
|
|
|
24374
25116
|
limit = 10,
|
|
24375
25117
|
sort = {},
|
|
24376
25118
|
site = "",
|
|
24377
|
-
status = "active"
|
|
25119
|
+
status = "active",
|
|
25120
|
+
recipients = []
|
|
24378
25121
|
}, session) {
|
|
24379
25122
|
page = page > 0 ? page - 1 : 0;
|
|
24380
25123
|
try {
|
|
@@ -24384,7 +25127,9 @@ function useBulletinBoardRepo() {
|
|
|
24384
25127
|
}
|
|
24385
25128
|
const query = {
|
|
24386
25129
|
site,
|
|
24387
|
-
status
|
|
25130
|
+
status,
|
|
25131
|
+
...search && { $text: { $search: search } },
|
|
25132
|
+
...recipients?.length && { recipients: { $in: recipients } }
|
|
24388
25133
|
};
|
|
24389
25134
|
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
24390
25135
|
const cacheOptions = {
|
|
@@ -24392,12 +25137,10 @@ function useBulletinBoardRepo() {
|
|
|
24392
25137
|
status,
|
|
24393
25138
|
sort: JSON.stringify(sort),
|
|
24394
25139
|
page,
|
|
24395
|
-
limit
|
|
25140
|
+
limit,
|
|
25141
|
+
...search && { search },
|
|
25142
|
+
...recipients?.length && { recipients: recipients.sort().join(",") }
|
|
24396
25143
|
};
|
|
24397
|
-
if (search) {
|
|
24398
|
-
query.$text = { $search: search };
|
|
24399
|
-
cacheOptions.search = search;
|
|
24400
|
-
}
|
|
24401
25144
|
const cacheKey = (0, import_node_server_utils131.makeCacheKey)(namespace_collection, cacheOptions);
|
|
24402
25145
|
const cachedData = await getCache(cacheKey);
|
|
24403
25146
|
if (cachedData) {
|
|
@@ -24489,7 +25232,7 @@ function useBulletinBoardRepo() {
|
|
|
24489
25232
|
throw error;
|
|
24490
25233
|
}
|
|
24491
25234
|
}
|
|
24492
|
-
async function deleteBulletinBoardById(_id) {
|
|
25235
|
+
async function deleteBulletinBoardById(_id, session) {
|
|
24493
25236
|
try {
|
|
24494
25237
|
_id = new import_mongodb72.ObjectId(_id);
|
|
24495
25238
|
} catch (error) {
|
|
@@ -24501,7 +25244,11 @@ function useBulletinBoardRepo() {
|
|
|
24501
25244
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24502
25245
|
deletedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24503
25246
|
};
|
|
24504
|
-
const res = await collection.updateOne(
|
|
25247
|
+
const res = await collection.updateOne(
|
|
25248
|
+
{ _id },
|
|
25249
|
+
{ $set: updateValue },
|
|
25250
|
+
{ session }
|
|
25251
|
+
);
|
|
24505
25252
|
if (res.modifiedCount === 0) {
|
|
24506
25253
|
throw new import_node_server_utils131.InternalServerError("Unable to delete bulletin board.");
|
|
24507
25254
|
}
|
|
@@ -24567,8 +25314,11 @@ function useBulletinBoardService() {
|
|
|
24567
25314
|
const {
|
|
24568
25315
|
add: _add,
|
|
24569
25316
|
updateBulletinBoardById: _updateBulletinBoardById,
|
|
24570
|
-
processExpiredBulletinBoards: _processExpiredBulletinBoards
|
|
25317
|
+
processExpiredBulletinBoards: _processExpiredBulletinBoards,
|
|
25318
|
+
deleteBulletinBoardById: _deleteBulletinBoardById,
|
|
25319
|
+
getBulletinBoardById: _getBulletinBoardById
|
|
24571
25320
|
} = useBulletinBoardRepo();
|
|
25321
|
+
const { deleteFileById: _deleteFileById } = useFileRepo();
|
|
24572
25322
|
async function add(value) {
|
|
24573
25323
|
const session = import_node_server_utils132.useAtlas.getClient()?.startSession();
|
|
24574
25324
|
session?.startTransaction();
|
|
@@ -24611,10 +25361,31 @@ function useBulletinBoardService() {
|
|
|
24611
25361
|
session?.endSession();
|
|
24612
25362
|
}
|
|
24613
25363
|
}
|
|
25364
|
+
async function deleteBulletinBoardById(id) {
|
|
25365
|
+
const session = import_node_server_utils132.useAtlas.getClient()?.startSession();
|
|
25366
|
+
session?.startTransaction();
|
|
25367
|
+
try {
|
|
25368
|
+
const existingBulletinBoard = await _getBulletinBoardById(id);
|
|
25369
|
+
if (Array.isArray(existingBulletinBoard.file)) {
|
|
25370
|
+
for (const file of existingBulletinBoard.file) {
|
|
25371
|
+
await _deleteFileById(file, session);
|
|
25372
|
+
}
|
|
25373
|
+
}
|
|
25374
|
+
await _deleteBulletinBoardById(id, session);
|
|
25375
|
+
await session?.commitTransaction();
|
|
25376
|
+
return "Successfully deleted bulletin board.";
|
|
25377
|
+
} catch (error) {
|
|
25378
|
+
await session?.abortTransaction();
|
|
25379
|
+
throw error;
|
|
25380
|
+
} finally {
|
|
25381
|
+
session?.endSession();
|
|
25382
|
+
}
|
|
25383
|
+
}
|
|
24614
25384
|
return {
|
|
24615
25385
|
add,
|
|
24616
25386
|
updateBulletinBoardById,
|
|
24617
|
-
processExpiredBulletinBoards
|
|
25387
|
+
processExpiredBulletinBoards,
|
|
25388
|
+
deleteBulletinBoardById
|
|
24618
25389
|
};
|
|
24619
25390
|
}
|
|
24620
25391
|
|
|
@@ -24622,12 +25393,12 @@ function useBulletinBoardService() {
|
|
|
24622
25393
|
var import_node_server_utils133 = require("@7365admin1/node-server-utils");
|
|
24623
25394
|
var import_joi76 = __toESM(require("joi"));
|
|
24624
25395
|
function useBulletinBoardController() {
|
|
24625
|
-
const { add: _add, updateBulletinBoardById: _updateBulletinBoardById } = useBulletinBoardService();
|
|
24626
25396
|
const {
|
|
24627
|
-
|
|
24628
|
-
|
|
25397
|
+
add: _add,
|
|
25398
|
+
updateBulletinBoardById: _updateBulletinBoardById,
|
|
24629
25399
|
deleteBulletinBoardById: _deleteBulletinBoardById
|
|
24630
|
-
} =
|
|
25400
|
+
} = useBulletinBoardService();
|
|
25401
|
+
const { getAll: _getAll, getBulletinBoardById: _getBulletinBoardById } = useBulletinBoardRepo();
|
|
24631
25402
|
async function add(req, res, next) {
|
|
24632
25403
|
const payload = { ...req.body };
|
|
24633
25404
|
const { error } = schemaBulletinBoard.validate(payload, {
|
|
@@ -24659,12 +25430,23 @@ function useBulletinBoardController() {
|
|
|
24659
25430
|
sort: import_joi76.default.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
|
|
24660
25431
|
order: import_joi76.default.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
24661
25432
|
site: import_joi76.default.string().hex().required(),
|
|
24662
|
-
status: import_joi76.default.string().optional().allow(null, "")
|
|
25433
|
+
status: import_joi76.default.string().optional().allow(null, ""),
|
|
25434
|
+
recipients: import_joi76.default.string().optional().allow("", null).custom((value, helpers) => {
|
|
25435
|
+
const parsed = value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
25436
|
+
for (const r of parsed) {
|
|
25437
|
+
if (!BULLETIN_RECIPIENTS.includes(r)) {
|
|
25438
|
+
return helpers.error("any.only");
|
|
25439
|
+
}
|
|
25440
|
+
}
|
|
25441
|
+
return value;
|
|
25442
|
+
}).messages({
|
|
25443
|
+
"any.only": `Recipients must be one of: ${BULLETIN_RECIPIENTS.join(
|
|
25444
|
+
", "
|
|
25445
|
+
)}`
|
|
25446
|
+
})
|
|
24663
25447
|
});
|
|
24664
25448
|
const query = { ...req.query };
|
|
24665
|
-
const { error } = validation.validate(query, {
|
|
24666
|
-
abortEarly: false
|
|
24667
|
-
});
|
|
25449
|
+
const { error } = validation.validate(query, { abortEarly: false });
|
|
24668
25450
|
if (error) {
|
|
24669
25451
|
const messages = error.details.map((d) => d.message).join(", ");
|
|
24670
25452
|
import_node_server_utils133.logger.log({ level: "error", message: messages });
|
|
@@ -24676,9 +25458,15 @@ function useBulletinBoardController() {
|
|
|
24676
25458
|
const limit = parseInt(req.query.limit ?? "10");
|
|
24677
25459
|
const site = req.query.site ?? "";
|
|
24678
25460
|
const status = req.query.status ?? "active";
|
|
25461
|
+
const recipientsRaw = req.query.recipients ?? "";
|
|
25462
|
+
const recipients = recipientsRaw && typeof recipientsRaw === "string" ? Array.from(
|
|
25463
|
+
new Set(
|
|
25464
|
+
recipientsRaw.split(",").map((r) => r.trim()).filter(Boolean)
|
|
25465
|
+
)
|
|
25466
|
+
) : [];
|
|
24679
25467
|
const sortObj = {};
|
|
24680
|
-
const sortFields = String(req.query.sort).split(",");
|
|
24681
|
-
const sortOrders = String(req.query.order).split(",");
|
|
25468
|
+
const sortFields = String(req.query.sort ?? "").split(",").filter(Boolean);
|
|
25469
|
+
const sortOrders = String(req.query.order ?? "").split(",").filter(Boolean);
|
|
24682
25470
|
sortFields.forEach((field, index) => {
|
|
24683
25471
|
if (allowedFields.includes(field)) {
|
|
24684
25472
|
const order = sortOrders[index] === "asc" ? 1 : -1;
|
|
@@ -24692,7 +25480,8 @@ function useBulletinBoardController() {
|
|
|
24692
25480
|
limit,
|
|
24693
25481
|
sort: sortObj,
|
|
24694
25482
|
site,
|
|
24695
|
-
status
|
|
25483
|
+
status,
|
|
25484
|
+
recipients
|
|
24696
25485
|
});
|
|
24697
25486
|
res.status(200).json(data);
|
|
24698
25487
|
return;
|
|
@@ -24775,6 +25564,16 @@ function useBulletinBoardController() {
|
|
|
24775
25564
|
var import_node_server_utils134 = require("@7365admin1/node-server-utils");
|
|
24776
25565
|
var import_mongodb73 = require("mongodb");
|
|
24777
25566
|
var import_joi77 = __toESM(require("joi"));
|
|
25567
|
+
|
|
25568
|
+
// src/types/enums/billing-frequency.enum.ts
|
|
25569
|
+
var EBillingFrequency = /* @__PURE__ */ ((EBillingFrequency2) => {
|
|
25570
|
+
EBillingFrequency2["MONTHLY"] = "monthly";
|
|
25571
|
+
EBillingFrequency2["QAURTERLY"] = "quarterly";
|
|
25572
|
+
EBillingFrequency2["ANNUALLY"] = "annually";
|
|
25573
|
+
return EBillingFrequency2;
|
|
25574
|
+
})(EBillingFrequency || {});
|
|
25575
|
+
|
|
25576
|
+
// src/models/site-billing-item.model.ts
|
|
24778
25577
|
var schemaUnits = import_joi77.default.object({
|
|
24779
25578
|
_id: import_joi77.default.string().hex().optional(),
|
|
24780
25579
|
name: import_joi77.default.string().optional()
|
|
@@ -24785,7 +25584,7 @@ var schemaBillingItem = import_joi77.default.object({
|
|
|
24785
25584
|
org: import_joi77.default.string().hex().required(),
|
|
24786
25585
|
name: import_joi77.default.string().required(),
|
|
24787
25586
|
amount: import_joi77.default.number().required(),
|
|
24788
|
-
frequency: import_joi77.default.string().valid(
|
|
25587
|
+
frequency: import_joi77.default.string().valid(...Object.values(EBillingFrequency)).required(),
|
|
24789
25588
|
billingType: import_joi77.default.string().valid("recurring", "non-recurring").required(),
|
|
24790
25589
|
dueInDays: import_joi77.default.number().optional().allow(null, ""),
|
|
24791
25590
|
date: import_joi77.default.string().required(),
|
|
@@ -24810,7 +25609,7 @@ var schemaUpdateSiteBillingItem = import_joi77.default.object({
|
|
|
24810
25609
|
org: import_joi77.default.string().hex().optional().allow(null, ""),
|
|
24811
25610
|
name: import_joi77.default.string().optional().allow(null, ""),
|
|
24812
25611
|
amount: import_joi77.default.number().optional().allow(null, ""),
|
|
24813
|
-
frequency: import_joi77.default.string().valid(
|
|
25612
|
+
frequency: import_joi77.default.string().valid(...Object.values(EBillingFrequency)).optional().allow(null, ""),
|
|
24814
25613
|
billingType: import_joi77.default.string().valid("recurring", "non-recurring").optional().allow(null, ""),
|
|
24815
25614
|
dueInDays: import_joi77.default.number().optional().allow(null, ""),
|
|
24816
25615
|
date: import_joi77.default.string().optional().allow(null, ""),
|
|
@@ -24955,7 +25754,16 @@ function useSiteBillingItemRepo() {
|
|
|
24955
25754
|
...search && {
|
|
24956
25755
|
$or: [
|
|
24957
25756
|
{ name: { $regex: search, $options: "i" } },
|
|
24958
|
-
{ frequency: { $regex: search, $options: "i" } }
|
|
25757
|
+
{ frequency: { $regex: search, $options: "i" } },
|
|
25758
|
+
{
|
|
25759
|
+
$expr: {
|
|
25760
|
+
$regexMatch: {
|
|
25761
|
+
input: { $toString: "$totalAmount" },
|
|
25762
|
+
regex: search,
|
|
25763
|
+
options: "i"
|
|
25764
|
+
}
|
|
25765
|
+
}
|
|
25766
|
+
}
|
|
24959
25767
|
]
|
|
24960
25768
|
},
|
|
24961
25769
|
...import_mongodb74.ObjectId.isValid(site) && { site: new import_mongodb74.ObjectId(site) }
|
|
@@ -26105,7 +26913,8 @@ function useEventManagementRepo() {
|
|
|
26105
26913
|
sort = {},
|
|
26106
26914
|
site = "",
|
|
26107
26915
|
status = "",
|
|
26108
|
-
type = ""
|
|
26916
|
+
type = "",
|
|
26917
|
+
date = ""
|
|
26109
26918
|
}, session) {
|
|
26110
26919
|
page = page > 0 ? page - 1 : 0;
|
|
26111
26920
|
try {
|
|
@@ -26116,7 +26925,13 @@ function useEventManagementRepo() {
|
|
|
26116
26925
|
const baseQuery = {
|
|
26117
26926
|
site,
|
|
26118
26927
|
status: status ? status : { $ne: "deleted" },
|
|
26119
|
-
...type && { type }
|
|
26928
|
+
...type && { type },
|
|
26929
|
+
...date && {
|
|
26930
|
+
dateTime: {
|
|
26931
|
+
$gte: `${date}T00:00:00.000Z`,
|
|
26932
|
+
$lt: `${date}T23:59:59.999Z`
|
|
26933
|
+
}
|
|
26934
|
+
}
|
|
26120
26935
|
};
|
|
26121
26936
|
let query = { ...baseQuery };
|
|
26122
26937
|
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
@@ -26414,7 +27229,8 @@ function useEventManagementController() {
|
|
|
26414
27229
|
order: import_joi82.default.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
|
|
26415
27230
|
site: import_joi82.default.string().hex().required(),
|
|
26416
27231
|
status: import_joi82.default.string().optional(),
|
|
26417
|
-
type: import_joi82.default.string().optional().valid("TASK", "EVENT").allow(null, "")
|
|
27232
|
+
type: import_joi82.default.string().optional().valid("TASK", "EVENT").allow(null, ""),
|
|
27233
|
+
date: import_joi82.default.string().optional().allow(null, "")
|
|
26418
27234
|
});
|
|
26419
27235
|
const query = { ...req.query };
|
|
26420
27236
|
const { error } = validation.validate(query, {
|
|
@@ -26432,6 +27248,7 @@ function useEventManagementController() {
|
|
|
26432
27248
|
const site = req.query.site ?? "";
|
|
26433
27249
|
const status = req.query.status ?? "";
|
|
26434
27250
|
const type = req.query.type ?? "";
|
|
27251
|
+
const date = req.query.date ?? "";
|
|
26435
27252
|
const sortObj = {};
|
|
26436
27253
|
const sortFields = String(req.query.sort).split(",");
|
|
26437
27254
|
const sortOrders = String(req.query.order).split(",");
|
|
@@ -26449,7 +27266,8 @@ function useEventManagementController() {
|
|
|
26449
27266
|
sort: sortObj,
|
|
26450
27267
|
site,
|
|
26451
27268
|
status,
|
|
26452
|
-
type
|
|
27269
|
+
type,
|
|
27270
|
+
date
|
|
26453
27271
|
});
|
|
26454
27272
|
res.status(200).json(data);
|
|
26455
27273
|
return;
|
|
@@ -26766,6 +27584,7 @@ function useSiteUnitBillingRepo() {
|
|
|
26766
27584
|
}
|
|
26767
27585
|
};
|
|
26768
27586
|
}
|
|
27587
|
+
const unitSearchRegex = search ? search.trim().replace(/\s+/g, "").replace(/\//g, "\\s*/\\s*") : null;
|
|
26769
27588
|
const query = {
|
|
26770
27589
|
paymentStatus,
|
|
26771
27590
|
status,
|
|
@@ -26773,7 +27592,16 @@ function useSiteUnitBillingRepo() {
|
|
|
26773
27592
|
$or: [
|
|
26774
27593
|
{ unitOwner: { $regex: search, $options: "i" } },
|
|
26775
27594
|
{ billName: { $regex: search, $options: "i" } },
|
|
26776
|
-
{ unit: { $regex:
|
|
27595
|
+
{ unit: { $regex: unitSearchRegex, $options: "i" } },
|
|
27596
|
+
{
|
|
27597
|
+
$expr: {
|
|
27598
|
+
$regexMatch: {
|
|
27599
|
+
input: { $toString: "$amountPaid" },
|
|
27600
|
+
regex: search,
|
|
27601
|
+
options: "i"
|
|
27602
|
+
}
|
|
27603
|
+
}
|
|
27604
|
+
}
|
|
26777
27605
|
]
|
|
26778
27606
|
},
|
|
26779
27607
|
...import_mongodb80.ObjectId.isValid(site) && { site: new import_mongodb80.ObjectId(site) },
|
|
@@ -27196,14 +28024,14 @@ function useSiteUnitBillingService() {
|
|
|
27196
28024
|
function isBillingChecker(billing_item, todayMonth, todayDate) {
|
|
27197
28025
|
const billingMonth = Number(billing_item.month);
|
|
27198
28026
|
const billingDay = Number(billing_item.date);
|
|
27199
|
-
if (billing_item.frequency === "
|
|
28027
|
+
if (billing_item.frequency === "monthly" /* MONTHLY */) {
|
|
27200
28028
|
return todayDate === billingDay;
|
|
27201
28029
|
}
|
|
27202
|
-
if (billing_item.frequency === "
|
|
28030
|
+
if (billing_item.frequency === "quarterly" /* QAURTERLY */) {
|
|
27203
28031
|
const monthDiff = todayMonth - billingMonth;
|
|
27204
28032
|
return monthDiff % 3 === 0 && todayDate === billingDay;
|
|
27205
28033
|
}
|
|
27206
|
-
if (billing_item.frequency === "
|
|
28034
|
+
if (billing_item.frequency === "annually" /* ANNUALLY */) {
|
|
27207
28035
|
return todayMonth === billingMonth && todayDate === billingDay;
|
|
27208
28036
|
}
|
|
27209
28037
|
return false;
|
|
@@ -27995,7 +28823,7 @@ function UseAccessManagementRepo() {
|
|
|
27995
28823
|
{
|
|
27996
28824
|
$match: {
|
|
27997
28825
|
...defaultQuery,
|
|
27998
|
-
status: { $
|
|
28826
|
+
status: { $eq: "active" }
|
|
27999
28827
|
}
|
|
28000
28828
|
},
|
|
28001
28829
|
// ✅ Only project needed fields before heavy lookups
|
|
@@ -28115,7 +28943,7 @@ function UseAccessManagementRepo() {
|
|
|
28115
28943
|
userType
|
|
28116
28944
|
}
|
|
28117
28945
|
},
|
|
28118
|
-
{ $project: { _id: 1, userId: 1, type: 1, cardNo: 1, isActivated: 1 } }
|
|
28946
|
+
{ $project: { _id: 1, userId: 1, type: 1, cardNo: 1, isActivated: 1, replacementStatus: 1 } }
|
|
28119
28947
|
],
|
|
28120
28948
|
as: "accessCards"
|
|
28121
28949
|
}
|
|
@@ -28134,7 +28962,21 @@ function UseAccessManagementRepo() {
|
|
|
28134
28962
|
$filter: {
|
|
28135
28963
|
input: "$accessCards",
|
|
28136
28964
|
as: "card",
|
|
28137
|
-
cond: { $ne: ["$$card.userId", null] }
|
|
28965
|
+
cond: { $and: [{ $ne: ["$$card.userId", null] }, { $eq: ["$$card.isActivated", true] }] }
|
|
28966
|
+
}
|
|
28967
|
+
},
|
|
28968
|
+
f_replaced: {
|
|
28969
|
+
$filter: {
|
|
28970
|
+
input: "$accessCards",
|
|
28971
|
+
as: "card",
|
|
28972
|
+
cond: { $and: [{ $eq: ["$$card.isActivated", false] }, { $ne: ["$$card.replacementStatus", null] }] }
|
|
28973
|
+
}
|
|
28974
|
+
},
|
|
28975
|
+
f_deleted: {
|
|
28976
|
+
$filter: {
|
|
28977
|
+
input: "$accessCards",
|
|
28978
|
+
as: "card",
|
|
28979
|
+
cond: { $and: [{ $eq: ["$$card.isActivated", false] }, { $eq: ["$$card.replacementStatus", null] }] }
|
|
28138
28980
|
}
|
|
28139
28981
|
}
|
|
28140
28982
|
}
|
|
@@ -28166,6 +29008,14 @@ function UseAccessManagementRepo() {
|
|
|
28166
29008
|
non_physical: { $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } }
|
|
28167
29009
|
}
|
|
28168
29010
|
},
|
|
29011
|
+
replaced: {
|
|
29012
|
+
physical: { $filter: { input: "$f_replaced", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
29013
|
+
non_physical: { $filter: { input: "$f_replaced", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
29014
|
+
},
|
|
29015
|
+
deleted: {
|
|
29016
|
+
physical: { $filter: { input: "$f_deleted", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
29017
|
+
non_physical: { $filter: { input: "$f_deleted", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
29018
|
+
},
|
|
28169
29019
|
totalCardCount: {
|
|
28170
29020
|
$add: [
|
|
28171
29021
|
{ $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
|
|
@@ -28622,16 +29472,26 @@ function UseAccessManagementRepo() {
|
|
|
28622
29472
|
async function cardReplacementRepo(params) {
|
|
28623
29473
|
const session = import_node_server_utils149.useAtlas.getClient()?.startSession();
|
|
28624
29474
|
try {
|
|
28625
|
-
const { cardId, remarks } = params;
|
|
29475
|
+
const { cardId, remarks, issuedCardId, unitId, userId } = params;
|
|
28626
29476
|
const id = new import_mongodb83.ObjectId(cardId);
|
|
29477
|
+
const newCardId = new import_mongodb83.ObjectId(issuedCardId);
|
|
29478
|
+
const unit = new import_mongodb83.ObjectId(unitId);
|
|
29479
|
+
const user = new import_mongodb83.ObjectId(userId);
|
|
28627
29480
|
session?.startTransaction();
|
|
28628
|
-
const
|
|
28629
|
-
|
|
28630
|
-
|
|
28631
|
-
|
|
28632
|
-
|
|
29481
|
+
const sessionResult = await Promise.all([
|
|
29482
|
+
await collection().findOneAndUpdate(
|
|
29483
|
+
{ _id: id },
|
|
29484
|
+
{ $set: { remarks, replacementStatus: "Complete", requestDate: /* @__PURE__ */ new Date(), isActivated: false } },
|
|
29485
|
+
{ returnDocument: "after", session }
|
|
29486
|
+
),
|
|
29487
|
+
await collection().findOneAndUpdate(
|
|
29488
|
+
{ _id: newCardId },
|
|
29489
|
+
{ $set: { updatedAt: /* @__PURE__ */ new Date(), assignedUnit: unit, userId: user } },
|
|
29490
|
+
{ returnDocument: "after", session }
|
|
29491
|
+
)
|
|
29492
|
+
]);
|
|
28633
29493
|
await session?.commitTransaction();
|
|
28634
|
-
return
|
|
29494
|
+
return sessionResult;
|
|
28635
29495
|
} catch (error) {
|
|
28636
29496
|
await session?.abortTransaction();
|
|
28637
29497
|
throw new Error(error.message);
|
|
@@ -28649,7 +29509,8 @@ function UseAccessManagementRepo() {
|
|
|
28649
29509
|
const query = {
|
|
28650
29510
|
site: siteId,
|
|
28651
29511
|
assignedUnit: { $ne: null },
|
|
28652
|
-
type: "NFC" /* NFC
|
|
29512
|
+
type: "NFC" /* NFC */,
|
|
29513
|
+
isActivated: true
|
|
28653
29514
|
};
|
|
28654
29515
|
if (search) {
|
|
28655
29516
|
query.$or = [{ accessLevel: { $regex: search, $options: "i" } }, { cardNo: { $regex: search, $options: "i" } }];
|
|
@@ -28657,7 +29518,7 @@ function UseAccessManagementRepo() {
|
|
|
28657
29518
|
if (type) {
|
|
28658
29519
|
query.userType = type;
|
|
28659
29520
|
} else {
|
|
28660
|
-
query.userType = { $ne: "Resident
|
|
29521
|
+
query.userType = { $ne: "Visitor/Resident" /* DEFAULT */ };
|
|
28661
29522
|
}
|
|
28662
29523
|
const res = await collection().aggregate([
|
|
28663
29524
|
{
|
|
@@ -28880,7 +29741,8 @@ function UseAccessManagementRepo() {
|
|
|
28880
29741
|
rawItems.map(async (item) => {
|
|
28881
29742
|
const date = new Date(item["startDate (format MM/DD/YYYY)"]);
|
|
28882
29743
|
const endDate = new Date(date.setFullYear(date.getFullYear() + 10));
|
|
28883
|
-
const cardNumber = item["cardNo (number 0-65535 ex. 301)"]
|
|
29744
|
+
const cardNumber = String(Number(item["cardNo (number 0-65535 ex. 301)"] || 0)).padStart(6, "0");
|
|
29745
|
+
const facilityCode = String(Number(item["facilityCode (number 0-255 ex. 11)"] || 0)).padStart(4, "0");
|
|
28884
29746
|
const pin = item["pin (number 6 digits only)"] ? item["pin (number 6 digits only)"].toString().padStart(6, "0") : "123456";
|
|
28885
29747
|
const match = item["accessLevel (number ex. 1)"];
|
|
28886
29748
|
const accessLevel = match ? match : null;
|
|
@@ -28894,9 +29756,9 @@ function UseAccessManagementRepo() {
|
|
|
28894
29756
|
accessLevel,
|
|
28895
29757
|
accessGroup,
|
|
28896
29758
|
accessType: "Normal" /* NORMAL */,
|
|
28897
|
-
cardNo: cardNumber
|
|
29759
|
+
cardNo: `${facilityCode}${cardNumber}`,
|
|
28898
29760
|
pin,
|
|
28899
|
-
qrData: await createQrData({ cardNumber }),
|
|
29761
|
+
qrData: await createQrData({ cardNumber: `${facilityCode}${cardNumber}` }),
|
|
28900
29762
|
startDate: new Date(item["startDate (format MM/DD/YYYY)"]),
|
|
28901
29763
|
endDate: new Date(item["endDate (format MM/DD/YYYY)"] || endDate),
|
|
28902
29764
|
isActivated: true,
|
|
@@ -28970,6 +29832,112 @@ function UseAccessManagementRepo() {
|
|
|
28970
29832
|
session?.endSession();
|
|
28971
29833
|
}
|
|
28972
29834
|
}
|
|
29835
|
+
async function deleteCardRepo(params) {
|
|
29836
|
+
try {
|
|
29837
|
+
const { cardId, remarks } = params;
|
|
29838
|
+
const id = new import_mongodb83.ObjectId(cardId);
|
|
29839
|
+
const result = await collection().findOneAndUpdate({ _id: id }, { $set: { isActivated: false, updatedAt: /* @__PURE__ */ new Date(), remarks, requestDate: /* @__PURE__ */ new Date() } }, { returnDocument: "after" });
|
|
29840
|
+
return result;
|
|
29841
|
+
} catch (error) {
|
|
29842
|
+
throw new Error(error.message);
|
|
29843
|
+
}
|
|
29844
|
+
}
|
|
29845
|
+
async function getCardDetailsRepo(params) {
|
|
29846
|
+
try {
|
|
29847
|
+
const { siteId, cardId } = params;
|
|
29848
|
+
const convertedSiteId = new import_mongodb83.ObjectId(siteId);
|
|
29849
|
+
const convertedCardId = new import_mongodb83.ObjectId(cardId);
|
|
29850
|
+
const card = await collection().findOne(
|
|
29851
|
+
{
|
|
29852
|
+
_id: convertedCardId,
|
|
29853
|
+
site: convertedSiteId,
|
|
29854
|
+
type: "NFC" /* NFC */,
|
|
29855
|
+
userType: "Visitor/Resident" /* DEFAULT */
|
|
29856
|
+
},
|
|
29857
|
+
{
|
|
29858
|
+
projection: {
|
|
29859
|
+
userId: 1,
|
|
29860
|
+
site: 1,
|
|
29861
|
+
type: 1,
|
|
29862
|
+
userType: 1,
|
|
29863
|
+
cardNo: 1,
|
|
29864
|
+
isActivated: 1,
|
|
29865
|
+
replacementStatus: 1,
|
|
29866
|
+
vmsRemarks: 1,
|
|
29867
|
+
remarks: 1,
|
|
29868
|
+
requestDate: 1,
|
|
29869
|
+
createdAt: 1,
|
|
29870
|
+
updatedAt: 1
|
|
29871
|
+
}
|
|
29872
|
+
}
|
|
29873
|
+
);
|
|
29874
|
+
if (!card)
|
|
29875
|
+
return null;
|
|
29876
|
+
const site = await collectionName("sites").findOne(
|
|
29877
|
+
{ _id: card.site },
|
|
29878
|
+
{ projection: { name: 1, status: 1 } }
|
|
29879
|
+
);
|
|
29880
|
+
const user = card.userId ? await collectionName("users").findOne(
|
|
29881
|
+
{ _id: card.userId },
|
|
29882
|
+
{ projection: { name: 1, email: 1 } }
|
|
29883
|
+
) : null;
|
|
29884
|
+
const status = card.userId === null && card.isActivated === true ? "available" : card.userId !== null && card.isActivated === true ? "assigned" : card.isActivated === false && card.replacementStatus !== null ? "replaced" : "deleted";
|
|
29885
|
+
return {
|
|
29886
|
+
...card,
|
|
29887
|
+
status,
|
|
29888
|
+
site,
|
|
29889
|
+
user
|
|
29890
|
+
};
|
|
29891
|
+
} catch (error) {
|
|
29892
|
+
throw new Error(error.message);
|
|
29893
|
+
}
|
|
29894
|
+
}
|
|
29895
|
+
async function addQrTagRepo(params) {
|
|
29896
|
+
try {
|
|
29897
|
+
const { site, payload } = params;
|
|
29898
|
+
const id = new import_mongodb83.ObjectId(site);
|
|
29899
|
+
const highestCardNo = await collection().aggregate([
|
|
29900
|
+
{ $match: { site: id, type: "NFC" /* NFC */, userType: "Visitor/Resident" /* DEFAULT */ } },
|
|
29901
|
+
{
|
|
29902
|
+
$addFields: {
|
|
29903
|
+
qrTagCardNoNumeric: { $toInt: "$qrTagCardNo" }
|
|
29904
|
+
// Convert string to integer
|
|
29905
|
+
}
|
|
29906
|
+
},
|
|
29907
|
+
{
|
|
29908
|
+
$sort: { qrTagCardNoNumeric: -1 }
|
|
29909
|
+
// Sort in descending order
|
|
29910
|
+
},
|
|
29911
|
+
{
|
|
29912
|
+
$limit: 1
|
|
29913
|
+
// Get the highest
|
|
29914
|
+
}
|
|
29915
|
+
]).toArray();
|
|
29916
|
+
let start = 0;
|
|
29917
|
+
if (highestCardNo.length > 0) {
|
|
29918
|
+
start = highestCardNo[0].qrTagCardNoNumeric || 0;
|
|
29919
|
+
}
|
|
29920
|
+
const nextCardNumbers = Array.from({ length: payload.length }, (_, i) => String(start + i + 1).padStart(5, "0"));
|
|
29921
|
+
const bulkOps = await Promise.all(
|
|
29922
|
+
payload.map(async (doc, index) => {
|
|
29923
|
+
const id2 = new import_mongodb83.ObjectId(doc._id);
|
|
29924
|
+
return {
|
|
29925
|
+
updateOne: {
|
|
29926
|
+
filter: { _id: id2 },
|
|
29927
|
+
update: { $set: { qrTag: doc.qrTag, qrTagCardNo: nextCardNumbers[index] } }
|
|
29928
|
+
}
|
|
29929
|
+
};
|
|
29930
|
+
})
|
|
29931
|
+
);
|
|
29932
|
+
let result;
|
|
29933
|
+
if (bulkOps.length > 0) {
|
|
29934
|
+
result = await collection().bulkWrite(bulkOps);
|
|
29935
|
+
}
|
|
29936
|
+
return result;
|
|
29937
|
+
} catch (error) {
|
|
29938
|
+
throw new Error(error.message);
|
|
29939
|
+
}
|
|
29940
|
+
}
|
|
28973
29941
|
return {
|
|
28974
29942
|
createIndexes,
|
|
28975
29943
|
createIndexForEntrypass,
|
|
@@ -28990,7 +29958,10 @@ function UseAccessManagementRepo() {
|
|
|
28990
29958
|
getCardReplacementRepo,
|
|
28991
29959
|
getAccessManagementSettingsRepo,
|
|
28992
29960
|
bulkPhysicalAccessCardRepo,
|
|
28993
|
-
assignAccessCardToUnitRepo
|
|
29961
|
+
assignAccessCardToUnitRepo,
|
|
29962
|
+
deleteCardRepo,
|
|
29963
|
+
getCardDetailsRepo,
|
|
29964
|
+
addQrTagRepo
|
|
28994
29965
|
};
|
|
28995
29966
|
}
|
|
28996
29967
|
|
|
@@ -29022,7 +29993,10 @@ function useAccessManagementSvc() {
|
|
|
29022
29993
|
getCardReplacementRepo,
|
|
29023
29994
|
getAccessManagementSettingsRepo,
|
|
29024
29995
|
bulkPhysicalAccessCardRepo,
|
|
29025
|
-
assignAccessCardToUnitRepo
|
|
29996
|
+
assignAccessCardToUnitRepo,
|
|
29997
|
+
deleteCardRepo,
|
|
29998
|
+
getCardDetailsRepo,
|
|
29999
|
+
addQrTagRepo
|
|
29026
30000
|
} = UseAccessManagementRepo();
|
|
29027
30001
|
const addPhysicalCardSvc = async (payload) => {
|
|
29028
30002
|
try {
|
|
@@ -29270,6 +30244,30 @@ function useAccessManagementSvc() {
|
|
|
29270
30244
|
throw new Error(err.message);
|
|
29271
30245
|
}
|
|
29272
30246
|
};
|
|
30247
|
+
const deleteCardSvc = async (params) => {
|
|
30248
|
+
try {
|
|
30249
|
+
const response = await deleteCardRepo({ ...params });
|
|
30250
|
+
return response;
|
|
30251
|
+
} catch (err) {
|
|
30252
|
+
throw new Error(err.message);
|
|
30253
|
+
}
|
|
30254
|
+
};
|
|
30255
|
+
const getCardDetailsSvc = async (params) => {
|
|
30256
|
+
try {
|
|
30257
|
+
const response = await getCardDetailsRepo({ ...params });
|
|
30258
|
+
return response;
|
|
30259
|
+
} catch (err) {
|
|
30260
|
+
throw new Error(err.message);
|
|
30261
|
+
}
|
|
30262
|
+
};
|
|
30263
|
+
const addQrTagSvc = async (params) => {
|
|
30264
|
+
try {
|
|
30265
|
+
const response = await addQrTagRepo({ ...params });
|
|
30266
|
+
return response;
|
|
30267
|
+
} catch (err) {
|
|
30268
|
+
throw new Error(err.message);
|
|
30269
|
+
}
|
|
30270
|
+
};
|
|
29273
30271
|
return {
|
|
29274
30272
|
addPhysicalCardSvc,
|
|
29275
30273
|
addNonPhysicalCardSvc,
|
|
@@ -29294,7 +30292,10 @@ function useAccessManagementSvc() {
|
|
|
29294
30292
|
getAccessManagementSettingsSvc,
|
|
29295
30293
|
convertBufferFile,
|
|
29296
30294
|
bulkPhysicalAccessCardSvc,
|
|
29297
|
-
assignAccessCardToUnitSvc
|
|
30295
|
+
assignAccessCardToUnitSvc,
|
|
30296
|
+
deleteCardSvc,
|
|
30297
|
+
getCardDetailsSvc,
|
|
30298
|
+
addQrTagSvc
|
|
29298
30299
|
};
|
|
29299
30300
|
}
|
|
29300
30301
|
|
|
@@ -29326,7 +30327,10 @@ function useAccessManagementController() {
|
|
|
29326
30327
|
getAccessManagementSettingsSvc,
|
|
29327
30328
|
convertBufferFile,
|
|
29328
30329
|
bulkPhysicalAccessCardSvc,
|
|
29329
|
-
assignAccessCardToUnitSvc
|
|
30330
|
+
assignAccessCardToUnitSvc,
|
|
30331
|
+
deleteCardSvc,
|
|
30332
|
+
getCardDetailsSvc,
|
|
30333
|
+
addQrTagSvc
|
|
29330
30334
|
} = useAccessManagementSvc();
|
|
29331
30335
|
const addPhysicalCard = async (req, res) => {
|
|
29332
30336
|
try {
|
|
@@ -29555,11 +30559,24 @@ function useAccessManagementController() {
|
|
|
29555
30559
|
userType: import_joi85.default.string().optional().allow("", null),
|
|
29556
30560
|
type: import_joi85.default.string().optional().allow("", null)
|
|
29557
30561
|
});
|
|
30562
|
+
const user = req.cookies?.sid;
|
|
29558
30563
|
const { error } = schema2.validate({ site, userType, type });
|
|
29559
30564
|
if (error) {
|
|
29560
30565
|
return res.status(400).json({ message: error.message });
|
|
29561
30566
|
}
|
|
30567
|
+
const key = `${namespace2}:${user}:available-access-cards`;
|
|
30568
|
+
const listKey = `${namespace2}:${user}:list`;
|
|
30569
|
+
const { redis } = (0, import_node_server_utils151.useCache)(key);
|
|
30570
|
+
const cachedData = await getCache({ key, redis });
|
|
30571
|
+
if (cachedData) {
|
|
30572
|
+
console.log("\u26A1 Cache hit:", key);
|
|
30573
|
+
redis.expire(key, 60).catch(console.error);
|
|
30574
|
+
redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
|
|
30575
|
+
return res.status(200).json({ message: "Success", data: cachedData });
|
|
30576
|
+
}
|
|
29562
30577
|
const result = await availableAccessCardsSvc({ site, userType, type });
|
|
30578
|
+
await setCache({ key, data: result, ttlSeconds: 60, redis });
|
|
30579
|
+
redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
|
|
29563
30580
|
return res.status(200).json({ message: "Success", data: result });
|
|
29564
30581
|
} catch (error) {
|
|
29565
30582
|
return res.status(400).json({
|
|
@@ -29741,16 +30758,19 @@ function useAccessManagementController() {
|
|
|
29741
30758
|
};
|
|
29742
30759
|
const cardReplacement = async (req, res) => {
|
|
29743
30760
|
try {
|
|
29744
|
-
const { cardId, remarks } = req.body;
|
|
30761
|
+
const { cardId, remarks, unitId, issuedCardId, userId } = req.body;
|
|
29745
30762
|
const schema2 = import_joi85.default.object({
|
|
29746
30763
|
cardId: import_joi85.default.string().required(),
|
|
29747
|
-
remarks: import_joi85.default.string().optional().allow("", null)
|
|
30764
|
+
remarks: import_joi85.default.string().optional().allow("", null),
|
|
30765
|
+
unitId: import_joi85.default.string().hex().required(),
|
|
30766
|
+
issuedCardId: import_joi85.default.string().required(),
|
|
30767
|
+
userId: import_joi85.default.string().hex().required()
|
|
29748
30768
|
});
|
|
29749
|
-
const { error } = schema2.validate({ cardId, remarks });
|
|
30769
|
+
const { error } = schema2.validate({ cardId, remarks, unitId, issuedCardId, userId });
|
|
29750
30770
|
if (error) {
|
|
29751
30771
|
return res.status(400).json({ message: error.message });
|
|
29752
30772
|
}
|
|
29753
|
-
const result = await cardReplacementSvc({ cardId, remarks });
|
|
30773
|
+
const result = await cardReplacementSvc({ cardId, remarks, unitId, issuedCardId, userId });
|
|
29754
30774
|
return res.status(200).json({ message: "Success", data: result });
|
|
29755
30775
|
} catch (error) {
|
|
29756
30776
|
return res.status(500).json({
|
|
@@ -29881,6 +30901,74 @@ function useAccessManagementController() {
|
|
|
29881
30901
|
});
|
|
29882
30902
|
}
|
|
29883
30903
|
};
|
|
30904
|
+
const deleteCard = async (req, res) => {
|
|
30905
|
+
try {
|
|
30906
|
+
const { cardId, remarks } = req.body;
|
|
30907
|
+
const schema2 = import_joi85.default.object({
|
|
30908
|
+
cardId: import_joi85.default.string().hex().required(),
|
|
30909
|
+
remarks: import_joi85.default.string().optional().allow("", null)
|
|
30910
|
+
});
|
|
30911
|
+
const { error } = schema2.validate({ cardId, remarks });
|
|
30912
|
+
if (error) {
|
|
30913
|
+
return res.status(400).json({ message: error.message });
|
|
30914
|
+
}
|
|
30915
|
+
const result = await deleteCardSvc({ cardId, remarks });
|
|
30916
|
+
return res.status(200).json({ message: "Success", data: result });
|
|
30917
|
+
} catch (error) {
|
|
30918
|
+
return res.status(500).json({
|
|
30919
|
+
data: null,
|
|
30920
|
+
message: error.message
|
|
30921
|
+
});
|
|
30922
|
+
}
|
|
30923
|
+
};
|
|
30924
|
+
const getCardDetails = async (req, res) => {
|
|
30925
|
+
try {
|
|
30926
|
+
const { siteId, cardId } = req.query;
|
|
30927
|
+
const schema2 = import_joi85.default.object({
|
|
30928
|
+
siteId: import_joi85.default.string().hex().required(),
|
|
30929
|
+
cardId: import_joi85.default.string().hex().required()
|
|
30930
|
+
});
|
|
30931
|
+
const { error } = schema2.validate({ siteId, cardId });
|
|
30932
|
+
if (error) {
|
|
30933
|
+
return res.status(400).json({ message: error.message });
|
|
30934
|
+
}
|
|
30935
|
+
const result = await getCardDetailsSvc({ siteId, cardId });
|
|
30936
|
+
return res.status(200).json({ message: "Success", data: result });
|
|
30937
|
+
} catch (error) {
|
|
30938
|
+
return res.status(500).json({
|
|
30939
|
+
data: null,
|
|
30940
|
+
message: error.message
|
|
30941
|
+
});
|
|
30942
|
+
}
|
|
30943
|
+
};
|
|
30944
|
+
const addQrTag = async (req, res) => {
|
|
30945
|
+
try {
|
|
30946
|
+
const payload = req.body;
|
|
30947
|
+
const site = req.params.site;
|
|
30948
|
+
const schema2 = import_joi85.default.object({
|
|
30949
|
+
site: import_joi85.default.string().hex().required(),
|
|
30950
|
+
payload: import_joi85.default.array().items(
|
|
30951
|
+
import_joi85.default.object({
|
|
30952
|
+
_id: import_joi85.default.string().hex().required(),
|
|
30953
|
+
cardNo: import_joi85.default.string().required(),
|
|
30954
|
+
qrTag: import_joi85.default.string().required(),
|
|
30955
|
+
qrTagCardNo: import_joi85.default.string().required()
|
|
30956
|
+
})
|
|
30957
|
+
).required()
|
|
30958
|
+
});
|
|
30959
|
+
const { error } = schema2.validate({ site, payload });
|
|
30960
|
+
if (error) {
|
|
30961
|
+
return res.status(400).json({ message: error.message });
|
|
30962
|
+
}
|
|
30963
|
+
const result = await addQrTagSvc({ payload, site });
|
|
30964
|
+
return res.status(200).json({ message: "Success", data: result });
|
|
30965
|
+
} catch (error) {
|
|
30966
|
+
return res.status(500).json({
|
|
30967
|
+
data: null,
|
|
30968
|
+
message: error.message
|
|
30969
|
+
});
|
|
30970
|
+
}
|
|
30971
|
+
};
|
|
29884
30972
|
return {
|
|
29885
30973
|
addPhysicalCard,
|
|
29886
30974
|
addNonPhysicalCard,
|
|
@@ -29902,7 +30990,10 @@ function useAccessManagementController() {
|
|
|
29902
30990
|
getCardReplacement,
|
|
29903
30991
|
getAccessManagementSettings,
|
|
29904
30992
|
bulkPhysicalAccessCard,
|
|
29905
|
-
assignAccessCardToUnit
|
|
30993
|
+
assignAccessCardToUnit,
|
|
30994
|
+
deleteCard,
|
|
30995
|
+
getCardDetails,
|
|
30996
|
+
addQrTag
|
|
29906
30997
|
};
|
|
29907
30998
|
}
|
|
29908
30999
|
|
|
@@ -31619,9 +32710,9 @@ function useStatementOfAccountRepo() {
|
|
|
31619
32710
|
page = page > 0 ? page - 1 : 0;
|
|
31620
32711
|
let dateExpr = {};
|
|
31621
32712
|
if (dateFrom && dateTo) {
|
|
31622
|
-
|
|
32713
|
+
let startDate = new Date(dateFrom);
|
|
31623
32714
|
startDate.setHours(0, 0, 0, 0);
|
|
31624
|
-
|
|
32715
|
+
let endDate = new Date(dateTo);
|
|
31625
32716
|
endDate.setHours(23, 59, 59, 999);
|
|
31626
32717
|
dateExpr = {
|
|
31627
32718
|
$expr: {
|
|
@@ -31632,13 +32723,15 @@ function useStatementOfAccountRepo() {
|
|
|
31632
32723
|
}
|
|
31633
32724
|
};
|
|
31634
32725
|
}
|
|
32726
|
+
const unitSearchRegex = search ? search.trim().replace(/\s+/g, "").replace(/\//g, "\\s*/\\s*") : null;
|
|
31635
32727
|
const query = {
|
|
31636
32728
|
...status && status !== "all" && { status },
|
|
31637
32729
|
...search && {
|
|
31638
32730
|
$or: [
|
|
31639
32731
|
{ unitOwner: { $regex: search, $options: "i" } },
|
|
31640
|
-
{ unit: { $regex:
|
|
31641
|
-
{ email: { $regex: search, $options: "i" } }
|
|
32732
|
+
{ unit: { $regex: unitSearchRegex, $options: "i" } },
|
|
32733
|
+
{ email: { $regex: search, $options: "i" } },
|
|
32734
|
+
{ category: { $regex: search, $options: "i" } }
|
|
31642
32735
|
]
|
|
31643
32736
|
},
|
|
31644
32737
|
...import_mongodb91.ObjectId.isValid(site) && { site: new import_mongodb91.ObjectId(site) },
|
|
@@ -33883,6 +34976,9 @@ function useIncidentReportRepo() {
|
|
|
33883
34976
|
$regex: search,
|
|
33884
34977
|
$options: "i"
|
|
33885
34978
|
}
|
|
34979
|
+
},
|
|
34980
|
+
{
|
|
34981
|
+
approvedByName: { $regex: search, $options: "i" }
|
|
33886
34982
|
}
|
|
33887
34983
|
]
|
|
33888
34984
|
},
|
|
@@ -36396,7 +37492,9 @@ function useNfcPatrolLogController() {
|
|
|
36396
37492
|
}
|
|
36397
37493
|
// Annotate the CommonJS export names for ESM import in node:
|
|
36398
37494
|
0 && (module.exports = {
|
|
37495
|
+
ANPRMode,
|
|
36399
37496
|
AccessTypeProps,
|
|
37497
|
+
BULLETIN_RECIPIENTS,
|
|
36400
37498
|
DEVICE_STATUS,
|
|
36401
37499
|
EAccessCardTypes,
|
|
36402
37500
|
EAccessCardUserTypes,
|
|
@@ -36455,12 +37553,15 @@ function useNfcPatrolLogController() {
|
|
|
36455
37553
|
MVerification,
|
|
36456
37554
|
MVisitorTransaction,
|
|
36457
37555
|
MWorkOrder,
|
|
37556
|
+
OrgNature,
|
|
36458
37557
|
PERSON_TYPES,
|
|
37558
|
+
STATUS_VALUES,
|
|
36459
37559
|
UseAccessManagementRepo,
|
|
36460
|
-
|
|
37560
|
+
VehicleCategory,
|
|
37561
|
+
VehicleStatus,
|
|
37562
|
+
VehicleType,
|
|
36461
37563
|
allowedFieldsSite,
|
|
36462
37564
|
allowedNatures,
|
|
36463
|
-
allowedTypes,
|
|
36464
37565
|
attendanceSchema,
|
|
36465
37566
|
attendanceSettingsSchema,
|
|
36466
37567
|
chatSchema,
|