Refactored accountRepository::getJournals > accountTasker > getJournals

This commit is contained in:
James Cole
2016-10-09 21:36:03 +02:00
parent 5bb8c6a366
commit e94ae126fd
25 changed files with 843 additions and 167 deletions

View File

@@ -218,7 +218,7 @@ class AccountController extends Controller
$page = intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
$set = $tasker->getJournalsInPeriod(new Collection([$account]), [], $start, $end);
$count = $set->count();
$subSet = $set->splice($offset, $pageSize);
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);
@@ -269,13 +269,13 @@ class AccountController extends Controller
}
/**
* @param ARI $repository
* @param Account $account
* @param string $date
* @param AccountTaskerInterface $tasker
* @param Account $account
* @param string $date
*
* @return View
*/
public function showWithDate(ARI $repository, Account $account, string $date)
public function showWithDate(AccountTaskerInterface $tasker, Account $account, string $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;
@@ -286,7 +286,7 @@ class AccountController extends Controller
$page = $page === 0 ? 1 : $page;
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
$set = $tasker->getJournalsInPeriod(new Collection([$account]), [], $start, $end);
$count = $set->count();
$subSet = $set->splice($offset, $pageSize);
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);

View File

@@ -249,7 +249,7 @@ class BudgetController extends Controller
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$journals = $repository->journalsInPeriodWithoutBudget(new Collection, $start, $end);
$journals = $repository->journalsInPeriodWithoutBudget(new Collection, $start, $end); // budget
$count = $journals->count();
$journals = $journals->slice($offset, $pageSize);
$list = new LengthAwarePaginator($journals, $count, $pageSize);
@@ -295,7 +295,7 @@ class BudgetController extends Controller
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$journals = $repository->journalsInPeriod(new Collection([$budget]), new Collection, $start, $end);
$journals = $repository->journalsInPeriod(new Collection([$budget]), new Collection, $start, $end); // budget
$count = $journals->count();
$journals = $journals->slice($offset, $pageSize);
$journals = new LengthAwarePaginator($journals, $count, $pageSize);
@@ -334,7 +334,7 @@ class BudgetController extends Controller
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$journals = $repository->journalsInPeriod(new Collection([$budget]), new Collection, $start, $end);
$journals = $repository->journalsInPeriod(new Collection([$budget]), new Collection, $start, $end); // budget
$count = $journals->count();
$journals = $journals->slice($offset, $pageSize);
$journals = new LengthAwarePaginator($journals, $count, $pageSize);

View File

@@ -149,7 +149,7 @@ class CategoryController extends Controller
$start = session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = session('end', Carbon::now()->startOfMonth());
$list = $repository->journalsInPeriodWithoutCategory(new Collection(), [], $start, $end);
$list = $repository->journalsInPeriodWithoutCategory(new Collection(), [], $start, $end); // category
$subTitle = trans(
'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
@@ -176,7 +176,7 @@ class CategoryController extends Controller
$page = intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$category]), new Collection, [], $start, $end);
$set = $repository->journalsInPeriod(new Collection([$category]), new Collection, [], $start, $end); // category
$count = $set->count();
$subSet = $set->splice($offset, $pageSize);
$subTitle = $category->name;
@@ -247,7 +247,7 @@ class CategoryController extends Controller
$page = intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$category]), new Collection, [], $start, $end);
$set = $repository->journalsInPeriod(new Collection([$category]), new Collection, [], $start, $end); // category
$count = $set->count();
$subSet = $set->splice($offset, $pageSize);
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);

View File

@@ -401,7 +401,7 @@ class BudgetController extends Controller
*/
private function spentInPeriodWithout(BudgetRepositoryInterface $repository, Carbon $start, Carbon $end):array
{
$list = $repository->journalsInPeriodWithoutBudget(new Collection, $start, $end);
$list = $repository->journalsInPeriodWithoutBudget(new Collection, $start, $end); // budget
$sum = '0';
/** @var TransactionJournal $entry */
foreach ($list as $entry) {

View File

@@ -19,6 +19,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
@@ -26,7 +27,6 @@ use Log;
use Preferences;
use Route;
use Session;
use Steam;
/**
@@ -114,12 +114,13 @@ class HomeController extends Controller
}
/**
* @param ARI $repository
* @param AccountCrudInterface $crud
* @param ARI $repository
* @param AccountCrudInterface $crud
* @param AccountTaskerInterface $tasker
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*/
public function index(ARI $repository, AccountCrudInterface $crud)
public function index(ARI $repository, AccountCrudInterface $crud, AccountTaskerInterface $tasker)
{
$types = config('firefly.accountTypesByIdentifier.asset');
@@ -139,12 +140,12 @@ class HomeController extends Controller
/** @var Carbon $start */
$start = session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
$showTour = Preferences::get('tour', true)->data;
$accounts = $crud->getAccountsById($frontPage->data);
$end = session('end', Carbon::now()->endOfMonth());
$showTour = Preferences::get('tour', true)->data;
$accounts = $crud->getAccountsById($frontPage->data);
foreach ($accounts as $account) {
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
$set = $tasker->getJournalsInPeriod(new Collection([$account]), [], $start, $end);
$set = $set->splice(0, 10);
if (count($set) > 0) {
@@ -153,7 +154,7 @@ class HomeController extends Controller
}
return view(
'index', compact('count', 'showTour', 'title','subTitle', 'mainTitleIcon', 'transactions')
'index', compact('count', 'showTour', 'title', 'subTitle', 'mainTitleIcon', 'transactions')
);
}

View File

@@ -19,9 +19,11 @@ use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collection\BalanceLine;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\Binder\AccountList;
@@ -185,22 +187,22 @@ class ReportController extends Controller
*/
private function expenseEntry(array $attributes): string
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$crud = app(AccountCrudInterface::class);
$account = $crud->find(intval($attributes['accountId']));
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
$journals = $repository->journalsInPeriod($attributes['accounts'], $types, $attributes['startDate'], $attributes['endDate']);
/** @var AccountTaskerInterface $tasker */
$tasker = app(AccountTaskerInterface::class);
$crud = app(AccountCrudInterface::class);
$account = $crud->find(intval($attributes['accountId']));
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
$journals = $tasker->getJournalsInPeriod($attributes['accounts'], $types, $attributes['startDate'], $attributes['endDate']);
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
// filter for transfers and withdrawals TO the given $account
$journals = $journals->filter(
function (TransactionJournal $journal) use ($account) {
$destinations = TransactionJournal::destinationAccountList($journal)->pluck('id')->toArray();
if (in_array($account->id, $destinations)) {
return true;
}
function (Transaction $transaction) use ($report) {
// get the destinations:
$destinations = TransactionJournal::destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
return false;
// do these intersect with the current list?
return !empty(array_intersect($report, $destinations));
}
);
@@ -219,27 +221,23 @@ class ReportController extends Controller
*/
private function incomeEntry(array $attributes): string
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
$account = $crud->find(intval($attributes['accountId']));
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
$journals = $repository->journalsInPeriod(new Collection([$account]), $types, $attributes['startDate'], $attributes['endDate']);
$destinations = $attributes['accounts']->pluck('id')->toArray();
// filter for transfers and withdrawals FROM the given $account
/** @var AccountTaskerInterface $tasker */
$tasker = app(AccountTaskerInterface::class);
/** @var AccountCrudInterface $crud */
$crud = app(AccountCrudInterface::class);
$account = $crud->find(intval($attributes['accountId']));
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
$journals = $tasker->getJournalsInPeriod(new Collection([$account]), $types, $attributes['startDate'], $attributes['endDate']);
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
// filter the set so the destinations outside of $attributes['accounts'] are not included.
$journals = $journals->filter(
function (TransactionJournal $journal) use ($account, $destinations) {
$currentSources = TransactionJournal::sourceAccountList($journal)->pluck('id')->toArray();
$currentDest = TransactionJournal::destinationAccountList($journal)->pluck('id')->toArray();
if (
!empty(array_intersect([$account->id], $currentSources))
&& !empty(array_intersect($destinations, $currentDest))
) {
return true;
}
function (Transaction $transaction) use ($report) {
// get the destinations:
$destinations = TransactionJournal::destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
return false;
// do these intersect with the current list?
return !empty(array_intersect($report, $destinations));
}
);

View File

@@ -21,8 +21,9 @@ use FireflyIII\Helpers\Report\BudgetReportHelperInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Support\Collection;
@@ -121,7 +122,7 @@ class ReportController extends Controller
switch ($reportType) {
default:
throw new FireflyException('Unfortunately, reports of the type "' . e($reportType) . '" are not yet available. ');
throw new FireflyException('Unfortunately, reports of the type "' . e($reportType) . '" are not available at this time.');
case 'default':
// more than one year date difference means year report.
@@ -153,54 +154,36 @@ class ReportController extends Controller
private function auditReport(Carbon $start, Carbon $end, Collection $accounts)
{
/** @var ARI $repos */
$repos = app(ARI::class);
$repos = app(ARI::class);
/** @var AccountTaskerInterface $tasker */
$tasker = app(AccountTaskerInterface::class);
$auditData = [];
$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);
/*
* Is there even activity on this account between the requested dates?
*/
if ($start->between($first, $last) || $end->between($first, $last)) {
$exists = true;
$journals = $repos->journalsInPeriod(new Collection([$account]), [], $start, $end);
$journals = $tasker->getJournalsInPeriod(new Collection([$account]), [], $start, $end);
$journals = $journals->reverse();
$startBalance = $dayBeforeBalance;
}
/*
* Reverse set, get balances.
*/
$journals = $journals->reverse();
$startBalance = $dayBeforeBalance;
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$journal->before = $startBalance;
$transactionAmount = $journal->source_amount;
// get currently relevant transaction:
$destinations = TransactionJournal::destinationAccountList($journal)->pluck('id')->toArray();
if (in_array($account->id, $destinations)) {
$transactionAmount = TransactionJournal::amountPositive($journal);
}
$newBalance = bcadd($startBalance, $transactionAmount);
$journal->after = $newBalance;
$startBalance = $newBalance;
/** @var Transaction $journal */
foreach ($journals as $transaction) {
$transaction->before = $startBalance;
$transactionAmount = $transaction->transaction_amount;
$newBalance = bcadd($startBalance, $transactionAmount);
$transaction->after = $newBalance;
$startBalance = $newBalance;
}
/*
* Reverse set again.
*/
$auditData[$id]['journals'] = $journals->reverse();
$auditData[$id]['exists'] = $exists;
$auditData[$id]['exists'] = $journals->count() > 0;
$auditData[$id]['end'] = $end->formatLocalized(strval(trans('config.month_and_day')));
$auditData[$id]['endBalance'] = Steam::balance($account, $end);
$auditData[$id]['dayBefore'] = $dayBefore->formatLocalized(strval(trans('config.month_and_day')));

View File

@@ -245,6 +245,7 @@ class TransactionController extends Controller
$date = new Carbon($request->get('date'));
if (count($ids) > 0) {
$order = 0;
$ids = array_unique($ids);
foreach ($ids as $id) {
$journal = $repository->find(intval($id));
if ($journal && $journal->date->format('Y-m-d') == $date->format('Y-m-d')) {

View File

@@ -25,6 +25,7 @@ use FireflyIII\Support\Twig\Journal;
use FireflyIII\Support\Twig\PiggyBank;
use FireflyIII\Support\Twig\Rule;
use FireflyIII\Support\Twig\Translation;
use FireflyIII\Support\Twig\Transaction;
use FireflyIII\Validation\FireflyValidator;
use Illuminate\Support\ServiceProvider;
use Twig;
@@ -52,6 +53,7 @@ class FireflyServiceProvider extends ServiceProvider
Twig::addExtension(new Journal);
Twig::addExtension(new Budget);
Twig::addExtension(new Translation);
Twig::addExtension(new Transaction);
Twig::addExtension(new Rule);
}

View File

@@ -111,63 +111,6 @@ class AccountRepository implements AccountRepositoryInterface
return $transaction;
}
/**
* @param Collection $accounts
* @param array $types
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsInPeriod(Collection $accounts, array $types, Carbon $start, Carbon $end): Collection
{
// first collect actual transaction journals (fairly easy)
$query = $this->user->transactionJournals()->expanded()->sortCorrectly();
if ($end >= $start) {
$query->before($end)->after($start);
}
if (count($types) > 0) {
$query->transactionTypes($types);
}
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$query->leftJoin(
'transactions as source', function (JoinClause $join) {
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')->where('source.amount', '<', 0);
}
);
$query->leftJoin(
'transactions as destination', function (JoinClause $join) {
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')->where('destination.amount', '>', 0);
}
);
$query->where(
// source.account_id in accountIds XOR destination.account_id in accountIds
function (Builder $query) use ($accountIds) {
$query->where(
function (Builder $q1) use ($accountIds) {
$q1->whereIn('source.account_id', $accountIds)
->whereNotIn('destination.account_id', $accountIds);
}
)->orWhere(
function (Builder $q2) use ($accountIds) {
$q2->whereIn('destination.account_id', $accountIds)
->whereNotIn('source.account_id', $accountIds);
}
);
}
);
}
// that should do it:
$fields = TransactionJournal::queryFields();
$complete = $query->get($fields);
return $complete;
}
/**
*
* @param Account $account

View File

@@ -60,16 +60,6 @@ interface AccountRepositoryInterface
*/
public function getFirstTransaction(TransactionJournal $journal, Account $account): Transaction;
/**
* @param Collection $accounts
* @param array $types
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsInPeriod(Collection $accounts, array $types, Carbon $start, Carbon $end): Collection;
/**
*
* @param Account $account

View File

@@ -190,6 +190,8 @@ class AccountTasker implements AccountTaskerInterface
}
/**
* It might be worth it to expand this query to include all account information required.
*
* @param Collection $accounts
* @param array $types
* @param Carbon $start
@@ -205,6 +207,8 @@ class AccountTasker implements AccountTaskerInterface
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereIn('transactions.account_id', $accountIds)
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
@@ -221,29 +225,35 @@ class AccountTasker implements AccountTaskerInterface
$set = $query->get(
[
'transaction_journals.id',
'transaction_journals.id as journal_id',
'transaction_journals.description',
'transaction_journals.date',
'transaction_journals.encrypted',
'transaction_journals.transaction_currency_id',
//'transaction_journals.transaction_currency_id',
'transaction_currencies.code as transaction_currency_code',
'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_journals.transaction_type_id',
//'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'bills.name as bill_name',
'transactions.id as transaction_id',
'transactions.id as id',
'transactions.amount as transaction_amount',
'transactions.description as transaction_description',
'transactions.account_id',
'transactions.identifier',
'transactions.transaction_journal_id',
'accounts.name as account_name',
'accounts.encrypted as account_encrypted',
'account_types.type as account_type',
]
);
// loop for decryption.
$set->each(
function (Transaction $transaction) {
$transaction->date = new Carbon($transaction->date);
$transaction->date = new Carbon($transaction->date);
$transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description;
$transaction->bill_name = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : '';
$transaction->bill_name = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : '';
}
);

View File

@@ -119,6 +119,41 @@ class Amount
return $this->formatAnything($currency, strval($transaction->amount), $coloured);
}
/**
* This method will properly format the given number, in color or "black and white",
* as a currency, given two things: the currency required and the currency code.
*
* @param string $code
* @param string $amount
* @param bool $coloured
*
* @return string
*/
public function formatWithCode(string $code, string $amount, bool $coloured = true): string
{
$locale = setlocale(LC_MONETARY, 0);
$float = round($amount, 2);
$formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$result = $formatter->formatCurrency($float, $code);
if ($coloured === true) {
if ($amount > 0) {
return '<span class="text-success" title="' . e($float) . '">' . $result . '</span>';
} else {
if ($amount < 0) {
return '<span class="text-danger" title="' . e($float) . '">' . $result . '</span>';
}
}
return '<span style="color:#999" title="' . e($float) . '">' . $result . '</span>';
}
return $result;
}
/**
* @return Collection
*/

View File

@@ -20,6 +20,7 @@ use FireflyIII\Models\Budget as ModelBudget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
use Twig_Extension;
use Twig_SimpleFilter;
@@ -164,7 +165,9 @@ class Journal extends Twig_Extension
*/
public function getFilters(): array
{
$filters = [$this->typeIcon()];
$filters = [
$this->typeIcon(),
];
return $filters;
}
@@ -407,4 +410,5 @@ class Journal extends Twig_Extension
}, ['is_safe' => ['html']]
);
}
}

View File

@@ -0,0 +1,298 @@
<?php
/**
* Transaction.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Support\Twig;
use Amount;
use Crypt;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction as TransactionModel;
use FireflyIII\Models\TransactionType;
use Twig_Extension;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
/**
* Class Transaction
*
* @package FireflyIII\Support\Twig
*/
class Transaction extends Twig_Extension
{
/**
* @return Twig_SimpleFunction
*/
public function formatAmountWithCode(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'formatAmountWithCode', function (string $amount, string $code): string {
return Amount::formatWithCode($code, $amount, true);
}, ['is_safe' => ['html']]
);
}
/**
* @return array
*/
public function getFilters(): array
{
$filters = [
$this->typeIconTransaction(),
];
return $filters;
}
/**
* @return array
*/
public function getFunctions(): array
{
$functions = [
$this->formatAmountWithCode(),
$this->transactionSourceAccount(),
$this->transactionDestinationAccount(),
$this->optionalJournalAmount(),
$this->transactionBudgets(),
$this->transactionCategories(),
$this->splitJournalIndicator(),
];
return $functions;
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName(): string
{
return 'transaction';
}
/**
* @return Twig_SimpleFunction
*/
public function optionalJournalAmount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'optionalJournalAmount', function (int $journalId, string $transactionAmount, string $code, string $type): string {
$amount = strval(
TransactionModel
::where('transaction_journal_id', $journalId)
->whereNull('deleted_at')
->where('amount', '<', 0)
->sum('amount')
);
if ($type === TransactionType::DEPOSIT || $type === TransactionType::TRANSFER) {
$amount = bcmul($amount, '-1');
}
if (
bccomp($amount, $transactionAmount) !== 0
&& bccomp($amount, bcmul($transactionAmount, '-1')) !== 0
) {
// not equal?
return ' (' . Amount::formatWithCode($code, $amount, true) . ')';
}
return '';
}, ['is_safe' => ['html']]
);
}
public function splitJournalIndicator(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'splitJournalIndicator', function (int $journalId) {
$count = TransactionModel::where('transaction_journal_id', $journalId)->whereNull('deleted_at')->count();
if ($count > 2) {
return '<i class="fa fa-fw fa-share-alt-square" aria-hidden="true"></i>';
}
return '';
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionBudgets(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionBudgets', function (TransactionModel $transaction): string {
// 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);
}
return join(', ', $str);
}
return '';
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionCategories(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionCategories', function (TransactionModel $transaction): string {
// 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);
}
return join(', ', $str);
}
return '';
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionDestinationAccount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionDestinationAccount', function (TransactionModel $transaction): string {
$name = intval($transaction->account_encrypted) === 1 ? Crypt::decrypt($transaction->account_name) : $transaction->account_name;
$id = intval($transaction->account_id);
$type = $transaction->account_type;
// if the amount is positive, assume that the current account (the one in $transaction) is indeed the destination account.
if (bccomp($transaction->transaction_amount, '0') === -1) {
// 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 = intval($other->encrypted) === 1 ? Crypt::decrypt($other->name) : $other->name;
$id = $other->account_id;
$type = $other->type;
}
if ($type === AccountType::CASH) {
return '<span class="text-success">(cash)</span>';
}
return '<a title="' . e($name) . '" href="' . route('accounts.show', $id) . '">' . e($name) . '</a>';
}, ['is_safe' => ['html']]
);
}
/**
* @return Twig_SimpleFunction
*/
public function transactionSourceAccount(): Twig_SimpleFunction
{
return new Twig_SimpleFunction(
'transactionSourceAccount', function (TransactionModel $transaction): string {
$name = intval($transaction->account_encrypted) === 1 ? Crypt::decrypt($transaction->account_name) : $transaction->account_name;
$id = intval($transaction->account_id);
$type = $transaction->account_type;
// if the amount is negative, assume that the current account (the one in $transaction) is indeed the source account.
if (bccomp($transaction->transaction_amount, '0') === 1) {
// if the amount is positive, 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 = intval($other->encrypted) === 1 ? Crypt::decrypt($other->name) : $other->name;
$id = $other->account_id;
$type = $other->type;
}
if ($type === AccountType::CASH) {
return '<span class="text-success">(cash)</span>';
}
return '<a title="' . e($name) . '" href="' . route('accounts.show', $id) . '">' . e($name) . '</a>';
}, ['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 = '<i class="fa fa-long-arrow-left fa-fw" title="' . trans('firefly.withdrawal') . '"></i>';
break;
case TransactionType::DEPOSIT:
$txt = '<i class="fa fa-long-arrow-right fa-fw" title="' . trans('firefly.deposit') . '"></i>';
break;
case TransactionType::TRANSFER:
$txt = '<i class="fa fa-fw fa-exchange" title="' . trans('firefly.transfer') . '"></i>';
break;
case TransactionType::OPENING_BALANCE:
$txt = '<i class="fa-fw fa fa-ban" title="' . trans('firefly.openingBalance') . '"></i>';
break;
default:
$txt = '';
break;
}
return $txt;
}, ['is_safe' => ['html']]
);
}
}