add transaction CSV export and category suggestion features
This commit is contained in:
@@ -2,6 +2,7 @@ import yaml
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import TypedDict
|
||||
from typing_extensions import NotRequired
|
||||
|
||||
import ynab
|
||||
|
||||
@@ -19,6 +20,14 @@ class YNABTransaction(TypedDict):
|
||||
account_name: str
|
||||
cleared: str
|
||||
import_id: str | None
|
||||
subtransactions: NotRequired[list["YNABSubTransaction"]]
|
||||
|
||||
|
||||
class YNABSubTransaction(TypedDict):
|
||||
"""Category and amount data for one line of a split transaction."""
|
||||
|
||||
category_name: str | None
|
||||
amount_milliCurrency: int
|
||||
|
||||
|
||||
class YNABConfig(TypedDict):
|
||||
@@ -75,6 +84,7 @@ class YNABClient:
|
||||
self,
|
||||
days: int = 30,
|
||||
exclude_cleared_statuses: list[str] | None = None,
|
||||
include_subtransactions: bool = False,
|
||||
) -> list[YNABTransaction]:
|
||||
"""
|
||||
Fetch transactions from configured accounts for the past x days.
|
||||
@@ -83,6 +93,7 @@ class YNABClient:
|
||||
days: Number of days to look back (default: 30)
|
||||
exclude_cleared_statuses: Optional list of normalized statuses to skip,
|
||||
for example ["reconciled"]
|
||||
include_subtransactions: Include category-level amounts for split transactions.
|
||||
|
||||
Returns:
|
||||
List of transactions with transformed data
|
||||
@@ -149,6 +160,17 @@ class YNABClient:
|
||||
"cleared": cleared_status,
|
||||
"import_id": txn.import_id,
|
||||
}
|
||||
if include_subtransactions:
|
||||
subtransactions: list[YNABSubTransaction] = []
|
||||
for sub in txn.subtransactions or []:
|
||||
category_name = sub.category_name
|
||||
if not category_name and sub.category_id:
|
||||
category_name = category_map.get(str(sub.category_id))
|
||||
subtransactions.append({
|
||||
"category_name": category_name,
|
||||
"amount_milliCurrency": sub.amount,
|
||||
})
|
||||
processed["subtransactions"] = subtransactions
|
||||
transactions.append(processed)
|
||||
|
||||
except Exception as e:
|
||||
@@ -173,6 +195,17 @@ class YNABClient:
|
||||
return account.balance
|
||||
raise ValueError(f"Account {account_id} not found")
|
||||
|
||||
def get_category_ids_by_name(self) -> dict[str, list[str]]:
|
||||
"""Return category IDs grouped by case-insensitive category name."""
|
||||
response = self.categories_api.get_categories(self.plan_id)
|
||||
category_ids: dict[str, list[str]] = {}
|
||||
for category_group in response.data.category_groups:
|
||||
for category in category_group.categories:
|
||||
if category.id and category.name:
|
||||
key = category.name.strip().casefold()
|
||||
category_ids.setdefault(key, []).append(str(category.id))
|
||||
return category_ids
|
||||
|
||||
def get_last_reconciled_date(
|
||||
self,
|
||||
account_ids: list[str] | None = None,
|
||||
|
||||
Reference in New Issue
Block a user