def test_payin_pays_in(self, sale, sfs, fch):
        fch.return_value = {}
        team = self.make_team('Gratiteam', is_approved=True)
        self.obama.set_payment_instruction(team, MINIMUM_CHARGE)        # >= MINIMUM_CHARGE

        txn_attrs = {
            'amount': MINIMUM_CHARGE,
            'tax_amount': 0,
            'status': 'authorized',
            'custom_fields': {'participant_id': self.obama.id},
            'credit_card': {'token': self.obama_route.address},
            'id': 'dummy_id'
        }
        submitted_txn_attrs = txn_attrs.copy()
        submitted_txn_attrs.update(status='submitted_for_settlement')
        authorized_txn = braintree.Transaction(None, txn_attrs)
        submitted_txn = braintree.Transaction(None, submitted_txn_attrs)
        sale.return_value.transaction = authorized_txn
        sale.return_value.is_success = True
        sfs.return_value.transaction = submitted_txn
        sfs.return_value.is_success = True

        Payday.start().payin()
        payments = self.db.all("SELECT amount, direction FROM payments")
        assert payments == [(MINIMUM_CHARGE, 'to-team'), (MINIMUM_CHARGE, 'to-participant')]
示例#2
0
    def test_update_cached_amounts(self):
        team = self.make_participant('team', claimed_time='now', number='plural')
        alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
        bob = self.make_participant('bob', claimed_time='now', last_bill_result=None)
        carl = self.make_participant('carl', claimed_time='now', last_bill_result="Fail!")
        dana = self.make_participant('dana', claimed_time='now')
        emma = self.make_participant('emma')
        roy = self.make_participant('roy', is_locked=True)
        alice.set_tip_to(dana, '3.00')
        alice.set_tip_to(bob, '6.00')
        alice.set_tip_to(emma, '1.00')
        alice.set_tip_to(team, '4.00')
        alice.set_tip_to(roy, '10.00')
        bob.set_tip_to(alice, '5.00')
        team.add_member(bob)
        team.set_take_for(bob, D('1.00'), bob)
        bob.set_tip_to(dana, '2.00')  # funded by bob's take
        bob.set_tip_to(emma, '7.00')  # not funded, insufficient receiving
        carl.set_tip_to(dana, '2.08')  # not funded, failing card

        def check():
            alice = Participant.from_username('alice')
            bob = Participant.from_username('bob')
            carl = Participant.from_username('carl')
            dana = Participant.from_username('dana')
            emma = Participant.from_username('emma')
            assert alice.giving == D('13.00')
            assert alice.pledging == D('1.00')
            assert alice.receiving == D('5.00')
            assert bob.giving == D('7.00')
            assert bob.receiving == D('7.00')
            assert bob.taking == D('1.00')
            assert carl.giving == D('0.00')
            assert carl.receiving == D('0.00')
            assert dana.receiving == D('5.00')
            assert dana.npatrons == 2
            assert emma.receiving == D('1.00')
            assert emma.npatrons == 1
            funded_tips = self.db.all("SELECT amount FROM tips WHERE is_funded ORDER BY id")
            assert funded_tips == [3, 6, 1, 4, 10, 5, 2]

        # Pre-test check
        check()

        # Check that update_cached_amounts doesn't mess anything up
        Payday.start().update_cached_amounts()
        check()

        # Check that update_cached_amounts actually updates amounts
        self.db.run("""
            UPDATE tips SET is_funded = false;
            UPDATE participants
               SET giving = 0
                 , npatrons = 0
                 , pledging = 0
                 , receiving = 0
                 , taking = 0;
        """)
        Payday.start().update_cached_amounts()
        check()
 def test_card_hold_error(self, tfh, fch):
     self.janet.set_tip_to(self.homer, 17)
     tfh.side_effect = Foobar
     fch.return_value = {}
     Payday.start().payin()
     payday = self.fetch_payday()
     assert payday['ncc_failing'] == 1
示例#4
0
def payday():

    # Wire things up.
    # ===============

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

    wireup.billing(env)
    wireup.nanswers(env)

    # Lazily import the billing module.
    # =================================
    # This dodges a problem where db in billing is None if we import it from
    # gratipay before calling wireup.billing.

    from gratipay.billing.exchanges import sync_with_balanced
    from gratipay.billing.payday import Payday

    try:
        sync_with_balanced(db)
        Payday.start().run()
    except KeyboardInterrupt:
        pass
    except:
        import aspen
        import traceback

        aspen.log(traceback.format_exc())
    def test_payin_doesnt_try_failed_cards(self, sale):
        team = self.make_team('Gratiteam', is_approved=True)
        self.obama_route.update_error('error')
        self.obama.set_payment_instruction(team, 1)

        Payday.start().payin()
        assert not sale.called
示例#6
0
    def test_update_cached_amounts_depth(self):
        alice = self.make_participant('alice',
                                      claimed_time='now',
                                      last_bill_result='')
        usernames = ('bob', 'carl', 'dana', 'emma', 'fred', 'greg')
        users = [
            self.make_participant(username, claimed_time='now')
            for username in usernames
        ]

        prev = alice
        for user in reversed(users):
            prev.set_tip_to(user, '1.00')
            prev = user

        def check():
            for username in reversed(usernames[1:]):
                user = Participant.from_username(username)
                assert user.giving == D('1.00')
                assert user.receiving == D('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

        check()
        Payday.start().update_cached_amounts()
        check()
    def test_paydays_json_gives_paydays(self):
        Payday.start()
        self.make_participant("alice")

        response = self.client.GET("/about/paydays.json")
        paydays = json.loads(response.body)
        assert paydays[0]['ntippers'] == 0
 def test_payout_skips_unreviewed(self, log):
     self.make_participant('alice', claimed_time='now', is_suspicious=None,
                           balance=20, balanced_customer_href='foo',
                           last_ach_result='')
     self.make_team(owner='alice', is_approved=True)
     Payday.start().payout()
     log.assert_any_call('UNREVIEWED: alice')
示例#9
0
    def test_payday_moves_money_cumulative_above_min_charge(self, fch):
        Enterprise = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise,
                                           '5.00')  # < MINIMUM_CHARGE
        # simulate already due amount
        self.db.run("""

            UPDATE payment_instructions ppi
               SET due = '5.00'
             WHERE ppi.participant = 'obama'
               AND ppi.team = 'TheEnterprise'

        """)

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

        fch.return_value = {}
        Payday.start().run()

        obama = Participant.from_username('obama')
        picard = Participant.from_username('picard')

        assert picard.balance == D('10.00')
        assert obama.balance == D('0.00')
        assert obama.get_due('TheEnterprise') == D('0.00')
示例#10
0
    def test_payin_doesnt_try_failed_cards(self, sale):
        team = self.make_team('Gratiteam', is_approved=True)
        self.obama_route.update_error('error')
        self.obama.set_subscription_to(team, 1)

        Payday.start().payin()
        assert not sale.called
示例#11
0
    def test_payin_pays_in(self, sale, sfs, fch):
        fch.return_value = {}
        team = self.make_team('Gratiteam', is_approved=True)
        self.obama.set_subscription_to(team, 1)

        txn_attrs = {
            'amount': 1,
            'tax_amount': 0,
            'status': 'authorized',
            'custom_fields': {
                'participant_id': self.obama.id
            },
            'credit_card': {
                'token': self.obama_route.address
            },
            'id': 'dummy_id'
        }
        submitted_txn_attrs = txn_attrs.copy()
        submitted_txn_attrs.update(status='submitted_for_settlement')
        authorized_txn = braintree.Transaction(None, txn_attrs)
        submitted_txn = braintree.Transaction(None, submitted_txn_attrs)
        sale.return_value.transaction = authorized_txn
        sale.return_value.is_success = True
        sfs.return_value.transaction = submitted_txn
        sfs.return_value.is_success = True

        Payday.start().payin()
        payments = self.db.all("SELECT amount, direction FROM payments")
        assert payments == [(1, 'to-team'), (1, 'to-participant')]
示例#12
0
    def test_paydays_json_gives_paydays(self):
        Payday.start()
        self.make_participant("alice")

        response = self.client.GET("/about/paydays.json")
        paydays = json.loads(response.body)
        assert paydays[0]['ntippers'] == 0
示例#13
0
 def test_card_hold_error(self, Customer, fch):
     self.janet.set_tip_to(self.homer, 17)
     Customer.side_effect = Foobar
     fch.return_value = {}
     Payday.start().payin()
     payday = self.fetch_payday()
     assert payday['ncc_failing'] == 1
示例#14
0
def payday():

    # Wire things up.
    # ===============

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

    wireup.billing(env)

    # Lazily import the billing module.
    # =================================
    # This dodges a problem where db in billing is None if we import it from
    # gratipay before calling wireup.billing.

    from gratipay.billing.exchanges import sync_with_balanced
    from gratipay.billing.payday import Payday

    try:
        sync_with_balanced(db)
        Payday.start().run()
    except KeyboardInterrupt:
        pass
    except:
        import aspen
        import traceback
        aspen.log(traceback.format_exc())
 def test_payin_doesnt_make_null_payments(self):
     team = self.make_team('Gratiteam', is_approved=True)
     alice = self.make_participant('alice', claimed_time='now')
     alice.set_payment_instruction(team, 1)
     alice.set_payment_instruction(team, 0)
     Payday.start().payin()
     payments = self.db.all("SELECT * FROM payments WHERE amount = 0")
     assert not payments
    def test_update_receiving_amounts_updates_receiving_amounts(self):
        A = self.make_participant('A')
        B = self.make_participant('B', claimed_time='now', last_bill_result='')
        B.set_tip_to(A, D('10.00'), update_tippee=False)
        assert Participant.from_username('A').receiving == 0

        Payday.start().update_receiving_amounts()
        assert Participant.from_username('A').receiving == 10
示例#17
0
 def test_card_hold_error(self, bt_sale, fch):
     team = self.make_team(owner=self.homer, is_approved=True)
     self.obama.set_subscription_to(team, '17.00')
     bt_sale.side_effect = Foobar
     fch.return_value = {}
     Payday.start().payin()
     payday = self.fetch_payday()
     assert payday['ncc_failing'] == 1
示例#18
0
 def test_payin_doesnt_make_null_payments(self):
     team = self.make_team('Gratiteam', is_approved=True)
     alice = self.make_participant('alice', claimed_time='now')
     alice.set_payment_instruction(team, 1)
     alice.set_payment_instruction(team, 0)
     Payday.start().payin()
     payments = self.db.all("SELECT * FROM payments WHERE amount = 0")
     assert not payments
 def test_card_hold_error(self, tfh, fch):
     team = self.make_team(owner=self.homer, is_approved=True)
     self.janet.set_subscription_to(team, '17.00')
     tfh.side_effect = Foobar
     fch.return_value = {}
     Payday.start().payin()
     payday = self.fetch_payday()
     assert payday['ncc_failing'] == 1
 def test_payout_ach_error(self, ach_credit):
     self.make_participant('alice', claimed_time='now', is_suspicious=False,
                           balance=20, balanced_customer_href='foo',
                           last_ach_result='')
     ach_credit.return_value = 'some error'
     Payday.start().payout()
     payday = self.fetch_payday()
     assert payday['nach_failing'] == 1
示例#21
0
 def test_payout_ach_error(self, ach_credit):
     self.make_participant('alice', claimed_time='now', is_suspicious=False,
                           balance=20, balanced_customer_href='foo',
                           last_ach_result='')
     ach_credit.return_value = 'some error'
     Payday.start().payout()
     payday = self.fetch_payday()
     assert payday['nach_failing'] == 1
示例#22
0
    def test_update_receiving_amounts_updates_receiving_amounts(self):
        A = self.make_participant('A')
        B = self.make_participant('B', claimed_time='now', last_bill_result='')
        B.set_tip_to(A, D('10.00'), update_tippee=False)
        assert Participant.from_username('A').receiving == 0

        Payday.start().update_receiving_amounts()
        assert Participant.from_username('A').receiving == 10
 def test_card_hold_error(self, bt_sale, fch):
     team = self.make_team(owner=self.homer, is_approved=True)
     self.obama.set_payment_instruction(team, '17.00')
     bt_sale.side_effect = Foobar
     fch.return_value = {}
     Payday.start().payin()
     payday = self.fetch_payday()
     assert payday['ncc_failing'] == 1
示例#24
0
    def test_update_cached_amounts(self):
        team = self.make_participant('team', claimed_time='now', number='plural')
        alice = self.make_participant('alice', claimed_time='now', last_bill_result='')
        bob = self.make_participant('bob', claimed_time='now', last_bill_result=None)
        carl = self.make_participant('carl', claimed_time='now', last_bill_result="Fail!")
        dana = self.make_participant('dana', claimed_time='now')
        emma = self.make_participant('emma')
        alice.set_tip_to(dana, '3.00')
        alice.set_tip_to(bob, '6.00')
        alice.set_tip_to(emma, '1.00')
        alice.set_tip_to(team, '4.00')
        bob.set_tip_to(alice, '5.00')
        team.add_member(bob)
        team.set_take_for(bob, D('1.00'), bob)
        bob.set_tip_to(dana, '2.00')  # funded by bob's take
        bob.set_tip_to(emma, '7.00')  # not funded, insufficient receiving
        carl.set_tip_to(dana, '2.08')  # not funded, failing card

        def check():
            alice = Participant.from_username('alice')
            bob = Participant.from_username('bob')
            carl = Participant.from_username('carl')
            dana = Participant.from_username('dana')
            emma = Participant.from_username('emma')
            assert alice.giving == D('13.00')
            assert alice.pledging == D('1.00')
            assert alice.receiving == D('5.00')
            assert bob.giving == D('7.00')
            assert bob.receiving == D('7.00')
            assert bob.taking == D('1.00')
            assert carl.giving == D('0.00')
            assert carl.receiving == D('0.00')
            assert dana.receiving == D('5.00')
            assert dana.npatrons == 2
            assert emma.receiving == D('1.00')
            assert emma.npatrons == 1
            funded_tips = self.db.all("SELECT amount FROM tips WHERE is_funded ORDER BY id")
            assert funded_tips == [3, 6, 1, 4, 5, 2]

        # Pre-test check
        check()

        # Check that update_cached_amounts doesn't mess anything up
        Payday.start().update_cached_amounts()
        check()

        # Check that update_cached_amounts actually updates amounts
        self.db.run("""
            UPDATE tips SET is_funded = false;
            UPDATE participants
               SET giving = 0
                 , npatrons = 0
                 , pledging = 0
                 , receiving = 0
                 , taking = 0;
        """)
        Payday.start().update_cached_amounts()
        check()
示例#25
0
 def test_payin_doesnt_make_null_transfers(self):
     alice = self.make_participant('alice', claimed_time='now')
     alice.set_tip_to(self.homer, 1)
     alice.set_tip_to(self.homer, 0)
     a_team = self.make_participant('a_team', claimed_time='now', number='plural')
     a_team.add_member(alice)
     Payday.start().payin()
     transfers0 = self.db.all("SELECT * FROM transfers WHERE amount = 0")
     assert not transfers0
示例#26
0
 def test_payout_unreviewed(self, log):
     self.make_participant('alice',
                           claimed_time='now',
                           is_suspicious=None,
                           balance=20,
                           balanced_customer_href='foo',
                           last_ach_result='')
     Payday.start().payout()
     log.assert_any_call('UNREVIEWED: alice')
 def test_payin_doesnt_make_null_transfers(self):
     alice = self.make_participant('alice', claimed_time='now')
     alice.set_tip_to(self.homer, 1)
     alice.set_tip_to(self.homer, 0)
     a_team = self.make_participant('a_team', claimed_time='now', number='plural')
     a_team.add_member(alice)
     Payday.start().payin()
     transfers0 = self.db.all("SELECT * FROM transfers WHERE amount = 0")
     assert not transfers0
示例#28
0
 def test_paying_out_sets_1_0_status_to_resolved(self, credit):
     alice = self.make_participant('alice', claimed_time='now', is_suspicious=False,
                                   balanced_customer_href='foo', last_ach_result='',
                                   balance=0, status_of_1_0_balance='pending-payout')
     self.make_exchange('balanced-cc', 20, 0, alice)  # sets balance, and satisfies self_check
     Payday.start().payout()
     alice = Participant.from_username('alice')
     assert alice.status_of_1_0_balance == 'resolved'
     assert alice.balance == 0
示例#29
0
    def test_payout_pays_out_Gratipay_1_0_balance(self, ach):
        alice = self.make_participant('alice', claimed_time='now', is_suspicious=False,
                                      balanced_customer_href='foo', last_ach_result='',
                                      balance=20, status_of_1_0_balance='pending-payout')
        Payday.start().payout()

        assert ach.call_count == 1
        assert ach.call_args_list[0][0][1].id == alice.id
        assert ach.call_args_list[0][0][2] == 0
示例#30
0
    def test_iter_payday_events(self):
        now = datetime.now()
        Payday().start().run()

        Enterprise = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise,
                                           '10.00')  # >= MINIMUM_CHARGE!
        for i in range(2):
            with patch.object(Payday, 'fetch_card_holds') as fch:
                fch.return_value = {}
                Payday.start().run()
            self.db.run("""
                UPDATE paydays
                   SET ts_start = ts_start - interval '1 week'
                     , ts_end = ts_end - interval '1 week';
                UPDATE payments
                   SET timestamp = "timestamp" - interval '1 week';
                UPDATE transfers
                   SET timestamp = "timestamp" - interval '1 week';
            """)

        obama = Participant.from_username('obama')
        picard = Participant.from_username('picard')

        assert obama.balance == D('0.00')
        assert picard.balance == D('20.00')

        Payday().start()  # to demonstrate that we ignore any open payday?

        # Make all events in the same year.
        delta = '%s days' % (364 - (now - datetime(now.year, 1, 1)).days)
        self.db.run(
            """
            UPDATE paydays
                SET ts_start = ts_start + interval %(delta)s
                  , ts_end = ts_end + interval %(delta)s;
            UPDATE payments
                SET timestamp = "timestamp" + interval %(delta)s;
            UPDATE transfers
                SET timestamp = "timestamp" + interval %(delta)s;
        """, dict(delta=delta))

        events = list(iter_payday_events(self.db, picard, now.year))
        assert len(events) == 7
        assert events[0]['kind'] == 'totals'
        assert events[0]['given'] == 0
        assert events[0]['received'] == 20
        assert events[1]['kind'] == 'day-open'
        assert events[1]['payday_number'] == 2
        assert events[2]['balance'] == 20
        assert events[-1]['kind'] == 'day-close'
        assert events[-1]['balance'] == 0

        events = list(iter_payday_events(self.db, obama))
        assert events[0]['given'] == 20
        assert len(events) == 11
示例#31
0
    def test_iter_payday_events(self):
        Payday.start().run()
        team = self.make_participant('team',
                                     number='plural',
                                     claimed_time='now')
        alice = self.make_participant('alice', claimed_time='now')
        self.make_exchange('bill', 10000, 0, team)
        self.make_exchange('bill', 10000, 0, alice)
        self.make_exchange('bill', -5000, 0, alice)
        self.db.run("""
            UPDATE transfers
               SET timestamp = "timestamp" - interval '1 month'
        """)
        bob = self.make_participant('bob', claimed_time='now')
        carl = self.make_participant('carl', claimed_time='now')
        team.add_member(bob)
        team.set_take_for(bob, Decimal('1.00'), team)
        alice.set_tip_to(bob, Decimal('5.00'))

        assert bob.balance == 0
        for i in range(2):
            with patch.object(Payday, 'fetch_card_holds') as fch:
                fch.return_value = {}
                Payday.start().run()
            self.db.run("""
                UPDATE paydays
                   SET ts_start = ts_start - interval '1 week'
                     , ts_end = ts_end - interval '1 week';
                UPDATE transfers
                   SET timestamp = "timestamp" - interval '1 week';
            """)
        bob = Participant.from_id(bob.id)
        assert bob.balance == 12

        Payday().start()
        events = list(iter_payday_events(self.db, bob))
        assert len(events) == 9
        assert events[0]['kind'] == 'totals'
        assert events[0]['given'] == 0
        assert events[0]['received'] == 12
        assert events[1]['kind'] == 'day-open'
        assert events[1]['payday_number'] == 2
        assert events[2]['balance'] == 12
        assert events[-1]['kind'] == 'day-close'
        assert events[-1]['balance'] == '0.00'

        alice = Participant.from_id(alice.id)
        assert alice.balance == 4990
        events = list(iter_payday_events(self.db, alice))
        assert events[0]['given'] == 10
        assert len(events) == 11

        carl = Participant.from_id(carl.id)
        assert carl.balance == 0
        events = list(iter_payday_events(self.db, carl))
        assert len(events) == 0
示例#32
0
    def test_payday_moves_money(self, fch):
        self.janet.set_tip_to(self.homer, '6.00')  # under $10!
        fch.return_value = {}
        Payday.start().run()

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

        assert homer.balance == D('6.00')
        assert janet.balance == D('3.41')
示例#33
0
    def test_nusers_includes_dues(self, fch):
        Enterprise  = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, '6.00')  # below MINIMUM_CHARGE
        fch.return_value = {}
        Payday.start().run()

        assert self.obama.get_due(Enterprise) == D('6.00')

        nusers = self.db.one("SELECT nusers FROM paydays")
        assert nusers == 1
    def test_payday_moves_money(self, fch):
        self.janet.set_tip_to(self.homer, '6.00')  # under $10!
        fch.return_value = {}
        Payday.start().run()

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

        assert homer.balance == D('6.00')
        assert janet.balance == D('3.41')
 def test_payin_doesnt_make_null_payments(self):
     team = self.make_team('Gratiteam', is_approved=True)
     alice = self.make_participant('alice', claimed_time='now')
     alice.set_subscription_to(team, 1)
     alice.set_subscription_to(team, 0)
     a_team = self.make_participant('a_team', claimed_time='now', number='plural')
     a_team.add_member(alice)
     Payday.start().payin()
     payments = self.db.all("SELECT * FROM payments WHERE amount = 0")
     assert not payments
    def test_nusers_includes_dues(self, fch):
        Enterprise  = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, '6.00')  # below MINIMUM_CHARGE
        fch.return_value = {}
        Payday.start().run()

        assert self.obama.get_due(Enterprise) == D('6.00')

        nusers = self.db.one("SELECT nusers FROM paydays")
        assert nusers == 1
示例#37
0
    def test_iter_payday_events(self):
        now = datetime.now()
        Payday().start().run()

        Enterprise = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, '10.00')  # >= MINIMUM_CHARGE!
        for i in range(2):
            with patch.object(Payday, 'fetch_card_holds') as fch:
                fch.return_value = {}
                Payday.start().run()
            self.db.run("""
                UPDATE paydays
                   SET ts_start = ts_start - interval '1 week'
                     , ts_end = ts_end - interval '1 week';
                UPDATE payments
                   SET timestamp = "timestamp" - interval '1 week';
                UPDATE transfers
                   SET timestamp = "timestamp" - interval '1 week';
            """)


        obama = P('obama')
        picard = P('picard')

        assert obama.balance == D('0.00')
        assert picard.balance == D('20.00')

        Payday().start()  # to demonstrate that we ignore any open payday?

        # Make all events in the same year.
        delta = '%s days' % (364 - (now - datetime(now.year, 1, 1)).days)
        self.db.run("""
            UPDATE paydays
                SET ts_start = ts_start + interval %(delta)s
                  , ts_end = ts_end + interval %(delta)s;
            UPDATE payments
                SET timestamp = "timestamp" + interval %(delta)s;
            UPDATE transfers
                SET timestamp = "timestamp" + interval %(delta)s;
        """, dict(delta=delta))

        events = list(iter_payday_events(self.db, picard, now.year))
        assert len(events) == 7
        assert events[0]['kind'] == 'totals'
        assert events[0]['given'] == 0
        assert events[0]['received'] == 20
        assert events[1]['kind'] == 'day-open'
        assert events[1]['payday_number'] == 2
        assert events[2]['balance'] == 20
        assert events[-1]['kind'] == 'day-close'
        assert events[-1]['balance'] == 0

        events = list(iter_payday_events(self.db, obama))
        assert events[0]['given'] == 20
        assert len(events) == 11
示例#38
0
    def test_iter_payday_events(self):
        Payday.start().run()
        team = self.make_participant('team', number='plural', claimed_time='now')
        alice = self.make_participant('alice', claimed_time='now')
        self.make_exchange('balanced-cc', 10000, 0, team)
        self.make_exchange('balanced-cc', 10000, 0, alice)
        self.make_exchange('balanced-cc', -5000, 0, alice)
        self.db.run("""
            UPDATE transfers
               SET timestamp = "timestamp" - interval '1 month'
        """)
        bob = self.make_participant('bob', claimed_time='now')
        carl = self.make_participant('carl', claimed_time='now')
        team.add_member(bob)
        team.set_take_for(bob, Decimal('1.00'), team)
        alice.set_tip_to(bob, Decimal('5.00'))

        assert bob.balance == 0
        for i in range(2):
            with patch.object(Payday, 'fetch_card_holds') as fch:
                fch.return_value = {}
                Payday.start().run()
            self.db.run("""
                UPDATE paydays
                   SET ts_start = ts_start - interval '1 week'
                     , ts_end = ts_end - interval '1 week';
                UPDATE transfers
                   SET timestamp = "timestamp" - interval '1 week';
            """)
        bob = Participant.from_id(bob.id)
        assert bob.balance == 12

        Payday().start()
        events = list(iter_payday_events(self.db, bob))
        assert len(events) == 9
        assert events[0]['kind'] == 'totals'
        assert events[0]['given'] == 0
        assert events[0]['received'] == 12
        assert events[1]['kind'] == 'day-open'
        assert events[1]['payday_number'] == 2
        assert events[2]['balance'] == 12
        assert events[-1]['kind'] == 'day-close'
        assert events[-1]['balance'] == 0

        alice = Participant.from_id(alice.id)
        assert alice.balance == 4990
        events = list(iter_payday_events(self.db, alice))
        assert events[0]['given'] == 10
        assert len(events) == 11

        carl = Participant.from_id(carl.id)
        assert carl.balance == 0
        events = list(iter_payday_events(self.db, carl))
        assert len(events) == 0
 def test_payin_dumps_transfers_for_debugging(self, cch, fch):
     self.janet.set_tip_to(self.homer, 10)
     fake_hold = mock.MagicMock()
     fake_hold.amount = 1500
     fch.return_value = {self.janet.id: fake_hold}
     cch.side_effect = Foobar
     open = mock.MagicMock()
     with mock.patch.dict(__builtins__, {'open': open}):
         with self.assertRaises(Foobar):
             Payday.start().payin()
     assert open.call_count == 1
示例#40
0
    def test_payout_can_pay_out(self, ach):
        alice = self.make_participant('alice', claimed_time='now', is_suspicious=False,
                              balanced_customer_href='foo',
                              last_ach_result='')
        self.make_exchange('balanced-cc', 20, 0, alice)
        self.make_team(owner='alice', is_approved=True)
        Payday.start().payout()

        assert ach.call_count == 1
        assert ach.call_args_list[0][0][1].id == alice.id
        assert ach.call_args_list[0][0][2] == 0
    def test_payday_moves_money(self, fch):
        A = self.make_team(is_approved=True)
        self.obama.set_subscription_to(A, '6.00')  # under $10!
        fch.return_value = {}
        Payday.start().run()

        obama = Participant.from_username('obama')
        hannibal = Participant.from_username('hannibal')

        assert hannibal.balance == D('6.00')
        assert obama.balance == D('3.41')
示例#42
0
    def test_payday_moves_money(self, fch):
        A = self.make_team(is_approved=True)
        self.obama.set_subscription_to(A, '6.00')  # under $10!
        fch.return_value = {}
        Payday.start().run()

        obama = Participant.from_username('obama')
        hannibal = Participant.from_username('hannibal')

        assert hannibal.balance == D('6.00')
        assert obama.balance == D('3.41')
示例#43
0
 def test_payin_dumps_transfers_for_debugging(self, cch, fch):
     self.janet.set_tip_to(self.homer, 10)
     fake_hold = mock.MagicMock()
     fake_hold.amount = 1500
     fch.return_value = {self.janet.id: fake_hold}
     cch.side_effect = Foobar
     open = mock.MagicMock()
     with mock.patch.dict(__builtins__, {'open': open}):
         with self.assertRaises(Foobar):
             Payday.start().payin()
     assert open.call_count == 1
示例#44
0
    def test_payday_does_not_move_money_below_min_charge(self, fch):
        Enterprise  = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, '6.00')  # not enough to reach MINIMUM_CHARGE
        fch.return_value = {}
        Payday.start().run()

        obama = P('obama')
        picard = P('picard')

        assert picard.balance == D('0.00')
        assert obama.balance == D('0.00')
        assert obama.get_due(Enterprise) == D('6.00')
 def test_transfer_takes_doesnt_make_negative_transfers(self, fch):
     hold = balanced.CardHold(amount=1500, meta={'participant_id': self.janet.id})
     hold.capture = lambda *a, **kw: None
     hold.save = lambda *a, **kw: None
     fch.return_value = {self.janet.id: hold}
     self.janet.update_number('plural')
     self.janet.set_tip_to(self.homer, 10)
     self.janet.add_member(self.david)
     Payday.start().payin()
     assert Participant.from_id(self.david.id).balance == 0
     assert Participant.from_id(self.homer.id).balance == 10
     assert Participant.from_id(self.janet.id).balance == 0
 def test_payin_cancels_uncaptured_holds(self, log):
     self.janet.set_tip_to(self.homer, 42)
     alice = self.make_participant('alice', claimed_time='now',
                                   is_suspicious=False)
     self.make_exchange('balanced-cc', 50, 0, alice)
     alice.set_tip_to(self.janet, 50)
     Payday.start().payin()
     assert log.call_args_list[-3][0] == ("Captured 0 card holds.",)
     assert log.call_args_list[-2][0] == ("Canceled 1 card holds.",)
     assert Participant.from_id(alice.id).balance == 0
     assert Participant.from_id(self.janet.id).balance == 8
     assert Participant.from_id(self.homer.id).balance == 42
    def test_payday_does_not_move_money_below_min_charge(self, fch):
        Enterprise  = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, '6.00')  # not enough to reach MINIMUM_CHARGE
        fch.return_value = {}
        Payday.start().run()

        obama = Participant.from_username('obama')
        picard = Participant.from_username('picard')

        assert picard.balance == D('0.00')
        assert obama.balance == D('0.00')
        assert obama.get_due('TheEnterprise') == D('6.00')
示例#48
0
 def test_payout_ignores_unresolved(self, credit):
     bob = self.make_participant('bob', claimed_time='now', is_suspicious=False,
                                 balanced_customer_href='foo', last_ach_result='',
                                 balance=13, status_of_1_0_balance='unresolved')
     alice = self.make_participant('alice', claimed_time='now', is_suspicious=False,
                                   balanced_customer_href='foo', last_ach_result='',
                                   balance=0, status_of_1_0_balance='pending-payout')
     self.make_exchange('balanced-cc', 20, 0, alice)
     Payday.start().payout()
     bob = Participant.from_username('bob')
     assert bob.status_of_1_0_balance == 'unresolved'
     assert bob.balance == 13
示例#49
0
    def test_payday_moves_money(self):
        Enterprise = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, '6.00')  # under $10!
        with mock.patch.object(Payday, 'fetch_card_holds') as fch:
            fch.return_value = {}
            Payday.start().run()

        obama = Participant.from_username('obama')
        picard = Participant.from_username('picard')

        assert picard.balance == D('6.00')
        assert obama.balance == D('3.41')
    def test_payday_moves_money(self):
        A = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(A, '6.00')  # under $10!
        with mock.patch.object(Payday, 'fetch_card_holds') as fch:
            fch.return_value = {}
            Payday.start().run()

        obama = Participant.from_username('obama')
        hannibal = Participant.from_username('hannibal')

        assert hannibal.balance == D('6.00')
        assert obama.balance == D('3.41')
示例#51
0
 def test_payin_cancels_uncaptured_holds(self, log):
     self.janet.set_tip_to(self.homer, 42)
     alice = self.make_participant('alice', claimed_time='now',
                                   is_suspicious=False)
     self.make_exchange('bill', 50, 0, alice)
     alice.set_tip_to(self.janet, 50)
     Payday.start().payin()
     assert log.call_args_list[-3][0] == ("Captured 0 card holds.",)
     assert log.call_args_list[-2][0] == ("Canceled 1 card holds.",)
     assert Participant.from_id(alice.id).balance == 0
     assert Participant.from_id(self.janet.id).balance == 8
     assert Participant.from_id(self.homer.id).balance == 42
示例#52
0
 def test_transfer_takes_doesnt_make_negative_transfers(self, fch):
     hold = balanced.CardHold(amount=1500, meta={'participant_id': self.janet.id})
     hold.capture = lambda *a, **kw: None
     hold.save = lambda *a, **kw: None
     fch.return_value = {self.janet.id: hold}
     self.janet.update_number('plural')
     self.janet.set_tip_to(self.homer, 10)
     self.janet.add_member(self.david)
     Payday.start().payin()
     assert Participant.from_id(self.david.id).balance == 0
     assert Participant.from_id(self.homer.id).balance == 10
     assert Participant.from_id(self.janet.id).balance == 0
示例#53
0
 def test_payin_doesnt_make_null_payments(self):
     team = self.make_team('Gratiteam', is_approved=True)
     alice = self.make_participant('alice', claimed_time='now')
     alice.set_subscription_to(team, 1)
     alice.set_subscription_to(team, 0)
     a_team = self.make_participant('a_team',
                                    claimed_time='now',
                                    number='plural')
     a_team.add_member(alice)
     Payday.start().payin()
     payments = self.db.all("SELECT * FROM payments WHERE amount = 0")
     assert not payments
    def test_payday_moves_money_above_min_charge(self):
        Enterprise = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, MINIMUM_CHARGE)  # must be >= MINIMUM_CHARGE
        with mock.patch.object(Payday, 'fetch_card_holds') as fch:
            fch.return_value = {}
            Payday.start().run()

        obama = Participant.from_username('obama')
        picard = Participant.from_username('picard')

        assert picard.balance == D(MINIMUM_CHARGE)
        assert obama.balance == D('0.00')
        assert obama.get_due('TheEnterprise') == D('0.00')
示例#55
0
    def test_payday_moves_money_above_min_charge(self, fch):
        Enterprise = self.make_team(is_approved=True)
        self.obama.set_payment_instruction(Enterprise, MINIMUM_CHARGE)  # must be >= MINIMUM_CHARGE

        fch.return_value = {}
        Payday.start().run()

        obama = P('obama')
        picard = P('picard')

        assert picard.balance == D(MINIMUM_CHARGE)
        assert obama.balance == D('0.00')
        assert obama.get_due(Enterprise) == D('0.00')
示例#56
0
 def test_payin_dumps_transfers_for_debugging(self, cch, fch):
     self.janet.set_tip_to(self.homer, 10)
     fake_hold = mock.MagicMock()
     fake_hold.amount = 1500
     fch.return_value = {self.janet.id: fake_hold}
     cch.side_effect = Foobar
     open_ = mock.MagicMock()
     open_.side_effect = open
     with mock.patch.dict(__builtins__, {'open': open_}):
         with self.assertRaises(Foobar):
             Payday.start().payin()
     filename = open_.call_args_list[-1][0][0]
     assert filename.endswith('_transfers.csv')
     os.unlink(filename)
示例#57
0
 def test_payin_dumps_transfers_for_debugging(self, cch, fch):
     team = self.make_team(owner=self.homer, is_approved=True)
     self.obama.set_subscription_to(team, '10.00')
     fake_hold = mock.MagicMock()
     fake_hold.amount = 1500
     fch.return_value = {self.obama.id: fake_hold}
     cch.side_effect = Foobar
     open_ = mock.MagicMock()
     open_.side_effect = open
     with mock.patch.dict(__builtins__, {'open': open_}):
         with self.assertRaises(Foobar):
             Payday.start().payin()
     filename = open_.call_args_list[-1][0][0]
     assert filename.endswith('_payments.csv')
     os.unlink(filename)
示例#58
0
    def test_payday_doesnt_move_money_to_a_suspicious_account(self, fch):
        self.db.run("""
            UPDATE participants
               SET is_suspicious = true
             WHERE username = '******'
        """)
        self.janet.set_tip_to(self.homer, '6.00')  # under $10!
        fch.return_value = {}
        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')
示例#59
0
    def test_start_prepare(self, log):
        self.clear_tables()
        self.make_participant('bob', balance=10, claimed_time=None)
        self.make_participant('carl', balance=10, claimed_time='now')

        payday = Payday.start()
        ts_start = payday.ts_start

        get_participants = lambda c: c.all("SELECT * FROM payday_participants")

        with self.db.get_cursor() as cursor:
            payday.prepare(cursor, ts_start)
            participants = get_participants(cursor)

        expected_logging_call_args = [
            ('Starting a new payday.'),
            ('Payday started at {}.'.format(ts_start)),
            ('Prepared the DB.'),
        ]
        expected_logging_call_args.reverse()
        for args, _ in log.call_args_list:
            assert args[0] == expected_logging_call_args.pop()

        log.reset_mock()

        # run a second time, we should see it pick up the existing payday
        payday = Payday.start()
        second_ts_start = payday.ts_start
        with self.db.get_cursor() as cursor:
            payday.prepare(cursor, second_ts_start)
            second_participants = get_participants(cursor)

        assert ts_start == second_ts_start
        participants = list(participants)
        second_participants = list(second_participants)

        # carl is the only valid participant as he has a claimed time
        assert len(participants) == 1
        assert participants == second_participants

        expected_logging_call_args = [
            ('Picking up with an existing payday.'),
            ('Payday started at {}.'.format(second_ts_start)),
            ('Prepared the DB.'),
        ]
        expected_logging_call_args.reverse()
        for args, _ in log.call_args_list:
            assert args[0] == expected_logging_call_args.pop()