@7365admin1/core 2.65.0 → 2.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +75 -13
- package/dist/index.js +1636 -626
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1635 -626
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -125,7 +125,15 @@ var userSchema = Joi2.object({
|
|
|
125
125
|
email: Joi2.string().email().required(),
|
|
126
126
|
password: Joi2.string().min(8).required(),
|
|
127
127
|
name: Joi2.string().required(),
|
|
128
|
-
defaultOrg: Joi2.string().hex().optional().allow("", null)
|
|
128
|
+
defaultOrg: Joi2.string().hex().optional().allow("", null),
|
|
129
|
+
status: Joi2.string().optional().allow("", null),
|
|
130
|
+
block: Joi2.number().optional().allow(null),
|
|
131
|
+
level: Joi2.string().optional().allow("", null),
|
|
132
|
+
type: Joi2.string().optional().allow("", null),
|
|
133
|
+
unitName: Joi2.string().optional().allow("", null),
|
|
134
|
+
contact: Joi2.string().optional().allow("", null),
|
|
135
|
+
site: Joi2.string().hex().optional().allow("", null),
|
|
136
|
+
unitId: Joi2.string().hex().optional().allow("", null)
|
|
129
137
|
});
|
|
130
138
|
function MUser(value) {
|
|
131
139
|
const { error } = userSchema.validate(value);
|
|
@@ -139,12 +147,33 @@ function MUser(value) {
|
|
|
139
147
|
throw new BadRequestError2("Invalid default org ID format.");
|
|
140
148
|
}
|
|
141
149
|
}
|
|
150
|
+
if (value.site && typeof value.site === "string") {
|
|
151
|
+
try {
|
|
152
|
+
value.site = new ObjectId(value.site);
|
|
153
|
+
} catch {
|
|
154
|
+
throw new BadRequestError2("Invalid site ID format.");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (value.unitId && typeof value.unitId === "string") {
|
|
158
|
+
try {
|
|
159
|
+
value.unitId = new ObjectId(value.unitId);
|
|
160
|
+
} catch {
|
|
161
|
+
throw new BadRequestError2("Invalid unit ID format.");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
142
164
|
return {
|
|
143
165
|
email: value.email,
|
|
144
166
|
password: value.password,
|
|
145
167
|
name: value.name ?? "",
|
|
146
168
|
defaultOrg: value.defaultOrg ?? "",
|
|
147
|
-
status: "active" /* ACTIVE */,
|
|
169
|
+
status: value.status ?? "active" /* ACTIVE */,
|
|
170
|
+
block: value.block ?? null,
|
|
171
|
+
level: value.level ?? "",
|
|
172
|
+
type: value.type ?? "",
|
|
173
|
+
unitName: value.unitName ?? "",
|
|
174
|
+
contact: value.contact ?? "",
|
|
175
|
+
site: value.site ?? "",
|
|
176
|
+
unitId: value.unitId ?? "",
|
|
148
177
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
149
178
|
updatedAt: value.updatedAt ?? "",
|
|
150
179
|
deletedAt: value.deletedAt ?? ""
|
|
@@ -4372,6 +4401,30 @@ function useOrgRepo() {
|
|
|
4372
4401
|
throw error;
|
|
4373
4402
|
}
|
|
4374
4403
|
}
|
|
4404
|
+
async function getOrgsByEmail(email) {
|
|
4405
|
+
const cacheKey = makeCacheKey8(namespace_collection, {
|
|
4406
|
+
type: "many",
|
|
4407
|
+
email
|
|
4408
|
+
});
|
|
4409
|
+
const cachedData = await getCache(cacheKey);
|
|
4410
|
+
if (cachedData) {
|
|
4411
|
+
logger10.info(`Cache hit for key: ${cacheKey}`);
|
|
4412
|
+
return cachedData;
|
|
4413
|
+
}
|
|
4414
|
+
try {
|
|
4415
|
+
const data = await collection.find({
|
|
4416
|
+
email
|
|
4417
|
+
}).toArray();
|
|
4418
|
+
setCache(cacheKey, data, 15 * 60).then(() => {
|
|
4419
|
+
logger10.info(`Cache set for key: ${cacheKey}`);
|
|
4420
|
+
}).catch((err) => {
|
|
4421
|
+
logger10.error(`Failed to set cache for key: ${cacheKey}`, err);
|
|
4422
|
+
});
|
|
4423
|
+
return data;
|
|
4424
|
+
} catch (error) {
|
|
4425
|
+
throw error;
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4375
4428
|
async function updateFieldById({
|
|
4376
4429
|
_id,
|
|
4377
4430
|
field,
|
|
@@ -4474,7 +4527,8 @@ function useOrgRepo() {
|
|
|
4474
4527
|
getByEmail,
|
|
4475
4528
|
updateFieldById,
|
|
4476
4529
|
updateStatusById,
|
|
4477
|
-
deleteById
|
|
4530
|
+
deleteById,
|
|
4531
|
+
getOrgsByEmail
|
|
4478
4532
|
};
|
|
4479
4533
|
}
|
|
4480
4534
|
|
|
@@ -5497,7 +5551,6 @@ function useVerificationService() {
|
|
|
5497
5551
|
await getSiteById(metadata.siteId);
|
|
5498
5552
|
}
|
|
5499
5553
|
const verificationIds = [];
|
|
5500
|
-
const invitedApps = [];
|
|
5501
5554
|
for (const app of apps) {
|
|
5502
5555
|
await useVerificationRepo().findOne({
|
|
5503
5556
|
type,
|
|
@@ -5520,34 +5573,32 @@ function useVerificationService() {
|
|
|
5520
5573
|
};
|
|
5521
5574
|
const createdId = await add(value);
|
|
5522
5575
|
verificationIds.push(createdId.toString());
|
|
5523
|
-
|
|
5576
|
+
const link = `${APP_MAIN}/verify/invitation/${createdId}`;
|
|
5577
|
+
const emailContent = compileHandlebar({
|
|
5578
|
+
context: {
|
|
5579
|
+
email,
|
|
5580
|
+
validity: VERIFICATION_USER_INVITE_DURATION,
|
|
5581
|
+
link,
|
|
5582
|
+
hasPropertyManagement: app === "property_management_agency",
|
|
5583
|
+
hasSecurity: app === "security_agency",
|
|
5584
|
+
hasCleaning: app === "cleaning_services",
|
|
5585
|
+
hasMechanical: app === "mechanical_electrical_services",
|
|
5586
|
+
hasLandscape: app === "landscaping_services",
|
|
5587
|
+
hasPestControl: app === "pest_control_services",
|
|
5588
|
+
hasPoolMaintenance: app === "pool_maintenance_services"
|
|
5589
|
+
},
|
|
5590
|
+
filePath: getDirectory(
|
|
5591
|
+
__dirname,
|
|
5592
|
+
"./public/handlebars/user-invite"
|
|
5593
|
+
)
|
|
5594
|
+
});
|
|
5595
|
+
await mailer.sendMail({
|
|
5596
|
+
to: email,
|
|
5597
|
+
subject: "User Invite",
|
|
5598
|
+
html: emailContent,
|
|
5599
|
+
sender: "iService365"
|
|
5600
|
+
});
|
|
5524
5601
|
}
|
|
5525
|
-
const link = `${APP_MAIN}/verify/invitation/${verificationIds[0]}`;
|
|
5526
|
-
const appsSet = new Set(invitedApps);
|
|
5527
|
-
const emailContent = compileHandlebar({
|
|
5528
|
-
context: {
|
|
5529
|
-
email,
|
|
5530
|
-
validity: VERIFICATION_USER_INVITE_DURATION,
|
|
5531
|
-
link,
|
|
5532
|
-
hasPropertyManagement: appsSet.has("property_management_agency"),
|
|
5533
|
-
hasSecurity: appsSet.has("security_agency"),
|
|
5534
|
-
hasCleaning: appsSet.has("cleaning_services"),
|
|
5535
|
-
hasMechanical: appsSet.has("mechanical_electrical_services"),
|
|
5536
|
-
hasLandscape: appsSet.has("landscaping_services"),
|
|
5537
|
-
hasPestControl: appsSet.has("pest_control_services"),
|
|
5538
|
-
hasPoolMaintenance: appsSet.has("pool_maintenance_services")
|
|
5539
|
-
},
|
|
5540
|
-
filePath: getDirectory(
|
|
5541
|
-
__dirname,
|
|
5542
|
-
"./public/handlebars/user-invite"
|
|
5543
|
-
)
|
|
5544
|
-
});
|
|
5545
|
-
await mailer.sendMail({
|
|
5546
|
-
to: email,
|
|
5547
|
-
subject: "User Invite",
|
|
5548
|
-
html: emailContent,
|
|
5549
|
-
sender: "iService365"
|
|
5550
|
-
});
|
|
5551
5602
|
return verificationIds;
|
|
5552
5603
|
}
|
|
5553
5604
|
async function createSimpleMemberInvite({
|
|
@@ -8042,7 +8093,7 @@ function useVerificationController() {
|
|
|
8042
8093
|
siteId: Joi16.string().hex().optional().allow("", null),
|
|
8043
8094
|
siteName: Joi16.string().optional().allow("", null)
|
|
8044
8095
|
});
|
|
8045
|
-
const { error } = validation.validate(payload);
|
|
8096
|
+
const { error, value } = validation.validate(payload);
|
|
8046
8097
|
if (error) {
|
|
8047
8098
|
logger22.log({
|
|
8048
8099
|
level: "error",
|
|
@@ -8051,15 +8102,17 @@ function useVerificationController() {
|
|
|
8051
8102
|
next(new BadRequestError31(error.message));
|
|
8052
8103
|
return;
|
|
8053
8104
|
}
|
|
8054
|
-
const email = req.body.email ?? "";
|
|
8055
|
-
const app = req.body.app ?? [];
|
|
8056
|
-
const role = req.body.role ?? "";
|
|
8057
|
-
const name = req.body.name ?? "";
|
|
8058
|
-
const org = req.body.org ?? "";
|
|
8059
|
-
const siteId = req.body.siteId ?? "";
|
|
8060
|
-
const siteName = req.body.siteName ?? "";
|
|
8061
8105
|
try {
|
|
8062
|
-
|
|
8106
|
+
const {
|
|
8107
|
+
email,
|
|
8108
|
+
app,
|
|
8109
|
+
role,
|
|
8110
|
+
name,
|
|
8111
|
+
org,
|
|
8112
|
+
siteId,
|
|
8113
|
+
siteName
|
|
8114
|
+
} = value;
|
|
8115
|
+
const verificationIds = await _createSimpleUserInvite({
|
|
8063
8116
|
email,
|
|
8064
8117
|
metadata: {
|
|
8065
8118
|
app,
|
|
@@ -8071,7 +8124,9 @@ function useVerificationController() {
|
|
|
8071
8124
|
}
|
|
8072
8125
|
});
|
|
8073
8126
|
res.status(201).json({
|
|
8074
|
-
message: "Successfully invited user."
|
|
8127
|
+
message: "Successfully invited user.",
|
|
8128
|
+
totalInvites: verificationIds.length,
|
|
8129
|
+
verificationIds
|
|
8075
8130
|
});
|
|
8076
8131
|
return;
|
|
8077
8132
|
} catch (error2) {
|
|
@@ -8531,7 +8586,8 @@ function useOrgController() {
|
|
|
8531
8586
|
getByEmail: _getByEmail,
|
|
8532
8587
|
getAll: _getAll,
|
|
8533
8588
|
add: _add,
|
|
8534
|
-
update: _update
|
|
8589
|
+
update: _update,
|
|
8590
|
+
getOrgsByEmail: _getOrgsByEmail
|
|
8535
8591
|
} = useOrgRepo();
|
|
8536
8592
|
async function add(req, res, next) {
|
|
8537
8593
|
const validation = Joi18.object({
|
|
@@ -8715,6 +8771,30 @@ function useOrgController() {
|
|
|
8715
8771
|
return;
|
|
8716
8772
|
}
|
|
8717
8773
|
}
|
|
8774
|
+
async function getOrgsByEmail(req, res, next) {
|
|
8775
|
+
const validation = Joi18.object({
|
|
8776
|
+
email: Joi18.string().email().required()
|
|
8777
|
+
});
|
|
8778
|
+
const query = {
|
|
8779
|
+
email: req.params.email
|
|
8780
|
+
};
|
|
8781
|
+
const { error } = validation.validate(query);
|
|
8782
|
+
if (error) {
|
|
8783
|
+
logger25.log({ level: "error", message: error.message });
|
|
8784
|
+
next(new BadRequestError33(error.message));
|
|
8785
|
+
return;
|
|
8786
|
+
}
|
|
8787
|
+
const email = req.params.email;
|
|
8788
|
+
try {
|
|
8789
|
+
const data = await _getOrgsByEmail(email);
|
|
8790
|
+
res.json(data);
|
|
8791
|
+
return;
|
|
8792
|
+
} catch (error2) {
|
|
8793
|
+
logger25.log({ level: "error", message: error2.message });
|
|
8794
|
+
next(error2);
|
|
8795
|
+
return;
|
|
8796
|
+
}
|
|
8797
|
+
}
|
|
8718
8798
|
async function update(req, res, next) {
|
|
8719
8799
|
const validation = Joi18.object({
|
|
8720
8800
|
name: Joi18.string().optional(),
|
|
@@ -8748,7 +8828,8 @@ function useOrgController() {
|
|
|
8748
8828
|
getByName,
|
|
8749
8829
|
getById,
|
|
8750
8830
|
getByEmail,
|
|
8751
|
-
update
|
|
8831
|
+
update,
|
|
8832
|
+
getOrgsByEmail
|
|
8752
8833
|
};
|
|
8753
8834
|
}
|
|
8754
8835
|
|
|
@@ -26552,7 +26633,14 @@ function usePersonService() {
|
|
|
26552
26633
|
password: hashedPassword,
|
|
26553
26634
|
name: value.name,
|
|
26554
26635
|
status: value.platform == "mobile" ? "pending" : "active",
|
|
26555
|
-
defaultOrg: value.org?.toString() || ""
|
|
26636
|
+
defaultOrg: value.org?.toString() || "",
|
|
26637
|
+
block: value.block,
|
|
26638
|
+
level: value.level,
|
|
26639
|
+
type: value.type,
|
|
26640
|
+
unitName: value.unitName,
|
|
26641
|
+
contact: value.contact,
|
|
26642
|
+
site: value.site?.toString() || "",
|
|
26643
|
+
unitId: value.unit?.toString() || ""
|
|
26556
26644
|
};
|
|
26557
26645
|
const userId = await addUser(user, session);
|
|
26558
26646
|
value.user = userId.toString();
|
|
@@ -36340,10 +36428,42 @@ function UseAccessManagementRepo() {
|
|
|
36340
36428
|
},
|
|
36341
36429
|
{
|
|
36342
36430
|
$facet: {
|
|
36343
|
-
available_physical: [
|
|
36344
|
-
|
|
36345
|
-
|
|
36346
|
-
|
|
36431
|
+
available_physical: [
|
|
36432
|
+
{
|
|
36433
|
+
$match: {
|
|
36434
|
+
assignedUnit: { $eq: null },
|
|
36435
|
+
type: "NFC" /* NFC */
|
|
36436
|
+
}
|
|
36437
|
+
},
|
|
36438
|
+
{ $count: "count" }
|
|
36439
|
+
],
|
|
36440
|
+
available_non_physical: [
|
|
36441
|
+
{
|
|
36442
|
+
$match: {
|
|
36443
|
+
assignedUnit: { $eq: null },
|
|
36444
|
+
type: "QRCODE" /* QR */
|
|
36445
|
+
}
|
|
36446
|
+
},
|
|
36447
|
+
{ $count: "count" }
|
|
36448
|
+
],
|
|
36449
|
+
assigned_physical: [
|
|
36450
|
+
{
|
|
36451
|
+
$match: {
|
|
36452
|
+
assignedUnit: { $ne: null },
|
|
36453
|
+
type: "NFC" /* NFC */
|
|
36454
|
+
}
|
|
36455
|
+
},
|
|
36456
|
+
{ $count: "count" }
|
|
36457
|
+
],
|
|
36458
|
+
assigned_non_physical: [
|
|
36459
|
+
{
|
|
36460
|
+
$match: {
|
|
36461
|
+
assignedUnit: { $ne: null },
|
|
36462
|
+
type: "QRCODE" /* QR */
|
|
36463
|
+
}
|
|
36464
|
+
},
|
|
36465
|
+
{ $count: "count" }
|
|
36466
|
+
]
|
|
36347
36467
|
}
|
|
36348
36468
|
}
|
|
36349
36469
|
]).toArray();
|
|
@@ -36428,16 +36548,35 @@ function UseAccessManagementRepo() {
|
|
|
36428
36548
|
case terms.length >= 3:
|
|
36429
36549
|
return {
|
|
36430
36550
|
$and: [
|
|
36431
|
-
{
|
|
36432
|
-
|
|
36433
|
-
|
|
36551
|
+
{
|
|
36552
|
+
$expr: { $eq: [{ $toLower: "$name" }, terms[0].toLowerCase()] }
|
|
36553
|
+
},
|
|
36554
|
+
{
|
|
36555
|
+
$expr: {
|
|
36556
|
+
$eq: [{ $toLower: "$level.level" }, terms[1].toLowerCase()]
|
|
36557
|
+
}
|
|
36558
|
+
},
|
|
36559
|
+
{
|
|
36560
|
+
$expr: {
|
|
36561
|
+
$eq: [
|
|
36562
|
+
{ $toLower: "$level.units.name" },
|
|
36563
|
+
getAfterSecondSlash(search)
|
|
36564
|
+
]
|
|
36565
|
+
}
|
|
36566
|
+
}
|
|
36434
36567
|
]
|
|
36435
36568
|
};
|
|
36436
36569
|
case terms.length === 2:
|
|
36437
36570
|
return {
|
|
36438
36571
|
$and: [
|
|
36439
|
-
{
|
|
36440
|
-
|
|
36572
|
+
{
|
|
36573
|
+
$expr: { $eq: [{ $toLower: "$name" }, terms[0].toLowerCase()] }
|
|
36574
|
+
},
|
|
36575
|
+
{
|
|
36576
|
+
$expr: {
|
|
36577
|
+
$eq: [{ $toLower: "$level.level" }, terms[1].toLowerCase()]
|
|
36578
|
+
}
|
|
36579
|
+
}
|
|
36441
36580
|
]
|
|
36442
36581
|
};
|
|
36443
36582
|
default:
|
|
@@ -36465,220 +36604,386 @@ function UseAccessManagementRepo() {
|
|
|
36465
36604
|
site
|
|
36466
36605
|
};
|
|
36467
36606
|
const searchQuery = buildSearchQuery(search);
|
|
36468
|
-
const result = await collectionName("buildings").aggregate(
|
|
36469
|
-
|
|
36470
|
-
|
|
36471
|
-
|
|
36472
|
-
|
|
36473
|
-
|
|
36474
|
-
|
|
36475
|
-
|
|
36476
|
-
|
|
36477
|
-
|
|
36478
|
-
|
|
36479
|
-
|
|
36480
|
-
|
|
36481
|
-
|
|
36482
|
-
|
|
36483
|
-
|
|
36484
|
-
|
|
36485
|
-
|
|
36486
|
-
|
|
36487
|
-
|
|
36488
|
-
|
|
36489
|
-
|
|
36490
|
-
|
|
36491
|
-
|
|
36492
|
-
|
|
36493
|
-
|
|
36494
|
-
|
|
36495
|
-
|
|
36496
|
-
|
|
36497
|
-
|
|
36498
|
-
|
|
36499
|
-
|
|
36500
|
-
|
|
36501
|
-
|
|
36502
|
-
|
|
36503
|
-
|
|
36504
|
-
|
|
36505
|
-
|
|
36506
|
-
|
|
36507
|
-
|
|
36508
|
-
|
|
36509
|
-
|
|
36510
|
-
|
|
36511
|
-
|
|
36512
|
-
|
|
36607
|
+
const result = await collectionName("buildings").aggregate(
|
|
36608
|
+
[
|
|
36609
|
+
// ✅ Match early with index-friendly query
|
|
36610
|
+
{
|
|
36611
|
+
$match: {
|
|
36612
|
+
...defaultQuery,
|
|
36613
|
+
status: { $eq: "active" }
|
|
36614
|
+
}
|
|
36615
|
+
},
|
|
36616
|
+
// ✅ Only project needed fields before heavy lookups
|
|
36617
|
+
{
|
|
36618
|
+
$project: {
|
|
36619
|
+
_id: 1,
|
|
36620
|
+
name: 1,
|
|
36621
|
+
site: 1,
|
|
36622
|
+
block: 1
|
|
36623
|
+
}
|
|
36624
|
+
},
|
|
36625
|
+
// ✅ Use localField/foreignField for better index usage
|
|
36626
|
+
{
|
|
36627
|
+
$lookup: {
|
|
36628
|
+
from: "building-levels",
|
|
36629
|
+
localField: "_id",
|
|
36630
|
+
foreignField: "block",
|
|
36631
|
+
pipeline: [
|
|
36632
|
+
{ $match: { status: { $ne: "deleted" } } },
|
|
36633
|
+
{
|
|
36634
|
+
$lookup: {
|
|
36635
|
+
from: "building-units",
|
|
36636
|
+
localField: "_id",
|
|
36637
|
+
foreignField: "level",
|
|
36638
|
+
pipeline: [
|
|
36639
|
+
{ $match: { status: { $ne: "deleted" }, site } },
|
|
36640
|
+
{ $project: { _id: 1, name: 1 } }
|
|
36641
|
+
],
|
|
36642
|
+
as: "units"
|
|
36643
|
+
}
|
|
36644
|
+
},
|
|
36645
|
+
{
|
|
36646
|
+
$match: { "units.0": { $exists: true } }
|
|
36647
|
+
},
|
|
36648
|
+
{
|
|
36649
|
+
$project: {
|
|
36650
|
+
_id: 1,
|
|
36651
|
+
level: 1,
|
|
36652
|
+
units: 1
|
|
36653
|
+
}
|
|
36513
36654
|
}
|
|
36514
|
-
|
|
36515
|
-
|
|
36516
|
-
|
|
36517
|
-
}
|
|
36518
|
-
|
|
36519
|
-
|
|
36520
|
-
|
|
36521
|
-
|
|
36522
|
-
|
|
36523
|
-
|
|
36524
|
-
|
|
36525
|
-
|
|
36526
|
-
|
|
36527
|
-
|
|
36528
|
-
}
|
|
36529
|
-
|
|
36530
|
-
|
|
36531
|
-
|
|
36532
|
-
|
|
36533
|
-
|
|
36534
|
-
}
|
|
36535
|
-
|
|
36536
|
-
|
|
36537
|
-
|
|
36538
|
-
|
|
36539
|
-
|
|
36540
|
-
|
|
36541
|
-
|
|
36542
|
-
|
|
36543
|
-
|
|
36544
|
-
|
|
36545
|
-
|
|
36546
|
-
|
|
36547
|
-
|
|
36548
|
-
|
|
36549
|
-
|
|
36550
|
-
}
|
|
36551
|
-
|
|
36552
|
-
|
|
36553
|
-
|
|
36554
|
-
|
|
36555
|
-
|
|
36556
|
-
|
|
36557
|
-
|
|
36558
|
-
|
|
36559
|
-
|
|
36560
|
-
|
|
36561
|
-
|
|
36562
|
-
|
|
36563
|
-
|
|
36564
|
-
|
|
36565
|
-
|
|
36566
|
-
|
|
36567
|
-
|
|
36568
|
-
|
|
36655
|
+
],
|
|
36656
|
+
as: "level"
|
|
36657
|
+
}
|
|
36658
|
+
},
|
|
36659
|
+
// ✅ Filter out buildings with no levels early
|
|
36660
|
+
{
|
|
36661
|
+
$match: { "level.0": { $exists: true } }
|
|
36662
|
+
},
|
|
36663
|
+
// ✅ Unwind to flatten the hierarchy
|
|
36664
|
+
{
|
|
36665
|
+
$unwind: {
|
|
36666
|
+
path: "$level",
|
|
36667
|
+
preserveNullAndEmptyArrays: false
|
|
36668
|
+
}
|
|
36669
|
+
},
|
|
36670
|
+
{
|
|
36671
|
+
$unwind: {
|
|
36672
|
+
path: "$level.units",
|
|
36673
|
+
preserveNullAndEmptyArrays: false
|
|
36674
|
+
}
|
|
36675
|
+
},
|
|
36676
|
+
// // Groups by unit _id and keeps only the first occurrence
|
|
36677
|
+
// {
|
|
36678
|
+
// $group: {
|
|
36679
|
+
// _id: "$level.units._id",
|
|
36680
|
+
// doc: { $first: "$$ROOT" },
|
|
36681
|
+
// },
|
|
36682
|
+
// },
|
|
36683
|
+
// {
|
|
36684
|
+
// $replaceRoot: { newRoot: "$doc" },
|
|
36685
|
+
// },
|
|
36686
|
+
// ✅ Apply search filter
|
|
36687
|
+
{
|
|
36688
|
+
$match: {
|
|
36689
|
+
...searchQuery
|
|
36690
|
+
}
|
|
36691
|
+
},
|
|
36692
|
+
{
|
|
36693
|
+
$facet: {
|
|
36694
|
+
totalCount: [{ $count: "count" }],
|
|
36695
|
+
items: [
|
|
36696
|
+
// ✅ Sort BEFORE skip/limit for correct pagination
|
|
36697
|
+
{ $skip: page * limit },
|
|
36698
|
+
{ $limit: limit },
|
|
36699
|
+
// ✅ Users lookup - optimized with index hint
|
|
36700
|
+
{
|
|
36701
|
+
$lookup: {
|
|
36702
|
+
from: "users",
|
|
36703
|
+
let: { unit: "$level.units._id" },
|
|
36704
|
+
pipeline: [
|
|
36705
|
+
{
|
|
36706
|
+
$match: {
|
|
36707
|
+
$expr: { $eq: ["$unitNumber", "$$unit"] },
|
|
36708
|
+
residentType: "House/Unit Owner"
|
|
36709
|
+
}
|
|
36710
|
+
},
|
|
36711
|
+
{ $limit: 1 },
|
|
36712
|
+
{ $project: { _id: 1, givenName: 1, surname: 1 } }
|
|
36713
|
+
],
|
|
36714
|
+
as: "unitOwner"
|
|
36715
|
+
}
|
|
36716
|
+
},
|
|
36717
|
+
// ✅ Access card lookup - optimized query
|
|
36718
|
+
{
|
|
36719
|
+
$lookup: {
|
|
36720
|
+
from: "access-cards",
|
|
36721
|
+
let: { unit: "$level.units._id" },
|
|
36722
|
+
pipeline: [
|
|
36723
|
+
{
|
|
36724
|
+
$match: {
|
|
36725
|
+
$expr: {
|
|
36726
|
+
$in: [
|
|
36727
|
+
"$$unit",
|
|
36728
|
+
{
|
|
36729
|
+
$cond: [
|
|
36730
|
+
{ $isArray: "$assignedUnit" },
|
|
36731
|
+
"$assignedUnit",
|
|
36732
|
+
["$assignedUnit"]
|
|
36733
|
+
]
|
|
36734
|
+
}
|
|
36735
|
+
]
|
|
36736
|
+
},
|
|
36737
|
+
userType
|
|
36738
|
+
}
|
|
36739
|
+
},
|
|
36740
|
+
{
|
|
36741
|
+
$project: {
|
|
36742
|
+
_id: 1,
|
|
36743
|
+
userId: 1,
|
|
36744
|
+
type: 1,
|
|
36745
|
+
cardNo: 1,
|
|
36746
|
+
isActivated: 1,
|
|
36747
|
+
replacementStatus: 1
|
|
36748
|
+
}
|
|
36749
|
+
}
|
|
36750
|
+
],
|
|
36751
|
+
as: "accessCards"
|
|
36752
|
+
}
|
|
36753
|
+
},
|
|
36754
|
+
// ✅ Compute all card categorization and counts in ONE stage
|
|
36755
|
+
{
|
|
36756
|
+
$addFields: {
|
|
36757
|
+
f_Available: {
|
|
36758
|
+
$filter: {
|
|
36759
|
+
input: "$accessCards",
|
|
36760
|
+
as: "card",
|
|
36761
|
+
cond: {
|
|
36762
|
+
$and: [
|
|
36763
|
+
{ $eq: ["$$card.userId", null] },
|
|
36764
|
+
{ $eq: ["$$card.isActivated", true] }
|
|
36765
|
+
]
|
|
36766
|
+
}
|
|
36569
36767
|
}
|
|
36570
36768
|
},
|
|
36571
|
-
|
|
36572
|
-
|
|
36573
|
-
|
|
36574
|
-
|
|
36575
|
-
|
|
36576
|
-
|
|
36577
|
-
|
|
36578
|
-
|
|
36579
|
-
$lookup: {
|
|
36580
|
-
from: "access-cards",
|
|
36581
|
-
let: { unit: "$level.units._id" },
|
|
36582
|
-
pipeline: [
|
|
36583
|
-
{
|
|
36584
|
-
$match: {
|
|
36585
|
-
$expr: {
|
|
36586
|
-
$in: [
|
|
36587
|
-
"$$unit",
|
|
36588
|
-
{ $cond: [{ $isArray: "$assignedUnit" }, "$assignedUnit", ["$assignedUnit"]] }
|
|
36769
|
+
f_Assigned: {
|
|
36770
|
+
$filter: {
|
|
36771
|
+
input: "$accessCards",
|
|
36772
|
+
as: "card",
|
|
36773
|
+
cond: {
|
|
36774
|
+
$and: [
|
|
36775
|
+
{ $ne: ["$$card.userId", null] },
|
|
36776
|
+
{ $eq: ["$$card.isActivated", true] }
|
|
36589
36777
|
]
|
|
36590
|
-
}
|
|
36591
|
-
userType
|
|
36778
|
+
}
|
|
36592
36779
|
}
|
|
36593
36780
|
},
|
|
36594
|
-
|
|
36595
|
-
|
|
36596
|
-
|
|
36597
|
-
|
|
36598
|
-
|
|
36599
|
-
|
|
36600
|
-
|
|
36601
|
-
|
|
36602
|
-
|
|
36603
|
-
|
|
36604
|
-
|
|
36605
|
-
|
|
36606
|
-
|
|
36607
|
-
|
|
36608
|
-
|
|
36609
|
-
|
|
36610
|
-
|
|
36611
|
-
|
|
36612
|
-
|
|
36613
|
-
|
|
36614
|
-
|
|
36615
|
-
|
|
36616
|
-
|
|
36617
|
-
$filter: {
|
|
36618
|
-
input: "$accessCards",
|
|
36619
|
-
as: "card",
|
|
36620
|
-
cond: { $and: [{ $eq: ["$$card.isActivated", false] }, { $ne: ["$$card.replacementStatus", null] }] }
|
|
36621
|
-
}
|
|
36622
|
-
},
|
|
36623
|
-
f_deleted: {
|
|
36624
|
-
$filter: {
|
|
36625
|
-
input: "$accessCards",
|
|
36626
|
-
as: "card",
|
|
36627
|
-
cond: { $and: [{ $eq: ["$$card.isActivated", false] }, { $eq: ["$$card.replacementStatus", null] }] }
|
|
36781
|
+
f_replaced: {
|
|
36782
|
+
$filter: {
|
|
36783
|
+
input: "$accessCards",
|
|
36784
|
+
as: "card",
|
|
36785
|
+
cond: {
|
|
36786
|
+
$and: [
|
|
36787
|
+
{ $eq: ["$$card.isActivated", false] },
|
|
36788
|
+
{ $ne: ["$$card.replacementStatus", null] }
|
|
36789
|
+
]
|
|
36790
|
+
}
|
|
36791
|
+
}
|
|
36792
|
+
},
|
|
36793
|
+
f_deleted: {
|
|
36794
|
+
$filter: {
|
|
36795
|
+
input: "$accessCards",
|
|
36796
|
+
as: "card",
|
|
36797
|
+
cond: {
|
|
36798
|
+
$and: [
|
|
36799
|
+
{ $eq: ["$$card.isActivated", false] },
|
|
36800
|
+
{ $eq: ["$$card.replacementStatus", null] }
|
|
36801
|
+
]
|
|
36802
|
+
}
|
|
36803
|
+
}
|
|
36628
36804
|
}
|
|
36629
36805
|
}
|
|
36630
|
-
}
|
|
36631
|
-
|
|
36632
|
-
|
|
36633
|
-
|
|
36634
|
-
|
|
36635
|
-
|
|
36636
|
-
|
|
36637
|
-
|
|
36638
|
-
|
|
36639
|
-
|
|
36640
|
-
unit_owner: { $arrayElemAt: ["$unitOwner", 0] },
|
|
36641
|
-
available: {
|
|
36642
|
-
physical: { $filter: { input: "$f_Available", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
36643
|
-
non_physical: { $filter: { input: "$f_Available", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
36644
|
-
},
|
|
36645
|
-
assigned: {
|
|
36646
|
-
physical: { $filter: { input: "$f_Assigned", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
36647
|
-
non_physical: { $filter: { input: "$f_Assigned", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
36648
|
-
},
|
|
36649
|
-
cardCounts: {
|
|
36806
|
+
},
|
|
36807
|
+
// ✅ Final projection with all computed fields
|
|
36808
|
+
{
|
|
36809
|
+
$project: {
|
|
36810
|
+
_id: "$level.units._id",
|
|
36811
|
+
name: "$level.units.name",
|
|
36812
|
+
level: { _id: "$level._id", level: "$level.level" },
|
|
36813
|
+
block: { _id: "$_id", name: "$name", block: "$block" },
|
|
36814
|
+
site: "$site",
|
|
36815
|
+
unit_owner: { $arrayElemAt: ["$unitOwner", 0] },
|
|
36650
36816
|
available: {
|
|
36651
|
-
physical: {
|
|
36652
|
-
|
|
36817
|
+
physical: {
|
|
36818
|
+
$filter: {
|
|
36819
|
+
input: "$f_Available",
|
|
36820
|
+
as: "c",
|
|
36821
|
+
cond: { $eq: ["$$c.type", "NFC" /* NFC */] }
|
|
36822
|
+
}
|
|
36823
|
+
},
|
|
36824
|
+
non_physical: {
|
|
36825
|
+
$filter: {
|
|
36826
|
+
input: "$f_Available",
|
|
36827
|
+
as: "c",
|
|
36828
|
+
cond: { $eq: ["$$c.type", "QRCODE" /* QR */] }
|
|
36829
|
+
}
|
|
36830
|
+
}
|
|
36653
36831
|
},
|
|
36654
36832
|
assigned: {
|
|
36655
|
-
physical: {
|
|
36656
|
-
|
|
36833
|
+
physical: {
|
|
36834
|
+
$filter: {
|
|
36835
|
+
input: "$f_Assigned",
|
|
36836
|
+
as: "c",
|
|
36837
|
+
cond: { $eq: ["$$c.type", "NFC" /* NFC */] }
|
|
36838
|
+
}
|
|
36839
|
+
},
|
|
36840
|
+
non_physical: {
|
|
36841
|
+
$filter: {
|
|
36842
|
+
input: "$f_Assigned",
|
|
36843
|
+
as: "c",
|
|
36844
|
+
cond: { $eq: ["$$c.type", "QRCODE" /* QR */] }
|
|
36845
|
+
}
|
|
36846
|
+
}
|
|
36847
|
+
},
|
|
36848
|
+
cardCounts: {
|
|
36849
|
+
available: {
|
|
36850
|
+
physical: {
|
|
36851
|
+
$size: {
|
|
36852
|
+
$filter: {
|
|
36853
|
+
input: { $ifNull: ["$f_Available", []] },
|
|
36854
|
+
as: "c",
|
|
36855
|
+
cond: {
|
|
36856
|
+
$eq: ["$$c.type", "NFC" /* NFC */]
|
|
36857
|
+
}
|
|
36858
|
+
}
|
|
36859
|
+
}
|
|
36860
|
+
},
|
|
36861
|
+
non_physical: {
|
|
36862
|
+
$size: {
|
|
36863
|
+
$filter: {
|
|
36864
|
+
input: { $ifNull: ["$f_Available", []] },
|
|
36865
|
+
as: "c",
|
|
36866
|
+
cond: {
|
|
36867
|
+
$eq: ["$$c.type", "QRCODE" /* QR */]
|
|
36868
|
+
}
|
|
36869
|
+
}
|
|
36870
|
+
}
|
|
36871
|
+
}
|
|
36872
|
+
},
|
|
36873
|
+
assigned: {
|
|
36874
|
+
physical: {
|
|
36875
|
+
$size: {
|
|
36876
|
+
$filter: {
|
|
36877
|
+
input: { $ifNull: ["$f_Assigned", []] },
|
|
36878
|
+
as: "c",
|
|
36879
|
+
cond: {
|
|
36880
|
+
$eq: ["$$c.type", "NFC" /* NFC */]
|
|
36881
|
+
}
|
|
36882
|
+
}
|
|
36883
|
+
}
|
|
36884
|
+
},
|
|
36885
|
+
non_physical: {
|
|
36886
|
+
$size: {
|
|
36887
|
+
$filter: {
|
|
36888
|
+
input: { $ifNull: ["$f_Assigned", []] },
|
|
36889
|
+
as: "c",
|
|
36890
|
+
cond: {
|
|
36891
|
+
$eq: ["$$c.type", "QRCODE" /* QR */]
|
|
36892
|
+
}
|
|
36893
|
+
}
|
|
36894
|
+
}
|
|
36895
|
+
}
|
|
36896
|
+
}
|
|
36897
|
+
},
|
|
36898
|
+
replaced: {
|
|
36899
|
+
physical: {
|
|
36900
|
+
$filter: {
|
|
36901
|
+
input: "$f_replaced",
|
|
36902
|
+
as: "c",
|
|
36903
|
+
cond: { $eq: ["$$c.type", "NFC" /* NFC */] }
|
|
36904
|
+
}
|
|
36905
|
+
},
|
|
36906
|
+
non_physical: {
|
|
36907
|
+
$filter: {
|
|
36908
|
+
input: "$f_replaced",
|
|
36909
|
+
as: "c",
|
|
36910
|
+
cond: { $eq: ["$$c.type", "QRCODE" /* QR */] }
|
|
36911
|
+
}
|
|
36912
|
+
}
|
|
36913
|
+
},
|
|
36914
|
+
deleted: {
|
|
36915
|
+
physical: {
|
|
36916
|
+
$filter: {
|
|
36917
|
+
input: "$f_deleted",
|
|
36918
|
+
as: "c",
|
|
36919
|
+
cond: { $eq: ["$$c.type", "NFC" /* NFC */] }
|
|
36920
|
+
}
|
|
36921
|
+
},
|
|
36922
|
+
non_physical: {
|
|
36923
|
+
$filter: {
|
|
36924
|
+
input: "$f_deleted",
|
|
36925
|
+
as: "c",
|
|
36926
|
+
cond: { $eq: ["$$c.type", "QRCODE" /* QR */] }
|
|
36927
|
+
}
|
|
36928
|
+
}
|
|
36929
|
+
},
|
|
36930
|
+
totalCardCount: {
|
|
36931
|
+
$add: [
|
|
36932
|
+
{
|
|
36933
|
+
$size: {
|
|
36934
|
+
$filter: {
|
|
36935
|
+
input: { $ifNull: ["$f_Available", []] },
|
|
36936
|
+
as: "c",
|
|
36937
|
+
cond: {
|
|
36938
|
+
$eq: ["$$c.type", "NFC" /* NFC */]
|
|
36939
|
+
}
|
|
36940
|
+
}
|
|
36941
|
+
}
|
|
36942
|
+
},
|
|
36943
|
+
{
|
|
36944
|
+
$size: {
|
|
36945
|
+
$filter: {
|
|
36946
|
+
input: { $ifNull: ["$f_Available", []] },
|
|
36947
|
+
as: "c",
|
|
36948
|
+
cond: {
|
|
36949
|
+
$eq: ["$$c.type", "QRCODE" /* QR */]
|
|
36950
|
+
}
|
|
36951
|
+
}
|
|
36952
|
+
}
|
|
36953
|
+
},
|
|
36954
|
+
{
|
|
36955
|
+
$size: {
|
|
36956
|
+
$filter: {
|
|
36957
|
+
input: { $ifNull: ["$f_Assigned", []] },
|
|
36958
|
+
as: "c",
|
|
36959
|
+
cond: {
|
|
36960
|
+
$eq: ["$$c.type", "NFC" /* NFC */]
|
|
36961
|
+
}
|
|
36962
|
+
}
|
|
36963
|
+
}
|
|
36964
|
+
},
|
|
36965
|
+
{
|
|
36966
|
+
$size: {
|
|
36967
|
+
$filter: {
|
|
36968
|
+
input: { $ifNull: ["$f_Assigned", []] },
|
|
36969
|
+
as: "c",
|
|
36970
|
+
cond: {
|
|
36971
|
+
$eq: ["$$c.type", "QRCODE" /* QR */]
|
|
36972
|
+
}
|
|
36973
|
+
}
|
|
36974
|
+
}
|
|
36975
|
+
}
|
|
36976
|
+
]
|
|
36657
36977
|
}
|
|
36658
|
-
},
|
|
36659
|
-
replaced: {
|
|
36660
|
-
physical: { $filter: { input: "$f_replaced", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
36661
|
-
non_physical: { $filter: { input: "$f_replaced", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
36662
|
-
},
|
|
36663
|
-
deleted: {
|
|
36664
|
-
physical: { $filter: { input: "$f_deleted", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
|
|
36665
|
-
non_physical: { $filter: { input: "$f_deleted", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
|
|
36666
|
-
},
|
|
36667
|
-
totalCardCount: {
|
|
36668
|
-
$add: [
|
|
36669
|
-
{ $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
|
|
36670
|
-
{ $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } },
|
|
36671
|
-
{ $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
|
|
36672
|
-
{ $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } }
|
|
36673
|
-
]
|
|
36674
36978
|
}
|
|
36675
|
-
}
|
|
36676
|
-
|
|
36677
|
-
|
|
36678
|
-
|
|
36979
|
+
},
|
|
36980
|
+
{ $sort: { totalCardCount: -1 } }
|
|
36981
|
+
]
|
|
36982
|
+
}
|
|
36679
36983
|
}
|
|
36680
|
-
|
|
36681
|
-
|
|
36984
|
+
],
|
|
36985
|
+
{ allowDiskUse: true }
|
|
36986
|
+
).toArray();
|
|
36682
36987
|
const totalCount = result[0]?.totalCount?.[0]?.count ?? 0;
|
|
36683
36988
|
const items = result[0]?.items ?? [];
|
|
36684
36989
|
const paginatedResult = paginate39(items, page, limit, totalCount);
|
|
@@ -36697,157 +37002,162 @@ function UseAccessManagementRepo() {
|
|
|
36697
37002
|
site: { $in: [site] }
|
|
36698
37003
|
};
|
|
36699
37004
|
const searchQuery = buildSearchQuery(search);
|
|
36700
|
-
const result = await collectionName("buildings").aggregate(
|
|
36701
|
-
|
|
36702
|
-
|
|
36703
|
-
|
|
36704
|
-
|
|
36705
|
-
|
|
36706
|
-
|
|
36707
|
-
|
|
36708
|
-
|
|
36709
|
-
|
|
36710
|
-
|
|
36711
|
-
|
|
36712
|
-
|
|
36713
|
-
|
|
36714
|
-
|
|
36715
|
-
|
|
36716
|
-
|
|
36717
|
-
|
|
36718
|
-
|
|
36719
|
-
|
|
36720
|
-
|
|
36721
|
-
|
|
36722
|
-
|
|
36723
|
-
|
|
36724
|
-
|
|
36725
|
-
|
|
36726
|
-
|
|
36727
|
-
|
|
36728
|
-
|
|
36729
|
-
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
|
|
36733
|
-
|
|
36734
|
-
|
|
36735
|
-
|
|
36736
|
-
|
|
36737
|
-
|
|
36738
|
-
|
|
36739
|
-
|
|
36740
|
-
|
|
36741
|
-
|
|
36742
|
-
|
|
36743
|
-
|
|
36744
|
-
|
|
36745
|
-
|
|
36746
|
-
|
|
36747
|
-
|
|
36748
|
-
|
|
36749
|
-
|
|
36750
|
-
|
|
36751
|
-
|
|
36752
|
-
|
|
36753
|
-
$
|
|
36754
|
-
|
|
36755
|
-
|
|
36756
|
-
|
|
36757
|
-
|
|
36758
|
-
|
|
36759
|
-
|
|
37005
|
+
const result = await collectionName("buildings").aggregate(
|
|
37006
|
+
[
|
|
37007
|
+
// ✅ Match early with index-friendly query
|
|
37008
|
+
{
|
|
37009
|
+
$match: {
|
|
37010
|
+
...query,
|
|
37011
|
+
status: { $ne: "deleted" }
|
|
37012
|
+
}
|
|
37013
|
+
},
|
|
37014
|
+
// ✅ Only project needed fields before heavy lookups
|
|
37015
|
+
{
|
|
37016
|
+
$project: {
|
|
37017
|
+
_id: 1,
|
|
37018
|
+
name: 1,
|
|
37019
|
+
site: 1
|
|
37020
|
+
}
|
|
37021
|
+
},
|
|
37022
|
+
// ✅ Use localField/foreignField for better index usage
|
|
37023
|
+
{
|
|
37024
|
+
$lookup: {
|
|
37025
|
+
from: "building-levels",
|
|
37026
|
+
localField: "_id",
|
|
37027
|
+
foreignField: "block",
|
|
37028
|
+
pipeline: [
|
|
37029
|
+
{ $match: { status: { $ne: "deleted" } } },
|
|
37030
|
+
{
|
|
37031
|
+
$lookup: {
|
|
37032
|
+
from: "building-units",
|
|
37033
|
+
localField: "_id",
|
|
37034
|
+
foreignField: "level",
|
|
37035
|
+
pipeline: [
|
|
37036
|
+
{ $match: { status: { $ne: "deleted" } } },
|
|
37037
|
+
{ $project: { _id: 1, name: 1 } },
|
|
37038
|
+
{
|
|
37039
|
+
$lookup: {
|
|
37040
|
+
from: "access-cards",
|
|
37041
|
+
localField: "_id",
|
|
37042
|
+
foreignField: "assignedUnit",
|
|
37043
|
+
pipeline: [
|
|
37044
|
+
{
|
|
37045
|
+
$match: {
|
|
37046
|
+
isActivated: true,
|
|
37047
|
+
userType,
|
|
37048
|
+
type
|
|
37049
|
+
}
|
|
37050
|
+
},
|
|
37051
|
+
{
|
|
37052
|
+
$group: {
|
|
37053
|
+
_id: null,
|
|
37054
|
+
accessLevels: { $addToSet: "$accessLevel" },
|
|
37055
|
+
liftAccessLevels: {
|
|
37056
|
+
$addToSet: "$liftAccessLevel"
|
|
37057
|
+
},
|
|
37058
|
+
doorNames: { $addToSet: "$doorName" },
|
|
37059
|
+
liftNames: { $addToSet: "$liftName" },
|
|
37060
|
+
cards: {
|
|
37061
|
+
$push: {
|
|
37062
|
+
_id: "$_id",
|
|
37063
|
+
cardNo: "$cardNo",
|
|
37064
|
+
accessLevel: "$accessLevel",
|
|
37065
|
+
liftAccessLevel: "$liftAccessLevel",
|
|
37066
|
+
doorName: "$doorName",
|
|
37067
|
+
liftName: "$liftName"
|
|
37068
|
+
}
|
|
36760
37069
|
}
|
|
36761
37070
|
}
|
|
37071
|
+
},
|
|
37072
|
+
{
|
|
37073
|
+
$project: {
|
|
37074
|
+
_id: 0,
|
|
37075
|
+
accessCardCount: {
|
|
37076
|
+
$size: "$cards"
|
|
37077
|
+
},
|
|
37078
|
+
accessLevels: 1,
|
|
37079
|
+
liftAccessLevels: 1,
|
|
37080
|
+
doorNames: 1,
|
|
37081
|
+
liftNames: 1
|
|
37082
|
+
}
|
|
36762
37083
|
}
|
|
36763
|
-
|
|
36764
|
-
|
|
36765
|
-
|
|
36766
|
-
|
|
36767
|
-
|
|
36768
|
-
|
|
36769
|
-
|
|
36770
|
-
|
|
36771
|
-
liftAccessLevels: 1,
|
|
36772
|
-
doorNames: 1,
|
|
36773
|
-
liftNames: 1
|
|
36774
|
-
}
|
|
36775
|
-
}
|
|
36776
|
-
],
|
|
36777
|
-
as: "fAccessCards"
|
|
36778
|
-
}
|
|
36779
|
-
},
|
|
36780
|
-
{
|
|
36781
|
-
$match: {
|
|
36782
|
-
"fAccessCards.0": { $exists: true }
|
|
37084
|
+
],
|
|
37085
|
+
as: "fAccessCards"
|
|
37086
|
+
}
|
|
37087
|
+
},
|
|
37088
|
+
{
|
|
37089
|
+
$match: {
|
|
37090
|
+
"fAccessCards.0": { $exists: true }
|
|
37091
|
+
}
|
|
36783
37092
|
}
|
|
36784
|
-
|
|
36785
|
-
|
|
36786
|
-
|
|
36787
|
-
}
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36792
|
-
|
|
36793
|
-
|
|
36794
|
-
|
|
36795
|
-
|
|
36796
|
-
|
|
37093
|
+
],
|
|
37094
|
+
as: "units"
|
|
37095
|
+
}
|
|
37096
|
+
},
|
|
37097
|
+
{
|
|
37098
|
+
$match: { "units.0": { $exists: true } }
|
|
37099
|
+
},
|
|
37100
|
+
{
|
|
37101
|
+
$project: {
|
|
37102
|
+
_id: 1,
|
|
37103
|
+
level: 1,
|
|
37104
|
+
units: 1
|
|
37105
|
+
}
|
|
36797
37106
|
}
|
|
36798
|
-
|
|
36799
|
-
|
|
36800
|
-
|
|
36801
|
-
}
|
|
36802
|
-
|
|
36803
|
-
|
|
36804
|
-
|
|
36805
|
-
|
|
36806
|
-
|
|
36807
|
-
|
|
36808
|
-
|
|
36809
|
-
|
|
36810
|
-
|
|
36811
|
-
|
|
36812
|
-
}
|
|
36813
|
-
|
|
36814
|
-
|
|
36815
|
-
|
|
36816
|
-
|
|
36817
|
-
|
|
36818
|
-
}
|
|
36819
|
-
|
|
36820
|
-
|
|
36821
|
-
|
|
36822
|
-
|
|
36823
|
-
|
|
36824
|
-
}
|
|
36825
|
-
|
|
36826
|
-
|
|
36827
|
-
|
|
36828
|
-
|
|
36829
|
-
|
|
36830
|
-
|
|
36831
|
-
}
|
|
36832
|
-
|
|
36833
|
-
|
|
36834
|
-
|
|
36835
|
-
|
|
36836
|
-
|
|
36837
|
-
|
|
36838
|
-
|
|
36839
|
-
|
|
36840
|
-
}
|
|
36841
|
-
|
|
36842
|
-
|
|
36843
|
-
|
|
36844
|
-
|
|
36845
|
-
|
|
36846
|
-
|
|
36847
|
-
|
|
37107
|
+
],
|
|
37108
|
+
as: "level"
|
|
37109
|
+
}
|
|
37110
|
+
},
|
|
37111
|
+
// ✅ Filter out buildings with no levels early
|
|
37112
|
+
{
|
|
37113
|
+
$match: { "level.0": { $exists: true } }
|
|
37114
|
+
},
|
|
37115
|
+
// ✅ Unwind to flatten the hierarchy
|
|
37116
|
+
{
|
|
37117
|
+
$unwind: {
|
|
37118
|
+
path: "$level",
|
|
37119
|
+
preserveNullAndEmptyArrays: false
|
|
37120
|
+
}
|
|
37121
|
+
},
|
|
37122
|
+
{
|
|
37123
|
+
$unwind: {
|
|
37124
|
+
path: "$level.units",
|
|
37125
|
+
preserveNullAndEmptyArrays: false
|
|
37126
|
+
}
|
|
37127
|
+
},
|
|
37128
|
+
{
|
|
37129
|
+
$unwind: {
|
|
37130
|
+
path: "$level.units.fAccessCards",
|
|
37131
|
+
preserveNullAndEmptyArrays: false
|
|
37132
|
+
}
|
|
37133
|
+
},
|
|
37134
|
+
// // Groups by unit _id and keeps only the first occurrence
|
|
37135
|
+
{
|
|
37136
|
+
$group: {
|
|
37137
|
+
_id: "$level.units._id",
|
|
37138
|
+
doc: { $first: "$$ROOT" }
|
|
37139
|
+
}
|
|
37140
|
+
},
|
|
37141
|
+
{
|
|
37142
|
+
$replaceRoot: { newRoot: "$doc" }
|
|
37143
|
+
},
|
|
37144
|
+
// ✅ Apply search filter
|
|
37145
|
+
{
|
|
37146
|
+
$match: {
|
|
37147
|
+
...searchQuery
|
|
37148
|
+
}
|
|
37149
|
+
},
|
|
37150
|
+
{
|
|
37151
|
+
$project: {
|
|
37152
|
+
name: 1,
|
|
37153
|
+
"level.level": 1,
|
|
37154
|
+
"level.units.name": 1,
|
|
37155
|
+
"level.units.fAccessCards": 1
|
|
37156
|
+
}
|
|
36848
37157
|
}
|
|
36849
|
-
|
|
36850
|
-
|
|
37158
|
+
],
|
|
37159
|
+
{ allowDiskUse: true }
|
|
37160
|
+
).toArray();
|
|
36851
37161
|
return result;
|
|
36852
37162
|
} catch (error) {
|
|
36853
37163
|
throw new Error(error.message);
|
|
@@ -36858,8 +37168,12 @@ function UseAccessManagementRepo() {
|
|
|
36858
37168
|
try {
|
|
36859
37169
|
session?.startTransaction();
|
|
36860
37170
|
const { userId, cardId, site } = params;
|
|
36861
|
-
const allUserId = await Promise.all(
|
|
36862
|
-
|
|
37171
|
+
const allUserId = await Promise.all(
|
|
37172
|
+
userId.map(async (id) => new ObjectId90(id))
|
|
37173
|
+
);
|
|
37174
|
+
const allCardId = await Promise.all(
|
|
37175
|
+
cardId.map(async (id) => new ObjectId90(id))
|
|
37176
|
+
);
|
|
36863
37177
|
const siteId = new ObjectId90(site);
|
|
36864
37178
|
const result = await collection().updateMany(
|
|
36865
37179
|
{
|
|
@@ -36902,16 +37216,19 @@ function UseAccessManagementRepo() {
|
|
|
36902
37216
|
liftAccessLevel,
|
|
36903
37217
|
isActivated: true
|
|
36904
37218
|
};
|
|
36905
|
-
const result = await collection().aggregate(
|
|
36906
|
-
|
|
36907
|
-
|
|
36908
|
-
|
|
36909
|
-
|
|
36910
|
-
|
|
36911
|
-
|
|
37219
|
+
const result = await collection().aggregate(
|
|
37220
|
+
[
|
|
37221
|
+
{
|
|
37222
|
+
$match: query
|
|
37223
|
+
},
|
|
37224
|
+
{
|
|
37225
|
+
$facet: {
|
|
37226
|
+
counts: [{ $count: "count" }]
|
|
37227
|
+
}
|
|
36912
37228
|
}
|
|
36913
|
-
|
|
36914
|
-
|
|
37229
|
+
],
|
|
37230
|
+
{ allowDiskUse: true }
|
|
37231
|
+
).toArray();
|
|
36915
37232
|
return result;
|
|
36916
37233
|
} catch (error) {
|
|
36917
37234
|
throw new Error(error.message);
|
|
@@ -36945,7 +37262,9 @@ function UseAccessManagementRepo() {
|
|
|
36945
37262
|
availableCardNo.push(num);
|
|
36946
37263
|
num++;
|
|
36947
37264
|
}
|
|
36948
|
-
const cardNumbers = availableCardNo.map(
|
|
37265
|
+
const cardNumbers = availableCardNo.map(
|
|
37266
|
+
(no) => no.toString().padStart(10, "0")
|
|
37267
|
+
);
|
|
36949
37268
|
const accessCards = [];
|
|
36950
37269
|
const convertedUnits = unit.map((obj) => new ObjectId90(obj));
|
|
36951
37270
|
for (let j = 0; j < (unit.length > 0 ? unit.length : quantity); j++) {
|
|
@@ -37005,10 +37324,18 @@ function UseAccessManagementRepo() {
|
|
|
37005
37324
|
liftAccessEndDate: formatEntryPassDate(item.liftAccessEndDate) || "19770510",
|
|
37006
37325
|
accessGroup: ag
|
|
37007
37326
|
};
|
|
37008
|
-
return readTemplate(
|
|
37327
|
+
return readTemplate(
|
|
37328
|
+
`${item.accessLevel !== null ? "add-card" : "add-card-lift"}`,
|
|
37329
|
+
{ ...command }
|
|
37330
|
+
);
|
|
37009
37331
|
}).flat();
|
|
37010
|
-
const response = await sendCommand(
|
|
37011
|
-
|
|
37332
|
+
const response = await sendCommand(
|
|
37333
|
+
commands.join("").toString(),
|
|
37334
|
+
params.acm_url
|
|
37335
|
+
);
|
|
37336
|
+
const result = await parseStringPromise2(response, {
|
|
37337
|
+
explicitArray: false
|
|
37338
|
+
});
|
|
37012
37339
|
if (result && result.RESULT.$.STCODE !== "0") {
|
|
37013
37340
|
throw new Error("Command failed, server error.");
|
|
37014
37341
|
}
|
|
@@ -37042,7 +37369,11 @@ function UseAccessManagementRepo() {
|
|
|
37042
37369
|
} else {
|
|
37043
37370
|
updateFields.isActivated = true;
|
|
37044
37371
|
}
|
|
37045
|
-
const res = await collection().updateOne(
|
|
37372
|
+
const res = await collection().updateOne(
|
|
37373
|
+
{ _id: card._id },
|
|
37374
|
+
{ $set: updateFields },
|
|
37375
|
+
{ session }
|
|
37376
|
+
);
|
|
37046
37377
|
results.push({ nfcId: nfc._id, modifiedCount: res.modifiedCount });
|
|
37047
37378
|
}
|
|
37048
37379
|
}
|
|
@@ -37069,8 +37400,20 @@ function UseAccessManagementRepo() {
|
|
|
37069
37400
|
assignedUnit: null,
|
|
37070
37401
|
userId: null,
|
|
37071
37402
|
$or: [
|
|
37072
|
-
{
|
|
37073
|
-
|
|
37403
|
+
{
|
|
37404
|
+
$and: [
|
|
37405
|
+
{ doorName: { $ne: null } },
|
|
37406
|
+
{ doorName: { $ne: "" } },
|
|
37407
|
+
{ accessLevel: { $ne: null } }
|
|
37408
|
+
]
|
|
37409
|
+
},
|
|
37410
|
+
{
|
|
37411
|
+
$and: [
|
|
37412
|
+
{ liftName: { $ne: null } },
|
|
37413
|
+
{ liftName: { $ne: "" } },
|
|
37414
|
+
{ liftAccessLevel: { $ne: null } }
|
|
37415
|
+
]
|
|
37416
|
+
}
|
|
37074
37417
|
]
|
|
37075
37418
|
}
|
|
37076
37419
|
},
|
|
@@ -37084,7 +37427,13 @@ function UseAccessManagementRepo() {
|
|
|
37084
37427
|
accessLevels: {
|
|
37085
37428
|
$addToSet: {
|
|
37086
37429
|
$cond: [
|
|
37087
|
-
{
|
|
37430
|
+
{
|
|
37431
|
+
$and: [
|
|
37432
|
+
{ $ne: ["$doorName", null] },
|
|
37433
|
+
{ $ne: ["$doorName", ""] },
|
|
37434
|
+
{ $ne: ["$accessLevel", null] }
|
|
37435
|
+
]
|
|
37436
|
+
},
|
|
37088
37437
|
{ name: "$doorName", no: "$accessLevel" },
|
|
37089
37438
|
"$$REMOVE"
|
|
37090
37439
|
]
|
|
@@ -37093,7 +37442,13 @@ function UseAccessManagementRepo() {
|
|
|
37093
37442
|
liftAccessLevels: {
|
|
37094
37443
|
$addToSet: {
|
|
37095
37444
|
$cond: [
|
|
37096
|
-
{
|
|
37445
|
+
{
|
|
37446
|
+
$and: [
|
|
37447
|
+
{ $ne: ["$liftName", null] },
|
|
37448
|
+
{ $ne: ["$liftName", ""] },
|
|
37449
|
+
{ $ne: ["$liftAccessLevel", null] }
|
|
37450
|
+
]
|
|
37451
|
+
},
|
|
37097
37452
|
{ name: "$liftName", no: "$liftAccessLevel" },
|
|
37098
37453
|
"$$REMOVE"
|
|
37099
37454
|
]
|
|
@@ -37129,7 +37484,14 @@ function UseAccessManagementRepo() {
|
|
|
37129
37484
|
const sessionResult = await Promise.all([
|
|
37130
37485
|
await collection().findOneAndUpdate(
|
|
37131
37486
|
{ _id: id },
|
|
37132
|
-
{
|
|
37487
|
+
{
|
|
37488
|
+
$set: {
|
|
37489
|
+
remarks,
|
|
37490
|
+
replacementStatus: "Complete",
|
|
37491
|
+
requestDate: /* @__PURE__ */ new Date(),
|
|
37492
|
+
isActivated: false
|
|
37493
|
+
}
|
|
37494
|
+
},
|
|
37133
37495
|
{ returnDocument: "after", session }
|
|
37134
37496
|
),
|
|
37135
37497
|
await collection().findOneAndUpdate(
|
|
@@ -37161,7 +37523,10 @@ function UseAccessManagementRepo() {
|
|
|
37161
37523
|
isActivated: true
|
|
37162
37524
|
};
|
|
37163
37525
|
if (search) {
|
|
37164
|
-
query.$or = [
|
|
37526
|
+
query.$or = [
|
|
37527
|
+
{ accessLevel: { $regex: search, $options: "i" } },
|
|
37528
|
+
{ cardNo: { $regex: search, $options: "i" } }
|
|
37529
|
+
];
|
|
37165
37530
|
}
|
|
37166
37531
|
if (type) {
|
|
37167
37532
|
query.userType = type;
|
|
@@ -37186,14 +37551,22 @@ function UseAccessManagementRepo() {
|
|
|
37186
37551
|
{
|
|
37187
37552
|
$addFields: {
|
|
37188
37553
|
extractedCardNo: {
|
|
37189
|
-
$substr: [
|
|
37554
|
+
$substr: [
|
|
37555
|
+
"$cardNo",
|
|
37556
|
+
{ $subtract: [{ $strLenCP: "$cardNo" }, 5] },
|
|
37557
|
+
5
|
|
37558
|
+
]
|
|
37190
37559
|
}
|
|
37191
37560
|
}
|
|
37192
37561
|
},
|
|
37193
37562
|
{
|
|
37194
37563
|
$facet: {
|
|
37195
37564
|
totalCount: [{ $count: "count" }],
|
|
37196
|
-
items: [
|
|
37565
|
+
items: [
|
|
37566
|
+
{ $sort: { _id: -1 } },
|
|
37567
|
+
{ $skip: page * limit },
|
|
37568
|
+
{ $limit: limit }
|
|
37569
|
+
]
|
|
37197
37570
|
}
|
|
37198
37571
|
}
|
|
37199
37572
|
]).toArray();
|
|
@@ -37224,145 +37597,151 @@ function UseAccessManagementRepo() {
|
|
|
37224
37597
|
query.replacementStatus = statusFilter;
|
|
37225
37598
|
}
|
|
37226
37599
|
if (dateFrom && dateTo) {
|
|
37227
|
-
query.requestDate = {
|
|
37600
|
+
query.requestDate = {
|
|
37601
|
+
$gte: new Date(dateFrom),
|
|
37602
|
+
$lte: new Date(dateTo)
|
|
37603
|
+
};
|
|
37228
37604
|
} else if (dateFrom) {
|
|
37229
37605
|
query.requestDate = { $gte: new Date(dateFrom) };
|
|
37230
37606
|
} else if (dateTo) {
|
|
37231
37607
|
query.requestDate = { $lte: new Date(dateTo) };
|
|
37232
37608
|
}
|
|
37233
|
-
const res = await collection().aggregate(
|
|
37234
|
-
|
|
37235
|
-
|
|
37236
|
-
|
|
37237
|
-
|
|
37238
|
-
|
|
37239
|
-
|
|
37240
|
-
|
|
37241
|
-
|
|
37242
|
-
|
|
37243
|
-
|
|
37244
|
-
$
|
|
37245
|
-
$
|
|
37609
|
+
const res = await collection().aggregate(
|
|
37610
|
+
[
|
|
37611
|
+
{
|
|
37612
|
+
$match: { ...query }
|
|
37613
|
+
},
|
|
37614
|
+
{
|
|
37615
|
+
$lookup: {
|
|
37616
|
+
from: "building-units",
|
|
37617
|
+
let: { unit: "$assignedUnit" },
|
|
37618
|
+
pipeline: [
|
|
37619
|
+
{
|
|
37620
|
+
$match: {
|
|
37621
|
+
$expr: {
|
|
37622
|
+
$eq: ["$_id", "$$unit"]
|
|
37623
|
+
}
|
|
37246
37624
|
}
|
|
37247
|
-
}
|
|
37248
|
-
|
|
37249
|
-
|
|
37250
|
-
|
|
37251
|
-
|
|
37252
|
-
|
|
37253
|
-
level: 1
|
|
37254
|
-
}
|
|
37255
|
-
}
|
|
37256
|
-
],
|
|
37257
|
-
as: "unit"
|
|
37258
|
-
}
|
|
37259
|
-
},
|
|
37260
|
-
{
|
|
37261
|
-
$unwind: { path: "$unit", preserveNullAndEmptyArrays: true }
|
|
37262
|
-
},
|
|
37263
|
-
{
|
|
37264
|
-
$lookup: {
|
|
37265
|
-
from: "building-levels",
|
|
37266
|
-
let: { level: "$unit.level" },
|
|
37267
|
-
pipeline: [
|
|
37268
|
-
{
|
|
37269
|
-
$match: {
|
|
37270
|
-
$expr: {
|
|
37271
|
-
$eq: ["$_id", "$$level"]
|
|
37625
|
+
},
|
|
37626
|
+
{
|
|
37627
|
+
$project: {
|
|
37628
|
+
_id: 1,
|
|
37629
|
+
name: 1,
|
|
37630
|
+
level: 1
|
|
37272
37631
|
}
|
|
37273
37632
|
}
|
|
37274
|
-
|
|
37275
|
-
|
|
37276
|
-
|
|
37277
|
-
|
|
37278
|
-
|
|
37279
|
-
|
|
37280
|
-
|
|
37281
|
-
|
|
37282
|
-
|
|
37283
|
-
|
|
37284
|
-
|
|
37285
|
-
|
|
37286
|
-
|
|
37287
|
-
|
|
37288
|
-
|
|
37289
|
-
|
|
37290
|
-
|
|
37291
|
-
|
|
37292
|
-
|
|
37293
|
-
|
|
37294
|
-
|
|
37295
|
-
|
|
37296
|
-
|
|
37297
|
-
|
|
37633
|
+
],
|
|
37634
|
+
as: "unit"
|
|
37635
|
+
}
|
|
37636
|
+
},
|
|
37637
|
+
{
|
|
37638
|
+
$unwind: { path: "$unit", preserveNullAndEmptyArrays: true }
|
|
37639
|
+
},
|
|
37640
|
+
{
|
|
37641
|
+
$lookup: {
|
|
37642
|
+
from: "building-levels",
|
|
37643
|
+
let: { level: "$unit.level" },
|
|
37644
|
+
pipeline: [
|
|
37645
|
+
{
|
|
37646
|
+
$match: {
|
|
37647
|
+
$expr: {
|
|
37648
|
+
$eq: ["$_id", "$$level"]
|
|
37649
|
+
}
|
|
37650
|
+
}
|
|
37651
|
+
},
|
|
37652
|
+
{
|
|
37653
|
+
$project: {
|
|
37654
|
+
_id: 1,
|
|
37655
|
+
level: 1,
|
|
37656
|
+
block: 1
|
|
37298
37657
|
}
|
|
37299
37658
|
}
|
|
37300
|
-
|
|
37301
|
-
|
|
37302
|
-
|
|
37303
|
-
|
|
37304
|
-
|
|
37305
|
-
|
|
37306
|
-
|
|
37307
|
-
|
|
37308
|
-
|
|
37309
|
-
|
|
37310
|
-
|
|
37311
|
-
|
|
37312
|
-
|
|
37313
|
-
|
|
37314
|
-
|
|
37315
|
-
|
|
37316
|
-
|
|
37317
|
-
|
|
37318
|
-
|
|
37319
|
-
|
|
37320
|
-
|
|
37321
|
-
|
|
37322
|
-
|
|
37659
|
+
],
|
|
37660
|
+
as: "level"
|
|
37661
|
+
}
|
|
37662
|
+
},
|
|
37663
|
+
{
|
|
37664
|
+
$unwind: { path: "$level", preserveNullAndEmptyArrays: true }
|
|
37665
|
+
},
|
|
37666
|
+
{
|
|
37667
|
+
$lookup: {
|
|
37668
|
+
from: "buildings",
|
|
37669
|
+
let: { block: "$level.block" },
|
|
37670
|
+
pipeline: [
|
|
37671
|
+
{
|
|
37672
|
+
$match: {
|
|
37673
|
+
$expr: {
|
|
37674
|
+
$eq: ["$_id", "$$block"]
|
|
37675
|
+
}
|
|
37676
|
+
}
|
|
37677
|
+
},
|
|
37678
|
+
{
|
|
37679
|
+
$project: {
|
|
37680
|
+
_id: 1,
|
|
37681
|
+
name: 1
|
|
37323
37682
|
}
|
|
37324
37683
|
}
|
|
37325
|
-
|
|
37326
|
-
|
|
37327
|
-
|
|
37328
|
-
|
|
37329
|
-
|
|
37684
|
+
],
|
|
37685
|
+
as: "building"
|
|
37686
|
+
}
|
|
37687
|
+
},
|
|
37688
|
+
{
|
|
37689
|
+
$unwind: { path: "$building", preserveNullAndEmptyArrays: true }
|
|
37690
|
+
},
|
|
37691
|
+
{
|
|
37692
|
+
$lookup: {
|
|
37693
|
+
from: "users",
|
|
37694
|
+
let: { id: "$userId" },
|
|
37695
|
+
pipeline: [
|
|
37696
|
+
{
|
|
37697
|
+
$match: {
|
|
37698
|
+
$expr: {
|
|
37699
|
+
$eq: ["$_id", "$$id"]
|
|
37700
|
+
}
|
|
37701
|
+
}
|
|
37702
|
+
},
|
|
37703
|
+
{
|
|
37704
|
+
$project: {
|
|
37705
|
+
givenName: 1,
|
|
37706
|
+
surname: 1
|
|
37707
|
+
}
|
|
37330
37708
|
}
|
|
37331
|
-
|
|
37332
|
-
|
|
37333
|
-
|
|
37334
|
-
}
|
|
37335
|
-
|
|
37336
|
-
|
|
37337
|
-
|
|
37338
|
-
|
|
37339
|
-
|
|
37340
|
-
|
|
37341
|
-
|
|
37342
|
-
|
|
37343
|
-
|
|
37344
|
-
|
|
37345
|
-
|
|
37346
|
-
|
|
37347
|
-
|
|
37348
|
-
|
|
37349
|
-
|
|
37350
|
-
|
|
37351
|
-
|
|
37352
|
-
|
|
37353
|
-
|
|
37354
|
-
|
|
37355
|
-
|
|
37356
|
-
|
|
37357
|
-
|
|
37358
|
-
|
|
37709
|
+
],
|
|
37710
|
+
as: "user"
|
|
37711
|
+
}
|
|
37712
|
+
},
|
|
37713
|
+
{
|
|
37714
|
+
$unwind: { path: "$user", preserveNullAndEmptyArrays: true }
|
|
37715
|
+
},
|
|
37716
|
+
{
|
|
37717
|
+
$match: { ...searchQuery }
|
|
37718
|
+
},
|
|
37719
|
+
{
|
|
37720
|
+
$facet: {
|
|
37721
|
+
data: [
|
|
37722
|
+
{ $skip: page * limit },
|
|
37723
|
+
{ $limit: limit },
|
|
37724
|
+
{
|
|
37725
|
+
$project: {
|
|
37726
|
+
_id: 1,
|
|
37727
|
+
cardNo: 1,
|
|
37728
|
+
accessLevel: 1,
|
|
37729
|
+
liftAccessLevel: 1,
|
|
37730
|
+
replacementStatus: 1,
|
|
37731
|
+
remarks: 1,
|
|
37732
|
+
block: "$building.name",
|
|
37733
|
+
level: "$level.level",
|
|
37734
|
+
unit: "$unit.name",
|
|
37735
|
+
user: "$user"
|
|
37736
|
+
}
|
|
37359
37737
|
}
|
|
37360
|
-
|
|
37361
|
-
|
|
37362
|
-
|
|
37738
|
+
],
|
|
37739
|
+
totalCount: [{ $count: "count" }]
|
|
37740
|
+
}
|
|
37363
37741
|
}
|
|
37364
|
-
|
|
37365
|
-
|
|
37742
|
+
],
|
|
37743
|
+
{ allowDiskUse: true }
|
|
37744
|
+
).toArray();
|
|
37366
37745
|
const count = res[0]?.totalCount[0] ? res[0].totalCount[0].count : 0;
|
|
37367
37746
|
const pagination = paginate39(res[0].data, page, limit, count);
|
|
37368
37747
|
return pagination;
|
|
@@ -37374,7 +37753,10 @@ function UseAccessManagementRepo() {
|
|
|
37374
37753
|
try {
|
|
37375
37754
|
const { site } = params;
|
|
37376
37755
|
const siteId = new ObjectId90(site);
|
|
37377
|
-
const res = await collectionName("entrypass-settings").findOne(
|
|
37756
|
+
const res = await collectionName("entrypass-settings").findOne(
|
|
37757
|
+
{ site: siteId },
|
|
37758
|
+
{ allowDiskUse: true }
|
|
37759
|
+
);
|
|
37378
37760
|
return res;
|
|
37379
37761
|
} catch (error) {
|
|
37380
37762
|
throw new Error(error.message);
|
|
@@ -37384,13 +37766,19 @@ function UseAccessManagementRepo() {
|
|
|
37384
37766
|
const session = useAtlas76.getClient()?.startSession();
|
|
37385
37767
|
try {
|
|
37386
37768
|
const { dataJson, site } = params;
|
|
37387
|
-
const rawItems = JSON.parse(dataJson).filter(
|
|
37769
|
+
const rawItems = JSON.parse(dataJson).filter(
|
|
37770
|
+
(_, index) => index !== -1
|
|
37771
|
+
);
|
|
37388
37772
|
const items = await Promise.all(
|
|
37389
37773
|
rawItems.map(async (item) => {
|
|
37390
37774
|
const date = new Date(item["startDate (format MM/DD/YYYY)"]);
|
|
37391
37775
|
const endDate = new Date(date.setFullYear(date.getFullYear() + 10));
|
|
37392
|
-
const cardNumber = String(
|
|
37393
|
-
|
|
37776
|
+
const cardNumber = String(
|
|
37777
|
+
Number(item["cardNo (number 0-65535 ex. 301)"] || 0)
|
|
37778
|
+
).padStart(6, "0");
|
|
37779
|
+
const facilityCode = String(
|
|
37780
|
+
Number(item["facilityCode (number 0-255 ex. 11)"] || 0)
|
|
37781
|
+
).padStart(4, "0");
|
|
37394
37782
|
const pin = item["pin (number 6 digits only)"] ? item["pin (number 6 digits only)"].toString().padStart(6, "0") : "123456";
|
|
37395
37783
|
const match = item["accessLevel (number ex. 1)"];
|
|
37396
37784
|
const accessLevel = match ? match : null;
|
|
@@ -37421,7 +37809,10 @@ function UseAccessManagementRepo() {
|
|
|
37421
37809
|
});
|
|
37422
37810
|
})
|
|
37423
37811
|
);
|
|
37424
|
-
const result = await collection().insertMany(items, {
|
|
37812
|
+
const result = await collection().insertMany(items, {
|
|
37813
|
+
session,
|
|
37814
|
+
ordered: false
|
|
37815
|
+
});
|
|
37425
37816
|
const mapping = items.map((item, i) => ({
|
|
37426
37817
|
cardNo: item.cardNo,
|
|
37427
37818
|
insertedId: result.insertedIds[i]
|
|
@@ -37436,8 +37827,19 @@ function UseAccessManagementRepo() {
|
|
|
37436
37827
|
let isAborted = false;
|
|
37437
37828
|
try {
|
|
37438
37829
|
await session?.startTransaction();
|
|
37439
|
-
const {
|
|
37440
|
-
|
|
37830
|
+
const {
|
|
37831
|
+
units,
|
|
37832
|
+
quantity,
|
|
37833
|
+
type,
|
|
37834
|
+
site,
|
|
37835
|
+
userType,
|
|
37836
|
+
accessLevel,
|
|
37837
|
+
liftAccessLevel
|
|
37838
|
+
} = params;
|
|
37839
|
+
const [convertedUnits, convertedSite] = await Promise.all([
|
|
37840
|
+
Promise.all(units.map((id) => new ObjectId90(id))),
|
|
37841
|
+
new ObjectId90(site)
|
|
37842
|
+
]);
|
|
37441
37843
|
const totalRequired = quantity * convertedUnits.length;
|
|
37442
37844
|
const availableCards = await collection().find({
|
|
37443
37845
|
assignedUnit: null,
|
|
@@ -37457,16 +37859,18 @@ function UseAccessManagementRepo() {
|
|
|
37457
37859
|
message: `Insufficient ${type} access cards. Need ${totalRequired}, but only ${availableCards.length} available.`
|
|
37458
37860
|
};
|
|
37459
37861
|
}
|
|
37460
|
-
const bulkUpdates = availableCards.map(
|
|
37461
|
-
|
|
37462
|
-
|
|
37463
|
-
|
|
37464
|
-
|
|
37465
|
-
|
|
37862
|
+
const bulkUpdates = availableCards.map(
|
|
37863
|
+
(card, index) => ({
|
|
37864
|
+
updateOne: {
|
|
37865
|
+
filter: { _id: card._id },
|
|
37866
|
+
update: {
|
|
37867
|
+
$set: {
|
|
37868
|
+
assignedUnit: convertedUnits[Math.floor(index / quantity)]
|
|
37869
|
+
}
|
|
37466
37870
|
}
|
|
37467
37871
|
}
|
|
37468
|
-
}
|
|
37469
|
-
|
|
37872
|
+
})
|
|
37873
|
+
);
|
|
37470
37874
|
await collection().bulkWrite(bulkUpdates, { session });
|
|
37471
37875
|
await session?.commitTransaction();
|
|
37472
37876
|
return {
|
|
@@ -37487,7 +37891,18 @@ function UseAccessManagementRepo() {
|
|
|
37487
37891
|
try {
|
|
37488
37892
|
const { cardId, remarks } = params;
|
|
37489
37893
|
const id = new ObjectId90(cardId);
|
|
37490
|
-
const result = await collection().findOneAndUpdate(
|
|
37894
|
+
const result = await collection().findOneAndUpdate(
|
|
37895
|
+
{ _id: id },
|
|
37896
|
+
{
|
|
37897
|
+
$set: {
|
|
37898
|
+
isActivated: false,
|
|
37899
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
37900
|
+
remarks,
|
|
37901
|
+
requestDate: /* @__PURE__ */ new Date()
|
|
37902
|
+
}
|
|
37903
|
+
},
|
|
37904
|
+
{ returnDocument: "after" }
|
|
37905
|
+
);
|
|
37491
37906
|
return result;
|
|
37492
37907
|
} catch (error) {
|
|
37493
37908
|
throw new Error(error.message);
|
|
@@ -37548,7 +37963,13 @@ function UseAccessManagementRepo() {
|
|
|
37548
37963
|
const { site, payload } = params;
|
|
37549
37964
|
const id = new ObjectId90(site);
|
|
37550
37965
|
const highestCardNo = await collection().aggregate([
|
|
37551
|
-
{
|
|
37966
|
+
{
|
|
37967
|
+
$match: {
|
|
37968
|
+
site: id,
|
|
37969
|
+
type: "NFC" /* NFC */,
|
|
37970
|
+
userType: "Visitor/Resident" /* DEFAULT */
|
|
37971
|
+
}
|
|
37972
|
+
},
|
|
37552
37973
|
{
|
|
37553
37974
|
$addFields: {
|
|
37554
37975
|
qrTagCardNoNumeric: { $toInt: "$qrTagCardNo" }
|
|
@@ -37568,14 +37989,19 @@ function UseAccessManagementRepo() {
|
|
|
37568
37989
|
if (highestCardNo.length > 0) {
|
|
37569
37990
|
start = highestCardNo[0].qrTagCardNoNumeric || 0;
|
|
37570
37991
|
}
|
|
37571
|
-
const nextCardNumbers = Array.from(
|
|
37992
|
+
const nextCardNumbers = Array.from(
|
|
37993
|
+
{ length: payload.length },
|
|
37994
|
+
(_, i) => String(start + i + 1).padStart(5, "0")
|
|
37995
|
+
);
|
|
37572
37996
|
const bulkOps = await Promise.all(
|
|
37573
37997
|
payload.map(async (doc, index) => {
|
|
37574
37998
|
const id2 = new ObjectId90(doc._id);
|
|
37575
37999
|
return {
|
|
37576
38000
|
updateOne: {
|
|
37577
38001
|
filter: { _id: id2 },
|
|
37578
|
-
update: {
|
|
38002
|
+
update: {
|
|
38003
|
+
$set: { qrTag: doc.qrTag, qrTagCardNo: nextCardNumbers[index] }
|
|
38004
|
+
}
|
|
37579
38005
|
}
|
|
37580
38006
|
};
|
|
37581
38007
|
})
|
|
@@ -37617,7 +38043,11 @@ function UseAccessManagementRepo() {
|
|
|
37617
38043
|
{
|
|
37618
38044
|
$addFields: {
|
|
37619
38045
|
extractedCardNo: {
|
|
37620
|
-
$substr: [
|
|
38046
|
+
$substr: [
|
|
38047
|
+
"$cardNo",
|
|
38048
|
+
{ $subtract: [{ $strLenCP: "$cardNo" }, 5] },
|
|
38049
|
+
5
|
|
38050
|
+
]
|
|
37621
38051
|
}
|
|
37622
38052
|
}
|
|
37623
38053
|
},
|
|
@@ -37655,7 +38085,11 @@ function UseAccessManagementRepo() {
|
|
|
37655
38085
|
},
|
|
37656
38086
|
{
|
|
37657
38087
|
$facet: {
|
|
37658
|
-
items: [
|
|
38088
|
+
items: [
|
|
38089
|
+
{ $skip: page * limit },
|
|
38090
|
+
{ $limit: limit },
|
|
38091
|
+
{ $project: { cardNo: 1 } }
|
|
38092
|
+
],
|
|
37659
38093
|
totalCounts: [{ $count: "count" }]
|
|
37660
38094
|
}
|
|
37661
38095
|
}
|
|
@@ -37666,7 +38100,9 @@ function UseAccessManagementRepo() {
|
|
|
37666
38100
|
_id: unitId
|
|
37667
38101
|
}
|
|
37668
38102
|
},
|
|
37669
|
-
{
|
|
38103
|
+
{
|
|
38104
|
+
$project: { _id: 1, name: 1, buildingName: 1, block: 1, level: 1 }
|
|
38105
|
+
},
|
|
37670
38106
|
{
|
|
37671
38107
|
$lookup: {
|
|
37672
38108
|
from: "building-levels",
|
|
@@ -37754,7 +38190,18 @@ function UseAccessManagementRepo() {
|
|
|
37754
38190
|
items: [
|
|
37755
38191
|
{ $skip: 0 },
|
|
37756
38192
|
{ $limit: 1 },
|
|
37757
|
-
{
|
|
38193
|
+
{
|
|
38194
|
+
$project: {
|
|
38195
|
+
_id: -1,
|
|
38196
|
+
accessLevel: 1,
|
|
38197
|
+
accessGroup: 1,
|
|
38198
|
+
userType: 1,
|
|
38199
|
+
doorName: 1,
|
|
38200
|
+
liftName: 1,
|
|
38201
|
+
liftAccessLevel: 1,
|
|
38202
|
+
isLiftCard: 1
|
|
38203
|
+
}
|
|
38204
|
+
}
|
|
37758
38205
|
]
|
|
37759
38206
|
}
|
|
37760
38207
|
}
|
|
@@ -37803,13 +38250,25 @@ function UseAccessManagementRepo() {
|
|
|
37803
38250
|
cardsToAttach = [...cardsId];
|
|
37804
38251
|
} else if (type === "NFC" /* NFC */) {
|
|
37805
38252
|
if (nfcCards && nfcCards.length > 0) {
|
|
37806
|
-
const objectIds = nfcCards.map(
|
|
38253
|
+
const objectIds = nfcCards.map(
|
|
38254
|
+
(card) => new ObjectId90(card._id)
|
|
38255
|
+
);
|
|
37807
38256
|
cards = await collection().find({ _id: { $in: objectIds } }).toArray();
|
|
37808
|
-
const nfcList = objectIds.map((card) => ({
|
|
38257
|
+
const nfcList = objectIds.map((card) => ({
|
|
38258
|
+
_id: card,
|
|
38259
|
+
status: "In use",
|
|
38260
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
38261
|
+
}));
|
|
37809
38262
|
cardsToAttach = [...nfcList];
|
|
37810
38263
|
}
|
|
37811
38264
|
}
|
|
37812
|
-
const result = await collectionName(
|
|
38265
|
+
const result = await collectionName(
|
|
38266
|
+
"visitor.transactions"
|
|
38267
|
+
).findOneAndUpdate(
|
|
38268
|
+
{ _id: visitorId },
|
|
38269
|
+
{ $push: { cards: cardsToAttach } },
|
|
38270
|
+
{ session, returnDocument: "after" }
|
|
38271
|
+
);
|
|
37813
38272
|
const updatedVisitor = result?._id;
|
|
37814
38273
|
const assignCards = cards.map((card) => card._id);
|
|
37815
38274
|
if (assignCards.length > 0) {
|
|
@@ -37865,10 +38324,18 @@ function UseAccessManagementRepo() {
|
|
|
37865
38324
|
liftAccessEndDate: formatEntryPassDate(item.liftAccessEndDate) || "19770510",
|
|
37866
38325
|
accessGroup: ag
|
|
37867
38326
|
};
|
|
37868
|
-
return readTemplate(
|
|
38327
|
+
return readTemplate(
|
|
38328
|
+
`${item.accessLevel !== null ? "add-card" : "add-card-lift"}`,
|
|
38329
|
+
{ ...command }
|
|
38330
|
+
);
|
|
37869
38331
|
}).flat();
|
|
37870
|
-
const response = await sendCommand(
|
|
37871
|
-
|
|
38332
|
+
const response = await sendCommand(
|
|
38333
|
+
commands.join("").toString(),
|
|
38334
|
+
acm_url
|
|
38335
|
+
);
|
|
38336
|
+
serverResult = await parseStringPromise2(response, {
|
|
38337
|
+
explicitArray: false
|
|
38338
|
+
});
|
|
37872
38339
|
if (result && serverResult.RESULT.$.STCODE !== "0") {
|
|
37873
38340
|
throw new Error("Command failed, server error.");
|
|
37874
38341
|
}
|
|
@@ -37917,7 +38384,10 @@ function UseAccessManagementRepo() {
|
|
|
37917
38384
|
try {
|
|
37918
38385
|
await session?.startTransaction();
|
|
37919
38386
|
const userId = new ObjectId90(params.userId);
|
|
37920
|
-
const result = await collection().updateMany(
|
|
38387
|
+
const result = await collection().updateMany(
|
|
38388
|
+
{ userId },
|
|
38389
|
+
{ $set: { userId: null, status: "Available", updatedAt: /* @__PURE__ */ new Date() } }
|
|
38390
|
+
);
|
|
37921
38391
|
await session?.commitTransaction();
|
|
37922
38392
|
return result;
|
|
37923
38393
|
} catch (error) {
|
|
@@ -37961,7 +38431,15 @@ function UseAccessManagementRepo() {
|
|
|
37961
38431
|
foreignField: "level",
|
|
37962
38432
|
pipeline: [
|
|
37963
38433
|
{ $match: { status: { $ne: "deleted" } } },
|
|
37964
|
-
{
|
|
38434
|
+
{
|
|
38435
|
+
$project: {
|
|
38436
|
+
_id: 1,
|
|
38437
|
+
name: 1,
|
|
38438
|
+
buildingName: 1,
|
|
38439
|
+
level: 1,
|
|
38440
|
+
block: 1
|
|
38441
|
+
}
|
|
38442
|
+
}
|
|
37965
38443
|
],
|
|
37966
38444
|
as: "units"
|
|
37967
38445
|
}
|
|
@@ -37982,11 +38460,20 @@ function UseAccessManagementRepo() {
|
|
|
37982
38460
|
throw new Error(error.message);
|
|
37983
38461
|
}
|
|
37984
38462
|
}
|
|
37985
|
-
async function getTransactionsRepo({
|
|
38463
|
+
async function getTransactionsRepo({
|
|
38464
|
+
page = 1,
|
|
38465
|
+
limit = 10,
|
|
38466
|
+
site,
|
|
38467
|
+
cardNo,
|
|
38468
|
+
url
|
|
38469
|
+
}) {
|
|
37986
38470
|
page = page ? page - 1 : 0;
|
|
37987
38471
|
site = new ObjectId90(site);
|
|
37988
38472
|
try {
|
|
37989
|
-
let index = await collectionName("access-card-transactions").findOne(
|
|
38473
|
+
let index = await collectionName("access-card-transactions").findOne(
|
|
38474
|
+
{},
|
|
38475
|
+
{ sort: { index: -1 } }
|
|
38476
|
+
);
|
|
37990
38477
|
index = index ? index.index : 0;
|
|
37991
38478
|
const response = await getTransactions(index, url);
|
|
37992
38479
|
if (response && Array.isArray(response.items) && response.items.length > 0) {
|
|
@@ -37995,7 +38482,9 @@ function UseAccessManagementRepo() {
|
|
|
37995
38482
|
data: JSON.parse(item.data),
|
|
37996
38483
|
timestamp: item.timestamp
|
|
37997
38484
|
}));
|
|
37998
|
-
result2 = result2.filter(
|
|
38485
|
+
result2 = result2.filter(
|
|
38486
|
+
(item) => item.data.Event.ETYPE === "0" && item.data.Event.CARDNO !== ""
|
|
38487
|
+
);
|
|
37999
38488
|
if (result2.length > 0) {
|
|
38000
38489
|
const transactions = result2.map(
|
|
38001
38490
|
(item) => new MAccessCardTransaction({
|
|
@@ -38006,11 +38495,16 @@ function UseAccessManagementRepo() {
|
|
|
38006
38495
|
accessType: item.data.Event.DEVNAME,
|
|
38007
38496
|
accessStatus: item.data.Event.TRCODE,
|
|
38008
38497
|
description: item.data.Event.TRDESC,
|
|
38009
|
-
accessTime: entryPassDate(
|
|
38498
|
+
accessTime: entryPassDate(
|
|
38499
|
+
item.data.Event.TRDATE,
|
|
38500
|
+
item.data.Event.TRTIME
|
|
38501
|
+
),
|
|
38010
38502
|
createdAt: /* @__PURE__ */ new Date()
|
|
38011
38503
|
})
|
|
38012
38504
|
);
|
|
38013
|
-
await collectionName("access-card-transactions").insertMany(
|
|
38505
|
+
await collectionName("access-card-transactions").insertMany(
|
|
38506
|
+
transactions
|
|
38507
|
+
);
|
|
38014
38508
|
}
|
|
38015
38509
|
}
|
|
38016
38510
|
const result = await collectionName("access-card-transactions").aggregate([
|
|
@@ -38081,7 +38575,11 @@ function UseAccessManagementRepo() {
|
|
|
38081
38575
|
{
|
|
38082
38576
|
$facet: {
|
|
38083
38577
|
totalCount: [{ $count: "count" }],
|
|
38084
|
-
items: [
|
|
38578
|
+
items: [
|
|
38579
|
+
{ $sort: { _id: -1 } },
|
|
38580
|
+
{ $skip: page * limit },
|
|
38581
|
+
{ $limit: limit }
|
|
38582
|
+
]
|
|
38085
38583
|
}
|
|
38086
38584
|
}
|
|
38087
38585
|
]).toArray();
|
|
@@ -38104,7 +38602,9 @@ function UseAccessManagementRepo() {
|
|
|
38104
38602
|
if (assignees.length < 1) {
|
|
38105
38603
|
throw new Error("No user to Assign.");
|
|
38106
38604
|
}
|
|
38107
|
-
assignees = assignees.map(
|
|
38605
|
+
assignees = assignees.map(
|
|
38606
|
+
(data) => new ObjectId90(data)
|
|
38607
|
+
);
|
|
38108
38608
|
unit = new ObjectId90(unit);
|
|
38109
38609
|
let availableCards = [];
|
|
38110
38610
|
let update = [];
|
|
@@ -38114,7 +38614,18 @@ function UseAccessManagementRepo() {
|
|
|
38114
38614
|
$match: {
|
|
38115
38615
|
$expr: {
|
|
38116
38616
|
$and: [
|
|
38117
|
-
{
|
|
38617
|
+
{
|
|
38618
|
+
$in: [
|
|
38619
|
+
unit,
|
|
38620
|
+
{
|
|
38621
|
+
$cond: [
|
|
38622
|
+
{ $isArray: "$assignedUnit" },
|
|
38623
|
+
"$assignedUnit",
|
|
38624
|
+
["$assignedUnit"]
|
|
38625
|
+
]
|
|
38626
|
+
}
|
|
38627
|
+
]
|
|
38628
|
+
},
|
|
38118
38629
|
{ $eq: ["$userId", null] },
|
|
38119
38630
|
{ $eq: ["$type", type] },
|
|
38120
38631
|
{ $eq: ["$isActivated", true] }
|
|
@@ -38131,7 +38642,10 @@ function UseAccessManagementRepo() {
|
|
|
38131
38642
|
card.staffNo = userId.toString().slice(-10);
|
|
38132
38643
|
return card;
|
|
38133
38644
|
});
|
|
38134
|
-
update = availableCards.slice(0, assignees.length).map((card, index) => ({
|
|
38645
|
+
update = availableCards.slice(0, assignees.length).map((card, index) => ({
|
|
38646
|
+
_id: card._id,
|
|
38647
|
+
userId: new ObjectId90(assignees[index])
|
|
38648
|
+
}));
|
|
38135
38649
|
const commands = cards.map((item, index) => {
|
|
38136
38650
|
let ag = null;
|
|
38137
38651
|
if (item.accessGroup !== void 0) {
|
|
@@ -38161,16 +38675,27 @@ function UseAccessManagementRepo() {
|
|
|
38161
38675
|
liftAccessEndDate: formatEntryPassDate(item.liftAccessEndDate) || "19770510",
|
|
38162
38676
|
accessGroup: ag
|
|
38163
38677
|
};
|
|
38164
|
-
return readTemplate(
|
|
38678
|
+
return readTemplate(
|
|
38679
|
+
`${item.accessLevel !== null ? "add-card" : "add-card-lift"}`,
|
|
38680
|
+
{ ...command }
|
|
38681
|
+
);
|
|
38165
38682
|
}).flat();
|
|
38166
38683
|
const response = await sendCommand(commands.join("").toString(), acm_url);
|
|
38167
|
-
const result = await parseStringPromise2(response, {
|
|
38684
|
+
const result = await parseStringPromise2(response, {
|
|
38685
|
+
explicitArray: false
|
|
38686
|
+
});
|
|
38168
38687
|
console.log("status code", result.RESULT.$.STCODE);
|
|
38169
38688
|
if (result && result.RESULT.$.STCODE !== "0") {
|
|
38170
38689
|
throw new Error("Command failed, server error.");
|
|
38171
38690
|
}
|
|
38172
38691
|
for (const { _id, userId } of update) {
|
|
38173
|
-
await collection().updateOne(
|
|
38692
|
+
await collection().updateOne(
|
|
38693
|
+
{ _id },
|
|
38694
|
+
{
|
|
38695
|
+
$set: { userId, staffNo: `STAFF-${userId.toString().slice(-10)}` }
|
|
38696
|
+
},
|
|
38697
|
+
{ session }
|
|
38698
|
+
);
|
|
38174
38699
|
}
|
|
38175
38700
|
await session?.commitTransaction();
|
|
38176
38701
|
return "Cards assigned successfully.";
|
|
@@ -38186,7 +38711,11 @@ function UseAccessManagementRepo() {
|
|
|
38186
38711
|
try {
|
|
38187
38712
|
session?.startTransaction();
|
|
38188
38713
|
const id = new ObjectId90(userId);
|
|
38189
|
-
await collection().updateMany(
|
|
38714
|
+
await collection().updateMany(
|
|
38715
|
+
{ userId: id },
|
|
38716
|
+
{ $set: { userId: null, status: "Available" } },
|
|
38717
|
+
{ session }
|
|
38718
|
+
);
|
|
38190
38719
|
session?.commitTransaction();
|
|
38191
38720
|
return "Successful Checkout";
|
|
38192
38721
|
} catch (error) {
|
|
@@ -38196,7 +38725,11 @@ function UseAccessManagementRepo() {
|
|
|
38196
38725
|
await session?.endSession();
|
|
38197
38726
|
}
|
|
38198
38727
|
}
|
|
38199
|
-
async function uploadTemplateRepo({
|
|
38728
|
+
async function uploadTemplateRepo({
|
|
38729
|
+
site,
|
|
38730
|
+
id,
|
|
38731
|
+
name
|
|
38732
|
+
}) {
|
|
38200
38733
|
site = new ObjectId90(site);
|
|
38201
38734
|
id = new ObjectId90(id);
|
|
38202
38735
|
try {
|
|
@@ -38209,6 +38742,46 @@ function UseAccessManagementRepo() {
|
|
|
38209
38742
|
throw new Error(error.message);
|
|
38210
38743
|
}
|
|
38211
38744
|
}
|
|
38745
|
+
async function getResidentsRepo({
|
|
38746
|
+
orgId,
|
|
38747
|
+
siteId,
|
|
38748
|
+
unitId
|
|
38749
|
+
}) {
|
|
38750
|
+
try {
|
|
38751
|
+
orgId = new ObjectId90(orgId);
|
|
38752
|
+
siteId = new ObjectId90(siteId);
|
|
38753
|
+
unitId = new ObjectId90(unitId);
|
|
38754
|
+
const result = await collectionName("users").aggregate([
|
|
38755
|
+
{
|
|
38756
|
+
$match: {
|
|
38757
|
+
$expr: {
|
|
38758
|
+
$and: [
|
|
38759
|
+
{ $eq: ["$defaultOrg", orgId] },
|
|
38760
|
+
{ $eq: ["$site", siteId] },
|
|
38761
|
+
{ $eq: ["$unitId", unitId] }
|
|
38762
|
+
]
|
|
38763
|
+
}
|
|
38764
|
+
}
|
|
38765
|
+
},
|
|
38766
|
+
{
|
|
38767
|
+
$project: {
|
|
38768
|
+
_id: 1,
|
|
38769
|
+
email: 1,
|
|
38770
|
+
unitName: 1,
|
|
38771
|
+
type: 1,
|
|
38772
|
+
status: 1,
|
|
38773
|
+
name: 1,
|
|
38774
|
+
defaultOrg: 1,
|
|
38775
|
+
site: 1,
|
|
38776
|
+
unitId: 1
|
|
38777
|
+
}
|
|
38778
|
+
}
|
|
38779
|
+
]).toArray();
|
|
38780
|
+
return result;
|
|
38781
|
+
} catch (error) {
|
|
38782
|
+
throw new Error(error.message);
|
|
38783
|
+
}
|
|
38784
|
+
}
|
|
38212
38785
|
return {
|
|
38213
38786
|
createIndexes,
|
|
38214
38787
|
createIndexForEntrypass,
|
|
@@ -38244,7 +38817,8 @@ function UseAccessManagementRepo() {
|
|
|
38244
38817
|
getTransactionsRepo,
|
|
38245
38818
|
assignMultipleCardsRepo,
|
|
38246
38819
|
visitorCheckoutRepo,
|
|
38247
|
-
uploadTemplateRepo
|
|
38820
|
+
uploadTemplateRepo,
|
|
38821
|
+
getResidentsRepo
|
|
38248
38822
|
};
|
|
38249
38823
|
}
|
|
38250
38824
|
|
|
@@ -38288,7 +38862,8 @@ function useAccessManagementSvc() {
|
|
|
38288
38862
|
getTransactionsRepo,
|
|
38289
38863
|
assignMultipleCardsRepo,
|
|
38290
38864
|
visitorCheckoutRepo,
|
|
38291
|
-
uploadTemplateRepo
|
|
38865
|
+
uploadTemplateRepo,
|
|
38866
|
+
getResidentsRepo
|
|
38292
38867
|
} = UseAccessManagementRepo();
|
|
38293
38868
|
const addPhysicalCardSvc = async (payload) => {
|
|
38294
38869
|
try {
|
|
@@ -38580,17 +39155,39 @@ function useAccessManagementSvc() {
|
|
|
38580
39155
|
throw new Error(err.message);
|
|
38581
39156
|
}
|
|
38582
39157
|
};
|
|
38583
|
-
const getTransactionsSvc = async ({
|
|
39158
|
+
const getTransactionsSvc = async ({
|
|
39159
|
+
page,
|
|
39160
|
+
limit,
|
|
39161
|
+
site,
|
|
39162
|
+
cardNo,
|
|
39163
|
+
url
|
|
39164
|
+
}) => {
|
|
38584
39165
|
try {
|
|
38585
|
-
const response = await getTransactionsRepo({
|
|
39166
|
+
const response = await getTransactionsRepo({
|
|
39167
|
+
page,
|
|
39168
|
+
limit,
|
|
39169
|
+
site,
|
|
39170
|
+
cardNo,
|
|
39171
|
+
url
|
|
39172
|
+
});
|
|
38586
39173
|
return response;
|
|
38587
39174
|
} catch (err) {
|
|
38588
39175
|
throw new Error(err.message);
|
|
38589
39176
|
}
|
|
38590
39177
|
};
|
|
38591
|
-
const assignMultipleCardsSvc = async ({
|
|
39178
|
+
const assignMultipleCardsSvc = async ({
|
|
39179
|
+
assignees,
|
|
39180
|
+
unit,
|
|
39181
|
+
type,
|
|
39182
|
+
acm_url
|
|
39183
|
+
}) => {
|
|
38592
39184
|
try {
|
|
38593
|
-
const response = await assignMultipleCardsRepo({
|
|
39185
|
+
const response = await assignMultipleCardsRepo({
|
|
39186
|
+
assignees,
|
|
39187
|
+
unit,
|
|
39188
|
+
type,
|
|
39189
|
+
acm_url
|
|
39190
|
+
});
|
|
38594
39191
|
return response;
|
|
38595
39192
|
} catch (err) {
|
|
38596
39193
|
throw new Error(err.message);
|
|
@@ -38604,7 +39201,11 @@ function useAccessManagementSvc() {
|
|
|
38604
39201
|
throw new Error(err.message);
|
|
38605
39202
|
}
|
|
38606
39203
|
};
|
|
38607
|
-
const uploadTemplateSvc = async ({
|
|
39204
|
+
const uploadTemplateSvc = async ({
|
|
39205
|
+
site,
|
|
39206
|
+
id,
|
|
39207
|
+
name
|
|
39208
|
+
}) => {
|
|
38608
39209
|
try {
|
|
38609
39210
|
const response = await uploadTemplateRepo({ site, id, name });
|
|
38610
39211
|
return response;
|
|
@@ -38612,6 +39213,18 @@ function useAccessManagementSvc() {
|
|
|
38612
39213
|
throw new Error(err.message);
|
|
38613
39214
|
}
|
|
38614
39215
|
};
|
|
39216
|
+
const getResidentsSvc = async ({
|
|
39217
|
+
orgId,
|
|
39218
|
+
siteId,
|
|
39219
|
+
unitId
|
|
39220
|
+
}) => {
|
|
39221
|
+
try {
|
|
39222
|
+
const response = await getResidentsRepo({ orgId, siteId, unitId });
|
|
39223
|
+
return response;
|
|
39224
|
+
} catch (err) {
|
|
39225
|
+
throw new Error(err.message);
|
|
39226
|
+
}
|
|
39227
|
+
};
|
|
38615
39228
|
return {
|
|
38616
39229
|
addPhysicalCardSvc,
|
|
38617
39230
|
addNonPhysicalCardSvc,
|
|
@@ -38650,7 +39263,8 @@ function useAccessManagementSvc() {
|
|
|
38650
39263
|
getTransactionsSvc,
|
|
38651
39264
|
assignMultipleCardsSvc,
|
|
38652
39265
|
visitorCheckoutSvc,
|
|
38653
|
-
uploadTemplateSvc
|
|
39266
|
+
uploadTemplateSvc,
|
|
39267
|
+
getResidentsSvc
|
|
38654
39268
|
};
|
|
38655
39269
|
}
|
|
38656
39270
|
|
|
@@ -38694,7 +39308,8 @@ function useAccessManagementController() {
|
|
|
38694
39308
|
getTransactionsSvc,
|
|
38695
39309
|
assignMultipleCardsSvc,
|
|
38696
39310
|
visitorCheckoutSvc,
|
|
38697
|
-
uploadTemplateSvc
|
|
39311
|
+
uploadTemplateSvc,
|
|
39312
|
+
getResidentsSvc
|
|
38698
39313
|
} = useAccessManagementSvc();
|
|
38699
39314
|
const addPhysicalCard = async (req, res) => {
|
|
38700
39315
|
try {
|
|
@@ -38943,11 +39558,25 @@ function useAccessManagementController() {
|
|
|
38943
39558
|
search: Joi86.string().optional().allow("", null),
|
|
38944
39559
|
userType: Joi86.string().required()
|
|
38945
39560
|
});
|
|
38946
|
-
const { error } = schema2.validate({
|
|
39561
|
+
const { error } = schema2.validate({
|
|
39562
|
+
page,
|
|
39563
|
+
limit,
|
|
39564
|
+
site,
|
|
39565
|
+
organization,
|
|
39566
|
+
search,
|
|
39567
|
+
userType
|
|
39568
|
+
});
|
|
38947
39569
|
if (error) {
|
|
38948
39570
|
return res.status(400).json({ message: error.message });
|
|
38949
39571
|
}
|
|
38950
|
-
const result = await userTypeAccessCardsSvc({
|
|
39572
|
+
const result = await userTypeAccessCardsSvc({
|
|
39573
|
+
page,
|
|
39574
|
+
limit,
|
|
39575
|
+
search,
|
|
39576
|
+
site,
|
|
39577
|
+
organization,
|
|
39578
|
+
userType
|
|
39579
|
+
});
|
|
38951
39580
|
return res.status(200).json({ message: "Success", data: result });
|
|
38952
39581
|
} catch (error) {
|
|
38953
39582
|
return res.status(500).json({
|
|
@@ -38958,7 +39587,12 @@ function useAccessManagementController() {
|
|
|
38958
39587
|
};
|
|
38959
39588
|
const assignedAccessCards = async (req, res) => {
|
|
38960
39589
|
try {
|
|
38961
|
-
const {
|
|
39590
|
+
const {
|
|
39591
|
+
site,
|
|
39592
|
+
userType,
|
|
39593
|
+
type,
|
|
39594
|
+
search = ""
|
|
39595
|
+
} = req.query;
|
|
38962
39596
|
const schema2 = Joi86.object({
|
|
38963
39597
|
site: Joi86.string().hex().required(),
|
|
38964
39598
|
userType: Joi86.string().required(),
|
|
@@ -38969,7 +39603,12 @@ function useAccessManagementController() {
|
|
|
38969
39603
|
if (error) {
|
|
38970
39604
|
return res.status(400).json({ message: error.message });
|
|
38971
39605
|
}
|
|
38972
|
-
const result = await assignedAccessCardsSvc({
|
|
39606
|
+
const result = await assignedAccessCardsSvc({
|
|
39607
|
+
site,
|
|
39608
|
+
userType,
|
|
39609
|
+
type,
|
|
39610
|
+
search
|
|
39611
|
+
});
|
|
38973
39612
|
return res.status(200).json({ message: "Success", data: result });
|
|
38974
39613
|
} catch (error) {
|
|
38975
39614
|
return res.status(500).json({
|
|
@@ -39015,11 +39654,23 @@ function useAccessManagementController() {
|
|
|
39015
39654
|
userType: Joi86.string().valid(...Object.values(EAccessCardUserTypes)).required(),
|
|
39016
39655
|
type: Joi86.string().valid(...Object.values(EAccessCardTypes)).required()
|
|
39017
39656
|
});
|
|
39018
|
-
const { error } = schema2.validate({
|
|
39657
|
+
const { error } = schema2.validate({
|
|
39658
|
+
accessLevel,
|
|
39659
|
+
liftAccessLevel,
|
|
39660
|
+
site,
|
|
39661
|
+
userType,
|
|
39662
|
+
type
|
|
39663
|
+
});
|
|
39019
39664
|
if (error) {
|
|
39020
39665
|
return res.status(400).json({ message: error.message });
|
|
39021
39666
|
}
|
|
39022
|
-
const result = await accessandLiftCardsSvc({
|
|
39667
|
+
const result = await accessandLiftCardsSvc({
|
|
39668
|
+
accessLevel,
|
|
39669
|
+
liftAccessLevel,
|
|
39670
|
+
site,
|
|
39671
|
+
userType,
|
|
39672
|
+
type
|
|
39673
|
+
});
|
|
39023
39674
|
return res.status(200).json({ message: "Success", data: result });
|
|
39024
39675
|
} catch (error) {
|
|
39025
39676
|
return res.status(500).json({
|
|
@@ -39106,11 +39757,23 @@ function useAccessManagementController() {
|
|
|
39106
39757
|
issuedCardId: Joi86.string().required(),
|
|
39107
39758
|
userId: Joi86.string().hex().required()
|
|
39108
39759
|
});
|
|
39109
|
-
const { error } = schema2.validate({
|
|
39760
|
+
const { error } = schema2.validate({
|
|
39761
|
+
cardId,
|
|
39762
|
+
remarks,
|
|
39763
|
+
unitId,
|
|
39764
|
+
issuedCardId,
|
|
39765
|
+
userId
|
|
39766
|
+
});
|
|
39110
39767
|
if (error) {
|
|
39111
39768
|
return res.status(400).json({ message: error.message });
|
|
39112
39769
|
}
|
|
39113
|
-
const result = await cardReplacementSvc({
|
|
39770
|
+
const result = await cardReplacementSvc({
|
|
39771
|
+
cardId,
|
|
39772
|
+
remarks,
|
|
39773
|
+
unitId,
|
|
39774
|
+
issuedCardId,
|
|
39775
|
+
userId
|
|
39776
|
+
});
|
|
39114
39777
|
return res.status(200).json({ message: "Success", data: result });
|
|
39115
39778
|
} catch (error) {
|
|
39116
39779
|
return res.status(500).json({
|
|
@@ -39139,7 +39802,13 @@ function useAccessManagementController() {
|
|
|
39139
39802
|
if (error) {
|
|
39140
39803
|
return res.status(400).json({ message: error.message });
|
|
39141
39804
|
}
|
|
39142
|
-
const result = await visitorAccessCardsSvc({
|
|
39805
|
+
const result = await visitorAccessCardsSvc({
|
|
39806
|
+
site,
|
|
39807
|
+
page,
|
|
39808
|
+
limit,
|
|
39809
|
+
type,
|
|
39810
|
+
search
|
|
39811
|
+
});
|
|
39143
39812
|
return res.status(200).json({ message: "Success", data: result });
|
|
39144
39813
|
} catch (error) {
|
|
39145
39814
|
return res.status(500).json({
|
|
@@ -39168,11 +39837,27 @@ function useAccessManagementController() {
|
|
|
39168
39837
|
limit: Joi86.number().optional().default(10),
|
|
39169
39838
|
site: Joi86.string().hex().required()
|
|
39170
39839
|
});
|
|
39171
|
-
const { error } = schema2.validate({
|
|
39840
|
+
const { error } = schema2.validate({
|
|
39841
|
+
search,
|
|
39842
|
+
statusFilter,
|
|
39843
|
+
dateFrom,
|
|
39844
|
+
dateTo,
|
|
39845
|
+
page,
|
|
39846
|
+
limit,
|
|
39847
|
+
site
|
|
39848
|
+
});
|
|
39172
39849
|
if (error) {
|
|
39173
39850
|
return res.status(400).json({ message: error.message });
|
|
39174
39851
|
}
|
|
39175
|
-
const result = await getCardReplacementSvc({
|
|
39852
|
+
const result = await getCardReplacementSvc({
|
|
39853
|
+
site,
|
|
39854
|
+
page,
|
|
39855
|
+
limit,
|
|
39856
|
+
search,
|
|
39857
|
+
statusFilter,
|
|
39858
|
+
dateFrom,
|
|
39859
|
+
dateTo
|
|
39860
|
+
});
|
|
39176
39861
|
return res.status(200).json({ message: "Success", data: result });
|
|
39177
39862
|
} catch (error) {
|
|
39178
39863
|
return res.status(500).json({
|
|
@@ -39218,7 +39903,15 @@ function useAccessManagementController() {
|
|
|
39218
39903
|
};
|
|
39219
39904
|
const assignAccessCardToUnit = async (req, res) => {
|
|
39220
39905
|
try {
|
|
39221
|
-
const {
|
|
39906
|
+
const {
|
|
39907
|
+
units,
|
|
39908
|
+
type,
|
|
39909
|
+
quantity,
|
|
39910
|
+
site,
|
|
39911
|
+
userType,
|
|
39912
|
+
accessLevel,
|
|
39913
|
+
liftAccessLevel
|
|
39914
|
+
} = req.body;
|
|
39222
39915
|
const schema2 = Joi86.object({
|
|
39223
39916
|
units: Joi86.array().items(Joi86.string().hex()).required(),
|
|
39224
39917
|
quantity: Joi86.number().required(),
|
|
@@ -39228,11 +39921,27 @@ function useAccessManagementController() {
|
|
|
39228
39921
|
accessLevel: Joi86.string().optional().allow("", null),
|
|
39229
39922
|
liftAccessLevel: Joi86.string().optional().allow("", null)
|
|
39230
39923
|
});
|
|
39231
|
-
const { error } = schema2.validate({
|
|
39924
|
+
const { error } = schema2.validate({
|
|
39925
|
+
units,
|
|
39926
|
+
quantity,
|
|
39927
|
+
type,
|
|
39928
|
+
site,
|
|
39929
|
+
userType,
|
|
39930
|
+
accessLevel,
|
|
39931
|
+
liftAccessLevel
|
|
39932
|
+
});
|
|
39232
39933
|
if (error) {
|
|
39233
39934
|
return res.status(400).json({ message: error.message });
|
|
39234
39935
|
}
|
|
39235
|
-
const result = await assignAccessCardToUnitSvc({
|
|
39936
|
+
const result = await assignAccessCardToUnitSvc({
|
|
39937
|
+
units,
|
|
39938
|
+
quantity,
|
|
39939
|
+
type,
|
|
39940
|
+
site,
|
|
39941
|
+
userType,
|
|
39942
|
+
accessLevel,
|
|
39943
|
+
liftAccessLevel
|
|
39944
|
+
});
|
|
39236
39945
|
return res.status(200).json({ message: "Success", data: result });
|
|
39237
39946
|
} catch (error) {
|
|
39238
39947
|
return res.status(500).json({
|
|
@@ -39330,7 +40039,12 @@ function useAccessManagementController() {
|
|
|
39330
40039
|
};
|
|
39331
40040
|
const availableCardContractors = async (req, res) => {
|
|
39332
40041
|
try {
|
|
39333
|
-
const {
|
|
40042
|
+
const {
|
|
40043
|
+
siteId,
|
|
40044
|
+
unitId,
|
|
40045
|
+
page = 1,
|
|
40046
|
+
limit = 20
|
|
40047
|
+
} = req.query;
|
|
39334
40048
|
const type = req.params.type;
|
|
39335
40049
|
const schema2 = Joi86.object({
|
|
39336
40050
|
siteId: Joi86.string().hex().required(),
|
|
@@ -39343,7 +40057,13 @@ function useAccessManagementController() {
|
|
|
39343
40057
|
if (error) {
|
|
39344
40058
|
return res.status(400).json({ message: error.message });
|
|
39345
40059
|
}
|
|
39346
|
-
const result = await availableCardContractorsSvc({
|
|
40060
|
+
const result = await availableCardContractorsSvc({
|
|
40061
|
+
siteId,
|
|
40062
|
+
unitId,
|
|
40063
|
+
page,
|
|
40064
|
+
limit,
|
|
40065
|
+
type
|
|
40066
|
+
});
|
|
39347
40067
|
return res.status(200).json({ message: "Success", data: result });
|
|
39348
40068
|
} catch (error) {
|
|
39349
40069
|
return res.status(500).json({
|
|
@@ -39354,7 +40074,11 @@ function useAccessManagementController() {
|
|
|
39354
40074
|
};
|
|
39355
40075
|
const vmsgenerateQrCodes = async (req, res) => {
|
|
39356
40076
|
try {
|
|
39357
|
-
const {
|
|
40077
|
+
const {
|
|
40078
|
+
site,
|
|
40079
|
+
unitId,
|
|
40080
|
+
quantity = 100
|
|
40081
|
+
} = req.body;
|
|
39358
40082
|
const schema2 = Joi86.object({
|
|
39359
40083
|
site: Joi86.string().hex().length(24).required(),
|
|
39360
40084
|
unitId: Joi86.string().hex().length(24).required(),
|
|
@@ -39365,7 +40089,12 @@ function useAccessManagementController() {
|
|
|
39365
40089
|
return res.status(400).json({ message: error.message });
|
|
39366
40090
|
}
|
|
39367
40091
|
const normalizedUnitId = [unitId];
|
|
39368
|
-
const result = await vmsgenerateQrCodesSvc({
|
|
40092
|
+
const result = await vmsgenerateQrCodesSvc({
|
|
40093
|
+
site,
|
|
40094
|
+
unitId,
|
|
40095
|
+
normalizedUnitId,
|
|
40096
|
+
quantity
|
|
40097
|
+
});
|
|
39369
40098
|
return res.status(200).json({ message: "Success", data: result });
|
|
39370
40099
|
} catch (error) {
|
|
39371
40100
|
return res.status(500).json({
|
|
@@ -39376,21 +40105,50 @@ function useAccessManagementController() {
|
|
|
39376
40105
|
};
|
|
39377
40106
|
const addVisitorAccessCard = async (req, res) => {
|
|
39378
40107
|
try {
|
|
39379
|
-
const {
|
|
40108
|
+
const {
|
|
40109
|
+
site,
|
|
40110
|
+
unitId,
|
|
40111
|
+
quantity = 1,
|
|
40112
|
+
type,
|
|
40113
|
+
nfcCards,
|
|
40114
|
+
visitorId,
|
|
40115
|
+
acm_url
|
|
40116
|
+
} = req.body;
|
|
39380
40117
|
const schema2 = Joi86.object({
|
|
39381
40118
|
site: Joi86.string().hex().length(24).required(),
|
|
39382
40119
|
unitId: Joi86.string().hex().length(24).required(),
|
|
39383
40120
|
quantity: Joi86.number().allow(null, "").optional(),
|
|
39384
40121
|
type: Joi86.string().required(),
|
|
39385
|
-
nfcCards: Joi86.array().items(
|
|
40122
|
+
nfcCards: Joi86.array().items(
|
|
40123
|
+
Joi86.object({
|
|
40124
|
+
_id: Joi86.string().hex().required(),
|
|
40125
|
+
cardNo: Joi86.string().required()
|
|
40126
|
+
})
|
|
40127
|
+
).required(),
|
|
39386
40128
|
acm_url: Joi86.string().required(),
|
|
39387
40129
|
visitorId: Joi86.string().hex().length(24).required()
|
|
39388
40130
|
});
|
|
39389
|
-
const { error } = schema2.validate({
|
|
40131
|
+
const { error } = schema2.validate({
|
|
40132
|
+
site,
|
|
40133
|
+
unitId,
|
|
40134
|
+
quantity,
|
|
40135
|
+
type,
|
|
40136
|
+
nfcCards,
|
|
40137
|
+
visitorId,
|
|
40138
|
+
acm_url
|
|
40139
|
+
});
|
|
39390
40140
|
if (error) {
|
|
39391
40141
|
return res.status(400).json({ message: error.message });
|
|
39392
40142
|
}
|
|
39393
|
-
const result = await addVisitorAccessCardSvc({
|
|
40143
|
+
const result = await addVisitorAccessCardSvc({
|
|
40144
|
+
site,
|
|
40145
|
+
unitId,
|
|
40146
|
+
quantity,
|
|
40147
|
+
type,
|
|
40148
|
+
nfcCards,
|
|
40149
|
+
visitorId,
|
|
40150
|
+
acm_url
|
|
40151
|
+
});
|
|
39394
40152
|
return res.status(200).json({ message: "Success", data: result });
|
|
39395
40153
|
} catch (error) {
|
|
39396
40154
|
return res.status(500).json({
|
|
@@ -39438,7 +40196,11 @@ function useAccessManagementController() {
|
|
|
39438
40196
|
});
|
|
39439
40197
|
}
|
|
39440
40198
|
};
|
|
39441
|
-
const removeAccessCard = async ({
|
|
40199
|
+
const removeAccessCard = async ({
|
|
40200
|
+
cardNo,
|
|
40201
|
+
staffNo,
|
|
40202
|
+
url
|
|
40203
|
+
}) => {
|
|
39442
40204
|
return removeAccessGroup({ cardNo, staffNo, url });
|
|
39443
40205
|
};
|
|
39444
40206
|
const getBlockLevelAndUnitList = async (req, res) => {
|
|
@@ -39457,7 +40219,13 @@ function useAccessManagementController() {
|
|
|
39457
40219
|
}
|
|
39458
40220
|
};
|
|
39459
40221
|
const getTransactions2 = async (req, res) => {
|
|
39460
|
-
const {
|
|
40222
|
+
const {
|
|
40223
|
+
page = 1,
|
|
40224
|
+
limit = 10,
|
|
40225
|
+
site,
|
|
40226
|
+
cardNo,
|
|
40227
|
+
url
|
|
40228
|
+
} = req.query;
|
|
39461
40229
|
const schema2 = Joi86.object({
|
|
39462
40230
|
page: Joi86.number().required(),
|
|
39463
40231
|
limit: Joi86.number().optional().default(10),
|
|
@@ -39496,7 +40264,12 @@ function useAccessManagementController() {
|
|
|
39496
40264
|
if (error) {
|
|
39497
40265
|
throw new Error(`${error.message}`);
|
|
39498
40266
|
}
|
|
39499
|
-
const result = await assignMultipleCardsSvc({
|
|
40267
|
+
const result = await assignMultipleCardsSvc({
|
|
40268
|
+
assignees,
|
|
40269
|
+
unit,
|
|
40270
|
+
type,
|
|
40271
|
+
acm_url
|
|
40272
|
+
});
|
|
39500
40273
|
return res.status(200).json({ message: "Success", data: result });
|
|
39501
40274
|
} catch (error) {
|
|
39502
40275
|
return res.status(400).json({
|
|
@@ -39539,6 +40312,27 @@ function useAccessManagementController() {
|
|
|
39539
40312
|
});
|
|
39540
40313
|
}
|
|
39541
40314
|
};
|
|
40315
|
+
const getResidents = async (req, res) => {
|
|
40316
|
+
try {
|
|
40317
|
+
const { orgId, siteId, unitId } = req.query;
|
|
40318
|
+
const schema2 = Joi86.object({
|
|
40319
|
+
orgId: Joi86.string().hex().required(),
|
|
40320
|
+
siteId: Joi86.string().hex().required(),
|
|
40321
|
+
unitId: Joi86.string().hex().required()
|
|
40322
|
+
});
|
|
40323
|
+
const { error } = schema2.validate({ orgId, siteId, unitId });
|
|
40324
|
+
if (error) {
|
|
40325
|
+
return res.status(400).json({ message: error.message });
|
|
40326
|
+
}
|
|
40327
|
+
const result = await getResidentsSvc({ orgId, siteId, unitId });
|
|
40328
|
+
return res.status(200).json({ data: result });
|
|
40329
|
+
} catch (error) {
|
|
40330
|
+
return res.status(400).json({
|
|
40331
|
+
data: null,
|
|
40332
|
+
message: error.message
|
|
40333
|
+
});
|
|
40334
|
+
}
|
|
40335
|
+
};
|
|
39542
40336
|
return {
|
|
39543
40337
|
addPhysicalCard,
|
|
39544
40338
|
addNonPhysicalCard,
|
|
@@ -39575,7 +40369,8 @@ function useAccessManagementController() {
|
|
|
39575
40369
|
getTransactions: getTransactions2,
|
|
39576
40370
|
assignMultipleCards,
|
|
39577
40371
|
visitorCheckout,
|
|
39578
|
-
uploadTemplate
|
|
40372
|
+
uploadTemplate,
|
|
40373
|
+
getResidents
|
|
39579
40374
|
};
|
|
39580
40375
|
}
|
|
39581
40376
|
|
|
@@ -54279,6 +55074,213 @@ function usePostPrelovedController() {
|
|
|
54279
55074
|
updateStatus
|
|
54280
55075
|
};
|
|
54281
55076
|
}
|
|
55077
|
+
|
|
55078
|
+
// src/models/online-forms-v2.model.ts
|
|
55079
|
+
import Joi134 from "joi";
|
|
55080
|
+
import { ObjectId as ObjectId131 } from "mongodb";
|
|
55081
|
+
var FormEntryStatus = /* @__PURE__ */ ((FormEntryStatus2) => {
|
|
55082
|
+
FormEntryStatus2["ACTIVE"] = "active";
|
|
55083
|
+
FormEntryStatus2["INACTIVE"] = "inactive";
|
|
55084
|
+
FormEntryStatus2["DELETED"] = "deleted";
|
|
55085
|
+
return FormEntryStatus2;
|
|
55086
|
+
})(FormEntryStatus || {});
|
|
55087
|
+
var schemaFormEntry = Joi134.object({
|
|
55088
|
+
_id: Joi134.string().hex().optional().allow("", null),
|
|
55089
|
+
formType: Joi134.string().required(),
|
|
55090
|
+
fields: Joi134.object().pattern(
|
|
55091
|
+
Joi134.string(),
|
|
55092
|
+
Joi134.alternatives().try(
|
|
55093
|
+
Joi134.string(),
|
|
55094
|
+
Joi134.number(),
|
|
55095
|
+
Joi134.boolean(),
|
|
55096
|
+
Joi134.valid(null)
|
|
55097
|
+
)
|
|
55098
|
+
).required(),
|
|
55099
|
+
status: Joi134.string().optional().allow("", null),
|
|
55100
|
+
org: Joi134.string().hex().optional().allow("", null),
|
|
55101
|
+
site: Joi134.string().hex().optional().allow("", null),
|
|
55102
|
+
createdAt: Joi134.date().optional().allow("", null),
|
|
55103
|
+
updatedAt: Joi134.date().optional().allow("", null),
|
|
55104
|
+
deletedAt: Joi134.date().optional().allow("", null)
|
|
55105
|
+
});
|
|
55106
|
+
var schemaUpdateFormEntry = Joi134.object({
|
|
55107
|
+
_id: Joi134.string().hex().required(),
|
|
55108
|
+
formType: Joi134.string().optional().allow("", null),
|
|
55109
|
+
fields: Joi134.object().pattern(
|
|
55110
|
+
Joi134.string(),
|
|
55111
|
+
Joi134.alternatives().try(
|
|
55112
|
+
Joi134.string(),
|
|
55113
|
+
Joi134.number(),
|
|
55114
|
+
Joi134.boolean(),
|
|
55115
|
+
Joi134.valid(null)
|
|
55116
|
+
)
|
|
55117
|
+
).optional(),
|
|
55118
|
+
status: Joi134.string().optional().allow("", null),
|
|
55119
|
+
createdAt: Joi134.date().optional().allow("", null),
|
|
55120
|
+
updatedAt: Joi134.date().optional().allow("", null),
|
|
55121
|
+
deletedAt: Joi134.date().optional().allow("", null)
|
|
55122
|
+
});
|
|
55123
|
+
function MFormEntry(value) {
|
|
55124
|
+
const { error } = schemaFormEntry.validate(value);
|
|
55125
|
+
if (error) {
|
|
55126
|
+
throw new Error(error.details[0].message);
|
|
55127
|
+
}
|
|
55128
|
+
if (value._id && typeof value._id === "string") {
|
|
55129
|
+
try {
|
|
55130
|
+
value._id = new ObjectId131(value._id);
|
|
55131
|
+
} catch {
|
|
55132
|
+
throw new Error("Invalid ID.");
|
|
55133
|
+
}
|
|
55134
|
+
}
|
|
55135
|
+
if (value.org && typeof value.org === "string") {
|
|
55136
|
+
try {
|
|
55137
|
+
value.org = new ObjectId131(value.org);
|
|
55138
|
+
} catch {
|
|
55139
|
+
throw new Error("Invalid org ID.");
|
|
55140
|
+
}
|
|
55141
|
+
}
|
|
55142
|
+
if (value.site && typeof value.site === "string") {
|
|
55143
|
+
try {
|
|
55144
|
+
value.site = new ObjectId131(value.site);
|
|
55145
|
+
} catch {
|
|
55146
|
+
throw new Error("Invalid site ID.");
|
|
55147
|
+
}
|
|
55148
|
+
}
|
|
55149
|
+
return {
|
|
55150
|
+
_id: value._id,
|
|
55151
|
+
formType: value.formType,
|
|
55152
|
+
fields: value.fields,
|
|
55153
|
+
status: value.status,
|
|
55154
|
+
org: value.org,
|
|
55155
|
+
site: value.site,
|
|
55156
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
55157
|
+
updatedAt: value.updatedAt ?? null,
|
|
55158
|
+
deletedAt: value.deletedAt ?? null
|
|
55159
|
+
};
|
|
55160
|
+
}
|
|
55161
|
+
|
|
55162
|
+
// src/repositories/online-forms-v2.repository.ts
|
|
55163
|
+
import {
|
|
55164
|
+
BadRequestError as BadRequestError212,
|
|
55165
|
+
InternalServerError as InternalServerError75,
|
|
55166
|
+
logger as logger187,
|
|
55167
|
+
useAtlas as useAtlas118,
|
|
55168
|
+
useCache as useCache69
|
|
55169
|
+
} from "@7365admin1/node-server-utils";
|
|
55170
|
+
var online_forms_namespace_collection = "online-forms";
|
|
55171
|
+
function useFormEntryRepo() {
|
|
55172
|
+
const db = useAtlas118.getDb();
|
|
55173
|
+
if (!db) {
|
|
55174
|
+
throw new InternalServerError75("Unable to connect to server.");
|
|
55175
|
+
}
|
|
55176
|
+
const collection = db.collection(online_forms_namespace_collection);
|
|
55177
|
+
const { delNamespace, getCache, setCache } = useCache69(
|
|
55178
|
+
online_forms_namespace_collection
|
|
55179
|
+
);
|
|
55180
|
+
async function createTextIndex() {
|
|
55181
|
+
try {
|
|
55182
|
+
await collection.createIndex({
|
|
55183
|
+
name: "text"
|
|
55184
|
+
});
|
|
55185
|
+
} catch (error) {
|
|
55186
|
+
throw new InternalServerError75(
|
|
55187
|
+
"Failed to create text index on online form."
|
|
55188
|
+
);
|
|
55189
|
+
}
|
|
55190
|
+
}
|
|
55191
|
+
async function add(value, session) {
|
|
55192
|
+
try {
|
|
55193
|
+
value = MFormEntry(value);
|
|
55194
|
+
const res = await collection.insertOne(value, { session });
|
|
55195
|
+
delNamespace().then(() => {
|
|
55196
|
+
logger187.info(
|
|
55197
|
+
`Cache cleared for namespace: ${online_forms_namespace_collection}`
|
|
55198
|
+
);
|
|
55199
|
+
}).catch((err) => {
|
|
55200
|
+
logger187.error(
|
|
55201
|
+
`Failed to clear cache for namespace: ${online_forms_namespace_collection}`,
|
|
55202
|
+
err
|
|
55203
|
+
);
|
|
55204
|
+
});
|
|
55205
|
+
return res.insertedId;
|
|
55206
|
+
} catch (error) {
|
|
55207
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
55208
|
+
if (isDuplicated) {
|
|
55209
|
+
throw new BadRequestError212("Online Form already exists.");
|
|
55210
|
+
}
|
|
55211
|
+
throw error;
|
|
55212
|
+
}
|
|
55213
|
+
}
|
|
55214
|
+
return {
|
|
55215
|
+
add,
|
|
55216
|
+
createTextIndex
|
|
55217
|
+
};
|
|
55218
|
+
}
|
|
55219
|
+
|
|
55220
|
+
// src/controllers/online-forms-v2.controller.ts
|
|
55221
|
+
import { BadRequestError as BadRequestError213, logger as logger188 } from "@7365admin1/node-server-utils";
|
|
55222
|
+
import ExcelJS3 from "exceljs";
|
|
55223
|
+
import fs5 from "fs";
|
|
55224
|
+
function useFormEntryController() {
|
|
55225
|
+
const { add: _add } = useFormEntryRepo();
|
|
55226
|
+
function toCamelCase(str) {
|
|
55227
|
+
return str.replace(/\s(.)/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "").replace(/^(.)/, (_, char) => char.toLowerCase());
|
|
55228
|
+
}
|
|
55229
|
+
function normalizeKeys(obj) {
|
|
55230
|
+
const normalized = {};
|
|
55231
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
55232
|
+
normalized[toCamelCase(key)] = value;
|
|
55233
|
+
}
|
|
55234
|
+
return normalized;
|
|
55235
|
+
}
|
|
55236
|
+
async function uploadFormEntrys(req, res, next) {
|
|
55237
|
+
try {
|
|
55238
|
+
if (!req.file) {
|
|
55239
|
+
next(new BadRequestError213("Excel file is required."));
|
|
55240
|
+
return;
|
|
55241
|
+
}
|
|
55242
|
+
const workbook = new ExcelJS3.Workbook();
|
|
55243
|
+
await workbook.xlsx.readFile(req.file.path);
|
|
55244
|
+
const worksheet = workbook.worksheets[0];
|
|
55245
|
+
if (!worksheet) {
|
|
55246
|
+
next(new BadRequestError213("No worksheet found in uploaded Excel file."));
|
|
55247
|
+
return;
|
|
55248
|
+
}
|
|
55249
|
+
const headerRow = worksheet.getRow(1);
|
|
55250
|
+
const headers = headerRow.values.slice(1).map((h) => String(h ?? "").trim());
|
|
55251
|
+
const fields = {};
|
|
55252
|
+
headers.forEach((header) => {
|
|
55253
|
+
fields[header] = null;
|
|
55254
|
+
});
|
|
55255
|
+
const formType = req.file.originalname.replace(/\.[^/.]+$/, "");
|
|
55256
|
+
const normalizedFields = normalizeKeys(fields);
|
|
55257
|
+
const payload = {
|
|
55258
|
+
formType,
|
|
55259
|
+
fields: normalizedFields,
|
|
55260
|
+
status: "active" /* ACTIVE */
|
|
55261
|
+
};
|
|
55262
|
+
const { error, value } = schemaFormEntry.validate(payload, {
|
|
55263
|
+
abortEarly: false
|
|
55264
|
+
});
|
|
55265
|
+
if (error) {
|
|
55266
|
+
const messages = error.details.map((d) => d.message).join(", ");
|
|
55267
|
+
logger188.log({ level: "error", message: messages });
|
|
55268
|
+
next(new BadRequestError213(messages));
|
|
55269
|
+
return;
|
|
55270
|
+
}
|
|
55271
|
+
const result = await _add(value);
|
|
55272
|
+
res.status(201).json(result);
|
|
55273
|
+
fs5.unlink(req.file.path, () => {
|
|
55274
|
+
});
|
|
55275
|
+
} catch (error) {
|
|
55276
|
+
logger188.log({ level: "error", message: error.message });
|
|
55277
|
+
next(error);
|
|
55278
|
+
}
|
|
55279
|
+
}
|
|
55280
|
+
return {
|
|
55281
|
+
uploadFormEntrys
|
|
55282
|
+
};
|
|
55283
|
+
}
|
|
54282
55284
|
export {
|
|
54283
55285
|
ANPRMode,
|
|
54284
55286
|
AccessTypeProps,
|
|
@@ -54305,6 +55307,7 @@ export {
|
|
|
54305
55307
|
EventType,
|
|
54306
55308
|
FacilitySort,
|
|
54307
55309
|
FacilityStatus,
|
|
55310
|
+
FormEntryStatus,
|
|
54308
55311
|
GuestSort,
|
|
54309
55312
|
GuestStatus,
|
|
54310
55313
|
MAccessCard,
|
|
@@ -54326,6 +55329,7 @@ export {
|
|
|
54326
55329
|
MEventManagement,
|
|
54327
55330
|
MFeedback,
|
|
54328
55331
|
MFile,
|
|
55332
|
+
MFormEntry,
|
|
54329
55333
|
MGuestManagement,
|
|
54330
55334
|
MIncidentReport,
|
|
54331
55335
|
MManpowerDesignations,
|
|
@@ -54437,6 +55441,7 @@ export {
|
|
|
54437
55441
|
nfcPatrolSettingsSchema,
|
|
54438
55442
|
nfcPatrolSettingsSchemaUpdate,
|
|
54439
55443
|
occurrence_book_namespace_collection,
|
|
55444
|
+
online_forms_namespace_collection,
|
|
54440
55445
|
orgSchema,
|
|
54441
55446
|
overnight_parking_requests_namespace_collection,
|
|
54442
55447
|
parseDahuaFind,
|
|
@@ -54461,6 +55466,7 @@ export {
|
|
|
54461
55466
|
schemaEntryPassSettings,
|
|
54462
55467
|
schemaEventManagement,
|
|
54463
55468
|
schemaFiles,
|
|
55469
|
+
schemaFormEntry,
|
|
54464
55470
|
schemaGuestManagement,
|
|
54465
55471
|
schemaIncidentReport,
|
|
54466
55472
|
schemaNfcPatrolLog,
|
|
@@ -54491,6 +55497,7 @@ export {
|
|
|
54491
55497
|
schemaUpdateDocumentManagement,
|
|
54492
55498
|
schemaUpdateEntryPassSettings,
|
|
54493
55499
|
schemaUpdateEventManagement,
|
|
55500
|
+
schemaUpdateFormEntry,
|
|
54494
55501
|
schemaUpdateGuestManagement,
|
|
54495
55502
|
schemaUpdateIncidentReport,
|
|
54496
55503
|
schemaUpdateOccurrenceBook,
|
|
@@ -54574,6 +55581,8 @@ export {
|
|
|
54574
55581
|
useFileController,
|
|
54575
55582
|
useFileRepo,
|
|
54576
55583
|
useFileService,
|
|
55584
|
+
useFormEntryController,
|
|
55585
|
+
useFormEntryRepo,
|
|
54577
55586
|
useGuestManagementController,
|
|
54578
55587
|
useGuestManagementRepo,
|
|
54579
55588
|
useGuestManagementService,
|