Skip to content

Journal-Format Reports — Sales / Cash Receipts / Purchase / Cash Disbursements

Date: 2026-07-01

Problem / motivation

Peachtree (Sage 50) exposes four "journal" reports that show transactions in debit/credit journal format rather than as document registers: Sales Journal, Cash Receipts Journal, Purchase Journal, and Cash Disbursements Journal (plus the client's Sales Journal_only / INFORME DE CAJA custom variants). We already post every source document to the general ledger with a source_type discriminator, so these reports are the same posted ledger_entries, filtered by the kind of source document and rendered as debit/credit lines. This closes the highest-leverage rows on the Peachtree Report Parity tracker (Phase 1).

In scope

  • One shared journal primitive (JournalReportRepository + JournalLineResponse) that lists posted ledger lines for a set of SourceTypes in a date range, in journal order (date, entry number, account).
  • Four read-only queries, each a thin wrapper binding the primitive to a source type:
  • sales_journal_reportSourceType.INVOICES
  • cash_receipts_journal_reportSourceType.RECEIPTS
  • purchase_journal_reportSourceType.SUPPLIER_INVOICES
  • cash_disbursements_journal_reportSourceType.PAYMENTS
  • Only posted entries (is_posted = TRUE). CSV export via the standard generate_csv flag.
  • Path.REPORTS permission.

Out of scope

  • General Journal (all source types) and manual-entry journal — already covered by JOURNAL_MOVEMENTS.
  • Payroll Journal — deferred to the payroll reporting suite.
  • Including EXPENSES in cash disbursements — expenses on credit are not disbursements; the Expense Register already covers them. The repo takes a list[SourceType], so this is a one-line extension later.

Data model changes

None. Reads existing ledger_entries (entry_date, entry_number, source_type, memo, is_posted) and ledger_entry_lines (debit_amount, credit_amount, account_id, memo) joined to accounts. No migration, no new Path/Resource.

What's being implemented

  • Responseapp/graphql/reports/strawberry/journals/journal_report_response.py (JournalLineResponse, one row per ledger line).
  • Repositoryapp/graphql/reports/repositories/journals/journal_report_repository.py.
  • Serviceapp/graphql/reports/services/journals/journal_report_service.py (get_journal(source_types, date_filter, generate_csv)).
  • Queriesapp/graphql/reports/queries/journals/journal_report_queries.py (JournalReportQueries).
  • Teststests/graphql/reports/test_journal_reports.py.

GraphQL surface

salesJournalReport(dateFilter: DateRangeFilter!, generateCsv: Boolean! = false): GenericReportPage!
cashReceiptsJournalReport(dateFilter: DateRangeFilter!, generateCsv: Boolean! = false): GenericReportPage!
purchaseJournalReport(dateFilter: DateRangeFilter!, generateCsv: Boolean! = false): GenericReportPage!
cashDisbursementsJournalReport(dateFilter: DateRangeFilter!, generateCsv: Boolean! = false): GenericReportPage!

type JournalLine {
  entryDate: Date!
  entryNumber: String!
  sourceType: SourceType
  memo: String
  accountCode: Int!
  accountName: String
  lineMemo: String
  debitAmount: Decimal!
  creditAmount: Decimal!
}

Frontend contract

  • Four journal reports under Reports; each takes a DateRangeFilter and returns records: [JournalLine].
  • Render grouped by entryNumber (a transaction), each group's lines showing accountCode/accountName with debitAmount / creditAmount in two columns; column totals per group and overall must balance.
  • generateCsv: true returns csvUrl and an empty records, matching every other report.

Future additions

  • Group-subtotal rollups server-side (currently a flat balanced line list; the client groups).
  • Payroll Journal once payroll postings carry a dedicated source type.