def test_paybacks(collective_with_transfers_for_payback): collective, user_1, user_2, user_3 = collective_with_transfers_for_payback paybacks = calc_paybacks(collective) assert len(paybacks) == 3 assert paybacks[0].debtor == user_3 assert paybacks[0].creditor == user_1 assert paybacks[0].amount == 48.33333333333333 assert paybacks[1].debtor == user_3 assert paybacks[1].creditor == user_2 assert paybacks[1].amount == 8.333333333333329 assert paybacks[2].debtor == user_1 assert paybacks[2].creditor == user_2 assert paybacks[2].amount == 50.0 # Adding a Liquidation can flip the creditor/debtor relation, # as otherwise the balance would become negative. mommy.make("purchases.Liquidation", collective=collective, creditor=user_1, debtor=user_2, amount=60.0) paybacks = calc_paybacks(collective) assert len(paybacks) == 3 assert paybacks[0].debtor == user_3 assert paybacks[0].creditor == user_1 assert paybacks[0].amount == 48.33333333333333 assert paybacks[1].debtor == user_3 assert paybacks[1].creditor == user_2 assert paybacks[1].amount == 8.333333333333329 assert paybacks[2].debtor == user_2 assert paybacks[2].creditor == user_1 assert paybacks[2].amount == 10.0
def test_calc_paybacks_with_negative_transfers(collective): user_1 = mommy.make("auth.User", username="******") user_2 = mommy.make("auth.User", username="******") user_3 = mommy.make("auth.User", username="******") collective.add_member(user_1) collective.add_member(user_2) collective.add_member(user_3) mommy.make("purchases.Purchase", collective=collective, buyer=user_1, name="Electricty Bill Refund", price=-90.00) mommy.make("purchases.Purchase", collective=collective, buyer=user_2, name="Pizza", price=15.00) mommy.make("purchases.Liquidation", collective=collective, creditor=user_2, debtor=user_3, name="This makes no sense, but hey", amount=-5.00) paybacks = calc_paybacks(collective) assert len(paybacks) == 3 data = [(payback.debtor, payback.creditor, payback.amount) for payback in paybacks] assert (user_1, user_2, 40.00) in data assert (user_1, user_3, 25.00) in data assert (user_2, user_3, 5.00) in data
def cashup(request, key): collective = collective_from_key(key) paybacks = [payback.to_json() for payback in calc_paybacks(collective)] return Response(paybacks)
def stats(self): """Calculate financial status for each member of the Collective. Returns: { 'median_debt': 50.00, 'median_purchased': 15.95, 'overall_debt': 50.00, 'overall_purchased': 603.45, 'member_id_to_balance': { '<member1-id>': -140.23, '<member2-id>': 67.04, ... }, 'cashup': [ {'debtor': ..., 'creditor': ..., 'amount': ...}, ... ], } """ collective = self members = collective.members num_members = len(members) purchases = collective.purchases num_purchases = purchases.count() liquidations = collective.liquidations num_liquidations = liquidations.count() prices = [float(purchase.price.amount) for purchase in purchases] overall_purchased = sum(prices) per_member = float(overall_purchased) / float(num_members) debts = [ float(liquidation.amount.amount) for liquidation in liquidations ] overall_debt = sum(debts) median_purchased = 0 if prices: median_purchased = median(prices) median_debt = 0 if debts: median_debt = median(debts) member_id_to_balance = {} for member in collective.members: member_purchased = sum([ float(purchase.price.amount) for purchase in purchases if purchase.buyer == member ]) credit = sum([ float(liq.amount.amount) for liq in liquidations if liq.creditor == member ]) debt = sum([ float(liq.amount.amount) for liq in liquidations if liq.debtor == member ]) has_to_pay = (per_member - float(member_purchased) - float(credit) + float(debt)) balance = has_to_pay * -1 if balance == 0: # Remove '-' from the display. balance = 0 member_id_to_balance[member.id] = balance sorted_balances = sorted(member_id_to_balance.items(), key=lambda item: item[1], reverse=True) serialized_paybacks = [ payback.to_json() for payback in calc_paybacks(collective) ] stats = { "median_debt": median_debt, "median_purchased": median_purchased, "num_liquidations": num_liquidations, "num_purchases": num_purchases, "overall_debt": overall_debt, "overall_purchased": overall_purchased, "sorted_balances": sorted_balances, "cashup": serialized_paybacks, } return stats