diff --git a/ihatemoney/models.py b/ihatemoney/models.py
index 3272cf41c..70c7fd04f 100644
--- a/ihatemoney/models.py
+++ b/ihatemoney/models.py
@@ -113,42 +113,57 @@ def active_members(self):
@property
def full_balance(self):
- """Returns a triple of dicts:
+ """Returns a tuple of dicts:
- - dict mapping each member to its balance
+ - dict mapping each member to its overall balance
- - dict mapping each member to how much he/she should pay others
- (i.e. how much he/she benefited from bills)
+ - dict mapping each member to its expenses (i.e. how much he/she
+ benefited from all bills, whoever actually paid)
- - dict mapping each member to how much he/she should be paid by
- others (i.e. how much he/she has paid for bills)
+ - dict mapping each member to how much he/she has paid for bills
+
+ - dict mapping each member to how much he/she has transferred
+ money to other members
+
+ - dict mapping each member to how much he/she has received money
+ from other members
+
+ balance, spent, paid, transferred, received
- balance spent paid
"""
- balances, should_pay, should_receive = (defaultdict(int) for time in (1, 2, 3))
+ balances, spent, paid, transferred, received = (
+ defaultdict(float) for _ in range(5)
+ )
for bill in self.get_bills_unordered().all():
total_weight = sum(ower.weight for ower in bill.owers)
if bill.bill_type == BillType.EXPENSE:
- should_receive[bill.payer.id] += bill.converted_amount
+ paid[bill.payer.id] += bill.converted_amount
for ower in bill.owers:
- should_pay[ower.id] += (
- ower.weight * bill.converted_amount / total_weight
- )
+ spent[ower.id] += ower.weight * bill.converted_amount / total_weight
if bill.bill_type == BillType.REIMBURSEMENT:
- should_receive[bill.payer.id] += bill.converted_amount
+ transferred[bill.payer.id] += bill.converted_amount
for ower in bill.owers:
- should_receive[ower.id] -= bill.converted_amount
+ received[ower.id] += (
+ ower.weight * bill.converted_amount / total_weight
+ )
for person in self.members:
- balance = should_receive[person.id] - should_pay[person.id]
+ balance = (
+ paid[person.id]
+ - spent[person.id]
+ + transferred[person.id]
+ - received[person.id]
+ )
balances[person.id] = balance
return (
balances,
- should_pay,
- should_receive,
+ spent,
+ paid,
+ transferred,
+ received,
)
@property
@@ -157,17 +172,19 @@ def balance(self):
@property
def members_stats(self):
- """Compute what each participant has paid
+ """Compute what each participant has spent, paid, transferred and received
:return: one stat dict per participant
:rtype list:
"""
- balance, spent, paid = self.full_balance
+ balance, spent, paid, transferred, received = self.full_balance
return [
{
"member": member,
+ "spent": -1.0 * spent[member.id],
"paid": paid[member.id],
- "spent": spent[member.id],
+ "transferred": transferred[member.id],
+ "received": -1.0 * received[member.id],
"balance": balance[member.id],
}
for member in self.active_members
@@ -209,7 +226,6 @@ def prettify(transactions, pretty_output):
)
return pretty_transactions
- # cache value for better performance
members = {person.id: person for person in self.members}
settle_plan = settle(self.balance.items()) or []
@@ -225,22 +241,6 @@ def prettify(transactions, pretty_output):
return prettify(transactions, pretty_output)
- def exactmatch(self, credit, debts):
- """Recursively try and find subsets of 'debts' whose sum is equal to credit"""
- if not debts:
- return None
- if debts[0]["balance"] > credit:
- return self.exactmatch(credit, debts[1:])
- elif debts[0]["balance"] == credit:
- return [debts[0]]
- else:
- match = self.exactmatch(credit - debts[0]["balance"], debts[1:])
- if match:
- match.append(debts[0])
- else:
- match = self.exactmatch(credit, debts[1:])
- return match
-
def has_bills(self):
"""return if the project do have bills or not"""
return self.get_bills_unordered().count() > 0
diff --git a/ihatemoney/templates/statistics.html b/ihatemoney/templates/statistics.html
index 86f9cd42e..e367c7470 100644
--- a/ihatemoney/templates/statistics.html
+++ b/ihatemoney/templates/statistics.html
@@ -10,20 +10,22 @@
{% block content %}
- {{ _("Who?") }} | {{ _("Paid") }} | {{ _("Spent") }} |
+ {{ _("Who?") }} | {{ _("Paid") }} | {{ _("Expenses") }} | {{ _("Transferred") }} | {{ _("Received") }} |
{% for stat in members_stats|sort(attribute='member.name') %}
{{ stat.member.name }} |
{{ stat.paid|currency }} |
{{ stat.spent|currency }} |
+ {{ stat.transferred|currency }} |
+ {{ stat.received|currency }} |
{% endfor %}
-
{{ _("Expenses by Month") }}
+
{{ _("Expenses by month") }}
- {{ _("Period") }} | {{ _("Spent") }} |
+ {{ _("Period") }} | {{ _("Expenses") }} |
{% for month in months %}