From b3db90545c5bd76d4acb6abfe5356e87b0f0cdcf Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Thu, 10 Mar 2011 02:37:21 +0000 Subject: initial import --- budget.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 budget.py (limited to 'budget.py') diff --git a/budget.py b/budget.py new file mode 100644 index 0000000..ce3086a --- /dev/null +++ b/budget.py @@ -0,0 +1,130 @@ +from datetime import datetime + +from flask import * +from flaskext.wtf import (Form, SelectField, SelectMultipleField, SubmitField, + DateTimeField, Required, TextField) +from flaskext.wtf.html5 import DecimalField +from flaskext.sqlalchemy import SQLAlchemy + +# configuration +DEBUG = True +SQLALCHEMY_DATABASE_URI = 'sqlite:///budget.db' +SQLACHEMY_ECHO = DEBUG +PAYERS = ["Raph", "Joel", "Alexis", "Nick", "Julius"] +PAYER_CHOICES = [(p.lower(), p) for p in PAYERS] +SECRET_KEY = "tralala" + + +# create the application, initialize stuff +app = Flask(__name__) +app.config.from_object(__name__) +app.config.from_envvar('BUDGET_SETTINGS', silent=True) + +db = SQLAlchemy(app) + +# define models +class Bill(db.Model): + __tablename__ = "bills" + + id = db.Column(db.Integer, primary_key=True) + what = db.Column(db.UnicodeText) + payer = db.Column(db.Unicode(200)) + amount = db.Column(db.Float) + date = db.Column(db.Date, default=datetime.now) + processed = db.Column(db.Boolean, default=False) + + def pay_each(self): + """Compute what each person have to pay""" + return round(self.amount / len(self.owers), 2) + + def __repr__(self): + return "" % (self.amount, + self.payer, ", ".join([o.name for o in self.owers])) + + + +class BillOwer(db.Model): + __tablename__ = "billowers" + + bill_id = db.Column(db.Integer, db.ForeignKey("bills.id"), primary_key=True) + name = db.Column(db.Unicode(200), primary_key=True) + + bill = db.relationship(Bill, backref=db.backref('owers', order_by=name)) + + +# define forms +class BillForm(Form): + what = TextField("What?", validators=[Required()]) + payer = SelectField("Payer", validators=[Required()], choices=PAYER_CHOICES) + amount = DecimalField("Amount payed", validators=[Required()]) + payed_for = SelectMultipleField("Who have to pay for this?", validators=[Required()], choices=PAYER_CHOICES) + submit = SubmitField("Add the bill") + + +@app.route("/") +def list_bills(): + bills = Bill.query.filter(Bill.processed==False).order_by(Bill.id.asc()) + return render_template("list_bills.html", bills=bills) + + +@app.route("/add", methods=["GET", "POST"]) +def add_bill(): + form = BillForm() + if request.method == 'POST': + if form.validate(): + bill = Bill() + form.populate_obj(bill) + + for ower in form.payed_for.data: + ower = BillOwer(name=ower) + db.session.add(ower) + bill.owers.append(ower) + + db.session.add(bill) + + + db.session.commit() + flash("The bill have been added") + return redirect(url_for('list_bills')) + + return render_template("add_bill.html", form=form) + + +@app.route("/compute") +def compute_bills(): + """Compute the sum each one have to pay to each other and display it""" + + balances, should_pay, should_receive = {}, {}, {} + # for each person, get the list of should_pay other have for him + for name, void in PAYER_CHOICES: + bills = Bill.query.join(BillOwer).filter(Bill.processed==False)\ + .filter(BillOwer.name==name) + for bill in bills.all(): + if name != bill.payer: + should_pay.setdefault(name, 0) + should_pay[name] += bill.pay_each() + should_receive.setdefault(bill.payer, 0) + should_receive[bill.payer] += bill.pay_each() + + for name, void in PAYER_CHOICES: + balances[name] = should_receive.get(name, 0) - should_pay.get(name, 0) + + return render_template("compute_bills.html", balances=balances) + + +@app.route("/reset") +def reset_bills(): + """Reset the list of bills""" + # get all the bills which are not processed + bills = Bill.query.filter(Bill.processed == False) + for bill in bills: + bill.processed = True + db.session.commit() + + return redirect(url_for('list_bills')) + + + +if __name__ == '__main__': + db.create_all() + app.run(host="0.0.0.0", debug=True) -- cgit v1.1