Към основното съдържание
Beancount.io Logo

Автоматизирайте счетоводството с bea

Скриптирайте вашите Beancount книги с bea: разрешете ledger-а изрично, анализирайте JSON обвивката с jq, разклонявайте се по exit кодове, изпълнявайте без потребител, и планирайте нощна проверка.

Скрипт управлява bea с четири решения: кой ledger чете, --json за машинно-четим изход, jq за стойността, от която се нуждае, и exit кода, по който се разклонява. Това ръководство преминава през тези четири решения от начало до край, след което ги планира.

Трябва ви bea на машината, която изпълнява задачата, и ledger, до който може да достигне. Ако започвате нови книги, следвайте CLI бърз старт първо. Всеки факт за флагове, ключове на обвивката и exit кодове се проверява в Beancount CLI справка, а не се повтаря тук.

Изберете ledger-а изрично

Посочете файла. Локална команда разрешава своята цел от --file, след това от $BEA_FILE, след това от ./main.bean в работната директория, а планирана задача рядко се изпълнява там, където мислите.

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

Глобалните опции отиват преди командата, както в bea --file main.bean check. Ако разрешеният файл не съществува, командата излиза с 2 и изброява всичките три източника, така че правописна грешка в cron запис се проваля шумно, вместо да валидира грешните книги. Хостирано насочване чрез --ledger флаг все още не съществува; bea никога не качва локален файл имплицитно.

Прочетете JSON обвивката

Добавете глобален --json и всяка поддържана команда отговаря със същата обвивка: bea, target, data, truncated и limit на ограничени списъци. Сумите са десетични низове, а датите са ISO YYYY-MM-DD, така че стойност е безопасна за сравнение, без float някога да влезе в тръбопровода. Ключовете на обвивката са таблично представени в JSON и exit код справка.

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}'

Тези три команди — report, list и import — запазват своите форми на резултати, така че jq път, написан срещу тях, остава валиден. bea --json check и bea --json query също издават обвивката днес, но те са командите, които се предават на родните Beancount изпълними файлове, така че скрипт трябва да се фокусира върху exit статуса на check, а не върху формата на неговия изход. Изберете вашата политика за дубликати умишлено: --duplicates все още е задължителен, когато импорт се нуждае от решение, както прегледът на импорт обяснява.

Спрете на правилния exit код

Разклонявайте се по статуса и прочетете обекта за греща, преди да опитате отново нещо, което записва. В --json режим неуспех не записва нищо на stdout и точно един обект на stderr, чийто error.category назовава класа: 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 е този, който скрипт никога не трябва да повтаря сляпо: той означава, че резултатът е конфликт или е неизвестен, като външна редакция, пристигаща по средата на запис, или init цел, която вече съществува. Проверете ledger-а, след това опитайте отново от свежо четене. Exit 1 покрива грешки при валидиране и всяка друга грешка по време на изпълнение; error.details носи индивидуалните грешки на ledger-а, а error.result носи какво всъщност е направил частичен запис. Ненулев exit никога не гарантира, че нищо не се е променило.

Изпълнете без терминал

bea спира да подканва самостоятелно. --no-input се подразбира винаги, когато stdin не е терминал, винаги, когато --json е зададен, и винаги, когато CI е истина — 1, true, yes или on. В този режим липсващо потвърждение се проваля с exit 2, вместо да чака вечно.

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

Четенията са снизходителни в терминал и строги навсякъде другаде. Когато ledger-ът има грешки при зареждане, query, list и report излизат с 1 под --json, под тръбен stdout, под истина CI или с --strict; предайте собствената --allow-errors на командата, за да приемете частичния отговор вместо това, което също задава ledger_valid: false и попълва ledger_errors в JSON. --strict е огледалният образ: той отказва частични отговори дори в терминал, което е това, което искате, когато човек изпълнява същия скрипт на ръка. bea check няма --allow-errors — докладването на грешки е цялата му работа — и винаги излиза с 1, когато намери такива. Задайте BEA_NO_UPDATE_NOTIFIER=1, за да заглушите пасивното известие за актуализация; истина CI вече прави това.

Планирайте проверка

Изпълнявайте валидиране всяка нощ и оставете exit кода да бъде алармата. И двата блока по-долу са шаблони — пътищата, графикът и изпълнителят са ваши.

# 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

Закачете версията, когато задачата трябва да бъде възпроизводима, и махнете закачката, когато предпочитате да следите изданията. CI вече е истина на GitHub Actions, така че подканванията са изключени и известието за актуализация е тихо, преди да зададете нещо. Няма стъпка за форматиране тук умишлено. Планирана задача не трябва да пренаписва файлове, които не е трябвало, така че използвайте bea format --check в pre-commit кука, която не докосва нищо и излиза с 1, когато файл се нуждае от форматиране.

Използвайте хостирано удостоверение в задача

Задайте BEA_TOKEN, от хранилището за тайни на вашия CI доставчик, и пропуснете влизането в браузъра изцяло. Токенът се чете от средата и никога не се записва на диск, така че нищо не попада в домашната директория на изпълнителя за следващата задача да намери.

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

Exit 0 означава, че удостоверението е разрешено и обвивката назовава акаунта, към който принадлежи; exit 3 с error.category от auth означава, че не е, и съобщението разграничава незададено удостоверение от отхвърлено. bea cloud logout не прави нищо на токен, предоставен по този начин — нито го отменя, нито го премахва, тъй като друга задача може да го споделя — така че отменете изтекъл токен от таблото вместо това. Локалните команди не се нуждаят от никакво удостоверение; само bea cloud и bea ask достигат до хостираната услуга. Пълният списък с променливи е в справката за настройки.

Не всичко отговаря в JSON. bea ask отхвърля JSON режима напълно, bea cloud login се нуждае от човек, а успешен bea cloud logout или bea cloud ledger clone не връща JSON обект за успех — прочетете техния exit статус вместо това. Помощ, версия и изход за завършване на обвивката остават текстови.

Следващи стъпки

Източник: https://beancount.io/bg/docs/Solutions/automate-bookkeeping-with-bea