Quarantine Review
Invoices reach a quarantine bill run by two paths — automatic (validation script) and manual (operator review). Both feed the same child quarantine BR and the same release flow.
Two ways into quarantine
1. Auto-quarantine (validation script)
When validation rejects an invoice — or flags it suspect — and the run's rejectAutoAction / suspectAutoAction is MOVE (default), the engine creates a child bill run holding the failing invoices:
- The invoicing job validates each invoice. The validation script (per-BR or inherited from the cycle) decides reject / suspect / pass.
- For each rejected or suspect invoice, when the corresponding auto-action is
MOVE, the engine:- Lazily creates a child bill run with
isQuarantine=true. - Copies scope and aggregation config from the origin BR; sets
originBillingRunback-reference; resets amounts to zero. - Moves the failing invoices into the child BR via dedicated named queries, setting
statustoREJECTEDorSUSPECT.
- Lazily creates a child bill run with
- The origin BR finishes with clean amounts. The child quarantine BR holds the problem invoices.
2. Manual quarantine (review before posting)
While a bill run sits at DRAFT_INVOICES or POSTINVOICED, the operator can review the draft invoices and selectively quarantine the bad ones before validating the rest:
POST /api/v1/billingRuns/{id}/quarantineInvoices
{ "invoiceIds": [12, 13], "description": "Carrefour amounts look wrong" }
Selected invoices move into a quarantine child BR (consolidated — repeated calls on one origin BR land in the same child). Status-gated: only valid in DRAFT_INVOICES / POSTINVOICED (409 otherwise). In the UI, the EditBillRun "Related Invoices" table becomes a checkbox multi-select with a Send to quarantine bulk action at those statuses.
Finding quarantine bill runs
The Bill Runs list page surfaces a Type column showing Quarantine of #N when isQuarantine=true, with the parent BR ID. Click the row to navigate to the dedicated quarantine review page.
In API terms, every BillingRunV1Response carries:
{
"id": 542,
"isQuarantine": true,
"originBillingRunId": 540,
"quarantine": {
"rejectedInvoiceCount": 2,
"suspectInvoiceCount": 1
}
}
Reviewing and releasing invoices
The quarantine review page lists the rejected and suspect invoices with their status, BA, and rejection reason. Each row offers three actions:
| Action | What it does |
|---|---|
| Revalidate | Flip the invoice status back to NEW and re-run validation. Successes attach to a fresh child BR (or a caller-supplied targetBillingRunId). |
| Cancel | Drop the invoice entirely. Underlying RTs stay BILLED. |
| Cancel and reopen RTs | Drop the invoice and reopen its RTs so the next bill run picks them up. |
API endpoint
POST /api/v1/billingRuns/{id}/releaseFromQuarantine
{
"invoiceIds": [12, 13, 14],
"action": "REVALIDATE",
"targetBillingRunId": null
}
Returns:
{
"quarantineBillingRunId": 542,
"action": "REVALIDATE",
"invoicesProcessed": 3,
"invoicesFailed": 0,
"targetBillingRunId": 543
}
Errors
| Code | Cause |
|---|---|
400 MISSING_INVOICE_IDS | invoiceIds is empty. |
400 INVALID_ACTION | action is not one of REVALIDATE / CANCEL / CANCEL_RT. |
404 BILLING_RUN_NOT_FOUND | BR id does not exist. |
| 409 | BR is not a quarantine BR (isQuarantine=false). |
Preventing quarantine
If you do not want auto-quarantine, set the auto-actions to something other than MOVE:
| Action | Effect when validation rejects/suspects an invoice |
|---|---|
MOVE (default) | Move to a child quarantine BR. |
CANCEL | Drop the invoice. |
CANCEL_RT | Drop the invoice and reopen its RTs. |
AUTOMATIC_VALIDATION | Treat as valid and continue (suspect only). |
MANUAL_ACTION | Stop the engine and wait for an operator. |
The "New Bill Run" form shows an inline warning under the run-options panel when either auto-action is set to MOVE, linking back here.