Commit Graph
3 Commits
Author SHA1 Message Date
toanhoang 03d74d69c1 Rename AssetItemStatus 'assigned' to 'in_use'
CI / test (push) Failing after 9s
'assigned' implied a specific person always holds the item, but
createAssignment() only requires status=in_stock to hand something out --
the status value itself never guaranteed a matching Assignment row exists.
~158 of the 613 real-imported assets carry this status with no Assignment
at all (shared/unowned equipment like meeting-room gear), so "assigned"
was actively misleading for them. 'in_use' doesn't carry that implication.

DB: `ALTER TYPE "AssetItemStatus" RENAME VALUE 'assigned' TO 'in_use'`
(hand-written migration -- runs cleanly, no data migration needed, every
existing row's status just reads under the new name). Renamed across:
schema.prisma enum, src/lib/assets.ts (type union + IMPORT_STATUS_MAP,
which keeps an `assigned` key mapped to `in_use` for backward-compat with
pre-2026-08-25 exports/CSVs), src/lib/assignments.ts (the literal status
value createAssignment() sets), src/app/assets/page.tsx + api/assets/
route.ts (filter dropdown + validStatuses), src/app/maintenance-records/
page.tsx (its own copy of the status list for the "close" targetStatus
picker). maintenance-records.ts itself needed no logic change -- its
closeableTargetStatusValues was already just ["in_stock", "retired"],
"assigned" was never a valid close target, only mentioned in comments
(updated for accuracy).

Also fixes a real regression found while verifying this: tests/
assets.test.ts (a pre-existing, properly-reviewed test file, not written
this session) broke 2 commits ago when GET /api/assets's signature and
response shape changed for pagination -- it still called GET() with no
Request and expected a bare array. tsc didn't catch this until now
because this container has no dev bind mount (Dockerfile is COPY-based,
`docker exec` only reflects the last build) -- see the
ubi-dan-itam-docker-no-bind-mount memory note. Added a getRequest()
helper and updated assertions to the {items, total} shape.

Verified by actually rebuilding and running the full suite fresh (not
just tsc/lint smoke checks): 369/369 tests pass, including
assignments.test.ts and maintenance-records.test.ts, which this rename
touches directly. tsc/lint clean against the rebuilt image. Migration
applied to the real DB, data verified intact (542 in_use + 71 in_stock =
613, matches pre-rename counts exactly).
2026-08-24 21:57:33 -04:00
toanhoang a9dafcc140 fix: add atomic Assignment transfer (close old + create new in one transaction)
The only way to move an Assignment to a new employee was two separate calls
(PATCH return + POST create), which is not atomic and left a race window
where a third party could grab the now-in_stock AssetItem in between, plus
no rollback if the second call failed. Adds transferAssignment() which
closes the old Assignment and creates the new one inside a single
prisma.$transaction(), per docs/asset-license-management.md's "Assignment
(chốt 2026-08-02)" spec. Does not touch AssetItem.status or
License.seatsUsed — the resource never becomes free mid-transfer. Wired
into PATCH /api/assignments/[id]: an employeeId key in the body dispatches
to transfer, a returnedAt key to return, both together is rejected as
mutually exclusive.
2026-08-03 19:46:43 -04:00
toanhoang 6b39c01f4e test: add Assignment API tests
48 tests covering the XOR validation, the AssetItem.status/active-assignment
preconditions, seat overbooking, seat/status sync across assign+return,
FK-not-found for all three FKs, double-return, 404s, auth-gating, malformed
bodies, and two explicit concurrency tests (Promise.all against a
1-remaining-seat License and against a single in_stock AssetItem) exercising
the transaction race-closing logic in src/lib/assignments.ts.
2026-08-02 21:19:40 -04:00