@7365admin1/core 3.52.2-staging.238 → 3.52.2-staging.239
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/.changeset/vehicle-deleted-plates-and-alert-pacing.md +10 -0
- package/dist/index.js +43 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/camera-alert.util.test.mjs +15 -3
- package/test/e2e/vehicle-deleted-plates.e2e.test.mjs +360 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Vehicle management: a deleted plate is gone from every list, a plate with no camera record can be deleted, and a camera blip no longer raises an alarm
|
|
6
|
+
|
|
7
|
+
- Deleting a vehicle is a soft delete, and no read path filtered on it — so the row never disappeared from the vehicle list, still sat on the blocklist (still stopping the car at the barrier), still filled the by-unit lookup, the season-pass options and the row counts, and still blocked re-creating that plate number. `getVehicles`, `getBlocklistedVehicles`, `getBlocklistedVehicleByPlateNumber`, `getAllVehiclesByUnitId` and `getSeasonPassTypes` now exclude deleted records, and `getVehicleById` drops deleted sibling plates. An explicit `status=deleted` is still honoured, which is the only way to look at them.
|
|
8
|
+
- Creating a vehicle no longer refuses a plate number that only exists on a deleted record. A live duplicate is still refused.
|
|
9
|
+
- The two database writes at the end of a delete ran together on one session inside one transaction; they now run in order. The person-side failure no longer reports itself as an NRIC problem and logs its real cause.
|
|
10
|
+
- An ANPR camera alert now waits for the third consecutive failed reconnect instead of the first. Writing a plate to a camera drops that camera's own event stream while the device services the write, so a successful "add vehicle" raised "the camera is not responding — ask your site technician" at the exact moment it succeeded.
|
package/dist/index.js
CHANGED
|
@@ -18228,7 +18228,13 @@ function usePersonRepo() {
|
|
|
18228
18228
|
{ session }
|
|
18229
18229
|
);
|
|
18230
18230
|
} catch (error) {
|
|
18231
|
-
|
|
18231
|
+
import_node_server_utils41.logger.log({
|
|
18232
|
+
level: "error",
|
|
18233
|
+
message: `pullVehicleByRecNo failed on ${matchKey} for ${owner ? "person" : "site"} ${String(owner ?? site)}: ${error?.message ?? error}`
|
|
18234
|
+
});
|
|
18235
|
+
throw new import_node_server_utils41.InternalServerError(
|
|
18236
|
+
"Could not take the plate off the resident's record."
|
|
18237
|
+
);
|
|
18232
18238
|
}
|
|
18233
18239
|
}
|
|
18234
18240
|
async function getByUserId(userId) {
|
|
@@ -21273,6 +21279,7 @@ function useVehicleRepo() {
|
|
|
21273
21279
|
throw new import_node_server_utils50.InternalServerError("Unable to connect to server.");
|
|
21274
21280
|
}
|
|
21275
21281
|
const collection = db2.collection(vehicles_namespace_collection);
|
|
21282
|
+
const NOT_DELETED = { status: { $ne: "deleted" /* DELETED */ } };
|
|
21276
21283
|
async function createIndex() {
|
|
21277
21284
|
try {
|
|
21278
21285
|
await collection.createIndexes([
|
|
@@ -21329,7 +21336,10 @@ function useVehicleRepo() {
|
|
|
21329
21336
|
}) {
|
|
21330
21337
|
page = page > 0 ? page - 1 : 0;
|
|
21331
21338
|
const baseQuery = {
|
|
21332
|
-
|
|
21339
|
+
// An explicit `status` is still honoured as it was - including
|
|
21340
|
+
// `status=deleted`, which is the only way to see deleted plates and is
|
|
21341
|
+
// what an audit view would ask for.
|
|
21342
|
+
...status ? { status } : NOT_DELETED,
|
|
21333
21343
|
...type && { type },
|
|
21334
21344
|
...category && { category },
|
|
21335
21345
|
...site && { site: new import_mongodb42.ObjectId(site) }
|
|
@@ -21540,7 +21550,7 @@ function useVehicleRepo() {
|
|
|
21540
21550
|
}
|
|
21541
21551
|
try {
|
|
21542
21552
|
const categories = await collection.aggregate([
|
|
21543
|
-
{ $match: { site } },
|
|
21553
|
+
{ $match: { site, ...NOT_DELETED } },
|
|
21544
21554
|
{
|
|
21545
21555
|
$group: {
|
|
21546
21556
|
_id: "$seasonPassType",
|
|
@@ -21715,7 +21725,19 @@ function useVehicleRepo() {
|
|
|
21715
21725
|
cond: {
|
|
21716
21726
|
$and: [
|
|
21717
21727
|
{ $ne: ["$$plate.plateNumber", null] },
|
|
21718
|
-
{ $ne: ["$$plate.plateNumber", ""] }
|
|
21728
|
+
{ $ne: ["$$plate.plateNumber", ""] },
|
|
21729
|
+
// The plate that was ASKED for is always returned,
|
|
21730
|
+
// deleted or not - Restore, Approve and Blocklist
|
|
21731
|
+
// all read the record by its own id. Its deleted
|
|
21732
|
+
// SIBLINGS are dropped, so the Preview dialog of a
|
|
21733
|
+
// live resident stops offering actions on plates
|
|
21734
|
+
// that have been deleted.
|
|
21735
|
+
{
|
|
21736
|
+
$or: [
|
|
21737
|
+
{ $eq: ["$$plate._id", "$$vehicleId"] },
|
|
21738
|
+
{ $ne: ["$$plate.status", "deleted"] }
|
|
21739
|
+
]
|
|
21740
|
+
}
|
|
21719
21741
|
]
|
|
21720
21742
|
}
|
|
21721
21743
|
}
|
|
@@ -21983,7 +22005,8 @@ function useVehicleRepo() {
|
|
|
21983
22005
|
try {
|
|
21984
22006
|
const unit = (0, import_node_server_utils50.toObjectId)(unitId);
|
|
21985
22007
|
const query2 = {
|
|
21986
|
-
unit
|
|
22008
|
+
unit,
|
|
22009
|
+
...NOT_DELETED
|
|
21987
22010
|
};
|
|
21988
22011
|
const items = await collection.find(query2, {
|
|
21989
22012
|
projection: {
|
|
@@ -22084,6 +22107,7 @@ function useVehicleRepo() {
|
|
|
22084
22107
|
page = page > 0 ? page - 1 : 0;
|
|
22085
22108
|
const baseQuery = {
|
|
22086
22109
|
type: "blocklist" /* BLOCKLIST */,
|
|
22110
|
+
...NOT_DELETED,
|
|
22087
22111
|
...site && {
|
|
22088
22112
|
site: typeof site === "string" ? new import_mongodb42.ObjectId(site) : site
|
|
22089
22113
|
}
|
|
@@ -22150,6 +22174,8 @@ function useVehicleRepo() {
|
|
|
22150
22174
|
const baseQuery = {
|
|
22151
22175
|
type: "blocklist" /* BLOCKLIST */,
|
|
22152
22176
|
plateNumber,
|
|
22177
|
+
// A blocklist entry that was deleted must stop blocking the car.
|
|
22178
|
+
...NOT_DELETED,
|
|
22153
22179
|
...site && {
|
|
22154
22180
|
site: typeof site === "string" ? new import_mongodb42.ObjectId(site) : site
|
|
22155
22181
|
}
|
|
@@ -22360,7 +22386,7 @@ function cameraCredentialsMessage(camera) {
|
|
|
22360
22386
|
function cameraNotAuthorisedMessage(camera) {
|
|
22361
22387
|
return `${describeCamera(camera)} rejected our connection, so it cannot read plates. This usually means its account is not allowed to use the plate-reading feed. Please ask your site technician or the security-system installer to check the camera's account permissions.`;
|
|
22362
22388
|
}
|
|
22363
|
-
var CAMERA_ALERT_AT_ATTEMPT = [
|
|
22389
|
+
var CAMERA_ALERT_AT_ATTEMPT = [3, 6, 30, 90];
|
|
22364
22390
|
var CAMERA_ALERT_EVERY_AFTER = 90;
|
|
22365
22391
|
function shouldAlertOnFailure(consecutiveFailures) {
|
|
22366
22392
|
if (!Number.isInteger(consecutiveFailures) || consecutiveFailures < 1)
|
|
@@ -35298,7 +35324,11 @@ function useVehicleService() {
|
|
|
35298
35324
|
};
|
|
35299
35325
|
if (vehicleValue.status && vehicleValue.status !== "pending" /* PENDING */) {
|
|
35300
35326
|
const siteObjectId = new import_mongodb67.ObjectId(vehicleValue.site);
|
|
35301
|
-
const existingPlateNumber = await findOne({
|
|
35327
|
+
const existingPlateNumber = await findOne({
|
|
35328
|
+
plateNumber,
|
|
35329
|
+
site: siteObjectId,
|
|
35330
|
+
status: { $ne: "deleted" /* DELETED */ }
|
|
35331
|
+
});
|
|
35302
35332
|
if (existingPlateNumber) {
|
|
35303
35333
|
throw new import_node_server_utils99.BadRequestError(`Vehicle plate number ${plateNumber} already exists.`);
|
|
35304
35334
|
}
|
|
@@ -35472,17 +35502,12 @@ function useVehicleService() {
|
|
|
35472
35502
|
throw new import_node_server_utils99.BadRequestError(message);
|
|
35473
35503
|
import_node_server_utils99.logger.warn(`deleteVehicle bypassed a failed ANPR revoke: ${message}`);
|
|
35474
35504
|
}
|
|
35475
|
-
await
|
|
35476
|
-
|
|
35477
|
-
|
|
35478
|
-
|
|
35479
|
-
|
|
35480
|
-
|
|
35481
|
-
recno,
|
|
35482
|
-
{ peopleId: vehicle?.peopleId, site, plateNumber },
|
|
35483
|
-
session
|
|
35484
|
-
)
|
|
35485
|
-
]);
|
|
35505
|
+
await _deleteVehicle(_id, session);
|
|
35506
|
+
await _pullVehicleByRecNo(
|
|
35507
|
+
recno,
|
|
35508
|
+
{ peopleId: vehicle?.peopleId, site, plateNumber },
|
|
35509
|
+
session
|
|
35510
|
+
);
|
|
35486
35511
|
await session.commitTransaction();
|
|
35487
35512
|
return `Vehicle plate number deleted from ${type} record successfully.`;
|
|
35488
35513
|
} catch (error) {
|