Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
Merge pull request #2988 from gratipay/fix-fake-payday-depth
Browse files Browse the repository at this point in the history
Fix fake payday depth
  • Loading branch information
rohitpaulk committed Dec 5, 2014
2 parents dae2e8f + 12b9e79 commit 0e49279
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 13 deletions.
39 changes: 33 additions & 6 deletions fake_payday.sql
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,45 @@ CREATE TRIGGER fake_take AFTER INSERT ON temp_takes
FOR EACH ROW EXECUTE PROCEDURE fake_take();


-- Create a function to settle whole tip graph

CREATE OR REPLACE FUNCTION settle_tip_graph() RETURNS void AS $$
DECLARE
count integer NOT NULL DEFAULT 0;
i integer := 0;
BEGIN
LOOP
i := i + 1;
WITH updated_rows AS (
UPDATE temp_tips
SET is_funded = true
WHERE is_funded IS NOT true
RETURNING *
)
SELECT COUNT(*) FROM updated_rows INTO count;
IF (count = 0) THEN
EXIT;
END IF;
IF (i > 50) THEN
RAISE 'Reached the maximum number of iterations';
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;


-- Start fake payday

-- Step 1: tips that are backed by a credit card
-- Step 1: tips
UPDATE temp_tips t
SET is_funded = true
FROM temp_participants p
WHERE p.username = t.tipper
AND p.credit_card_ok;

-- Step 2: tips that are covered by the user's balance
UPDATE temp_tips t
SET is_funded = true
WHERE is_funded IS NOT true;
SELECT settle_tip_graph();

-- Step 3: team takes
-- Step 2: team takes
INSERT INTO temp_takes
SELECT team, member, amount
FROM current_takes t
Expand All @@ -139,6 +163,9 @@ INSERT INTO temp_takes
AND t.member IN (SELECT username FROM temp_participants)
ORDER BY ctime DESC;

-- Step 3: tips again
SELECT settle_tip_graph();

-- Step 4: update the real tables
UPDATE tips t
SET is_funded = tt.is_funded
Expand Down
2 changes: 2 additions & 0 deletions gratipay/models/_mixin_team.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ def __set_take_for(self, member, amount, recorder, cursor=None):
new_takes = self.compute_actual_takes(cursor)
# Update receiving amounts in the participants table
self.update_taking(old_takes, new_takes, cursor, member)
# Update is_funded on member's tips
member.update_giving(cursor)

def update_taking(self, old_takes, new_takes, cursor=None, member=None):
"""Update `taking` amounts based on the difference between `old_takes`
Expand Down
5 changes: 4 additions & 1 deletion gratipay/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def __ne__(self, other):
return False
return self.username != other.username

def __repr__(self):
return '<Participant %s>' % repr(self.username)


# Constructors
# ============
Expand Down Expand Up @@ -598,7 +601,7 @@ def update_giving(self, cursor=None):
AND p2.is_suspicious IS NOT true
ORDER BY p2.claimed_time IS NULL, t.ctime ASC
""", (self.username,))
fake_balance = self.balance + self.receiving - self.taking
fake_balance = self.balance + self.receiving
for tip in tips:
if tip.amount > fake_balance:
is_funded = False
Expand Down
37 changes: 31 additions & 6 deletions tests/py/test_billing_payday.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,11 @@ def test_update_cached_amounts(self):
alice.set_tip_to(team, '4.00')
alice.set_tip_to(roy, '10.00')
bob.set_tip_to(alice, '5.00')
bob.set_tip_to(dana, '2.00')
carl.set_tip_to(dana, '2.08')
team.add_member(bob)
team.set_take_for(bob, D('1.00'), bob)
bob.set_tip_to(dana, '2.00') # funded by bob's take
bob.set_tip_to(emma, '7.00') # not funded, insufficient receiving
carl.set_tip_to(dana, '2.08') # not funded, failing card

def check():
alice = Participant.from_username('alice')
Expand All @@ -123,17 +124,17 @@ def check():
assert alice.giving == D('13.00')
assert alice.pledging == D('1.00')
assert alice.receiving == D('5.00')
assert bob.giving == D('5.00')
assert bob.giving == D('7.00')
assert bob.receiving == D('7.00')
assert bob.taking == D('1.00')
assert carl.giving == D('0.00')
assert carl.receiving == D('0.00')
assert dana.receiving == D('3.00')
assert dana.npatrons == 1
assert dana.receiving == D('5.00')
assert dana.npatrons == 2
assert emma.receiving == D('1.00')
assert emma.npatrons == 1
funded_tips = self.db.all("SELECT amount FROM tips WHERE is_funded ORDER BY id")
assert funded_tips == [3, 6, 1, 4, 10, 5]
assert funded_tips == [3, 6, 1, 4, 10, 5, 2]

# Pre-test check
check()
Expand All @@ -155,6 +156,30 @@ def check():
Payday.start().update_cached_amounts()
check()

def test_update_cached_amounts_depth(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
usernames = ('bob', 'carl', 'dana', 'emma', 'fred', 'greg')
users = [self.make_participant(username, claimed_time='now') for username in usernames]

prev = alice
for user in reversed(users):
prev.set_tip_to(user, '1.00')
prev = user

def check():
for username in reversed(usernames[1:]):
user = Participant.from_username(username)
assert user.giving == D('1.00')
assert user.pledging == D('0.00')
assert user.receiving == D('1.00')
assert user.npatrons == 1
funded_tips = self.db.all("SELECT id FROM tips WHERE is_funded ORDER BY id")
assert len(funded_tips) == 6

check()
Payday.start().update_cached_amounts()
check()

@mock.patch('gratipay.billing.payday.log')
def test_start_prepare(self, log):
self.clear_tables()
Expand Down

0 comments on commit 0e49279

Please sign in to comment.