MJ-Prod commited on
Commit
7640e2d
·
1 Parent(s): c21f683
Files changed (1) hide show
  1. plaid_client.py +90 -0
plaid_client.py CHANGED
@@ -207,6 +207,96 @@ def exchange_public_token(public_token: str) -> str:
207
 
208
 
209
  def get_chart_data(access_token: str) -> dict:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  """Returns structured JSON for frontend charts."""
211
  end_date = date.today()
212
  start_date = end_date - timedelta(days=30)
 
207
 
208
 
209
  def get_chart_data(access_token: str) -> dict:
210
+ """Returns burn-down velocity chart data."""
211
+ end_date = date.today()
212
+ start_date = end_date.replace(day=1) # Start of current month
213
+
214
+ # Get balances
215
+ accounts = []
216
+ try:
217
+ balance_req = AccountsBalanceGetRequest(access_token=access_token)
218
+ balance_resp = plaid_client.accounts_balance_get(balance_req)
219
+ for account in balance_resp['accounts']:
220
+ current = account['balances']['current']
221
+ if current is None:
222
+ continue
223
+ accounts.append({
224
+ "name": account['name'],
225
+ "type": str(account['subtype']),
226
+ "balance": round(current, 2),
227
+ })
228
+ except Exception as e:
229
+ print(f"Balance error in chart_data: {e}", flush=True)
230
+
231
+ # Get transactions for current month
232
+ burndown = []
233
+ income_total = 0.0
234
+ expense_total = 0.0
235
+
236
+ try:
237
+ request = TransactionsGetRequest(
238
+ access_token=access_token,
239
+ start_date=start_date,
240
+ end_date=end_date,
241
+ options=TransactionsGetRequestOptions(
242
+ count=200,
243
+ include_personal_finance_category=True
244
+ )
245
+ )
246
+ response = plaid_client.transactions_get(request)
247
+ transactions = response['transactions']
248
+
249
+ # Build daily income and spending
250
+ daily_income: dict[str, float] = {}
251
+ daily_spending: dict[str, float] = {}
252
+
253
+ for txn in transactions:
254
+ amount = txn['amount']
255
+ txn_date = str(txn['date'])
256
+ category = txn.get('personal_finance_category', {}).get('primary', 'OTHER')
257
+
258
+ if amount < 0:
259
+ income_total += abs(amount)
260
+ daily_income[txn_date] = daily_income.get(txn_date, 0) + abs(amount)
261
+ continue
262
+
263
+ if category in ['TRANSFER_IN', 'TRANSFER_OUT']:
264
+ continue
265
+
266
+ name_lower = txn['name'].lower()
267
+ if category == 'LOAN_PAYMENTS' and any(w in name_lower for w in ['payroll', 'salary', 'direct dep', 'employer', 'wages']):
268
+ income_total += amount
269
+ daily_income[txn_date] = daily_income.get(txn_date, 0) + amount
270
+ continue
271
+
272
+ expense_total += amount
273
+ daily_spending[txn_date] = daily_spending.get(txn_date, 0) + amount
274
+
275
+ # Build burn-down: start with total income, subtract spending each day
276
+ running_balance = income_total
277
+ current = start_date
278
+ while current <= end_date:
279
+ day_str = str(current)
280
+ day_spend = daily_spending.get(day_str, 0)
281
+ day_income = daily_income.get(day_str, 0)
282
+ running_balance = running_balance - day_spend + (day_income if current != start_date else 0)
283
+
284
+ burndown.append({
285
+ "date": current.strftime("%b %d"),
286
+ "balance": round(running_balance, 2),
287
+ "spent": round(day_spend, 2),
288
+ })
289
+ current += timedelta(days=1)
290
+
291
+ except Exception as e:
292
+ print(f"Transaction error in chart_data: {e}", flush=True)
293
+
294
+ return {
295
+ "burndown": burndown,
296
+ "income_total": round(income_total, 2),
297
+ "expense_total": round(expense_total, 2),
298
+ "accounts": accounts,
299
+ }
300
  """Returns structured JSON for frontend charts."""
301
  end_date = date.today()
302
  start_date = end_date - timedelta(days=30)