doc_type'invoice' | 'credit_note'
counterparty_idstring nullable
issuer_profile_idstring nullable
issue_datestring date required
due_datestring date nullable
service_period_startstring date nullable
service_period_endstring date nullable
payment_terms_idstring nullable
invoice_discount_kind'none' | 'percent' | 'amount'
invoice_discount_valuestring
footer_textstring nullable
legal_textstring nullable
credited_invoice_idstring nullable
status'draft' | 'issued' | 'cancelled' required
Editorial lifecycle owned by ar_invoice (paid/overdue are derived on
read from the linked gl_open_item, not stored here).
origin'human' | 'system' | 'ai' | 'api' | 'mcp' | 'chat'
What KIND of actor posted a journal entry — the attribution flag.
Two axes in one vocabulary, because the column answers one question — can a
reader take this as a person's own judgement?
Authorship — the value says who composed the booking:
- ai = the AI-accountant composed it (an autonomous post, or a one-click
accept where the content is still the accountant's proposal);
- system = a mechanical/background SystemPrincipal post (migrations,
close automation, deterministic seeds).
Channel — the value says which surface a person's own action arrived
through, because "a UserPrincipal acted" is NOT the same claim as "a
person decided". All four are derived from the request edge by
:func:~invoiage_db.repos.gl_posting._resolve_origin:
- human = an interactive browser session (cookie/JWT auth). The only
value that asserts a person was looking at the screen;
- mcp = an API-key request carrying the mcp shell's X-Zeno-Surface
marker — a connected agent, which MAY be relaying a person and may not;
- api = any other API-key request (a script, an integration, an agent
calling the REST api directly). Not provably a person either;
- chat = the built-in CFO chat relaying a person's approval in-app. Its
authored bookings stamp ai; chat is only for the relay.
Widening this vocabulary is a one-way door on rollback: the PG type is a
native enum converted at load (pg_enums._pg_enum), so an api whose Python
enum lacks a value raises LookupError reading any row that carries it.
See the 0112 migration.
document_nostring nullable
commercial_document_idstring nullable
snapshot_document_idstring nullable
gross_totalstring required
payment_statusstring nullable
open_amountstring nullable
sent_atstring date-time nullable
last_sent_tostring nullable
issued_atstring date-time nullable
created_atstring date-time required
updated_atstring date-time required