addProcess
addProcess creates a new process โ the workflow definition that purchase orders later flow through. You name the workflow, describe it, attach it to an organization (and optionally narrow it to a specific unit or product), and it lands in the database as a Draft. Only Manager/Admin users can create processes; you'll add steps with addProcessStep and switch it to Active with activateProcess before any purchase order can run on it.
getProcesses
getProcesses lists the process documents for the workflow chapter. It's a read-only aggregation that lets you filter by organization and status and returns the newest processes first (sorted by createdAt descending). Every authenticated role can call it โ it's what the UI uses to show the process list before you open one and add steps.
activateProcess
activateProcess turns a Draft process into an Active one. Only an active process can be resolved for a purchase order โ resolveProcessForPO filters strictly on status: "Active" โ so this is a mandatory step between defining a workflow and submitting POs against it. It refuses to activate a process twice, and it refuses to activate a process that has no steps yet. Only Manager/Admin users can call it.
addProcessStep
addProcessStep adds one ordered step to a process. A step names an approval gate, gives it an order number (steps run in ascending order), and declares who must approve it via groupsOperator + assigneeGroups โ the AND/OR logic that evaluateStepStatus later interprets. Only Manager/Admin users can create steps. A process needs at least one step before activateProcess will accept it.
getProcessSteps
getProcessSteps lists the processStep documents of one process in ascending order. It's the read-side companion to addProcessStep โ you use it to review the approval chain before activating, and the submit flow itself reuses the same query internally. Every authenticated role can call it.
add (purchaseOrder)
add creates the core procurement document โ a purchaseOrder. It's where you capture the request: who is asking (requester), what they want (product), which organization/unit it belongs to, an estimated cost, and an optional budgetLine to encumber. The PO is created as a Draft with an initial history entry of "created". If you don't pass a process explicitly, the fn resolves one automatically via resolveProcessForPO. This is the first of many purchaseOrder acts โ everything else in the chapter reads or mutates what you create here.
gets (purchaseOrder)
gets is the paginated, filterable list endpoint for purchase orders โ the workhorse of any PO dashboard. It supports full-text search, filtering by status, organization, requestingUnit, or requester, and page/limit/skip pagination. It runs two queries in parallel (items + total count) and returns a { items, total, page, limit } envelope. Every authenticated role can call it.
get (purchaseOrder)
get fetches a single purchase order by _id with the full depth-2 projection โ including related snapshots like requester, product, process, stepApprovals, and budgetLine. It's the detail view behind any PO card: click a row in gets and load it here. Every authenticated role can call it.
count (purchaseOrder)
count returns the number of purchase orders matching a filter โ a cheap badge counter for dashboards ("37 Pending", "5 Awaiting approval"). Unlike gets it returns no documents, just { count }, so it's ideal for status chips and header stats. Every authenticated role can call it.
getHistory (purchaseOrder)
getHistory returns the audit trail of a purchase order: the history[] array of every action (created, submitted, approved, rejected, finalized, cancelled, ...) with who performed it and when. Because every PO action in this app pushes a history entry, this one act gives you the complete lifecycle story of a document. Every authenticated role can call it.
submit (purchaseOrder)
submit is the act that starts the procurement workflow. It takes a Draft (or Pending) purchase order and:
finalize (purchaseOrder)
finalize closes the procurement loop: it converts an Approved purchase order into Completed, converts the budget encumbrance into actual spend, stamps completedAt, and pushes a finalized history entry. This is the only place where money truly leaves the budget โ nothing else in the chapter touches totalSpent. Only Manager/Admin, or UnitHead with the canConfirmGoodsReceipt feature, can finalize.
cancel (purchaseOrder)
cancel aborts a purchase order that hasn't finished. It's allowed from Draft, Pending, and InProgress โ i.e. any state before the order is Approved/Rejected/terminal. On cancel it releases the budget reservation (totalEncumbered -= amount, remainingBudget += amount), sets status: "Cancelled", stamps completedAt, and pushes a cancelled history entry with an optional reason. Only Manager/Admin, or UnitHead with the canRegisterPurchaseOrder feature, can cancel.
remove (purchaseOrder)
remove permanently deletes a purchase order with deleteOne. It's a blunt instrument โ there's no status guard, so any PO can be removed, and deleting a document with live relations cascades through the ODM's relation machinery (the related user, product, process, etc. snapshots get cleaned up too). Only Manager/Admin users can call it. Prefer cancel for a record-preserving abort; use remove only for true deletions.
updateRelations (purchaseOrder)
updateRelations lets you replace one or more relations of a purchase order after it was created โ requester, organization, requestingUnit, product, process, budgetLine, tender, or the attachments array. Every relation is swapped with replace: true, so the old embedded snapshot is dropped and the new one takes its place, with back-references kept in sync. This is how you fix a wrong budgetLine before submit, or attach a tender to a PO. Only Manager/Admin, or UnitHead with the canRegisterPurchaseOrder feature, can call it.
submitDecision (stepApproval)
submitDecision is where a unit head votes on a pending approval task. Given one approvalId, a decision (approved or rejected) and an optional comment, it:
getStepApprovals (stepApproval)
getStepApprovals lists every stepApproval created for one purchase order, oldest first. It's the audit view of the approval process: which units voted, in which step, with what decision and comment. Because the get projection is depth-2, you can pull the related processStep and unit snapshots alongside each vote. Every authenticated role can call it.
getPendingByUnit (stepApproval)
getPendingByUnit is the inbox โ the list of approval tasks waiting on a specific unit. It returns every stepApproval whose unit._id matches and whose status is still pending, newest first. This is what a UnitHead sees when they open "my pending approvals": each row links out to the PO, so they can review and then submitDecision. Manager/Admin/UnitHead/Employee roles can call it.
evaluateStepStatus
evaluateStepStatus is the pure function that decides whether an approval step is approved, rejected, or still pending, given all the units' votes and the step's AND/OR configuration. It's not an act โ it's a shared utility in utils/stepEvaluator.ts used by submitDecision after every vote. If you understand this one function, you understand the whole decision engine of the app.
resolveProcessForPO
resolveProcessForPO is the shared utility that answers one question: which Active process should this purchase order run on? It's used by po-add (when no process is passed) and by po-submit (when the PO has no process link yet). It walks a three-step fallback chain โ unit-specific, then product-specific, then organization default โ and returns the first Active process it finds.