Basic reconcile view for #736

This commit is contained in:
James Cole 2017-11-10 18:25:11 +01:00
parent b899628dbe
commit f0e195f33b
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
6 changed files with 208 additions and 26 deletions

View File

@ -257,7 +257,7 @@ class AccountController extends Controller
* *
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/ */
public function reconcile(Request $request, Account $account, string $moment = '') public function reconcile(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
{ {
if ($account->accountType->type === AccountType::INITIAL_BALANCE) { if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
return $this->redirectToOriginalAccount($account); return $this->redirectToOriginalAccount($account);
@ -270,21 +270,39 @@ class AccountController extends Controller
$currency = app('amount')->getDefaultCurrency(); $currency = app('amount')->getDefaultCurrency();
} }
// get start and end // no start or end:
$range = Preferences::get('viewRange', '1M')->data; $range = Preferences::get('viewRange', '1M')->data;
// get start and end
if(is_null($start) && is_null($end)) {
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range)); $start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range)); $end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
$startBalance = round(app('steam')->balance($account, $start), $currency->decimal_places); }
if(is_null($end)) {
$end = Navigation::endOfPeriod($start, $range);
}
$startDate = clone $start;
$startDate->subDays(1);
$startBalance = round(app('steam')->balance($account, $startDate), $currency->decimal_places);
$endBalance = round(app('steam')->balance($account, $end), $currency->decimal_places); $endBalance = round(app('steam')->balance($account, $end), $currency->decimal_places);
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type); $subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$subTitle = trans('firefly.reconcile_account', ['account' => $account->name]); $subTitle = trans('firefly.reconcile_account', ['account' => $account->name]);
if(strlen($moment) > 0 && $moment !== 'all') { // get the transactions
$start = new Carbon($moment); $selectionStart = clone $start;
$end = Navigation::endOfPeriod($start, $range); $selectionStart->subDays(7);
} $selectionEnd = clone $end;
$selectionEnd->addDays(5);
return view('accounts.reconcile', compact('account', 'currency', 'subTitleIcon', 'start', 'end', 'subTitle', 'startBalance', 'endBalance')); // grab transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))
->setRange($selectionStart, $selectionEnd)->withBudgetInformation()->withOpposingAccount()->withCategoryInformation();
$transactions = $collector->getJournals();
return view('accounts.reconcile', compact('account', 'currency', 'subTitleIcon', 'start', 'end', 'subTitle', 'startBalance', 'endBalance','transactions','selectionStart','selectionEnd'));
// prep for "specific date" view. // prep for "specific date" view.
if (strlen($moment) > 0 && $moment !== 'all') { if (strlen($moment) > 0 && $moment !== 'all') {
@ -292,14 +310,7 @@ class AccountController extends Controller
$end = Navigation::endOfPeriod($start, $range); $end = Navigation::endOfPeriod($start, $range);
} }
// grab journals:
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
if (!is_null($start)) {
$collector->setRange($start, $end);
}
$transactions = $collector->getPaginatedJournals();
$transactions->setPath(route('accounts.show', [$account->id, $moment]));
return view( return view(
'accounts.show', 'accounts.show',

37
public/js/ff/accounts/reconcile.js vendored Normal file
View File

@ -0,0 +1,37 @@
/*
* reconcile.js
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
$(function () {
"use strict";
$('input[type="date"]').on('change', showUpdateButton);
$('.update_view').on('click', updateView);
});
function showUpdateButton() {
$('.update_date_button').show();
}
function updateView() {
var startDate = $('input[name="start_date"]').val();
var endDate = $('input[name="end_date"]').val();
window.location = '/accounts/reconcile/2/' + startDate + '/' + endDate;
return false;
}

View File

@ -619,6 +619,8 @@ return [
'cash_accounts' => 'Cash accounts', 'cash_accounts' => 'Cash accounts',
'Cash account' => 'Cash account', 'Cash account' => 'Cash account',
'reconcile_account' => 'Reconcile account ":account"', 'reconcile_account' => 'Reconcile account ":account"',
'end_of_reconcile_period' => 'End of reconcile period: :period',
'start_of_reconcile_period' => 'Start of reconcile period: :period',
'cash' => 'cash', 'cash' => 'cash',
'account_type' => 'Account type', 'account_type' => 'Account type',
'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:', 'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:',

View File

@ -13,7 +13,7 @@
<h3 class="box-title">{{ 'reconcile_range'|_ }}</h3> <h3 class="box-title">{{ 'reconcile_range'|_ }}</h3>
</div> </div>
<div class="box-body no-padding"> <div class="box-body no-padding">
<table class="table"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
<th colspan="2" style="width:50%;">{{ 'start_balance'|_ }}</th> <th colspan="2" style="width:50%;">{{ 'start_balance'|_ }}</th>
@ -67,11 +67,12 @@
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr> <tr class="update_date_button" style="display:none;">
<td colspan="4"> <td colspan="4">
<a href="#" class="btn btn-default"> <a href="#" class="btn btn-default update_view">
{{ 'update'|_ }} {{ 'update_view'|_ }}
</a> </a>
<span class="text-muted">(unsaved progress will be lost!)</span>
</td> </td>
</tr> </tr>
</tfoot> </tfoot>
@ -84,8 +85,28 @@
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">{{ 'reconcile_options'|_ }}</h3> <h3 class="box-title">{{ 'reconcile_options'|_ }}</h3>
</div> </div>
<div class="box-body"> <div class="box-body no-padding">
Do something <table class="table table-hover">
<thead>
<tr>
<th style="width:50%;">{{ 'difference'|_ }}</th>
<th>{{ 'actions'|_ }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span id="difference"></span>
</td>
<td>
<div class="btn-group">
<a href="#" class="btn btn-default">Reconcile</a>
<a href="#" class="btn btn-default">Reconcile with transaction</a>
</div>
</td>
</tr>
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
@ -99,6 +120,111 @@
<h3 class="box-title">{{ 'transactions'|_ }}</h3> <h3 class="box-title">{{ 'transactions'|_ }}</h3>
</div> </div>
<div class="box-body"> <div class="box-body">
<table class="table table-striped table-condensed">
<thead>
<tr class="ignore">
<th class="hidden-xs" colspan="2">&nbsp;</th>
<th>{{ trans('list.description') }}</th>
<th style="text-align:right;">{{ trans('list.amount') }}</th>
<th class="hidden-xs hidden-sm hidden-md">{{ trans('list.reconcile') }}</th>
<th class="hidden-xs hidden-sm">{{ trans('list.date') }}</th>
<th class="hidden-xs hidden-sm hidden-md">{{ trans('list.from') }}</th>
<th class="hidden-xs hidden-sm hidden-md">{{ trans('list.to') }}</th>
<th class="hidden-xs"><i class="fa fa-tasks fa-fw" title="{{ trans('list.budget') }}"></i></th>
<th class="hidden-xs"><i class="fa fa-bar-chart fa-fw" title="{{ trans('list.category') }}"></i></th>
</tr>
</thead>
<tbody>
{# data for previous/next markers #}
{% set endSet = false %}
{% set startSet = false %}
{% for transaction in transactions %}
{# start marker #}
{% if transaction.date < start and startSet == false %}
<tr>
<td colspan="5">
&nbsp;
</td>
<td colspan="3">
<span class="label label-default">
{{ trans('firefly.start_of_reconcile_period', {period: start.formatLocalized(monthAndDayFormat) }) }}
</span>
</td>
<td colspan="2">
&nbsp;
</td>
</tr>
{% set startSet = true %}
{% endif %}
<tr data-date="{{ transaction.date.format('Y-m-d') }}" data-id="{{ transaction.journal_id }}"
data-transaction-id="{{ transaction.id }}">
<td class="hidden-xs">
<div class="btn-group btn-group-xs">
<a href="{{ route('transactions.edit',transaction.journal_id) }}" class="btn btn-xs btn-default"><i
class="fa fa-fw fa-pencil"></i></a>
</div>
</td>
{# icon #}
<td class="hidden-xs">
{{ transaction|transactionIcon }}
</td>
{# description #}
<td>
<a href="{{ route('transactions.show',transaction.journal_id) }}">
{{ transaction|transactionDescription }}
</a>
{# is a split journal #}
{{ transaction|transactionIsSplit }}
{# count attachments #}
{{ transaction|transactionHasAtt }}
</td>
<td style="text-align: right;"><span style="margin-right:5px;">{{ transaction|transactionAmount }}</span></td>
<td>
<input type="checkbox" name="reconciled[]" value="{{ transaction.amount }}" class="reconcile_checkbox">
</td>
<td class="hidden-sm hidden-xs">
{{ transaction.date.formatLocalized(monthAndDayFormat) }}
</td>
<td class="hidden-xs hidden-sm hidden-md">
{# all source accounts #}
{{ transaction|transactionSourceAccount }}
</td>
<td class="hidden-xs hidden-sm hidden-md">
{# all destination accounts #}
{{ transaction|transactionDestinationAccount }}
</td>
<td class="hidden-xs">
{{ transaction|transactionBudgets }}
</td>
<td class="hidden-xs">
{{ transaction|transactionCategories }}
</td>
</tr>
{# end marker #}
{% if transaction.date <= end and endSet == false %}
<tr>
<td colspan="5">
&nbsp;
</td>
<td colspan="3">
<span class="label label-default">
{{ trans('firefly.end_of_reconcile_period', {period: end.formatLocalized(monthAndDayFormat) }) }}
</span>
</td>
<td colspan="2">
&nbsp;
</td>
</tr>
{% set endSet = true %}
{% endif %}
{% endfor %}
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
@ -112,6 +238,8 @@
<script type="text/javascript"> <script type="text/javascript">
currencySymbol = "{{ currency.symbol }}"; currencySymbol = "{{ currency.symbol }}";
var accountID = {{ account.id }}; var accountID = {{ account.id }};
var startBalance = {{ startBalance }};
var endBalance = {{ endBalance }};
</script> </script>
<script src="js/ff/accounts/reconcile.js?v={{ FF_VERSION }}" type="text/javascript"></script> <script src="js/ff/accounts/reconcile.js?v={{ FF_VERSION }}" type="text/javascript"></script>
{% endblock %} {% endblock %}

View File

@ -48,7 +48,11 @@
<a href="#" class="btn btn-default mass_stop_select" style="display:none;"><i class="fa faw-fw fa-square-o" <a href="#" class="btn btn-default mass_stop_select" style="display:none;"><i class="fa faw-fw fa-square-o"
></i> {{ 'stop_selection'|_ }}</a> ></i> {{ 'stop_selection'|_ }}</a>
{% if showReconcile == true %} {% if showReconcile == true %}
<a href="{{ route('accounts.reconcile', [account.id, moment]) }}" class="btn btn-info mass_reconcile"><i class="fa fa-fw fa-check"></i> {{ 'reconcile_this_account'|_ }}</a> {% if moment == 'all' %}
<a href="{{ route('accounts.reconcile', [account.id, start.format('Ymd')]) }}" class="btn btn-info mass_reconcile"><i class="fa fa-fw fa-check"></i> {{ 'reconcile_this_account'|_ }}</a>
{% else %}
<a href="{{ route('accounts.reconcile', [account.id, start.format('Ymd'), end.format('Ymd')]) }}" class="btn btn-info mass_reconcile"><i class="fa fa-fw fa-check"></i> {{ 'reconcile_this_account'|_ }}</a>
{% endif %}
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -90,7 +90,7 @@ Route::group(
Route::get('{what}', ['uses' => 'AccountController@index', 'as' => 'index'])->where('what', 'revenue|asset|expense'); Route::get('{what}', ['uses' => 'AccountController@index', 'as' => 'index'])->where('what', 'revenue|asset|expense');
Route::get('create/{what}', ['uses' => 'AccountController@create', 'as' => 'create'])->where('what', 'revenue|asset|expense'); Route::get('create/{what}', ['uses' => 'AccountController@create', 'as' => 'create'])->where('what', 'revenue|asset|expense');
Route::get('edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'edit']); Route::get('edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'edit']);
Route::get('reconcile/{account}/{moment?}', ['uses' => 'AccountController@reconcile', 'as' => 'reconcile']); Route::get('reconcile/{account}/{start_date?}/{end_date?}', ['uses' => 'AccountController@reconcile', 'as' => 'reconcile']);
Route::get('delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'delete']); Route::get('delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'delete']);
Route::get('show/{account}/{moment?}', ['uses' => 'AccountController@show', 'as' => 'show']); Route::get('show/{account}/{moment?}', ['uses' => 'AccountController@show', 'as' => 'show']);