def location(request, year=None, month=None, location_id=None): context = base_context(request) location = get_object_or_404(Location, pk=location_id) if month: m = Month.get_month(year, month) transaction_set = location.transaction_set_for_month(m) elif year: y = get_object_or_404(Year, year=year) transaction_set = location.transaction_set_for_year(y) else: transaction_set = location.transaction_set.all() context['transactions'] = [] TransactionTemplate = namedtuple('TransactionTemplate', ['date', 'amount', 'account', 'description']) for t in transaction_set: amount = t.amount if not t.is_debit(): amount = -1 * amount context['transactions'].append(TransactionTemplate( t.date, amount, t.account.name, t.get_description(), )) context['location_id'] = location_id context['name'] = location.name context['total_spent'] = location.transaction_total(transaction_set) return render_to_response(template_base + 'location.html', context)
def edit_budget(request, year, month, subcategory_id): subcategory = get_object_or_404(Subcategory, pk=subcategory_id) m = Month.get_month(year, month) next_url = reverse('budget-subcategory', kwargs={'year': year, 'month': month, 'subcategory_id': subcategory_id}) try: budget = CategoryBudget.objects.get(subcategory=subcategory, month=m) except CategoryBudget.DoesNotExist: budget = CategoryBudget(subcategory=subcategory, month=m, amount=0) budget.save() return simple_form(request, CategoryBudgetForm, next_url, 'Edit Budget', 'Edit Budget', instance=budget)
def setUp(self): self.period_length = PeriodLength() self.month = Month() self.year = Year() now = datetime.now() self.now = now self.month_beginning = datetime(now.year, now.month, 1) self.month_end = datetime(now.year, now.month, monthrange(now.year, now.month)[1]) self.next_month = datetime(now.year, now.month + 1, 1) self.previous_month = datetime(now.year, now.month - 1, 1) self.year_beginning = datetime(now.year, 1, 1) self.year_end = datetime(now.year, 12, 31) self.next_year = datetime(now.year + 1, now.month, 1) self.previous_year = datetime(now.year - 1, now.month, 1)
def finalize_month(request, year, month): m = Month.get_month(year, month) total_income = 0 total_investments = 0 total_expense = 0 total_mandatory = 0 final_balance = 0 for a in Account.objects.all(): balance = a.monthly_balance(m, recalculate=True) try: account_balance = AccountBalance.objects.get(account=a, month=m) account_balance.balance = balance except AccountBalance.DoesNotExist: account_balance = AccountBalance(account=a, month=m, balance=balance) account_balance.save() final_balance += balance for c in Subcategory.objects.all(): balance = c.monthly_balance(m) try: cat_balance = CategoryBalance.objects.get(subcategory=c, month=m) cat_balance.amount = balance except CategoryBalance.DoesNotExist: cat_balance = CategoryBalance(subcategory=c, month=m, amount=balance) cat_balance.save() if c.category.type == 'I': total_income -= balance elif c.category.type == 'E': total_expense += balance elif c.category.type == 'V': total_investments += balance elif c.category.type == 'M': total_mandatory += balance balances = m.monthlybalances balances.total_income = total_income balances.total_investments = total_investments balances.total_expense = total_expense balances.total_mandatory = total_mandatory balances.final_balance = final_balance balances.finalized = True balances.save() redirect = reverse('budget-month', kwargs={'year': year, 'month': month}) return HttpResponseRedirect(redirect)
def main(request, year, month): context = base_context(request) m = Month.get_month(year, month) if m.monthlybalances.finalized: context['finalize'] = 'Re-finalize' else: context['finalize'] = 'Finalize' today = date.today() if int(year) < today.year: context['can_finalize'] = True elif int(year) == today.year and int(month) < today.month: context['can_finalize'] = True else: context['can_finalize'] = False context['month'] = month context['year'] = year context['month_id'] = m.id context['last_balanced'] = request.user.finances.last_balanced context['balances'] = m.monthlybalances context['recurring_transactions'] = RecurringTransaction.objects.all() add_json_variables_to_context(context) add_urls_to_context(context) balance = 0 balance_pending = 0 context['accounts'] = [] prev_month = m.previous() prev_balance = 0 for a in Account.objects.all(): account = namedtuple('Account', ['id', 'name']) context['accounts'].append(account(a.id, a.name)) balance += a.monthly_balance(m) balance_pending += a.monthly_balance(m, True) prev_balance += a.monthly_balance(prev_month, True) context['current_balance'] = balance context['pending_balance'] = balance_pending category_template = namedtuple('CategoryTemplate', ['name', 'id', 'income', 'budget', 'balance', 'remaining', 'budget_width', 'remaining_width', 'subcategories']) context['income_categories'] = [] context['mandatory_categories'] = [] context['expense_categories'] = [] context['investment_categories'] = [] context['total_income'] = 0 context['total_mandatory'] = 0 context['total_expenses'] = 0 context['total_investments'] = 0 context['net_income'] = 0 context['previous_balance'] = prev_balance context['budgeted_balance'] = (prev_balance + m.monthlybalances.budgeted_income - m.monthlybalances.budgeted_mandatory - m.monthlybalances.budgeted_expense - m.monthlybalances.budgeted_investments) for c in Category.objects.all(): # Categories are set up such that their balance is what is _spent_ (to # make account balances and transactions easier), but budgets are # always _positive_. That means that income categories have to have # their balance flipped to have it match the budget. subcategories = _render_subcategories(c, m) budget = c.monthly_budget(m) balance = c.monthly_balance(m) if c.type == 'I': balance *= -1 remaining = budget - balance if c.type == 'I': context['total_income'] += balance context['net_income'] += balance elif c.type == 'M': context['total_mandatory'] += balance context['net_income'] -= balance elif c.type == 'E': context['total_expenses'] += balance context['net_income'] -= balance elif c.type == 'V': context['total_investments'] += balance else: raise ValueError("not sure how I got here") budget_width = 100*float(balance) / float(budget) if budget != 0 else 0 if remaining < 0: budget_width = 100 if budget_width > 100: budget_width = 100 remaining_width = 100 - budget_width cat_template = category_template( c.name, c.id, c.type == 'I', budget, balance, remaining, budget_width, remaining_width, subcategories ) if c.type == 'I': context['income_categories'].append(cat_template) elif c.type == 'M': context['mandatory_categories'].append(cat_template) elif c.type == 'E': context['expense_categories'].append(cat_template) elif c.type == 'V': context['investment_categories'].append(cat_template) else: raise ValueError("not sure how I got here") context['categories'] = ( context['income_categories'] + context['mandatory_categories'] + context['expense_categories'] + context['investment_categories'] ) location_template = namedtuple('LocationTemplate', ['id', 'name', 'total_spent']) context['locations'] = [] # TODO(matt): This is a lot of DB lookups, and should be pushed into an # AJAX request - it's not really looked at very much, and shouldn't be # allowed to slow down the initial page load. for l in Location.objects.all(): if l.total_spent_in_month(m) > 0: context['locations'].append(location_template(l.id, l.name, l.total_spent_in_month(m))) return render_to_response(template_base + 'month.html', context)
class PeriodLengthTests(TestCase): """ Test for all PeriodLength subclasses. """ def setUp(self): self.period_length = PeriodLength() self.month = Month() self.year = Year() now = datetime.now() self.now = now self.month_beginning = datetime(now.year, now.month, 1) self.month_end = datetime(now.year, now.month, monthrange(now.year, now.month)[1]) self.next_month = datetime(now.year, now.month + 1, 1) self.previous_month = datetime(now.year, now.month - 1, 1) self.year_beginning = datetime(now.year, 1, 1) self.year_end = datetime(now.year, 12, 31) self.next_year = datetime(now.year + 1, now.month, 1) self.previous_year = datetime(now.year - 1, now.month, 1) def test_period_length(self): now = datetime.now() try: self.period_length.current_period_start_date() assert(False) except NotImplementedError: assert(True) try: self.period_length.current_period_end_date() assert(False) except NotImplementedError: assert(True) try: self.period_length.in_current_period(now) assert(False) except NotImplementedError: assert(True) def test_month(self): assert(self.month.current_period_start_date == self.month_beginning) assert(self.month.current_period_end_date == self.month_end) assert(self.month.in_current_period(self.now)) assert(self.month.in_current_period(self.month_end)) assert(self.month.in_current_period(self.month_beginning)) assert(self.month.in_current_period(self.next_month) == False) assert(self.month.in_current_period(self.previous_month) == False) def test_year(self): assert(self.year.current_period_start_date == self.year_beginning) assert(self.year.current_period_end_date == self.year_end) assert(self.year.in_current_period(self.now)) assert(self.year.in_current_period(self.year_end)) assert(self.year.in_current_period(self.year_beginning)) assert(self.year.in_current_period(self.next_year) == False) assert(self.year.in_current_period(self.previous_year) == False)