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