mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
First attempt at audit report (uses lots of queries).
This commit is contained in:
parent
8116644526
commit
33bf373151
@ -7,11 +7,13 @@ use FireflyIII\Helpers\Report\BalanceReportHelperInterface;
|
|||||||
use FireflyIII\Helpers\Report\BudgetReportHelperInterface;
|
use FireflyIII\Helpers\Report\BudgetReportHelperInterface;
|
||||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Session;
|
use Session;
|
||||||
|
use Steam;
|
||||||
use View;
|
use View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,6 +130,25 @@ class ReportController extends Controller
|
|||||||
return $this->defaultMonth($reportType, $start, $end, $accounts);
|
return $this->defaultMonth($reportType, $start, $end, $accounts);
|
||||||
case 'audit':
|
case 'audit':
|
||||||
|
|
||||||
|
return $this->auditReport($start, $end, $accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
private function auditReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||||
|
{
|
||||||
|
bcscale(2);
|
||||||
|
/** @var ARI $repos */
|
||||||
|
|
||||||
|
$repos = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||||
View::share(
|
View::share(
|
||||||
'subTitle', trans(
|
'subTitle', trans(
|
||||||
'firefly.report_audit',
|
'firefly.report_audit',
|
||||||
@ -139,11 +160,64 @@ class ReportController extends Controller
|
|||||||
);
|
);
|
||||||
View::share('subTitleIcon', 'fa-calendar');
|
View::share('subTitleIcon', 'fa-calendar');
|
||||||
|
|
||||||
throw new FireflyException('Unfortunately, reports of the type "' . e($reportType) . '" are not yet available. ');
|
$auditData = [];
|
||||||
break;
|
$dayBefore = clone $start;
|
||||||
|
$dayBefore->subDay();
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
// balance the day before:
|
||||||
|
$id = $account->id;
|
||||||
|
$first = $repos->oldestJournalDate($account);
|
||||||
|
$last = $repos->newestJournalDate($account);
|
||||||
|
$exists = false;
|
||||||
|
$journals = new Collection;
|
||||||
|
$dayBeforeBalance = Steam::balance($account, $dayBefore);
|
||||||
|
|
||||||
|
if ($start->between($first, $last) || $end->between($first, $last)) {
|
||||||
|
$exists = true;
|
||||||
|
$journals = $repos->getJournalsInRange($account, $start, $end);
|
||||||
|
$journals = $journals->reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$startBalance = $dayBeforeBalance;
|
||||||
|
foreach ($journals as $journal) {
|
||||||
|
$journal->before = $startBalance;
|
||||||
|
|
||||||
|
// get currently relevant transaction:
|
||||||
|
$transaction = $journal->transactions->filter(
|
||||||
|
function (Transaction $t) use ($account) {
|
||||||
|
return $t->account_id === $account->id;
|
||||||
|
}
|
||||||
|
)->first();
|
||||||
|
|
||||||
|
$newBalance = bcadd($startBalance, $transaction->amount);
|
||||||
|
$journal->after = $newBalance;
|
||||||
|
$startBalance = $newBalance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$journals = $journals->reverse();
|
||||||
|
|
||||||
|
|
||||||
|
$auditData[$id]['journals'] = $journals;
|
||||||
|
$auditData[$id]['exists'] = $exists;
|
||||||
|
$auditData[$id]['end'] = $end->formatLocalized(trans('config.month_and_day'));
|
||||||
|
$auditData[$id]['endBalance'] = Steam::balance($account, $end);
|
||||||
|
$auditData[$id]['dayBefore'] = $dayBefore->formatLocalized(trans('config.month_and_day'));
|
||||||
|
$auditData[$id]['dayBeforeBalance'] = $dayBeforeBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$reportType = 'audit';
|
||||||
|
$accountIds = join(',', $accounts->pluck('id')->toArray());
|
||||||
|
|
||||||
|
$hideable = ['buttons', 'icon', 'description', 'balance_before', 'amount', 'balance_after', 'date', 'book_date', 'process_date', 'interest_date',
|
||||||
|
'from', 'to', 'budget', 'category', 'bill', 'create_date', 'update_date',
|
||||||
|
];
|
||||||
|
$defaultShow = ['icon', 'description', 'balance_before', 'amount', 'balance_after', 'date', 'to'];
|
||||||
|
|
||||||
|
return view('reports.audit.report', compact('start', 'end', 'reportType', 'accountIds', 'accounts', 'auditData', 'hideable', 'defaultShow'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -280,6 +280,43 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getJournalsInRange(Account $account, Carbon $start, Carbon $end): Collection
|
||||||
|
{
|
||||||
|
$query = $this->user
|
||||||
|
->transactionJournals()
|
||||||
|
->expanded()
|
||||||
|
->with(
|
||||||
|
[
|
||||||
|
'transactions' => function (HasMany $q) {
|
||||||
|
$q->orderBy('amount', 'ASC');
|
||||||
|
},
|
||||||
|
'transactionType',
|
||||||
|
'transactionCurrency',
|
||||||
|
'budgets',
|
||||||
|
'categories',
|
||||||
|
'bill',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->where('transactions.account_id', $account->id)
|
||||||
|
->after($start)
|
||||||
|
->before($end)
|
||||||
|
->orderBy('transaction_journals.date', 'DESC')
|
||||||
|
->orderBy('transaction_journals.order', 'ASC')
|
||||||
|
->orderBy('transaction_journals.id', 'DESC');
|
||||||
|
|
||||||
|
$set = $query->get(TransactionJournal::QUERYFIELDS);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the accounts of a user that have piggy banks connected to them.
|
* Get the accounts of a user that have piggy banks connected to them.
|
||||||
*
|
*
|
||||||
@ -387,6 +424,56 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date of the very last transaction in this account.
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function newestJournalDate(Account $account): Carbon
|
||||||
|
{
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
$journal = TransactionJournal::
|
||||||
|
leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->where('transactions.account_id', $account->id)
|
||||||
|
->orderBy('transaction_journals.date', 'ASC')
|
||||||
|
->first(['transaction_journals.*']);
|
||||||
|
if (is_null($journal)) {
|
||||||
|
$date = new Carbon;
|
||||||
|
$date->addYear(); // in the future.
|
||||||
|
} else {
|
||||||
|
$date = $journal->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date of the very first transaction in this account.
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function oldestJournalDate(Account $account): Carbon
|
||||||
|
{
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
$journal = TransactionJournal::
|
||||||
|
leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->where('transactions.account_id', $account->id)
|
||||||
|
->orderBy('transaction_journals.date', 'DESC')
|
||||||
|
->first(['transaction_journals.*']);
|
||||||
|
if (is_null($journal)) {
|
||||||
|
$date = new Carbon;
|
||||||
|
$date->addYear(); // in the future.
|
||||||
|
} else {
|
||||||
|
$date = $journal->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
*
|
*
|
||||||
|
@ -129,6 +129,15 @@ interface AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getJournals(Account $account, int $page): LengthAwarePaginator;
|
public function getJournals(Account $account, int $page): LengthAwarePaginator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getJournalsInRange(Account $account, Carbon $start, Carbon $end): Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the accounts of a user that have piggy banks connected to them.
|
* Get the accounts of a user that have piggy banks connected to them.
|
||||||
*
|
*
|
||||||
@ -151,6 +160,24 @@ interface AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function leftOnAccount(Account $account, Carbon $date): string;
|
public function leftOnAccount(Account $account, Carbon $date): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date of the very last transaction in this account.
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function newestJournalDate(Account $account): Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date of the very first transaction in this account.
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function oldestJournalDate(Account $account): Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
*
|
*
|
||||||
|
114
public/js/reports/audit/all.js
Normal file
114
public/js/reports/audit/all.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* all.js
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* globals hideable */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by sander on 01/04/16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// scan current selection of checkboxes and put them in a cookie:
|
||||||
|
var arr;
|
||||||
|
if ((readCookie('audit-option-checkbox') !== null)) {
|
||||||
|
arr = readCookie('audit-option-checkbox').split(',');
|
||||||
|
arr.forEach(function (val) {
|
||||||
|
$('input[type="checkbox"][value="' + val + '"]').prop('checked', true);
|
||||||
|
});
|
||||||
|
console.log('arr from cookie is ' + arr)
|
||||||
|
} else {
|
||||||
|
// no cookie? read list, store in array 'arr'
|
||||||
|
// all account ids:
|
||||||
|
arr = readCheckboxes();
|
||||||
|
}
|
||||||
|
storeCheckboxes(arr);
|
||||||
|
|
||||||
|
|
||||||
|
// process options:
|
||||||
|
showOnlyColumns(arr);
|
||||||
|
|
||||||
|
// respond to click each button:
|
||||||
|
$('.audit-option-checkbox').click(clickColumnOption);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function clickColumnOption() {
|
||||||
|
"use strict";
|
||||||
|
var newArr = readCheckboxes();
|
||||||
|
showOnlyColumns(newArr);
|
||||||
|
storeCheckboxes(newArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeCheckboxes(checkboxes) {
|
||||||
|
"use strict";
|
||||||
|
// store new cookie with those options:
|
||||||
|
console.log('Store new cookie with those options: ' + checkboxes);
|
||||||
|
createCookie('audit-option-checkbox', checkboxes, 365);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCheckboxes() {
|
||||||
|
"use strict";
|
||||||
|
var checkboxes = [];
|
||||||
|
$.each($('.audit-option-checkbox'), function (i, v) {
|
||||||
|
var c = $(v);
|
||||||
|
if (c.prop('checked')) {
|
||||||
|
//url += c.val() + ',';
|
||||||
|
checkboxes.push(c.val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('arr is now (default): ' + checkboxes);
|
||||||
|
return checkboxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showOnlyColumns(checkboxes) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
for (var i = 0; i < hideable.length; i++) {
|
||||||
|
var opt = hideable[i];
|
||||||
|
if(checkboxes.indexOf(opt) > -1) {
|
||||||
|
console.log(opt + ' is in checkboxes');
|
||||||
|
$('td.hide-' + opt).show();
|
||||||
|
$('th.hide-' + opt).show();
|
||||||
|
} else {
|
||||||
|
console.log(opt + ' is NOT in checkboxes');
|
||||||
|
$('th.hide-' + opt).hide();
|
||||||
|
$('td.hide-' + opt).hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createCookie(name, value, days) {
|
||||||
|
"use strict";
|
||||||
|
var expires;
|
||||||
|
|
||||||
|
if (days) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = "; expires=" + date.toGMTString();
|
||||||
|
} else {
|
||||||
|
expires = "";
|
||||||
|
}
|
||||||
|
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCookie(name) {
|
||||||
|
"use strict";
|
||||||
|
var nameEQ = encodeURIComponent(name) + "=";
|
||||||
|
var ca = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < ca.length; i++) {
|
||||||
|
var c = ca[i];
|
||||||
|
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||||
|
if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'buttons' => 'Buttons',
|
||||||
|
'icon' => 'Icon',
|
||||||
|
'create_date' => 'Created at',
|
||||||
|
'update_date' => 'Updated at',
|
||||||
|
'balance_before' => 'Balance before',
|
||||||
|
'balance_after' => 'Balance after',
|
||||||
'name' => 'Name',
|
'name' => 'Name',
|
||||||
'role' => 'Role',
|
'role' => 'Role',
|
||||||
'currentBalance' => 'Current balance',
|
'currentBalance' => 'Current balance',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{ journals.render|raw }}
|
{{ journals.render|raw }}
|
||||||
|
|
||||||
<table class="table table-hover {% if sorting %}sortable-table{% endif %}">
|
<table class="table table-hover table-compressed {% if sorting %}sortable-table{% endif %}">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="ignore">
|
<tr class="ignore">
|
||||||
<th class="hidden-xs" colspan="2"> </th>
|
<th class="hidden-xs" colspan="2"> </th>
|
||||||
|
@ -6,6 +6,28 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
<!-- options block -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'options'|_ }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
<ul class="list-inline">
|
||||||
|
{% for hide in hideable %}
|
||||||
|
<li><input
|
||||||
|
{% if hide in defaultShow %}checked{% endif %}
|
||||||
|
type="checkbox" class="audit-option-checkbox" name="option[]" value="{{ hide }}" id="option_{{ hide }}" /> <label for="option_{{ hide }}" style="font-weight:normal;">{{ trans('list.'~hide) }}</label></li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% for account in accounts %}
|
{% for account in accounts %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||||
@ -13,8 +35,9 @@
|
|||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">{{ account.name }}</h3>
|
<h3 class="box-title">{{ account.name }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body">
|
|
||||||
{% if not auditData[account.id].exists %}
|
{% if not auditData[account.id].exists %}
|
||||||
|
<div class="box-body">
|
||||||
<em>
|
<em>
|
||||||
No activity was recorded
|
No activity was recorded
|
||||||
on account <a href="{{ route('accounts.show',account.id) }}"
|
on account <a href="{{ route('accounts.show',account.id) }}"
|
||||||
@ -23,21 +46,23 @@
|
|||||||
{{ start }} and
|
{{ start }} and
|
||||||
{{ end }}.
|
{{ end }}.
|
||||||
</em>
|
</em>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>
|
<div class="box-body table-responsive no-padding">
|
||||||
|
<p style="padding:10px;">
|
||||||
Account balance of <a href="{{ route('accounts.show',account.id) }}"
|
Account balance of <a href="{{ route('accounts.show',account.id) }}"
|
||||||
title="{{ account.name }}">{{ account.name }}</a>
|
title="{{ account.name }}">{{ account.name }}</a>
|
||||||
at the end of {{ auditData[account.id].end }} was:
|
at the end of {{ auditData[account.id].end }} was:
|
||||||
{{ auditData[account.id].endBalance|formatAmount }}
|
{{ auditData[account.id].endBalance|formatAmount }}
|
||||||
</p>
|
</p>
|
||||||
{% include 'list/journals-extended.twig' with {'journals': auditData[account.id].journals,'account':account} %}
|
{% include 'reports/partials/journals-audit.twig' with {'journals': auditData[account.id].journals,'account':account} %}
|
||||||
<p>
|
<p style="padding:10px;">
|
||||||
Account balance of <a href="{{ route('accounts.show',account.id) }}" title="{{ account.name }}">{{ account.name }}</a>
|
Account balance of <a href="{{ route('accounts.show',account.id) }}" title="{{ account.name }}">{{ account.name }}</a>
|
||||||
at the end of {{ auditData[account.id].dayBefore }} was:
|
at the end of {{ auditData[account.id].dayBefore }} was:
|
||||||
{{ auditData[account.id].dayBeforeBalance|formatAmount }}
|
{{ auditData[account.id].dayBeforeBalance|formatAmount }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -47,4 +72,8 @@
|
|||||||
{% block styles %}
|
{% block styles %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
var hideable = {{ hideable|json_encode|raw }};
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="js/reports/audit/all.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
96
resources/views/reports/partials/journals-audit.twig
Normal file
96
resources/views/reports/partials/journals-audit.twig
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{{ journals.render|raw }}
|
||||||
|
|
||||||
|
<table class="table table-hover table-compressed">
|
||||||
|
<thead>
|
||||||
|
<tr class="ignore">
|
||||||
|
<th class="hide-buttons"> </th>
|
||||||
|
<th class="hide-icon"> </th>
|
||||||
|
|
||||||
|
<th class="hide-description">{{ trans('list.description') }}</th>
|
||||||
|
<th class="hide-balance_before">{{ trans('list.balance_before') }}</th>
|
||||||
|
<th class="hide-amount">{{ trans('list.amount') }}</th>
|
||||||
|
<th class="hide-balance_after">{{ trans('list.balance_after') }}</th>
|
||||||
|
|
||||||
|
<th class="hide-date">{{ trans('list.date') }}</th>
|
||||||
|
<th class="hide-book_date">{{ trans('list.book_date') }}</th>
|
||||||
|
<th class="hide-process_date">{{ trans('list.process_date') }}</th>
|
||||||
|
<th class="hide-interest_date">{{ trans('list.interest_date') }}</th>
|
||||||
|
|
||||||
|
<th class="hide-from">{{ trans('list.from') }}</th>
|
||||||
|
<th class="hide-to">{{ trans('list.to') }}</th>
|
||||||
|
|
||||||
|
<th class="hide-budget"><i class="fa fa-tasks fa-fw" title="{{ trans('list.budget') }}"></i></th>
|
||||||
|
<th class="hide-category"><i class="fa fa-bar-chart fa-fw" title="{{ trans('list.category') }}"></i></th>
|
||||||
|
<th class="hide-bill">{{ trans('list.bill') }}</th>
|
||||||
|
|
||||||
|
<th class="hide-create_date">{{ trans('list.create_date') }}</th>
|
||||||
|
<th class="hide-update_date">{{ trans('list.update_date') }}</th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for journal in journals %}
|
||||||
|
<tr data-date="{{ journal.date.format('Y-m-d') }}" data-id="{{ journal.id }}">
|
||||||
|
<td class="hide-buttons">
|
||||||
|
<div class="btn-group btn-group-xs">
|
||||||
|
<a href="{{ route('transactions.edit',journal.id) }}" class="btn btn-xs btn-default"><i class="fa fa-fw fa-pencil"></i></a>
|
||||||
|
<a href="{{ route('transactions.delete',journal.id) }}" class="btn btn-xs btn-danger"><i class="fa fa-fw fa-trash-o"></i></a></div></td>
|
||||||
|
<td class="hide-icon">{{ journal|typeIcon }}</td>
|
||||||
|
|
||||||
|
<td class="hide-description"><a href="{{ route('transactions.show',journal.id) }}" title="{{ journal.description }}">{{ journal.description }}</a></td>
|
||||||
|
<td class="hide-balance_before">{{ journal.before|formatAmount }}</td>
|
||||||
|
<td class="hide-amount">{{ journal|formatJournal }}</td>
|
||||||
|
<td class="hide-balance_after">{{ journal.after|formatAmount }}</td>
|
||||||
|
|
||||||
|
<td class="hide-date">{{ journal.date.formatLocalized(monthAndDayFormat) }}</td>
|
||||||
|
<td class="hide-book_date">{{ journal.book_date.formatLocalized(monthAndDayFormat) }}</td>
|
||||||
|
<td class="hide-process_date">{{ journal.process_date.formatLocalized(monthAndDayFormat) }}</td>
|
||||||
|
<td class="hide-interest_date">{{ journal.interest_date.formatLocalized(monthAndDayFormat) }}</td>
|
||||||
|
|
||||||
|
<td class="hide-from">
|
||||||
|
{% if journal.source_account_type == 'Cash account' %}
|
||||||
|
<span class="text-success">(cash)</span>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ route('accounts.show',journal.source_account_id) }}">{{ journal.source_account_name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="hide-to">
|
||||||
|
{% if journal.destination_account_type == 'Cash account' %}
|
||||||
|
<span class="text-success">(cash)</span>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ route('accounts.show',journal.destination_account_id) }}">{{ journal.destination_account_name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
{% if journal.budgets[0] %}
|
||||||
|
<td class="hide-budget"><a href="{{ route('budgets.show',journal.budgets[0].id) }}">{{ journal.budgets[0].name }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td class="hide-budget"><em>{{ 'no_budget'|_ }}</em></td>
|
||||||
|
{% endif %}
|
||||||
|
{% if journal.categories[0] %}
|
||||||
|
<td class="hide-category"><a href="{{ route('categories.show',journal.categories[0].id) }}">{{ journal.categories[0].name }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td class="hide-category"><em>{{ 'no_category'|_ }}</em></td>
|
||||||
|
{% endif %}
|
||||||
|
{% if journal.bill_id %}
|
||||||
|
<td class="hide-bill"><i class="fa fa-fw fa-rotate-right" title="{{ trans('list.bill') }}"></i> <a
|
||||||
|
href="{{ route('bills.show',journal.bill_id) }}">{{ journal.bill.name }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td class="hide-bill"> </td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<td class="hide-create_date">
|
||||||
|
{{ journal.created_at.formatLocalized(dateTimeFormat) }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="hide-update_date">
|
||||||
|
{{ journal.updated_at.formatLocalized(dateTimeFormat) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{ journals.render|raw }}
|
Loading…
Reference in New Issue
Block a user