Files
scripts/cleaners/nationwide-cleaner.py
2026-03-08 14:54:52 +00:00

133 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python3
import csv
from decimal import Decimal, InvalidOperation
from pathlib import Path
from datetime import datetime
import sys
RAW_DIR = Path("/home/zaine/master-folder/attachments/bank-statements/nationwide/raw")
CLEANED_DIR = Path("/home/zaine/master-folder/attachments/bank-statements/nationwide/cleaned")
def clean_money(value: str) -> Decimal | None:
if not value:
return None
value = (
value.replace("£", "")
.replace(",", "")
.strip()
)
if not value:
return None
try:
return Decimal(value)
except InvalidOperation:
return None
def parse_date(value: str) -> str | None:
"""
Convert '01 Dec 2025''12/01/2025'
"""
value = value.strip()
if not value:
return None
try:
dt = datetime.strptime(value, "%d %b %Y")
return dt.strftime("%m/%d/%Y")
except ValueError:
return None
def convert(in_path: Path, out_path: Path):
with open(in_path, newline="", encoding="latin-1") as f_in, \
open(out_path, "w", newline="", encoding="utf-8") as f_out:
reader = csv.reader(f_in)
# Skip metadata lines until header
for row in reader:
if row and row[0] == "Date":
header = row
break
else:
raise RuntimeError("Could not find Nationwide CSV header row")
dict_reader = csv.DictReader(f_in, fieldnames=header)
fieldnames = ["Date", "Payee", "Description", "Amount"]
writer = csv.DictWriter(f_out, fieldnames=fieldnames)
writer.writeheader()
for row in dict_reader:
raw_date = row.get("Date") or ""
date = parse_date(raw_date)
if not date:
continue
desc = (row.get("Description") or "").strip()
payee = desc
paid_out = clean_money(row.get("Paid out", ""))
paid_in = clean_money(row.get("Paid in", ""))
if paid_out is not None:
amount = -paid_out
elif paid_in is not None:
amount = paid_in
else:
continue
writer.writerow({
"Date": date,
"Payee": payee,
"Description": desc,
"Amount": f"{amount:.2f}",
})
def select_file(files: list[Path]) -> Path:
print("\nSelect a Nationwide CSV to clean:\n")
for i, f in enumerate(files, start=1):
print(f"[{i}] {f.name}")
try:
choice = int(input("\nEnter number: ").strip())
return files[choice - 1]
except (ValueError, IndexError):
print("Invalid selection.")
sys.exit(1)
def main():
if not RAW_DIR.exists():
print(f"Raw directory does not exist: {RAW_DIR}")
sys.exit(1)
CLEANED_DIR.mkdir(parents=True, exist_ok=True)
csv_files = sorted(RAW_DIR.glob("*.csv"))
if not csv_files:
print("No CSV files found in raw directory.")
sys.exit(0)
in_path = select_file(csv_files)
out_name = f"{in_path.stem}-cleaned.csv"
out_path = CLEANED_DIR / out_name
convert(in_path, out_path)
print(f"\n✔ Written cleaned file to:\n{out_path}\n")
if __name__ == "__main__":
main()