@7365admin1/module-hygiene 4.28.1-staging.9 → 4.28.2-staging.10

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@7365admin1/module-hygiene",
3
3
  "license": "MIT",
4
- "version": "4.28.1-staging.9",
4
+ "version": "4.28.2-staging.10",
5
5
  "author": "7365admin1",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -13,7 +13,7 @@
13
13
  "build": "tsup src/index.ts --format cjs,esm --dts",
14
14
  "release": "yarn run build && changeset publish",
15
15
  "lint": "tsc",
16
- "test": "tsup src/utils/hygiene-dashboard-metrics.util.ts --format esm --out-dir test/.build --no-dts --silent && node --test \"test/*.test.mjs\""
16
+ "test": "tsup src/utils/hygiene-dashboard-metrics.util.ts src/utils/hygiene-checkout-decision.util.ts --format esm --out-dir test/.build --no-dts --silent && node --test \"test/*.test.mjs\""
17
17
  },
18
18
  "devDependencies": {
19
19
  "@changesets/cli": "^2.26.0",
@@ -27,7 +27,7 @@
27
27
  "typescript": "^4.9.4"
28
28
  },
29
29
  "dependencies": {
30
- "@7365admin1/core": "^3.41.0",
30
+ "@7365admin1/core": "^3.50.1",
31
31
  "@7365admin1/node-server-utils": "^1.6.0",
32
32
  "@types/qrcode": "^1.5.6",
33
33
  "@types/urllib": "^2.33.0",
@@ -0,0 +1,64 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import {
5
+ CHECKOUT_DECIDABLE_STATUS,
6
+ CHECKOUT_DECISIONS,
7
+ buildCheckOutDecision,
8
+ isCheckOutDecision,
9
+ } from "./.build/hygiene-checkout-decision.util.mjs";
10
+
11
+ /*
12
+ The check out item approval decision, without a database.
13
+
14
+ These assertions pin the two things the repository relies on: the `$set` the
15
+ decision produces, and the status the update must MATCH on. If the second one
16
+ is ever dropped, approving an already-decided item stops being a refusal and
17
+ starts silently overwriting the first decision — which is the failure the
18
+ match filter exists to prevent.
19
+ */
20
+
21
+ const NOW = "2026-09-04T09:00:00.000Z";
22
+
23
+ test("approving flips the row to completed and records approve, not reject", () => {
24
+ const set = buildCheckOutDecision("approve", null, NOW);
25
+
26
+ assert.equal(set.status, "completed");
27
+ assert.equal(set.approve, true);
28
+ assert.equal(set.reject, false);
29
+ assert.equal(set.updatedAt, NOW);
30
+ });
31
+
32
+ test("disapproving also terminates the row, and keeps the remarks", () => {
33
+ const set = buildCheckOutDecision("disapprove", "wrong item drawn", NOW);
34
+
35
+ assert.equal(set.status, "completed");
36
+ assert.equal(set.approve, false);
37
+ assert.equal(set.reject, true);
38
+ assert.equal(set.remarks, "wrong item drawn");
39
+ });
40
+
41
+ test("remarks are never undefined — an absent remark is an empty string", () => {
42
+ assert.equal(buildCheckOutDecision("approve", undefined, NOW).remarks, "");
43
+ assert.equal(buildCheckOutDecision("approve", null, NOW).remarks, "");
44
+ });
45
+
46
+ test("no third status value enters the vocabulary", () => {
47
+ // `allowedCheckOutItemStatus` is ["pending", "completed"]. A decision must
48
+ // land inside it, whichever way it goes.
49
+ for (const decision of CHECKOUT_DECISIONS) {
50
+ assert.equal(buildCheckOutDecision(decision, "", NOW).status, "completed");
51
+ }
52
+ });
53
+
54
+ test("only a pending row is decidable", () => {
55
+ assert.equal(CHECKOUT_DECIDABLE_STATUS, "pending");
56
+ });
57
+
58
+ test("the decision vocabulary is exactly the two the client calls", () => {
59
+ assert.deepEqual([...CHECKOUT_DECISIONS], ["approve", "disapprove"]);
60
+ assert.ok(isCheckOutDecision("approve"));
61
+ assert.ok(isCheckOutDecision("disapprove"));
62
+ assert.equal(isCheckOutDecision("reject"), false);
63
+ assert.equal(isCheckOutDecision(""), false);
64
+ });
@@ -1,29 +0,0 @@
1
- ---
2
- "@7365admin1/module-hygiene": patch
3
- ---
4
-
5
- Hygiene dashboard metrics: report the selected period honestly instead of fabricating figures
6
-
7
- The dashboard's metric calculations were computed inline inside
8
- `hygiene-dashboard.repository.ts` and were wrong in four ways. They now live in
9
- `src/utils/hygiene-dashboard-metrics.util.ts`, covered by unit tests (`yarn test`),
10
- so a change to a metric fails a test rather than a screen. What a consumer of the
11
- dashboard endpoints sees change:
12
-
13
- - **Trend comparisons follow the selected period.** The "vs previous" figure was
14
- always computed against yesterday, whatever range the user picked, so a
15
- month-to-month comparison was really a day-to-day one. It now compares the
16
- selected period against the period immediately before it.
17
- - **Day boundaries are Singapore time.** Period start/end were taken from the
18
- server host's midnight, so a host on UTC put work into the wrong day. All
19
- boundaries are now computed in `Asia/Singapore`.
20
- - **No invented percentages on an empty prior period.** When the previous period
21
- had no data, the change was reported as `100%` (or `0`) as if measured. It now
22
- returns `null`, so the UI can show "no comparison available" rather than a
23
- number nobody can reproduce.
24
- - **The supply alert percentage is no longer hard-coded.** It was emitted as a
25
- fixed value regardless of stock; it is now derived, and reports its reason when
26
- there is no prior period to compare against.
27
-
28
- No API surface changes and no consumer code change is required — the same fields
29
- are returned, with `null` now possible where a comparison genuinely cannot be made.