Files
Moon-Household-Budget/assets.py
tonym be74ca1eb7 Harden JSON storage (atomic writes + crash-safe loads) + suggestions lightbulb
- storage.py: atomic save_json (temp+fsync+os.replace) and load_json that
  survives missing/corrupt files (moves corrupt aside). Closes #11/#12.
- route all data modules + app.py helpers through storage (closes #31 core);
  fixes mutable DEFAULT_FUNDS/DEFAULT_CARS return (#23).
- gunicorn --workers 1 --threads 4 to remove the write race (#13); strip
  Dockerfile template scaffolding (#40).
- base.html: 💡 suggestions link in the shared nav (shows on every page).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:34:06 -05:00

88 lines
2.3 KiB
Python

import copy
import json
import os
from storage import load_json, save_json
DATA_DIR = os.environ.get("DATA_DIR", os.path.join(os.path.dirname(__file__), "data"))
ASSETS_FILE = os.path.join(DATA_DIR, "assets.json")
DEFAULT_CARS = [
{
"id": "kia-forte",
"type": "personal",
"year": 2012,
"make": "Kia",
"model": "Forte 5 SX",
"trim": "2.4L",
"color": "",
"owner": "Bonna",
"purchase_price": 0,
"purchase_date": "",
"estimated_value": 0,
"notes": "",
"gas_log": [],
"maintenance_log": [],
},
{
"id": "silverado",
"type": "personal",
"year": 2009,
"make": "Chevy",
"model": "Silverado LTZ",
"trim": "5.3L",
"color": "",
"owner": "Tony",
"purchase_price": 0,
"purchase_date": "",
"estimated_value": 0,
"notes": "",
"gas_log": [],
"maintenance_log": [],
},
]
ASSET_CATEGORIES = ["Investments", "Real Estate", "Equipment", "Other Valuables"]
def load_assets():
data = load_json(ASSETS_FILE, None)
if data is None:
data = {"personal": copy.deepcopy(DEFAULT_CARS), "flips": [], "other_assets": []}
save_assets(data)
return data
# migrate old format if needed
if "other_assets" not in data:
data["other_assets"] = []
return data
def save_assets(data):
save_json(ASSETS_FILE, data)
def car_display_name(car):
return f"{car['year']} {car['make']} {car['model']}"
def total_spent(car):
gas = sum(float(e.get("amount", 0)) for e in car.get("gas_log", []))
maintenance = sum(float(e.get("amount", 0)) for e in car.get("maintenance_log", []))
return round(gas + maintenance, 2)
def flip_profit(flip):
invested = float(flip.get("purchase_price", 0))
repairs = sum(float(e.get("amount", 0)) for e in flip.get("expense_log", []))
sale = float(flip.get("sale_price", 0))
total_in = invested + repairs
if sale > 0:
return round(sale - total_in, 2)
return None
def flip_total_invested(flip):
invested = float(flip.get("purchase_price", 0))
repairs = sum(float(e.get("amount", 0)) for e in flip.get("expense_log", []))
return round(invested + repairs, 2)