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

Bring back takes in payday #4102

Merged
merged 7 commits into from
Sep 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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