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

Cap unfunded dues #3876

Closed
wants to merge 11 commits into from
16 changes: 16 additions & 0 deletions sql/branch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from gratipay import wireup

db = wireup.db(wireup.env())

participants = db.all("""
SELECT p.*::participants
FROM participants p
JOIN payment_instructions pi ON pi.participant = p.username -- Only include those with tips
""")
total = len(participants)
Copy link
Contributor

Choose a reason for hiding this comment

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

=> select count(*) from participants p JOIN payment_instructions pi ON pi.participant = p.username;
┌───────┐
│ count │
├───────┤
│  2921 │
└───────┘
(1 row)

I would expect this script to run for a few minutes, anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, and I think that's fine - the operations are idempotent so crash/rerun shouldn't be a problem.

counter = 0

for p in participants:
print("Participant %s/%s" % (counter, total))
p.update_giving_and_teams()
counter += 1
3 changes: 3 additions & 0 deletions sql/branch.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
BEGIN;
UPDATE payment_instructions SET due = 0 WHERE due > 9.41;
Copy link
Contributor

Choose a reason for hiding this comment

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

We could do something like this instead:

BEGIN;
    CREATE TEMP TABLE _participants AS
        SELECT id
             , username
             , ( SELECT count(*)
                   FROM current_exchange_routes r
                  WHERE r.participant = p.id
                    AND network = 'braintree-cc'
                    AND error = ''
               ) > 0 AS has_credit_card
          FROM participants p;

    UPDATE payment_instructions SET due = 0 WHERE due >= 9.41 AND participant IN (
        SELECT username FROM _participants WHERE NOT has_credit_card
    );

    DROP TABLE _participants;
END;

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm outta time to work on this today, though. I will try to pick up again tomorrow, @rohitpaulk.

END;
6 changes: 4 additions & 2 deletions sql/payday.sql
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,14 @@ CREATE OR REPLACE FUNCTION process_payment_instruction() RETURNS trigger AS $$
FROM payday_participants p
WHERE username = NEW.participant
);

IF (NEW.amount + NEW.due <= participant.new_balance OR participant.card_hold_ok) THEN
EXECUTE pay(NEW.participant, NEW.team, NEW.amount + NEW.due, 'to-team');
RETURN NEW;
ELSE
ELSIF participant.has_credit_card THEN
EXECUTE park(NEW.participant, NEW.team, NEW.amount + NEW.due);
RETURN NULL;
END IF;

RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Expand All @@ -202,6 +203,7 @@ 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 $$
Expand Down
22 changes: 22 additions & 0 deletions tests/py/test_billing_payday.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,28 @@ def test_payday_preserves_due_until_charged(self, fch):
assert obama.balance == D('0.00')
assert obama.get_due('TheEnterprise') == D('0.00')

@mock.patch.object(Payday, 'fetch_card_holds')
def test_payday_keeps_dues_under_minimum_charge(self, fch):
Enterprise = self.make_team(is_approved=True)
self.obama.set_payment_instruction(Enterprise, '4.00')
assert self.obama.get_due('TheEnterprise') == D('0.00')

fch.return_value = {}
Payday.start().run() # payday 0

assert self.obama.get_due('TheEnterprise') == D('4.00')

fch.return_value = {}
self.obama_route.update_error("failed") # card fails
Payday.start().run() # payday 1

assert self.obama.get_due('TheEnterprise') == D('4.00')

fch.return_value = {}
Payday.start().run() # payday 2

assert self.obama.get_due('TheEnterprise') == D('4.00')

@mock.patch.object(Payday, 'fetch_card_holds')
def test_payday_does_not_move_money_below_min_charge(self, fch):
Enterprise = self.make_team(is_approved=True)
Expand Down