From ea881e272b33c434cd9407a183ca5a4f9e7bb681 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Fri, 17 Apr 2026 20:29:43 +0000 Subject: [PATCH] sinks: match Wealthfolio NewAccount camelCase schema + required booleans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wealthfolio 3.2's POST /api/v1/accounts was 422ing on live traffic — its NewAccount struct uses camelCase field names and requires isDefault + isActive as booleans. Reference: https://github.com/afadil/wealthfolio/blob/main/apps/server/src/models.rs#L~145 Sends trackingMode=TRANSACTIONS so Wealthfolio computes holdings from our imported activities (vs HOLDINGS mode which requires periodic holdings snapshots). Populates providerAccountId so the broker account is traceable back to our sync's id scheme. Test plan: poetry run pytest -q → 70 passed poetry run mypy → clean poetry run ruff check → clean Live re-run of the backfill Job follows this commit's image rebuild. --- broker_sync/sinks/wealthfolio.py | 9 ++++++++- tests/sinks/test_wealthfolio.py | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/broker_sync/sinks/wealthfolio.py b/broker_sync/sinks/wealthfolio.py index 426ec52..a7c2654 100644 --- a/broker_sync/sinks/wealthfolio.py +++ b/broker_sync/sinks/wealthfolio.py @@ -126,15 +126,22 @@ class WealthfolioSink: existing = await self.list_accounts() if any(a.get("id") == account.id for a in existing): return + # Wealthfolio 3.2's NewAccount is camelCase with required booleans. + # See apps/server/src/models.rs#NewAccount. resp = await self._request( "POST", _ACCOUNTS_PATH, json={ "id": account.id, "name": account.name, - "account_type": str(account.account_type), + "accountType": str(account.account_type), "currency": account.currency, + "isDefault": False, + "isActive": True, + "isArchived": False, + "trackingMode": "TRANSACTIONS", "provider": account.provider, + "providerAccountId": account.id, }, ) resp.raise_for_status() diff --git a/tests/sinks/test_wealthfolio.py b/tests/sinks/test_wealthfolio.py index d8969f8..049f6aa 100644 --- a/tests/sinks/test_wealthfolio.py +++ b/tests/sinks/test_wealthfolio.py @@ -183,8 +183,10 @@ async def test_ensure_account_creates_if_missing(tmp_path: Path) -> None: await sink.ensure_account(acc) assert len(posted) == 1 assert posted[0]["id"] == "t212-isa" - assert posted[0]["account_type"] == "ISA" + assert posted[0]["accountType"] == "ISA" assert posted[0]["currency"] == "GBP" + assert posted[0]["isActive"] is True + assert posted[0]["isDefault"] is False # -- Activity import --