beancount-cli 0.2.7__tar.gz → 0.2.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/CHANGELOG.md +15 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/PKG-INFO +39 -12
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/README.md +38 -11
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/pyproject.toml +1 -1
- beancount_cli-0.2.9/src/beancount_cli/__init__.py +1 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/adapters.py +12 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/cli.py +4 -3
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/commands/account.py +33 -11
- beancount_cli-0.2.9/src/beancount_cli/commands/commodity.py +100 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/commands/common.py +8 -0
- beancount_cli-0.2.9/src/beancount_cli/commands/price.py +238 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/commands/root.py +31 -62
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/commands/transaction.py +5 -10
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/models.py +26 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/services.py +191 -37
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/smoke_test.py +1 -1
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_cli.py +7 -22
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_coverage_gap.py +30 -2
- beancount_cli-0.2.7/src/beancount_cli/__init__.py +0 -1
- beancount_cli-0.2.7/src/beancount_cli/commands/commodity.py +0 -50
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/.gitignore +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/LICENSE +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/commands/__init__.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/commands/report.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/config.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/formatting.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/src/beancount_cli/py.typed +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/conftest.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_advanced.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_bql.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_config.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_models.py +0 -0
- {beancount_cli-0.2.7 → beancount_cli-0.2.9}/tests/test_services.py +0 -0
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.8] - 2026-04-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `commodity list`: List all declared commodities, with optional `--asset-class` filter.
|
|
12
|
+
- `commodity check`: Identify currencies used in transactions that are missing a `commodity` directive.
|
|
13
|
+
- `price check`: Identify periods of missing price data for held assets. Supports `--rate` (daily, weekday, weekly, monthly) and `--tolerance` (days before flagging a gap).
|
|
14
|
+
- `price fetch`: Fetch latest quotes via the `bean-price` library with `--update`, `--fill-gaps`, `--dry-run`, `--inactive`, and `--verbose` options.
|
|
15
|
+
- `account balance`: Add a `balance` assertion directive to the ledger via `--json`.
|
|
16
|
+
- `--target` flag on `transaction add`, `account create`, and `commodity create` to override the destination file, bypassing config-driven routing.
|
|
17
|
+
- Structured JSON error output for `check --format json` with typed `error_type` and `exit_code` fields.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `price` is now a subcommand group (`price check`, `price fetch`), replacing the former single `price` command.
|
|
21
|
+
- `check` now exits with code `2` on missing/unreadable files (system error) and code `1` on validation errors, instead of raising an uncaught exception.
|
|
22
|
+
|
|
8
23
|
## [0.2.6] - 2026-03-03
|
|
9
24
|
|
|
10
25
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: beancount-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: A CLI tool to manage Beancount ledgers
|
|
5
5
|
Project-URL: Homepage, https://github.com/romamo/beancount-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/romamo/beancount-cli
|
|
@@ -42,9 +42,9 @@ A robust command-line interface and Python library for programmatically managing
|
|
|
42
42
|
- Add transactions via CLI arguments or JSON (stdin supported).
|
|
43
43
|
- Draft mode support (flag `!`).
|
|
44
44
|
- **Entities**:
|
|
45
|
-
- Manage Accounts (list, create).
|
|
46
|
-
- Manage Commodities (create).
|
|
47
|
-
- Manage Prices (
|
|
45
|
+
- Manage Accounts (list, create, balance assertion).
|
|
46
|
+
- Manage Commodities (list, create, check undeclared).
|
|
47
|
+
- Manage Prices (check gaps, fetch/update via bean-price).
|
|
48
48
|
- **Formatting**:
|
|
49
49
|
- Auto-format ledgers (`bean-format` wrapper).
|
|
50
50
|
- Global output formatting: `--format` support (`table`, `json`, `csv`) for all data commands.
|
|
@@ -125,7 +125,7 @@ bean report trial-balance main.beancount
|
|
|
125
125
|
bean report holdings main.beancount
|
|
126
126
|
|
|
127
127
|
# Audit a specific currency (Source of Exposure)
|
|
128
|
-
bean report audit USD main.beancount
|
|
128
|
+
bean report audit --currency USD main.beancount
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
> [!TIP]
|
|
@@ -167,7 +167,7 @@ bean transaction add main.beancount --json ... --draft
|
|
|
167
167
|
|
|
168
168
|
### Manage Accounts & Commodities
|
|
169
169
|
|
|
170
|
-
All creation commands (`transaction add`, `account create`, `commodity create`) support batch processing via JSON arrays on STDIN.
|
|
170
|
+
All creation commands (`transaction add`, `account create`, `commodity create`) support batch processing via JSON arrays on STDIN. Use `--target` to override the destination file.
|
|
171
171
|
|
|
172
172
|
```bash
|
|
173
173
|
# Batch add transactions from a file
|
|
@@ -177,19 +177,46 @@ cat txs.json | bean transaction add --json -
|
|
|
177
177
|
bean --format json account list --file old.beancount | bean account create --json -
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
**
|
|
180
|
+
**Accounts:**
|
|
181
181
|
```bash
|
|
182
|
-
# List
|
|
182
|
+
# List accounts
|
|
183
183
|
bean account list
|
|
184
184
|
|
|
185
|
-
# Create
|
|
185
|
+
# Create account
|
|
186
186
|
bean account create --name "Assets:NewBank" --currency "USD"
|
|
187
187
|
|
|
188
|
-
#
|
|
188
|
+
# Add a balance assertion
|
|
189
|
+
bean account balance --json '{"date": "2024-01-01", "account": "Assets:Bank", "amount": {"number": 1000, "currency": "USD"}}'
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Commodities:**
|
|
193
|
+
```bash
|
|
194
|
+
# List all declared commodities
|
|
195
|
+
bean commodity list
|
|
196
|
+
|
|
197
|
+
# List by asset class
|
|
198
|
+
bean commodity list --asset-class stock
|
|
199
|
+
|
|
200
|
+
# Find currencies used in transactions but missing a commodity directive
|
|
201
|
+
bean commodity check
|
|
202
|
+
|
|
203
|
+
# Create a commodity
|
|
189
204
|
bean commodity create "BTC" --name "Bitcoin"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Prices:**
|
|
208
|
+
```bash
|
|
209
|
+
# Check for periods of missing price data
|
|
210
|
+
bean price check
|
|
211
|
+
|
|
212
|
+
# Check with weekly rate and 14-day tolerance
|
|
213
|
+
bean price check --rate weekly --tolerance 14
|
|
214
|
+
|
|
215
|
+
# Fetch latest quotes (dry run)
|
|
216
|
+
bean price fetch --dry-run
|
|
190
217
|
|
|
191
|
-
# Fetch and
|
|
192
|
-
bean price --update
|
|
218
|
+
# Fetch and write new prices to the ledger
|
|
219
|
+
bean price fetch --update
|
|
193
220
|
```
|
|
194
221
|
|
|
195
222
|
`beancount-cli` is specifically optimized for AI agents, providing both operational guidance and machine-readable interfaces.
|
|
@@ -11,9 +11,9 @@ A robust command-line interface and Python library for programmatically managing
|
|
|
11
11
|
- Add transactions via CLI arguments or JSON (stdin supported).
|
|
12
12
|
- Draft mode support (flag `!`).
|
|
13
13
|
- **Entities**:
|
|
14
|
-
- Manage Accounts (list, create).
|
|
15
|
-
- Manage Commodities (create).
|
|
16
|
-
- Manage Prices (
|
|
14
|
+
- Manage Accounts (list, create, balance assertion).
|
|
15
|
+
- Manage Commodities (list, create, check undeclared).
|
|
16
|
+
- Manage Prices (check gaps, fetch/update via bean-price).
|
|
17
17
|
- **Formatting**:
|
|
18
18
|
- Auto-format ledgers (`bean-format` wrapper).
|
|
19
19
|
- Global output formatting: `--format` support (`table`, `json`, `csv`) for all data commands.
|
|
@@ -94,7 +94,7 @@ bean report trial-balance main.beancount
|
|
|
94
94
|
bean report holdings main.beancount
|
|
95
95
|
|
|
96
96
|
# Audit a specific currency (Source of Exposure)
|
|
97
|
-
bean report audit USD main.beancount
|
|
97
|
+
bean report audit --currency USD main.beancount
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
> [!TIP]
|
|
@@ -136,7 +136,7 @@ bean transaction add main.beancount --json ... --draft
|
|
|
136
136
|
|
|
137
137
|
### Manage Accounts & Commodities
|
|
138
138
|
|
|
139
|
-
All creation commands (`transaction add`, `account create`, `commodity create`) support batch processing via JSON arrays on STDIN.
|
|
139
|
+
All creation commands (`transaction add`, `account create`, `commodity create`) support batch processing via JSON arrays on STDIN. Use `--target` to override the destination file.
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
142
|
# Batch add transactions from a file
|
|
@@ -146,19 +146,46 @@ cat txs.json | bean transaction add --json -
|
|
|
146
146
|
bean --format json account list --file old.beancount | bean account create --json -
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
**
|
|
149
|
+
**Accounts:**
|
|
150
150
|
```bash
|
|
151
|
-
# List
|
|
151
|
+
# List accounts
|
|
152
152
|
bean account list
|
|
153
153
|
|
|
154
|
-
# Create
|
|
154
|
+
# Create account
|
|
155
155
|
bean account create --name "Assets:NewBank" --currency "USD"
|
|
156
156
|
|
|
157
|
-
#
|
|
157
|
+
# Add a balance assertion
|
|
158
|
+
bean account balance --json '{"date": "2024-01-01", "account": "Assets:Bank", "amount": {"number": 1000, "currency": "USD"}}'
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Commodities:**
|
|
162
|
+
```bash
|
|
163
|
+
# List all declared commodities
|
|
164
|
+
bean commodity list
|
|
165
|
+
|
|
166
|
+
# List by asset class
|
|
167
|
+
bean commodity list --asset-class stock
|
|
168
|
+
|
|
169
|
+
# Find currencies used in transactions but missing a commodity directive
|
|
170
|
+
bean commodity check
|
|
171
|
+
|
|
172
|
+
# Create a commodity
|
|
158
173
|
bean commodity create "BTC" --name "Bitcoin"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Prices:**
|
|
177
|
+
```bash
|
|
178
|
+
# Check for periods of missing price data
|
|
179
|
+
bean price check
|
|
180
|
+
|
|
181
|
+
# Check with weekly rate and 14-day tolerance
|
|
182
|
+
bean price check --rate weekly --tolerance 14
|
|
183
|
+
|
|
184
|
+
# Fetch latest quotes (dry run)
|
|
185
|
+
bean price fetch --dry-run
|
|
159
186
|
|
|
160
|
-
# Fetch and
|
|
161
|
-
bean price --update
|
|
187
|
+
# Fetch and write new prices to the ledger
|
|
188
|
+
bean price fetch --update
|
|
162
189
|
```
|
|
163
190
|
|
|
164
191
|
`beancount-cli` is specifically optimized for AI agents, providing both operational guidance and machine-readable interfaces.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.9"
|
|
@@ -5,6 +5,7 @@ from beancount.core import amount, data, position
|
|
|
5
5
|
from beancount_cli.models import (
|
|
6
6
|
AccountName,
|
|
7
7
|
AmountModel,
|
|
8
|
+
BalanceModel,
|
|
8
9
|
CostModel,
|
|
9
10
|
CurrencyCode,
|
|
10
11
|
PostingModel,
|
|
@@ -98,3 +99,14 @@ def from_core_transaction(core: data.Transaction) -> TransactionModel:
|
|
|
98
99
|
postings=[from_core_posting(p) for p in core.postings],
|
|
99
100
|
meta=core.meta or {},
|
|
100
101
|
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def to_core_balance(model: BalanceModel) -> data.Balance:
|
|
105
|
+
return data.Balance(
|
|
106
|
+
meta=model.meta or {},
|
|
107
|
+
date=model.date,
|
|
108
|
+
account=str(model.account),
|
|
109
|
+
amount=to_core_amount(model.amount),
|
|
110
|
+
diff_amount=None,
|
|
111
|
+
tolerance=None,
|
|
112
|
+
)
|
|
@@ -5,8 +5,9 @@ import agentyper as typer
|
|
|
5
5
|
from beancount_cli import __version__
|
|
6
6
|
from beancount_cli.commands.account import app as acc_app
|
|
7
7
|
from beancount_cli.commands.commodity import app as comm_app
|
|
8
|
+
from beancount_cli.commands.price import app as price_app
|
|
8
9
|
from beancount_cli.commands.report import app as report_app
|
|
9
|
-
from beancount_cli.commands.root import check, format_cmd,
|
|
10
|
+
from beancount_cli.commands.root import check, format_cmd, tree
|
|
10
11
|
from beancount_cli.commands.transaction import app as tx_app
|
|
11
12
|
|
|
12
13
|
app = typer.Agentyper(
|
|
@@ -19,11 +20,11 @@ app.add_typer(report_app, name="report")
|
|
|
19
20
|
app.add_typer(tx_app, name="transaction")
|
|
20
21
|
app.add_typer(acc_app, name="account")
|
|
21
22
|
app.add_typer(comm_app, name="commodity")
|
|
22
|
-
|
|
23
23
|
app.command(name="check")(check)
|
|
24
24
|
app.command(name="tree")(tree)
|
|
25
25
|
app.command(name="format")(format_cmd)
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
app.add_typer(price_app, name="price")
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def main(args=None):
|
|
@@ -6,8 +6,13 @@ from pathlib import Path
|
|
|
6
6
|
import agentyper as typer
|
|
7
7
|
from pydantic import TypeAdapter
|
|
8
8
|
|
|
9
|
-
from beancount_cli.commands.common import
|
|
10
|
-
|
|
9
|
+
from beancount_cli.commands.common import (
|
|
10
|
+
_is_table_format,
|
|
11
|
+
console,
|
|
12
|
+
get_ledger_file,
|
|
13
|
+
read_json_input,
|
|
14
|
+
)
|
|
15
|
+
from beancount_cli.models import AccountModel, BalanceModel
|
|
11
16
|
from beancount_cli.services import AccountService
|
|
12
17
|
|
|
13
18
|
app = typer.Agentyper(help="Manage accounts.")
|
|
@@ -53,27 +58,23 @@ def account_create(
|
|
|
53
58
|
json_data: str | None = typer.Option(
|
|
54
59
|
None, "--json", "-j", help="JSON string data (or '-' to read from STDIN)"
|
|
55
60
|
),
|
|
61
|
+
target: Path | None = typer.Option(None, "--target", help="Override target file to write to"),
|
|
56
62
|
):
|
|
57
63
|
"""Create a new account."""
|
|
58
64
|
actual_file = get_ledger_file(ledger_file or file)
|
|
59
65
|
service = AccountService(actual_file)
|
|
60
66
|
|
|
61
67
|
if json_data:
|
|
62
|
-
|
|
63
|
-
content = sys.stdin.read()
|
|
64
|
-
else:
|
|
65
|
-
content = json_data
|
|
66
|
-
|
|
67
|
-
data_input = json.loads(content)
|
|
68
|
+
data_input = json.loads(read_json_input(json_data))
|
|
68
69
|
if isinstance(data_input, list):
|
|
69
70
|
ta = TypeAdapter(list[AccountModel])
|
|
70
71
|
models = ta.validate_python(data_input)
|
|
71
72
|
for m in models:
|
|
72
|
-
service.create_account(m)
|
|
73
|
+
service.create_account(m, target_file=target)
|
|
73
74
|
console.print(f"[green]Account {m.name} created.[/green]")
|
|
74
75
|
else:
|
|
75
76
|
model = AccountModel(**data_input)
|
|
76
|
-
service.create_account(model)
|
|
77
|
+
service.create_account(model, target_file=target)
|
|
77
78
|
console.print(f"[green]Account {model.name} created.[/green]")
|
|
78
79
|
else:
|
|
79
80
|
if not name:
|
|
@@ -86,5 +87,26 @@ def account_create(
|
|
|
86
87
|
|
|
87
88
|
currencies = [c.strip() for c in currency_opt.split(",")] if currency_opt else []
|
|
88
89
|
model = AccountModel(name=name, open_date=d, currencies=currencies)
|
|
89
|
-
service.create_account(model)
|
|
90
|
+
service.create_account(model, target_file=target)
|
|
90
91
|
console.print(f"[green]Account {name} created.[/green]")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@app.command(name="balance")
|
|
95
|
+
def account_balance(
|
|
96
|
+
ledger_file: Path | None = typer.Argument(None, help="Path to ledger file"),
|
|
97
|
+
file: Path | None = typer.Option(
|
|
98
|
+
None, "--file", "-f", envvar="BEANCOUNT_FILE", help="Main beancount file"
|
|
99
|
+
),
|
|
100
|
+
json_data: str = typer.Option(
|
|
101
|
+
..., "--json", "-j", help="JSON string data (or '-' to read from STDIN)"
|
|
102
|
+
),
|
|
103
|
+
target: Path | None = typer.Option(None, "--target", help="Override target file to write to"),
|
|
104
|
+
):
|
|
105
|
+
"""Add a balance directive for an account."""
|
|
106
|
+
actual_file = get_ledger_file(ledger_file or file)
|
|
107
|
+
service = AccountService(actual_file)
|
|
108
|
+
|
|
109
|
+
data_input = json.loads(read_json_input(json_data))
|
|
110
|
+
model = BalanceModel(**data_input)
|
|
111
|
+
service.add_balance(model, target_file=target)
|
|
112
|
+
console.print(f"[green]Balance check for {model.account} added.[/green]")
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import agentyper as typer
|
|
6
|
+
|
|
7
|
+
from beancount_cli.commands.common import (
|
|
8
|
+
_is_table_format,
|
|
9
|
+
console,
|
|
10
|
+
get_ledger_file,
|
|
11
|
+
read_json_input,
|
|
12
|
+
)
|
|
13
|
+
from beancount_cli.services import CommodityService
|
|
14
|
+
|
|
15
|
+
app = typer.Agentyper(help="Manage commodities.")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command(name="list")
|
|
19
|
+
def commodity_list(
|
|
20
|
+
ledger_file: Path | None = typer.Argument(None, help="Path to ledger file"),
|
|
21
|
+
file: Path | None = typer.Option(
|
|
22
|
+
None, "--file", "-f", envvar="BEANCOUNT_FILE", help="Main beancount file"
|
|
23
|
+
),
|
|
24
|
+
asset_class: str | None = typer.Option(
|
|
25
|
+
None, "--asset-class", "-c", help="Filter by asset-class meta (e.g. stock, Cash)"
|
|
26
|
+
),
|
|
27
|
+
):
|
|
28
|
+
"""List all commodities."""
|
|
29
|
+
actual_file = get_ledger_file(ledger_file or file)
|
|
30
|
+
service = CommodityService(actual_file)
|
|
31
|
+
commodities = service.list_commodities(asset_class=asset_class)
|
|
32
|
+
|
|
33
|
+
if _is_table_format():
|
|
34
|
+
data = [
|
|
35
|
+
{
|
|
36
|
+
"Currency": c.currency,
|
|
37
|
+
"Date": str(c.date) if c.date else "",
|
|
38
|
+
"Name": c.meta.get("name", "") if c.meta else "",
|
|
39
|
+
}
|
|
40
|
+
for c in commodities
|
|
41
|
+
]
|
|
42
|
+
typer.output(data, title=f"Commodities ({len(commodities)})")
|
|
43
|
+
else:
|
|
44
|
+
typer.output(commodities, title=f"Commodities ({len(commodities)})")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@app.command(name="check")
|
|
48
|
+
def commodity_check(
|
|
49
|
+
ledger_file: Path | None = typer.Argument(None, help="Path to ledger file"),
|
|
50
|
+
file: Path | None = typer.Option(
|
|
51
|
+
None, "--file", "-f", envvar="BEANCOUNT_FILE", help="Main beancount file"
|
|
52
|
+
),
|
|
53
|
+
):
|
|
54
|
+
"""Check for currencies used in transactions but missing a commodity directive."""
|
|
55
|
+
actual_file = get_ledger_file(ledger_file or file)
|
|
56
|
+
service = CommodityService(actual_file)
|
|
57
|
+
undeclared = service.get_undeclared_commodities()
|
|
58
|
+
|
|
59
|
+
if _is_table_format():
|
|
60
|
+
if not undeclared:
|
|
61
|
+
console.print("[green]All used currencies are declared.[/green]")
|
|
62
|
+
else:
|
|
63
|
+
typer.output(undeclared, title=f"Undeclared Commodities ({len(undeclared)})")
|
|
64
|
+
else:
|
|
65
|
+
typer.output(undeclared, title="Undeclared Commodities")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@app.command(name="create")
|
|
69
|
+
def commodity_create(
|
|
70
|
+
currency: str | None = typer.Argument(None, help="Currency code (e.g. USD)"),
|
|
71
|
+
ledger_file: Path | None = typer.Argument(None, help="Path to ledger file"),
|
|
72
|
+
file: Path | None = typer.Option(
|
|
73
|
+
None, "--file", "-f", envvar="BEANCOUNT_FILE", help="Main beancount file"
|
|
74
|
+
),
|
|
75
|
+
name: str | None = typer.Option(None, "--name", "-n", help="Full name"),
|
|
76
|
+
json_data: str | None = typer.Option(
|
|
77
|
+
None, "--json", "-j", help="JSON string data (or '-' to read from STDIN)"
|
|
78
|
+
),
|
|
79
|
+
):
|
|
80
|
+
"""Create a new commodity."""
|
|
81
|
+
actual_file = get_ledger_file(ledger_file or file)
|
|
82
|
+
service = CommodityService(actual_file)
|
|
83
|
+
|
|
84
|
+
if json_data:
|
|
85
|
+
data_input = json.loads(read_json_input(json_data))
|
|
86
|
+
items = data_input if isinstance(data_input, list) else [data_input]
|
|
87
|
+
for item in items:
|
|
88
|
+
curr = item.get("currency")
|
|
89
|
+
comm_name = item.get("name")
|
|
90
|
+
if not curr:
|
|
91
|
+
console.print(f"[yellow]Skipping invalid commodity entry: {item}[/yellow]")
|
|
92
|
+
continue
|
|
93
|
+
service.create_commodity(curr, name=comm_name)
|
|
94
|
+
console.print(f"[green]Commodity {curr} created.[/green]")
|
|
95
|
+
else:
|
|
96
|
+
if not currency:
|
|
97
|
+
console.print("[red]Error: currency argument is required if not using --json.[/red]")
|
|
98
|
+
sys.exit(typer.EXIT_VALIDATION)
|
|
99
|
+
service.create_commodity(currency, name=name)
|
|
100
|
+
console.print(f"[green]Commodity {currency} created.[/green]")
|
|
@@ -7,6 +7,14 @@ from rich.console import Console
|
|
|
7
7
|
from rich.table import Table
|
|
8
8
|
|
|
9
9
|
console = Console()
|
|
10
|
+
error_console = Console(stderr=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def read_json_input(json_data: str) -> str:
|
|
14
|
+
"""Read JSON from a string or from STDIN when json_data is '-'."""
|
|
15
|
+
if json_data == "-":
|
|
16
|
+
return sys.stdin.read()
|
|
17
|
+
return json_data
|
|
10
18
|
|
|
11
19
|
|
|
12
20
|
def get_ledger_file(override: str | Path | None = None) -> Path:
|