New code for #736

This commit is contained in:
James Cole 2017-11-15 06:29:49 +01:00
parent d413615943
commit 5530347bb2
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
9 changed files with 539 additions and 194 deletions

View File

@ -0,0 +1,173 @@
<?php
/**
* ReconcileController.php
* 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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Account;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Navigation;
use Preferences;
use Response;
use View;
/**
* Class ReconcileController
*
* @package FireflyIII\Http\Controllers\Account
*/
class ReconcileController extends Controller
{
/**
*
*/
public function __construct()
{
parent::__construct();
// translations:
$this->middleware(
function ($request, $next) {
View::share('mainTitleIcon', 'fa-credit-card');
View::share('title', trans('firefly.accounts'));
return $next($request);
}
);
}
/**
* @param Request $request
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse
*/
public function overview(Request $request, Account $account, Carbon $start, Carbon $end)
{
$startBalance = $request->get('startBalance');
$endBalance = $request->get('endBalance');
$transactions = $request->get('transactions');
$return = [
'is_zero' => false,
'post_uri' => route('accounts.reconcile.submit', [$account->id, $start->format('Ymd'), $end->format('Ymd')]),
'html' => '',
];
$return['html'] = view('accounts.reconcile.overview', compact('account', 'start', 'end'))->render();
return Response::json($return);
}
/**
* @param Account $account
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function reconcile(Account $account, Carbon $start = null, Carbon $end = null)
{
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
return $this->redirectToOriginalAccount($account);
}
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencyId = intval($account->getMeta('currency_id'));
$currency = $currencyRepos->find($currencyId);
if ($currencyId === 0) {
$currency = app('amount')->getDefaultCurrency();
}
// no start or end:
$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));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
}
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);
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$subTitle = trans('firefly.reconcile_account', ['account' => $account->name]);
// various links
$transactionsUri = route('accounts.reconcile.transactions', [$account->id, '%start%', '%end%']);
$overviewUri = route('accounts.reconcile.overview', [$account->id, '%start%', '%end%']);
$indexUri = route('accounts.reconcile', [$account->id, '%start%', '%end%']);
return view(
'accounts.reconcile.index', compact(
'account', 'currency', 'subTitleIcon', 'start', 'end', 'subTitle', 'startBalance', 'endBalance', 'transactionsUri',
'selectionStart', 'selectionEnd', 'overviewUri', 'indexUri'
)
);
}
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function transactions(Account $account, Carbon $start, Carbon $end)
{
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
return $this->redirectToOriginalAccount($account);
}
// get the transactions
$selectionStart = clone $start;
$selectionStart->subDays(3);
$selectionEnd = clone $end;
$selectionEnd->addDays(3);
// grab transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))
->setRange($selectionStart, $selectionEnd)->withBudgetInformation()->withOpposingAccount()->withCategoryInformation();
$transactions = $collector->getJournals();
$html = view('accounts.reconcile.transactions', compact('account', 'transactions', 'start', 'end', 'selectionStart', 'selectionEnd'))->render();
return Response::json(['html' => $html]);
}
}

View File

@ -250,74 +250,6 @@ class AccountController extends Controller
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
}
/**
* @param Request $request
* @param Account $account
* @param string $moment
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function reconcile(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
{
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
return $this->redirectToOriginalAccount($account);
}
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencyId = intval($account->getMeta('currency_id'));
$currency = $currencyRepos->find($currencyId);
if ($currencyId === 0) {
$currency = app('amount')->getDefaultCurrency();
}
// no start or end:
$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));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
}
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);
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$subTitle = trans('firefly.reconcile_account', ['account' => $account->name]);
// get the transactions
$selectionStart = clone $start;
$selectionStart->subDays(7);
$selectionEnd = clone $end;
$selectionEnd->addDays(5);
// 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.
if (strlen($moment) > 0 && $moment !== 'all') {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
}
return view(
'accounts.show',
compact('account', 'currency', 'moment', 'periods', 'subTitleIcon', 'transactions', 'subTitle', 'start', 'end', 'chartUri')
);
}
/**
* Show an account.
*

View File

@ -18,20 +18,178 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
var balanceDifference = 0;
var difference = 0;
var selectedAmount = 0;
var reconcileStarted = false;
/**
*
*/
$(function () {
"use strict";
$('input[type="date"]').on('change', showUpdateButton);
$('.update_view').on('click', updateView);
/*
Respond to changes in balance statements.
*/
$('input[type="number"]').on('change', function () {
if (reconcileStarted) {
calculateBalanceDifference();
difference = balanceDifference - selectedAmount;
updateDifference();
}
});
/*
Respond to changes in the date range.
*/
$('input[type="date"]').on('change', function () {
if (reconcileStarted) {
// hide original instructions.
$('.select_transactions_instruction').hide();
// show date-change warning
$('.date_change_warning').show();
// show update button
$('.change_date_button').show();
}
});
$('.change_date_button').click(startReconcile);
$('.start_reconcile').click(startReconcile);
$('.store_reconcile').click(storeReconcile);
});
function showUpdateButton() {
$('.update_date_button').show();
function storeReconcile() {
// get modal HTML:
var ids = [];
$.each($('.reconcile_checkbox:checked'), function (i, v) {
ids.push($(v).data('id'));
});
var variables = {
startBalance: parseFloat($('input[name="start_balance"]').val()),
endBalance: parseFloat($('input[name="end_balance"]').val()),
startDate: $('input[name="start_date"]').val(),
startEnd: $('input[name="end_date"]').val(),
transactions: ids
};
var uri = overviewUri.replace('%start%', $('input[name="start_date"]').val()).replace('%end%', $('input[name="end_date"]').val());
$.getJSON(uri, variables).done(function (data) {
if (data.is_zero === false) {
$('#defaultModal').empty().html(data.html).modal('show');
}
});
}
function updateView() {
var startDate = $('input[name="start_date"]').val();
var endDate = $('input[name="end_date"]').val();
window.location = '/accounts/reconcile/2/' + startDate + '/' + endDate;
/**
* What happens when you check a checkbox:
* @param e
*/
function checkReconciledBox(e) {
var el = $(e.target);
var amount = parseFloat(el.val());
console.log('Amount is ' + amount);
// if checked, add to selected amount
if (el.prop('checked') === true && el.data('younger') === false) {
console.log("Sum is: " + selectedAmount + " - " + amount + " = " + (selectedAmount - amount));
selectedAmount = selectedAmount - amount;
}
if (el.prop('checked') === false && el.data('younger') === false) {
console.log("Sum is: " + selectedAmount + " + " + amount + " = " + (selectedAmount + amount));
selectedAmount = selectedAmount + amount;
}
difference = balanceDifference - selectedAmount;
updateDifference();
allowReconcile();
}
/**
*
*/
function allowReconcile() {
var count = $('.reconcile_checkbox:checked').length;
console.log('Count checkboxes is ' + count);
if (count > 0) {
$('.store_reconcile').prop('disabled', false);
}
}
/**
* Calculate the difference between given start and end balance
* and put it in balanceDifference.
*/
function calculateBalanceDifference() {
var startBalance = parseFloat($('input[name="start_balance"]').val());
var endBalance = parseFloat($('input[name="end_balance"]').val());
balanceDifference = startBalance - endBalance;
if (balanceDifference < 0) {
balanceDifference = balanceDifference * -1;
}
}
function getTransactionsForRange() {
// clear out the box:
$('#transactions_holder').empty().append($('<p>').addClass('text-center').html('<i class="fa fa-fw fa-spin fa-spinner"></i>'));
var uri = transactionsUri.replace('%start%', $('input[name="start_date"]').val()).replace('%end%', $('input[name="end_date"]').val());
var index = indexUri.replace('%start%', $('input[name="start_date"]').val()).replace('%end%', $('input[name="end_date"]').val());
window.history.pushState('object or string', "Reconcile account", index);
$.getJSON(uri).done(placeTransactions);
}
function placeTransactions(data) {
$('#transactions_holder').empty().html(data.html);
// as long as the dates are equal, changing the balance does not matter.
calculateBalanceDifference();
difference = balanceDifference;
updateDifference();
// enable the check buttons:
$('.reconcile_checkbox').prop('disabled', false).unbind('change').change(checkReconciledBox);
// show the other instruction:
$('.select_transactions_instruction').show();
}
/**
*
* @returns {boolean}
*/
function startReconcile() {
reconcileStarted = true;
// hide the start button.
$('.start_reconcile').hide();
// hide the start instructions:
$('.update_balance_instruction').hide();
// hide date-change warning
$('.date_change_warning').hide();
// hide update button
$('.change_date_button').hide();
getTransactionsForRange();
return false;
}
function updateDifference() {
var addClass = 'text-info';
if (difference > 0) {
addClass = 'text-success';
}
if (difference < 0) {
addClass = 'text-danger';
}
$('#difference').addClass(addClass).text(accounting.formatMoney(difference));
}

View File

@ -619,8 +619,19 @@ return [
'cash_accounts' => 'Cash accounts',
'Cash account' => 'Cash account',
'reconcile_account' => 'Reconcile account ":account"',
'end_of_reconcile_period' => 'End of reconcile period: :period',
'start_of_reconcile_period' => 'Start of reconcile period: :period',
'end_of_reconcile_period' => 'End of reconcile period: :period',
'start_of_reconcile_period' => 'Start of reconcile period: :period',
'start_balance' => 'Start balance',
'end_balance' => 'End balance',
'update_balance_dates_instruction' => 'Match the amounts and dates above to your bank statement, and press "Start reconciling"',
'select_transactions_instruction' => 'Select the transactions that appear on your bank statement.',
'select_range_and_balance' => 'First verify the date-range and balances. Then press "Start reconciling"',
'date_change_instruction' => 'If you change the date range now, any progress will be lost.',
'update_selection' => 'Update selection',
'store_reconcile' => 'Store reconciliation',
'reconcile_options' => 'Reconciliation options',
'reconcile_range' => 'Reconciliation range',
'start_reconcile' => 'Start reconciling',
'cash' => 'cash',
'account_type' => 'Account type',
'save_transactions_by_moving' => 'Save these transaction(s) by moving them to another account:',

View File

@ -75,9 +75,13 @@
<div class="select_transactions_instruction" style="display:none;">
{{ 'select_transactions_instruction'|_ }}
</div>
<div class="date_change_warning text-danger" style="display:none;">
{{ 'date_change_instruction'|_ }}
</div>
</td>
<td>
<a href="#" class="btn btn-default start_reconcile">{{ 'start_reconcile'|_ }}</a>
<a href="#" class="btn btn-default change_date_button" style="display: none;">{{ 'update_selection'|_ }}</a>
</td>
</tr>
</tfoot>
@ -124,120 +128,9 @@
<h3 class="box-title">{{ 'transactions'|_ }}</h3>
</div>
<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 %}
{# 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 %}
<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>
{% if transaction.reconciled %}
{{ transaction|transactionReconciled }}
{% else %}
<input type="checkbox" name="reconciled[]"
data-younger="{% if transaction.date > end %}true{% else %}false{% endif %}"
value="{{ transaction.transaction_amount }}" data-id="{{ transaction.id }}" disabled class="reconcile_checkbox">
{% endif %}
</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>
{% endfor %}
</tbody>
</table>
<div id="transactions_holder">
<p class="text-center lead">{{ 'select_range_and_balance'|_ }}</p>
</div>
</div>
</div>
</div>
@ -253,6 +146,9 @@
var accountID = {{ account.id }};
var startBalance = {{ startBalance }};
var endBalance = {{ endBalance }};
var transactionsUri = '{{ transactionsUri }}';
var overviewUri = '{{ overviewUri }}';
var indexUri = '{{ indexUri }}';
</script>
<script src="js/ff/accounts/reconcile.js?v={{ FF_VERSION }}" type="text/javascript"></script>
{% endblock %}

View File

@ -0,0 +1,39 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span><span class="sr-only">{{ 'close'|_ }}</span>
</button>
<h4 class="modal-title">Overview of reconciliation
</h4>
</div>
<form style="display: inline;" id="income" action="some route" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>
<input type="hidden" name="end" value="{{ end.format('Y-m-d') }}"/>
You have selected X transactions. Total value X. Difference is zero
reconcile will go ahead. (so no popup actually)
Difference is X or -X. X = you have too much money in Firefly III register. -X = you are missing amount X
in your Firefly III register.
Please correct this first, or allow firefly to create a reconcilliation transaction. You can always edit or delete this later:
[X] Create a reconciling withdrawal for amount X
[X] Create a reconciling deposit for amount X.
<div class="input-group">
<div class="input-group-addon">{{ getCurrencySymbol()|raw }}</div>
<input step="any" class="form-control" id="amount" value="{{ available }}" autocomplete="off" name="amount" type="number"/>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
<button type="submit" class="btn btn-primary">{{ 'update_amount'|_ }}</button>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,131 @@
<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 %}
{# 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 %}
<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>
{% if transaction.reconciled %}
{{ transaction|transactionReconciled }}
{% else %}
<input type="checkbox" name="reconciled[]"
data-younger="{% if transaction.date > end %}true{% else %}false{% endif %}"
value="{{ transaction.transaction_amount }}" data-id="{{ transaction.id }}" disabled class="reconcile_checkbox">
{% endif %}
</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>
{% endfor %}
{# if the start marker has not been generated yet, do it now, at the end of the loop. #}
{% if 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 %}
</tbody>
</table>

View File

@ -21,7 +21,7 @@
{# description #}
<td>
{# count attachments #}
{# is reconciled? #}
{{ transaction|transactionReconciled }}
<a href="{{ route('transactions.show',transaction.journal_id) }}">

View File

@ -90,10 +90,15 @@ Route::group(
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('edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'edit']);
Route::get('reconcile/{account}/{start_date?}/{end_date?}', ['uses' => 'AccountController@reconcile', 'as' => 'reconcile']);
Route::get('delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'delete']);
Route::get('show/{account}/{moment?}', ['uses' => 'AccountController@show', 'as' => 'show']);
// reconcile routes:
Route::get('reconcile/{account}/index/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@reconcile', 'as' => 'reconcile']);
Route::get('reconcile/{account}/transactions/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@transactions', 'as' => 'reconcile.transactions']);
Route::get('reconcile/{account}/overview/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@overview', 'as' => 'reconcile.overview']);
Route::post('reconcile/{account}/submit/{start_date?}/{end_date?}', ['uses' => 'Account\ReconcileController@submit', 'as' => 'reconcile.submit']);
Route::post('store', ['uses' => 'AccountController@store', 'as' => 'store']);
Route::post('update/{account}', ['uses' => 'AccountController@update', 'as' => 'update']);
Route::post('destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'destroy']);