aboutsummaryrefslogtreecommitdiff
path: root/budget
diff options
context:
space:
mode:
Diffstat (limited to 'budget')
-rw-r--r--budget/forms.py2
-rw-r--r--budget/migrations/versions/26d6a218c329_.py26
-rw-r--r--budget/models.py9
-rw-r--r--budget/tests.py30
4 files changed, 64 insertions, 3 deletions
diff --git a/budget/forms.py b/budget/forms.py
index 2dde57d..918e82a 100644
--- a/budget/forms.py
+++ b/budget/forms.py
@@ -152,6 +152,7 @@ class BillForm(Form):
class MemberForm(Form):
name = TextField(_("Name"), validators=[Required()])
+ weight = CommaDecimalField(_("Weight"), default=1)
submit = SubmitField(_("Add"))
def __init__(self, project, *args, **kwargs):
@@ -170,6 +171,7 @@ class MemberForm(Form):
# if the user is already bound to the project, just reactivate him
person.name = self.name.data
person.project = project
+ person.weight = self.weight.data
return person
diff --git a/budget/migrations/versions/26d6a218c329_.py b/budget/migrations/versions/26d6a218c329_.py
new file mode 100644
index 0000000..859b9af
--- /dev/null
+++ b/budget/migrations/versions/26d6a218c329_.py
@@ -0,0 +1,26 @@
+"""Add Person.weight column
+
+Revision ID: 26d6a218c329
+Revises: b9a10d5d63ce
+Create Date: 2016-06-15 09:22:04.069447
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '26d6a218c329'
+down_revision = 'b9a10d5d63ce'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('person', sa.Column('weight', sa.Float(), nullable=True))
+ ### end Alembic commands ###
+
+
+def downgrade():
+ ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column('person', 'weight')
+ ### end Alembic commands ###
diff --git a/budget/models.py b/budget/models.py
index 727200f..16cc6c1 100644
--- a/budget/models.py
+++ b/budget/models.py
@@ -40,8 +40,9 @@ class Project(db.Model):
bills = Bill.query.filter(Bill.owers.contains(person))
for bill in bills.all():
if person != bill.payer:
- should_pay[person] += bill.pay_each()
- should_receive[bill.payer] += bill.pay_each()
+ share = bill.pay_each() * person.weight
+ should_pay[person] += share
+ should_receive[bill.payer] += share
for person in self.members:
balance = should_receive[person] - should_pay[person]
@@ -159,6 +160,7 @@ class Person(db.Model):
bills = db.relationship("Bill", backref="payer")
name = db.Column(db.UnicodeText)
+ weight = db.Column(db.Float, default=1)
activated = db.Column(db.Boolean, default=True)
def has_bills(self):
@@ -219,7 +221,8 @@ class Bill(db.Model):
def pay_each(self):
"""Compute what each person has to pay"""
if self.owers:
- return self.amount / len(self.owers)
+ # FIXME: SQL might dot that more efficiently
+ return self.amount / sum(i.weight for i in self.owers)
else:
return 0
diff --git a/budget/tests.py b/budget/tests.py
index 760ffc0..021b425 100644
--- a/budget/tests.py
+++ b/budget/tests.py
@@ -416,6 +416,36 @@ class BudgetTestCase(TestCase):
bill = models.Bill.query.filter(models.Bill.date == '2011-08-01')[0]
self.assertEqual(bill.amount, 25.02)
+ def test_weighted_balance(self):
+ self.post_project("raclette")
+
+ # add two persons
+ self.app.post("/raclette/members/add", data={'name': 'alexis'})
+ self.app.post("/raclette/members/add", data={'name': 'freddy familly', 'weight': 4})
+
+ members_ids = [m.id for m in
+ models.Project.query.get("raclette").members]
+
+ # test balance
+ self.app.post("/raclette/add", data={
+ 'date': '2011-08-10',
+ 'what': u'fromage à raclette',
+ 'payer': members_ids[0],
+ 'payed_for': members_ids,
+ 'amount': '10',
+ })
+
+ self.app.post("/raclette/add", data={
+ 'date': '2011-08-10',
+ 'what': u'pommes de terre',
+ 'payer': members_ids[1],
+ 'payed_for': members_ids,
+ 'amount': '10',
+ })
+
+ balance = models.Project.query.get("raclette").balance
+ self.assertEqual(set(balance.values()), set([6, -6]))
+
def test_rounding(self):
self.post_project("raclette")