Naar hoofdinhoud springen

Boekhouden automatiseren met bea

Script uw Beancount-boeken met bea: los het grootboek expliciet op, parse de JSON-envelop met jq, vertak op exitcodes, voer onbeheerd uit en plan een nachtelijke controle.

Een script bestuurt bea met vier beslissingen: welk grootboek het leest, --json voor machineleesbare uitvoer, jq voor de waarde die het nodig heeft, en de exitcode waarop het vertakt. Deze handleiding doorloopt die vier beslissingen van begin tot eind en plant ze vervolgens in.

U heeft bea nodig op de machine die de taak uitvoert en een grootboek dat het kan bereiken. Als u met nieuwe boeken begint, volg dan eerst de CLI-snelstart. Elk feit over vlaggen, envelopsleutels en exitcodes wordt opgezocht in de Beancount CLI-referentie, niet hier herhaald.

Kies het grootboek expliciet

Noem het bestand. Een lokaal commando lost zijn doel op via --file, daarna $BEA_FILE, daarna ./main.bean in de werkmap, en een geplande taak draait zelden waar u denkt dat het draait.

bea --file ~/books/main.bean check
BEA_FILE=~/books/main.bean bea check
cd ~/books && bea check

Globale opties gaan vóór het commando, zoals in bea --file main.bean check. Als het opgeloste bestand niet bestaat, eindigt het commando met exit 2 en noemt het alle drie de bronnen, zodat een typfout in een cron-regel luid faalt in plaats van de verkeerde boeken te valideren. Hosted targeting via een --ledger-vlag bestaat nog niet; bea uploadt nooit impliciet een lokaal bestand.

Lees de JSON-envelop

Voeg globaal --json toe en elk ondersteund commando antwoordt met dezelfde envelop: bea, target, data, truncated en limit op begrensde lijsten. Bedragen zijn decimale tekenreeksen en datums zijn ISO YYYY-MM-DD, dus een waarde is veilig om te vergelijken zonder dat er ooit een float in de pijplijn komt. De sleutels van de envelop zijn weergegeven in de JSON- en exitcode-referentie.

bea --json --file main.bean report income-statement | jq .data.net_profit
bea --json --file main.bean list transaction --limit 2 | jq '.data[0].postings[0].units'
bea --json --file main.bean import statement.csv --csv date=Date,amount=Amount,payee=Payee \
  --account Assets:Checking --apply --duplicates skip | jq '.data | {written, ready, duplicates}'

Die drie commando's — report, list en import — behouden hun resultaatstructuren, dus een jq-pad dat ertegen is geschreven blijft geldig. bea --json check en bea --json query emitteren vandaag ook de envelop, maar dit zijn de commando's die worden overgedragen aan de oorspronkelijke Beancount-uitvoerbare bestanden, dus een script moet zich richten op de exitstatus van check in plaats van op de vorm van de uitvoer. Kies uw duplicaatbeleid bewust: --duplicates is nog steeds vereist wanneer een import een beslissing nodig heeft, zoals de import-walkthrough uitlegt.

Stop op de juiste exitcode

Vertak op de status en lees het foutobject voordat u iets opnieuw probeert dat schrijft. In --json-modus schrijft een fout niets naar stdout en precies één object naar stderr, waarvan error.category de klasse noemt: validation (1), usage (2), auth (3), conflict (4).

#!/usr/bin/env bash
set -euo pipefail
 
out=$(mktemp)
err=$(mktemp)
status=0
 
bea --json --file main.bean report income-statement >"$out" 2>"$err" || status=$?
 
case "$status" in
  0) jq -r '.data.net_profit | to_entries[] | "net profit: \(.value) \(.key)"' "$out" ;;
  4) echo "conflict — inspect the ledger before retrying" >&2
     jq -r '.error.message' "$err" >&2
     exit 4 ;;
  *) jq -r '.error | "\(.category) (exit \(.exit_code)): \(.message)"' "$err" >&2
     exit "$status" ;;
esac

Exit 4 is degene die een script nooit blindelings opnieuw mag proberen: het betekent dat de uitkomst een conflict is of onbekend, zoals een externe bewerking die midden in een schrijfbewerking arriveert of een init-doel dat al bestaat. Inspecteer het grootboek en probeer het dan opnieuw vanaf een verse leesbewerking. Exit 1 dekt validatiefouten en elke andere runtime-fout; error.details draagt de afzonderlijke grootboekfouten en error.result draagt wat een gedeeltelijke schrijfbewerking daadwerkelijk heeft gedaan. Een niet-nul exitcode garandeert nooit dat er niets is veranderd.

Draai zonder terminal

bea stopt zelf met vragen. --no-input wordt geïmpliceerd wanneer stdin geen terminal is, wanneer --json is ingesteld en wanneer CI waarheidsgetrouw is — 1, true, yes of on. In die modus faalt een ontbrekende bevestiging met exit 2 in plaats van voor altijd te wachten.

CI=true BEA_NO_UPDATE_NOTIFIER=1 bea --json --file main.bean report balance-sheet
bea --json --file main.bean list transaction --limit 100 --sort oldest

Leesbewerkingen zijn tolerant in een terminal en strikt overal elders. Wanneer het grootboek loader-fouten heeft, eindigen query, list en report met exit 1 onder --json, onder een gepijpte stdout, onder een waarheidsgetrouwe CI, of met --strict; geef het eigen --allow-errors van het commando door om het gedeeltelijke antwoord te accepteren, wat ook ledger_valid: false instelt en ledger_errors vult in de JSON. --strict is het spiegelbeeld: het weigert gedeeltelijke antwoorden zelfs in een terminal, wat u wilt wanneer een mens hetzelfde script handmatig uitvoert. bea check heeft geen --allow-errors — fouten rapporteren is zijn hele taak — en eindigt altijd met exit 1 wanneer het er een vindt. Stel BEA_NO_UPDATE_NOTIFIER=1 in om de passieve updatemelding te dempen; een waarheidsgetrouwe CI doet dat al.

Plan een controle

Voer elke nacht een validatie uit en laat de exitcode de waarschuwing zijn. Beide blokken hieronder zijn sjablonen — de paden, het schema en de runner zijn van u.

# crontab -e — 07:15 daily; cron mails you only when bea exits nonzero
15 7 * * * BEA_NO_UPDATE_NOTIFIER=1 /opt/homebrew/bin/bea --file /home/alice/books/main.bean check
name: ledger
on:
  schedule:
    - cron: "15 7 * * *"
  push:
jobs:
  check:
    runs-on: ubuntu-latest
    env:
      BEA_NO_UPDATE_NOTIFIER: "1"
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5
      - run: uv tool install beancount-io==0.1.0
      - run: bea --file main.bean check
      - run: bea --json --file main.bean report balance-sheet > balance-sheet.json

Pind de versie wanneer de taak reproduceerbaar moet zijn, en verwijder de pin wanneer u liever releases volgt. CI is al waarheidsgetrouw op GitHub Actions, dus prompts zijn uit en de updatemelding is stil voordat u iets instelt. Er is hier opzettelijk geen opmaakstap. Een geplande taak moet geen bestanden herschrijven die het niet hoefde te doen, dus gebruik bea format --check in een pre-commit hook, dat niets aanraakt en eindigt met exit 1 wanneer een bestand opmaak nodig heeft.

Gebruik een gehoste referentie in een taak

Stel BEA_TOKEN in, vanuit de geheime opslag van uw CI-provider, en sla de browser-aanmelding volledig over. De token wordt uit de omgeving gelezen en nooit naar schijf geschreven, dus er belandt niets in de thuismap van de runner waar de volgende taak het kan vinden.

export BEA_TOKEN="$YOUR_CI_SECRET"
bea --json cloud status

Exit 0 betekent dat de referentie is opgelost en de envelop noemt het account waartoe het behoort; exit 3 met error.category van auth betekent dat dit niet zo is, en het bericht onderscheidt een niet-ingestelde referentie van een afgewezen referentie. bea cloud logout doet niets met een op deze manier verstrekte token — het trekt het noch in, noch schakelt het uit, omdat een andere taak het kan delen — dus trek een gelekt token in via het dashboard in plaats daarvan. Lokale commando's hebben helemaal geen referentie nodig; alleen bea cloud en bea ask bereiken de gehoste service. De volledige variabelelijke staat in de instellingenreferentie.

Niet alles antwoordt in JSON. bea ask wijst JSON-modus regelrecht af, bea cloud login heeft een mens nodig, en een succesvol bea cloud logout of bea cloud ledger clone retourneert geen JSON-succesobject — lees hun exitstatus in plaats daarvan. Help-, versie- en shell-aanvullingsuitvoer blijven tekstueel.

Volgende stappen

Bron: https://beancount.io/nl/docs/Solutions/automate-bookkeeping-with-bea