Skip to content

Commit

Permalink
Create DebtFilter module for Bet
Browse files Browse the repository at this point in the history
-DebtFilter addresses the problem, where some of the created Debts for a
particular Bet would cross-reference each other (PersonA -$50-> PersonB
&& PersonB -$20-> PersonA) or accumulate as separate entries (PerosnA
-$50-> PersonB && PersonA -$20-> PersonB) by filtering them before
saving.
-Added DebtFilter to Bet model. Debts are now filtered before getting
saved.
  • Loading branch information
LeonTenko committed Apr 5, 2017
1 parent 0679398 commit ec4c39c
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 3 deletions.
7 changes: 4 additions & 3 deletions app/models/bet.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class Bet < ApplicationRecord
include DebtFilter
has_many :users, through: :user_bets
has_many :user_bets
has_many :options, class_name: 'BetOption'
Expand All @@ -12,14 +13,14 @@ class Bet < ApplicationRecord
def resolve(winning_option:)
winning_option.update!(winner: true)
debt_relationships = user_bets.winners.to_a.product(user_bets.losers.to_a)
debt_relationships.map do |(won_bet, lost_bet)|
Debt.create(
save_debts(debt_relationships.map do |(won_bet, lost_bet)|
Debt.new(
creditor: won_bet.user,
debtor: lost_bet.user,
amount: amount_owed(lost_bet, won_bet),
bet: self
)
end
end)
end

def winner_total
Expand Down
56 changes: 56 additions & 0 deletions app/models/debt_filter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module DebtFilter
def save_debts(debts)
filter_debts(debts).map do |debt|
debt.save
debt
end
end

private

def filter_debts(debts)
reverse_negatives(merge_debts(reverse_duplicates(debts)))
end

def unique_participants(debts)
uniques = []
debts.each do |debt|
next if uniques.include?([debt.creditor, debt.debtor]) ||
uniques.include?([debt.debtor, debt.creditor])
uniques << [debt.debtor, debt.creditor]
end
uniques
end

def reverse_duplicates(debts)
uniques = unique_participants(debts)
debts.map do |debt|
if uniques.include?([debt.debtor, debt.creditor])
debt
else
Debt.new(debtor: debt.creditor,
creditor: debt.debtor, amount: -debt.amount)
end
end
end

def merge_debts(debts)
debts.group_by { |debt| [debt.debtor, debt.creditor] }.map do |_, group|
next if group.sum(&:amount).zero?
Debt.new(debtor: group.first.debtor,
creditor: group.first.creditor,
amount: group.sum(&:amount))
end.compact
end

def reverse_negatives(debts)
debts.map do |debt|
if debt.amount < 0
Debt.new(debtor: debt.creditor,
creditor: debt.debtor, amount: debt.amount.abs)
else
debt
end
end
end
end
44 changes: 44 additions & 0 deletions spec/modules/debt_filter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'rails_helper'

RSpec.describe DebtFilter, type: :module do
let(:debt_filter) { Class.new { extend DebtFilter } }
let(:bob) do
User.create(username: 'Bob', email: '[email protected]', password: '123')
end
let(:peter) do
User.create(username: 'Peter', email: '[email protected]', password: 'pete1')
end
let(:jack) do
User.create(username: 'Jack', email: '[email protected]', password: 'jeeek')
end

let(:debt1) { Debt.new(debtor: bob, creditor: peter, amount: 20) }
let(:debt2) { Debt.new(debtor: peter, creditor: bob, amount: 100) }
let(:debt3) { Debt.new(debtor: bob, creditor: peter, amount: 60) }
let(:debt4) { Debt.new(debtor: jack, creditor: peter, amount: 55.5) }
let(:debt5) { Debt.new(debtor: bob, creditor: jack, amount: 20) }
let(:debt6) { Debt.new(debtor: jack, creditor: bob, amount: 20) }
let(:debts) { [debt1, debt2, debt3, debt4, debt5, debt6] }

describe('#save_debts') do
subject(:saved_debts) { debt_filter.save_debts(debts) }
let(:expected_debt1) do
Debt.new(debtor: peter, creditor: bob, amount: 20)
end
let(:expected_debt2) { debt4 }
it 'saves debts after filtering them' do
aggregate_failures 'testing debts' do
expect(saved_debts.first).to(
have_attributes(debtor: expected_debt1.debtor,
creditor: expected_debt1.creditor,
amount: expected_debt1.amount)
)
expect(saved_debts.second).to(
have_attributes(debtor: expected_debt2.debtor,
creditor: expected_debt2.creditor,
amount: expected_debt2.amount)
)
end
end
end
end

0 comments on commit ec4c39c

Please sign in to comment.