Example #1
0
 def setUp(self):
     Harness.setUp(self)
     self.david = self.make_participant(
         "david",
         is_suspicious=False,
         mangopay_user_id=self.david_id,
         mangopay_wallet_id=self.david_wallet_id,
         email="*****@*****.**",
     )
     self.janet = self.make_participant(
         "janet",
         is_suspicious=False,
         mangopay_user_id=self.janet_id,
         mangopay_wallet_id=self.janet_wallet_id,
         email="*****@*****.**",
     )
     self.janet_route = ExchangeRoute.insert(self.janet, "mango-cc", self.card_id)
     self.homer = self.make_participant(
         "homer",
         is_suspicious=False,
         mangopay_user_id=self.homer_id,
         mangopay_wallet_id=self.homer_wallet_id,
         email="*****@*****.**",
     )
     self.homer_route = ExchangeRoute.insert(self.homer, "mango-ba", self.bank_account.Id)
Example #2
0
 def setUp(self):
     Harness.setUp(self)
     self.david = self.make_participant(
         'david',
         mangopay_user_id=self.david_id,
         mangopay_wallet_id=self.david_wallet_id,
         email='*****@*****.**')
     self.janet = self.make_participant(
         'janet',
         mangopay_user_id=self.janet_id,
         mangopay_wallet_id=self.janet_wallet_id,
         email='*****@*****.**')
     self.janet_route = ExchangeRoute.insert(self.janet,
                                             'mango-cc',
                                             self.card_id,
                                             'chargeable',
                                             currency='EUR')
     self.homer = self.make_participant(
         'homer',
         mangopay_user_id=self.homer_id,
         mangopay_wallet_id=self.homer_wallet_id,
         email='*****@*****.**')
     self.homer_route = ExchangeRoute.insert(self.homer, 'mango-ba',
                                             self.bank_account.Id,
                                             'chargeable')
 def make_exchange(self,
                   route,
                   amount,
                   fee,
                   participant,
                   status='succeeded',
                   error='',
                   vat=0):
     amount = amount if isinstance(amount, Money) else Money(amount, 'EUR')
     fee = fee if isinstance(fee, Money) else Money(fee, amount.currency)
     vat = vat if isinstance(vat, Money) else Money(vat, fee.currency)
     if not isinstance(route, ExchangeRoute):
         network = route
         currency = amount.currency if network == 'mango-cc' else None
         routes = ExchangeRoute.from_network(participant,
                                             network,
                                             currency=currency)
         if routes:
             route = routes[0]
         else:
             from .mangopay import MangopayHarness
             address = MangopayHarness.card_id if network == 'mango-cc' else -participant.id
             route = ExchangeRoute.insert(participant,
                                          network,
                                          address,
                                          'chargeable',
                                          currency=currency)
             assert route
     e_id = record_exchange(self.db, route, amount, fee, vat, participant,
                            'pre').id
     record_exchange_result(self.db, e_id, -e_id, status, error,
                            participant)
     return e_id
Example #4
0
def payin_bank_wire(db, participant, debit_amount):
    """Prepare to receive a bank wire payin.

    The amount should be how much the user intends to send, not how much will
    arrive in the wallet.
    """

    route = ExchangeRoute.from_network(participant, 'mango-bw')
    if not route:
        route = ExchangeRoute.insert(participant, 'mango-bw', 'x')

    amount, fee, vat = skim_amount(debit_amount, FEE_PAYIN_BANK_WIRE)

    e_id = record_exchange(db, route, amount, fee, vat, participant, 'pre')
    payin = PayIn()
    payin.AuthorId = participant.mangopay_user_id
    if not participant.mangopay_wallet_id:
        create_wallet(db, participant)
    payin.CreditedWalletId = participant.mangopay_wallet_id
    payin.ExecutionDetails = PayInExecutionDetailsDirect()
    payin.PaymentDetails = PayInPaymentDetailsBankWire(
        DeclaredDebitedFunds=Money(int(debit_amount * 100), 'EUR'),
        DeclaredFees=Money(int(fee * 100), 'EUR'),
    )
    payin.Tag = str(e_id)
    try:
        test_hook()
        payin = mangoapi.payIns.Create(payin)
    except Exception as e:
        error = repr_exception(e)
        return None, record_exchange_result(db, e_id, 'failed', error, participant)

    e = record_exchange_result(db, e_id, payin.Status.lower(), repr_error(payin), participant)
    return payin, e
Example #5
0
def payin_bank_wire(db, participant, debit_amount):
    """Prepare to receive a bank wire payin.

    The amount should be how much the user intends to send, not how much will
    arrive in the wallet.
    """

    route = ExchangeRoute.from_network(participant, 'mango-bw')
    if not route:
        route = ExchangeRoute.insert(participant, 'mango-bw', 'x')

    amount, fee, vat = skim_bank_wire(debit_amount)

    e_id = record_exchange(db, route, amount, fee, vat, participant, 'pre')
    payin = BankWirePayIn()
    payin.AuthorId = participant.mangopay_user_id
    if not participant.mangopay_wallet_id:
        create_wallet(db, participant)
    payin.CreditedWalletId = participant.mangopay_wallet_id
    payin.DeclaredDebitedFunds = Money(int(debit_amount * 100), 'EUR')
    payin.DeclaredFees = Money(int(fee * 100), 'EUR')
    payin.Tag = str(e_id)
    try:
        test_hook()
        payin.save()
    except Exception as e:
        error = repr_exception(e)
        return None, record_exchange_result(db, e_id, 'failed', error, participant)

    e = record_exchange_result(db, e_id, payin.Status.lower(), repr_error(payin), participant)
    return payin, e
Example #6
0
    def make_participant(self, username, **kw):
        platform = kw.pop('elsewhere', 'github')
        domain = kw.pop('domain', '')
        kw2 = {}
        for key in ('last_bill_result', 'balance', 'mangopay_wallet_id'):
            if key in kw:
                kw2[key] = kw.pop(key)

        kind = kw.setdefault('kind', 'individual')
        if kind not in ('group', 'community'):
            kw.setdefault('password', 'x')
            kw.setdefault('session_token', username)
            i = next(self.seq)
            kw.setdefault('mangopay_user_id', -i)
        kw.setdefault('status', 'active')
        if username:
            kw['username'] = username
        if 'join_time' not in kw:
            kw['join_time'] = utcnow()
        cols, vals = zip(*kw.items())
        cols = ', '.join(cols)
        placeholders = ', '.join(['%s']*len(vals))
        participant = self.db.one("""
            INSERT INTO participants
                        ({0})
                 VALUES ({1})
              RETURNING participants.*::participants
        """.format(cols, placeholders), vals)

        self.db.run("""
            INSERT INTO elsewhere
                        (platform, user_id, user_name, participant, domain)
                 VALUES (%s,%s,%s,%s,%s)
        """, (platform, participant.id, username, participant.id, domain))

        if kind not in ('group', 'community') and participant.mangopay_user_id:
            wallet_id = kw2.get('mangopay_wallet_id', -participant.id)
            zero = ZERO[participant.main_currency]
            self.db.run("""
                INSERT INTO wallets
                            (remote_id, balance, owner, remote_owner_id)
                     VALUES (%s, %s, %s, %s)
            """, (wallet_id, zero, participant.id, participant.mangopay_user_id))

        if 'email' in kw:
            self.db.run("""
                INSERT INTO emails
                            (participant, address, verified, verified_time)
                     VALUES (%s, %s, true, now())
            """, (participant.id, kw['email']))
        if 'last_bill_result' in kw2:
            ExchangeRoute.insert(
                participant, 'mango-cc', '-1', kw2['last_bill_result'],
                currency=participant.main_currency
            )
        if 'balance' in kw2 and kw2['balance'] != 0:
            self.make_exchange('mango-cc', kw2['balance'], 0, participant)

        return participant
Example #7
0
 def test_get_tip_distribution_ignores_bad_cc(self):
     bad_cc = self.make_participant('bad_cc')
     ExchangeRoute.insert(bad_cc, 'mango-cc', '-1', 'failed', currency='EUR')
     self.alice.set_tip_to(self.bob, EUR('1.00'))
     self.make_payin_and_transfer(self.alice_card, self.bob, EUR('25.00'))
     bad_cc.set_tip_to(self.bob, EUR('3.00'))
     expected = ([[EUR('1.00'), 1, EUR('1.00'), EUR('1.00'), 1, Decimal('1')]],
                 1, EUR('1.00'))
     actual = self.bob.get_tip_distribution()
     assert actual == expected
Example #8
0
 def make_exchange(self, route, amount, fee, participant, status='succeeded', error='', vat=0):
     if not isinstance(route, ExchangeRoute):
         network = route
         route = ExchangeRoute.from_network(participant, network)
         if not route:
             from .mangopay import MangopayHarness
             route = ExchangeRoute.insert(participant, network, MangopayHarness.card_id)
             assert route
     e_id = record_exchange(self.db, route, amount, fee, vat, participant, 'pre')
     record_exchange_result(self.db, e_id, status, error, participant)
     return e_id
Example #9
0
 def make_exchange(self, route, amount, fee, participant, status='succeeded', error='', vat=0):
     if not isinstance(route, ExchangeRoute):
         network = route
         route = ExchangeRoute.from_network(participant, network)
         if not route:
             from .mangopay import MangopayHarness
             route = ExchangeRoute.insert(participant, network, MangopayHarness.card_id)
             assert route
     e_id = record_exchange(self.db, route, amount, fee, vat, participant, 'pre')
     record_exchange_result(self.db, e_id, status, error, participant)
     return e_id
Example #10
0
def payout(db, participant, amount):
    if participant.is_suspicious:
        raise UserIsSuspicious

    route = ExchangeRoute.from_network(participant, 'mango-ba')
    assert route
    ba = mangoapi.users.GetBankAccount(participant.mangopay_user_id,
                                       route.address)

    # Do final calculations
    credit_amount, fee = skim_credit(amount, ba)
    if credit_amount <= 0 or fee / credit_amount > 0.1:
        raise TransactionFeeTooHigh

    # Try to dance with MangoPay
    e_id = record_exchange(db, route, -credit_amount, fee, participant, 'pre')
    payout = PayOut()
    payout.AuthorId = participant.mangopay_user_id
    payout.DebitedFunds = Money(int(credit_amount * 100), 'EUR')
    payout.DebitedWalletId = participant.mangopay_wallet_id
    payout.Fees = Money(int(fee * 100), 'EUR')
    payout.MeanOfPaymentDetails = PayOutPaymentDetailsBankWire(
        BankAccountId=route.address,
        BankWireRef=str(e_id),
    )
    payout.Tag = str(e_id)
    try:
        test_hook()
        mangoapi.payOuts.Create(payout)
        return record_exchange_result(db, e_id, 'created', None, participant)
    except Exception as e:
        error = repr_exception(e)
        return record_exchange_result(db, e_id, 'failed', error, participant)
Example #11
0
    def test_direct_debit_creation(self, url):
        path = b'/homer/wallet/payin/direct-debit'
        data = {'amount': '100.00'}

        url.return_value = b'https://liberapay.com' + path

        r = self.client.PxST(path, data, auth_as=self.homer)
        assert r.code == 403  # rejected because homer has no donations set up

        self.homer.set_tip_to(self.david, EUR('10.00'))
        r = self.client.GET(path, auth_as=self.homer)
        assert b'FRxxxxxxxxxxxxxxxxxxxxx2606' in r.body, r.text

        r = self.client.POST(path, data, auth_as=self.homer, raise_immediately=False)
        assert r.code == 200, r.text
        assert ';url=https://api.sandbox.mangopay.com/' in r.text

        exchange = self.db.one("SELECT * FROM exchanges")
        assert exchange.status == 'pre-mandate'
        route = ExchangeRoute.from_id(exchange.route)

        path += ('/%s?MandateId=%s' % (exchange.id, route.mandate)).encode('ascii')
        r = self.client.GET(path, auth_as=self.homer)
        assert r.code == 200

        exchange = self.db.one("SELECT * FROM exchanges")
        assert exchange.status == 'failed'
        assert exchange.note == '001833: The Status of this Mandate does not allow for payments'
Example #12
0
 def setUp(self):
     Harness.setUp(self)
     self.david = self.make_participant(
         'david', mangopay_user_id=self.david_id,
         mangopay_wallet_id=self.david_wallet_id, email='*****@*****.**'
     )
     self.janet = self.make_participant(
         'janet', mangopay_user_id=self.janet_id,
         mangopay_wallet_id=self.janet_wallet_id, email='*****@*****.**'
     )
     self.janet_route = ExchangeRoute.insert(self.janet, 'mango-cc', self.card_id)
     self.homer = self.make_participant(
         'homer', mangopay_user_id=self.homer_id,
         mangopay_wallet_id=self.homer_wallet_id, email='*****@*****.**'
     )
     self.homer_route = ExchangeRoute.insert(self.homer, 'mango-ba', self.bank_account.Id)
Example #13
0
 def test_payout_amount_under_minimum(self, gba):
     usd_user = self.make_participant('usd_user', main_currency='USD')
     route = ExchangeRoute.insert(usd_user, 'mango-ba', 'fake ID', 'chargeable')
     self.make_exchange('mango-cc', USD(8), 0, usd_user)
     gba.return_value = self.bank_account_outside_sepa
     with self.assertRaises(FeeExceedsAmount):
         payout(self.db, route, USD('0.10'))
Example #14
0
def payin_bank_wire(db, participant, debit_amount):
    """Prepare to receive a bank wire payin.

    The amount should be how much the user intends to send, not how much will
    arrive in the wallet.
    """

    route = ExchangeRoute.upsert_bankwire_route(participant)

    if not isinstance(debit_amount, Money):
        debit_amount = Money(debit_amount, 'EUR')
    amount, fee, vat = skim_bank_wire(debit_amount)

    wallet = participant.get_current_wallet(amount.currency, create=True)
    e_id = record_exchange(db, route, amount, fee, vat, participant, 'pre').id
    payin = BankWirePayIn()
    payin.AuthorId = participant.mangopay_user_id
    payin.CreditedWalletId = wallet.remote_id
    payin.DeclaredDebitedFunds = debit_amount.int()
    payin.DeclaredFees = fee.int()
    payin.Tag = str(e_id)
    try:
        test_hook()
        payin.save()
    except Exception as e:
        error = repr_exception(e)
        return None, record_exchange_result(db, e_id, '', 'failed', error, participant)

    e = record_exchange_result(
        db, e_id, payin.Id, payin.Status.lower(), repr_error(payin), participant
    )
    return payin, e
Example #15
0
def payin_bank_wire(db, participant, debit_amount):
    """Prepare to receive a bank wire payin.

    The amount should be how much the user intends to send, not how much will
    arrive in the wallet.
    """

    route = ExchangeRoute.upsert_generic_route(participant, 'mango-bw')

    if not isinstance(debit_amount, Money):
        debit_amount = Money(debit_amount, 'EUR')
    amount, fee, vat = skim_bank_wire(debit_amount)

    wallet = participant.get_current_wallet(amount.currency, create=True)
    e_id = record_exchange(db, route, amount, fee, vat, participant, 'pre').id
    payin = BankWirePayIn()
    payin.AuthorId = participant.mangopay_user_id
    payin.CreditedWalletId = wallet.remote_id
    payin.DeclaredDebitedFunds = Money_to_cents(debit_amount)
    payin.DeclaredFees = Money_to_cents(fee)
    payin.Tag = str(e_id)
    try:
        test_hook()
        payin.save()
    except Exception as e:
        error = repr_exception(e)
        return None, record_exchange_result(db, e_id, '', 'failed', error, participant)

    e = record_exchange_result(
        db, e_id, payin.Id, payin.Status.lower(), repr_error(payin), participant
    )
    return payin, e
Example #16
0
 def _test_payin_bank_wire_callback_amount_mismatch(self, Get, fee):
     homer = self.homer
     route = ExchangeRoute.insert(homer, 'mango-bw', 'x')
     e_id = record_exchange(self.db, route, 11, 0, 0, homer, 'pre')
     assert homer.balance == 0
     homer.close(None)
     assert homer.status == 'closed'
     qs = "EventType=PAYIN_NORMAL_SUCCEEDED&RessourceId=123456790"
     payin = BankWirePayIn()
     payin.Status = 'SUCCEEDED'
     payin.ResultCode = '000000'
     payin.ResultMessage = None
     payin.AuthorId = homer.mangopay_user_id
     payin.PaymentType = 'BANK_WIRE'
     payin.DeclaredDebitedFunds = Money(4500, 'EUR')
     payin.DeclaredFees = Money(100, 'EUR')
     payin.DebitedFunds = Money(302, 'EUR')
     payin.Fees = Money(fee, 'EUR')
     payin.CreditedFunds = Money(302 - fee, 'EUR')
     payin.Tag = str(e_id)
     Get.return_value = payin
     r = self.callback(qs)
     assert r.code == 200, r.text
     e = self.db.one("SELECT * FROM exchanges WHERE id = %s", (e_id, ))
     assert e.amount == D(payin.CreditedFunds.Amount) / D(100)
     assert e.fee == D(fee) / D(100)
     assert e.vat == D('0.01')
     assert e.status == 'succeeded'
     homer = homer.refetch()
     assert homer.balance == e.amount
     assert homer.status == 'active'
     emails = self.get_emails()
     assert len(emails) == 1
     assert emails[0]['to'][0] == 'homer <%s>' % homer.email
     assert 'succ' in emails[0]['subject']
Example #17
0
 def attach_stripe_payment_method(self,
                                  participant,
                                  stripe_pm_id,
                                  one_off=False):
     pm = stripe.PaymentMethod.retrieve(stripe_pm_id)
     return ExchangeRoute.attach_stripe_payment_method(
         participant, pm, one_off)
Example #18
0
    def test_takes_paid_in_advance(self):
        team = self.make_participant(
            'team', kind='group', accepted_currencies='EUR,USD'
        )
        alice = self.make_participant('alice', main_currency='EUR',
                                      accepted_currencies='EUR,USD')
        team.set_take_for(alice, EUR('1.00'), team)
        bob = self.make_participant('bob', main_currency='USD',
                                    accepted_currencies='EUR,USD')
        team.set_take_for(bob, EUR('1.00'), team)

        stripe_account_alice = self.add_payment_account(alice, 'stripe', default_currency='EUR')
        self.add_payment_account(bob, 'stripe', country='US', default_currency='USD')

        carl = self.make_participant('carl')
        carl.set_tip_to(team, EUR('10'))

        carl_card = ExchangeRoute.insert(
            carl, 'stripe-card', 'x', 'chargeable', remote_user_id='x'
        )
        payin, pt = self.make_payin_and_transfer(carl_card, team, EUR('10'))
        assert pt.destination == stripe_account_alice.pk

        Payday.start().run()

        transfers = self.db.all("SELECT * FROM transfers ORDER BY id")
        assert len(transfers) == 1
        assert transfers[0].virtual is True
        assert transfers[0].tipper == carl.id
        assert transfers[0].tippee == alice.id
        assert transfers[0].amount == EUR('1')
Example #19
0
 def test_payout_amount_under_minimum(self, gba):
     usd_user = self.make_participant('usd_user', main_currency='USD')
     route = ExchangeRoute.insert(usd_user, 'mango-ba', 'fake ID')
     self.make_exchange('mango-cc', USD(8), 0, usd_user)
     gba.return_value = self.bank_account_outside_sepa
     with self.assertRaises(FeeExceedsAmount):
         payout(self.db, route, USD('0.10'))
Example #20
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
Example #21
0
    def test_direct_debit_creation(self, url):
        path = b'/homer/wallet/payin/direct-debit'
        data = {'amount': '100.00'}

        url.return_value = b'https://liberapay.com' + path

        r = self.client.PxST(path, data, auth_as=self.homer)
        assert r.code == 403  # rejected because homer has no donations set up

        self.homer.set_tip_to(self.david, EUR('10.00'))
        r = self.client.GET(path, auth_as=self.homer)
        assert b'FRxxxxxxxxxxxxxxxxxxxxx2606' in r.body, r.text

        r = self.client.POST(path,
                             data,
                             auth_as=self.homer,
                             raise_immediately=False)
        assert r.code == 200, r.text
        assert ';url=https://api.sandbox.mangopay.com/' in r.text

        exchange = self.db.one("SELECT * FROM exchanges")
        assert exchange.status == 'pre-mandate'
        route = ExchangeRoute.from_id(self.homer, exchange.route)

        path += ('/%s?MandateId=%s' %
                 (exchange.id, route.mandate)).encode('ascii')
        r = self.client.GET(path, auth_as=self.homer)
        assert r.code == 200

        exchange = self.db.one("SELECT * FROM exchanges")
        assert exchange.status == 'failed'
        assert exchange.note == '001833: The Status of this Mandate does not allow for payments'
Example #22
0
    def test_takes_paid_in_advance(self):
        team = self.make_participant(
            'team', kind='group', accepted_currencies='EUR,USD'
        )
        alice = self.make_participant('alice', main_currency='EUR',
                                      accepted_currencies='EUR,USD')
        team.set_take_for(alice, EUR('1.00'), team)
        bob = self.make_participant('bob', main_currency='USD',
                                    accepted_currencies='EUR,USD')
        team.set_take_for(bob, EUR('1.00'), team)

        stripe_account_alice = self.add_payment_account(alice, 'stripe', default_currency='EUR')
        self.add_payment_account(bob, 'stripe', default_currency='USD')

        carl = self.make_participant('carl')
        carl.set_tip_to(team, EUR('10'))

        carl_card = ExchangeRoute.insert(
            carl, 'stripe-card', 'x', 'chargeable', remote_user_id='x'
        )
        payin, pt = self.make_payin_and_transfer(carl_card, team, EUR('10'))
        assert pt.destination == stripe_account_alice.pk

        Payday.start().run()

        transfers = self.db.all("SELECT * FROM transfers ORDER BY id")
        assert len(transfers) == 1
        assert transfers[0].virtual is True
        assert transfers[0].tipper == carl.id
        assert transfers[0].tippee == alice.id
        assert transfers[0].amount == EUR('1')
Example #23
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
Example #24
0
def payout(db, participant, amount):
    if participant.is_suspicious:
        raise UserIsSuspicious

    route = ExchangeRoute.from_network(participant, 'mango-ba')
    assert route
    ba = mangoapi.users.GetBankAccount(participant.mangopay_user_id, route.address)

    # Do final calculations
    credit_amount, fee = skim_credit(amount, ba)
    if credit_amount <= 0 or fee / credit_amount > 0.1:
        raise TransactionFeeTooHigh

    # Try to dance with MangoPay
    e_id = record_exchange(db, route, -credit_amount, fee, participant, 'pre')
    payout = PayOut()
    payout.AuthorId = participant.mangopay_user_id
    payout.DebitedFunds = Money(int(credit_amount * 100), 'EUR')
    payout.DebitedWalletId = participant.mangopay_wallet_id
    payout.Fees = Money(int(fee * 100), 'EUR')
    payout.MeanOfPaymentDetails = PayOutPaymentDetailsBankWire(
        BankAccountId=route.address,
        BankWireRef=str(e_id),
    )
    payout.Tag = str(e_id)
    try:
        test_hook()
        mangoapi.payOuts.Create(payout)
        return record_exchange_result(db, e_id, 'created', None, participant)
    except Exception as e:
        error = repr_exception(e)
        return record_exchange_result(db, e_id, 'failed', error, participant)
Example #25
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
Example #26
0
 def test_associate_nonexistent_card(self, Card_get):
     Card_get.side_effect = Card.DoesNotExist
     r = self.client.PxST('/homer/routes/credit-card.json',
                          data={'CardId': '-1'}, auth_as=self.homer)
     assert r.code == 400
     cards = ExchangeRoute.from_network(self.homer, 'mango-cc')
     assert not cards
Example #27
0
 def test_payin_bank_wire_callback(self, Get):
     homer = self.homer
     route = ExchangeRoute.insert(homer, 'mango-bw', 'x')
     for status in ('failed', 'succeeded'):
         status_up = status.upper()
         error = 'FOO' if status == 'failed' else None
         e_id = record_exchange(self.db, route, 11, 0, 0, homer, 'pre')
         assert homer.balance == 0
         homer.close(None)
         assert homer.status == 'closed'
         qs = "EventType=PAYIN_NORMAL_"+status_up+"&RessourceId=123456790"
         payin = PayIn()
         payin.Status = status_up
         payin.ResultCode = '000001' if error else '000000'
         payin.ResultMessage = error
         payin.AuthorId = homer.mangopay_user_id
         payin.PaymentType = 'BANK_WIRE'
         payin.Tag = str(e_id)
         Get.return_value = payin
         r = self.callback(qs)
         assert r.code == 200, r.text
         homer = homer.refetch()
         if status == 'succeeded':
             assert homer.balance == 11
             assert homer.status == 'active'
         else:
             assert homer.balance == 0
             assert homer.status == 'closed'
         emails = self.get_emails()
         assert len(emails) == 1
         assert emails[0]['to'][0] == 'homer <%s>' % homer.email
         assert status[:4] in emails[0]['subject']
         homer.update_status('active')  # reset for next loop run
    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
    def test_identity_form(self):
        janeway = self.make_participant(
            'janeway',
            email='*****@*****.**',
            mangopay_user_id=None,
        )
        assert janeway.mangopay_user_id is None

        # Create a mangopay natural user
        data = dict(user_data, terms='agree')
        kw = dict(auth_as=janeway, raise_immediately=False, xhr=True)
        r = self.client.POST('/janeway/identity', data, **kw)
        assert r.code == 200, r.text
        janeway = janeway.refetch()
        assert janeway.mangopay_user_id

        # Test the rendering of the identity page
        r = self.client.GET('/janeway/identity.html', auth_as=janeway)
        assert r.code == 200, r.text
        assert user_data['FirstName'] in r.text

        # Edit the natural user
        data2 = dict(data,
                     FirstName='Kathryn',
                     Nationality='US',
                     Birthday='1970-01-01')
        r = self.client.POST('/janeway/identity', data2, **kw)
        assert r.code == 200, r.text
        janeway2 = janeway.refetch()
        assert janeway2.mangopay_user_id == janeway.mangopay_user_id

        # Add some money for the next test
        create_wallet(self.db, janeway, 'EUR')
        cr = create_card(janeway.mangopay_user_id)
        route = ExchangeRoute.insert(janeway,
                                     'mango-cc',
                                     cr.CardId,
                                     'chargeable',
                                     currency='EUR')
        charge(self.db, route, EUR('20.00'), 'http://127.0.0.1/')

        # Switch to a legal user
        data = dict(data2)
        data['organization'] = 'yes'
        data['LegalPersonType'] = 'BUSINESS'
        data['Name'] = 'Starfleet'
        data['confirmed'] = 'yes'
        r = self.client.POST('/janeway/identity', data, **kw)
        assert r.code == 200, r.text
        janeway = janeway.refetch()
        assert janeway.mangopay_user_id != janeway2.mangopay_user_id
        assert janeway.kind == 'organization'
        self.db.self_check()

        # Edit the legal user
        data2 = dict(data, LegalPersonType='ORGANIZATION')
        r = self.client.POST('/janeway/identity', data2, **kw)
        assert r.code == 200, r.text
        janeway2 = janeway.refetch()
        assert janeway2.mangopay_user_id == janeway.mangopay_user_id
Example #30
0
def fake_exchange(db, participant, amount, fee, vat, timestamp):
    routes = ExchangeRoute.from_network(participant, 'mango-cc', currency='EUR')
    if routes:
        route = routes[0]
    else:
        route = _fake_thing(
            db,
            "exchange_routes",
            participant=participant.id,
            network='mango-cc',
            address='-1',
            status='chargeable',
            one_off=False,
            remote_user_id=participant.mangopay_user_id,
            currency='EUR',
        )
    e = _fake_thing(
        db,
        "exchanges",
        timestamp=timestamp,
        participant=participant.id,
        amount=amount,
        fee=fee,
        vat=vat,
        status='pre',
        route=route.id,
        wallet_id='-%i' % participant.id,
    )
    record_exchange_result(db, e.id, -e.id, 'succeeded', '', participant)
    return e
Example #31
0
def fake_exchange(db, participant, amount, fee, vat, timestamp):
    route = ExchangeRoute.from_network(participant, 'mango-cc')
    if not route:
        route = _fake_thing(
            db,
            "exchange_routes",
            participant=participant.id,
            network='mango-cc',
            address='-1',
            error='',
            one_off=False,
        )
    e = _fake_thing(
        db,
        "exchanges",
        timestamp=timestamp,
        participant=participant.id,
        amount=amount,
        fee=fee,
        vat=vat,
        status='pre',
        route=route.id,
    )
    record_exchange_result(db, e.id, 'succeeded', '', participant)
    return e
Example #32
0
 def test_associate_nonexistent_card(self, Card_get):
     Card_get.side_effect = Card.DoesNotExist
     r = self.client.PxST('/homer/routes/credit-card.json',
                          data={'CardId': '-1'}, auth_as=self.homer)
     assert r.code == 400
     cards = ExchangeRoute.from_network(self.homer, 'mango-cc')
     assert not cards
Example #33
0
def fake_exchange(db, participant, amount, fee, vat, timestamp):
    routes = ExchangeRoute.from_network(participant, 'mango-cc')
    if routes:
        route = routes[0]
    else:
        route = _fake_thing(
            db,
            "exchange_routes",
            participant=participant.id,
            network='mango-cc',
            address='-1',
            error='',
            one_off=False,
            remote_user_id=participant.mangopay_user_id,
        )
    e = _fake_thing(
        db,
        "exchanges",
        timestamp=timestamp,
        participant=participant.id,
        amount=amount,
        fee=fee,
        vat=vat,
        status='pre',
        route=route.id,
        wallet_id=participant.mangopay_wallet_id,
    )
    record_exchange_result(db, e.id, -e.id, 'succeeded', '', participant)
    return e
Example #34
0
    def test_negative_paid_in_advance(self):
        team = self.make_participant('team', kind='group')
        alice = self.make_participant('alice')
        team.set_take_for(alice, EUR('1.00'), team)

        stripe_account_alice = self.add_payment_account(alice, 'stripe')

        donor = self.make_participant('donor')
        donor.set_tip_to(team, EUR('5'))

        donor_card = ExchangeRoute.insert(donor,
                                          'stripe-card',
                                          'x',
                                          'chargeable',
                                          remote_user_id='x')
        payin, pt = self.make_payin_and_transfer(donor_card, team, EUR('10'),
                                                 'stripe')
        assert pt.destination == stripe_account_alice.pk

        self.db.run("UPDATE takes SET paid_in_advance = -paid_in_advance")

        Payday.start().run()

        transfers = self.db.all("SELECT * FROM transfers ORDER BY id")
        assert len(transfers) == 0
Example #35
0
 def make_exchange(self, route, amount, fee, participant, status='succeeded', error='', vat=0):
     amount = amount if isinstance(amount, Money) else Money(amount, 'EUR')
     fee = fee if isinstance(fee, Money) else Money(fee, amount.currency)
     vat = vat if isinstance(vat, Money) else Money(vat, fee.currency)
     if not isinstance(route, ExchangeRoute):
         network = route
         currency = amount.currency if network == 'mango-cc' else None
         routes = ExchangeRoute.from_network(participant, network, currency=currency)
         if routes:
             route = routes[0]
         else:
             from .mangopay import MangopayHarness
             address = MangopayHarness.card_id if network == 'mango-cc' else -participant.id
             route = ExchangeRoute.insert(participant, network, address, currency=currency)
             assert route
     e_id = record_exchange(self.db, route, amount, fee, vat, participant, 'pre').id
     record_exchange_result(self.db, e_id, -e_id, status, error, participant)
     return e_id
Example #36
0
 def test_charge_invalidated_card(self):
     bob = self.make_participant('bob')
     route = ExchangeRoute.insert(bob,
                                  'mango-cc',
                                  '-1',
                                  'canceled',
                                  currency='EUR')
     with self.assertRaises(AssertionError):
         charge(self.db, route, EUR('10.00'), 'http://localhost/')
Example #37
0
    def make_participant(self, username, **kw):
        platform = kw.pop('elsewhere', 'github')
        kw2 = {}
        for key in ('last_bill_result', 'balance'):
            if key in kw:
                kw2[key] = kw.pop(key)

        kind = kw.setdefault('kind', 'individual')
        if kind not in ('group', 'community'):
            kw.setdefault('password', 'x')
            kw.setdefault('session_token', username)
            i = next(self.seq)
            kw.setdefault('mangopay_user_id', -i)
            kw.setdefault('mangopay_wallet_id', -i)
        kw.setdefault('status', 'active')
        if not 'join_time' in kw:
            kw['join_time'] = utcnow()
        cols, vals = zip(*kw.items())
        cols = ', '.join(cols)
        placeholders = ', '.join(['%s'] * len(vals))
        participant = self.db.one(
            """
            INSERT INTO participants
                        (username, {0})
                 VALUES (%s, {1})
              RETURNING participants.*::participants
        """.format(cols, placeholders), (username, ) + vals)

        self.db.run(
            """
            INSERT INTO elsewhere
                        (platform, user_id, user_name, participant)
                 VALUES (%s,%s,%s,%s)
        """, (platform, participant.id, username, participant.id))

        if 'last_bill_result' in kw2:
            ExchangeRoute.insert(participant, 'mango-cc', '-1',
                                 kw2['last_bill_result'])
        if 'balance' in kw2 and kw2['balance'] != 0:
            self.make_exchange('mango-cc', kw2['balance'], 0, participant)

        return participant
Example #38
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.error == 'invalidated'
        assert homer.mangopay_user_id

        # Check that update_error doesn't update an invalidated route
        route.update_error('some error')
        assert route.error == 'invalidated'
Example #39
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.error == homer.get_bank_account_error() == "invalidated"
        assert homer.mangopay_user_id

        # Check that update_error doesn't update an invalidated route
        route.update_error("some error")
        assert route.error == homer.get_bank_account_error() == "invalidated"
    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.error == 'invalidated'
        assert homer.mangopay_user_id

        # Check that update_error doesn't update an invalidated route
        route.update_error('some error')
        assert route.error == 'invalidated'
Example #41
0
    def make_participant(self, username, **kw):
        platform = kw.pop('elsewhere', 'github')
        kw2 = {}
        for key in ('last_bill_result', 'balance'):
            if key in kw:
                kw2[key] = kw.pop(key)

        kind = kw.setdefault('kind', 'individual')
        if kind != 'group':
            kw.setdefault('password', 'x')
            kw.setdefault('session_token', username)
        kw.setdefault('status', 'active')
        if not 'join_time' in kw:
            kw['join_time'] = utcnow()
        i = next(self.seq)
        kw.setdefault('mangopay_user_id', -i)
        kw.setdefault('mangopay_wallet_id', -i)
        cols, vals = zip(*kw.items())
        cols = ', '.join(cols)
        placeholders = ', '.join(['%s']*len(vals))
        participant = self.db.one("""
            INSERT INTO participants
                        (username, {0})
                 VALUES (%s, {1})
              RETURNING participants.*::participants
        """.format(cols, placeholders), (username,)+vals)

        self.db.run("""
            INSERT INTO elsewhere
                        (platform, user_id, user_name, participant)
                 VALUES (%s,%s,%s,%s)
        """, (platform, participant.id, username, participant.id))

        if 'last_bill_result' in kw2:
            ExchangeRoute.insert(participant, 'mango-cc', '-1', kw2['last_bill_result'])
        if 'balance' in kw2:
            self.make_exchange('mango-cc', kw2['balance'], 0, participant)

        return participant
Example #42
0
    def test_identity_form(self):
        janeway = self.make_participant(
            'janeway', email='*****@*****.**', mangopay_user_id=None,
        )
        assert janeway.mangopay_user_id is None

        # Create a mangopay natural user
        data = dict(user_data, terms='agree')
        kw = dict(auth_as=janeway, raise_immediately=False, xhr=True)
        r = self.client.POST('/janeway/identity-v1', data, **kw)
        assert r.code == 200, r.text
        janeway = janeway.refetch()
        assert janeway.mangopay_user_id

        # Test the rendering of the identity page
        r = self.client.GET('/janeway/identity-v1.html', auth_as=janeway)
        assert r.code == 200, r.text
        assert user_data['FirstName'] in r.text

        # Edit the natural user
        data2 = dict(data, FirstName='Kathryn', Nationality='US', Birthday='1970-01-01')
        r = self.client.POST('/janeway/identity-v1', data2, **kw)
        assert r.code == 200, r.text
        janeway2 = janeway.refetch()
        assert janeway2.mangopay_user_id == janeway.mangopay_user_id

        # Add some money for the next test
        create_wallet(self.db, janeway, 'EUR')
        cr = create_card(janeway.mangopay_user_id)
        route = ExchangeRoute.insert(janeway, 'mango-cc', cr.CardId, 'chargeable', currency='EUR')
        charge(self.db, route, EUR('20.00'), 'http://127.0.0.1/')

        # Switch to a legal user
        data = dict(data2)
        data['organization'] = 'yes'
        data['LegalPersonType'] = 'BUSINESS'
        data['Name'] = 'Starfleet'
        data['confirmed'] = 'yes'
        r = self.client.POST('/janeway/identity-v1', data, **kw)
        assert r.code == 200, r.text
        janeway = janeway.refetch()
        assert janeway.mangopay_user_id != janeway2.mangopay_user_id
        assert janeway.kind == 'organization'
        self.db.self_check()

        # Edit the legal user
        data2 = dict(data, LegalPersonType='ORGANIZATION')
        r = self.client.POST('/janeway/identity-v1', data2, **kw)
        assert r.code == 200, r.text
        janeway2 = janeway.refetch()
        assert janeway2.mangopay_user_id == janeway.mangopay_user_id
Example #43
0
def charge(db, participant, amount, return_url):
    """Charge the participant's credit card.

    Amount should be the nominal amount. We'll compute fees below this function
    and add it to amount to end up with charge_amount.

    """
    typecheck(amount, Decimal)

    if participant.is_suspicious:
        raise UserIsSuspicious

    route = ExchangeRoute.from_network(participant, 'mango-cc')
    assert route

    charge_amount, fee = upcharge(amount)
    amount = charge_amount - fee

    e_id = record_exchange(db, route, amount, fee, participant, 'pre')
    payin = PayIn()
    payin.AuthorId = participant.mangopay_user_id
    if not participant.mangopay_wallet_id:
        create_wallet(db, participant)
    payin.CreditedWalletId = participant.mangopay_wallet_id
    payin.DebitedFunds = Money(int(charge_amount * 100), 'EUR')
    payin.ExecutionDetails = PayInExecutionDetailsDirect(
        CardId=route.address,
        SecureModeReturnURL=return_url,
    )
    payin.Fees = Money(int(fee * 100), 'EUR')
    payin.PaymentDetails = PayInPaymentDetailsCard(
        CardType='CB_VISA_MASTERCARD')
    payin.Tag = str(e_id)
    try:
        test_hook()
        payin = mangoapi.payIns.Create(payin)
    except Exception as e:
        error = repr_exception(e)
        return record_exchange_result(db, e_id, 'failed', error, participant)

    if payin.ExecutionDetails.SecureModeRedirectURL:
        raise Response(
            302,
            headers={'Location': payin.ExecutionDetails.SecureModeRedirectURL})

    return record_exchange_result(db, e_id, 'succeeded', None, participant)
Example #44
0
def fake_exchange(db, participant, amount, fee, timestamp):
    route = ExchangeRoute.from_network(participant, "mango-cc")
    if not route:
        route = _fake_thing(
            db, "exchange_routes", participant=participant.id, network="mango-cc", address="-1", error="", one_off=False
        )
    e = _fake_thing(
        db,
        "exchanges",
        timestamp=timestamp,
        participant=participant.id,
        amount=amount,
        fee=fee,
        status="pre",
        route=route.id,
    )
    record_exchange_result(db, e.id, "succeeded", "", participant)
    return e
Example #45
0
 def test_user_page_shows_pledges(self, get_user_info):
     alice = self.make_elsewhere('github', 1, 'alice').participant
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     # bob needs to be an active donor for his pledge to be counted
     bob.set_tip_to(carl, EUR('1.00'))
     bob_card = ExchangeRoute.insert(
         bob, 'stripe-card', 'x', 'chargeable', remote_user_id='x'
     )
     self.add_payment_account(carl, 'stripe')
     self.make_payin_and_transfer(bob_card, carl, EUR('1.00'))
     Payday.start().run()
     # okay, let's check
     amount = EUR('14.97')
     bob.set_tip_to(alice, amount)
     assert alice.receiving == amount
     r = self.client.GET('/on/github/alice/')
     assert str(amount.amount) in r.text, r.text
Example #46
0
 def test_user_page_shows_pledges(self, get_user_info):
     alice = self.make_elsewhere('github', 1, 'alice').participant
     bob = self.make_participant('bob')
     carl = self.make_participant('carl')
     # bob needs to be an active donor for his pledge to be counted
     bob.set_tip_to(carl, EUR('1.00'))
     bob_card = ExchangeRoute.insert(
         bob, 'stripe-card', 'x', 'chargeable', remote_user_id='x'
     )
     self.add_payment_account(carl, 'stripe')
     self.make_payin_and_transfer(bob_card, carl, EUR('1.00'))
     Payday.start().run()
     # okay, let's check
     amount = EUR('14.97')
     bob.set_tip_to(alice, amount)
     assert alice.receiving == amount
     r = self.client.GET('/on/github/alice/')
     assert str(amount.amount) in r.text, r.text
Example #47
0
def record_payout_refund(db, payout_refund):
    orig_payout = BankWirePayOut.get(payout_refund.InitialTransactionId)
    e_origin = db.one("SELECT * FROM exchanges WHERE id = %s" % (orig_payout.Tag,))
    e_refund_id = db.one("SELECT id FROM exchanges WHERE refund_ref = %s", (e_origin.id,))
    if e_refund_id:
        # Already recorded
        return e_refund_id
    amount, fee, vat = -e_origin.amount, -e_origin.fee, -e_origin.vat
    assert payout_refund.DebitedFunds == Money(int(amount * 100), 'EUR')
    assert payout_refund.Fees == Money(int(fee * 100), 'EUR')
    route = ExchangeRoute.from_id(e_origin.route)
    participant = Participant.from_id(e_origin.participant)
    return db.one("""
        INSERT INTO exchanges
               (amount, fee, vat, participant, status, route, note, refund_ref)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
     RETURNING id
    """, (amount, fee, vat, participant.id, 'created', route.id, None, e_origin.id))
Example #48
0
 def test_payin_bank_wire_callback(self, Get):
     homer = self.homer
     route = ExchangeRoute.insert(homer, 'mango-bw', 'x', 'chargeable')
     cases = (
         ('failed', '000001', 'FOO'),
         ('failed', '101109', 'The payment period has expired'),
         ('succeeded', '000000', None),
     )
     for status, result_code, error in cases:
         status_up = status.upper()
         e_id = record_exchange(self.db, route, EUR(11), EUR(0), EUR(0),
                                homer, 'pre').id
         assert homer.balance == 0
         homer.close(None)
         assert homer.status == 'closed'
         qs = "EventType=PAYIN_NORMAL_" + status_up + "&RessourceId=123456790"
         payin = BankWirePayIn(Id=-1)
         payin.Status = status_up
         payin.ResultCode = result_code
         payin.ResultMessage = error
         payin.AuthorId = homer.mangopay_user_id
         payin.PaymentType = 'BANK_WIRE'
         payin.DeclaredDebitedFunds = Money(1100, 'EUR')
         payin.DeclaredFees = Money(0, 'EUR')
         payin.CreditedFunds = Money(0, 'XXX') if error else Money(
             1100, 'EUR')
         payin.Tag = str(e_id)
         Get.return_value = payin
         r = self.callback(qs)
         assert r.code == 200, r.text
         homer = homer.refetch()
         if status == 'succeeded':
             assert homer.balance == 11
             assert homer.status == 'active'
         else:
             assert homer.balance == 0
             assert homer.status == 'closed'
         emails = self.get_emails()
         assert len(emails) == 1
         assert emails[0]['to'][0] == 'homer <%s>' % homer.email
         expected = 'expired' if result_code == '101109' else status[:4]
         assert expected in emails[0]['subject']
         self.db.self_check()
         homer.update_status('active')  # reset for next loop run
Example #49
0
def payout(db, participant, amount, ignore_high_fee=False):
    assert amount > 0

    if participant.is_suspended:
        raise AccountSuspended()

    payday = db.one("SELECT * FROM paydays WHERE ts_start > ts_end")
    if payday:
        raise PaydayIsRunning

    route = ExchangeRoute.from_network(participant, 'mango-ba')
    assert route
    ba = mangoapi.users.GetBankAccount(participant.mangopay_user_id,
                                       route.address)

    # Do final calculations
    credit_amount, fee, vat = skim_credit(amount, ba)
    if credit_amount <= 0 and fee > 0:
        raise FeeExceedsAmount
    fee_percent = fee / amount
    if fee_percent > FEE_PAYOUT_WARN and not ignore_high_fee:
        raise TransactionFeeTooHigh(fee_percent, fee, amount)

    # Try to dance with MangoPay
    e_id = record_exchange(db, route, -credit_amount, fee, vat, participant,
                           'pre')
    payout = PayOut()
    payout.AuthorId = participant.mangopay_user_id
    payout.DebitedFunds = Money(int(amount * 100), 'EUR')
    payout.DebitedWalletId = participant.mangopay_wallet_id
    payout.Fees = Money(int(fee * 100), 'EUR')
    payout.MeanOfPaymentDetails = PayOutPaymentDetailsBankWire(
        BankAccountId=route.address,
        BankWireRef=str(e_id),
    )
    payout.Tag = str(e_id)
    try:
        test_hook()
        payout = mangoapi.payOuts.Create(payout)
        return record_exchange_result(db, e_id, payout.Status.lower(),
                                      repr_error(payout), participant)
    except Exception as e:
        error = repr_exception(e)
        return record_exchange_result(db, e_id, 'failed', error, participant)
Example #50
0
def record_unexpected_payin(db, payin):
    """Record an unexpected bank wire payin.
    """
    assert payin.PaymentType == 'BANK_WIRE'
    debited_amount = payin.DebitedFunds / Decimal(100)
    paid_fee = payin.Fees / Decimal(100)
    vat = skim_bank_wire(debited_amount)[2]
    wallet_id = payin.CreditedWalletId
    participant = Participant.from_mangopay_user_id(payin.AuthorId)
    current_wallet = participant.get_current_wallet(debited_amount.currency)
    assert current_wallet.remote_id == wallet_id
    route = ExchangeRoute.upsert_bankwire_route(participant)
    amount = debited_amount - paid_fee
    return db.one("""
        INSERT INTO exchanges
               (amount, fee, vat, participant, status, route, note, remote_id, wallet_id)
        VALUES (%s, %s, %s, %s, 'created', %s, NULL, %s, %s)
     RETURNING id
    """, (amount, paid_fee, vat, participant.id, route.id, payin.Id, wallet_id))
Example #51
0
def record_unexpected_payin(db, payin):
    """Record an unexpected bank wire payin.
    """
    assert payin.PaymentType == 'BANK_WIRE'
    debited_amount = payin.DebitedFunds / Decimal(100)
    paid_fee = payin.Fees / Decimal(100)
    vat = skim_bank_wire(debited_amount)[2]
    wallet_id = payin.CreditedWalletId
    participant = Participant.from_mangopay_user_id(payin.AuthorId)
    current_wallet = participant.get_current_wallet(debited_amount.currency)
    assert current_wallet.remote_id == wallet_id
    route = ExchangeRoute.upsert_generic_route(participant, 'mango-bw')
    amount = debited_amount - paid_fee
    return db.one("""
        INSERT INTO exchanges
               (amount, fee, vat, participant, status, route, note, remote_id, wallet_id)
        VALUES (%s, %s, %s, %s, 'created', %s, NULL, %s, %s)
     RETURNING id
    """, (amount, paid_fee, vat, participant.id, route.id, payin.Id, wallet_id))
Example #52
0
def charge(db, participant, amount, return_url):
    """Charge the participant's credit card.

    Amount should be the nominal amount. We'll compute fees below this function
    and add it to amount to end up with charge_amount.

    """
    typecheck(amount, Decimal)

    if participant.is_suspicious:
        raise UserIsSuspicious

    route = ExchangeRoute.from_network(participant, 'mango-cc')
    assert route

    charge_amount, fee = upcharge(amount)
    amount = charge_amount - fee

    e_id = record_exchange(db, route, amount, fee, participant, 'pre')
    payin = PayIn()
    payin.AuthorId = participant.mangopay_user_id
    if not participant.mangopay_wallet_id:
        create_wallet(db, participant)
    payin.CreditedWalletId = participant.mangopay_wallet_id
    payin.DebitedFunds = Money(int(charge_amount * 100), 'EUR')
    payin.ExecutionDetails = PayInExecutionDetailsDirect(
        CardId=route.address,
        SecureModeReturnURL=return_url,
    )
    payin.Fees = Money(int(fee * 100), 'EUR')
    payin.PaymentDetails = PayInPaymentDetailsCard(CardType='CB_VISA_MASTERCARD')
    payin.Tag = str(e_id)
    try:
        test_hook()
        payin = mangoapi.payIns.Create(payin)
    except Exception as e:
        error = repr_exception(e)
        return record_exchange_result(db, e_id, 'failed', error, participant)

    if payin.ExecutionDetails.SecureModeRedirectURL:
        raise Response(302, headers={'Location': payin.ExecutionDetails.SecureModeRedirectURL})

    return record_exchange_result(db, e_id, 'succeeded', None, participant)
Example #53
0
 def test_payin_bank_wire_callback(self, Get):
     homer = self.homer
     route = ExchangeRoute.insert(homer, 'mango-bw', 'x')
     cases = (
         ('failed', '000001', 'FOO'),
         ('failed', '101109', 'The payment period has expired'),
         ('succeeded', '000000', None),
     )
     for status, result_code, error in cases:
         status_up = status.upper()
         e_id = record_exchange(self.db, route, EUR(11), EUR(0), EUR(0), homer, 'pre').id
         assert homer.balance == 0
         homer.close(None)
         assert homer.status == 'closed'
         qs = "EventType=PAYIN_NORMAL_"+status_up+"&RessourceId=123456790"
         payin = BankWirePayIn(Id=-1)
         payin.Status = status_up
         payin.ResultCode = result_code
         payin.ResultMessage = error
         payin.AuthorId = homer.mangopay_user_id
         payin.PaymentType = 'BANK_WIRE'
         payin.DeclaredDebitedFunds = Money(1100, 'EUR')
         payin.DeclaredFees = Money(0, 'EUR')
         payin.CreditedFunds = Money(0, 'XXX') if error else Money(1100, 'EUR')
         payin.Tag = str(e_id)
         Get.return_value = payin
         r = self.callback(qs)
         assert r.code == 200, r.text
         homer = homer.refetch()
         if status == 'succeeded':
             assert homer.balance == 11
             assert homer.status == 'active'
         else:
             assert homer.balance == 0
             assert homer.status == 'closed'
         emails = self.get_emails()
         assert len(emails) == 1
         assert emails[0]['to'][0] == 'homer <%s>' % homer.email
         expected = 'expired' if result_code == '101109' else status[:4]
         assert expected in emails[0]['subject']
         self.db.self_check()
         homer.update_status('active')  # reset for next loop run
Example #54
0
def record_payout_refund(db, payout_refund):
    orig_payout = BankWirePayOut.get(payout_refund.InitialTransactionId)
    e_origin = db.one("SELECT * FROM exchanges WHERE id = %s", (orig_payout.Tag,))
    e_refund_id = db.one("SELECT id FROM exchanges WHERE refund_ref = %s", (e_origin.id,))
    if e_refund_id:
        # Already recorded
        return e_refund_id
    amount, fee, vat = -e_origin.amount, -e_origin.fee, -e_origin.vat
    assert payout_refund.DebitedFunds / 100 == amount
    assert payout_refund.Fees / 100 == fee
    route = ExchangeRoute.from_id(e_origin.route)
    participant = Participant.from_id(e_origin.participant)
    remote_id = payout_refund.Id
    wallet_id = e_origin.wallet_id
    return db.one("""
        INSERT INTO exchanges
               (amount, fee, vat, participant, status, route, note, refund_ref, remote_id, wallet_id)
        VALUES (%s, %s, %s, %s, 'created', %s, NULL, %s, %s, %s)
     RETURNING id
    """, (amount, fee, vat, participant.id, route.id, e_origin.id, remote_id, wallet_id))
Example #55
0
def record_payout_refund(db, payout_refund):
    orig_payout = BankWirePayOut.get(payout_refund.InitialTransactionId)
    e_origin = db.one("SELECT * FROM exchanges WHERE id = %s", (orig_payout.Tag,))
    e_refund_id = db.one("SELECT id FROM exchanges WHERE refund_ref = %s", (e_origin.id,))
    if e_refund_id:
        # Already recorded
        return e_refund_id
    amount, fee, vat = -e_origin.amount, -e_origin.fee, -e_origin.vat
    assert payout_refund.DebitedFunds / 100 == amount
    assert payout_refund.Fees / 100 == fee
    participant = Participant.from_id(e_origin.participant)
    route = ExchangeRoute.from_id(participant, e_origin.route)
    remote_id = payout_refund.Id
    wallet_id = e_origin.wallet_id
    return db.one("""
        INSERT INTO exchanges
               (amount, fee, vat, participant, status, route, note, refund_ref, remote_id, wallet_id)
        VALUES (%s, %s, %s, %s, 'created', %s, NULL, %s, %s, %s)
     RETURNING id
    """, (amount, fee, vat, participant.id, route.id, e_origin.id, remote_id, wallet_id))
Example #56
0
    def test_negative_paid_in_advance(self):
        team = self.make_participant('team', kind='group')
        alice = self.make_participant('alice')
        team.set_take_for(alice, EUR('1.00'), team)

        stripe_account_alice = self.add_payment_account(alice, 'stripe')

        donor = self.make_participant('donor')
        donor.set_tip_to(team, EUR('5'))

        donor_card = ExchangeRoute.insert(
            donor, 'stripe-card', 'x', 'chargeable', remote_user_id='x'
        )
        payin, pt = self.make_payin_and_transfer(donor_card, team, EUR('10'))
        assert pt.destination == stripe_account_alice.pk

        self.db.run("UPDATE takes SET paid_in_advance = -paid_in_advance")

        Payday.start().run()

        transfers = self.db.all("SELECT * FROM transfers ORDER BY id")
        assert len(transfers) == 0
Example #57
0
def payout(db, participant, amount, ignore_high_fee=False):
    assert amount > 0

    payday = db.one("SELECT * FROM paydays WHERE ts_start > ts_end")
    if payday:
        raise PaydayIsRunning

    route = ExchangeRoute.from_network(participant, 'mango-ba')
    assert route
    ba = mangoapi.users.GetBankAccount(participant.mangopay_user_id, route.address)

    # Do final calculations
    credit_amount, fee, vat = skim_credit(amount, ba)
    if credit_amount <= 0 and fee > 0:
        raise FeeExceedsAmount
    fee_percent = fee / amount
    if fee_percent > FEE_CREDIT_WARN and not ignore_high_fee:
        raise TransactionFeeTooHigh(fee_percent, fee, amount)

    # Try to dance with MangoPay
    e_id = record_exchange(db, route, -credit_amount, fee, vat, participant, 'pre')
    payout = PayOut()
    payout.AuthorId = participant.mangopay_user_id
    payout.DebitedFunds = Money(int(amount * 100), 'EUR')
    payout.DebitedWalletId = participant.mangopay_wallet_id
    payout.Fees = Money(int(fee * 100), 'EUR')
    payout.MeanOfPaymentDetails = PayOutPaymentDetailsBankWire(
        BankAccountId=route.address,
        BankWireRef=str(e_id),
    )
    payout.Tag = str(e_id)
    try:
        test_hook()
        mangoapi.payOuts.Create(payout)
        return record_exchange_result(db, e_id, 'created', None, participant)
    except Exception as e:
        error = repr_exception(e)
        return record_exchange_result(db, e_id, 'failed', error, participant)
Example #58
0
 def test_payin_bank_wire_callback(self, Get):
     homer = self.homer
     route = ExchangeRoute.insert(homer, 'mango-bw', 'x')
     for status in ('failed', 'succeeded'):
         status_up = status.upper()
         error = 'FOO' if status == 'failed' else None
         e_id = record_exchange(self.db, route, 11, 0, 0, homer, 'pre')
         assert homer.balance == 0
         homer.close(None)
         assert homer.status == 'closed'
         qs = "EventType=PAYIN_NORMAL_" + status_up + "&RessourceId=123456790"
         payin = PayIn()
         payin.Status = status_up
         payin.ResultCode = '000001' if error else '000000'
         payin.ResultMessage = error
         payin.AuthorId = homer.mangopay_user_id
         payin.PaymentType = 'BANK_WIRE'
         pd = payin.PaymentDetails = PayInPaymentDetailsBankWire()
         pd.DeclaredDebitedFunds = Money(1100, 'EUR').__dict__
         pd.DeclaredFees = Money(0, 'EUR').__dict__
         payin.CreditedFunds = Money(1100, 'EUR')
         payin.Tag = str(e_id)
         Get.return_value = payin
         r = self.callback(qs)
         assert r.code == 200, r.text
         homer = homer.refetch()
         if status == 'succeeded':
             assert homer.balance == 11
             assert homer.status == 'active'
         else:
             assert homer.balance == 0
             assert homer.status == 'closed'
         emails = self.get_emails()
         assert len(emails) == 1
         assert emails[0]['to'][0] == 'homer <%s>' % homer.email
         assert status[:4] in emails[0]['subject']
         homer.update_status('active')  # reset for next loop run