def setUp(self): # Balanced Customer without funding instruments self.david = self.make_participant('david', is_suspicious=False, claimed_time='now', balanced_customer_href=self.david_href) # Balanced Customer with CC attached self.janet = self.make_participant('janet', is_suspicious=False, claimed_time='now', balanced_customer_href=self.janet_href) self.janet_route = ExchangeRoute.insert(self.janet, 'balanced-cc', self.card_href) # Balanced Customer with BA attached self.homer = self.make_participant('homer', is_suspicious=False, claimed_time='now', balanced_customer_href=self.homer_href) self.homer_route = ExchangeRoute.insert(self.homer, 'balanced-ba', self.bank_account_href) # Braintree Customer without funding instruments self.roman = self.make_participant('roman', is_suspicious=False, claimed_time='now', braintree_customer_id=self.roman_bt_id) # Braintree Customer with CC attached self.obama = self.make_participant('obama', is_suspicious=False, claimed_time='now', braintree_customer_id=self.obama_bt_id) self.obama_route = ExchangeRoute.insert(self.obama, 'braintree-cc', self.obama_cc_token)
def test_credit_callback(self, rer): alice = self.make_participant('alice') ExchangeRoute.insert(alice, 'balanced-ba', '/bank/foo', '') ba = ExchangeRoute.from_network(alice, 'balanced-ba') for status in ('succeeded', 'failed'): error = 'FOO' if status == 'failed' else None e_id = record_exchange(self.db, ba, 10, 0, alice, 'pre') body = json.dumps({ "events": [{ "type": "credit." + status, "entity": { "credits": [{ "failure_reason": error, "meta": { "participant_id": alice.id, "exchange_id": e_id, }, "status": status, }] } }] }) r = self.callback(body=body, csrf_token=False) assert r.code == 200, r.body assert rer.call_count == 1 assert rer.call_args[0][:-1] == (self.db, e_id, status, error) assert rer.call_args[0][-1].id == alice.id assert rer.call_args[1] == {} rer.reset_mock()
def test_credit_callback(self, rer): alice = self.make_participant('alice') ExchangeRoute.insert(alice, 'balanced-ba', '/bank/foo', '') ba = ExchangeRoute.from_network(alice, 'balanced-ba') for status in ('succeeded', 'failed'): error = 'FOO' if status == 'failed' else None e_id = record_exchange(self.db, ba, 10, 0, alice, 'pre') body = json.dumps({ "events": [ { "type": "credit."+status, "entity": { "credits": [ { "failure_reason": error, "meta": { "participant_id": alice.id, "exchange_id": e_id, }, "status": status, } ] } } ] }) r = self.callback(body=body, csrf_token=False) assert r.code == 200, r.body assert rer.call_count == 1 assert rer.call_args[0][:-1] == (self.db, e_id, status, error) assert rer.call_args[0][-1].id == alice.id assert rer.call_args[1] == {} rer.reset_mock()
def test_grprbn_includes_1_0_payouts(self): alice = self.make_participant('alice', balance=24, status_of_1_0_payout='pending-payout', claimed_time='now') ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') routes = get_ready_payout_routes_by_network(self.db, 'paypal') assert [r.participant.username for r in routes] == ['alice']
def test_grprbn_includes_1_0_payouts(self): alice = self.make_participant( 'alice' , balance=24 , status_of_1_0_payout='pending-payout' , claimed_time='now' ) ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') routes = get_ready_payout_routes_by_network(self.db, 'paypal') assert [r.participant.username for r in routes] == ['alice']
def make_participant(self, username, **kw): """Factory for :py:class:`~gratipay.models.participant.Participant`. """ participant = self.db.one( """ INSERT INTO participants (username, username_lower) VALUES (%s, %s) RETURNING participants.*::participants """, (username, username.lower())) if 'elsewhere' in kw or 'claimed_time' in kw: platform = kw.pop('elsewhere', 'github') self.db.run( """ INSERT INTO elsewhere (platform, user_id, user_name, participant) VALUES (%s,%s,%s,%s) """, (platform, participant.id, username, username)) # Insert exchange routes if 'last_bill_result' in kw: route = ExchangeRoute.insert(participant, 'braintree-cc', '/cards/foo') route.update_error(kw.pop('last_bill_result')) if 'last_paypal_result' in kw: route = ExchangeRoute.insert(participant, 'paypal', '*****@*****.**') route.update_error(kw.pop('last_paypal_result')) # Update participant verified_in = kw.pop('verified_in', []) if kw: if kw.get('claimed_time') == 'now': kw['claimed_time'] = utcnow() cols, vals = zip(*kw.items()) cols = ', '.join(cols) placeholders = ', '.join(['%s'] * len(vals)) participant = self.db.one( """ UPDATE participants SET ({0}) = ({1}) WHERE username=%s RETURNING participants.*::participants """.format(cols, placeholders), vals + (username, )) # Verify identity countries = [verified_in ] if type(verified_in) in (str, unicode) else verified_in for code in countries: country = self.db.one("SELECT id FROM countries WHERE code=%s", (code, )) participant.store_identity_info(country, 'nothing-enforced', {'name': username}) participant.set_identity_verification(country, True) return participant
def setUp(self): self.david = self.make_participant('david', is_suspicious=False, claimed_time='now', balanced_customer_href=self.david_href) self.janet = self.make_participant('janet', is_suspicious=False, claimed_time='now', balanced_customer_href=self.janet_href) self.janet_route = ExchangeRoute.insert(self.janet, 'balanced-cc', self.card_href) self.homer = self.make_participant('homer', is_suspicious=False, claimed_time='now', balanced_customer_href=self.homer_href) self.homer_route = ExchangeRoute.insert(self.homer, 'balanced-ba', self.bank_account_href)
def test_create_card_hold_bad_card(self): bob = self.make_participant('bob', balanced_customer_href='new', is_suspicious=False) card = balanced.Card(number='4444444444444448', expiration_year=2020, expiration_month=12).save() card.associate_to_customer(bob.balanced_customer_href) ExchangeRoute.insert(bob, 'balanced-cc', card.href) hold, error = create_card_hold(self.db, bob, D('10.00')) assert error.startswith('402 Payment Required, ')
def test_create_card_hold_bad_card(self): bob = self.make_participant('bob', balanced_customer_href='new', is_suspicious=False) card = balanced.Card( number='4444444444444448', expiration_year=2020, expiration_month=12 ).save() card.associate_to_customer(bob.balanced_customer_href) ExchangeRoute.insert(bob, 'balanced-cc', card.href) hold, error = create_card_hold(self.db, bob, D('10.00')) assert error.startswith('402 Payment Required, ')
def set_paypal_email(username='', email='', api_key_fragment='', overwrite=False): """ Usage: [gratipay] $ env/bin/invoke set_paypal_email --username=username [email protected] [--api-key-fragment=12e4s678] [--overwrite] """ if not username or not email: print_help(set_paypal_email) sys.exit(1) if not os.environ.get('DATABASE_URL'): load_prod_envvars() if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment wireup.db(wireup.env()) participant = Participant.from_username(username) if not participant: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) route = ExchangeRoute.from_network(participant, 'paypal') # PayPal caps the MassPay fee at $20 for users outside the U.S., and $1 for # users inside the U.S. Most Gratipay users using PayPal are outside the U.S. # so we set to $20 and I'll manually adjust to $1 when running MassPay and # noticing that something is off. FEE_CAP = 20 if route: print("PayPal email is already set to: " + route.address) if not overwrite: print("Not overwriting existing PayPal email.") sys.exit(3) if participant.api_key == None: assert first_eight == "None" else: assert participant.api_key[0:8] == first_eight print("Setting PayPal email for " + username + " to " + email) ExchangeRoute.insert(participant, 'paypal', email, fee_cap=FEE_CAP) print("All done.")
def setUp(self): # Braintree Customer without funding instruments self.roman = self.make_participant('roman', is_suspicious=False, claimed_time='now', braintree_customer_id=self.roman_bt_id) # Braintree Customer with CC attached self.obama = self.make_participant('obama', is_suspicious=False, claimed_time='now', braintree_customer_id=self.obama_bt_id) self.obama_route = ExchangeRoute.insert(self.obama, 'braintree-cc', self.obama_cc_token) # A customer with Paypal attached. self.homer = self.make_participant('homer', is_suspicious=False, claimed_time='now') self.homer_route = ExchangeRoute.insert(self.homer, 'paypal', '*****@*****.**')
def test_cch_multiple_cards(self): bob = self.make_participant('bob', is_suspicious=False) customer_id = bob.get_braintree_account().id for i in range(2): result = braintree.PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.Transactable }) assert result.is_success ExchangeRoute.insert(bob, 'braintree-cc', result.payment_method.token) self.hold, error = create_card_hold(self.db, bob, D('100.00')) assert error == ''
def test_cch_multiple_cards(self): bob = self.make_participant('bob', is_suspicious=False) customer_id = bob.get_braintree_account().id for i in range(2): result = braintree.PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.Transactable }) assert result.is_success ExchangeRoute.insert(bob, 'braintree-cc', result.payment_method.token) self.hold, error = create_card_hold(self.db, bob, D('100.00')) assert error == ''
def test_giving_is_updated_when_credit_card_is_updated(self, btd): alice = self.make_participant('alice', claimed_time='now', last_bill_result='fail') team = self.make_team(is_approved=True) alice.set_payment_instruction(team, '5.00') # Not funded, failing card assert alice.giving == Decimal('0.00') assert Team.from_slug(team.slug).receiving == Decimal('0.00') # Alice updates her card.. ExchangeRoute.from_network(alice, 'braintree-cc').invalidate() ExchangeRoute.insert(alice, 'braintree-cc', '/cards/bar', '') assert alice.giving == Decimal('5.00') assert Team.from_slug(team.slug).receiving == Decimal('5.00')
def test_giving_is_updated_when_credit_card_is_updated(self, btd): alice = self.make_participant('alice', claimed_time='now', last_bill_result='fail') team = self.make_team(is_approved=True) alice.set_payment_instruction(team, '5.00') # Not funded, failing card assert alice.giving == Decimal('0.00') assert Team.from_slug(team.slug).receiving == Decimal('0.00') # Alice updates her card.. ExchangeRoute.from_network(alice, 'braintree-cc').invalidate() ExchangeRoute.insert(alice, 'braintree-cc', '/cards/bar', '') assert alice.giving == Decimal('5.00') assert Team.from_slug(team.slug).receiving == Decimal('5.00')
def test_cch_bad_card(self): bob = self.make_participant('bob', is_suspicious=False) customer_id = bob.get_braintree_account().id result = braintree.PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.Transactable }) assert result.is_success ExchangeRoute.insert(bob, 'braintree-cc', result.payment_method.token) # https://developers.braintreepayments.com/ios+python/reference/general/testing#test-amounts # $2002 is upcharged to $2062, which corresponds to 'Invalid Tax Amount' self.hold, error = create_card_hold(self.db, bob, D('2002.00')) assert self.hold is None assert error.startswith('Invalid Tax Amount')
def test_cch_bad_card(self): bob = self.make_participant('bob', is_suspicious=False) customer_id = bob.get_braintree_account().id result = braintree.PaymentMethod.create({ "customer_id": customer_id, "payment_method_nonce": Nonces.Transactable }) assert result.is_success ExchangeRoute.insert(bob, 'braintree-cc', result.payment_method.token) # https://developers.braintreepayments.com/ios+python/reference/general/testing#test-amounts # $2002 is upcharged to $2062, which corresponds to 'Invalid Tax Amount' self.hold, error = create_card_hold(self.db, bob, D('2002.00')) assert self.hold is None assert error.startswith('Invalid Tax Amount')
def test_giving_is_updated_when_credit_card_is_updated(self, btd): alice = self.make_participant("alice", claimed_time="now", last_bill_result="fail") team = self.make_team(is_approved=True) alice.set_payment_instruction(team, "5.00") # Not funded, failing card assert alice.giving == Decimal("0.00") assert Team.from_slug(team.slug).receiving == Decimal("0.00") # Alice updates her card.. ExchangeRoute.from_network(alice, "braintree-cc").invalidate() ExchangeRoute.insert(alice, "braintree-cc", "/cards/bar", "") assert alice.giving == Decimal("5.00") assert Team.from_slug(team.slug).receiving == Decimal("5.00")
def set_paypal_email(username='', email='', api_key_fragment='', overwrite=False): """ Usage: [gratipay] $ env/bin/invoke set_paypal_email --username=username [email protected] [--api-key-fragment=12e4s678] [--overwrite] """ if not username or not email: print_help(set_paypal_email) sys.exit(1) if not os.environ.get('DATABASE_URL'): load_prod_envvars() if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment wireup.db(wireup.env()) participant = Participant.from_username(username) if not participant: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) route = ExchangeRoute.from_network(participant, 'paypal') # PayPal caps the MassPay fee at $20 for users outside the U.S., and $1 for # users inside the U.S. Most Gratipay users using PayPal are outside the U.S. # so we set to $20 and I'll manually adjust to $1 when running MassPay and # noticing that something is off. FEE_CAP = 20 if route: print("PayPal email is already set to: " + route.address) if not overwrite: print("Not overwriting existing PayPal email.") sys.exit(3) if participant.api_key == None: assert first_eight == "None" else: assert participant.api_key[0:8] == first_eight print("Setting PayPal email for " + username + " to " + email) ExchangeRoute.insert(participant, 'paypal', email, fee_cap=FEE_CAP) print("All done.")
def make_participant(self, username, **kw): participant = self.db.one( """ INSERT INTO participants (username, username_lower) VALUES (%s, %s) RETURNING participants.*::participants """, (username, username.lower()), ) if "elsewhere" in kw or "claimed_time" in kw: platform = kw.pop("elsewhere", "github") self.db.run( """ INSERT INTO elsewhere (platform, user_id, user_name, participant) VALUES (%s,%s,%s,%s) """, (platform, participant.id, username, username), ) # Insert exchange routes if "last_bill_result" in kw: ExchangeRoute.insert(participant, "braintree-cc", "/cards/foo", kw.pop("last_bill_result")) if "last_paypal_result" in kw: ExchangeRoute.insert(participant, "paypal", "*****@*****.**", kw.pop("last_paypal_result")) # Update participant if kw: if kw.get("claimed_time") == "now": kw["claimed_time"] = utcnow() cols, vals = zip(*kw.items()) cols = ", ".join(cols) placeholders = ", ".join(["%s"] * len(vals)) participant = self.db.one( """ UPDATE participants SET ({0}) = ({1}) WHERE username=%s RETURNING participants.*::participants """.format( cols, placeholders ), vals + (username,), ) return participant
def test_bitcoin_payout(self, cb): # https://developers.coinbase.com/api#send-money cb.return_value.status_code = 200 cb.return_value.json = lambda: { 'success': True, 'transfer': { 'fees': { 'coinbase': {'currency_iso': 'USD', 'cents': 10}, 'bank': {'currency_iso': 'USD', 'cents': 15} }, 'subtotal': {'currency': 'USD', 'amount': 20}, 'btc': {'currency': 'BTC', 'amount': 1} } } alice = self.make_participant('alice', api_key='abcdefgh', balance=100) route = ExchangeRoute.insert(alice, 'bitcoin', '17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j') bitcoin_payout(username='******', amount=20, api_key_fragment=alice.api_key[0:8]) alice = Participant.from_username('alice') assert alice.balance == 79.75 exchange = self.db.one(""" SELECT * FROM exchanges WHERE participant='alice' """) assert exchange.amount == -20 assert exchange.fee == 0.25 assert exchange.route == route.id
def test_scopes_to_cursor(self): alice = self.make_participant('alice', claimed_time='now') with self.db.get_cursor() as cursor: route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**', cursor=cursor) assert alice.get_payout_routes() == [] assert alice.get_payout_routes(cursor=cursor) == [route] assert alice.get_payout_routes() == [route]
def record_an_exchange(self, data, make_participants=True): if make_participants: self.make_participants() data.setdefault('status', 'succeeded') data.setdefault('note', 'noted') if 'route_id' not in data: try: data['route_id'] = ExchangeRoute.insert( self.bob, 'paypal', '*****@*****.**').id except IntegrityError: data['route_id'] = ExchangeRoute.from_network( self.bob, 'paypal').id if data['status'] is None: del (data['status']) if data['route_id'] is None: del (data['route_id']) if 'ref' not in data: data['ref'] = 'N/A' return self.client.PxST('/~bob/history/record-an-exchange', data, auth_as='alice')
def test_cch_deleted_card(self): bob = self.make_participant('bob', is_suspicious=False) route = ExchangeRoute.insert(bob, 'braintree-cc', 'foo') self.db.run("UPDATE exchange_routes SET is_deleted=true WHERE id=%s", (route.id,)) self.hold, error = create_card_hold(self.db, bob, D('10.00')) assert error == 'No credit card'
def make_participant(self, username, **kw): """Factory for :py:class:`~gratipay.models.participant.Participant`. """ participant = self.db.one(""" INSERT INTO participants (username, username_lower) VALUES (%s, %s) RETURNING participants.*::participants """, (username, username.lower())) if 'elsewhere' in kw or 'claimed_time' in kw: platform = kw.pop('elsewhere', 'github') self.db.run(""" INSERT INTO elsewhere (platform, user_id, user_name, participant) VALUES (%s,%s,%s,%s) """, (platform, participant.id, username, username)) # Insert exchange routes if 'last_bill_result' in kw: ExchangeRoute.insert(participant, 'braintree-cc', '/cards/foo', kw.pop('last_bill_result')) if 'last_paypal_result' in kw: ExchangeRoute.insert(participant, 'paypal', '*****@*****.**', kw.pop('last_paypal_result')) # Update participant verified_in = kw.pop('verified_in', []) if kw: if kw.get('claimed_time') == 'now': kw['claimed_time'] = utcnow() cols, vals = zip(*kw.items()) cols = ', '.join(cols) placeholders = ', '.join(['%s']*len(vals)) participant = self.db.one(""" UPDATE participants SET ({0}) = ({1}) WHERE username=%s RETURNING participants.*::participants """.format(cols, placeholders), vals+(username,)) # Verify identity countries = [verified_in] if type(verified_in) in (str, unicode) else verified_in for code in countries: country = self.db.one("SELECT id FROM countries WHERE code=%s", (code,)) participant.store_identity_info(country, 'nothing-enforced', {'name': username}) participant.set_identity_verification(country, True) return participant
def get_route_id(cur, transaction, counts, usernames, exchange_id): # First strategy: match on exchange id. route_id = cur.one("SELECT route FROM exchanges WHERE id=%s", (exchange_id,)) if route_id: counts.route_in_exchange += 1 log("exchange has a route", 22) return route_id # Second strategy: match on known cards. if not route_id: routes = cur.all( "SELECT * FROM exchange_routes " "WHERE network='balanced-cc' AND address='/cards/'||%s" , (transaction['links']['source'],) ) route_id = resolve_route(cur, transaction, counts, routes, usernames) if route_id: counts.route_matched_via_card += 1 log("card matches {}".format(route_id), 22) return route_id # Third strategy: match on usernames. if not route_id: routes = cur.all("""\ SELECT * FROM exchange_routes WHERE network='balanced-cc' and participant in ( SELECT id FROM participants WHERE username=ANY(%s) ) """, (usernames,)) route_id = resolve_route(cur, transaction, counts, routes, usernames) if route_id: counts.route_matched_via_customer += 1 log("customer matches {}".format(route_id), 22) return route_id # Fourth strategy: make a route! if not route_id: if len(usernames) > 1: counts.route_ambiguous_customer += 1 raise AmbiguousCustomer() username = usernames[0] participant = cur.one("SELECT participants.*::participants FROM participants " "WHERE username=%s", (username,)) route = ExchangeRoute.insert( participant , 'balanced-cc' , '/cards/'+transaction['links']['source'] , cursor=cur ) route_id = route.id if route_id: counts.route_created += 1 log("created a route", 22) return route_id counts.route_unknown += 1 raise UnknownRoute()
def test_cch_deleted_card(self): bob = self.make_participant('bob', is_suspicious=False) route = ExchangeRoute.insert(bob, 'braintree-cc', 'foo') self.db.run("UPDATE exchange_routes SET is_deleted=true WHERE id=%s", (route.id, )) self.hold, error = create_card_hold(self.db, bob, D('10.00')) assert error == 'No credit card'
def setUp(self): if not BillingHarness._fixture_installed: install_fixture() # Braintree Customer without funding instruments self.roman = self.make_participant('roman', is_suspicious=False, claimed_time='now', braintree_customer_id=self.roman_bt_id) # Braintree Customer with CC attached self.obama = self.make_participant('obama', is_suspicious=False, claimed_time='now', braintree_customer_id=self.obama_bt_id) self.obama_route = ExchangeRoute.insert(self.obama, 'braintree-cc', self.obama_cc_token) # A customer with Paypal attached. self.homer = self.make_participant('homer', is_suspicious=False, verified_in='US', claimed_time='now', email_address='*****@*****.**') self.homer_route = ExchangeRoute.insert(self.homer, 'paypal', '*****@*****.**')
def test_route_should_belong_to_user_else_400(self): alice = self.make_participant('alice', claimed_time='now', is_admin=True) self.make_participant('bob', claimed_time='now') route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') response = self.record_an_exchange({'amount': '10', 'fee': '0', 'route_id': route.id}, False) assert response.code == 400 assert response.body == "Route doesn't exist"
def test_create_card_hold_multiple_cards(self): bob = self.make_participant('bob', balanced_customer_href='new', is_suspicious=False) card = balanced.Card(number='4242424242424242', expiration_year=2020, expiration_month=12).save() card.associate_to_customer(bob.balanced_customer_href) ExchangeRoute.insert(bob, 'balanced-cc', card.href) card = balanced.Card(number='4242424242424242', expiration_year=2030, expiration_month=12).save() card.associate_to_customer(bob.balanced_customer_href) ExchangeRoute.insert(bob, 'balanced-cc', card.href) hold, error = create_card_hold(self.db, bob, D('10.00')) assert error == ''
def make_exchange(self, route, amount, fee, participant, status='succeeded', error=''): if not isinstance(route, ExchangeRoute): network = route route = ExchangeRoute.from_network(participant, network) if not route: route = ExchangeRoute.insert(participant, network, 'dummy-address') assert route e_id = record_exchange(self.db, route, amount, fee, participant, 'pre') record_exchange_result(self.db, e_id, status, error, participant) return e_id
def test_scopes_to_cursor(self): alice = self.make_participant('alice', claimed_time='now') with self.db.get_cursor() as cursor: route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**', cursor=cursor) assert alice.get_payout_routes() == [] assert alice.get_payout_routes(cursor=cursor) == [route] assert alice.get_payout_routes() == [route]
def make_exchange(self, route, amount, fee, participant, status='succeeded', error=''): if not isinstance(route, ExchangeRoute): network = route route = ExchangeRoute.from_network(participant, network) if not route: route = ExchangeRoute.insert(participant, network, 'dummy-address') assert route e_id = record_exchange(self.db, route, amount, fee, participant, 'pre') record_exchange_result(self.db, e_id, status, error, participant) return e_id
def make_participant(self, username, **kw): participant = self.db.one( """ INSERT INTO participants (username, username_lower) VALUES (%s, %s) RETURNING participants.*::participants """, (username, username.lower())) if 'elsewhere' in kw or 'claimed_time' in kw: platform = kw.pop('elsewhere', 'github') self.db.run( """ INSERT INTO elsewhere (platform, user_id, user_name, participant) VALUES (%s,%s,%s,%s) """, (platform, participant.id, username, username)) # Insert exchange routes if 'last_bill_result' in kw: ExchangeRoute.insert(participant, 'braintree-cc', '/cards/foo', kw.pop('last_bill_result')) if 'last_paypal_result' in kw: ExchangeRoute.insert(participant, 'paypal', '*****@*****.**', kw.pop('last_paypal_result')) # Update participant if kw: if kw.get('claimed_time') == 'now': kw['claimed_time'] = utcnow() cols, vals = zip(*kw.items()) cols = ', '.join(cols) placeholders = ', '.join(['%s'] * len(vals)) participant = self.db.one( """ UPDATE participants SET ({0}) = ({1}) WHERE username=%s RETURNING participants.*::participants """.format(cols, placeholders), vals + (username, )) return participant
def make_exchange(self, route, amount, fee, participant, status='succeeded', error=''): if not isinstance(route, ExchangeRoute): network = route route = ExchangeRoute.from_network(participant, network) if not route: from .balanced import BalancedHarness route = ExchangeRoute.insert(participant, network, BalancedHarness.card_href) assert route e_id = record_exchange(self.db, route, amount, fee, participant, 'pre') record_exchange_result(self.db, e_id, status, error, participant) return e_id
def setUp(self): self.david = self.make_participant( 'david', is_suspicious=False, claimed_time='now', balanced_customer_href=self.david_href) self.janet = self.make_participant( 'janet', is_suspicious=False, claimed_time='now', balanced_customer_href=self.janet_href) self.janet_route = ExchangeRoute.insert(self.janet, 'balanced-cc', self.card_href) self.homer = self.make_participant( 'homer', is_suspicious=False, claimed_time='now', balanced_customer_href=self.homer_href) self.homer_route = ExchangeRoute.insert(self.homer, 'balanced-ba', self.bank_account_href)
def test_create_card_hold_multiple_cards(self): bob = self.make_participant('bob', balanced_customer_href='new', is_suspicious=False) card = balanced.Card( number='4242424242424242', expiration_year=2020, expiration_month=12 ).save() card.associate_to_customer(bob.balanced_customer_href) ExchangeRoute.insert(bob, 'balanced-cc', card.href) card = balanced.Card( number='4242424242424242', expiration_year=2030, expiration_month=12 ).save() card.associate_to_customer(bob.balanced_customer_href) ExchangeRoute.insert(bob, 'balanced-cc', card.href) hold, error = create_card_hold(self.db, bob, D('10.00')) assert error == ''
def make_exchange(self, route, amount, fee, participant, status='succeeded', error='', ref='dummy-trans-id', address='dummy-address'): """Factory for exchanges. """ if not isinstance(route, ExchangeRoute): network = route route = ExchangeRoute.from_network(participant, network) if not route: route = ExchangeRoute.insert(participant, network, address) assert route e_id = record_exchange(self.db, route, amount, fee, participant, 'pre', ref) record_exchange_result(self.db, e_id, status, error, participant) return e_id
def make_participant(self, username, **kw): participant = self.db.one(""" INSERT INTO participants (username, username_lower) VALUES (%s, %s) RETURNING participants.*::participants """, (username, username.lower())) if 'elsewhere' in kw or 'claimed_time' in kw: platform = kw.pop('elsewhere', 'github') self.db.run(""" INSERT INTO elsewhere (platform, user_id, user_name, participant) VALUES (%s,%s,%s,%s) """, (platform, participant.id, username, username)) # Insert exchange routes if 'last_bill_result' in kw: ExchangeRoute.insert(participant, 'balanced-cc', '/cards/foo', kw.pop('last_bill_result')) if 'last_ach_result' in kw: ExchangeRoute.insert(participant, 'balanced-ba', '/bank_accounts/bar', kw.pop('last_ach_result')) # Update participant if kw: if kw.get('claimed_time') == 'now': kw['claimed_time'] = utcnow() if kw.get('balanced_customer_href') == 'new': kw['balanced_customer_href'] = self.make_balanced_customer() cols, vals = zip(*kw.items()) cols = ', '.join(cols) placeholders = ', '.join(['%s']*len(vals)) participant = self.db.one(""" UPDATE participants SET ({0}) = ({1}) WHERE username=%s RETURNING participants.*::participants """.format(cols, placeholders), vals+(username,)) return participant
def make_exchange(self, route, amount, fee, participant, status='succeeded', error='', ref='dummy-trans-id', address='dummy-address'): """Factory for exchanges. """ if not isinstance(route, ExchangeRoute): network = route route = ExchangeRoute.from_network(participant, network) if not route: route = ExchangeRoute.insert(participant, network, address) assert route e_id = record_exchange(self.db, route, amount, fee, participant, 'pre', ref) record_exchange_result(self.db, e_id, status, error, participant) return e_id
def test_route_should_belong_to_user_else_400(self): alice = self.make_participant('alice', claimed_time='now', is_admin=True) self.make_participant('bob', claimed_time='now') route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') response = self.record_an_exchange( { 'amount': '10', 'fee': '0', 'route_id': route.id }, False) assert response.code == 400 assert response.body == "Route doesn't exist"
def record_an_exchange(self, data, make_participants=True): if make_participants: self.make_participants() data.setdefault('status', 'succeeded') data.setdefault('note', 'noted') if 'route_id' not in data: try: data['route_id'] = ExchangeRoute.insert(self.bob, 'paypal', '*****@*****.**').id except IntegrityError: data['route_id'] = ExchangeRoute.from_network(self.bob, 'paypal').id if data['status'] is None: del(data['status']) if data['route_id'] is None: del(data['route_id']) return self.client.PxST('/~bob/history/record-an-exchange', data, auth_as='alice')
def test_gets_only_good_routes(self): alice = self.make_participant('alice', claimed_time='now') route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') route.update_error('so erroneous') assert alice.get_payout_routes(good_only=True) == []
def test_gets_payout_routes(self): alice = self.make_participant('alice', claimed_time='now') route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') assert alice.get_payout_routes() == [route]
def test_gets_only_good_routes(self): alice = self.make_participant('alice', claimed_time='now') route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') route.update_error('so erroneous') assert alice.get_payout_routes(good_only=True) == []
def test_cch_invalidated_card(self): bob = self.make_participant('bob', is_suspicious=False) ExchangeRoute.insert(bob, 'braintree-cc', 'foo', error='invalidated') self.hold, error = create_card_hold(self.db, bob, D('10.00')) assert error == 'No credit card'
def test_cch_invalidated_card(self): bob = self.make_participant('bob', is_suspicious=False) ExchangeRoute.insert(bob, 'braintree-cc', 'foo', error='invalidated') self.hold, error = create_card_hold(self.db, bob, D('10.00')) assert error == 'No credit card'
def test_gets_payout_routes(self): alice = self.make_participant('alice', claimed_time='now') route = ExchangeRoute.insert(alice, 'paypal', '*****@*****.**') assert alice.get_payout_routes() == [route]