diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 42fabc7488..547fa6b043 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -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); diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index fcd6928cd6..aed7c69989 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -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); diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php index 577a52b8d8..ce693de019 100644 --- a/app/Http/Controllers/CategoryController.php +++ b/app/Http/Controllers/CategoryController.php @@ -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); diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index b93a52e8bb..56eeb966ef 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -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) { diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index bc1586f7cc..740ac32380 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -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') ); } diff --git a/app/Http/Controllers/Popup/ReportController.php b/app/Http/Controllers/Popup/ReportController.php index 11b052b34d..db139560b5 100644 --- a/app/Http/Controllers/Popup/ReportController.php +++ b/app/Http/Controllers/Popup/ReportController.php @@ -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)); } ); diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 8f34806a8b..18b34b50c9 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -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'))); diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 7880ddea05..aac0dccaae 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -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')) { diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index 6396519875..47dd8d0bbe 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -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); } diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index 369a88ccdb..a1fa361844 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -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 diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php index 7ed47ff454..784d29df48 100644 --- a/app/Repositories/Account/AccountRepositoryInterface.php +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -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 diff --git a/app/Repositories/Account/AccountTasker.php b/app/Repositories/Account/AccountTasker.php index 4fe51d3f0d..84d1c0b000 100644 --- a/app/Repositories/Account/AccountTasker.php +++ b/app/Repositories/Account/AccountTasker.php @@ -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) : ''; } ); diff --git a/app/Support/Amount.php b/app/Support/Amount.php index 3142a7e5ca..7937ae148a 100644 --- a/app/Support/Amount.php +++ b/app/Support/Amount.php @@ -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 '' . $result . ''; + } else { + if ($amount < 0) { + return '' . $result . ''; + } + } + + return '' . $result . ''; + + + } + + return $result; + } + /** * @return Collection */ diff --git a/app/Support/Twig/Journal.php b/app/Support/Twig/Journal.php index a359f76ea4..d49171e3e1 100644 --- a/app/Support/Twig/Journal.php +++ b/app/Support/Twig/Journal.php @@ -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']] ); } + } diff --git a/app/Support/Twig/Transaction.php b/app/Support/Twig/Transaction.php new file mode 100644 index 0000000000..1baebdfc7a --- /dev/null +++ b/app/Support/Twig/Transaction.php @@ -0,0 +1,298 @@ + ['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 ''; + } + + 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('%s', 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('%s', 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 '(cash)'; + } + + return '' . e($name) . ''; + + }, ['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 '(cash)'; + } + + return '' . e($name) . ''; + + }, ['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 = ''; + break; + case TransactionType::DEPOSIT: + $txt = ''; + break; + case TransactionType::TRANSFER: + $txt = ''; + break; + case TransactionType::OPENING_BALANCE: + $txt = ''; + break; + default: + $txt = ''; + break; + } + + return $txt; + }, ['is_safe' => ['html']] + ); + } +} \ No newline at end of file diff --git a/resources/views/accounts/show.twig b/resources/views/accounts/show.twig index 4f298d6748..61d41da0c5 100644 --- a/resources/views/accounts/show.twig +++ b/resources/views/accounts/show.twig @@ -37,7 +37,7 @@

{{ 'transactions'|_ }}

- {% include 'list.journals' with {sorting:true, accountPerspective: account} %} + {% include 'list.journals-tasker' with {sorting:true} %}
diff --git a/resources/views/accounts/show_with_date.twig b/resources/views/accounts/show_with_date.twig index 8ebe28de97..89ae367972 100644 --- a/resources/views/accounts/show_with_date.twig +++ b/resources/views/accounts/show_with_date.twig @@ -39,7 +39,7 @@

{{ 'transactions'|_ }}

- {% include 'list.journals' with {sorting:true} %} + {% include 'list.journals-tasker' with {sorting:true} %}
diff --git a/resources/views/index.twig b/resources/views/index.twig index e7356da910..88bd28b7e1 100644 --- a/resources/views/index.twig +++ b/resources/views/index.twig @@ -79,7 +79,7 @@
- {% include 'list.journals-tiny' with {'transactions': data[0],'account': data[1]} %} + {% include 'list.journals-tiny-tasker' with {'transactions': data[0],'account': data[1]} %}