From 166f82d0bfdc598099c088275d68dc42499694f9 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 2 Jul 2026 09:10:46 +0200 Subject: feat: tx add --from-id/--to-id to disambiguate same-name accounts (v0.3.7) ISSUES.md #2: two accounts can share a name (e.g. expense id 52 and revenue id 129 both "Nexi"), making --from/--to ambiguous and unresolvable. Add --from-id/--to-id to target an account by numeric id. Per side, exactly one of the name flag or the id flag; sides independent. The id path fetches the account (resolver.account_by_id), validating existence before writing. Name-only callers unchanged; JSON/exit unchanged, so PATCH. Co-Authored-By: Claude Opus 4.8 --- firefly_cli/commands/transaction.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'firefly_cli/commands') diff --git a/firefly_cli/commands/transaction.py b/firefly_cli/commands/transaction.py index 714d2d4..3ce20f3 100644 --- a/firefly_cli/commands/transaction.py +++ b/firefly_cli/commands/transaction.py @@ -22,8 +22,12 @@ def _infer_type(src_type, dst_type): def _add_args(p): p.add_argument("amount") - p.add_argument("--from", dest="source", required=True, help="source account") - p.add_argument("--to", dest="dest", required=True, help="destination account") + p.add_argument("--from", dest="source", default=None, help="source account (name)") + p.add_argument("--to", dest="dest", default=None, help="destination account (name)") + p.add_argument("--from-id", dest="source_id", default=None, + help="source account by numeric id (disambiguates same-name accounts)") + p.add_argument("--to-id", dest="dest_id", default=None, + help="destination account by numeric id (disambiguates same-name accounts)") p.add_argument("--desc", default=None) p.add_argument("--date", default=None, help="YYYY-MM-DD (default today)") p.add_argument("--category", default=None) @@ -36,9 +40,18 @@ def _add_args(p): help="skip if a tx with same amount+date+source+destination exists") @registry.command("tx add", help="record a transaction; source/destination resolve to accounts, category/tags auto-create", args=_add_args) +def _resolve_side(ctx, name, acc_id, side): + # Exactly one of name/id per side (mutually exclusive). id path (ISSUES.md + # #2) fetches by id, validating existence; name path resolves as before. + if bool(name) == bool(acc_id): + raise FireflyError( + f"--{side}/--{side}-id: supply exactly one " + f"(got name={name!r}, id={acc_id!r})") + return ctx.resolver.account_by_id(acc_id) if acc_id else ctx.resolver.account(name) + def cmd_add(args, ctx): - src = ctx.resolver.account(args.source) - dst = ctx.resolver.account(args.dest) + src = _resolve_side(ctx, args.source, args.source_id, "from") + dst = _resolve_side(ctx, args.dest, args.dest_id, "to") ttype = args.type or _infer_type(src.get("type"), dst.get("type")) from datetime import date as _date split = { -- cgit v1.2.3