Inventory Physical Stock QA
Manual checks for U3 receipts, transfers, corrections, expiry approval, and retry recovery.
This guide covers Inventory U3 source services. It does not confirm Hospital UI integration. Use a disposable local test database. U5 now provides source HTTP routes; use the HTTP QA guide for authenticated request checks. Use the API contract and developer guide.
Setup
- Use two facilities and two tenants. Assign a stock manager to one facility only.
- Set a valid facility timezone. Use View and Manage grants for receipts and transfers.
- Grant adjustments separately for corrections, write-offs, expiry corrections, and reversals.
- Create an item and two locations. Record the current stock and operation count.
- Do not use a patient ID, case ID, patient name, or clinical note as a stock source reference.
Physical Commands
Invoke Inventory::CommandContext.call in an explicit tenant context.
Pass the authenticated user, authorized facility, kind, operation_key, and command input.
Quantities are decimal strings. A result has success?, operation, error_code, replayed, and outcome.
- Receive five units. Check one operation, one positive movement, and five on hand.
- Retry the same key and source with quantity
5.0. Check the same operation and no extra quantity or audit event. - Change the quantity with that key. Check
OPERATION_KEY_REUSEDand unchanged stock. - Use a new key for the same source row. Check
DUPLICATE_SOURCEand unchanged stock. - Transfer two units. Check matching debit and credit entries and no net stock change.
- Request more than free stock. Check
INSUFFICIENT_STOCK, no partial effect, and no occupied key. - Record a real receipt. Retry the original failed key. Check one new confirmed transfer.
- Reject a foreign destination before evaluating an invalid quantity. Do not show foreign stock details.
- Apply a count correction with a count reference and reason. Check appended history.
- Write off expired or quarantined stock with a reason. Do not make free stock negative.
- Reverse part of a receipt. Reject compensation above its remaining quantity or available stock.
- Receive a serial at one location. Reject a second live unit at any location under another source or key.
- Test a fractional countable quantity, excess precision, invalid unit, and unknown clinical field. Check no effect.
Expiry Approval
There is no default interpretation. A facility inventory or pharmacy lead must approve the rule before pilot use.
An authorized backend operator records that decision with Inventory::ExpiryApproval.approve!.
The actor needs View, Manage, and adjustments at that facility. There is no public approval route in U3.
Record the chosen label precision, rule, and version. The service stores the facility timezone and actor.
period_start and next_period_start describe calendar boundaries. Neither is a default clinical policy.
explicit_instant requires an ISO instant with an explicit UTC offset.
- Create approval evidence only after the facility lead approves the interpretation.
- Validate an unresolved lot with its expected version and scoped approval reference.
- Check the stored source label, rule, version, timezone, UTC cutoff, reason, and operation.
- Check no movement, physical-stock change, or silent reservation release.
- Correct a validation with adjustments permission. Check the prior revision remains readable.
- Retry the initial validation after a correction. Check the original operation and revision return.
- Remove adjustments permission. Check an initial validation retry still works but a new correction fails.
- Reject stale versions, revoked approval, foreign approval, unapproved rules, and browser cutoff/timezone fields.
- Reject a missing or invalid facility timezone. Do not choose a fallback timezone.
Transaction And Recovery
- Roll back the outer caller transaction. Check no stock effect, operation identity, expiry revision, or confirmed audit event remains.
- Fail the required audit write. Check the stock command does not report success or retain a partial effect.
- Simulate a lost connection after commit. Check
outcome: unknown, not a claim that no effect exists. - Keep the original key after a timeout or unavailable/empty lookup. Retry identical input to resolve the result.
- Submit concurrent first receipts, identical retries, duplicate serial receipts, expiry validations, and partial reversals.
- Check one balance identity, one effect per key/source, one version winner, and no negative quantity.
- Check movement totals equal every affected on-hand projection.
Automated Evidence
Run with PARALLEL_WORKERS=1 against the disposable database:
bin/rails db:test:prepare db:rls_test_role:provision
bin/rails test domains/inventory/test domains/identity/test/rbacThe concurrency suite uses independent database connections. RLS checks use the non-bypass role. Operator QA, broad CI, deployment, and Hospital integration are separate gates.