This commit is contained in:
James Cole
2017-12-09 21:49:19 +01:00
parent 1fec7d6271
commit 4998eaeaf1
19 changed files with 876 additions and 41 deletions

View File

@@ -786,6 +786,7 @@ return [
'report_default' => 'Default financial report between :start and :end',
'report_audit' => 'Transaction history overview between :start and :end',
'report_category' => 'Category report between :start and :end',
'report_account' => 'Expense/revenue account report between :start and :end',
'report_budget' => 'Budget report between :start and :end',
'report_tag' => 'Tag report between :start and :end',
'quick_link_reports' => 'Quick links',
@@ -821,6 +822,7 @@ return [
'report_type_category' => 'Category report',
'report_type_budget' => 'Budget report',
'report_type_tag' => 'Tag report',
'report_type_account' => 'Combined account report',
'more_info_help' => 'More information about these types of reports can be found in the help pages. Press the (?) icon in the top right corner.',
'report_included_accounts' => 'Included accounts',
'report_date_range' => 'Date range',
@@ -873,49 +875,52 @@ return [
'budget_chart_click' => 'Please click on a budget name in the table above to see a chart.',
'category_chart_click' => 'Please click on a category name in the table above to see a chart.',
'in_out_accounts' => 'Earned and spent per combined account',
'in_out_accounts_period' => 'Earned and spent, grouped by :period',
'in_out_per_category' => 'Earned and spent per category',
'out_per_budget' => 'Spent per budget',
// charts:
'chart' => 'Chart',
'month' => 'Month',
'budget' => 'Budget',
'spent' => 'Spent',
'spent_in_budget' => 'Spent in budget',
'left_to_spend' => 'Left to spend',
'earned' => 'Earned',
'overspent' => 'Overspent',
'left' => 'Left',
'no_budget' => '(no budget)',
'max-amount' => 'Maximum amount',
'min-amount' => 'Minumum amount',
'journal-amount' => 'Current bill entry',
'name' => 'Name',
'date' => 'Date',
'paid' => 'Paid',
'unpaid' => 'Unpaid',
'day' => 'Day',
'budgeted' => 'Budgeted',
'period' => 'Period',
'balance' => 'Balance',
'sum' => 'Sum',
'average' => 'Average',
'balanceFor' => 'Balance for :name',
'chart' => 'Chart',
'month' => 'Month',
'budget' => 'Budget',
'spent' => 'Spent',
'spent_in_budget' => 'Spent in budget',
'left_to_spend' => 'Left to spend',
'earned' => 'Earned',
'overspent' => 'Overspent',
'left' => 'Left',
'max-amount' => 'Maximum amount',
'min-amount' => 'Minumum amount',
'journal-amount' => 'Current bill entry',
'name' => 'Name',
'date' => 'Date',
'paid' => 'Paid',
'unpaid' => 'Unpaid',
'day' => 'Day',
'budgeted' => 'Budgeted',
'period' => 'Period',
'balance' => 'Balance',
'sum' => 'Sum',
'average' => 'Average',
'balanceFor' => 'Balance for :name',
// piggy banks:
'add_money_to_piggy' => 'Add money to piggy bank ":name"',
'piggy_bank' => 'Piggy bank',
'new_piggy_bank' => 'New piggy bank',
'store_piggy_bank' => 'Store new piggy bank',
'stored_piggy_bank' => 'Store new piggy bank ":name"',
'account_status' => 'Account status',
'left_for_piggy_banks' => 'Left for piggy banks',
'sum_of_piggy_banks' => 'Sum of piggy banks',
'saved_so_far' => 'Saved so far',
'left_to_save' => 'Left to save',
'suggested_amount' => 'Suggested monthly amount to save',
'add_money_to_piggy_title' => 'Add money to piggy bank ":name"',
'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"',
'add' => 'Add',
'no_money_for_piggy' => 'You have no money to put in this piggy bank.',
'add_money_to_piggy' => 'Add money to piggy bank ":name"',
'piggy_bank' => 'Piggy bank',
'new_piggy_bank' => 'New piggy bank',
'store_piggy_bank' => 'Store new piggy bank',
'stored_piggy_bank' => 'Store new piggy bank ":name"',
'account_status' => 'Account status',
'left_for_piggy_banks' => 'Left for piggy banks',
'sum_of_piggy_banks' => 'Sum of piggy banks',
'saved_so_far' => 'Saved so far',
'left_to_save' => 'Left to save',
'suggested_amount' => 'Suggested monthly amount to save',
'add_money_to_piggy_title' => 'Add money to piggy bank ":name"',
'remove_money_from_piggy_title' => 'Remove money from piggy bank ":name"',
'add' => 'Add',
'no_money_for_piggy' => 'You have no money to put in this piggy bank.',
'remove' => 'Remove',
'max_amount_add' => 'The maximum amount you can add is',

View File

@@ -0,0 +1,438 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, accountIds, expenseIds, start, end) }}
{% endblock %}
{% block content %}
{# in/out + In/out per per periode #}
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'in_out_accounts'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding" id="inOutAccounts">
{# loading indicator #}
<div class="overlay">
<i class="fa fa-refresh fa-spin"></i>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12" id="inOutPeriod">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'in_out_accounts_period'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding">
{# loading indicator #}
<div class="overlay">
<i class="fa fa-refresh fa-spin"></i>
</div>
</div>
</div>
</div>
</div>
{# chart #}
<div class="row">
<div class="col-lg-12">
<div class="box" id="incomeAndExpensesChart">
<div class="box-header with-border">
<h3 class="box-title">{{ 'income_and_expenses'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="in-out-chart" style="width:100%;height:400px;" height="400" width="100%"></canvas>
</div>
</div>
</div>
</div>
{# in/out category + out per budget #}
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'in_out_per_category'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding" id="inOutCategory">
{# loading indicator #}
<div class="overlay">
<i class="fa fa-refresh fa-spin"></i>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'out_per_budget'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding" id="inOutBudget">
{# loading indicator #}
<div class="overlay">
<i class="fa fa-refresh fa-spin"></i>
</div>
</div>
</div>
</div>
</div>
{# expenses top 10 + income top 10 #}
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'expenses'|_ }} ({{ trans('firefly.topX', {number: listLength}) }})</h3>
</div>
<div class="box-body table-responsive no-padding" id="topXExpense">
{# loading indicator #}
<div class="overlay">
<i class="fa fa-refresh fa-spin"></i>
</div>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'income'|_ }} ({{ trans('firefly.topX', {number: listLength}) }})</h3>
</div>
<div class="box-body table-responsive no-padding" id="topXincome">
{# loading indicator #}
<div class="overlay">
<i class="fa fa-refresh fa-spin"></i>
</div>
</div>
</div>
</div>
</div>
{#
<div class="row">
{% if categories.count > 1 %}
<div class="col-lg-2 col-md-3">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'income_per_category'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="categories-in-pie-chart" style="margin:0 auto;" height="150" width="150"></canvas>
<label style="font-weight:normal;">
<input type="checkbox" id="categories-in-pie-chart-checked">
<small>{{ 'include_income_not_in_category'|_ }}</small>
</label>
</div>
</div>
</div>
<div class="col-lg-2 col-md-3">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'expense_per_category'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="categories-out-pie-chart" style="margin:0 auto;" height="150" width="150"></canvas>
<label style="font-weight:normal;">
<input type="checkbox" id="categories-out-pie-chart-checked">
<small>{{ 'include_expense_not_in_category'|_ }}</small>
</label>
</div>
</div>
</div>
{% endif %}
<div class="col-lg-2 col-md-3" id="pieCharts">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'income_per_account'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="accounts-in-pie-chart" style="margin:0 auto;" height="150" width="150"></canvas>
<label style="font-weight:normal;">
<input type="checkbox" id="accounts-in-pie-chart-checked">
<small>{{ 'include_income_not_in_account'|_ }}</small>
</label>
</div>
</div>
</div>
<div class="col-lg-2 col-md-3">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'expense_per_account'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="accounts-out-pie-chart" style="margin:0 auto;" height="150" width="150"></canvas>
<label style="font-weight:normal;">
<input type="checkbox" id="accounts-out-pie-chart-checked">
<small>{{ 'include_expense_not_in_account'|_ }}</small>
</label>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="box" id="incomeAndExpensesChart">
<div class="box-header with-border">
<h3 class="box-title">{{ 'income_and_expenses'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="in-out-chart" style="width:100%;height:400px;" height="400" width="100%"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
{% if averageExpenses|length > 0 %}
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'average_spending_per_account'|_ }}</h3>
</div>
<div class="box-body table-responsive no-padding">
<table class="table table-hover sortable">
<thead>
<tr>
<th data-defaultsign="az">{{ 'account'|_ }}</th>
<th data-defaultsign="_19" style="text-align: right;">{{ 'spent_average'|_ }}</th>
<th data-defaultsign="_19" style="text-align: right;">{{ 'total'|_ }}</th>
<th data-defaultsign="_19">{{ 'transaction_count'|_ }}</th>
</tr>
</thead>
<tbody>
{% for row in averageExpenses %}
{% if loop.index > listLength %}
<tr class="overListLength">
{% else %}
<tr>
{% endif %}
<td data-value="{{ row.name }}">
<a href="{{ route('accounts.show', row.id) }}">{{ row.name }}</a>
</td>
<td data-value="{{ row.average }}" style="text-align: right;">
{{ row.average|formatAmount }}
</td>
<td data-value="{{ row.sum }}" style="text-align: right;">
{{ row.sum|formatAmount }}
</td>
<td data-value="{{ row.count }}">
{{ row.count }}
</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
{% if averageExpenses|length > listLength %}
<tr>
<td colspan="4" class="active">
<a href="#" class="listLengthTrigger">{{ trans('firefly.show_full_list',{number:incomeTopLength}) }}</a>
</td>
</tr>
{% endif %}
</tfoot>
</table>
</div>
</div>
</div>
{% endif %}
{% if topExpenses.count > 0 %}
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'expenses'|_ }} ({{ trans('firefly.topX', {number: listLength}) }})</h3>
</div>
<div class="box-body">
<table class="table table-hover sortable">
<thead>
<tr>
<th data-defaultsort="disabled">{{ 'description'|_ }}</th>
<th data-defaultsign="month">{{ 'date'|_ }}</th>
<th data-defaultsign="az">{{ 'account'|_ }}</th>
<th data-defaultsign="_19" style="text-align: right;">{{ 'amount'|_ }}</th>
</tr>
</thead>
<tbody>
{% for row in topExpenses %}
{% if loop.index > listLength %}
<tr class="overListLength">
{% else %}
<tr>
{% endif %}
<td data-sortable="false">
<a href="{{ route('transactions.show', row.journal_id) }}">
{% if row.transaction_description|length > 0 %}
{{ row.transaction_description }} ({{ row.description }})
{% else %}
{{ row.description }}
{% endif %}
</a>
</td>
<td data-value="{{ row.date.format('Y-m-d') }}">
{{ row.date.formatLocalized(monthAndDayFormat) }}
</td>
<td data-value="{{ row.opposing_account_name }}">
<a href="{{ route('accounts.show', row.opposing_account_id) }}">
{{ row.opposing_account_name }}
</a>
</td>
<td data-value="{{ row.transaction_amount }}" style="text-align: right;">
{{ row.transaction_amount|formatAmount }}
</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
{% if topExpenses|length > listLength %}
<tr>
<td colspan="3" class="active">
<a href="#" class="listLengthTrigger">{{ trans('firefly.show_full_list',{number:incomeTopLength}) }}</a>
</td>
</tr>
{% endif %}
</tfoot>
</table>
</div>
</div>
</div>
{% endif %}
</div>
<div class="row">
{% if averageIncome|length > 0 %}
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'average_income_per_account'|_ }}</h3>
</div>
<div class="box-body">
<table class="table table-hover sortable">
<thead>
<tr>
<th data-defaultsign="az">{{ 'account'|_ }}</th>
<th data-defaultsign="_19">{{ 'income_average'|_ }}</th>
<th data-defaultsign="_19">{{ 'total'|_ }}</th>
<th data-defaultsign="_19">{{ 'transaction_count'|_ }}</th>
</tr>
</thead>
<tbody>
{% for row in averageIncome %}
<tr>
<td data-value="{{ row.name }}">
<a href="{{ route('accounts.show', row.id) }}">{{ row.name }}</a>
</td>
<td data-value="{{ row.average }}">
{{ row.average|formatAmount }}
</td>
<td data-value="{{ row.sum }}">
{{ row.sum|formatAmount }}
</td>
<td data-value="{{ row.count }}">
{{ row.count }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
<div class="col-lg-6">
{% if topIncome.count > 0 %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'income'|_ }} ({{ trans('firefly.topX', {number: listLength}) }})</h3>
</div>
<div class="box-body">
<table class="table table-hover sortable">
<thead>
<tr>
<th data-defaultsort="disabled">{{ 'description'|_ }}</th>
<th data-defaultsign="month">{{ 'date'|_ }}</th>
<th data-defaultsign="az">{{ 'account'|_ }}</th>
<th data-defaultsign="_19">{{ 'amount'|_ }}</th>
</tr>
</thead>
<tbody>
{% for row in topIncome %}
{% if loop.index > listLength %}
<tr class="overListLength">
{% else %}
<tr>
{% endif %}
<td>
<a href="{{ route('transactions.show', row.journal_id) }}">
{% if row.transaction_description|length > 0 %}
{{ row.transaction_description }} ({{ row.description }})
{% else %}
{{ row.description }}
{% endif %}
</a>
</td>
<td data-value="{{ row.date.format('Y-m-d H-i-s') }}">
{{ row.date.formatLocalized(monthAndDayFormat) }}
</td>
<td data-value="{{ row.opposing_account_name }}">
<a href="{{ route('accounts.show', row.opposing_account_id) }}">
{{ row.opposing_account_name }}
</a>
</td>
<td data-value="{{ row.transaction_amount }}">
{{ row.transaction_amount|formatAmount }}
</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
{% if topIncome.count > listLength %}
<tr>
<td colspan="3" class="active">
<a href="#" class="listLengthTrigger">{{ trans('firefly.show_full_list',{number:incomeTopLength}) }}</a>
</td>
</tr>
{% endif %}
</tfoot>
</table>
</div>
</div>
{% endif %}
</div>
</div>
#}
{% endblock %}
{% block scripts %}
<script type="text/javascript" src="js/lib/Chart.bundle.min.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="js/ff/charts.defaults.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="js/ff/charts.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="js/lib/bootstrap-sortable.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript">
// to report another URL:
var startDate = '{{ start.format('Ymd') }}';
var endDate = '{{ end.format('Ymd') }}';
var accountIds = '{{ accountIds }}';
var categoryIds = '{{ categoryIds }}';
// chart uri's
var categoryIncomeUri = '{{ route('chart.category.category-income', [accountIds, categoryIds, start.format('Ymd'), end.format('Ymd'),'OTHERS']) }}';
var categoryExpenseUri = '{{ route('chart.category.category-expense', [accountIds, categoryIds, start.format('Ymd'), end.format('Ymd'),'OTHERS']) }}';
var accountIncomeUri = '{{ route('chart.category.account-income', [accountIds, categoryIds, start.format('Ymd'), end.format('Ymd'),'OTHERS']) }}';
var accountExpenseUri = '{{ route('chart.category.account-expense', [accountIds, categoryIds, start.format('Ymd'), end.format('Ymd'),'OTHERS']) }}';
var mainUri = '{{ route('chart.category.main', [accountIds, categoryIds, start.format('Ymd'), end.format('Ymd')]) }}';
</script>
<script type="text/javascript" src="js/ff/reports/category/all.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="js/ff/reports/category/month.js?v={{ FF_VERSION }}"></script>
{% endblock %}
{% block styles %}
<link rel="stylesheet" href="css/bootstrap-sortable.css?v={{ FF_VERSION }}" type="text/css" media="all"/>
{% endblock %}

View File

@@ -29,6 +29,7 @@
<option label="{{ 'report_type_budget'|_ }}" value="budget">{{ 'report_type_budget'|_ }}</option>
<option label="{{ 'report_type_category'|_ }}" value="category">{{ 'report_type_category'|_ }}</option>
<option label="{{ 'report_type_tag'|_ }}" value="tag">{{ 'report_type_tag'|_ }}</option>
<option label="{{ 'report_type_account'|_ }}" value="account">{{ 'report_type_account'|_ }}</option>
</select>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<div class="form-group">
<label for="inputExpRevAccounts" class="col-sm-3 control-label">{{ 'select_expense_revenue'|_ }}</label>
<div class="col-sm-9">
<select id="inputExpRevAccounts" name="exp_rev[]" multiple="multiple" class="form-control">
{% for account in set %}
<option value="{{ account.id }}" label="{{ account.name }}">{{ account.name }}</option>
{% endfor %}
</select>
</div>
</div>