Add chase accounts + chase csv upload
This commit is contained in:
0
backend/app/services/__init__.py
Normal file
0
backend/app/services/__init__.py
Normal file
69
backend/app/services/chase_csv.py
Normal file
69
backend/app/services/chase_csv.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import csv
|
||||
import io
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def parse_chase_csv(content: str, account_type: str) -> tuple[list[dict], list[str]]:
|
||||
"""Parse a Chase CSV file into transaction dicts.
|
||||
|
||||
Returns (rows, errors) where rows is a list of dicts with keys:
|
||||
date, amount, category, description.
|
||||
"""
|
||||
content = content.lstrip("\ufeff")
|
||||
reader = csv.DictReader(io.StringIO(content))
|
||||
|
||||
if not reader.fieldnames:
|
||||
return [], ["Empty CSV file"]
|
||||
|
||||
first_field = reader.fieldnames[0].strip()
|
||||
if first_field == "Details":
|
||||
return _parse_checking(reader)
|
||||
elif first_field == "Transaction Date":
|
||||
return _parse_credit_card(reader)
|
||||
else:
|
||||
return [], [f"Unrecognized CSV format (first column: '{first_field}')"]
|
||||
|
||||
|
||||
def _parse_checking(reader: csv.DictReader) -> tuple[list[dict], list[str]]:
|
||||
"""Chase checking/savings: Details,Posting Date,Description,Amount,Type,Balance,Check or Slip #"""
|
||||
rows = []
|
||||
errors = []
|
||||
for i, row in enumerate(reader, start=2):
|
||||
try:
|
||||
date_str = row.get("Posting Date", "").strip()
|
||||
description = row.get("Description", "").strip()
|
||||
amount_str = row.get("Amount", "").strip()
|
||||
if not date_str or not amount_str:
|
||||
continue
|
||||
rows.append({
|
||||
"date": datetime.strptime(date_str, "%m/%d/%Y").date(),
|
||||
"amount": float(amount_str),
|
||||
"category": "Uncategorized",
|
||||
"description": description,
|
||||
})
|
||||
except (ValueError, KeyError) as e:
|
||||
errors.append(f"Row {i}: {e}")
|
||||
return rows, errors
|
||||
|
||||
|
||||
def _parse_credit_card(reader: csv.DictReader) -> tuple[list[dict], list[str]]:
|
||||
"""Chase credit card: Transaction Date,Post Date,Description,Category,Type,Amount,Memo"""
|
||||
rows = []
|
||||
errors = []
|
||||
for i, row in enumerate(reader, start=2):
|
||||
try:
|
||||
date_str = row.get("Transaction Date", "").strip()
|
||||
description = row.get("Description", "").strip()
|
||||
amount_str = row.get("Amount", "").strip()
|
||||
category = row.get("Category", "").strip() or "Uncategorized"
|
||||
if not date_str or not amount_str:
|
||||
continue
|
||||
rows.append({
|
||||
"date": datetime.strptime(date_str, "%m/%d/%Y").date(),
|
||||
"amount": float(amount_str),
|
||||
"category": category,
|
||||
"description": description,
|
||||
})
|
||||
except (ValueError, KeyError) as e:
|
||||
errors.append(f"Row {i}: {e}")
|
||||
return rows, errors
|
||||
Reference in New Issue
Block a user