Exemplo n.º 1
0
    def test_payment_providers_of_team(self):
        # 1. Test when the creator doesn't have any connected payment account.
        alice = self.make_participant('alice')
        data = {'name': 'Team1'}
        r = self.client.PxST('/about/teams', data, auth_as=alice)
        assert r.code == 302
        team = Participant.from_username(data['name'])
        assert team.payment_providers == 0

        # 2. Test when the creator has connected a PayPal account.
        self.add_payment_account(alice, 'paypal')
        data = {'name': 'Team2'}
        r = self.client.PxST('/about/teams', data, auth_as=alice)
        assert r.code == 302
        team = Participant.from_username(data['name'])
        assert team.payment_providers == 2

        # 3. Test after adding a member with a connected Stripe account.
        bob = self.make_participant('bob')
        self.add_payment_account(bob, 'stripe')
        team.add_member(bob)
        team = team.refetch()
        assert team.payment_providers == 3

        # 4. Test after the creator leaves.
        team.set_take_for(alice, None, alice)
        team = team.refetch()
        assert team.payment_providers == 1
Exemplo n.º 2
0
 def test_dbtd_distributes_balance_as_final_gift(self):
     alice = self.make_participant('alice', balance=EUR('10.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, EUR('3.00'))
     alice.set_tip_to(carl, EUR('2.00'))
     alice.distribute_balances_to_donees()
     assert Participant.from_username('bob').balance == EUR('6.00')
     assert Participant.from_username('carl').balance == EUR('4.00')
     assert Participant.from_username('alice').balance == EUR('0.00')
Exemplo n.º 3
0
 def test_dbtd_favors_highest_tippee_in_rounding_errors(self):
     alice = self.make_participant('alice', balance=EUR('10.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, EUR('3.00'))
     alice.set_tip_to(carl, EUR('6.00'))
     alice.distribute_balances_to_donees()
     assert Participant.from_username('bob').balance == EUR('3.33')
     assert Participant.from_username('carl').balance == EUR('6.67')
     assert Participant.from_username('alice').balance == EUR('0.00')
Exemplo n.º 4
0
 def test_dbtd_with_zero_balance_is_a_noop(self):
     alice = self.make_participant('alice', balance=EUR('0.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, EUR('3.00'))
     alice.set_tip_to(carl, EUR('6.00'))
     alice.distribute_balances_to_donees()
     assert self.db.one("SELECT count(*) FROM tips") == 2
     assert Participant.from_username('bob').balance == EUR('0.00')
     assert Participant.from_username('carl').balance == EUR('0.00')
     assert Participant.from_username('alice').balance == EUR('0.00')
Exemplo n.º 5
0
 def test_dbtd_skips_stopped_tips(self):
     alice = self.make_participant('alice', balance=EUR('10.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, EUR('1.00'))
     alice.stop_tip_to(bob)
     alice.set_tip_to(carl, EUR('2.00'))
     alice.distribute_balances_to_donees()
     assert Participant.from_username('bob').balance == EUR('0.00')
     assert Participant.from_username('carl').balance == EUR('10.00')
     assert Participant.from_username('alice').balance == EUR('0.00')
Exemplo n.º 6
0
 def test_dbafg_favors_highest_tippee_in_rounding_errors(self):
     alice = self.make_participant('alice', balance=D('10.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, D('3.00'))
     alice.set_tip_to(carl, D('6.00'))
     with self.db.get_cursor() as cursor:
         alice.distribute_balance_as_final_gift(cursor)
     assert Participant.from_username('bob').balance == D('3.33')
     assert Participant.from_username('carl').balance == D('6.67')
     assert Participant.from_username('alice').balance == D('0.00')
Exemplo n.º 7
0
    def test_can_post_to_close_page(self):
        alice = self.make_participant('alice', balance=7)
        bob = self.make_participant('bob')
        alice.set_tip_to(bob, D('10.00'))

        data = {'disburse_to': 'downstream'}
        response = self.client.PxST('/alice/settings/close', auth_as=alice, data=data)
        assert response.code == 302
        assert response.headers['Location'] == '/alice/'
        assert Participant.from_username('alice').balance == 0
        assert Participant.from_username('bob').balance == 7
Exemplo n.º 8
0
 def test_dbafg_distributes_balance_as_final_gift(self):
     alice = self.make_participant('alice', balance=D('10.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, D('3.00'))
     alice.set_tip_to(carl, D('2.00'))
     with self.db.get_cursor() as cursor:
         alice.distribute_balance_as_final_gift(cursor)
     assert Participant.from_username('bob').balance == D('6.00')
     assert Participant.from_username('carl').balance == D('4.00')
     assert Participant.from_username('alice').balance == D('0.00')
Exemplo n.º 9
0
 def test_dbafg_skips_zero_tips(self):
     alice = self.make_participant('alice', balance=D('10.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, D('0.00'))
     alice.set_tip_to(carl, D('2.00'))
     with self.db.get_cursor() as cursor:
         alice.distribute_balance_as_final_gift(cursor)
     assert self.db.one("SELECT count(*) FROM tips WHERE tippee=%s", (bob.id,)) == 1
     assert Participant.from_username('bob').balance == D('0.00')
     assert Participant.from_username('carl').balance == D('10.00')
     assert Participant.from_username('alice').balance == D('0.00')
Exemplo n.º 10
0
 def test_dbafg_with_zero_balance_is_a_noop(self):
     alice = self.make_participant('alice', balance=D('0.00'))
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     alice.set_tip_to(bob, D('3.00'))
     alice.set_tip_to(carl, D('6.00'))
     with self.db.get_cursor() as cursor:
         alice.distribute_balance_as_final_gift(cursor)
     assert self.db.one("SELECT count(*) FROM tips") == 2
     assert Participant.from_username('bob').balance == D('0.00')
     assert Participant.from_username('carl').balance == D('0.00')
     assert Participant.from_username('alice').balance == D('0.00')
Exemplo n.º 11
0
    def test_payday_moves_money(self):
        self.janet.set_tip_to(self.homer, EUR('6.00'))  # under $10!
        self.make_exchange('mango-cc', 10, 0, self.janet)
        Payday.start().run()

        janet = Participant.from_username('janet')
        homer = Participant.from_username('homer')

        assert homer.balance == EUR('6.00')
        assert janet.balance == EUR('4.00')

        assert self.transfer_mock.call_count
Exemplo n.º 12
0
 def test_sync_with_mangopay_transfers(self):
     self.make_exchange('mango-cc', 10, 0, self.janet)
     with mock.patch('liberapay.billing.exchanges.record_transfer_result') as rtr:
         rtr.side_effect = Foobar()
         with self.assertRaises(Foobar):
             transfer(self.db, self.janet.id, self.david.id, D('10.00'), 'tip')
     t = self.db.one("SELECT * FROM transfers")
     assert t.status == 'pre'
     sync_with_mangopay(self.db)
     t = self.db.one("SELECT * FROM transfers")
     assert t.status == 'succeeded'
     assert Participant.from_username('david').balance == 10
     assert Participant.from_username('janet').balance == 0
Exemplo n.º 13
0
    def test_changes_to_others_take_can_increase_members_take(self):
        team, alice, bob = self.make_team_of_two()

        self.take_last_week(team, alice, '30.00')
        team.set_take_for(alice, D('25.00'), alice)

        self.take_last_week(team, bob, '50.00')
        team.set_take_for(bob, D('100.00'), bob)
        alice = Participant.from_username('alice')
        assert alice.receiving == alice.taking == 20

        team.set_take_for(bob, D('75.00'), bob)
        alice = Participant.from_username('alice')
        assert alice.receiving == alice.taking == 25
Exemplo n.º 14
0
 def test_sync_with_mangopay_deletes_transfers_that_didnt_happen(self):
     self.make_exchange('mango-cc', 10, 0, self.janet)
     with mock.patch('liberapay.billing.exchanges.record_transfer_result') as rtr \
        , mock.patch('liberapay.billing.mangoapi.transfers.Create') as Create:
         rtr.side_effect = Create.side_effect = Foobar
         with self.assertRaises(Foobar):
             transfer(self.db, self.janet.id, self.david.id, D('10.00'), 'tip')
     t = self.db.one("SELECT * FROM transfers")
     assert t.status == 'pre'
     sync_with_mangopay(self.db)
     transfers = self.db.all("SELECT * FROM transfers")
     assert not transfers
     assert Participant.from_username('david').balance == 0
     assert Participant.from_username('janet').balance == 10
    def test_payday_doesnt_move_money_to_a_suspicious_account(self):
        self.db.run("""
            UPDATE participants
               SET is_suspicious = true
             WHERE username = '******'
        """)
        self.janet.set_tip_to(self.homer, '6.00')  # under $10!
        Payday.start().run()

        janet = Participant.from_username('janet')
        homer = Participant.from_username('homer')

        assert janet.balance == D('0.00')
        assert homer.balance == D('0.00')
Exemplo n.º 16
0
 def test_3_sync_with_mangopay_handles_transfers_that_didnt_happen(self):
     self.make_exchange('mango-cc', 10, 0, self.janet)
     with mock.patch('liberapay.billing.transactions._record_transfer_result') as rtr, \
          mock.patch('liberapay.billing.transactions.Transfer.save', autospec=True) as save:
         rtr.side_effect = save.side_effect = Foobar
         with self.assertRaises(Foobar):
             transfer(self.db, self.janet.id, self.david.id, EUR('10.00'), 'tip')
     t = self.db.one("SELECT * FROM transfers")
     assert t.status == 'pre'
     self.throw_transactions_back_in_time()
     sync_with_mangopay(self.db)
     t = self.db.one("SELECT * FROM transfers")
     assert t.status == 'failed'
     assert t.error == 'interrupted'
     assert Participant.from_username('david').balance == 0
     assert Participant.from_username('janet').balance == 10
Exemplo n.º 17
0
def fake_participant(db, kind=None, is_admin=False):
    """Create a fake User.
    """
    username = faker.first_name() + fake_text_id(3)
    try:
        _fake_thing(
            db,
            "participants",
            username=username,
            password=None if kind == "group" else "x",
            email=username + "@example.org",
            is_admin=is_admin,
            balance=0,
            hide_giving=kind != "group" and (random.randrange(5) == 0),
            hide_receiving=kind != "group" and (random.randrange(5) == 0),
            is_suspicious=False,
            status="active",
            join_time=faker.date_time_this_year(),
            kind=kind or random.choice(("individual", "organization")),
            mangopay_user_id=username,
            mangopay_wallet_id="-1",
        )
    except IntegrityError:
        return fake_participant(db, is_admin)

    # Call participant constructor to perform other DB initialization
    return Participant.from_username(username)
Exemplo n.º 18
0
 def test_verify_email_after_update(self):
     self.verify_and_change_email('*****@*****.**', '*****@*****.**')
     nonce = self.alice.get_email('*****@*****.**').nonce
     self.verify_email('*****@*****.**', nonce)
     expected = '*****@*****.**'
     actual = Participant.from_username('alice').email
     assert expected == actual
Exemplo n.º 19
0
 def test_verify_email(self):
     self.hit_email_spt('add-email', '*****@*****.**')
     nonce = self.alice.get_email('*****@*****.**').nonce
     self.verify_email('*****@*****.**', nonce)
     expected = '*****@*****.**'
     actual = Participant.from_username('alice').email
     assert expected == actual
Exemplo n.º 20
0
    def test_delete_card(self):
        self.hit('janet', 'delete', 'mango-cc', self.card_id)

        janet = Participant.from_username('janet')
        cards = ExchangeRoute.from_network(janet, 'mango-cc')
        assert not cards
        assert janet.mangopay_user_id
Exemplo n.º 21
0
 def test_receiving_includes_taking(self):
     alice = self.make_participant('alice')
     alice_card = self.upsert_route(alice, 'stripe-card')
     bob = self.make_participant('bob', taking=EUR('42.00'))
     alice.set_tip_to(bob, EUR('3.00'))
     self.make_payin_and_transfer(alice_card, bob, EUR('30.00'))
     assert Participant.from_username('bob').receiving == bob.receiving == EUR('45.00')
Exemplo n.º 22
0
    def test_delete_bank_account(self):
        self.hit('homer', 'delete', 'mango-ba', self.bank_account.Id)

        homer = Participant.from_username('homer')
        route = ExchangeRoute.from_address(homer, 'mango-ba', self.bank_account.Id)
        assert route.status == 'canceled'
        assert homer.mangopay_user_id
Exemplo n.º 23
0
def fake_participant(db, kind=None, is_admin=False):
    """Create a fake User.
    """
    username = faker.first_name() + fake_text_id(3)
    kind = kind or random.choice(('individual', 'organization'))
    is_a_person = kind in ('individual', 'organization')
    try:
        _fake_thing( db
                   , "participants"
                   , username=username
                   , password=None if not is_a_person else 'x'
                   , email=username+'@example.org'
                   , is_admin=is_admin
                   , balance=0
                   , hide_giving=is_a_person and (random.randrange(5) == 0)
                   , hide_receiving=is_a_person and (random.randrange(5) == 0)
                   , status='active'
                   , join_time=faker.date_time_this_year()
                   , kind=kind
                   , mangopay_user_id=username
                   , mangopay_wallet_id='-1'
                    )
    except IntegrityError:
        return fake_participant(db, is_admin)

    #Call participant constructor to perform other DB initialization
    return Participant.from_username(username)
Exemplo n.º 24
0
    def test_cpi_clears_personal_information(self, mailer):
        alice = self.make_participant( 'alice'
                                     , goal=100
                                     , hide_giving=True
                                     , hide_receiving=True
                                     , avatar_url='img-url'
                                     , email='*****@*****.**'
                                     , session_token='deadbeef'
                                     , session_expires='2000-01-01'
                                     , giving=20
                                     , pledging=30
                                     , receiving=40
                                     , npatrons=21
                                      )
        alice.upsert_statement('en', 'not forgetting to be awesome!')
        alice.add_email('*****@*****.**')

        with self.db.get_cursor() as cursor:
            alice.clear_personal_information(cursor)
        new_alice = Participant.from_username('alice')

        assert alice.get_statement(['en']) == (None, None)
        assert alice.goal == new_alice.goal == None
        assert alice.hide_giving == new_alice.hide_giving == True
        assert alice.hide_receiving == new_alice.hide_receiving == True
        assert alice.avatar_url == new_alice.avatar_url == None
        assert alice.email == new_alice.email
        assert alice.giving == new_alice.giving == 0
        assert alice.pledging == new_alice.pledging == 0
        assert alice.receiving == new_alice.receiving == 0
        assert alice.npatrons == new_alice.npatrons == 0
        assert alice.session_token == new_alice.session_token == None
        assert alice.session_expires.year == new_alice.session_expires.year == date.today().year
        assert not alice.get_emails()
Exemplo n.º 25
0
 def test_record_exchange_result_restores_balance_on_error(self):
     homer, ba = self.homer, self.homer_route
     self.make_exchange('mango-cc', 30, 0, homer)
     e_id = record_exchange(self.db, ba, D('-27.06'), D('0.81'), 0, homer, 'pre')
     assert homer.balance == D('02.13')
     record_exchange_result(self.db, e_id, 'failed', 'SOME ERROR', homer)
     homer = Participant.from_username('homer')
     assert homer.balance == D('30.00')
Exemplo n.º 26
0
 def test_record_exchange_result_doesnt_restore_balance_on_success(self):
     homer, ba = self.homer, self.homer_route
     self.make_exchange('mango-cc', 50, 0, homer)
     e_id = record_exchange(self.db, ba, D('-43.98'), D('1.60'), 0, homer, 'pre')
     assert homer.balance == D('4.42')
     record_exchange_result(self.db, e_id, 'succeeded', None, homer)
     homer = Participant.from_username('homer')
     assert homer.balance == D('4.42')
Exemplo n.º 27
0
 def test_record_exchange_result_updates_balance_for_positive_amounts(self):
     janet, cc = self.janet, self.janet_route
     self.make_exchange('mango-cc', 4, 0, janet)
     e_id = record_exchange(self.db, cc, D('31.59'), D('0.01'), 0, janet, 'pre')
     assert janet.balance == D('4.00')
     record_exchange_result(self.db, e_id, 'succeeded', None, janet)
     janet = Participant.from_username('janet')
     assert janet.balance == D('35.59')
Exemplo n.º 28
0
    def test_changes_to_team_receiving_affect_members_take(self):
        team, alice = self.make_team_of_one()
        self.take_last_week(team, alice, '40.00')
        team.set_take_for(alice, D('42.00'), alice)

        self.warbucks.set_tip_to(team, EUR('10.00'))  # hard times
        alice = Participant.from_username('alice')
        assert alice.receiving == alice.taking == 10
Exemplo n.º 29
0
 def check():
     for username in reversed(usernames[1:]):
         user = Participant.from_username(username)
         assert user.giving == EUR('1.00')
         assert user.receiving == EUR('1.00')
         assert user.npatrons == 1
     funded_tips = self.db.all("SELECT id FROM tips WHERE is_funded ORDER BY id")
     assert len(funded_tips) == 6
Exemplo n.º 30
0
 def test_record_exchange_doesnt_update_balance_for_positive_amounts(self):
     record_exchange(
         self.db, self.janet_route,
         amount=D("0.59"), fee=D("0.41"), vat=D("0.00"),
         participant=self.janet, status='pre',
     )
     janet = Participant.from_username('janet')
     assert self.janet.balance == janet.balance == D('0.00')
Exemplo n.º 31
0
    def test_delete_card(self):
        self.hit('janet', 'delete', 'mango-cc', self.card_id)

        janet = Participant.from_username('janet')
        assert janet.get_credit_card_error() == 'invalidated'
        assert janet.mangopay_user_id
Exemplo n.º 32
0
def refund_payin(db,
                 exchange,
                 create_debts=False,
                 refund_fee=False,
                 dry_run=False):
    """Refund a specific payin.
    """
    assert exchange.status == 'succeeded' and exchange.remote_id, exchange
    e_refund = db.one("SELECT e.* FROM exchanges e WHERE e.refund_ref = %s",
                      (exchange.id, ))
    if e_refund and e_refund.status == 'succeeded':
        return 'already done', e_refund

    # Lock the bundles and try to swap them
    with db.get_cursor() as cursor:
        cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
        bundles = [
            NS(d._asdict()) for d in cursor.all(
                """
            UPDATE cash_bundles
               SET disputed = true
             WHERE origin = %s
         RETURNING *
        """, (exchange.id, ))
        ]
        bundles_sum = sum(b.amount for b in bundles)
        assert bundles_sum == exchange.amount
        original_owner = exchange.participant
        for b in bundles:
            if b.owner == original_owner:
                continue
            try_to_swap_bundle(cursor, b, original_owner)

    # Move the funds back to the original wallet
    LiberapayOrg = Participant.from_username('LiberapayOrg')
    assert LiberapayOrg
    return_payin_bundles_to_origin(db, exchange, LiberapayOrg, create_debts)

    # Add a debt for the fee
    if create_debts and refund_fee:
        create_debt(db, original_owner, LiberapayOrg.id, exchange.fee,
                    exchange.id)

    # Compute and check the amount
    wallet = db.one("SELECT * FROM wallets WHERE remote_id = %s",
                    (exchange.wallet_id, ))
    if e_refund and e_refund.status == 'pre':
        amount = -e_refund.amount
    else:
        amount = min(wallet.balance, exchange.amount)
        if amount <= 0:
            return ('not enough money: wallet balance = %s' %
                    wallet.balance), None

    # Stop here if this is a dry run
    zero = exchange.fee.zero()
    fee, vat = (exchange.fee, exchange.vat) if refund_fee else (zero, zero)
    if dry_run:
        msg = (
            '[dry run] full refund of payin #%s (liberapay id %s): amount = %s, fee = %s'
            % (exchange.remote_id, exchange.id, exchange.amount, exchange.fee)
        ) if amount + fee == exchange.amount + exchange.fee else (
            '[dry run] partial refund of payin #%s (liberapay id %s): %s of %s, fee %s of %s'
            % (exchange.remote_id, exchange.id, amount, exchange.amount, fee,
               exchange.fee))
        return msg, None

    # Record the refund attempt
    participant = Participant.from_id(exchange.participant)
    if not (e_refund and e_refund.status == 'pre'):
        with db.get_cursor() as cursor:
            cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
            bundles = [
                NS(d._asdict()) for d in cursor.all(
                    """
                SELECT *
                  FROM cash_bundles
                 WHERE origin = %s
                   AND wallet_id = %s
                   AND disputed = true
            """, (exchange.id, exchange.wallet_id))
            ]
            e_refund = cursor.one(
                """
                INSERT INTO exchanges
                            (participant, amount, fee, vat, route, status, refund_ref, wallet_id)
                     VALUES (%s, %s, %s, %s, %s, 'pre', %s, %s)
                  RETURNING *
            """, (participant.id, -amount, -fee, -vat, exchange.route,
                  exchange.id, exchange.wallet_id))
            cursor.run(
                """
                INSERT INTO exchange_events
                            (timestamp, exchange, status, wallet_delta)
                     VALUES (%s, %s, 'pre', %s)
            """, (e_refund.timestamp, e_refund.id,
                  e_refund.amount - e_refund.fee))
            propagate_exchange(cursor,
                               participant,
                               e_refund,
                               None,
                               e_refund.amount,
                               bundles=bundles)

    # Submit the refund
    m_refund = PayInRefund(payin_id=exchange.remote_id)
    m_refund.AuthorId = wallet.remote_owner_id
    m_refund.Tag = str(e_refund.id)
    m_refund.DebitedFunds = amount.int()
    m_refund.Fees = -fee.int()
    try:
        m_refund.save()
    except Exception as e:
        error = repr_exception(e)
        e_refund = record_exchange_result(db, e_refund.id, '', 'failed', error,
                                          participant)
        return 'exception', e_refund
    e_refund = record_exchange_result(db, e_refund.id, m_refund.Id,
                                      m_refund.Status.lower(),
                                      repr_error(m_refund), participant)
    return e_refund.status, e_refund
Exemplo n.º 33
0
 def test_verified_email_is_not_changed_after_update(self):
     self.add_and_verify_email('*****@*****.**')
     self.alice.add_email('*****@*****.**')
     expected = '*****@*****.**'
     actual = Participant.from_username('alice').email
     assert expected == actual
Exemplo n.º 34
0
 def test_changing_username_successfully(self):
     self.stub.change_username('user2')
     actual = Participant.from_username('user2')
     assert self.stub == actual
Exemplo n.º 35
0
 def test_changing_username_strips_spaces(self):
     self.stub.change_username('  aaa  ')
     actual = Participant.from_username('aaa')
     assert self.stub == actual
Exemplo n.º 36
0
 def test_known_user_is_known(self):
     alice = self.make_participant('alice')
     alice2 = Participant.from_username('alice')
     assert alice == alice2
Exemplo n.º 37
0
 def test_username_is_case_insensitive(self):
     self.make_participant('AlIcE')
     actual = Participant.from_username('aLiCe').username
     assert actual == 'AlIcE'
Exemplo n.º 38
0
 def test_bad_username(self):
     p = Participant.from_username('deadbeef')
     assert not p
Exemplo n.º 39
0
 def test_rs_returns_openstreetmap_url_for_stub_from_openstreetmap(self):
     unclaimed = self.make_elsewhere('openstreetmap', '1', 'alice')
     stub = Participant.from_username(unclaimed.participant.username)
     actual = stub.resolve_stub()
     assert actual == "/on/openstreetmap/alice/"
Exemplo n.º 40
0
 def test_receiving_includes_taking_when_updated_from_set_tip_to(self):
     alice = self.make_participant('alice', balance=100)
     bob = self.make_participant('bob', taking=Decimal('42.00'))
     alice.set_tip_to(bob, '3.00')
     assert Participant.from_username(
         'bob').receiving == bob.receiving == Decimal('45.00')
Exemplo n.º 41
0
 def test_rs_returns_twitter_url_for_stub_from_twitter(self):
     unclaimed = self.make_elsewhere('twitter', '1234', 'alice')
     stub = Participant.from_username(unclaimed.participant.username)
     actual = stub.resolve_stub()
     assert actual == "/on/twitter/alice/"
Exemplo n.º 42
0
 def test_rs_returns_bitbucket_url_for_stub_from_bitbucket(self):
     unclaimed = self.make_elsewhere('bitbucket', '1234', 'alice')
     stub = Participant.from_username(unclaimed.participant.username)
     actual = stub.resolve_stub()
     assert actual == "/on/bitbucket/alice/"
Exemplo n.º 43
0
def recover_lost_funds(db, exchange, lost_amount, repudiation_id):
    """Recover as much money as possible from a payin which has been reverted.
    """
    original_owner = exchange.participant
    # Try (again) to swap the disputed bundles
    with db.get_cursor() as cursor:
        cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE")
        disputed_bundles = [
            NS(d._asdict()) for d in cursor.all(
                """
            SELECT *
              FROM cash_bundles
             WHERE origin = %s
               AND disputed = true
        """, (exchange.id, ))
        ]
        bundles_sum = sum(b.amount for b in disputed_bundles)
        assert bundles_sum == lost_amount - exchange.fee
        for b in disputed_bundles:
            if b.owner == original_owner:
                continue
            try_to_swap_bundle(cursor, b, original_owner)
    # Move the funds back to the original wallet
    currency = exchange.amount.currency
    chargebacks_account, credit_wallet = Participant.get_chargebacks_account(
        currency)
    LiberapayOrg = Participant.from_username('LiberapayOrg')
    assert LiberapayOrg
    grouped = group_by(disputed_bundles, lambda b: (b.owner, b.withdrawal))
    for (owner, withdrawal), bundles in grouped.items():
        assert owner != chargebacks_account.id
        if owner == original_owner:
            continue
        amount = sum(b.amount for b in bundles)
        if owner is None:
            bundles = None
            withdrawer = db.one(
                "SELECT participant FROM exchanges WHERE id = %s",
                (withdrawal, ))
            payer = LiberapayOrg.id
            create_debt(db, withdrawer, payer, amount, exchange.id)
            create_debt(db, original_owner, withdrawer, amount, exchange.id)
        else:
            payer = owner
            create_debt(db, original_owner, payer, amount, exchange.id)
        transfer(db,
                 payer,
                 original_owner,
                 amount,
                 'chargeback',
                 bundles=bundles)
    # Add a debt for the fee
    create_debt(db, original_owner, LiberapayOrg.id, exchange.fee, exchange.id)
    # Send the funds to the credit wallet
    # We have to do a SettlementTransfer instead of a normal Transfer. The amount
    # can't exceed the original payin amount, so we can't settle the fee debt.
    original_owner = Participant.from_id(original_owner)
    from_wallet = original_owner.get_current_wallet(currency).remote_id
    to_wallet = credit_wallet.remote_id
    t_id = prepare_transfer(
        db,
        original_owner.id,
        chargebacks_account.id,
        exchange.amount,
        'chargeback',
        from_wallet,
        to_wallet,
        prefer_bundles_from=exchange.id,
    )
    tr = SettlementTransfer()
    tr.AuthorId = original_owner.mangopay_user_id
    tr.CreditedUserId = chargebacks_account.mangopay_user_id
    tr.CreditedWalletId = to_wallet
    tr.DebitedFunds = exchange.amount.int()
    tr.DebitedWalletId = from_wallet
    tr.Fees = Money(0, currency)
    tr.RepudiationId = repudiation_id
    tr.Tag = str(t_id)
    return execute_transfer(db, t_id, tr)
Exemplo n.º 44
0
 def test_team_participant_does_show_up_on_explore_teams(self):
     alice = Participant.from_username('alice')
     self.make_participant('A-Team', kind='group').add_member(alice)
     assert 'A-Team' in self.client.GET("/explore/teams/").text