Beispiel #1
0
 def get(self):
     d_str = request.args.get('date', None)
     if d_str is None:
         pp = BiweeklyPayPeriod.period_for_date(dtnow().date(), db_session)
         logger.debug('Redirect to current payperiod: %s', pp)
     else:
         d = datetime.strptime(d_str, '%Y-%m-%d').date()
         pp = BiweeklyPayPeriod.period_for_date(d, db_session)
         logger.debug('Found period for %s (%s): %s', d_str, d, pp)
     return redirect('/payperiod/%s' % pp.start_date.strftime('%Y-%m-%d'),
                     code=302)
Beispiel #2
0
 def get(self, period_date):
     d = datetime.strptime(period_date, '%Y-%m-%d').date()
     pp = BiweeklyPayPeriod.period_for_date(d, db_session)
     curr_pp = BiweeklyPayPeriod.period_for_date(dtnow(), db_session)
     budgets = {}
     for b in db_session.query(Budget).all():
         k = b.name
         if b.is_income:
             k = '%s (i)' % b.name
         budgets[b.id] = k
     standing = {
         b.id: b.current_balance
         for b in db_session.query(Budget).filter(
             Budget.is_periodic.__eq__(False), Budget.is_active.__eq__(
                 True)).all()
     }
     periodic = {
         b.id: b.current_balance
         for b in db_session.query(Budget).filter(
             Budget.is_periodic.__eq__(True), Budget.is_active.__eq__(
                 True)).all()
     }
     accts = {a.name: a.id for a in db_session.query(Account).all()}
     txfr_date_str = dtnow().strftime('%Y-%m-%d')
     if dtnow().date() < pp.start_date or dtnow().date() > pp.end_date:
         # If we're looking at a non-current pay period, default the
         # transfer modal date to the start of the period.
         txfr_date_str = pp.start_date.strftime('%Y-%m-%d')
     return render_template(
         'payperiod.html',
         pp=pp,
         pp_prev_date=pp.previous.start_date,
         pp_prev_sums=pp.previous.overall_sums,
         pp_prev_suffix=self.suffix_for_period(curr_pp, pp.previous),
         pp_curr_date=pp.start_date,
         pp_curr_sums=pp.overall_sums,
         pp_curr_suffix=self.suffix_for_period(curr_pp, pp),
         pp_next_date=pp.next.start_date,
         pp_next_sums=pp.next.overall_sums,
         pp_next_suffix=self.suffix_for_period(curr_pp, pp.next),
         pp_following_date=pp.next.next.start_date,
         pp_following_sums=pp.next.next.overall_sums,
         pp_following_suffix=self.suffix_for_period(curr_pp, pp.next.next),
         pp_last_date=pp.next.next.next.start_date,
         pp_last_sums=pp.next.next.next.overall_sums,
         pp_last_suffix=self.suffix_for_period(curr_pp, pp.next.next.next),
         budget_sums=pp.budget_sums,
         budgets=budgets,
         standing=standing,
         periodic=periodic,
         transactions=pp.transactions_list,
         accts=accts,
         txfr_date_str=txfr_date_str)
 def test_6_transaction_list_ordering(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 10), testdb)
     type_id = [[x['type'], x['id']] for x in pp.transactions_list]
     assert type_id == [['ScheduledTransaction', 1], ['Transaction', 1],
                        ['ScheduledTransaction', 3],
                        ['ScheduledTransaction', 2], ['Transaction', 2],
                        ['Transaction', 3], ['Transaction', 4]]
Beispiel #4
0
    def validate(self, data):
        """
        Validate the form data. Return None if it is valid, or else a hash of
        field names to list of error strings for each field.

        :param data: submitted form data
        :type data: dict
        :return: None if no errors, or hash of field name to errors for that
          field
        """
        _id = int(data['id'])
        # make sure the ID is valid
        db_session.query(ScheduledTransaction).get(_id)
        d = datetime.strptime(data['date'], '%Y-%m-%d').date()
        pp = BiweeklyPayPeriod.period_for_date(d, db_session)
        have_errors = False
        errors = {k: [] for k in data.keys()}
        if data.get('description', '').strip() == '':
            errors['description'].append('Description cannot be empty')
            have_errors = True
        if float(data['amount']) == 0:
            errors['amount'].append('Amount cannot be zero')
            have_errors = True
        if d < pp.start_date or d > pp.end_date:
            errors['date'].append('Date must be in current pay period')
            have_errors = True
        if have_errors:
            return errors
        return None
Beispiel #5
0
 def _by_pay_period(self):
     min_txn = db_session.query(Transaction).order_by(
         Transaction.date.asc()
     ).first()
     budget_names = self._budget_names()
     logger.debug('budget_names=%s', budget_names)
     records = []
     budgets_present = set()
     pp = BiweeklyPayPeriod.period_for_date(min_txn.date, db_session)
     dt_now = dtnow().date()
     while pp.end_date <= dt_now:
         sums = pp.budget_sums
         logger.debug('sums=%s', sums)
         records.append({
             budget_names[y]: sums[y]['spent'] for y in sums.keys()
             if y in budget_names
         })
         records[-1]['date'] = pp.start_date.strftime('%Y-%m-%d')
         budgets_present.update(
             [budget_names[y] for y in sums.keys() if y in budget_names]
         )
         pp = pp.next
     res = {
         'data': records,
         'keys': sorted(list(budgets_present))
     }
     return jsonify(res)
Beispiel #6
0
 def get(self):
     standing = db_session.query(Budget).filter(
         Budget.is_active.__eq__(True),
         Budget.is_periodic.__eq__(False)).order_by(Budget.name).all()
     pp = BiweeklyPayPeriod.period_for_date(dtnow(), db_session)
     pp_curr_idx = 1
     pp_next_idx = 2
     pp_following_idx = 3
     periods = [pp]
     x = pp
     # add another
     for i in range(0, 8):
         x = x.next
         periods.append(x)
     # trigger calculation/cache of data before passing on to jinja
     for p in periods:
         p.overall_sums
     return render_template(
         'index.html',
         bank_accounts=db_session.query(Account).filter(
             Account.acct_type == AcctType.Bank,
             Account.is_active == True).all(),  # noqa
         credit_accounts=db_session.query(Account).filter(
             Account.acct_type == AcctType.Credit,
             Account.is_active == True).all(),  # noqa
         investment_accounts=db_session.query(Account).filter(
             Account.acct_type == AcctType.Investment,
             Account.is_active == True).all(),  # noqa
         standing_budgets=standing,
         periods=periods,
         curr_pp=pp,
         pp_curr_idx=pp_curr_idx,
         pp_next_idx=pp_next_idx,
         pp_following_idx=pp_following_idx)
 def _budgets_preshot(self):
     logger.info('budgets preshot - DB update')
     conn = engine.connect()
     data_sess = scoped_session(
         sessionmaker(autocommit=False, autoflush=False, bind=conn)
     )
     pp = BiweeklyPayPeriod.period_for_date(dtnow(), data_sess).previous
     data_sess.add(Budget(
         name='Budget3', is_periodic=True, starting_balance=Decimal('0')
     ))
     data_sess.add(Budget(
         name='Budget4', is_periodic=True, starting_balance=Decimal('0')
     ))
     data_sess.add(Budget(
         name='Budget5', is_periodic=True, starting_balance=Decimal('250')
     ))
     data_sess.flush()
     data_sess.commit()
     for i in range(0, 10):
         self._add_transactions(data_sess, pp)
         pp = pp.previous
     data_sess.close()
     conn.close()
     logger.info('budgets preshot - DB update done; click')
     self.get('/budgets')
     sleep(10)
     logger.info('budgets preshot - executing script')
     self.browser.execute_script(
         "$('#budget-per-period-chart').find('.morris-hover').show()"
     )
     sleep(2)
     logger.info('budgets preshot done')
Beispiel #8
0
 def pay_periods(self, db):
     x = BiweeklyPayPeriod.period_for_date(
         (PAY_PERIOD_START_DATE - timedelta(days=2)), db)
     periods = []
     for i in range(0, 10):
         periods.append(x)
         x = x.next
     return periods
 def test_5_overall_sums(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 10), testdb)
     assert pp._data['overall_sums'] == {
         'allocated': Decimal('1100.0'),
         'spent': Decimal('853.0'),
         'income': Decimal('322.45'),
         'remaining': Decimal('-530.55')
     }
 def test_7_spent_greater_than_allocated(self, testdb):
     acct = testdb.query(Account).get(1)
     budget = testdb.query(Budget).get(5)
     testdb.add(
         Transaction(date=date(2017, 4, 13),
                     description='B6 T',
                     actual_amount=2032.0,
                     budgeted_amount=32.0,
                     account=acct,
                     budget=budget))
     testdb.flush()
     testdb.commit()
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 10), testdb)
     assert pp._data['budget_sums'] == {
         2: {
             'budget_amount': Decimal('123.45'),
             'allocated': Decimal('0.0'),
             'spent': Decimal('0.0'),
             'trans_total': Decimal('0.0'),
             'is_income': True,
             'remaining': Decimal('123.45')
         },
         3: {
             'budget_amount': Decimal('0.0'),
             'allocated': Decimal('199.0'),
             'spent': Decimal('100.0'),
             'trans_total': Decimal('199.0'),
             'is_income': True,
             'remaining': Decimal('199.0')
         },
         4: {
             'budget_amount': Decimal('500.00'),
             'allocated': Decimal('1000.0'),
             'spent': Decimal('850.0'),
             'trans_total': Decimal('1100.0'),
             'is_income': False,
             'remaining': Decimal('-600.0')
         },
         5: {
             'budget_amount': Decimal('100.0'),
             'allocated': Decimal('35.0'),
             'spent': Decimal('2035.0'),
             'trans_total': Decimal('2037.0'),
             'is_income': False,
             'remaining': Decimal('-1937.0')
         }
     }
     assert pp._data['overall_sums'] == {
         'allocated': Decimal('1100.0'),
         'spent': Decimal('2885.0'),
         'income': Decimal('322.45'),
         'remaining': Decimal('-2562.55')
     }
 def _payperiods_preshot(self):
     logger.info('payperiods preshot')
     # BEGIN DB update
     conn = engine.connect()
     data_sess = scoped_session(
         sessionmaker(autocommit=False, autoflush=False, bind=conn)
     )
     pp = BiweeklyPayPeriod.period_for_date(dtnow(), data_sess).previous
     data_sess.add(Budget(
         name='Budget3', is_periodic=True, starting_balance=Decimal('0')
     ))
     data_sess.add(Budget(
         name='Budget4', is_periodic=True, starting_balance=Decimal('0')
     ))
     data_sess.flush()
     data_sess.commit()
     budgets = list(data_sess.query(Budget).filter(
         Budget.is_active.__eq__(True),
         Budget.is_income.__eq__(False),
         Budget.is_periodic.__eq__(True)
     ).all())
     for i in range(0, 12):  # payperiods
         mult = choice([-1, 1])
         target = 2011.67 + (mult * uniform(0, 500))
         total = 0
         count = 0
         while total < target:
             count += 1
             amt = uniform(0, target * 0.2)
             if total + amt > target:
                 amt = target - total
             total += amt
             amt = Decimal(Decimal(amt).quantize(
                 Decimal('.001'), rounding=ROUND_HALF_UP
             ))
             data_sess.add(Transaction(
                 account_id=1,
                 budgeted_amount=amt,
                 date=pp.start_date + timedelta(days=1),
                 description='Transaction %d.%d' % (i, count),
                 budget_amounts={
                     choice(budgets): amt
                 }
             ))
             data_sess.flush()
             data_sess.commit()
         pp = pp.next
     data_sess.close()
     conn.close()
     # END DB update
     self.get('/payperiods')
     sleep(1)
Beispiel #12
0
    def validate(self, data):
        """
        Validate the form data. Return None if it is valid, or else a hash of
        field names to list of error strings for each field.

        :param data: submitted form data
        :type data: dict
        :return: None if no errors, or hash of field name to errors for that
          field
        """
        _id = int(data['id'])
        # make sure the ID is valid
        db_session.query(ScheduledTransaction).get(_id)
        d = datetime.strptime(data['payperiod_start_date'], '%Y-%m-%d').date()
        BiweeklyPayPeriod.period_for_date(d, db_session)
        have_errors = False
        errors = {k: [] for k in data.keys()}
        if data.get('notes', '').strip() == '':
            errors['notes'].append('Notes cannot be empty')
            have_errors = True
        if have_errors:
            return errors
        return None
Beispiel #13
0
 def test_83_issue201_confirm(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2020, 4, 9), testdb)
     assert pp._data['budget_sums'] == {
         2: {
             'budget_amount': Decimal('123.45'),
             'allocated': Decimal('0.0'),
             'spent': Decimal('0.0'),
             'trans_total': Decimal('0.0'),
             'is_income': True,
             'remaining': Decimal('123.45')
         },
         3: {
             'budget_amount': Decimal('0.0'),
             'allocated': Decimal('99.0'),
             'spent': Decimal('0.0'),
             'trans_total': Decimal('99.0'),
             'is_income': True,
             'remaining': Decimal('99.0')
         },
         4: {
             'budget_amount': Decimal('500.00'),
             'allocated': Decimal('0.0'),
             'spent': Decimal('0.0'),
             'trans_total': Decimal('0.0'),
             'is_income': False,
             'remaining': Decimal('500.0')
         },
         5: {
             'budget_amount': Decimal('100.0'),
             'allocated': Decimal('2.0'),
             'spent': Decimal('0.0'),
             'trans_total': Decimal('2.0'),
             'is_income': False,
             'remaining': Decimal('98.0')
         },
         6: {
             'budget_amount': Decimal('0.0'),
             'allocated': Decimal('2.0'),
             'spent': Decimal('200.0'),
             'trans_total': Decimal('200.0'),
             'is_income': False,
             'remaining': Decimal('-200.0')
         }
     }
     assert pp._data['overall_sums'] == {
         'allocated': Decimal('602.0'),
         'income': Decimal('222.45'),
         'remaining': Decimal('-577.55'),
         'spent': Decimal('200.0')
     }
    def pp_sum(sess=None):
        """
        Return the overall allocated sum for the current payperiod minus the
        sum of all reconciled Transactions for the pay period.

        :return: overall allocated sum for the current pay period minus the sum
          of all reconciled Transactions for the pay period.
        :rtype: float
        """
        if sess is None:
            sess = db_session
        pp = BiweeklyPayPeriod.period_for_date(dtnow(), sess)
        allocated = pp.overall_sums['allocated']
        spent = pp.overall_sums['spent']
        logger.debug('PayPeriod=%s; allocated=%s; spent=%s', pp, allocated,
                     spent)
        return allocated - spent
 def test_3_previous_pay_period(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 1), testdb)
     assert pp.start_date == date(2017, 3, 24)
     all_trans = pp.transactions_list
     all_monthly = [x for x in all_trans if x['sched_type'] == 'monthly']
     assert len(all_monthly) == 11
     # note monthly scheduled must have a day number <= 28
     assert all_monthly[0]['date'] == date(2017, 3, 24)
     assert all_monthly[1]['date'] == date(2017, 3, 25)
     assert all_monthly[2]['date'] == date(2017, 3, 26)
     assert all_monthly[3]['date'] == date(2017, 3, 27)
     assert all_monthly[4]['date'] == date(2017, 3, 28)
     assert all_monthly[5]['date'] == date(2017, 4, 1)
     assert all_monthly[6]['date'] == date(2017, 4, 2)
     assert all_monthly[7]['date'] == date(2017, 4, 3)
     assert all_monthly[8]['date'] == date(2017, 4, 4)
     assert all_monthly[9]['date'] == date(2017, 4, 5)
     assert all_monthly[10]['date'] == date(2017, 4, 6)
Beispiel #16
0
 def test_3_verify_db(self, testdb):
     d = dtnow().date()
     pp = BiweeklyPayPeriod.period_for_date(d, testdb)
     print('Found period for %s: %s' % (d, pp))
     assert pp.budget_sums[2]['allocated'] == Decimal('98.77')
     assert pp.budget_sums[2]['budget_amount'] == Decimal('234.0')
     assert pp.budget_sums[2]['remaining'] == Decimal('135.23')
     assert pp.budget_sums[2]['spent'] == Decimal('98.77')
     assert pp.budget_sums[2]['trans_total'] == Decimal('98.77')
     desc = 'Budget Transfer - 123.45 from Standing2 (5) to Periodic2 (2)'
     t1 = testdb.query(Transaction).get(5)
     assert t1.date == dtnow().date()
     assert t1.actual_amount == Decimal('123.45')
     assert t1.budgeted_amount == Decimal('123.45')
     assert t1.description == desc
     assert t1.notes == 'Budget Transfer Notes'
     assert t1.account_id == 1
     assert t1.scheduled_trans_id is None
     assert len(t1.budget_transactions) == 1
     assert t1.budget_transactions[0].budget_id == 5
     assert t1.budget_transactions[0].amount == Decimal('123.45')
     rec1 = testdb.query(TxnReconcile).get(2)
     assert rec1.txn_id == 5
     assert rec1.ofx_fitid is None
     assert rec1.ofx_account_id is None
     assert rec1.note == desc
     t2 = testdb.query(Transaction).get(6)
     assert t2.date == dtnow().date()
     assert t2.actual_amount == Decimal('-123.45')
     assert t2.budgeted_amount == Decimal('-123.45')
     assert t2.description == desc
     assert t2.notes == 'Budget Transfer Notes'
     assert t2.account_id == 1
     assert t2.scheduled_trans_id is None
     assert len(t2.budget_transactions) == 1
     assert t2.budget_transactions[0].budget_id == 2
     assert t2.budget_transactions[0].amount == Decimal('-123.45')
     rec2 = testdb.query(TxnReconcile).get(3)
     assert rec2.txn_id == 6
     assert rec2.ofx_fitid is None
     assert rec2.ofx_account_id is None
     assert rec2.note == desc
 def test_5_current_pay_period(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 13), testdb)
     assert pp.start_date == date(2017, 4, 7)
     all_trans = pp.transactions_list
     all_monthly = [x for x in all_trans if x['sched_type'] == 'monthly']
     assert len(all_monthly) == 14
     assert all_monthly[0]['date'] == date(2017, 4, 7)
     assert all_monthly[1]['date'] == date(2017, 4, 8)
     assert all_monthly[2]['date'] == date(2017, 4, 9)
     assert all_monthly[3]['date'] == date(2017, 4, 10)
     assert all_monthly[4]['date'] == date(2017, 4, 11)
     assert all_monthly[5]['date'] == date(2017, 4, 12)
     assert all_monthly[6]['date'] == date(2017, 4, 13)
     assert all_monthly[7]['date'] == date(2017, 4, 14)
     assert all_monthly[8]['date'] == date(2017, 4, 15)
     assert all_monthly[9]['date'] == date(2017, 4, 16)
     assert all_monthly[10]['date'] == date(2017, 4, 17)
     assert all_monthly[11]['date'] == date(2017, 4, 18)
     assert all_monthly[12]['date'] == date(2017, 4, 19)
     assert all_monthly[13]['date'] == date(2017, 4, 20)
Beispiel #18
0
 def get(self):
     pp = BiweeklyPayPeriod.period_for_date(dtnow(), db_session)
     pp_curr_idx = 1
     pp_next_idx = 2
     pp_following_idx = 3
     periods = [pp.previous, pp]
     x = pp
     # add another
     for i in range(0, 8):
         x = x.next
         periods.append(x)
     # trigger calculation/cache of data before passing on to jinja
     for p in periods:
         p.overall_sums
     return render_template('payperiods.html',
                            periods=periods,
                            curr_pp=pp,
                            pp_curr_idx=pp_curr_idx,
                            pp_next_idx=pp_next_idx,
                            pp_following_idx=pp_following_idx)
 def test_0_update_db(self, testdb):
     b = testdb.query(Budget).get(4)
     b.current_balance = 1617.56
     testdb.add(b)
     acct = testdb.query(Account).get(1)
     budget = testdb.query(Budget).get(1)
     pp = BiweeklyPayPeriod.period_for_date(dtnow(), testdb)
     tdate = pp.start_date + timedelta(days=2)
     stmt1 = OFXStatement(account=acct,
                          filename='a1.ofx',
                          file_mtime=dtnow(),
                          as_of=dtnow(),
                          currency='USD',
                          acctid='1',
                          bankid='b1',
                          routing_number='r1')
     testdb.add(stmt1)
     o = OFXTransaction(account=acct,
                        statement=stmt1,
                        fitid='OFX8',
                        trans_type='Purchase',
                        date_posted=dtnow(),
                        amount=-600.0,
                        name='ofx8-trans4')
     testdb.add(o)
     t = Transaction(date=tdate,
                     actual_amount=600.00,
                     description='trans6',
                     account=acct,
                     budget=budget)
     testdb.add(t)
     testdb.add(TxnReconcile(transaction=t, ofx_trans=o))
     testdb.add(
         Transaction(date=tdate,
                     actual_amount=34000.00,
                     description='transFoo',
                     account=acct,
                     budget=budget))
     testdb.flush()
     testdb.commit()
Beispiel #20
0
 def test_3_verify_db(self, testdb):
     d = dtnow().date()
     pp = BiweeklyPayPeriod.period_for_date(d, testdb)
     print('Found period for %s: %s' % (d, pp))
     assert float(pp.budget_sums[2]['allocated']) == 98.77
     assert float(pp.budget_sums[2]['budget_amount']) == 234.0
     # ugh, floating point issues...
     assert "%.2f" % pp.budget_sums[2]['remaining'] == '135.23'
     assert float(pp.budget_sums[2]['spent']) == 98.77
     assert float(pp.budget_sums[2]['trans_total']) == 98.77
     desc = 'Budget Transfer - 123.45 from Standing2 (5) to Periodic2 (2)'
     t1 = testdb.query(Transaction).get(4)
     assert t1.date == dtnow().date()
     assert float(t1.actual_amount) == 123.45
     assert float(t1.budgeted_amount) == 123.45
     assert t1.description == desc
     assert t1.notes == 'Budget Transfer Notes'
     assert t1.account_id == 1
     assert t1.scheduled_trans_id is None
     assert t1.budget_id == 5
     rec1 = testdb.query(TxnReconcile).get(2)
     assert rec1.txn_id == 4
     assert rec1.ofx_fitid is None
     assert rec1.ofx_account_id is None
     assert rec1.note == desc
     t2 = testdb.query(Transaction).get(5)
     assert t2.date == dtnow().date()
     assert float(t2.actual_amount) == -123.45
     assert float(t2.budgeted_amount) == -123.45
     assert t2.description == desc
     assert t2.notes == 'Budget Transfer Notes'
     assert t2.account_id == 1
     assert t2.scheduled_trans_id is None
     assert t2.budget_id == 2
     rec2 = testdb.query(TxnReconcile).get(3)
     assert rec2.txn_id == 5
     assert rec2.ofx_fitid is None
     assert rec2.ofx_account_id is None
     assert rec2.note == desc
 def test_4_budget_sums(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 10), testdb)
     assert pp._data['budget_sums'] == {
         2: {
             'budget_amount': Decimal('123.45'),
             'allocated': Decimal('0.0'),
             'spent': Decimal('0.0'),
             'trans_total': Decimal('0.0'),
             'is_income': True,
             'remaining': Decimal('123.45')
         },
         3: {
             'budget_amount': Decimal('0.0'),
             'allocated': Decimal('199.0'),
             'spent': Decimal('100.0'),
             'trans_total': Decimal('199.0'),
             'is_income': True,
             'remaining': Decimal('199.0')
         },
         4: {
             'budget_amount': Decimal('500.00'),
             'allocated': Decimal('1000.0'),
             'spent': Decimal('850.0'),
             'trans_total': Decimal('1100.0'),
             'is_income': False,
             'remaining': Decimal('-600.0')
         },
         5: {
             'budget_amount': Decimal('100.0'),
             'allocated': Decimal('3.0'),
             'spent': Decimal('3.0'),
             'trans_total': Decimal('5.0'),
             'is_income': False,
             'remaining': Decimal('95.0')
         }
     }
 def test_1_confirm_pay_period_start(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 10), testdb)
     assert pp.start_date == date(2017, 4, 7)
Beispiel #23
0
 def test_2_transfer_modal(self, base_url, selenium, testdb):
     # Fill in the form
     self.get(selenium, base_url + '/budgets')
     # test that updated budget was removed from the page
     stable = selenium.find_element_by_id('table-standing-budgets')
     stexts = self.tbody2textlist(stable)
     assert stexts[1] == ['yes', 'Standing2 (5)', '$9,482.29']
     ptable = selenium.find_element_by_id('table-periodic-budgets')
     ptexts = self.tbody2textlist(ptable)
     assert ptexts[2] == ['yes', 'Periodic2 (2)', '$234.00']
     pp = BiweeklyPayPeriod.period_for_date(dtnow(), testdb)
     assert float(pp.budget_sums[2]['allocated']) == 222.22
     assert float(pp.budget_sums[2]['budget_amount']) == 234.0
     assert "%.2f" % float(pp.budget_sums[2]['remaining']) == '11.78'
     assert float(pp.budget_sums[2]['spent']) == 222.22
     assert float(pp.budget_sums[2]['trans_total']) == 222.22
     link = selenium.find_element_by_id('btn_budget_txfr')
     link.click()
     modal, title, body = self.get_modal_parts(selenium)
     self.assert_modal_displayed(modal, title, body)
     assert title.text == 'Budget Transfer'
     assert body.find_element_by_id('budg_txfr_frm_date').get_attribute(
         'value') == dtnow().strftime('%Y-%m-%d')
     amt = body.find_element_by_id('budg_txfr_frm_amount')
     amt.clear()
     amt.send_keys('123.45')
     acct_sel = Select(body.find_element_by_id('budg_txfr_frm_account'))
     opts = []
     for o in acct_sel.options:
         opts.append([o.get_attribute('value'), o.text])
     assert opts == [['None', ''], ['1', 'BankOne'], ['2', 'BankTwoStale'],
                     ['3', 'CreditOne'], ['4', 'CreditTwo'],
                     ['6', 'DisabledBank'], ['5', 'InvestmentOne']]
     assert acct_sel.first_selected_option.get_attribute('value') == '1'
     from_budget_sel = Select(
         body.find_element_by_id('budg_txfr_frm_from_budget'))
     opts = []
     for o in from_budget_sel.options:
         opts.append([o.get_attribute('value'), o.text])
     assert opts == [['None', ''], ['1', 'Periodic1'], ['2', 'Periodic2'],
                     ['3', 'Periodic3 Inactive'], ['4', 'Standing1'],
                     ['5', 'Standing2'], ['6', 'Standing3 Inactive'],
                     ['7', 'Income (i)']]
     assert from_budget_sel.first_selected_option.get_attribute(
         'value') == 'None'
     from_budget_sel.select_by_value('5')
     to_budget_sel = Select(
         body.find_element_by_id('budg_txfr_frm_to_budget'))
     opts = []
     for o in from_budget_sel.options:
         opts.append([o.get_attribute('value'), o.text])
     assert opts == [['None', ''], ['1', 'Periodic1'], ['2', 'Periodic2'],
                     ['3', 'Periodic3 Inactive'], ['4', 'Standing1'],
                     ['5', 'Standing2'], ['6', 'Standing3 Inactive'],
                     ['7', 'Income (i)']]
     assert to_budget_sel.first_selected_option.get_attribute(
         'value') == 'None'
     to_budget_sel.select_by_value('2')
     notes = selenium.find_element_by_id('budg_txfr_frm_notes')
     notes.clear()
     notes.send_keys('Budget Transfer Notes')
     # submit the form
     selenium.find_element_by_id('modalSaveButton').click()
     self.wait_for_jquery_done(selenium)
     # check that we got positive confirmation
     _, _, body = self.get_modal_parts(selenium)
     x = body.find_elements_by_tag_name('div')[0]
     assert 'alert-success' in x.get_attribute('class')
     assert x.text.strip() == 'Successfully saved Transactions 4 and 5' \
                              ' in database.'
     # dismiss the modal
     selenium.find_element_by_id('modalCloseButton').click()
     self.wait_for_load_complete(selenium)
     self.wait_for_id(selenium, 'table-standing-budgets')
     # test that updated budget was removed from the page
     stable = selenium.find_element_by_id('table-standing-budgets')
     stexts = self.tbody2textlist(stable)
     assert stexts[1] == ['yes', 'Standing2 (5)', '$9,358.84']
     ptable = selenium.find_element_by_id('table-periodic-budgets')
     ptexts = self.tbody2textlist(ptable)
     assert ptexts[2] == ['yes', 'Periodic2 (2)', '$234.00']
 def test_8_income_trans_is_first_next_period(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 5, 4), testdb)
     all_trans = pp.transactions_list
     income_id = self.find_income_trans_id(testdb)
     assert income_id is not None
     assert all_trans[0]['id'] == income_id
 def test_3_ignore_scheduled_converted_to_real_trans(self, testdb):
     pp = BiweeklyPayPeriod.period_for_date(date(2017, 4, 7), testdb)
     assert pp.start_date == date(2017, 4, 7)
     all_trans = pp.transactions_list
     assert all_trans == [
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('222.22'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': None,
             'date': None,
             'description': 'ST_pp_1',
             'id': 8,
             'sched_trans_id': None,
             'sched_type': 'per period',
             'type': 'ScheduledTransaction',
             'reconcile_id': None
         },
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('333.33'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': None,
             'date': None,
             'description': 'ST_pp_3',
             'id': 9,
             'sched_trans_id': None,
             'sched_type': 'per period',
             'type': 'ScheduledTransaction',
             'reconcile_id': None
         },
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('555.55'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': None,
             'date': date(2017, 4, 8),
             'description': 'Trans_foo',
             'id': 8,
             'sched_trans_id': None,
             'sched_type': None,
             'type': 'Transaction',
             'reconcile_id': None
         },
         # ST7 (ST_day_9)
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('111.33'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': Decimal('111.11'),
             'date': date(2017, 4, 9),
             'description': 'Trans_ST_day_9',
             'id': 4,
             'sched_trans_id': 7,
             'sched_type': None,
             'type': 'Transaction',
             'reconcile_id': 2
         },
         # ST10 (ST_date)
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('444.44'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': Decimal('444.44'),
             'date': date(2017, 4, 12),
             'description': 'Trans_ST_date',
             'id': 7,
             'sched_trans_id': 10,
             'sched_type': None,
             'type': 'Transaction',
             'reconcile_id': None
         },
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('333.33'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': Decimal('333.33'),
             'date': date(2017, 4, 14),
             'description': 'Trans_ST_pp_3_A',
             'id': 5,
             'sched_trans_id': 9,
             'sched_type': None,
             'type': 'Transaction',
             'reconcile_id': None
         },
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('333.33'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': Decimal('333.33'),
             'date': date(2017, 4, 15),
             'description': 'Trans_ST_pp_3_B',
             'id': 6,
             'sched_trans_id': 9,
             'sched_type': None,
             'type': 'Transaction',
             'reconcile_id': None
         },
         {
             'account_id': 1,
             'account_name': 'BankOne',
             'amount': Decimal('666.66'),
             'budget_id': 1,
             'budget_name': 'Periodic1',
             'budgeted_amount': None,
             'date': date(2017, 4, 16),
             'description': 'Trans_bar',
             'id': 9,
             'sched_trans_id': None,
             'sched_type': None,
             'type': 'Transaction',
             'reconcile_id': None
         }
     ]