This commit is contained in:
John Lamb 2025-02-24 21:57:36 -06:00
commit 7aa2260bfd
3 changed files with 181 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*/.DS_Store/*
.env
*/.idea/*
CapitalOne.csv
Chase.csv
*/__pychache__/*

90
process_csv.py Normal file
View File

@ -0,0 +1,90 @@
import logging
import os
import csv
import subprocess
from datetime import date, datetime
from collections import namedtuple
from tx_categories import TX_TO_CATEGORY, Category
logging.basicConfig(level=logging.INFO)
# poetry run python process_csv.py
# DESIRED_MONTH = date.today().month
DESIRED_MONTH = 2
CSV_TX = namedtuple('CSV_TX', ['TX_DATE', 'POST_DATE', 'DESCRIPTION', 'CATEGORY', 'TYPE', 'AMOUNT', 'MEMO'])
class Transaction:
def __init__(self, date, payee, type, amount):
# self.date = date.replace(tzinfo=pytz.utc).astimezone(pytz.timezone('America/Chicago'))
self.date = date
self.payee = payee
self.type = type
self.amount = amount
self.category = self.get_category()
def get_category(self):
category = None
for agent, cat in TX_TO_CATEGORY.items():
if agent.lower() in self.payee.lower():
category = cat
return category or Category.OTHER
def load_chase_csv():
working_dir = os.path.abspath(os.getcwd())
filenames = os.listdir(working_dir)
tx_filename = None
for filename in filenames:
if filename.lower().startswith("chase"):
tx_filename = os.path.join(working_dir, filename)
break
if not tx_filename:
exit("Could not find tx file")
with open(tx_filename) as csvfile:
reader = csv.reader(csvfile, delimiter=',', quotechar='|')
output = list(reader)
all_transactions = []
for raw_tx in output[1:]:
all_transactions.append(CSV_TX(*raw_tx))
return all_transactions
def get_transactions(all_transactions):
formatted_transactions = []
for tx in all_transactions:
tx_post_date = datetime.strptime(tx.POST_DATE, '%m/%d/%Y')
if tx_post_date.month != DESIRED_MONTH or tx_post_date.year != date.today().year:
continue
cc_trans = Transaction(
date=tx_post_date,
payee=tx.DESCRIPTION,
type=tx.TYPE,
amount=tx.AMOUNT
)
formatted_transactions.append(cc_trans)
sorted_transactions = sorted(formatted_transactions, key=lambda x: x.date, reverse=False)
return sorted_transactions
def print_transactions(transactions):
for tx in transactions:
print(f"{tx.date} - {tx.payee} - {tx.amount} - {tx.category}")
def convert_tx_to_csv(transactions):
output = ""
for tx in transactions:
output += f"{tx.date.strftime('%m/%d/%Y')},{tx.payee},{tx.amount},{tx.category.value}\n"
return output
if __name__ == "__main__":
all_transactions = load_chase_csv()
transactions = get_transactions(all_transactions)
print_transactions(transactions)
output = convert_tx_to_csv(transactions)
subprocess.run("pbcopy", universal_newlines=True, input=output)
print("TXs copied to clipboard!")

85
tx_categories.py Normal file
View File

@ -0,0 +1,85 @@
from enum import Enum
class Category(Enum):
RECURRING = "Recurring"
FOOD = "Food"
GROCERY = "Groceries"
CLOTHING = "Clothing"
OTHER = "Other"
TRAVEL = "Vacation"
GAS = "Gas"
CAR = "Car"
EXCLUDED = "N/A"
MEDICAL = "Medical"
UTILITIES = "Utilities"
COUNSELING = "Counseling"
TX_TO_CATEGORY = {
"NYTimes": Category.RECURRING,
"Easy Tiger": Category.FOOD,
"Doordash": Category.FOOD,
"H-E-B": Category.GROCERY,
"HEB": Category.GROCERY,
"its organic": Category.GROCERY,
"Poshmark": Category.CLOTHING,
"Apple": Category.RECURRING,
"AMZN": Category.OTHER,
"farmbox delivery": Category.GROCERY,
"central market": Category.GROCERY,
"black star": Category.FOOD,
"Southwes": Category.TRAVEL,
"Honest marys": Category.FOOD,
"Cabo Bobs": Category.FOOD,
"disneyplus": Category.RECURRING,
"peloton": Category.RECURRING,
"ATT*Bill": Category.UTILITIES,
"google *fiber": Category.UTILITIES,
"Sunrise citgo mini mart": Category.OTHER,
"celis": Category.FOOD,
"barrett?s": Category.FOOD,
"cava": Category.FOOD,
"shell oil": Category.GAS,
"American eagle": Category.CLOTHING,
"turnstile": Category.FOOD,
"turo": Category.TRAVEL,
"o'reilly auto parts": Category.CAR,
"modern market": Category.FOOD,
"enchiladas-y-mas": Category.FOOD,
"spotify": Category.RECURRING,
"automatic payment": Category.EXCLUDED,
"fresh plus": Category.GROCERY,
"fwb hancock": Category.FOOD,
"vuori": Category.CLOTHING,
"american ai": Category.TRAVEL,
"titayas": Category.FOOD,
"central machine work": Category.FOOD,
"lazarus brewing": Category.FOOD,
"nervous charlies": Category.FOOD,
"trader joe": Category.GROCERY,
"peached tortilla": Category.FOOD,
"that burger": Category.FOOD,
"BROTZMAN SPORTS MEDICINE": Category.MEDICAL,
"Jack allens kitchen": Category.FOOD,
"airbnb": Category.TRAVEL,
"buddys burgers": Category.TRAVEL,
"SHELLEY GAUNTT MOELLER": Category.COUNSELING,
"marine layer": Category.CLOTHING,
"disney plus": Category.RECURRING,
"tylers": Category.CLOTHING,
"state farm insurance": Category.RECURRING,
"lululemon": Category.CLOTHING,
"chick-fil-a": Category.FOOD,
"going.com": Category.RECURRING,
"progressive ins": Category.RECURRING,
"VERACRUZALLNATURA.COM": Category.FOOD,
"epoch coffee": Category.FOOD,
"Mondo sports": Category.MEDICAL,
"tri county practice": Category.MEDICAL,
"aspire fertility": Category.MEDICAL,
"juiceland": Category.FOOD,
"MONDOSPORTSTHERAPY": Category.MEDICAL,
"chatgpt": Category.RECURRING,
"WWW.PERPLEXITY.AI": Category.RECURRING,
"payment thank you": Category.EXCLUDED,
"public storage": Category.RECURRING,
}