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

Commit

Permalink
Add {get,set}_subscription_to to Participant
Browse files Browse the repository at this point in the history
The test suite uses this extensively. I want to modify payday tests so I
really need this.
  • Loading branch information
chadwhitacre committed May 14, 2015
1 parent b34352a commit 5f8bc3d
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
1 change: 1 addition & 0 deletions gratipay/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def __str__(self):
class TooGreedy(Exception): pass
class NoSelfTipping(Exception): pass
class NoTippee(Exception): pass
class NoTeam(Exception): pass
class BadAmount(Exception): pass

class FailedToReserveUsername(Exception): pass
Expand Down
83 changes: 83 additions & 0 deletions gratipay/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
UsernameAlreadyTaken,
NoSelfTipping,
NoTippee,
NoTeam,
BadAmount,
EmailAlreadyTaken,
CannotRemovePrimaryEmail,
Expand All @@ -46,6 +47,7 @@
from gratipay.models._mixin_team import MixinTeam
from gratipay.models.account_elsewhere import AccountElsewhere
from gratipay.models.exchange_route import ExchangeRoute
from gratipay.models.team import Team
from gratipay.security.crypto import constant_time_compare
from gratipay.utils import i18n, is_card_expiring, emails, notifications, pricing
from gratipay.utils.username import safely_reserve_a_username
Expand Down Expand Up @@ -1108,6 +1110,87 @@ def update_is_free_rider(self, is_free_rider, cursor=None):
self.set_attributes(is_free_rider=is_free_rider)


# New payday system

def set_subscription_to(self, team, amount, update_self=True, update_team=True, cursor=None):
"""Given a Team or username, and amount as str, returns a dict.
We INSERT instead of UPDATE, so that we have history to explore. The
COALESCE function returns the first of its arguments that is not NULL.
The effect here is to stamp all tips with the timestamp of the first
tip from this user to that. I believe this is used to determine the
order of payments during payday.
The dict returned represents the row inserted in the subscriptions
table.
"""
assert self.is_claimed # sanity check

if not isinstance(team, Team):
team, slug = Team.from_slug(team), team
if not team:
raise NoTeam(slug)

amount = Decimal(amount) # May raise InvalidOperation
if (amount < gratipay.MIN_TIP) or (amount > gratipay.MAX_TIP):
raise BadAmount

# Insert subscription
NEW_SUBSCRIPTION = """\
INSERT INTO subscriptions
(ctime, subscriber, team, amount)
VALUES ( COALESCE (( SELECT ctime
FROM subscriptions
WHERE (subscriber=%(subscriber)s AND team=%(team)s)
LIMIT 1
), CURRENT_TIMESTAMP)
, %(subscriber)s, %(team)s, %(amount)s
)
RETURNING *
"""
args = dict(subscriber=self.username, team=team.slug, amount=amount)
t = (cursor or self.db).one(NEW_SUBSCRIPTION, args)

if update_self:
# Update giving amount of subscriber
self.update_giving(cursor)
if update_team:
# Update receiving amount of team
team.update_receiving(cursor)
if team.slug == 'Gratipay':
# Update whether the subscriber is using Gratipay for free
self.update_is_free_rider(None if amount == 0 else False, cursor)

return t._asdict()


def get_subscription_to(self, team):
"""Given a slug, returns a dict.
"""

if not isinstance(team, Team):
team, slug = Team.from_slug(team), team
if not slug:

This comment has been minimized.

Copy link
@rohitpaulk

rohitpaulk May 14, 2015

Contributor

Shouldn't this be if not team?

This comment has been minimized.

Copy link
@chadwhitacre

chadwhitacre May 14, 2015

Author Contributor

Good catch. Fixed in 51a449c.

raise NoTeam(slug)

default = dict(amount=Decimal('0.00'), is_funded=False)
return self.db.one("""\
SELECT *
FROM subscriptions
WHERE subscriber=%s
AND team=%s
ORDER BY mtime DESC
LIMIT 1
""", (self.username, team.slug), back_as=dict, default=default)


# Old payday system, deprecated and going away ...

def set_tip_to(self, tippee, amount, update_self=True, update_tippee=True, cursor=None):
"""Given a Participant or username, and amount as str, returns a dict.
Expand Down
4 changes: 4 additions & 0 deletions gratipay/models/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ def create_new(cls, owner, fields):
fields['product_or_service'], fields['getting_involved'], fields['getting_paid'],
owner.username))


def update_receiving(self, cursor=None):
# Stubbed out for now. Migrate this over from Participant.
pass
63 changes: 63 additions & 0 deletions tests/py/test_participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
UsernameIsRestricted,
NoSelfTipping,
NoTippee,
NoTeam,
BadAmount,
)
from gratipay.models.account_elsewhere import AccountElsewhere
Expand Down Expand Up @@ -449,6 +450,68 @@ def test_can_go_plural(self):
bob.update_number('plural')
assert Participant.from_username('bob').number == 'plural'


# set_subscription_to - sst

def test_sst_sets_subscription_to(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
team = self.make_team()
alice.set_subscription_to(team, '1.00')

actual = alice.get_subscription_to(team)['amount']
assert actual == Decimal('1.00')

def test_sst_returns_a_dict(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
team = self.make_team()
actual = alice.set_subscription_to(team, '1.00')
assert isinstance(actual, dict)
assert isinstance(actual['amount'], Decimal)
assert actual['amount'] == 1

def test_sst_allows_up_to_a_thousand(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
team = self.make_team()
alice.set_subscription_to(team, '1000.00')

def test_sst_doesnt_allow_a_penny_more(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
team = self.make_team()
self.assertRaises(BadAmount, alice.set_subscription_to, team, '1000.01')

def test_sst_allows_a_zero_subscription(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
team = self.make_team()
alice.set_subscription_to(team, '0.00')

def test_sst_doesnt_allow_a_penny_less(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
team = self.make_team()
self.assertRaises(BadAmount, alice.set_subscription_to, team, '-0.01')

def test_sst_fails_to_subscribe_to_an_unknown_team(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
self.assertRaises(NoTeam, alice.set_subscription_to, 'The B Team', '1.00')

def test_sst_is_free_rider_defaults_to_none(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
assert alice.is_free_rider is None

def test_sst_sets_is_free_rider_to_false(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
gratipay = self.make_team('Gratipay', owner=self.make_participant('Gratipay').username)
alice.set_subscription_to(gratipay, '0.01')
assert alice.is_free_rider is False
assert Participant.from_username('alice').is_free_rider is False

def test_sst_resets_is_free_rider_to_null(self):
alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
gratipay = self.make_team('Gratipay', owner=self.make_participant('Gratipay').username)
alice.set_subscription_to(gratipay, '0.00')
assert alice.is_free_rider is None
assert Participant.from_username('alice').is_free_rider is None


# set_tip_to - stt

def test_stt_sets_tip_to(self):
Expand Down

0 comments on commit 5f8bc3d

Please sign in to comment.