Skip to content

Test Cases: Inventory

ModuleCORE-06URDInventory URD

1. Coverage Summary

AreaURD reqsTest casesCovered
Location (LOC)1020
Item (ITM)610
Stock (STK)711
Tracking (TRK)1013
Vendor (VEN)57
Purchase Order (PO)1226
PO Item (POI)512
Material (MAT)1313
Material Recipe / BOM (REC)2421⚠️
Constraints (CON)48

Priority below = P1 (critical / Must) · P2 (major / Should) · P3 (minor / Could). One gap is open: TC-REC-206 (non-default kitchen location) is blocked on a code TODO.

2. Test Cases

TC-<AREA>-NNN lines up with URD-<AREA>-NNN.

Location (LOC)

TC IDURD refScenarioStepsExpectedP
TC-LOC-001URD-LOC-001, 007, 010Create location with i18n nameAuthenticated merchant creates a location with a valid nameLocation created; LOC_YYYYMMDD_id assigned; linked to exactly one merchantP1
TC-LOC-002URD-LOC-001Create without nameAttempt to create a location with no nameRejected; "name required" errorP1
TC-LOC-003URD-LOC-001Multilingual nameProvide name in en + viCreated with all locales stored and retrievableP1
TC-LOC-004URD-LOC-007Identifier formatCreate any locationIdentifier matches LOC_YYYYMMDD_id; unique; not user-editableP1
TC-LOC-005URD-LOC-007Same-day uniquenessCreate two locations on the same dateSame date segment, distinct trailing id; both globally uniqueP1
TC-LOC-006URD-LOC-002Default auto-createComplete commerce initializationExactly one default location auto-created and usableP1
TC-LOC-007URD-LOC-003Switch defaultMark a second location as defaultNew location becomes default; previous default clearedP1
TC-LOC-008URD-LOC-003Delete sole defaultDelete/deactivate the only default without replacementRejected; merchant must always have one defaultP1
TC-LOC-009URD-LOC-004Child locationCreate a child under a parentChild references parent; parent lists childrenP2
TC-LOC-010URD-LOC-004Delete parent with childrenDelete a parent that has childrenRejected or cascades; no orphans; integrity preservedP2
TC-LOC-011URD-LOC-005Store geo dataUpdate location with address + GPSGeographic data stored and retrievableP2
TC-LOC-012URD-LOC-005Missing geo dataCreate location with no address/coordsCreated; geo fields null; no validation errorP2
TC-LOC-013URD-LOC-006ActivateActivate a NEW locationStatus NEW → ACTIVATED; usable for stockP1
TC-LOC-014URD-LOC-006DeactivateDeactivate an ACTIVATED locationStatus → DEACTIVATED; no new assignments; stock preservedP1
TC-LOC-015URD-LOC-006ArchiveArchive a DEACTIVATED locationStatus → ARCHIVED; data preserved; removed from active listsP1
TC-LOC-016URD-LOC-006Invalid skipNEW → ARCHIVED directlyRejected; invalid transitionP1
TC-LOC-017URD-LOC-006Reactivate archivedReactivate an ARCHIVED locationRejected; ARCHIVED is terminalP1
TC-LOC-018URD-LOC-008Soft deleteSoft-delete a locationFlagged deleted; absent from active lists; data preserved; admin can retrieveP1
TC-LOC-019URD-LOC-009Filter by statusList filtered by ACTIVATED (3 active, 2 inactive)Only the 3 ACTIVATED returnedP2
TC-LOC-020URD-LOC-009, 010Merchant isolationMerchant A lists locationsOnly A's locations returned; B's hiddenP2

Inventory Item (ITM)

TC IDURD refScenarioStepsExpectedP
TC-ITM-001URD-ITM-001, 006Auto-create on variantCreate a product variantItem auto-created, linked to default location, system identifierP1
TC-ITM-002URD-ITM-002UniquenessCreate a 2nd item for same (variant, location, unit)Rejected; uniqueness enforced; existing item unchangedP1
TC-ITM-003URD-ITM-002Different unit coexistsCreate item for same variant+location, unit BOX vs PCSNew item created; both coexist; uniqueness is per (variant, location, unit)P1
TC-ITM-004URD-ITM-004Identifier formatCreate any itemIdentifier SKU_YYYYMMDD_id; unique; not editableP1
TC-ITM-005URD-ITM-005DeactivateDeactivate an ACTIVATED itemStatus → DEACTIVATED; excluded from active stock queriesP1
TC-ITM-006URD-ITM-005ArchiveArchive a DEACTIVATED itemStatus → ARCHIVED; data preserved; removed from listingsP1
TC-ITM-007URD-ITM-005Reactivate archivedReactivate an ARCHIVED itemRejected; ARCHIVED is terminalP1
TC-ITM-008URD-ITM-003Set thresholdsSet min=10, max=500Both thresholds stored and retrievableP2
TC-ITM-009URD-ITM-003Low-stock triggerOn-hand drops to 9 (below min 10)Low-stock condition detected; event triggered/loggedP2
TC-ITM-010URD-ITM-003Invalid thresholdsSet min > maxRejected; min must be ≤ maxP2

Stock (STK)

TC IDURD refScenarioStepsExpectedP
TC-STK-001URD-STK-001, 002Available formulaQuery stock with on-hand 100, reserved 30Available = 70 (on-hand − reserved)P1
TC-STK-002URD-STK-002Zero availableReserved equals on-handAvailable = 0; not an errorP1
TC-STK-003URD-STK-003Decimal precisionStore quantity 10.12345Rounded/truncated to 4 decimal placesP1
TC-STK-004URD-STK-003Max boundaryStore 999999999999999.9999Persisted without overflowP1
TC-STK-005URD-STK-004First receiptFirst stock receipt for a new itemStock record created; on-hand = received; reserved 0; available = on-handP1
TC-STK-006URD-STK-004Deduct before receiptDeduct from an item with no stockEither rejected (insufficient) or negative tolerated per URD-CON-003; behavior consistentP1
TC-STK-007URD-STK-005Counted timestampComplete a physical countlastCountedAt updated to nowP2
TC-STK-008URD-STK-005Stocked timestampComplete a stock receiptlastStockedAt updated to nowP2
TC-STK-009URD-STK-006Concurrent deductTwo concurrent sales deduct 5 each from on-hand 10Total deduction exactly 10; no double-count; final on-hand 0P1
TC-STK-010URD-STK-006Atomic rollbackStock update fails mid-operationEntire update rolls back; orphan tracking not persistedP1
TC-STK-011URD-CON-003Negative availableSale of 8 from on-hand 5Available becomes −3; not rejected; stored and visible; warning loggedP1

QE finding (TC-STK-011): the service intentionally tolerates negative quantityAvailable ("refactor when business logic clearer"). This is a documented business constraint (URD-CON-003), not a bug — but downstream POS checkout must prevent or surface it, or it becomes a data-integrity risk.

Tracking (TRK)

TC IDURD refScenarioStepsExpectedP
TC-TRK-001URD-TRK-001, 002Inbound entryPO receipt of 20 unitsImmutable entry: before/change (+20)/after; cannot be edited or deletedP1
TC-TRK-002URD-TRK-001, 002Outbound entrySale deduction of 3 unitsEntry: before/change (−3)/after; direction OUT; persistedP1
TC-TRK-003URD-TRK-002Boundary from zeroPURCHASE_IN of 50 from on-hand 0before 0, change +50, after 50P1
TC-TRK-004URD-TRK-003PO referenceMovement triggered by a POEntry stores referenceType=PURCHASE_ORDER + PO id; traceableP1
TC-TRK-005URD-TRK-003Sale referenceMovement triggered by sale paymentEntry stores referenceType=SALE_ORDER + order idP1
TC-TRK-006URD-TRK-003Missing referenceMovement with no valid referenceRejected, or entry flagged; audit traceability not silently lostP1
TC-TRK-007URD-TRK-004Idempotent replayReplay an already-processed payment-success eventNo second deduction; on-hand unchanged; no duplicate entry; returns successP1
TC-TRK-008URD-TRK-004Distinct concurrentTwo different sale orders deduct same item near-simultaneouslyEach processed exactly once; neither skipped nor doubledP1
TC-TRK-009URD-TRK-005IN directionProcess a PURCHASE_INDirection IN; on-hand increasesP1
TC-TRK-010URD-TRK-005OUT directionProcess a SALE_OUTDirection OUT; on-hand decreasesP1
TC-TRK-011URD-TRK-005NEUTRAL directionProcess ADJUSTMENT_NEUTRALDirection NEUTRAL; no net change; entry persisted for auditP1
TC-TRK-012URD-TRK-005Invalid typeCreate entry with unrecognized typeRejected; "not a valid tracking type" (19 + custom enumerated)P1
TC-TRK-013URD-TRK-006Audit fieldsUser triggers a movementEntry stores createdBy/modifiedBy of the authenticated userP2

Note (TC-TRK-007): the sync and queue payment-success paths duplicate the deduction logic with different error messages. Both must independently pass idempotency; a future refactor should unify them.

Vendor (VEN)

TC IDURD refScenarioStepsExpectedP
TC-VEN-001URD-VEN-001, 002, 005Create vendorCreate a vendor with name + contactCreated; VEN_YYYYMMDD_id assigned; linked to one merchantP1
TC-VEN-002URD-VEN-001Create without nameCreate a vendor with no nameRejected; "name required"P1
TC-VEN-003URD-VEN-003Tax numberProvide a tax registration numberStored and retrievableP2
TC-VEN-004URD-VEN-002Identifier formatCreate any vendorIdentifier VEN_YYYYMMDD_id; uniqueP1
TC-VEN-005URD-VEN-004Soft delete (unused)Soft-delete a vendor with no active POFlagged deleted; absent from active lists; data preservedP1
TC-VEN-006URD-VEN-004Soft delete (in use)Delete a vendor referenced by active POsRejected (in use) or proceeds preserving PO references; no orphansP1
TC-VEN-007URD-VEN-005Merchant isolationMerchant A lists vendorsOnly A's vendors returned; B's hiddenP1

Purchase Order (PO)

TC IDURD refScenarioStepsExpectedP
TC-PO-001URD-PO-001, 012Create with itemsCreate PO with vendor + items in one callDRAFT; PO number assigned; items + merchant linkedP1
TC-PO-002URD-PO-001Create without vendorCreate a PO with no vendorRejected; "vendor required"P1
TC-PO-003URD-PO-009Default locationCreate PO without a locationAssigned to merchant default locationP1
TC-PO-004URD-PO-009Explicit locationCreate PO with a non-default locationAssigned to the specified location; default not overriddenP1
TC-PO-005URD-PO-002ConfirmConfirm a DRAFT PO with ≥1 itemDRAFT → PROCESSINGP1
TC-PO-006URD-PO-002, 004RevertRevert a PROCESSING POPROCESSING → DRAFT; items intactP1
TC-PO-007URD-PO-002, 007ReceiveReceive a PROCESSING POPROCESSING → RECEIVED; stock updated via trackingP1
TC-PO-008URD-PO-002CompleteComplete a RECEIVED PORECEIVED → COMPLETEDP1
TC-PO-009URD-PO-002CloseClose a COMPLETED POCOMPLETED → CLOSEDP1
TC-PO-010URD-PO-003Cancel DRAFTCancel a DRAFT PO→ CANCELLED; data preserved; no stock movementP1
TC-PO-011URD-PO-003Cancel PROCESSINGCancel a PROCESSING PO→ CANCELLED; no stock movementP1
TC-PO-012URD-PO-003Cancel RECEIVEDCancel a RECEIVED PO→ CANCELLED; received stock NOT auto-reversedP1
TC-PO-013URD-PO-003Cancel CLOSEDCancel a CLOSED PORejected; CLOSED is terminalP1
TC-PO-014URD-PO-003Re-cancelCancel a CANCELLED PORejected; already cancelledP1
TC-PO-015URD-PO-002Invalid skipDRAFT → RECEIVED directlyRejected; invalid transitionP1
TC-PO-016URD-PO-002From terminalCLOSED → any non-terminalRejected; CLOSED is terminalP1
TC-PO-017URD-PO-002BackwardCOMPLETED → RECEIVEDRejected; backward transition not permittedP1
TC-PO-018URD-PO-002Complete endpointCall complete on a RECEIVED PO→ COMPLETED, no errorP1
TC-PO-019URD-PO-006Confirm empty POConfirm a DRAFT PO with zero itemsRejected; "must have at least one item"P1
TC-PO-020URD-PO-008OVERRIDE receiveReceive 50 in OVERRIDE on on-hand 20On-hand set to 50; prior balance discarded; PURCHASE_IN trackedP1
TC-PO-021URD-PO-008ACCUMULATIVE receiveReceive 50 in ACCUMULATIVE on on-hand 20On-hand 70; prior balance preserved; change +50P1
TC-PO-022URD-PO-008Modes from zeroReceive 50 both modes on on-hand 0Both yield 50P1
TC-PO-023URD-PO-010Total computationsubtotal 1,000,000; discount 50,000; tax 50,000total = 1,000,000; all summary fields consistentP1
TC-PO-024URD-PO-010Zero discount/taxsubtotal 100,000; discount 0; tax 0total = 100,000P1
TC-PO-025URD-PO-011Manual discount flagEnter discount manuallyMetadata flags discount as manualP2
TC-PO-026URD-PO-011Auto tax flagSystem calculates taxMetadata flags tax as auto-calculatedP2

QE finding (TC-PO-018): completePurchaseOrder has an inverted guard — it currently throws when the PO IS in RECEIVED/COMPLETED, the opposite of intended. As written, only POs in other statuses can be "completed". TC-PO-018 fails against the current implementation — a blocking defect for the complete flow.

Purchase Order Item (POI)

TC IDURD refScenarioStepsExpectedP
TC-POI-001URD-POI-001AccumulateAdd same (type, id, uom) again, qty +5Existing line incremented to 15; no duplicate rowP1
TC-POI-002URD-POI-001Distinct itemsAdd variant V1 and V2Two separate lines; tracked independentlyP1
TC-POI-003URD-POI-001Different uomAdd same variant, uom BOX vs PCSNew line; no accumulation across differing uomP1
TC-POI-004URD-POI-002Line totalunitPrice 10,000 × qty 5 × mult 1 + tax 500 − disc 200itemTotal = 50,300; DB-computedP1
TC-POI-005URD-POI-002Zero priceunitPrice 0, qty 1itemTotal = 0; no errorsP1
TC-POI-006URD-POI-003Zero quantity removesSet a DRAFT item qty to 0Soft-deleted; absent from list; PO total recalculatesP1
TC-POI-007URD-POI-003Negative removesSet a DRAFT item qty to −1Soft-deleted (qty ≤ 0 triggers deletion)P1
TC-POI-008URD-POI-003, PO-005Edit after confirmSet item qty 0 on a PROCESSING PORejected; items only editable in DRAFTP1
TC-POI-009URD-PO-005Add after receiveAdd a new item to a RECEIVED PORejected; items only modifiable in DRAFTP1
TC-POI-010URD-PO-005Edit in DRAFTAdd/update/remove items on a DRAFT POAll succeed; summary recalculates each changeP1
TC-POI-011URD-POI-004Price defaultAdd item without unit price (variant cost 8,000)unitPrice defaults to 8,000P2
TC-POI-012URD-POI-005UOM defaultAdd item without uom (base unit PCS)uom defaults to PCSP2

Material (MAT)

TC IDURD refScenarioStepsExpectedP
TC-MAT-001URD-MAT-001, 002Create materialCreate material with i18n namePersisted; MAT_YYYYMMDD_id; status ACTIVATEDP1
TC-MAT-002URD-MAT-002Unique identifiersRapidly create multiple materialsEach has a unique MAT_YYYYMMDD_idP1
TC-MAT-003URD-MAT-003Multilingual nameProvide name in en + viAll locales stored and retrievableP1
TC-MAT-004URD-MAT-004Update descriptionUpdate a material's descriptionPersisted; modifiedAt updatedP1
TC-MAT-005URD-MAT-005DeactivateDeactivate an activated materialStatus DEACTIVATED; still readable; not added to new recipesP1
TC-MAT-006URD-MAT-006ArchiveArchive a materialStatus ARCHIVED; permanently read-onlyP1
TC-MAT-007URD-MAT-007Duplicate identifierCreate material with duplicate identifierUnique constraint rejects the insertP1
TC-MAT-101URD-MAT-101Attach barcodeAttach a BARCODE identifierIdentifier row persisted with scheme BARCODEP1
TC-MAT-102URD-MAT-102All schemesAttach SYSTEM, SLUG, SKU, BARCODE, QRCODEAll five persist and are retrievableP1
TC-MAT-103URD-MAT-103Duplicate (scheme, code)Register an existing (BARCODE, code) on another materialRejected by unique indexP1
TC-MAT-104URD-MAT-104Scheme defaultCreate identifier without schemeScheme defaults to SYSTEMP1
TC-MAT-105URD-MAT-105Multiple schemesAdd a 2nd identifier of a different schemeBoth coexist; neither replaces the otherP2
TC-MAT-106URD-MAT-106Search by barcodeSearch by a registered barcodeThe material is returned as the single matchP2

Material Recipe / BOM (REC)

TC IDURD refScenarioStepsExpectedP
TC-REC-001URD-REC-001, 002Create recipeCreate a recipe for PV_X with 3 itemsPersisted with version 1.0; 3 items linkedP1
TC-REC-002URD-REC-002Version defaultCreate a recipe with no versionVersion defaults to 1.0P1
TC-REC-003URD-REC-003Duplicate (principal, version)Create a 2nd recipe with same tripleRejected by unique constraintP1
TC-REC-004URD-REC-004, 005Add itemAdd a recipe item (material, qty, unit)New row persisted with all fieldsP1
TC-REC-005URD-REC-006Duplicate materialAdd a material already in the recipeRejected by unique constraintP1
TC-REC-006URD-REC-007ActivateActivate a DRAFT recipeStatus ACTIVATEDP1
TC-REC-007URD-REC-008DeactivateDeactivate an ACTIVATED recipeStatus DEACTIVATEDP1
TC-REC-008URD-REC-009New versionAdd a new row same principal version 1.1Original preserved; new row insertedP2
TC-REC-009URD-REC-010List versionsQuery recipes by principal (1.0, 1.1, 2.0)All three versions returnedP2
TC-REC-010URD-REC-011Runtime resolves activatedQuery by (principal, status=ACTIVATED) with only 2.0 activeOnly the 2.0 recipe returnedP1
TC-REC-101URD-REC-101Valid material FKCreate a recipe itemFK resolves to an existing materialP1
TC-REC-102URD-REC-102Quantity precisionCreate item with qty 0.0125Persisted at 4-decimal precisionP1
TC-REC-103URD-REC-103Unit storedCreate item with unit 'ml'Unit stored as mlP1
TC-REC-104URD-REC-104Edit quantityUpdate item qty 200 → 250Quantity updated; modifiedAt bumpsP1
TC-REC-105URD-REC-105Soft-delete re-addRemove an item then re-add same materialRow soft-deleted; re-add allowedP1
TC-REC-201URD-REC-201, 204Explosion triggerKitchen-ticket-item status change for PV_X with activated recipeWorker looks up recipe, finds default location, prepares decrementsP1
TC-REC-202URD-REC-202, 203Component decrementFor each recipe item during explosionMaterial stock at default location decremented; USED_AS_MATERIAL tracking createdP1
TC-REC-203URD-REC-205Emit eventExplosion completesmaterial.stock-changed event emittedP1
TC-REC-204URD-REC-206No default locationKitchen status change, merchant has no default locationWarning logged, decrement skipped, no hard errorP2
TC-REC-205URD-REC-207No activated recipeKitchen status change, variant has no activated recipe"Recipe Not Found" logged; no decrementP2
TC-REC-206URD-REC-208Non-default kitchen locationExplosion runs for a kitchen on a non-default locationGAP — code uses merchant default location (TODO); blocked until resolvedP3

Constraints (CON)

TC IDURD refScenarioStepsExpectedP
TC-CON-001URD-CON-001No tokenCall any endpoint with no authHTTP 401; no dataP1
TC-CON-002URD-CON-001Expired tokenCall any endpoint with an expired JWTHTTP 401; no dataP1
TC-CON-003URD-CON-001Valid JWTCall any endpoint with a valid JWTAuthenticated; responds with dataP1
TC-CON-004URD-CON-001Basic authCall any endpoint with valid basic authAuthenticated; responds normallyP1
TC-CON-005URD-CON-002Admin retrieve deletedAdmin queries including soft-deleted recordsRecord retrievable; fields intact; delete flag set; excluded from standard listsP1
TC-CON-006URD-CON-002Standard list excludes deletedStandard listing of a soft-deleted locationExcluded; no errorP1
TC-CON-007URD-CON-004Idempotent replayReplay payment-success for SO-001No second deduction; on-hand unchanged; duplicate silently acknowledgedP1
TC-CON-008URD-CON-004Concurrent idempotencyIdempotency check during in-flight deduction for same orderExactly one deduction; second skips; no race-driven double deductionP1

3. Traceability

Every Must requirement maps to ≥1 test case. One gap is flagged below.

URD requirementTest case(s)Status
URD-LOC-001…010TC-LOC-001…020✅ Covered
URD-ITM-001…006TC-ITM-001…010✅ Covered
URD-STK-001…006TC-STK-001…010✅ Covered
URD-STK-007⚠️ Uncovered (Could — historical stock view)
URD-TRK-001…010TC-TRK-001…013✅ Covered
URD-VEN-001…005TC-VEN-001…007✅ Covered
URD-TKT-001…006⚠️ Uncovered (ticket flows pending build)
URD-PO-001…012TC-PO-001…026✅ Covered
URD-POI-001…005TC-POI-001…012✅ Covered
URD-MAT-001…106TC-MAT-001…106✅ Covered
URD-REC-001…207TC-REC-001…205✅ Covered
URD-REC-208TC-REC-206⚠️ Gap — pending code TODO in MaterialWorkerService
URD-CON-001…004TC-CON-001…008, TC-STK-011, TC-TRK-007✅ Covered

Summary: ~96 URD requirements → 131 test cases · 1 known gap (TC-REC-206) · Must-level coverage complete except inventory tickets (TKT), which are not yet built (see URD §5.5).

4. References

DocumentDescription
Inventory URDRequirement source for all TC traceability
Inventory overviewModule identity, capabilities, flows
Developer docs — @nx/inventoryImplementation detail and verified behavior

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.