@baseworks/invoice
v0.1.1
Published
Invoice capability: typed HTTP client, event catalog, projections, and CLI plugin for invoice-service (AR ledger). Contract-first, versioned with the service.
Readme
@baseworks/invoice
Typed client, event catalog, projections, and CLI plugin for invoice-service — the per-org AR ledger (invoices + a transaction ledger). Contract-first, versioned with the service.
pnpm add @baseworks/invoiceClient
Invoices are org-scoped (X-Org-Id + identity token). Money is integer
cents throughout. Status machine: draft → finalized → paid | void. A finalized
invoice is immutable (only payments / void follow).
import { createInvoiceClient } from '@baseworks/invoice'
const invoices = createInvoiceClient({
baseUrl: process.env.INVOICE_SERVICE_URL!,
token: identityJwt,
orgId: activeOrgId,
})
// 1. draft — customerId is a customers-service ref (validated + name snapshotted)
const draft = await invoices.create({
customerId: 'acct-42',
currency: 'USD',
lines: [
{ description: 'Consulting', quantity: 10, unitPriceCents: 15000 }, // $150.00 × 10
{ description: 'Setup', quantity: 1, unitPriceCents: 50000 },
],
})
// 2. finalize — assigns a per-org number, freezes lines + totals
const final = await invoices.finalize(draft.id, { dueAt: Date.parse('2026-08-01') })
// 3. record payments — balance can't go below zero (overpayment is rejected)
await invoices.recordPayment(final.id, { amountCents: 100000, method: 'bank', reference: 'TXN-1' })
await invoices.recordPayment(final.id, { amountCents: 100000 }) // → status 'paid'
// 4. the ledger — one row per money movement
await invoices.transactions() // all org transactions
await invoices.invoiceTransactions(final.id) // this invoice's payments
await invoices.list({ status: 'finalized' })
await invoices.get(final.id)
await invoices.void(final.id, 'issued in error')Errors throw InvoiceError (.status, .code): 409 not_draft (edit a finalized
invoice), 409 overpayment / 409 already_paid, 404 customer_not_found.
CLI plugin
import { buildInvoiceCommand } from '@baseworks/invoice/cli'
program.addCommand(buildInvoiceCommand({ http, cliName: 'dtab' }))
// dtab invoices | inv list (--status) · create · get · update · finalize · pay · void
// dtab invoices create --customer <ref> --currency USD --line "Consulting|10|150.00"
// dtab invoices pay <ref> --amount 150.00 --method bank
// dtab invoices payments [<ref>] (the transaction ledger)Service integration
import { PROJECTIONS, POLICIES } from '@baseworks/invoice/projections'
import { InvoiceEvents, TransactionEvents } from '@baseworks/invoice/events'Projections invoices → read_invoices, transactions → read_transactions
(one row per payment). Tenant = org id.
See also
Service: projects/invoice-service · ADR-010.
