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 #4102 from gratipay/takes-payday
Browse files Browse the repository at this point in the history
Bring back takes in payday
  • Loading branch information
Paul Kuruvilla authored Sep 1, 2016
2 parents 6460223 + 3ac7fee commit 8c49b4b
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 146 deletions.
56 changes: 30 additions & 26 deletions gratipay/billing/payday.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ class Payday(object):
prepare
create_card_holds
process_payment_instructions
transfer_takes
process_draws
process_takes
process_remainder
settle_card_holds
update_balances
take_over_balances
Expand Down Expand Up @@ -153,8 +153,8 @@ def payin(self):
self.prepare(cursor)
holds = self.create_card_holds(cursor)
self.process_payment_instructions(cursor)
self.transfer_takes(cursor, self.ts_start)
self.process_draws(cursor)
self.process_takes(cursor, self.ts_start)
self.process_remainder(cursor)
_payments_for_debugging = cursor.all("""
SELECT * FROM payments WHERE "timestamp" > %s
""", (self.ts_start,))
Expand Down Expand Up @@ -261,37 +261,41 @@ def process_payment_instructions(cursor):


@staticmethod
def transfer_takes(cursor, ts_start):
return # XXX Bring me back!
def process_takes(cursor, ts_start):
log("Processing takes.")
cursor.run("""
UPDATE payday_teams SET available_today = LEAST(available, balance);
INSERT INTO payday_takes
SELECT team, member, amount
FROM ( SELECT DISTINCT ON (team, member)
team, member, amount, ctime
FROM takes
WHERE mtime < %(ts_start)s
ORDER BY team, member, mtime DESC
) t
WHERE t.amount > 0
AND t.team IN (SELECT username FROM payday_participants)
AND t.member IN (SELECT username FROM payday_participants)
AND ( SELECT id
FROM payday_transfers_done t2
WHERE t.team = t2.tipper
AND t.member = t2.tippee
AND context = 'take'
) IS NULL
ORDER BY t.team, t.ctime DESC;
SELECT team_id, participant_id, amount
FROM ( SELECT DISTINCT ON (team_id, participant_id)
team_id, participant_id, amount, ctime
FROM takes
WHERE mtime < %(ts_start)s
ORDER BY team_id, participant_id, mtime DESC
) t
WHERE t.amount > 0
AND t.team_id IN (SELECT id FROM payday_teams)
AND t.participant_id IN (SELECT id FROM payday_participants)
AND ( SELECT ppd.id
FROM payday_payments_done ppd
JOIN participants ON participants.id = t.participant_id
JOIN teams ON teams.id = t.team_id
WHERE participants.username = ppd.participant
AND teams.slug = ppd.team
AND direction = 'to-participant'
) IS NULL
ORDER BY t.team_id, t.amount ASC;
""", dict(ts_start=ts_start))


@staticmethod
def process_draws(cursor):
"""Send whatever remains after payouts to the team owner.
def process_remainder(cursor):
"""Send whatever remains after processing takes to the team owner.
"""
log("Processing draws.")
log("Processing remainder.")
cursor.run("UPDATE payday_teams SET is_drained=true;")


Expand Down
11 changes: 8 additions & 3 deletions gratipay/models/team/mixins/takes.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,15 @@ def vet(p):
vet(participant)
vet(recorder)

if recorder.username == self.owner:
if take not in (ZERO, PENNY):
owner_recording = recorder.username == self.owner
owner_taking = participant.username == self.owner
taker_recording = recorder == participant
adding_or_removing = take in (ZERO, PENNY)

if owner_recording:
if not adding_or_removing and not owner_taking:
raise NotAllowed("owner can only add and remove members, not otherwise set takes")
elif recorder != participant:
elif not taker_recording:
raise NotAllowed("can only set own take")

with self.db.get_cursor(cursor) as cursor:
Expand Down
35 changes: 20 additions & 15 deletions sql/payday.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ CREATE TABLE payday_teams AS
SELECT t.id
, slug
, owner
, available -- The maximum amount that can be distributed to members (ever)
, 0::numeric(35, 2) AS balance
, 0::numeric(35, 2) AS available_today -- The max that can be distributed this payday
, false AS is_drained
FROM teams t
JOIN participants p
Expand Down Expand Up @@ -86,9 +88,9 @@ UPDATE payday_participants pp

DROP TABLE IF EXISTS payday_takes;
CREATE TABLE payday_takes
( team text
, member text
, amount numeric(35,2)
( team_id bigint
, participant_id bigint
, amount numeric(35,2)
);

DROP TABLE IF EXISTS payday_payments;
Expand Down Expand Up @@ -204,24 +206,27 @@ CREATE TRIGGER process_payment_instruction BEFORE UPDATE OF is_funded ON payday_
WHEN (NEW.is_funded IS true AND OLD.is_funded IS NOT true)
EXECUTE PROCEDURE process_payment_instruction();


-- Create a trigger to process takes

CREATE OR REPLACE FUNCTION process_take() RETURNS trigger AS $$
DECLARE
actual_amount numeric(35,2);
team_balance numeric(35,2);
amount numeric(35,2);
available_today_ numeric(35,2);
BEGIN
team_balance := (
SELECT new_balance
FROM payday_participants
WHERE username = NEW.team
);
IF (team_balance <= 0) THEN RETURN NULL; END IF;
actual_amount := NEW.amount;
IF (team_balance < NEW.amount) THEN
actual_amount := team_balance;
amount := NEW.amount;
available_today_ := (SELECT available_today FROM payday_teams WHERE id = NEW.team_id);

IF amount > available_today_ THEN
amount := available_today_;
END IF;

IF amount > 0 THEN
UPDATE payday_teams
SET available_today = (available_today - amount)
WHERE id = NEW.team_id;
EXECUTE pay(NEW.participant_id, NEW.team_id, amount, 'to-participant');
END IF;
EXECUTE transfer(NEW.team, NEW.member, actual_amount, 'take');
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Expand Down
Loading

0 comments on commit 8c49b4b

Please sign in to comment.