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 3 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
54 changes: 28 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,39 @@ 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("""

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
46 changes: 27 additions & 19 deletions sql/payday.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ CREATE TABLE payday_teams AS
SELECT t.id
, slug
, owner
, available
, 0::numeric(35, 2) AS balance
, false AS is_drained
FROM teams t
Expand Down Expand Up @@ -86,9 +87,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,30 +205,37 @@ 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 $$
-- Create a trigger to process distributions based on takes

CREATE OR REPLACE FUNCTION process_distribution() RETURNS trigger AS $$
DECLARE
actual_amount numeric(35,2);
team_balance numeric(35,2);
amount numeric(35,2);
balance_ numeric(35,2);
available_ 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;

balance_ := (SELECT balance FROM payday_teams WHERE id = NEW.team_id);
IF balance_ < amount THEN
amount := balance_;
END IF;

available_ := (SELECT available FROM payday_teams WHERE id = NEW.team_id);
IF available_ < amount THEN
amount := available_;
END IF;

IF amount > 0 THEN
UPDATE payday_teams SET available = (available - amount) WHERE id = NEW.team_id;
Copy link
Contributor

@rohitpaulk rohitpaulk Aug 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So many varying values here :/ Both balance and available are reducing at the same rate - we decrease the available here, and pay ends up decreasing the balance by the same amount. And then every time, we check against both of them, whereas logically we should only be checking against whichever is lowest.

Wondering if there is a cleaner way to model this... What if we're using two variables where we only need one? Haven't thought this through, just speaking out loud - will revisit once I'm done with the rest

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;

CREATE TRIGGER process_take AFTER INSERT ON payday_takes
FOR EACH ROW EXECUTE PROCEDURE process_take();
CREATE TRIGGER process_takes AFTER INSERT ON payday_takes
FOR EACH ROW EXECUTE PROCEDURE process_distribution();


-- Create a trigger to process draws
Expand Down
Loading