Arc Forge Labs Docs v2026.10.53

Invoice tabs and Send all ready

The Invoices page has seven tabs, left to right: Pending, Ready, Draft, Approved, Sent, Non-chargeable and Void. Earlier names: Problem is now Pending, Drafts is gone (a clean draft is Ready), and Finalised is split into Draft, Approved and Sent. Code: server/core/sending.js, server/api/invoicing.js (invoiceTabs) and server/integrations/xero/reconcile.js (stageOf).

Tab An invoice is here when
Pending A check failed, or the accounting system refused it. A person must look.
Ready A Flow draft, and no check fails. Nobody has to mark it.
Draft Issued in Flow and a draft in the accounting system, or on its way there.
Approved Approved in the accounting system, not yet sent to the customer. With no accounting system, every issued invoice is here.
Sent The accounting system sent it to the customer, or it is part paid or paid.
Non-chargeable A Flow draft whose job a non-chargeable rule matches (docs/INVOICE_RULES.md). The work is done but never billed. Nothing sends or approves it.
Void Voided or deleted.

The list starts with Number, Client, Reference, Date, Total, Status and Linked. + at the end of the head adds more: Due (the invoice's due date), the invoice's job's Case, Practitioner and Shipped date, and each custom field (the job's value, docs/CUSTOM_FIELDS.md). The columns, their order and widths stay with the person's account (docs/DESIGN.md, Columns).

A Ready invoice can go to the accounting system at any time. It then moves to Draft, the lowest stage Xero takes. Draft, Approved and Sent follow Xero's own status and its SentToContact flag, read from Flow's copy of Xero (no extra Xero calls). An invoice in that copy from before the sent_to_contact column (Xero migration 0009) shows as Approved until Xero changes it and Flow reads it again.

Ready

A draft with no problem is in Ready. A saved change keeps it there while the checks pass. A draft with a problem is in Pending until the problem is fixed; then it goes to Ready by itself. There is no half-made Flow draft: every invoice before it is sent is Pending (a check fails) or Ready (every check passes). Draft is the accounting system's word for an invoice it holds.

On the invoice the buttons are, left to right, Delete (a draft that was never issued; an owner or admin), Preview, Save, then Send to Xero (accounting system on) or Approve (no accounting system). A Pending draft has no send button. Delete asks first, removes the draft, and frees its job: the lab's rules then decide whether Flow drafts it again. The result stays until the person closes it. An issued invoice whose accounting copy is a draft also has Delete (owner or admin), before Void. The confirm says Also deletes the draft in Xero. Flow reads that invoice live, deletes it there while it is still a draft, then voids it in Flow. The issued versions stay, and the job is freed the same way. Delete is hidden when the copy says Approved or Paid. With no accounting system, Delete of an issued invoice, including one opened to revise, is refused and the invoice stays as it is.

The Problem banner gives the first sentence of each problem: what is wrong. The field the failed check reads glows red, like a required field (fieldError, problem.fields): a rule on the Reference marks the Reference box, a line with no price item marks its item. Typing in the field clears the red.

Save is the check, like CI: it saves, and Flow runs every check again (its own, the lab's rules, the accounting system's). A Pending invoice that now passes moves to Ready: a toast says so and the next invoice of the list opens. One that still fails stays Pending, with the toast giving the problem and its red fields. While the draft's job changed after it was made (below), send and Approve are off: fix the job at its source, or accept the change.

Bulk bar

Ticking rows on any tab of the Invoices list brings up the bulk bar (server/ui/bulk-bar.js). It floats at the foot of the page, and the tabs, search stay at the top while the rows scroll under them. The bar shows N selected × (× or Esc clears the ticks), then the tab's actions in groups, then More, a searchable menu of every action plus Tick all shown, Invert ticks and Clear ticks. An icon-only action shows its name on hover.

Tab Actions
Pending Retry (send-again for the ticked issued ones the accounting system refused), Copy references, Export CSV, Delete (a ticked draft that was never issued; asks first)
Ready Send to Xero (send-ready for the ticked ids; Approve with no accounting system), Copy references, Export CSV, Delete (asks first)
Draft Copy numbers, Export CSV, Download PDFs, Delete (a ticked invoice whose accounting copy is a draft; the confirm says Also deletes the draft in Xero.; each row reports deleted or refused, with the reason), Void (asks first; Void does not change the accounting system)
Approved, Sent Copy numbers, Export CSV, Download PDFs, Void (asks first; Flow does not change the accounting system). Delete is hidden: the copy says Approved or Paid.
Non-chargeable Copy references, Export CSV, Delete (asks first)
Void Copy numbers, Export CSV, Download PDFs

Checks

Flow checks its own data first. The Problem column shows a short fact for each failed check; the full text is its hover title.

Check Short fact Full text
The draft has lines No lines The invoice has no lines.
The total is above zero Total $0 The total is $0.00 or less.
Every line has a price item Line N: no item Line N has no price item.
The job is not in review Line 4 added, Client changed, Job changed, Job deleted, Status moved back, Job needs a look The job needs a look before this invoice goes: (the review reason).
A skip rule matches the job the rule's name Rule "": not invoiced. Void this draft or change the rule.

When an accounting system is on and connected, its own checks are added (checkDrafts). For Xero these come from Flow's copy of Xero, so they cost no Xero calls: the customer matches one Xero contact (Client not in Xero, Client twice in Xero), and every item is in Xero (CODE not in Xero). With Create missing clients on, Client not in Xero offers Create, which adds the client in Xero from the Flow contact (docs/CONTACTS.md). With it off, add the client in Xero, then sync. Owners and admins see Create. Staff see the flag.

An issued invoice that the accounting system refused is in Pending (Send failed). It shows the refusal until a person sends it again.

Send all ready

On the Ready tab, an owner or admin ticks the rows (the head tick takes every row shown), then presses Send to Xero (or Approve) in the bulk bar. It asks first. There is no separate send bar. Then:

  1. Flow stops before it issues anything when the accounting system is on but not connected, or does not take writes (XERO_ALLOW_LIVE_WRITES).
  2. Read before act (issue #141): the job behind each ready draft whose work system report is over two hours old is read again from the work system, one call per job, at most 20 a press. A job that changed after its draft, or that the work system deleted or no longer bills, goes to review and its draft to Pending. A draft whose job could not be read waits for the next press (waiting in the answer). Jobs past the 20-read cap are not read on this press; they count in waiting too. Then the accounting system reads its latest changes (issue #45, see XERO.md). When that read cannot run, nothing is issued and every draft in the press waits. A ticked press, including a bulk press, answers not_ready and names the cause (for example "the accounting copy has more changes than one read takes"): that one read covers them all. Send on one invoice is all or nothing: if that job cannot be confirmed, nothing is sent (not_ready), and the answer names the cause and the count (for example "1 job could not be read from the work system"). A bulk press (more than one ticked invoice) sends the ones Flow confirmed. The rest stay in Ready, or move to Pending when the job went to review, and the toast names how many could not be confirmed. When a bulk press confirms none, it answers not_ready with that count (for example "3 jobs could not be read from the work system"). A danger toast for a stopped press stays until the person closes it. Every draft check then runs again, the lab's pending rules and skip rules (INVOICE_RULES.md) included. A draft that fails one now stays on Pending and is not sent. When a person ticked drafts, the rest go and the answer counts the ones held (held); when every ticked draft fails, nothing is sent and the answer names the first problem.
  3. Each ready draft is issued and gets its number. One press takes up to 100 drafts; the rest wait for the next press.
  4. Each issued invoice is queued for the accounting system, and shows in Draft with the status Sending.
  5. The send worker sends the queue in the background, every 30 seconds, on the job queue. For Xero, each invoice goes as a Xero draft by default; the customer's send mode can make it an approved invoice that Xero emails.
  6. A sent invoice leaves the queue. A refused invoice moves to Pending. The send worker reports that refusal once: how many, each invoice's number and id (five at most), and the accounting system's code and short message. The report has no customer name and no email address. An invoice that waits for Xero's call limits stays queued.
  7. With an integration on, every tab has a Linked column: one icon for each connected system (Seazona, Xero), never one column per system. A dot gives the state of this invoice's link: green linked and in step, amber not in Xero yet, red out of step with Xero. A dashed grey icon means no link. The Xero icon shows on issued and void invoices; its title gives Xero's number and state. An icon with a link opens the record there.
  8. One invoice's page has a Linked card with the same systems: the work system row gives the order number, the accounting row gives Xero's number and state, and each has Open. A separate Xero card shows only when Xero differs from what Flow sent.

With no accounting system on, the button is Approve all N ready: it issues the ready drafts only, and they go to Approved.

One ready invoice has its own Send to Xero button (Send to Xero and email when the customer's send mode is approve and email). It does the same steps for that invoice only. With no accounting system on, Approve gives the invoice the next number and locks it, and sends nothing. It is greyed until the invoice has a client and a due date, and while the draft's job change is open.

New invoice from a job

A new invoice can start blank or from a job. From a job, in the page header, lists the jobs with no invoice yet (client, practitioner, shipped date, total), with a search. Picking one makes its draft the way the invoicing rules do (POST /api/invoicing/jobs/:id/draft): the client, the Reference from the Reference rule, and the job's lines, linked to the job. A job the rules refuse is not drafted, and the toast names the reason. An invoice with no job stays allowed.

After a send, the next invoice of the list opens. The count in the bar holds (1 of 35, then 2 of 35): the sent invoice stays in the bar's list until the person goes back. Previous opens it again, issued, with a greyed Sent to Xero button: an invoice that is queued, sent, or found in Xero cannot be sent twice. Back reloads the list, where the sent invoice is under Draft. After the last invoice of the list, the list opens.

Approve, and a Save that makes a Pending invoice Ready, open the next invoice of the list too, so a person reviews invoices one after another without going back. Accept change stays on the invoice, to show the result. An invoice opened from somewhere else (the job board, search, a link) steps through its own tab.

Records

invoices.send_state is queued, sent or failed (null when the invoice was never queued). send_error holds { code, message } while failed. Revising an issued invoice clears both. xero_invoices.sent_to_contact holds Xero's SentToContact flag.

API

  • GET /api/invoicing/invoices?status=pending|ready|draft|approved|sent|void lists a tab. The old names problem, to_check and issued still work. Each invoice carries tab, sending and problems. counts has one number per tab. The list is one page: offset and limit (default 200, at most 500) cut it, filter (the Filter chip's view as JSON, the rules of server/ui/job-view.js), sort (number, client, reference, date, total) with dir (asc or desc) and today (the person's day, for date filters) run over every invoice of the tab first. The answer has total and totalCents of every match and clients (the tab's clients, for the Filter's choices). One invoice (GET /invoices/:id) carries the same tab, view (problem or ready, for a draft) and problems, and, for a draft, sendsTo and sendMode (this customer's mode, and whether the accounting system is connected and takes writes).
  • POST /api/invoicing/invoices/mark-ready and mark-not-ready stay for older pages; they no longer change the tab.
  • POST /api/invoicing/invoices/send-ready { issueDate, invoiceIds? }: with invoiceIds, only those drafts. One id is all or nothing (not_ready when it is not ready, or its job cannot be confirmed; the message names the cause). More than one id sends the ones that are ready and confirmed; held counts drafts that failed a check, and waiting counts jobs that could not be confirmed. When none can go, the answer is not_ready and names the cause and the count.
  • POST /api/invoicing/invoices/send-again { invoiceIds? }.
  • DELETE /api/invoicing/invoices/:id (owner or admin) removes a draft that was never issued (status draft and issuedVersion 0). Its job's billing obligation is freed, so the job is ready again and the lab's rules decide whether to draft it. An invoice that was issued is deleted only when its accounting adapter deletes the draft there, or reports it already gone: Flow then voids the invoice (the issued versions stay) and frees the job. Approved or paid answers accounting_approved (Approved in Xero. Void it in Xero first. when the adapter is Xero) and changes nothing. Not connected or writes off answers accounting_not_connected or accounting_writes_off, and changes nothing. With no accounting system, or when a connected adapter cannot delete it, the answer is accounting_unavailable and the invoice stays as it is. A timeout leaves the invoice as it was.
  • POST /api/invoicing/jobs/:id/use-new-lines { accept? }: the draft takes the work system's lines. With accept: true it also replaces lines changed in both places, while the invoice is not sent.
  • POST /api/invoicing/jobs/:id/recheck: reads this one job from the work system now (at most once per job every 10 seconds), runs the checks again, and answers the invoice.

The job changed after the draft was made

When the work system's job changes after Flow made its draft (docs/DATA_SPINE.md, three-way compare), the draft is in Pending and the invoice page shows a banner: one row for each changed fact (client, a line's item, description, quantity or price, an added or removed line, and the total), with what it Was when the draft was made and what it is Now in the work system. Flow never writes to the work system.

Button What it does
Open in Seazona Opens this order in Seazona's own web app by its id (OrderEdit.aspx?id=…), to fix it there. The Seazona setting Order address (docs/SEAZONA.md) overrides the address. With no order id, it opens the lab's Seazona home page.
Accept change Only while the invoice is not sent. The draft takes the Now column, also for a line changed in both places (it asks first, and replaces the change made here). The problem closes, and the draft goes to Ready when no other check fails. Nothing goes to Seazona or the accounting system.
Recheck (round arrow icon) Reads this job from Seazona again now, for when Seazona was wrong and is fixed. When it matches the draft, the problem closes.

A fix made in the work system closes the problem when Flow next reads the job.

The Jobs page shows the same review. Each problem a job must fix is a chip beside its stage, such as Job changed, so the panel keeps one layout with or without a fix. A chip is a toggle. A click opens the panel's sidecar on the right (in place of Activity) on its Fix tab, for that problem, and shows the chip pressed; a second click closes the sidecar. For Job changed the tab has this banner and its buttons, so a person checks and accepts the change without leaving the job. For another problem it says what is wrong, what to do, and has one button to the place to fix it. The sidecar has tabs (Activity, Fix) and closes with ×; closed, the job's details take the full width. The panel icon at the top reopens it.

The job and its draft hold one fact: the job is in review. Flow stores it once (the job's hold, and one open review item for each job; a second report updates that item). The panel shows it once: the draft's copy of the hold (job_review) is left out, as on the invoice page. Accept change, a recheck that matches, or a fix in the work system clears the hold and closes the item.