# SplitBuddy — Flask app with ratio-based splits (You vs Idan)
from __future__ import annotations
import os, sqlite3, csv, io, datetime as dt
from typing import Optional
from flask import Flask, g, request, redirect, url_for, render_template_string, send_file
app = Flask(__name__)
DB_PATH = os.environ.get("SPLITBUDDY_DB", "splitbuddy.db")
CURRENCY = "₪"
PERSON_A = os.environ.get("SPLITBUDDY_ME", "Me") # you
PERSON_B = os.environ.get("SPLITBUDDY_ROOMIE", "Idan") # roommate
# ------------------------- DB helpers --------------------------- #
def get_db() -> sqlite3.Connection:
if "db" not in g:
g.db = sqlite3.connect(DB_PATH)
g.db.row_factory = sqlite3.Row
return g.db
@app.teardown_appcontext
def close_db(_=None):
db = g.pop("db", None)
if db is not None:
db.close()
def init_db():
db = get_db()
# Base table
db.execute("""
CREATE TABLE IF NOT EXISTS entries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at TEXT NOT NULL,
total REAL NOT NULL DEFAULT 0, -- total bill amount
payer TEXT NOT NULL DEFAULT 'A', -- 'A' (you) or 'B' (Idan)
a_share REAL NOT NULL DEFAULT 0.5, -- your share as fraction (0..1)
method TEXT NOT NULL DEFAULT 'cash',
note TEXT
)
""")
# Migrate older schema (from signed amount version)
# If old columns exist, add new if missing
try:
db.execute("ALTER TABLE entries ADD COLUMN total REAL")
except sqlite3.OperationalError:
pass
try:
db.execute("ALTER TABLE entries ADD COLUMN payer TEXT")
except sqlite3.OperationalError:
pass
try:
db.execute("ALTER TABLE entries ADD COLUMN a_share REAL")
except sqlite3.OperationalError:
pass
# If we had old 'amount' signed records and 'total' is NULL, map amount→total and infer payer/a_share=0.5
db.execute("""
UPDATE entries
SET total = COALESCE(total, 0),
payer = COALESCE(payer, CASE WHEN total IS NOT NULL THEN 'A' ELSE 'A' END),
a_share = COALESCE(a_share, 0.5)
""")
db.commit()
# --------------------------- Template --------------------------- #
BASE = r"""
SplitBuddy
SplitBuddy
{% if summary.total > 0 %}
{{ A }} owes {{ B }} {{ currency }}{{ '%.2f'|format(summary.total) }}
{% elif summary.total < 0 %}
{{ B }} owes {{ A }} {{ currency }}{{ '%.2f'|format(-summary.total) }}
{% else %}All settled ✨{% endif %}
Balance: {{ currency }}{{ '%.2f'|format(summary.total) }}Export CSV