Esempio n. 1
0
def debt_vs_liquid_assets(credit_accounts=None, liquid_asset_accounts=None):
    """
    Provides a report showing the balances of credit_accounts and liquid_asset_accounts.  This data can be used to show
    if there is enough liquid assets to be able to cover credit card debt.
    :param credit_accounts: account walking parameters for all of the credit accounts to be used in this report.
    :param liquid_asset_accounts: account walking parameters for all of the liquid asset accounts to be used in this
    report.
    :return: dictionary showing results
    - credit_used - currency amount showing how much credit is being used.
    - liquid_assets - currency amount showing how much is in the liquid asset_accounts
    """
    credit_accounts = parse_walker_parameters(credit_accounts)
    liquid_accounts = parse_walker_parameters(liquid_asset_accounts)
    credit_used = Decimal('0.0')
    liquid_assets = Decimal('0.0')

    currency = get_currency()

    for credit_account in account_walker(**credit_accounts):
        # Multiplying by account.sign because if this is a liability account, the value is negative.  For the report
        # it should be a positive value because it shows that there is credit used.
        credit_used += get_balance_on_date(credit_account,
                                           PeriodStart.today.date,
                                           currency) * credit_account.sign

    for liquid_asset_account in account_walker(**liquid_accounts):
        liquid_assets += get_balance_on_date(liquid_asset_account,
                                             PeriodStart.today.date, currency)

    return {'credit_used': credit_used, 'liquid_assets': liquid_assets}
def account_usage_categories(start=PeriodStart.this_month, end=PeriodEnd.this_month, accounts=None):
    """
    Walk through the accounts defined, and find calculate how money is spent based on the categories that the
    transaction split belongs to.
    :param start: date value to be used to filter down the data.
    :param end: date value to be used to filter down the data.
    :param accounts: walker parameters for the accounts that should be used to find how spending occurs.
    :return: dictionary containing
    - categories - tuple containing category name, and the amount that is spent in that category.
    """
    start_of_trend = PeriodStart(start)
    end_of_trend = PeriodEnd(end)

    accounts = parse_walker_parameters(accounts)

    data_values = CategoryCollate(decimal_generator, split_summation)

    for account in account_walker(**accounts):
        for split in get_splits(account, start_of_trend.date, end_of_trend.date, credit=False):

            transaction = split.transaction

            for transaction_split in [s for s in transaction.splits if s.account.fullname != account.fullname]:
                data_values.store_value(transaction_split)

    return {
        'categories': sorted([[k, v] for k, v in data_values.container.iteritems()], key=itemgetter(0))
    }
Esempio n. 3
0
def investment_allocation(investment_accounts=None):
    """
    Investment allocation report.  Walks through all of the investment accounts and determines the breakdowns of the
    assets based on the category mapping data.
    :param investment_accounts: the accounts to walk through when calculation asset breakdown
    :return: dictionary containing
    categories - list of tuples containing human readable term key to the value contained in the investment accounts.
    """
    investment_accounts = investment_accounts or []

    investment_accounts = parse_walker_parameters(investment_accounts)

    breakdown = dict()
    today = get_today()
    currency = get_currency()

    for account in account_walker(**investment_accounts):
        balance = get_balance_on_date(account, today, currency)
        commodity = account.commodity.mnemonic

        results = get_asset_allocation(commodity, balance)

        for key, value in results.iteritems():
            breakdown[key] = breakdown.get(key, Decimal('0.0')) + value

    return dict(categories=sorted([[key.replace('_', ' ').title(), value]
                                   for key, value in breakdown.iteritems()],
                                  key=itemgetter(0)))
def expenses_period(expenses=None, start=PeriodStart.this_month_year_ago, end=PeriodEnd.this_month,
                    period_size=PeriodSize.month):
    """
    Calculate the amount of money that when into an expense account over the given period.
    :param expenses: account walker parameters for accounts to calculate
    :param start: the start of the time frame for the report
    :param end: the end of the time frame for the report
    :param period_size: the size of the buckets for the report
    :return: dictionary containing:
    expenses: sorted dictionary containing keys for date and value.
    """
    expenses = expenses or []

    accounts = parse_walker_parameters(expenses)
    start_period = PeriodStart(start)
    end_period = PeriodEnd(end)
    period_size = PeriodSize(period_size)

    bucket = PeriodCollate(start_period.date, end_period.date, decimal_generator, split_summation,
                           frequency=period_size.frequency, interval=period_size.interval)

    for account in account_walker(**accounts):
        for split in get_splits(account, start_period.date, end_period.date):
            bucket.store_value(split)

    sorted_results = []

    for key, value in bucket.container.iteritems():
        sorted_results.append((time.mktime(key.timetuple()), value))

    data_set = {
        'expenses': sorted(sorted_results, key=itemgetter(0))
    }

    return data_set
Esempio n. 5
0
def cash_flow(accounts=None, start=PeriodStart.this_month_year_ago, end=PeriodEnd.this_month,
              period_size=PeriodSize.month):
    """
    Create a report showing the amount of money that enters and exits an account over a period of time.  Each row
    in the report is based on period size values.
    :param accounts: account walker properties to define the accounts that are reported on
    :param start: the PeriodStart definition that tells when the report should start collecting data from
    :param end: the PeriodEnd definition that tells when the report should stop collecting data
    :param period_size: the size of the buckets to store the data into.
    :return: dictionary containing:
    credits - sorted list of dictionaries containing date and value keys
    debit - sorted list of dictionaries containing date and value keys
    net - sorted list of dictionaries containing date and value keys
    """
    accounts = accounts or []

    accounts = parse_walker_parameters(accounts)
    period_start = PeriodStart(start)
    period_end = PeriodEnd(end)
    period_size = PeriodSize(period_size)

    bucket = PeriodCollate(period_start.date, period_end.date, debit_credit_generator,
                           store_credit_debit, frequency=period_size.frequency, interval=period_size.interval)

    for account in account_walker(**accounts):
        for split in get_splits(account, period_start.date, period_end.date):
            bucket.store_value(split)

    credit_values = []
    debit_values = []
    difference_value = []

    for key, value in bucket.container.iteritems():
        store_key = time.mktime(key.timetuple())
        credit_values.append((store_key, value['credit']))
        debit_values.append((store_key, value['debit']))
        difference_value.append((store_key, value['credit'] + value['debit']))

    return {'credits': sorted(credit_values, key=itemgetter(0)),
            'debits': sorted(debit_values, key=itemgetter(0)),
            'net': sorted(difference_value, key=itemgetter(0))}
def expenses_box(expenses=None, start=PeriodStart.this_month_year_ago, end=PeriodEnd.this_month,
                 period_size=PeriodSize.month):
    """
    Calculate the amount of money that when into an expense account over the given period.
    :param expenses: account walker parameters for accounts to calculate
    :param start: the start of the time frame for the report
    :param end: the end of the time frame for the report
    :param period_size: the size of the buckets for the report
    :return: dictionary containing:
    expenses: dictionary containing the following keys:
        low - lowest amount spent
        high - highest amount spent
        q1 - first quartile value
        q2 - second quartile value
        q3 - third quartile value
    """
    expenses = expenses or []

    accounts = parse_walker_parameters(expenses)
    start_period = PeriodStart(start)
    end_period = PeriodEnd(end)
    period_size = PeriodSize(period_size)

    bucket = PeriodCollate(start_period.date, end_period.date, decimal_generator, split_summation,
                           frequency=period_size.frequency, interval=period_size.interval)

    for account in account_walker(**accounts):
        for split in get_splits(account, start_period.date, end_period.date):
            bucket.store_value(split)

    results = []

    for key, value in bucket.container.iteritems():
        results.append(float(value))

    results = sorted(results)

    return {'low': results[0], 'high': results[-1], 'q1': get_median(get_lower_half(results)),
            'q2': get_median(results), 'q3': get_median(get_upper_half(results))}
def expenses_categories(expenses=None, start=PeriodStart.this_month, end=PeriodEnd.this_month):
    """
    Walk through the accounts defined in expenses base and collate the spending in the period into the categories
    defined in the configuration object.
    :param expenses: account walker definition of the accounts to grab expenses for.
    :param start: when the report should start collecting data from
    :param end: when the report should stop collecting data
    :return: dictionary containing:
    categories - list of tuples (category name, value) containing the results sorted by category name
    """
    expenses = expenses or []

    accounts = parse_walker_parameters(expenses)
    start_period = PeriodStart(start)
    end_period = PeriodEnd(end)

    bucket = CategoryCollate(decimal_generator, split_summation)

    for account in account_walker(**accounts):
        for split in get_splits(account, start_period.date, end_period.date):
            bucket.store_value(split)

    return {'categories': sorted([[key, value] for key, value in bucket.container.iteritems()], key=itemgetter(0))}
Esempio n. 8
0
def configure(configuration):
    """
    Load a list of all the expense categories and the accounts that implement that category.  The account definition
    is a dictionary that will be passed to the account walker method to find accounts (so can ignore and recursively
    search an account tree).
    :param configuration: configuration object.
    """
    global _expense_categories, _reverse
    from gnucash_reports.wrapper import account_walker, parse_walker_parameters

    for definition in configuration.get('expenses_categories', []):
        category = definition['name']
        accounts = parse_walker_parameters(definition.get('definition', []))

        all_accounts = set()
        for account in account_walker(**accounts):
            # print 'loading account: %s' % account.fullname
            all_accounts.add(clean_account_name(account.fullname))

        for account in all_accounts:
            _reverse[account] = category

        _expense_categories[category] = all_accounts
def savings_goal(savings=None,
                 goal='0.0',
                 as_of=PeriodStart.today,
                 contributions=None):
    """
    Report that shows progress towards a savings goal.
    :param savings: account walker parameters for the accounts that should have their balance count towards the goal
    :param goal: the amount that should be in the account for the goal to be met (in currency)
    :param as_of: when should the balance be looked up for
    :param contributions: list of additional contributions towards the goal which are not apart of the account
    :return: dictionary containing:
    balance - balance of the account and the contributions
    goal - the goal for the account to be at
    """
    savings = savings or []

    walker_params = parse_walker_parameters(savings)

    goal_amount = Decimal(goal)

    as_of = PeriodStart(as_of)
    contributions = contributions or []

    if not isinstance(contributions, list):
        contributions = [contributions]

    total_balance = Decimal('0.0')
    currency = get_currency()

    for account in account_walker(**walker_params):
        balance = get_balance_on_date(account, as_of.date, currency)
        total_balance += balance

    for contribution in contributions:
        total_balance += Decimal(contribution)

    return {'balance': total_balance, 'goal': goal_amount}
def income_vs_expense(income_accounts=None,
                      expense_accounts=None,
                      start=PeriodStart.this_month_year_ago,
                      end=PeriodEnd.this_month,
                      period_size=PeriodSize.month):
    """
    Report that collects the expenses from the expense accounts defined, the income from the income accounts defined
    and collates the data into buckets based on the arguments for start, end, and period_size.
    :param income_accounts: account walker parameters for the income accounts to walk through
    :param expense_accounts: account walker parameters for the expense accounts to walk through
    :param start: how far back to collect data for
    :param end: how far forward to collect data for
    :param period_size: the size of the buckets to collect data for.
    :return: dictionary containing:
    - expenses: list of dictionaries containing date and value key value pairs for the expenses defined
    - income: list of dictionaries containing date and value paris for the income defined
    - net: list of dictionaries containing date and value pairs for the net values defined
    """
    income_accounts = income_accounts or []
    expense_accounts = expense_accounts or []

    income_accounts = parse_walker_parameters(income_accounts)
    expense_accounts = parse_walker_parameters(expense_accounts)

    period_start = PeriodStart(start)
    period_end = PeriodEnd(end)
    period_size = PeriodSize(period_size)

    bucket = PeriodCollate(period_start.date,
                           period_end.date,
                           debit_credit_generator,
                           store_credit_debit,
                           frequency=period_size.frequency,
                           interval=period_size.interval)

    for account in account_walker(**income_accounts):
        for split in get_splits(account, period_start.date, period_end.date):
            bucket.store_value(split)

    for account in account_walker(**expense_accounts):
        for split in get_splits(account, period_start.date, period_end.date):
            bucket.store_value(split)

    credit_values = []
    debit_values = []
    difference_value = []

    for key, value in bucket.container.iteritems():
        time_value = time.mktime(key.timetuple())

        # Have to switch the signs so that the graph will make sense.  In GNUCash the income accounts are debited
        # when paid, and the expense accounts are 'credited' when purchased.
        credit_values.append((time_value, -value['credit']))
        debit_values.append((time_value, -value['debit']))
        difference_value.append(
            (time_value, -(value['debit'] + value['credit'])))

    return {
        'expenses': sorted(credit_values, key=itemgetter(0)),
        'income': sorted(debit_values, key=itemgetter(0)),
        'net': sorted(difference_value, key=itemgetter(0))
    }
Esempio n. 11
0
def net_worth(assets=None, liabilities=None, start=PeriodStart.this_month_year_ago,
              end=PeriodEnd.today, period_size=PeriodSize.month):
    """
    Create a graph that will calculate the assets, liabilities and net asset changes in values over time.
    :param assets: account walker parameters for the accounts containing assets
    :param liabilities: account walker parameters for the accounts containing liabilities
    :param start: the start of the period for collecting the data
    :param end: the end of the period for collecting data
    :param period_size: the size of the steps between start and end
    :return: dictionary containing:
    assets - time value data containing date and value keys
    liabilities - time value data containing date and liability keys
    net - time value data containing date and net keys
    inflation - time value data containing the inflation increase based on the net value at the start of the period
    """
    assets = assets or []
    liabilities = liabilities or []

    assets = parse_walker_parameters(assets)
    liabilities = parse_walker_parameters(liabilities)

    period_start = PeriodStart(start)
    period_end = PeriodEnd(end)
    period_size = PeriodSize(period_size)

    start_of_trend = period_start.date
    end_of_trend = period_end.date

    asset_bucket = PeriodCollate(start_of_trend, end_of_trend, decimal_generator, split_summation,
                                 frequency=period_size.frequency, interval=period_size.interval)
    liability_bucket = PeriodCollate(start_of_trend, end_of_trend, decimal_generator, split_summation,
                                     frequency=period_size.frequency, interval=period_size.interval)
    net_bucket = PeriodCollate(start_of_trend, end_of_trend, decimal_generator, split_summation,
                               frequency=period_size.frequency, interval=period_size.interval)

    currency = get_currency()

    # Calculate the asset balances
    for account in account_walker(**assets):
        for key, value in asset_bucket.container.iteritems():
            balance = get_balance_on_date(account, key, currency)
            asset_bucket.container[key] += balance

    # Calculate the liability balances
    for account in account_walker(**liabilities):
        for key, value in liability_bucket.container.iteritems():
            balance = get_balance_on_date(account, key, currency)
            liability_bucket.container[key] += balance

    # Now calculate the net values from the difference.
    for key, value in liability_bucket.container.iteritems():
        net_bucket.container[key] = asset_bucket.container[key] + liability_bucket.container[key]

    assets = time_series_dict_to_list(asset_bucket.container)
    # Convert the liabilities to positive values to show the amount of liabilities
    liabilities = time_series_dict_to_list(liability_bucket.container, value=lambda s: -s)
    net = time_series_dict_to_list(net_bucket.container)

    inflation = get_monthly_inflation()
    starting_point = None
    inflation_data = []
    for record in net:
        if starting_point:
            starting_point += (starting_point * inflation)
        else:
            starting_point = record[1]

        inflation_data.append((record[0], starting_point))

    inflation = inflation_data

    return {'assets': assets, 'liabilities': liabilities, 'net': net, 'inflation': inflation}
Esempio n. 12
0
def _calculate_payload(account_list, delta_months, trend_months):
    """
    Calculate the delta and trend values for the account list provided.
    :param account_list: account walker parameters with additional field 'name'
    :param delta_months: list of delta months to calculate
    :param trend_months: list of trend months to calculate
    :return: dictionary containing
    records - the list of sub accounts stored in the report containing
        name - the name of the record
        current_data - the current value in the account
        deltas - a list of the value in the account for the deltas
        trend - a list of the value in the account for the trend query
    current_data - the current value of all the records
    deltas - the list of the deltas for all the records
    trend - the list of the trends for all the records
    """
    currency = get_currency()
    today = date.today()
    end_of_month = date(today.year, today.month, monthrange(today.year, today.month)[1])
    total_data = {'records': [], 'current_data': Decimal('0.0'), 'deltas': [Decimal('0.0')] * len(delta_months),
                  'delta_sub_total': [Decimal('0.0')] * len(delta_months),
                  'trend': [Decimal('0.0')] * len(trend_months)}

    for definition in account_list:
        definition_data = {'name': definition['name'], 'current_data': Decimal('0.0'),
                           'deltas': [Decimal('0.0')] * len(delta_months),
                           'trend': [Decimal('0.0')] * len(trend_months)}

        # Get Current Data first
        for account in account_walker(**parse_walker_parameters(definition)):
            balance = get_balance_on_date(account, end_of_month, currency)
            definition_data['current_data'] += balance
            total_data['current_data'] += balance

        # Calculate the trends
        for index, trend in enumerate(trend_months):
            for account in account_walker(**parse_walker_parameters(definition)):
                balance = get_balance_on_date(account, trend, currency)
                definition_data['trend'][index] += balance
                total_data['trend'][index] += balance

        # Calculate deltas
        for index, delta in enumerate(delta_months):
            value = Decimal(0.0)
            for account in account_walker(**parse_walker_parameters(definition)):
                balance = get_balance_on_date(account, delta, currency)
                value += balance

                # Store the balance in the subtotal delta as well so don't have to fetch the data again.
                total_data['delta_sub_total'][index] += balance

            try:
                delta = definition_data['current_data'] - value
                definition_data['deltas'][index] = (delta / value).copy_sign(delta)
            except:
                definition_data['deltas'][index] = 'N/A'

        total_data['records'].append(definition_data)

    # Calculate the deltas for the total values.
    for index, value in enumerate(total_data['delta_sub_total']):
        try:
            delta = total_data['current_data'] - value
            total_data['deltas'][index] = (delta / value).copy_sign(delta)
        except:
            total_data['deltas'][index] = 'N/A'

    return total_data
Esempio n. 13
0
def investment_trend(investment_accounts=None,
                     start=PeriodStart.this_month_year_ago,
                     end=PeriodEnd.this_month,
                     period_size=PeriodSize.month):
    """
    Report showing how the investment has changed over a period of time.  This report provides data based on the period
    size provided in the arguments.
    :param investment_accounts: account walker parameters for all of the accounts that this report should provide
    data on
    :param start: the start time frame of the report
    :param end: the end time frame of the report
    :param period_size: the step size between start and end
    :return: dictionary containing the following
    start_value - no clue
    income - time series data containing the income generated by account (dividends)
    money_in - time series data containing the purchases into the accounts
    expense - time series data containing the expenses of the accounts
    value - time series data containing the current value of the accounts
    basis - time series data containing the basis value of the accounts (not sure if this is correct)
    """

    # TODO: Figure out what this report is really doing with start_value and basis values. Verify they are calculated
    # correctly.
    investment_accounts = investment_accounts or []

    investment_accounts = parse_walker_parameters(investment_accounts)
    period_start = PeriodStart(start)
    period_end = PeriodEnd(end)
    period_size = PeriodSize(period_size)

    investment_value = dict()
    buckets = PeriodCollate(period_start.date,
                            period_end.date,
                            investment_bucket_generator,
                            store_investment,
                            frequency=period_size.frequency,
                            interval=period_size.interval)

    start_value = Decimal('0.0')
    start_value_date = period_start.date - relativedelta(days=1)
    currency = get_currency()

    for account in account_walker(**investment_accounts):
        for split in get_splits(account, period_start.date, period_end.date):
            buckets.store_value(split)

        start_value += get_balance_on_date(account, start_value_date, currency)

        for key in buckets.container.keys():
            date_value = key + relativedelta(months=1) - relativedelta(days=1)
            investment_value[key] = investment_value.get(
                key, Decimal('0.0')) + get_balance_on_date(
                    account, date_value, currency)

    results = {
        'start_value':
        start_value,
        'income':
        time_series_dict_to_list(buckets.container,
                                 value=lambda x: x['income']),
        'money_in':
        time_series_dict_to_list(buckets.container,
                                 value=lambda x: x['money_in']),
        'expense':
        time_series_dict_to_list(buckets.container,
                                 value=lambda x: x['expense']),
        'value':
        time_series_dict_to_list(investment_value),
        'basis':
        sorted([[time.mktime(key.timetuple()),
                 Decimal('0.0')] for key in buckets.container.keys()],
               key=itemgetter(0))
    }

    monthly_start = start_value
    for index, record in enumerate(results['basis']):
        record[1] += (monthly_start + results['income'][index][1] +
                      results['money_in'][index][1] +
                      results['expense'][index][1])
        monthly_start = record[1]

    return results
Esempio n. 14
0
def budget_level(accounts=None, budget_value='0.0', year_to_date=True):
    """
    Calculates how much is spent in the accounts provided.
    :param accounts: account walker parameters to calculate spending in.
    :param budget_value: budget value for the month
    :param year_to_date: should a year to date be calculated as well

    :return: dictionary containing:
    balance - the current balance for the month
    month - the month number
    daysInMonth - the number of days in the month
    today - current day in the month
    budgetValue - the maximum allowed to be spent in this month

    Optional values returned if year_to_date is true:
    yearlyBalance - the amount spent in these accounts this year
    daysInYear - the number of days in the current year
    currentYearDay - the current year day for this year
    """
    accounts = accounts or []
    budget_value = Decimal(budget_value or '0.0')

    accounts = parse_walker_parameters(accounts)
    budget_value = Decimal(budget_value)

    balance = Decimal('0.0')

    for account in account_walker(**accounts):
        split_list = get_splits(account,
                                PeriodStart.this_month.date,
                                PeriodEnd.today.date,
                                debit=False)

        for split in split_list:
            balance += split.value

    data_payload = {
        'balance':
        balance,
        'month':
        PeriodEnd.today.date.month,
        'daysInMonth':
        monthrange(PeriodEnd.today.date.year, PeriodEnd.today.date.month)[1],
        'today':
        PeriodEnd.today.date.day,
        'budgetValue':
        budget_value
    }

    if year_to_date:
        yearly_balance = Decimal('0.0')

        for account in account_walker(**accounts):
            split_list = get_splits(account,
                                    PeriodStart.this_year.date,
                                    PeriodEnd.today.date,
                                    debit=False)

            for split in split_list:
                yearly_balance += split.value

        today = PeriodStart.today.date
        data_payload.update({
            'yearlyBalance':
            yearly_balance,
            'daysInYear':
            date(today.year, 12, 31).timetuple().tm_yday,
            'currentYearDay':
            today.timetuple().tm_yday
        })

    return data_payload
Esempio n. 15
0
def income_tax(income=None,
               tax=None,
               start=PeriodStart.this_year,
               end=PeriodEnd.this_year,
               tax_name='federal',
               tax_status='single',
               deductions=None,
               deduction=None):
    """
    Walk through all of the income accounts provided to determine tax owed based on tax tables.  Then use deductions,
    deduction_accounts to reduce income, and then calculate a simple tax owed based on the tax_name and tax_status
    information.  Will only use the account data between the start and end values.
    :param income: account walker parameters for the income accounts
    :param tax: account walker parameters for the tax paid accounts
    :param start: Period start date
    :param end: Period end date,
    :param tax_name: name of tax table to use
    :param tax_status: name of tax sub-table to use
    :param deductions: list of decimal definitions that should be deducted from the taxable income
    :param deduction: account walker parameters that should be used to reduce the taxable income as well
    :return: dictionary containing
    income - total taxable income made during the period
    tax_value - total calculated tax based on income value
    taxes_paid - total taxes paid into the tax accounts
    """

    income_accounts = income or []
    tax_accounts = tax or []
    deductions = deductions or []
    deduction_accounts = deduction or []

    income_accounts = parse_walker_parameters(income_accounts)
    tax_accounts = parse_walker_parameters(tax_accounts)
    period_start = PeriodStart(start)
    period_end = PeriodEnd(end)
    deduction_accounts = parse_walker_parameters(deduction_accounts)

    total_income = Decimal(0.0)
    total_taxes = Decimal(0.0)
    pre_tax_deductions = Decimal(0.0)

    # Find all of the deduction accounts, and store them in a list so that they can be walked when handling the
    # income from the income accounts
    deduction_account_names = set()
    for account in account_walker(**deduction_accounts):
        deduction_account_names.add(clean_account_name(account.fullname))

    # Calculate all of the income that has been received, and calculate all of the contributions to the deduction
    # accounts that will reduce tax burden.
    for account in account_walker(**income_accounts):
        for split in get_splits(account, period_start.date, period_end.date):
            value = split.value * -1  # negate the value because income is leaving these accounts
            total_income += value

            # Go through the split's parent and find all of the values that are in the deduction accounts as well
            transaction = split.transaction
            for t_split in transaction.splits:
                if clean_account_name(
                        t_split.account.fullname) in deduction_account_names:
                    pre_tax_deductions += t_split.value

    # Calculate all of the taxes that have been currently paid
    for account in account_walker(**tax_accounts):
        for split in get_splits(account, period_start.date, period_end.date):
            value = split.value
            total_taxes += value

    # Remove all of the deductions from the total income value
    for deduction in deductions:
        pre_tax_deductions += Decimal(deduction)

    # Remove all of the contributions from the income accounts that went into pre-tax accounts and any standard
    # deductions
    total_income -= pre_tax_deductions

    tax_value = calculate_tax(tax_name, tax_status, total_income)

    return {
        'income': total_income,
        'tax_value': tax_value,
        'taxes_paid': total_taxes
    }