Browse the docs

DocsKeep the books

@ekwo-ai/journal-items

Reads an export of journal items — the lines of every entry, one row per line, saved as CSV from the list view of an ERP whose ledger is a table of lines — into plain objects, in TypeScript, with no dependencies. Beside it, the chart of accounts and the partners exported from the same screen.

import { readJournalItems } from '@ekwo-ai/journal-items';

const books = readJournalItems([items, accounts, partners]); // any order; the last two are optional

books.entries;    // [{ number: 'INV/2025/00001', journal: 'Customer Invoices', date: '2025-01-15', lines: […] }, …]
books.accounts;   // [{ code: '400000', name: 'Receivable', type: 'Receivable' }, …]
books.contacts;   // the partners, with their tax ID and e-mail when the partners file has them
books.currency;   // the company currency the export states, or null
books.violations; // an entry that does not balance, a line of a draft entry

The files

Each file is recognised by its header, so they may be given in any order.

The journal items (required). The columns are found by name, under either spelling the export uses — the label a person reads, or the technical name of the field an export for re-import writes:

Column Labels Field names
the entry Number, or Journal Entry move_name, or move_id
journal Journal journal_id
date Date date
account Account account_id
partner Partner partner_id
label Label name
reference Reference ref
debit, credit Debit, Credit debit, credit
currency, amount Currency, Amount in Currency currency_id, amount_currency
company currency Company Currency company_currency_id
due date Due Date date_maturity
matching Matching # matching_number
status Status parent_state
  • Lines belong to one entry when they share its number; without that column, its display name.
  • An account arrives as it is displayed, its code and then its name (400000 Receivable). With the chart beside it the display is matched whole; without, the code is what comes before the first space.
  • A partner arrives as its name, and is identified by it.
  • A line whose entry is not posted is refused in violations: filter the export on posted entries, which is what books are made of.
  • Dates are ISO, YYYY-MM-DD; amounts have a point for decimal mark, a minus for a negative. A negative debit is a credit, and the other way round.
  • An export with a group-by active cannot be saved as CSV; remove the grouping first. A spreadsheet export is saved as CSV before it is read.

The chart of accounts (optional): Code, Account Name or Name, Type (or code, name, account_type). The type is kept in the source's words.

The partners (optional): Name, Tax ID, Email, Company ID, and the country as a two-letter code (Country/Country Code) — a country written as its name is not turned into a code.

What it returns

The shape declared in src/types.ts, which is, field for field, the shape every reader of an accounting export in this repository declares for itself. Amounts are decimal strings, never negative; the side is the sign. What does not add up comes back in violations and the entry comes back as written; what is not an export of journal items is thrown as a BooksFileError with a code.

It knows no chart of accounts. Which account of another chart each code becomes is the importer's business: in Ekwo OS, ekwo import journal-items <files…>.

Sources

This reader was written against the export of the Journal Items of Odoo (Accounting), versions 17 and 18, read on 22 September 2026 from:

ekwo import odoo <files…> is the same as ekwo import journal-items.

The fixtures under test/fixtures/ are written by hand from those pages and hold no real data.

MIT.

Rendered from packages/formats/journal-items/README.md, in the repository, when the site was built. Read or change it on GitHub