Fix YNAB transaction fetching for SDK v2 compatibility

- Convert date strings to datetime.date objects before passing to API (strict Pydantic validation rejects strings)
- Use txn.var_date instead of txn.date (renamed in SDK v2 to avoid Python builtin conflict)
- Migrate BudgetsApi → PlansApi and update method names accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ryan
2026-03-12 18:54:20 -04:00
parent da9b52dda1
commit 30d7f0a060
2 changed files with 17 additions and 22 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -27,18 +27,14 @@ class YNABService:
self.api_client = ynab.ApiClient(configuration) self.api_client = ynab.ApiClient(configuration)
# Initialize API endpoints # Initialize API endpoints
self.budgets_api = ynab.BudgetsApi(self.api_client) self.plans_api = ynab.PlansApi(self.api_client)
self.transactions_api = ynab.TransactionsApi(self.api_client) self.transactions_api = ynab.TransactionsApi(self.api_client)
self.months_api = ynab.MonthsApi(self.api_client) self.months_api = ynab.MonthsApi(self.api_client)
self.categories_api = ynab.CategoriesApi(self.api_client) self.categories_api = ynab.CategoriesApi(self.api_client)
# Get budget ID if not provided # Get budget ID if not provided, fall back to last-used
if not self.budget_id: if not self.budget_id:
budgets_response = self.budgets_api.get_budgets() self.budget_id = "last-used"
if budgets_response.data and budgets_response.data.budgets:
self.budget_id = budgets_response.data.budgets[0].id
else:
raise ValueError("No YNAB budgets found")
def get_budget_summary(self) -> dict[str, Any]: def get_budget_summary(self) -> dict[str, Any]:
"""Get overall budget summary and health status. """Get overall budget summary and health status.
@@ -47,7 +43,7 @@ class YNABService:
Dictionary containing budget summary with to-be-budgeted amount, Dictionary containing budget summary with to-be-budgeted amount,
total budgeted, total activity, and overall budget health. total budgeted, total activity, and overall budget health.
""" """
budget_response = self.budgets_api.get_budget_by_id(self.budget_id) budget_response = self.plans_api.get_plan_by_id(self.budget_id)
budget_data = budget_response.data.budget budget_data = budget_response.data.budget
# Calculate totals from categories # Calculate totals from categories
@@ -59,10 +55,7 @@ class YNABService:
total_activity = 0 total_activity = 0
total_available = 0 total_available = 0
for category_group in budget_data.category_groups or []: for category in budget_data.categories or []:
if category_group.deleted or category_group.hidden:
continue
for category in category_group.categories or []:
if category.deleted or category.hidden: if category.deleted or category.hidden:
continue continue
total_budgeted += category.budgeted / 1000 total_budgeted += category.budgeted / 1000
@@ -109,9 +102,10 @@ class YNABService:
if not end_date: if not end_date:
end_date = datetime.now().strftime("%Y-%m-%d") end_date = datetime.now().strftime("%Y-%m-%d")
# Get transactions # Get transactions (SDK v2 requires datetime.date, not string)
since_date_obj = datetime.strptime(start_date, "%Y-%m-%d").date()
transactions_response = self.transactions_api.get_transactions( transactions_response = self.transactions_api.get_transactions(
self.budget_id, since_date=start_date self.budget_id, since_date=since_date_obj
) )
transactions = transactions_response.data.transactions or [] transactions = transactions_response.data.transactions or []
@@ -124,7 +118,7 @@ class YNABService:
# Skip if deleted or before start date or after end date # Skip if deleted or before start date or after end date
if txn.deleted: if txn.deleted:
continue continue
txn_date = str(txn.date) txn_date = str(txn.var_date)
if txn_date < start_date or txn_date > end_date: if txn_date < start_date or txn_date > end_date:
continue continue
@@ -141,7 +135,7 @@ class YNABService:
amount = txn.amount / 1000 # Convert milliunits to dollars amount = txn.amount / 1000 # Convert milliunits to dollars
filtered_transactions.append( filtered_transactions.append(
{ {
"date": txn_date, "date": str(txn.var_date),
"payee": txn.payee_name, "payee": txn.payee_name,
"category": txn.category_name, "category": txn.category_name,
"memo": txn.memo, "memo": txn.memo,
@@ -180,8 +174,9 @@ class YNABService:
if len(month) == 7: # YYYY-MM if len(month) == 7: # YYYY-MM
month = f"{month}-01" month = f"{month}-01"
# Get budget month # Get budget month (SDK v2 requires datetime.date, not string)
month_response = self.months_api.get_budget_month(self.budget_id, month) month_date_obj = datetime.strptime(month, "%Y-%m-%d").date()
month_response = self.months_api.get_plan_month(self.budget_id, month_date_obj)
month_data = month_response.data.month month_data = month_response.data.month