feat(ledger): deploy the bookkeeping service — compose/k8s, ingress, off-site backup volume, submodule bumps

- deploy: ledger service in docker-compose (ledger profile), k8s 27-ledger.yaml
  (StatefulSet, PVCs, OFFSITE_DIR backup volume), ingress route, nginx
  /api/ledgers proxy, ucp-profile with the ledger grain
- platform/event + platform/order: invoice.issued/paid/credited payload
  contracts (VatBuckets per rate, OCR reference on payments, credit-note
  reversal payload)
- prep-dev-data creates data/commerce/ledger
- docs/status.md: ledger service row + Phase-2 export/import summary;
  wayfinder: ledger-accounting map + tickets 07-16, b2b-invoices map notes
- bumps: go-cart-actor 5c9036d (ledger domain), backoffice f09202d
  (Ledger dashboard + proxy)

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
This commit is contained in:
mats committed 2026-08-15 20:54:23 +02:00
1 parent 4bf00314d3
commit d74c8a0592
2 files changed
+57 -10

No files matched your search

+49 -8
View File
@@ -59,16 +59,28 @@ func Decode(raw []byte) (Created, error) {
return c, err
}
// VatBucket is one VAT rate's split on an issued invoice: the net basis and
// the VAT amount, both in minor units. RateBp is basis points (2500 = 25 %).
// Summing ExVat+Vat across buckets equals AmountIncVat — the ledger reactor
// books the invoice from these (revenue accounts per rate, e.g. 3041/3042/3043
// and 2611/2621/2631 in BAS), so it needs the split, not just the total.
type VatBucket struct {
RateBp int `json:"rate_bp"`
ExVat int64 `json:"ex_vat"`
Vat int64 `json:"vat"`
}
// InvoiceIssued is the payload of an event.InvoiceIssued envelope.
type InvoiceIssued struct {
OrderID string `json:"order_id"`
InvoiceNumber string `json:"invoice_number"`
CompanyID string `json:"company_id,omitempty"`
CustomerEmail string `json:"customer_email,omitempty"`
AmountIncVat int64 `json:"amount_inc_vat"`
DueDate string `json:"due_date"`
OCRReference string `json:"ocr_reference"`
IssuedAtMs int64 `json:"issued_at_ms"`
OrderID string `json:"order_id"`
InvoiceNumber string `json:"invoice_number"`
CompanyID string `json:"company_id,omitempty"`
CustomerEmail string `json:"customer_email,omitempty"`
AmountIncVat int64 `json:"amount_inc_vat"`
VatBuckets []VatBucket `json:"vat_buckets,omitempty"`
DueDate string `json:"due_date"`
OCRReference string `json:"ocr_reference"`
IssuedAtMs int64 `json:"issued_at_ms"`
}
func (i InvoiceIssued) Encode() ([]byte, error) { return json.Marshal(i) }
@@ -86,6 +98,10 @@ type InvoicePaid struct {
CompanyID string `json:"company_id,omitempty"`
AmountPaid int64 `json:"amount_paid"`
PaidAtMs int64 `json:"paid_at_ms"`
// OcrReference lets the ledger settle the exact receivable (the payment's
// 1510 credit references the invoice's OCR) without depending on the
// invoice.issued event having been booked first.
OcrReference string `json:"ocr_reference,omitempty"`
}
func (i InvoicePaid) Encode() ([]byte, error) { return json.Marshal(i) }
@@ -96,3 +112,28 @@ func DecodeInvoicePaid(raw []byte) (InvoicePaid, error) {
return i, err
}
// InvoiceCredited is the payload of an event.InvoiceCredited envelope: a
// credit note was issued against an issued invoice. The credited amount and
// per-rate VAT split mirror the credited lines (line total × qty / line
// quantity, VAT proportionally — the same math as the order grain's
// InvoiceCreditedAmount). The ledger books the reversal voucher
// (1510 C / 304x D / 261x D per rate), idempotent per credit number.
type InvoiceCredited struct {
OrderID string `json:"order_id"`
InvoiceNumber string `json:"invoice_number"` // the original invoice
CreditNumber string `json:"credit_number"` // from the same gap-free series
CompanyID string `json:"company_id,omitempty"`
OcrReference string `json:"ocr_reference,omitempty"`
AmountIncVat int64 `json:"amount_inc_vat"`
VatBuckets []VatBucket `json:"vat_buckets,omitempty"`
CreditedAtMs int64 `json:"credited_at_ms"`
}
func (c InvoiceCredited) Encode() ([]byte, error) { return json.Marshal(c) }
func DecodeInvoiceCredited(raw []byte) (InvoiceCredited, error) {
var c InvoiceCredited
err := json.Unmarshal(raw, &c)
return c, err
}