summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SKILL.md4
-rw-r--r--completions/firefly.bash1
-rw-r--r--firefly_cli/__init__.py2
-rw-r--r--firefly_cli/commands/account.py15
-rw-r--r--pyproject.toml2
-rw-r--r--tests/unit/test_commands_account.py16
6 files changed, 35 insertions, 5 deletions
diff --git a/SKILL.md b/SKILL.md
index 98b9472..672c97e 100644
--- a/SKILL.md
+++ b/SKILL.md
@@ -52,7 +52,7 @@ If `firefly` is not on PATH, run from the repo with `python -m firefly_cli ...`
firefly auth test verify connectivity and token
firefly account list [--type asset|expense|revenue|liability|...]
firefly account get <name|id>
-firefly account balance <name|id>
+firefly account balance <name|id> [--at YYYY-MM-DD]
firefly account create <name> --type asset|expense|revenue
[--opening-balance N] [--currency CODE]
firefly tx add <amount> --from <acct> --to <acct>
@@ -105,6 +105,8 @@ automatically. Unlike categories/tags, accounts are NOT auto-created by
**Check a balance:**
```bash
firefly account balance test01 # -> {"id","name","current_balance"}
+firefly account balance test01 --at 2026-05-31 # historical: balance as of that date
+ # -> adds "date"; useful for reconciliation
```
**Find recent spending in a window:**
diff --git a/completions/firefly.bash b/completions/firefly.bash
index 697cd1a..b23f081 100644
--- a/completions/firefly.bash
+++ b/completions/firefly.bash
@@ -37,6 +37,7 @@ _firefly() {
local leaf_opts=""
case "$group $leaf" in
"auth set") leaf_opts="--token --url";;
+ "account balance") leaf_opts="--at";;
"account create") leaf_opts="--currency --opening-balance --type";;
"account list") leaf_opts="--type";;
"tx add") leaf_opts="--category --date --desc --from --tags --to --type";;
diff --git a/firefly_cli/__init__.py b/firefly_cli/__init__.py
index 79ea6e3..eb73e59 100644
--- a/firefly_cli/__init__.py
+++ b/firefly_cli/__init__.py
@@ -2,4 +2,4 @@
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
# Licensed under the GNU General Public License v2.0 only.
-__version__ = "0.3.1"
+__version__ = "0.3.2"
diff --git a/firefly_cli/commands/account.py b/firefly_cli/commands/account.py
index 9dbfab6..d78f8fc 100644
--- a/firefly_cli/commands/account.py
+++ b/firefly_cli/commands/account.py
@@ -52,9 +52,22 @@ def cmd_get(args, ctx):
output.emit(acc, human=ctx.human)
return 0
-@registry.command("account balance", help="show current balance for one account (name or id)", args=_name_arg)
+def _balance_args(p):
+ p.add_argument("account", help="account name or id")
+ p.add_argument("--at", default=None,
+ help="balance as of this date YYYY-MM-DD (default: current)")
+
+@registry.command("account balance", help="show balance for one account (name or id); --at for a historical date", args=_balance_args)
def cmd_balance(args, ctx):
acc = ctx.resolver.account(args.account)
+ if args.at:
+ # Firefly recomputes current_balance as of ?date= on the account show endpoint.
+ dated = output.unwrap(ctx.client.request(
+ "GET", f"/api/v1/accounts/{acc['id']}", params={"date": args.at}))
+ output.emit({"id": acc["id"], "name": dated.get("name") or acc.get("name"),
+ "date": args.at,
+ "current_balance": dated.get("current_balance")}, human=ctx.human)
+ return 0
output.emit({"id": acc["id"], "name": acc.get("name"),
"current_balance": acc.get("current_balance")}, human=ctx.human)
return 0
diff --git a/pyproject.toml b/pyproject.toml
index cb0fdaa..fd0d369 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "firefly-iii-agent"
-version = "0.3.1"
+version = "0.3.2"
description = "CLI tool for agent interaction with Firefly III"
readme = "README.md"
requires-python = ">=3.11"
diff --git a/tests/unit/test_commands_account.py b/tests/unit/test_commands_account.py
index 2c07780..4a01292 100644
--- a/tests/unit/test_commands_account.py
+++ b/tests/unit/test_commands_account.py
@@ -22,11 +22,25 @@ class TestAccountCmd(unittest.TestCase):
ctx, client, resolver = make_ctx()
resolver.account.return_value = {"id": "3", "name": "Checking",
"current_balance": "100.00"}
- args = MagicMock(account="Checking")
+ args = MagicMock(account="Checking", at=None)
rc = acct.cmd_balance(args, ctx)
resolver.account.assert_called_once_with("Checking")
+ client.request.assert_not_called() # current balance from resolver, no extra call
self.assertEqual(rc, 0)
+ def test_balance_at_date_fetches_dated_account(self):
+ ctx, client, resolver = make_ctx()
+ resolver.account.return_value = {"id": "3", "name": "Checking",
+ "current_balance": "100.00"}
+ client.request.return_value = {"data": {"id": "3", "attributes": {
+ "name": "Checking", "current_balance": "42.00"}}}
+ args = MagicMock(account="Checking", at="2026-05-31")
+ rc = acct.cmd_balance(args, ctx)
+ self.assertEqual(rc, 0)
+ method, path = client.request.call_args[0][:2]
+ self.assertEqual((method, path), ("GET", "/api/v1/accounts/3"))
+ self.assertEqual(client.request.call_args[1]["params"], {"date": "2026-05-31"})
+
class TestAccountCreate(unittest.TestCase):
def _args(self, **kw):
base = dict(name=None, type=None, opening_balance=None, currency=None)