Documentation Index
Fetch the complete documentation index at: https://docs.ntropii.com/llms.txt
Use this file to discover all available pages before exploring further.
JournalProposalRow captures one journal entry waiting on operator approval before it posts to the external GL. Stored in ledgers.journal_proposals. Migration: 005_journal_proposals_subledger.sql.
"journal_proposals" subledger type on import.
Type-specific fields
| Field | Type | Purpose |
|---|---|---|
description | str | None | Narrative the GL stores as memo / description. Operator-facing. |
posting_date | date | None | Date the journal posts on. Distinct from period — a March journal might post on the 31st, a year-end adjustment on the prior day. Required for GL commit; if absent we derive last-day-of-period at handoff. |
currency | str | None | ISO-4217. Optional — the GL provider uses the entity’s default when omitted. |
lines | list[dict] | List of {account_code, description, debit, credit, tax_code?} dicts. Stored as JSONB. Strict typing happens at GL handoff. |
GL-handoff fields
MirrorsExpenseRow. Populated by the post step, never written by runbook code directly.
| Field | Type | Purpose |
|---|---|---|
approved_at | datetime | None | Set by the HITL approval step. |
posted_to_gl | bool | True once the GL post succeeded. |
posted_journal_ref | str | None | Provider-assigned journal id. |
Why lines is a list of dicts (not a typed sub-model)
- Matches the existing
ledgers.journal_proposals.linesJSONB column shape — keeps the migration cheap. - Line shape evolves per-runbook.
nav-monthly-journalscarriesaccount_code/description/debit/credit/tax_codetoday. Other runbooks may addcost_centreortracking_categories. Loose dict here, strict typing happens atpropose_for_gltime when we land in the unifiedJournalEntryLineItem.
Validation rules
Two model validators run at row construction:_strict_fields_present_when_not_needs_attention
Outside NEEDS_ATTENTION, lines must be non-empty AND each line must:
- Have a non-empty
account_code. - Have non-negative
debitandcredit. - Have a non-zero amount on exactly one side (debit XOR credit > 0). Both zero → invalid; both positive → invalid.
NEEDS_ATTENTION rows are the only status allowed to be empty (placeholder for HITL fix-up).
_balanced_when_approved
A journal posted to the GL MUST balance (Σ debits == Σ credits). Enforced only on APPROVED / POSTED rows so the runbook can store an in-progress draft mid-HITL before the user adds the balancing line.
GL handoff — JournalProposalRow.propose_for_gl
APPROVED subledger rows to a single JournalProposal for GL commit. nav-monthly-journals calls this with one row (the approved monthly allocation journal). Other runbooks may pass multiple rows when the GL provider’s batched-journal model suits — e.g. a period-close runbook posting all true-up journals as one batch. When multiple rows are passed:
linesare merged into a single journal entry.descriptionandposting_datecome from the first row (caller’s responsibility to pre-validate they share these).
| Row | → | GL (JournalEntry) |
|---|---|---|
line account_code | → | JournalEntryLineItem.ledger_account.nominal_code |
line debit / credit | → | JournalEntryLineItem.type ("Debit" / "Credit") + total_amount |
line description | → | JournalEntryLineItem.description |
description | → | memo |
currency | → | currency |
posting_date (or last-day-of-period default) | → | posted_at (datetime, midnight UTC) |
"journal_proposals:{task_id}:{row.id}" for single-row proposals. Multi-row uses the first row’s id (deterministic across re-invocations as long as the row order is stable).
Rejects non-APPROVED rows — only signed-off journals go to the GL.
Related
Subledgers overview
Row base + SubledgerStatus lifecycle.expenses
The other shipped platform type.
Accounting
JournalLine / JournalProposal proposal-builder helpers.General ledgers
Posting the
JournalProposal via provider.journal_entries.create.