Various cleanup in transaction and journal display code.

This commit is contained in:
James Cole 2017-11-04 07:10:21 +01:00
parent b4dc70244a
commit bb46d034cd
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
25 changed files with 885 additions and 543 deletions

View File

@ -73,6 +73,7 @@ class JournalCollector implements JournalCollectorInterface
'transaction_journals.encrypted',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'transaction_journals.updated_at',
'bills.name as bill_name',
'bills.name_encrypted as bill_name_encrypted',

View File

@ -125,11 +125,11 @@ class TransactionController extends Controller
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount();
$collector->removeFilter(InternalTransferFilter::class);
$journals = $collector->getPaginatedJournals();
$journals->setPath($path);
$transactions = $collector->getPaginatedJournals();
$transactions->setPath($path);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals', 'periods', 'start', 'end', 'moment'));
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'transactions', 'periods', 'start', 'end', 'moment'));
}

View File

@ -56,6 +56,8 @@ use FireflyIII\Support\Steam;
use FireflyIII\Support\Twig\AmountFormat;
use FireflyIII\Support\Twig\General;
use FireflyIII\Support\Twig\Journal;
use FireflyIII\Support\Twig\Loader\TransactionJournalLoader;
use FireflyIII\Support\Twig\Loader\TransactionLoader;
use FireflyIII\Support\Twig\PiggyBank;
use FireflyIII\Support\Twig\Rule;
use FireflyIII\Support\Twig\Transaction;
@ -83,6 +85,8 @@ class FireflyServiceProvider extends ServiceProvider
);
$config = app('config');
Twig::addExtension(new Functions($config));
Twig::addRuntimeLoader(new TransactionLoader);
Twig::addRuntimeLoader(new TransactionJournalLoader);
Twig::addExtension(new PiggyBank);
Twig::addExtension(new General);
Twig::addExtension(new Journal);

View File

@ -124,6 +124,7 @@ class JournalTasker implements JournalTaskerInterface
);
$transactions = [];
$transactionType = $journal->transactionType->type;
/** @var Transaction $entry */
foreach ($set as $entry) {
@ -132,6 +133,8 @@ class JournalTasker implements JournalTaskerInterface
$budget = $entry->budgets->first();
$category = $entry->categories->first();
$transaction = [
'journal_type' => $transactionType,
'updated_at' => $journal->updated_at,
'source_id' => $entry->id,
'source_amount' => $entry->amount,
'foreign_source_amount' => $entry->foreign_amount,

View File

@ -267,140 +267,4 @@ class Amount
];
}
/**
* @param TransactionJournal $journal
* @param bool $coloured
*
* @return string
*/
public function journalAmount(TransactionJournal $journal, bool $coloured = true): string
{
$amounts = [];
$transactions = $journal->transactions()->where('amount', '>', 0)->get();
/** @var TransactionModel $transaction */
foreach ($transactions as $transaction) {
// model some fields to fit "transactionAmount()":
$transaction->transaction_amount = $transaction->amount;
$transaction->transaction_foreign_amount = $transaction->foreign_amount;
$transaction->transaction_type_type = $journal->transactionType->type;
$transaction->transaction_currency_symbol = $transaction->transactionCurrency->symbol;
$transaction->transaction_currency_dp = $transaction->transactionCurrency->decimal_places;
if (!is_null($transaction->foreign_currency_id)) {
$transaction->foreign_currency_symbol = $transaction->foreignCurrency->symbol;
$transaction->foreign_currency_dp = $transaction->foreignCurrency->decimal_places;
}
$amounts[] = $this->transactionAmount($transaction, $coloured);
}
return join(' / ', $amounts);
}
/**
* @param TransactionJournal $journal
* @param bool $coloured
*
* @return string
*/
public function journalTotalAmount(TransactionJournal $journal, bool $coloured = true): string
{
$transactions = $journal->transactions()->where('amount', '>', 0)->get();
$totals = [];
$type = $journal->transactionType->type;
/** @var TransactionModel $transaction */
foreach ($transactions as $transaction) {
// model some fields to fit "transactionAmount()":
$currencyId = $transaction->transaction_currency_id;
if (!isset($totals[$currencyId])) {
$totals[$currencyId] = [
'amount' => '0',
'symbol' => $transaction->transactionCurrency->symbol,
'dp' => $transaction->transactionCurrency->decimal_places,
];
}
$totals[$currencyId]['amount'] = bcadd($transaction->amount, $totals[$currencyId]['amount']);
if (!is_null($transaction->foreign_currency_id)) {
$foreignId = $transaction->foreign_currency_id;
if (!isset($totals[$foreignId])) {
$totals[$foreignId] = [
'amount' => '0',
'symbol' => $transaction->foreignCurrency->symbol,
'dp' => $transaction->foreignCurrency->decimal_places,
];
}
$totals[$foreignId]['amount'] = bcadd($transaction->foreign_amount, $totals[$foreignId]['amount']);
}
}
$array = [];
foreach ($totals as $total) {
$currency = new TransactionCurrency;
$currency->symbol = $total['symbol'];
$currency->decimal_places = $total['dp'];
if ($type === TransactionType::WITHDRAWAL) {
$total['amount'] = bcmul($total['amount'], '-1');
}
$array[] = $this->formatAnything($currency, $total['amount']);
}
return join(' / ', $array);
}
/**
* This formats a transaction, IF that transaction has been "collected" using the JournalCollector.
*
* @param TransactionModel $transaction
* @param bool $coloured
*
* @return string
*/
public function transactionAmount(TransactionModel $transaction, bool $coloured = true): string
{
$amount = bcmul(app('steam')->positive(strval($transaction->transaction_amount)), '-1');
$format = '%s';
if ($transaction->transaction_type_type === TransactionType::DEPOSIT) {
$amount = bcmul($amount, '-1');
}
if ($transaction->transaction_type_type === TransactionType::TRANSFER) {
$amount = app('steam')->positive($amount);
$coloured = false;
$format = '<span class="text-info">%s</span>';
}
if ($transaction->transaction_type_type === TransactionType::OPENING_BALANCE) {
$amount = strval($transaction->transaction_amount);
}
$currency = new TransactionCurrency;
$currency->symbol = $transaction->transaction_currency_symbol;
$currency->decimal_places = $transaction->transaction_currency_dp;
$str = sprintf($format, $this->formatAnything($currency, $amount, $coloured));
if (!is_null($transaction->transaction_foreign_amount)) {
$amount = bcmul(app('steam')->positive(strval($transaction->transaction_foreign_amount)), '-1');
if ($transaction->transaction_type_type === TransactionType::DEPOSIT) {
$amount = bcmul($amount, '-1');
}
if ($transaction->transaction_type_type === TransactionType::TRANSFER) {
$amount = app('steam')->positive($amount);
$coloured = false;
$format = '<span class="text-info">%s</span>';
}
$currency = new TransactionCurrency;
$currency->symbol = $transaction->foreign_currency_symbol;
$currency->decimal_places = $transaction->foreign_currency_dp;
$str .= ' (' . sprintf($format, $this->formatAnything($currency, $amount, $coloured)) . ')';
}
return $str;
}
}

View File

@ -37,7 +37,7 @@ class CacheProperties
{
/** @var string */
protected $md5 = '';
protected $hash = '';
/** @var Collection */
protected $properties;
@ -66,15 +66,15 @@ class CacheProperties
*/
public function get()
{
return Cache::get($this->md5);
return Cache::get($this->hash);
}
/**
* @return string
*/
public function getMd5(): string
public function getHash(): string
{
return $this->md5;
return $this->hash;
}
/**
@ -85,9 +85,9 @@ class CacheProperties
if (getenv('APP_ENV') === 'testing') {
return false;
}
$this->md5();
$this->hash();
return Cache::has($this->md5);
return Cache::has($this->hash);
}
/**
@ -95,18 +95,18 @@ class CacheProperties
*/
public function store($data)
{
Cache::forever($this->md5, $data);
Cache::forever($this->hash, $data);
}
/**
* @return void
*/
private function md5()
private function hash()
{
$this->md5 = '';
$content = '';
foreach ($this->properties as $property) {
$this->md5 .= json_encode($property);
$content .= json_encode($property);
}
$this->md5 = md5($this->md5);
$this->hash = substr(sha1($content), 0, 16);
}
}

View File

@ -586,7 +586,7 @@ class ExpandedForm
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amt::getDefaultCurrency();
$currencies = Amt::getAllCurrencies();
$currencies = app('amount')->getAllCurrencies();
unset($options['currency']);
unset($options['placeholder']);

View File

@ -0,0 +1,47 @@
<?php
/**
* SingleCacheProperties.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\Support;
use Illuminate\Support\Collection;
/**
* Class CacheProperties
*
* @package FireflyIII\Support
*/
class SingleCacheProperties extends CacheProperties
{
/**
*
*/
public function __construct()
{
parent::__construct();
$this->properties = new Collection;
if (auth()->check()) {
$this->addProperty(auth()->user()->id);
}
}
}

View File

@ -59,9 +59,6 @@ class AmountFormat extends Twig_Extension
return [
$this->formatAmountByAccount(),
$this->formatAmountBySymbol(),
$this->transactionAmount(),
$this->journalAmount(),
$this->journalTotalAmount(),
$this->formatDestinationAfter(),
$this->formatDestinationBefore(),
$this->formatSourceAfter(),
@ -274,43 +271,4 @@ class AmountFormat extends Twig_Extension
);
}
/**
* @return Twig_SimpleFunction
*/
protected function journalAmount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'journalAmount', function (TransactionJournal $journal): string {
return app('amount')->journalAmount($journal, true);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function journalTotalAmount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'journalTotalAmount', function (TransactionJournal $journal): string {
return app('amount')->journalTotalAmount($journal, true);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
protected function transactionAmount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionAmount', function (TransactionModel $transaction): string {
return app('amount')->transactionAmount($transaction, true);
}, ['is_safe' => ['html']]
);
}
}

View File

@ -0,0 +1,487 @@
<?php
/**
* Transaction.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\Support\Twig\Extension;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Transaction as TransactionModel;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\SingleCacheProperties;
use Lang;
use Twig_Extension;
/**
* Class Transaction
*
* @package FireflyIII\Support\Twig\Extension
*/
class Transaction extends Twig_Extension
{
/**
* Can show the amount of a transaction, if that transaction has been collected by the journal collector.
*
* @param TransactionModel $transaction
*
* @return string
*/
public function amount(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('transaction-amount');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
$amount = bcmul(app('steam')->positive(strval($transaction->transaction_amount)), '-1');
$format = '%s';
$coloured = true;
if ($transaction->transaction_type_type === TransactionType::DEPOSIT) {
$amount = bcmul($amount, '-1');
}
if ($transaction->transaction_type_type === TransactionType::TRANSFER) {
$amount = app('steam')->positive($amount);
$coloured = false;
$format = '<span class="text-info">%s</span>';
}
if ($transaction->transaction_type_type === TransactionType::OPENING_BALANCE) {
$amount = strval($transaction->transaction_amount);
}
$currency = new TransactionCurrency;
$currency->symbol = $transaction->transaction_currency_symbol;
$currency->decimal_places = $transaction->transaction_currency_dp;
$str = sprintf($format, app('amount')->formatAnything($currency, $amount, $coloured));
if (!is_null($transaction->transaction_foreign_amount)) {
$amount = bcmul(app('steam')->positive(strval($transaction->transaction_foreign_amount)), '-1');
if ($transaction->transaction_type_type === TransactionType::DEPOSIT) {
$amount = bcmul($amount, '-1');
}
if ($transaction->transaction_type_type === TransactionType::TRANSFER) {
$amount = app('steam')->positive($amount);
$coloured = false;
$format = '<span class="text-info">%s</span>';
}
$currency = new TransactionCurrency;
$currency->symbol = $transaction->foreign_currency_symbol;
$currency->decimal_places = $transaction->foreign_currency_dp;
$str .= ' (' . sprintf($format, app('amount')->formatAnything($currency, $amount, $coloured)) . ')';
}
$cache->store($str);
return $str;
}
/**
* @param array $transaction
*
* @return string
*/
public function amountArray(array $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('transaction-array-amount');
$cache->addProperty($transaction['source_id']);
$cache->addProperty($transaction['destination_id']);
$cache->addProperty($transaction['updated_at']);
if ($cache->has()) {
return $cache->get();
}
// first display amount:
$amount = $transaction['journal_type'] === TransactionType::WITHDRAWAL ? $transaction['source_amount']
: $transaction['destination_amount'];
$fakeCurrency = new TransactionCurrency;
$fakeCurrency->decimal_places = $transaction['transaction_currency_dp'];
$fakeCurrency->symbol = $transaction['transaction_currency_symbol'];
$string = app('amount')->formatAnything($fakeCurrency, $amount, true);
// then display (if present) the foreign amount:
if(!is_null($transaction['foreign_source_amount'])) {
$amount = $transaction['journal_type'] === TransactionType::WITHDRAWAL ? $transaction['foreign_source_amount']
: $transaction['foreign_destination_amount'];
$fakeCurrency = new TransactionCurrency;
$fakeCurrency->decimal_places = $transaction['foreign_currency_dp'];
$fakeCurrency->symbol = $transaction['foreign_currency_symbol'];
$string .= ' ('.app('amount')->formatAnything($fakeCurrency, $amount, true).')';
}
$cache->store($string);
return $string;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function budgets(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('transaction-budgets');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
// journal has a budget:
if (isset($transaction->transaction_journal_budget_id)) {
$name = app('steam')->tryDecrypt($transaction->transaction_journal_budget_name);
$txt = sprintf('<a href="%s" title="%s">%s</a>', route('budgets.show', [$transaction->transaction_journal_budget_id]), $name, $name);
$cache->store($txt);
return $txt;
}
// transaction has a budget
if (isset($transaction->transaction_budget_id)) {
$name = app('steam')->tryDecrypt($transaction->transaction_budget_name);
$txt = sprintf('<a href="%s" title="%s">%s</a>', route('budgets.show', [$transaction->transaction_budget_id]), $name, $name);
$cache->store($txt);
return $txt;
}
// see if the transaction has a budget:
$budgets = $transaction->budgets()->get();
if ($budgets->count() === 0) {
$budgets = $transaction->transactionJournal()->first()->budgets()->get();
}
if ($budgets->count() > 0) {
$str = [];
foreach ($budgets as $budget) {
$str[] = sprintf('<a href="%s" title="%s">%s</a>', route('budgets.show', [$budget->id]), $budget->name, $budget->name);
}
$txt = join(', ', $str);
$cache->store($txt);
return $txt;
}
$txt = '';
$cache->store($txt);
return $txt;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function categories(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('transaction-categories');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
// journal has a category:
if (isset($transaction->transaction_journal_category_id)) {
$name = app('steam')->tryDecrypt($transaction->transaction_journal_category_name);
$txt = sprintf('<a href="%s" title="%s">%s</a>', route('categories.show', [$transaction->transaction_journal_category_id]), $name, $name);
$cache->store($txt);
return $txt;
}
// transaction has a category:
if (isset($transaction->transaction_category_id)) {
$name = app('steam')->tryDecrypt($transaction->transaction_category_name);
$txt = sprintf('<a href="%s" title="%s">%s</a>', route('categories.show', [$transaction->transaction_category_id]), $name, $name);
$cache->store($txt);
return $txt;
}
// see if the transaction has a category:
$categories = $transaction->categories()->get();
if ($categories->count() === 0) {
$categories = $transaction->transactionJournal()->first()->categories()->get();
}
if ($categories->count() > 0) {
$str = [];
foreach ($categories as $category) {
$str[] = sprintf('<a href="%s" title="%s">%s</a>', route('categories.show', [$category->id]), $category->name, $category->name);
}
$txt = join(', ', $str);
$cache->store($txt);
return $txt;
}
$txt = '';
$cache->store($txt);
return $txt;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function description(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('description');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
$description = $transaction->description;
if (strlen(strval($transaction->transaction_description)) > 0) {
$description = $transaction->transaction_description . '(' . $transaction->description . ')';
}
$cache->store($description);
return $description;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function destinationAccount(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('transaction-destination');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
$name = app('steam')->tryDecrypt($transaction->account_name);
$transactionId = intval($transaction->account_id);
$type = $transaction->account_type;
// name is present in object, use that one:
if (bccomp($transaction->transaction_amount, '0') === -1 && !is_null($transaction->opposing_account_id)) {
$name = $transaction->opposing_account_name;
$transactionId = intval($transaction->opposing_account_id);
$type = $transaction->opposing_account_type;
}
// Find the opposing account and use that one:
if (bccomp($transaction->transaction_amount, '0') === -1 && is_null($transaction->opposing_account_id)) {
// if the amount is negative, find the opposing account and use that one:
$journalId = $transaction->journal_id;
/** @var TransactionModel $other */
$other = TransactionModel::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
->where('amount', '=', bcmul($transaction->transaction_amount, '-1'))->where(
'identifier', $transaction->identifier
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->first(['transactions.account_id', 'accounts.encrypted', 'accounts.name', 'account_types.type']);
$name = app('steam')->tryDecrypt($other->name);
$transactionId = $other->account_id;
$type = $other->type;
}
if ($type === AccountType::CASH) {
$txt = '<span class="text-success">(' . trans('firefly.cash') . ')</span>';
$cache->store($txt);
return $txt;
}
$txt = sprintf('<a title="%1$s" href="%2$s">%1$s</a>', e($name), route('accounts.show', [$transactionId]));
$cache->store($txt);
return $txt;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function hasAttachments(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('attachments');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
$journalId = intval($transaction->journal_id);
$count = Attachment::whereNull('deleted_at')
->where('attachable_type', 'FireflyIII\Models\TransactionJournal')
->where('attachable_id', $journalId)
->count();
if ($count > 0) {
$res = sprintf('<i class="fa fa-paperclip" title="%s"></i>', Lang::choice('firefly.nr_of_attachments', $count, ['count' => $count]));
$cache->store($res);
return $res;
}
$res = '';
$cache->store($res);
return $res;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function icon(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('icon');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
switch ($transaction->transaction_type_type) {
case TransactionType::WITHDRAWAL:
$txt = sprintf('<i class="fa fa-long-arrow-left fa-fw" title="%s"></i>', trans('firefly.withdrawal'));
break;
case TransactionType::DEPOSIT:
$txt = sprintf('<i class="fa fa-long-arrow-right fa-fw" title="%s"></i>', trans('firefly.deposit'));
break;
case TransactionType::TRANSFER:
$txt = sprintf('<i class="fa fa-fw fa-exchange" title="%s"></i>', trans('firefly.transfer'));
break;
case TransactionType::OPENING_BALANCE:
$txt = sprintf('<i class="fa-fw fa fa-star-o" title="%s"></i>', trans('firefly.openingBalance'));
break;
default:
$txt = '';
break;
}
$cache->store($txt);
return $txt;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function isSplit(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('split');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
$journalId = intval($transaction->journal_id);
$count = TransactionModel::where('transaction_journal_id', $journalId)->whereNull('deleted_at')->count();
if ($count > 2) {
$res = '<i class="fa fa-fw fa-share-alt" aria-hidden="true"></i>';
$cache->store($res);
return $res;
}
$res = '';
$cache->store($res);
return $res;
}
/**
* @param TransactionModel $transaction
*
* @return string
*/
public function sourceAccount(TransactionModel $transaction): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('transaction-source');
$cache->addProperty($transaction->id);
$cache->addProperty($transaction->updated_at);
if ($cache->has()) {
return $cache->get();
}
// if the amount is negative, assume that the current account (the one in $transaction) is indeed the source account.
$name = app('steam')->tryDecrypt($transaction->account_name);
$transactionId = intval($transaction->account_id);
$type = $transaction->account_type;
// name is present in object, use that one:
if (bccomp($transaction->transaction_amount, '0') === 1 && !is_null($transaction->opposing_account_id)) {
$name = $transaction->opposing_account_name;
$transactionId = intval($transaction->opposing_account_id);
$type = $transaction->opposing_account_type;
}
// Find the opposing account and use that one:
if (bccomp($transaction->transaction_amount, '0') === 1 && is_null($transaction->opposing_account_id)) {
$journalId = $transaction->journal_id;
/** @var TransactionModel $other */
$other = TransactionModel::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
->where('amount', '=', bcmul($transaction->transaction_amount, '-1'))->where(
'identifier', $transaction->identifier
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->first(['transactions.account_id', 'accounts.encrypted', 'accounts.name', 'account_types.type']);
$name = app('steam')->tryDecrypt(intval($other->encrypted), $other->name);
$transactionId = $other->account_id;
$type = $other->type;
}
if ($type === AccountType::CASH) {
$txt = '<span class="text-success">(' . trans('firefly.cash') . ')</span>';
$cache->store($txt);
return $txt;
}
$txt = sprintf('<a title="%1$s" href="%2$s">%1$s</a>', e($name), route('accounts.show', [$transactionId]));
$cache->store($txt);
return $txt;
}
}

View File

@ -0,0 +1,92 @@
<?php
/**
* TransactionJournal.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\Support\Twig\Extension;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal as JournalModel;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\SingleCacheProperties;
use Twig_Extension;
class TransactionJournal extends Twig_Extension
{
/**
* @param JournalModel $journal
*
* @return string
*/
function totalAmount(JournalModel $journal): string
{
$cache = new SingleCacheProperties;
$cache->addProperty('total-amount');
$cache->addProperty($journal->id);
$cache->addProperty($journal->updated_at);
if ($cache->has()) {
return $cache->get();
}
$transactions = $journal->transactions()->where('amount', '>', 0)->get();
$totals = [];
$type = $journal->transactionType->type;
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$currencyId = $transaction->transaction_currency_id;
$currency = $transaction->transactionCurrency;
if (!isset($totals[$currencyId])) {
$totals[$currencyId] = [
'amount' => '0',
'currency' => $currency,
];
}
$totals[$currencyId]['amount'] = bcadd($transaction->amount, $totals[$currencyId]['amount']);
if (!is_null($transaction->foreign_currency_id)) {
$foreignId = $transaction->foreign_currency_id;
$foreign = $transaction->foreignCurrency;
if (!isset($totals[$foreignId])) {
$totals[$foreignId] = [
'amount' => '0',
'currency' => $foreign,
];
}
$totals[$foreignId]['amount'] = bcadd($transaction->foreign_amount, $totals[$foreignId]['amount']);
}
}
$array = [];
foreach ($totals as $total) {
if ($type === TransactionType::WITHDRAWAL) {
$total['amount'] = bcmul($total['amount'], '-1');
}
$array[] = app('amount')->formatAnything($total['currency'], $total['amount']);
}
$txt = join(' / ', $array);
$cache->store($txt);
return $txt;
}
}

View File

@ -32,7 +32,7 @@ use FireflyIII\Support\CacheProperties;
use Twig_Extension;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
use FireflyIII\Support\Twig\Extension\TransactionJournal as TransactionJournalExtension;
/**
* Class Journal
*
@ -83,6 +83,7 @@ class Journal extends Twig_Extension
{
$filters = [
$this->typeIcon(),
new Twig_SimpleFilter('journalTotalAmount', [TransactionJournalExtension::class, 'totalAmount'], ['is_safe' => ['html']]),
];
return $filters;

View File

@ -0,0 +1,57 @@
<?php
/**
* TransactionJournalLoader.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\Support\Twig\Loader;
use FireflyIII\Support\Twig\Extension\TransactionJournal;
use Twig_RuntimeLoaderInterface;
/**
* Class TransactionJournalLoader
*
* @package FireflyIII\Support\Twig\Extension
*/
class TransactionJournalLoader implements Twig_RuntimeLoaderInterface
{
/**
* Creates the runtime implementation of a Twig element (filter/function/test).
*
* @param string $class A runtime class
*
* @return object|null The runtime instance or null if the loader does not know how to create the runtime for this class
*/
public function load($class)
{
// implement the logic to create an instance of $class
// and inject its dependencies
// most of the time, it means using your dependency injection container
if (TransactionJournal::class === $class) {
return app(TransactionJournal::class);
}
return null;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* TransactionLoader.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\Support\Twig\Loader;
use FireflyIII\Support\Twig\Extension\Transaction;
use Twig_RuntimeLoaderInterface;
/**
* Class TransactionLoader
*
* @package FireflyIII\Support\Twig\Extension
*/
class TransactionLoader implements Twig_RuntimeLoaderInterface
{
/**
* Creates the runtime implementation of a Twig element (filter/function/test).
*
* @param string $class A runtime class
*
* @return object|null The runtime instance or null if the loader does not know how to create the runtime for this class
*/
public function load($class)
{
// implement the logic to create an instance of $class
// and inject its dependencies
// most of the time, it means using your dependency injection container
if (Transaction::class === $class) {
return app(Transaction::class);
}
return null;
}
}

View File

@ -23,12 +23,8 @@ declare(strict_types=1);
namespace FireflyIII\Support\Twig;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Transaction as TransactionModel;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
use Lang;
use FireflyIII\Support\Twig\Extension\Transaction as TransactionExtension;
use Steam;
use Twig_Extension;
use Twig_SimpleFilter;
@ -41,48 +37,22 @@ use Twig_SimpleFunction;
*/
class Transaction extends Twig_Extension
{
/**
* @return Twig_SimpleFunction
*/
public function attachmentIndicator(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'attachmentIndicator', function (int $journalId) {
$cache = new CacheProperties;
$cache->addProperty('attachments_journal');
$cache->addProperty($journalId);
if ($cache->has()) {
return $cache->get();
}
$count = Attachment::whereNull('deleted_at')
->where('attachable_type', 'FireflyIII\Models\TransactionJournal')
->where('attachable_id', $journalId)
->count();
if ($count > 0) {
$res = sprintf('<i class="fa fa-paperclip" title="%s"></i>', Lang::choice('firefly.nr_of_attachments', $count, ['count' => $count]));
$cache->store($res);
return $res;
}
$res = '';
$cache->store($res);
return $res;
}, ['is_safe' => ['html']]
);
}
/**
* @return array
*/
public function getFilters(): array
{
$filters = [
$this->typeIconTransaction(),
new Twig_SimpleFilter('transactionIcon', [TransactionExtension::class, 'icon'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionDescription', [TransactionExtension::class, 'description']),
new Twig_SimpleFilter('transactionIsSplit', [TransactionExtension::class, 'isSplit'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionHasAtt', [TransactionExtension::class, 'hasAttachments'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionAmount', [TransactionExtension::class, 'amount'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionArrayAmount', [TransactionExtension::class, 'amountArray'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionBudgets', [TransactionExtension::class, 'budgets'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionCategories', [TransactionExtension::class, 'categories'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionSourceAccount', [TransactionExtension::class, 'sourceAccount'], ['is_safe' => ['html']]),
new Twig_SimpleFilter('transactionDestinationAccount', [TransactionExtension::class, 'destinationAccount'], ['is_safe' => ['html']]),
];
return $filters;
@ -94,14 +64,8 @@ class Transaction extends Twig_Extension
public function getFunctions(): array
{
$functions = [
$this->transactionSourceAccount(),
$this->transactionDestinationAccount(),
$this->transactionBudgets(),
$this->transactionIdBudgets(),
$this->transactionCategories(),
$this->transactionIdCategories(),
$this->splitJournalIndicator(),
$this->attachmentIndicator(),
];
return $functions;
@ -117,107 +81,6 @@ class Transaction extends Twig_Extension
return 'transaction';
}
/**
* @return Twig_SimpleFunction
*/
public function splitJournalIndicator(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'splitJournalIndicator', function (int $journalId) {
$cache = new CacheProperties;
$cache->addProperty('is_split_journal');
$cache->addProperty($journalId);
if ($cache->has()) {
return $cache->get();
}
$count = TransactionModel::where('transaction_journal_id', $journalId)->whereNull('deleted_at')->count();
if ($count > 2) {
$res = '<i class="fa fa-fw fa-share-alt" aria-hidden="true"></i>';
$cache->store($res);
return $res;
}
$res = '';
$cache->store($res);
return $res;
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionBudgets(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionBudgets', function (TransactionModel $transaction): string {
return $this->getTransactionBudgets($transaction);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionCategories(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionCategories', function (TransactionModel $transaction): string {
return $this->getTransactionCategories($transaction);
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionDestinationAccount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionDestinationAccount', function (TransactionModel $transaction): string {
$name = Steam::decrypt(intval($transaction->account_encrypted), $transaction->account_name);
$transactionId = intval($transaction->account_id);
$type = $transaction->account_type;
// name is present in object, use that one:
if (bccomp($transaction->transaction_amount, '0') === -1 && !is_null($transaction->opposing_account_id)) {
$name = $transaction->opposing_account_name;
$transactionId = intval($transaction->opposing_account_id);
$type = $transaction->opposing_account_type;
}
// Find the opposing account and use that one:
if (bccomp($transaction->transaction_amount, '0') === -1 && is_null($transaction->opposing_account_id)) {
// if the amount is negative, find the opposing account and use that one:
$journalId = $transaction->journal_id;
/** @var TransactionModel $other */
$other = TransactionModel::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
->where('amount', '=', bcmul($transaction->transaction_amount, '-1'))->where(
'identifier', $transaction->identifier
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->first(['transactions.account_id', 'accounts.encrypted', 'accounts.name', 'account_types.type']);
$name = Steam::decrypt(intval($other->encrypted), $other->name);
$transactionId = $other->account_id;
$type = $other->type;
}
if ($type === AccountType::CASH) {
return '<span class="text-success">(cash)</span>';
}
return sprintf('<a title="%1$s" href="%2$s">%1$s</a>', e($name), route('accounts.show', [$transactionId]));
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
@ -247,84 +110,6 @@ class Transaction extends Twig_Extension
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionSourceAccount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionSourceAccount', function (TransactionModel $transaction): string {
// if the amount is negative, assume that the current account (the one in $transaction) is indeed the source account.
$name = Steam::decrypt(intval($transaction->account_encrypted), $transaction->account_name);
$transactionId = intval($transaction->account_id);
$type = $transaction->account_type;
// name is present in object, use that one:
if (bccomp($transaction->transaction_amount, '0') === 1 && !is_null($transaction->opposing_account_id)) {
$name = $transaction->opposing_account_name;
$transactionId = intval($transaction->opposing_account_id);
$type = $transaction->opposing_account_type;
}
// Find the opposing account and use that one:
if (bccomp($transaction->transaction_amount, '0') === 1 && is_null($transaction->opposing_account_id)) {
$journalId = $transaction->journal_id;
/** @var TransactionModel $other */
$other = TransactionModel::where('transaction_journal_id', $journalId)->where('transactions.id', '!=', $transaction->id)
->where('amount', '=', bcmul($transaction->transaction_amount, '-1'))->where(
'identifier', $transaction->identifier
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->first(['transactions.account_id', 'accounts.encrypted', 'accounts.name', 'account_types.type']);
$name = Steam::decrypt(intval($other->encrypted), $other->name);
$transactionId = $other->account_id;
$type = $other->type;
}
if ($type === AccountType::CASH) {
return '<span class="text-success">(cash)</span>';
}
return sprintf('<a title="%1$s" href="%2$s">%1$s</a>', e($name), route('accounts.show', [$transactionId]));
}, ['is_safe' => ['html']]
);
}
/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's 5.
*
* @return Twig_SimpleFilter
*/
public function typeIconTransaction(): Twig_SimpleFilter
{
return new Twig_SimpleFilter(
'typeIconTransaction', function (TransactionModel $transaction): string {
switch ($transaction->transaction_type_type) {
case TransactionType::WITHDRAWAL:
$txt = sprintf('<i class="fa fa-long-arrow-left fa-fw" title="%s"></i>', trans('firefly.withdrawal'));
break;
case TransactionType::DEPOSIT:
$txt = sprintf('<i class="fa fa-long-arrow-right fa-fw" title="%s"></i>', trans('firefly.deposit'));
break;
case TransactionType::TRANSFER:
$txt = sprintf('<i class="fa fa-fw fa-exchange" title="%s"></i>', trans('firefly.transfer'));
break;
case TransactionType::OPENING_BALANCE:
$txt = sprintf('<i class="fa-fw fa fa-star-o" title="%s"></i>', trans('firefly.openingBalance'));
break;
default:
$txt = '';
break;
}
return $txt;
}, ['is_safe' => ['html']]
);
}
/**
* @param TransactionModel $transaction
*

View File

@ -34,13 +34,14 @@
<td data-value="{{ link.source.description }}">
<a href="{{ route('transactions.show', [link.source_id]) }}">{{ link.source.description }}</a>
</td>
<td>{{ journalAmount(link.source) }}</td>
<td>{{ link.source|journalTotalAmount }}</td>
<td>{{ linkType.outward }}</td>
<td data-value="{{ link.destination.description }}">
<a href="{{ route('transactions.show', [link.destination_id]) }}">{{ link.destination.description }}</a>
</td>
<td>
{{ journalAmount(link.destination) }}
{{ link.destination|journalTotalAmount }}
</td>
</tr>
{% endfor %}

View File

@ -7,14 +7,10 @@
href="{{ route('transactions.show',transaction.journal_id) }}"
{% endif %}
>
{{ transaction|typeIconTransaction }}
{% if transaction.transaction_description|length > 0 %}
{{ transaction.transaction_description }} ({{ transaction.description }})
{% else %}
{{ transaction.description }}
{% endif %}
{{ transaction|transactionIcon }}
{{ transaction|transactionDescription }}
<span class="pull-right small">
{{ transactionAmount(transaction) }}
{{ transaction|transactionAmount }}
</span>
</a>
{% endfor %}

View File

@ -27,80 +27,8 @@
</tr>
</thead>
<tbody>
{% for transaction in journals %}
<tr class="drag" data-date="{{ transaction.date.format('Y-m-d') }}" data-id="{{ transaction.journal_id }}">
{# input buttons #}
<td class="hidden-xs">
<div class="select_single" style="display:none;">
<input name="select_all_single[]" class="select_all_single" value="{{ transaction.journal_id }}" type="checkbox"/>
</div>
<div class="btn-group btn-group-xs edit_buttons edit_tr_buttons">{% if sorting %}<a href="#" class="handle btn btn-default btn-xs"><i
class="fa fa-fw fa-arrows-v"></i></a>{% endif %}<a href="{{ route('transactions.edit',transaction.journal_id) }}"
class="btn btn-xs btn-default"><i class="fa fa-fw fa-pencil"></i></a><a
href="{{ route('transactions.delete',transaction.journal_id) }}" class="btn btn-xs btn-danger"><i
class="fa fa-fw fa-trash-o"></i></a></div>
</td>
{# icon #}
<td class="hidden-xs">
{{ transaction|typeIconTransaction }}
</td>
{# description #}
<td>
<a href="{{ route('transactions.show',transaction.journal_id) }}">
{% if transaction.transaction_description|length > 0 %}
{{ transaction.transaction_description }} ({{ transaction.description }})
{% else %}
{{ transaction.description }}
{% endif %}
</a>
{# is a split journal #}
{{ splitJournalIndicator(transaction.journal_id) }}
{# count attachments #}
{{ attachmentIndicator(transaction.journal_id) }}
</td>
<td style="text-align: right;">
<span style="margin-right:5px;">
{{ transactionAmount(transaction) }}
</span>
</td>
<td class="hidden-sm hidden-xs">
{{ transaction.date.formatLocalized(monthAndDayFormat) }}
</td>
<td class="hidden-xs hidden-sm hidden-md">
{{ transactionSourceAccount(transaction) }}
</td>
<td class="hidden-xs hidden-sm hidden-md">
{{ transactionDestinationAccount(transaction) }}
</td>
<!-- Do NOT hide the budget? -->
{% if not hideBudgets %}
<td class="hidden-xs">
{{ transactionBudgets(transaction) }}
</td>
{% endif %}
<!-- Do NOT hide the category? -->
{% if not hideCategories %}
<td class="hidden-xs">
{{ transactionCategories(transaction) }}
</td>
{% endif %}
<!-- Do NOT hide the bill? -->
{% if not hideBills %}
<td class="hidden-xs">
{% if transaction.bill_id %}
<a href="{{ route('bills.show',transaction.bill_id) }}">{{ transaction.bill_name }}</a>
{% endif %}
</td>
{% endif %}
</tr>
{% for transaction in transactions %}
{% include 'partials.transaction-row' %}
{% endfor %}
</tbody>
</table>

View File

@ -0,0 +1,65 @@
<tr class="drag" data-date="{{ transaction.date.format('Y-m-d') }}" data-id="{{ transaction.journal_id }}">
{# input buttons #}
<td class="hidden-xs">
<div class="select_single" style="display:none;">
<input name="select_all_single[]" class="select_all_single" value="{{ transaction.journal_id }}" type="checkbox"/>
</div>
<div class="btn-group btn-group-xs edit_buttons edit_tr_buttons">{% if sorting %}<a href="#" class="handle btn btn-default btn-xs"><i
class="fa fa-fw fa-arrows-v"></i></a>{% endif %}<a href="{{ route('transactions.edit',transaction.journal_id) }}"
class="btn btn-xs btn-default"><i class="fa fa-fw fa-pencil"></i></a><a
href="{{ route('transactions.delete',transaction.journal_id) }}" class="btn btn-xs btn-danger"><i
class="fa fa-fw fa-trash-o"></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 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>
{# Do NOT hide the budget? #}
{% if not hideBudgets %}
<td class="hidden-xs">
{{ transaction|transactionBudgets }}
</td>
{% endif %}
{# Do NOT hide the category? #}
{% if not hideCategories %}
<td class="hidden-xs">
{{ transaction|transactionCategories }}
</td>
{% endif %}
{# Do NOT hide the bill? #}
{% if not hideBills %}
<td class="hidden-xs">
{% if transaction.bill_id %}
<a href="{{ route('bills.show',transaction.bill_id) }}">{{ transaction.bill_name }}</a>
{% endif %}
</td>
{% endif %}
</tr>

View File

@ -11,68 +11,61 @@
{% if not hideDestination %}
<th class="hidden-xs">{{ trans('list.to') }}</th>
{% endif %}
<!-- Hide budgets? -->
{# Hide budgets? #}
{% if not hideBudget %}
<th class="hidden-xs"><i class="fa fa-tasks fa-fw" title="{{ trans('list.budget') }}"></i></th>
{% endif %}
<!-- Hide categories? -->
{# Hide categories? #}
{% if not hideCategory %}
<th class="hidden-xs"><i class="fa fa-bar-chart fa-fw" title="{{ trans('list.category') }}"></i></th>
{% endif %}
</tr>
</thead>
<tbody>
<!--
Make sum:
{# Make sum: #}
{% set sum = 0 %}
-->
{% for transaction in journals %}
<!-- add to sum
{% set sum = (sum + transaction.transaction_amount) %}
-->
<tr class="drag" data-date="{{ transaction.date.format('Y-m-d') }}" data-id="{{ transaction.journal_id }}">
<td class="hidden-xs">
{{ transaction|typeIconTransaction }}
{{ transaction|transactionIcon }}
</td>
<td>
<a href="{{ route('transactions.show',transaction.journal_id) }}">
{% if transaction.transaction_description|length > 0 %}
{{ transaction.transaction_description }} ({{ transaction.description }})
{% else %}
{{ transaction.description }}
{% endif %}
{{ transaction|transactionDescription }}
</a>
</td>
<td>
{# TODO replace with new format code #}
{{ transactionAmount(transaction) }}
{{ transaction|transactionAmount }}
</td>
<td class="hidden-sm hidden-xs">
{{ transaction.date.formatLocalized(monthAndDayFormat) }}
</td>
{% if not hideSource %}
<td class="hidden-xs">
{{ transactionSourceAccount(transaction) }}
{{ transaction|transactionSourceAccount }}
</td>
{% endif %}
{% if not hideDestination %}
<td class="hidden-xs">
{{ transactionDestinationAccount(transaction) }}
{{ transaction|transactionDestinationAccount }}
</td>
{% endif %}
<!-- Do NOT hide the budget? -->
{# Do NOT hide the budget? #}
{% if not hideBudget %}
<td class="hidden-xs">
{{ transactionBudgets(transaction) }}
{{ transaction|transactionBudgets }}
</td>
{% endif %}
<!-- Do NOT hide the category? -->
{# Do NOT hide the category? #}
{% if not hideCategory %}
<td class="hidden-xs">
{{ transactionCategories(transaction) }}
{{ transaction|transactionCategories }}
</td>
{% endif %}
</tr>

View File

@ -46,7 +46,7 @@
<a href="{{ route('transactions.delete',transaction.journal_id) }}" class="btn btn-xs btn-danger"><i class="fa fa-fw fa-trash-o"></i></a>
</div>
</td>
<td class="hide-icon">{{ transaction|typeIconTransaction }}</td>
<td class="hide-icon">{{ transaction|transactionIcon }}</td>
<td class="hide-description">
<a href="{{ route('transactions.show',transaction.journal_id) }}">
@ -59,7 +59,7 @@
</td>
<td class="hide-balance_before" style="text-align: right;">{{ formatAmountByCurrency(transaction.currency, transaction.before) }}</td>
<td class="hide-amount" style="text-align: right;">
{{ transactionAmount(transaction) }}
{{ transaction|transactionAmount }}
</td>
<td class="hide-balance_after" style="text-align: right;">{{ formatAmountByCurrency(transaction.currency, transaction.after) }}</td>
@ -104,17 +104,17 @@
<td class="hide-from">
{{ transactionSourceAccount(transaction) }}
{{ transaction|transactionSourceAccount }}
</td>
<td class="hide-to">
{{ transactionDestinationAccount(transaction) }}
{{ transaction|transactionDestinationAccount }}
</td>
<td class="hide-budget">
{{ transactionBudgets(transaction) }}
{{ transaction|transactionBudgets }}
</td>
<td class="hide-category">
{{ transactionCategories(transaction) }}
{{ transaction|transactionCategories }}
</td>
{% if transaction.bill_id %}
<td class="hide-bill">

View File

@ -28,7 +28,7 @@
class="fa fa-fw fa-trash-o"></i></a></div>
</td>
<td class="hidden-xs">
{{ transaction|typeIconTransaction }}
{{ transaction|transactionIcon }}
</td>
<td>
<a href="{{ route('transactions.show',transaction.journal_id) }}">
@ -39,7 +39,7 @@
{{ transaction.description }}
{% endif %}
</a>
{{ splitJournalIndicator(transaction.journal_id) }}
{{ transaction|transactionIsSplit }}
{% if transaction.transactionJournal.attachments|length > 0 %}
<i class="fa fa-paperclip"
@ -48,23 +48,23 @@
</td>
<td style="text-align: right;">
<span style="margin-right:5px;">
{{ transactionAmount(transaction) }}
{{ transaction|transactionAmount }}
</span>
</td>
<td class="hidden-sm hidden-xs">
{{ transaction.date.formatLocalized(monthAndDayFormat) }}
</td>
<td class="hidden-xs">
{{ transactionSourceAccount(transaction) }}
{{ transaction|transactionSourceAccount }}
</td>
<td class="hidden-xs">
{{ transactionDestinationAccount(transaction) }}
{{ transaction|transactionDestinationAccount }}
</td>
<td class="hidden-xs">
{{ transactionBudgets(transaction) }}
{{ transaction|transactionBudgets }}
</td>
<td class="hidden-xs">
{{ transactionCategories(transaction) }}
{{ transaction|transactionCategories }}
</td>
<td class="hidden-xs">
{% if transaction.bill_id %}

View File

@ -43,7 +43,8 @@
<a href="{{ route('transactions.show',journal.id) }}" title="{{ journal.description }}">{{ journal.description }}</a>
</td>
<td>
{{ journalAmount(journal) }}
{{ journal|journalTotalAmount }}
</td>
<td>
{{ journal.date.formatLocalized(monthAndDayFormat) }}

View File

@ -88,11 +88,13 @@
<tr>
<td>{{ 'total_amount'|_ }}</td>
<td>
{{ journalAmount(journal) }}
{{ journal|journalTotalAmount }}
{# if more transactions, list each one: #}
{% if transactions|length > 1 %}
({{ journalTotalAmount(journal) }})
({% for transaction in transactions %}{{ transaction|transactionArrayAmount }}{% if loop.index != loop.length %}, {% endif %}{% endfor %})
{% endif %}
</td>
</tr>
<tr>
@ -336,12 +338,12 @@
<a href="{{ route('transactions.show',link.destination.id) }}">
#{{ link.destination.id }}: {{ link.destination.description }}
</a>
({{ journalAmount(link.destination) }})
({{ link.destination|journalTotalAmount }})
{% else %}
{{ journalLinkTranslation('inward', link.linkType.inward) }}
<a href="{{ route('transactions.show',link.source.id) }}">
#{{ link.source.id }}: {{ link.source.description }}</a>
({{ journalAmount(link.source) }})
({{ link.source|journalTotalAmount }})
{% endif %}
{% if link.comment != "" %}
<br/><em>{{ link.comment }}</em>