Перейти до основного вмісту
Beancount.io Logo

Автоматизуйте бухгалтерію за допомогою bea

Скриптуйте свої книги Beancount за допомогою bea: розв'язуйте реєстр явно, аналізуйте JSON-обгортку за допомогою jq, розгалужуйтесь за кодами виходу, працюйте без нагляду та плануйте щоденну перевірку.

Скрипт керує bea через чотири рішення: який реєстр він читає, --json для машинозчитуваного виводу, jq для потрібного значення та код виходу, на якому він розгалужується. Цей посібник детально розглядає ці чотири рішення, а потім планує їх.

Вам потрібен bea на машині, що виконує завдання, і реєстр, до якого він може звернутись. Якщо ви починаєте нові книги, спочатку скористайтесь коротким посібником CLI. Кожен факт про прапорці, ключі обгортки та коди виходу шукайте в довіднику CLI Beancount, а не повторюйте тут.

Оберіть реєстр явно

Назвіть файл. Локальна команда розв'язує свій цільовий об'єкт через --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 та кодів виходу.

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, тому скрипт має спиратися на статус виходу check, а не на форму його виводу. Обирайте політику дублікатів свідомо: --duplicates все ще потрібний, коли імпорту потрібне рішення, як пояснюється в покроковому посібнику з імпорту.

Зупиніться на правильному коді виходу

Розгалужуйтесь за статусом і читайте об'єкт помилки, перш ніж повторювати будь-що, що записує. У режимі --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

Код виходу 4 — це той, який скрипт ніколи не повинен повторювати наосліп: він означає, що результат є конфліктом або невідомим, наприклад, зовнішнє редагування прибуло під час запису або ціль init вже існує. Перевірте реєстр, потім повторіть зі свіжого читання. Код виходу 1 охоплює помилки перевірки та будь-які інші помилки виконання; error.details несе окремі помилки реєстру, а error.result несе те, що частковий запис фактично зробив. Ненульовий код виходу ніколи не гарантує, що нічого не змінилося.

Працюйте без терміналу

bea самостійно припиняє запити. --no-input мається на увазі, коли stdin не є терміналом, коли встановлено --json, і коли CI є істинним — 1, true, yes або on. У цьому режимі відсутнє підтвердження завершується кодом виходу 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

Читання поблажливі в терміналі та суворі всюди інакше. Коли реєстр має помилки завантажувача, 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 вже це робить.

Заплануйте перевірку

Запускайте перевірку щоночі, і нехай код виходу буде попередженням. Обидва блоки нижче є шаблонами — шляхи, розклад і виконувач — ваші.

# 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

Код виходу 0 означає, що облікові дані розв'язані, а обгортка називає обліковий запис, якому вони належать; код виходу 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-об'єкт успіху — читайте їхній статус виходу. Вивід довідки, версії та завершення командного рядка залишається текстовим.

Наступні кроки

Джерело: https://beancount.io/uk/docs/Solutions/automate-bookkeeping-with-bea