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:
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 91 KiB |
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user