This commit is contained in:
James Cole 2018-03-25 13:30:55 +02:00
parent 41e468b507
commit 992657b942
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
13 changed files with 392 additions and 210 deletions

View File

@ -25,11 +25,13 @@ namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Filter\CountAttachmentsFilter;
use FireflyIII\Helpers\Filter\FilterInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\SplitIndicatorFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
@ -760,6 +762,8 @@ class JournalCollector implements JournalCollectorInterface
TransferFilter::class => new TransferFilter,
PositiveAmountFilter::class => new PositiveAmountFilter,
NegativeAmountFilter::class => new NegativeAmountFilter,
SplitIndicatorFilter::class => new SplitIndicatorFilter,
CountAttachmentsFilter::class => new CountAttachmentsFilter,
];
Log::debug(sprintf('Will run %d filters on the set.', count($this->filters)));
foreach ($this->filters as $enabled) {

View File

@ -0,0 +1,67 @@
<?php
/**
* CountAttachmentsFilter.php
* Copyright (c) 2018 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\Helpers\Filter;
use DB;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection;
/**
* Class CountAttachmentsFilter
*/
class CountAttachmentsFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
// grab journal ID's:
$ids = $set->pluck('journal_id')->toArray();
$result = DB::table('attachments')
->whereNull('deleted_at')
->whereIn('attachable_id', $ids)
->where('attachable_type', TransactionJournal::class)
->groupBy('attachable_id')->get(['attachable_id', DB::raw('COUNT(*) as number')]);
$counter = [];
foreach ($result as $row) {
$counter[$row->attachable_id] = $row->number;
}
$set->each(
function (Transaction $transaction) use ($counter) {
$id = (int)$transaction->journal_id;
$count = $counter[$id] ?? 0;
$transaction->attachmentCount = $count;
}
);
return $set;
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* SplitIndicatorFilter.php
* Copyright (c) 2018 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\Helpers\Filter;
use DB;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
/**
* Class SplitIndicatorFilter
*/
class SplitIndicatorFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
// grab journal ID's:
$ids = $set->pluck('journal_id')->toArray();
$result = DB::table('transactions')
->whereNull('deleted_at')->whereIn('transaction_journal_id', $ids)
->groupBy('transaction_journal_id')->get(['transaction_journal_id', DB::raw('COUNT(*) as number')]);
$counter = [];
foreach ($result as $row) {
$counter[$row->transaction_journal_id] = $row->number;
}
$set->each(
function (Transaction $transaction) use ($counter) {
$id = (int)$transaction->journal_id;
$count = $counter[$id] ?? 0;
$transaction->is_split = false;
if ($count > 2) {
$transaction->is_split = true;
}
}
);
return $set;
}
}

View File

@ -435,33 +435,34 @@ class AccountController extends Controller
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
/** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = new Collection;
// loop dates
foreach ($dates as $date) {
foreach ($dates as $currentDate) {
// try a collector for income:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($date['start'], $date['end'])->setTypes([TransactionType::DEPOSIT])
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::DEPOSIT])
->withOpposingAccount();
$earned = strval($collector->getJournals()->sum('transaction_amount'));
$earned = (string)$collector->getJournals()->sum('transaction_amount');
// try a collector for expenses:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($date['start'], $date['end'])->setTypes([TransactionType::WITHDRAWAL])
$collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::WITHDRAWAL])
->withOpposingAccount();
$spent = strval($collector->getJournals()->sum('transaction_amount'));
$spent = (string)$collector->getJournals()->sum('transaction_amount');
$dateName = app('navigation')->periodShow($date['start'], $date['period']);
$dateName = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
$entries->push(
[
'name' => $dateName,
'spent' => $spent,
'earned' => $earned,
'start' => $date['start']->format('Y-m-d'),
'end' => $date['end']->format('Y-m-d'),
'start' => $currentDate['start']->format('Y-m-d'),
'end' => $currentDate['end']->format('Y-m-d'),
]
);
}

View File

@ -447,20 +447,20 @@ class CategoryController extends Controller
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
/** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = new Collection;
foreach ($dates as $date) {
$spent = $this->repository->spentInPeriod(new Collection([$category]), $accounts, $date['start'], $date['end']);
$earned = $this->repository->earnedInPeriod(new Collection([$category]), $accounts, $date['start'], $date['end']);
$dateStr = $date['end']->format('Y-m-d');
$dateName = app('navigation')->periodShow($date['end'], $date['period']);
foreach ($dates as $currentDate) {
$spent = $this->repository->spentInPeriod(new Collection([$category]), $accounts, $currentDate['start'], $currentDate['end']);
$earned = $this->repository->earnedInPeriod(new Collection([$category]), $accounts, $currentDate['start'], $currentDate['end']);
$dateStr = $currentDate['end']->format('Y-m-d');
$dateName = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
// amount transferred
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($date['start'], $date['end'])->setCategory($category)
$collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->setCategory($category)
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
$collector->removeFilter(InternalTransferFilter::class);
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
@ -473,7 +473,7 @@ class CategoryController extends Controller
'earned' => $earned,
'sum' => bcadd($earned, $spent),
'transferred' => $transferred,
'date' => clone $date['end'],
'date' => clone $currentDate['end'],
]
);
}

View File

@ -25,13 +25,14 @@ namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\CountAttachmentsFilter;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\SplitIndicatorFilter;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Transformers\TransactionTransformer;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
@ -45,6 +46,9 @@ use View;
*/
class TransactionController extends Controller
{
/** @var JournalRepositoryInterface */
private $repository;
/**
* TransactionController constructor.
*/
@ -56,6 +60,7 @@ class TransactionController extends Controller
function ($request, $next) {
app('view')->share('title', trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-repeat');
$this->repository = app(JournalRepositoryInterface::class);
return $next($request);
}
@ -63,96 +68,141 @@ class TransactionController extends Controller
}
/**
* @param Request $request
* @param JournalRepositoryInterface $repository
* @param string $what
* @param string $moment
* Index for a range of transactions.
*
* @param Request $request
* @param string $what
* @param Carbon $start
* @param Carbon $end
*
* @return View
*
*/
public function index(Request $request, JournalRepositoryInterface $repository, string $what, string $moment = '')
public function index(Request $request, string $what, Carbon $start = null, Carbon $end = null)
{
// default values:
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$page = intval($request->get('page'));
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
$range = Preferences::get('viewRange', '1M')->data;
$start = null;
$end = null;
$periods = new Collection;
$page = (int)$request->get('page');
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
$path = route('transactions.index', [$what]);
// prep for "all" view.
if ('all' === $moment) {
$subTitle = trans('firefly.all_' . $what);
$first = $repository->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
$path = route('transactions.index', [$what, 'all']);
if (null === $start) {
$start = session('start');
$end = session('end');
}
if (null === $end) {
$end = session('end');
}
// prep for "specific date" view.
if (strlen($moment) > 0 && 'all' !== $moment) {
$start = new Carbon($moment);
$end = app('navigation')->endOfPeriod($start, $range);
$path = route('transactions.index', [$what, $moment]);
$subTitle = trans(
'firefly.title_' . $what . '_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
$periods = $this->getPeriodOverview($what);
}
// prep for current period
if (0 === strlen($moment)) {
$start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
$end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
$periods = $this->getPeriodOverview($what);
$subTitle = trans(
'firefly.title_' . $what . '_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
if ($end < $start) {
list($start, $end) = [$end, $start];
}
$startStr = $start->formatLocalized($this->monthAndDayFormat);
$endStr = $end->formatLocalized($this->monthAndDayFormat);
$subTitle = trans('firefly.title_' . $what . '_between', ['start' => $startStr, 'end' => $endStr]);
$periods = $this->getPeriodOverview($what, $end);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount();
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->withBudgetInformation()->withCategoryInformation();
$collector->removeFilter(InternalTransferFilter::class);
$collector->addFilter(SplitIndicatorFilter::class);
$collector->addFilter(CountAttachmentsFilter::class);
$transactions = $collector->getPaginatedJournals();
$transactions->setPath($path);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'transactions', 'periods', 'start', 'end', 'moment'));
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'transactions', 'periods', 'start', 'end'));
//
// // prep for "all" view.
// if ('all' === $moment) {
// $subTitle = trans('firefly.all_' . $what);
// $first = $this->repository->first();
// $start = $first->date ?? new Carbon;
// $end = new Carbon;
// $path = route('transactions.index', [$what, 'all']);
// }
//
// // prep for "specific date" view.
// if (strlen($moment) > 0 && 'all' !== $moment) {
// $start = new Carbon($moment);
// $end = app('navigation')->endOfPeriod($start, $range);
// $path = route('transactions.index', [$what, $moment]);
//
// }
// // prep for current period
// if (0 === strlen($moment)) {
// $start = clone session('start', app('navigation')->startOfPeriod(new Carbon, $range));
// $end = clone session('end', app('navigation')->endOfPeriod(new Carbon, $range));
// $subTitle = trans(
// 'firefly.title_' . $what . '_between',
// ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
// );
// }
}
/**
* @param Request $request
* @param JournalRepositoryInterface $repository
* @param Request $request
* @param string $what
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function indexAll(Request $request, string $what)
{
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$page = (int)$request->get('page');
$pageSize = (int)Preferences::get('listPageSize', 50)->data;
$path = route('transactions.index.all', [$what]);
$first = $this->repository->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
$subTitle = trans('firefly.all_' . $what);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->withBudgetInformation()->withCategoryInformation();
$collector->removeFilter(InternalTransferFilter::class);
$collector->addFilter(SplitIndicatorFilter::class);
$collector->addFilter(CountAttachmentsFilter::class);
$transactions = $collector->getPaginatedJournals();
$transactions->setPath($path);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'transactions', 'start', 'end'));
}
/**
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function reconcile(Request $request, JournalRepositoryInterface $repository)
public function reconcile(Request $request)
{
$transactionIds = $request->get('transactions');
foreach ($transactionIds as $transactionId) {
$transactionId = intval($transactionId);
$transaction = $repository->findTransaction($transactionId);
$transactionId = (int)$transactionId;
$transaction = $this->repository->findTransaction($transactionId);
Log::debug(sprintf('Transaction ID is %d', $transaction->id));
$repository->reconcile($transaction);
$this->repository->reconcile($transaction);
}
return response()->json(['ok' => 'reconciled']);
}
/**
* @param Request $request
* @param JournalRepositoryInterface $repository
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function reorder(Request $request, JournalRepositoryInterface $repository)
public function reorder(Request $request)
{
$ids = $request->get('items');
$date = new Carbon($request->get('date'));
@ -160,9 +210,9 @@ class TransactionController extends Controller
$order = 0;
$ids = array_unique($ids);
foreach ($ids as $id) {
$journal = $repository->find(intval($id));
$journal = $this->repository->find((int)$id);
if ($journal && $journal->date->isSameDay($date)) {
$repository->setOrder($journal, $order);
$this->repository->setOrder($journal, $order);
++$order;
}
}
@ -174,13 +224,12 @@ class TransactionController extends Controller
/**
* @param TransactionJournal $journal
* @param JournalRepositoryInterface $repository
* @param LinkTypeRepositoryInterface $linkTypeRepository
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
* @throws FireflyException
*/
public function show(TransactionJournal $journal, JournalRepositoryInterface $repository, LinkTypeRepositoryInterface $linkTypeRepository)
public function show(TransactionJournal $journal, LinkTypeRepositoryInterface $linkTypeRepository)
{
if ($this->isOpeningBalance($journal)) {
return $this->redirectToAccount($journal);
@ -206,7 +255,7 @@ class TransactionController extends Controller
$transactions[] = $transformer->transform($transaction);
}
$events = $repository->getPiggyBankEvents($journal);
$events = $this->repository->getPiggyBankEvents($journal);
$what = strtolower($transactionType);
$subTitle = trans('firefly.' . $what) . ' "' . $journal->description . '"';
@ -218,61 +267,44 @@ class TransactionController extends Controller
*
* @return Collection
*/
private function getPeriodOverview(string $what): Collection
private function getPeriodOverview(string $what, Carbon $date): Collection
{
$repository = app(JournalRepositoryInterface::class);
$first = $repository->first();
$start = $first->date ?? new Carbon;
$range = Preferences::get('viewRange', '1M')->data;
$start = app('navigation')->startOfPeriod($start, $range);
$end = app('navigation')->endOfX(new Carbon, $range, null);
$entries = new Collection;
$types = config('firefly.transactionTypesByWhat.' . $what);
// properties for cache
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($what);
$cache->addProperty('transaction-list-entries');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
$range = Preferences::get('viewRange', '1M')->data;
$first = $this->repository->first();
$start = (new Carbon)->subYear();
$types = config('firefly.transactionTypesByWhat.' . $what);
$entries = new Collection;
if (null !== $first) {
$start = $first->date;
}
if ($date < $start) {
list($start, $date) = [$date, $start]; // @codeCoverageIgnore
}
/** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $date, $range);
Log::debug(sprintf('Going to get period expenses and incomes between %s and %s.', $start->format('Y-m-d'), $end->format('Y-m-d')));
while ($end >= $start) {
Log::debug('Loop start!');
$end = app('navigation')->startOfPeriod($end, $range);
$currentEnd = app('navigation')->endOfPeriod($end, $range);
// count journals without budget in this period:
foreach ($dates as $currentDate) {
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withOpposingAccount()->setTypes($types);
$collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->withOpposingAccount()->setTypes($types);
$collector->removeFilter(InternalTransferFilter::class);
$journals = $collector->getJournals();
$sum = $journals->sum('transaction_amount');
// count per currency:
$sums = $this->sumPerCurrency($journals);
$dateStr = $end->format('Y-m-d');
$dateName = app('navigation')->periodShow($end, $range);
$array = [
'string' => $dateStr,
'name' => $dateName,
'sum' => $sum,
'sums' => $sums,
'date' => clone $end,
];
Log::debug(sprintf('What is %s', $what));
if ($journals->count() > 0) {
$entries->push($array); // @codeCoverageIgnore
$sums = $this->sumPerCurrency($journals);
$dateName = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
$sum = $journals->sum('transaction_amount');
$entries->push(
[
'name' => $dateName,
'sums' => $sums,
'sum' => $sum,
'start' => $currentDate['start']->format('Y-m-d'),
'end' => $currentDate['end']->format('Y-m-d'),
]
);
}
$end = app('navigation')->subtractPeriod($end, $range, 1);
}
Log::debug('End of loop');
$cache->store($entries);
return $entries;
}
@ -287,7 +319,7 @@ class TransactionController extends Controller
$return = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
$currencyId = intval($transaction->transaction_currency_id);
$currencyId = (int)$transaction->transaction_currency_id;
// save currency information:
if (!isset($return[$currencyId])) {

View File

@ -68,6 +68,8 @@ use Watson\Validating\ValidatingTrait;
* @property int $transaction_currency_dp
* @property string $transaction_currency_code
* @property string $description
* @property bool $is_split
* @property int $attachmentCount
*/
class Transaction extends Model
{

View File

@ -103,8 +103,8 @@ class EventServiceProvider extends ServiceProvider
function (PiggyBank $piggyBank) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = null === $piggyBank->startdate ? null : $piggyBank->startdate;
$repetition->targetdate = null === $piggyBank->targetdate ? null : $piggyBank->targetdate;
$repetition->startdate = $piggyBank->startdate;
$repetition->targetdate = $piggyBank->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}

View File

@ -120,44 +120,40 @@ class Transaction extends Twig_Extension
}
/**
*
* @param TransactionModel $transaction
*
* @return string
*/
public function budgets(TransactionModel $transaction): string
{
$txt = '';
// journal has a budget:
if (isset($transaction->transaction_journal_budget_id)) {
if (null !== $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);
return $txt;
}
// transaction has a budget
if (isset($transaction->transaction_budget_id)) {
if (null !== $transaction->transaction_budget_id && $txt === '') {
$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);
return $txt;
}
// see if the transaction has a budget:
$budgets = $transaction->budgets()->get();
if (0 === $budgets->count()) {
$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);
if ($txt === '') {
// see if the transaction has a budget:
$budgets = $transaction->budgets()->get();
if (0 === $budgets->count()) {
$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 = implode(', ', $str);
}
$txt = join(', ', $str);
return $txt;
}
$txt = '';
return $txt;
}
@ -169,40 +165,35 @@ class Transaction extends Twig_Extension
*/
public function categories(TransactionModel $transaction): string
{
$txt = '';
// journal has a category:
if (isset($transaction->transaction_journal_category_id)) {
if (null !== $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);
return $txt;
}
// transaction has a category:
if (isset($transaction->transaction_category_id)) {
if (null !== $transaction->transaction_category_id && $txt === '') {
$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);
return $txt;
}
// see if the transaction has a category:
$categories = $transaction->categories()->get();
if (0 === $categories->count()) {
$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);
if ($txt === '') {
// see if the transaction has a category:
$categories = $transaction->categories()->get();
if (0 === $categories->count()) {
$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);
return $txt;
$txt = implode(', ', $str);
}
}
$txt = '';
return $txt;
}
@ -286,18 +277,25 @@ class Transaction extends Twig_Extension
*/
public function hasAttachments(TransactionModel $transaction): string
{
$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]));
return $res;
}
$res = '';
if (is_int($transaction->attachmentCount) && $transaction->attachmentCount > 0) {
$res = sprintf(
'<i class="fa fa-paperclip" title="%s"></i>', Lang::choice(
'firefly.nr_of_attachments',
$transaction->attachmentCount, ['count' => $transaction->attachmentCount]
)
);
}
if ($transaction->attachmentCount === null) {
$journalId = (int)$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]));
}
}
return $res;
}
@ -341,7 +339,7 @@ class Transaction extends Twig_Extension
public function isReconciled(TransactionModel $transaction): string
{
$icon = '';
if (1 === intval($transaction->reconciled)) {
if (1 === (int)$transaction->reconciled) {
$icon = '<i class="fa fa-check"></i>';
}
@ -349,21 +347,26 @@ class Transaction extends Twig_Extension
}
/**
* Returns an icon when the transaction is a split transaction.
*
* @param TransactionModel $transaction
*
* @return string
*/
public function isSplit(TransactionModel $transaction): string
{
$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>';
return $res;
$res = '';
if ($transaction->is_split === true) {
$res = '<i class="fa fa-fw fa-share-alt" aria-hidden="true"></i>!!!';
}
$res = '';
if ($transaction->is_split === null) {
$journalId = (int)$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>';
}
}
return $res;
}

View File

@ -35,34 +35,31 @@
</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 %}

View File

@ -1,7 +1,7 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, what, moment, start, end) }}
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, what, start, end) }}
{% endblock %}
{% block content %}
@ -10,7 +10,7 @@
{% if periods.count > 0 %}
<div class="row">
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
<p class="small text-center"><a href="{{ route('transactions.index',[what, 'all']) }}">{{ 'showEverything'|_ }}</a></p>
<p class="small text-center"><a href="{{ route('transactions.index.all',[what]) }}">{{ 'showEverything'|_ }}</a></p>
</div>
</div>
{% endif %}
@ -38,7 +38,7 @@
{% if periods.count > 0 %}
<p>
<i class="fa fa-calendar"></i>
<a href="{{ route('transactions.index', [what, 'all']) }}">{{ 'show_all_no_filter'|_ }}</a>
<a href="{{ route('transactions.index.all', [what]) }}">{{ 'show_all_no_filter'|_ }}</a>
</p>
{% else %}
<p>
@ -56,10 +56,9 @@
{% for period in periods %}
{% if period.sum != 0 %}
<div class="box {% if period.date == start %}box-solid box-primary{% endif %}">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title"><a href="{{ route('transactions.index',[what, period.string]) }}">{{ period.name }}</a>
<h3 class="box-title"><a href="{{ route('transactions.index',[what, period.start,period.end]) }}">{{ period.name }}</a>
</h3>
</div>
<div class="box-body no-padding">
@ -91,7 +90,6 @@
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
@ -105,7 +103,7 @@
{% if periods.count > 0 %}
<div class="row">
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
<p class="small text-center"><a href="{{ route('transactions.index',[what, 'all']) }}">{{ 'showEverything'|_ }}</a></p>
<p class="small text-center"><a href="{{ route('transactions.index.all',[what]) }}">{{ 'showEverything'|_ }}</a></p>
</div>
</div>
{% endif %}

View File

@ -877,31 +877,37 @@ Breadcrumbs::register(
);
// TRANSACTIONS
Breadcrumbs::register(
'transactions.index',
function (BreadCrumbsGenerator $breadcrumbs, string $what, string $moment = '', Carbon $start, Carbon $end) {
function (BreadCrumbsGenerator $breadcrumbs, string $what, Carbon $start = null, Carbon $end = null) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.' . $what . '_list'), route('transactions.index', [$what]));
if ('all' === $moment) {
$breadcrumbs->push(trans('firefly.everything'), route('transactions.index', [$what, 'all']));
}
// when is specific period or when empty:
if ('all' !== $moment && '(nothing)' !== $moment) {
if (null !== $start && null !== $end) {
// add date range:
$title = trans(
'firefly.between_dates_breadcrumb',
['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day'))),]
['start' => $start->formatLocalized((string)trans('config.month_and_day')),
'end' => $end->formatLocalized((string)trans('config.month_and_day')),]
);
$breadcrumbs->push($title, route('transactions.index', [$what, $moment]));
$breadcrumbs->push($title, route('transactions.index', [$what, $start, $end]));
}
}
);
Breadcrumbs::register(
'transactions.index.all',
function (BreadCrumbsGenerator $breadcrumbs, string $what, Carbon $start = null, Carbon $end = null) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.' . $what . '_list'), route('transactions.index', [$what]));
}
);
Breadcrumbs::register(
'transactions.create',
function (BreadCrumbsGenerator $breadcrumbs, string $what) {
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('transactions.create', [$what]));
}
);
@ -937,7 +943,7 @@ Breadcrumbs::register(
'transactions.show',
function (BreadCrumbsGenerator $breadcrumbs, TransactionJournal $journal) {
$what = strtolower($journal->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
}
);
@ -960,7 +966,7 @@ Breadcrumbs::register(
if ($journals->count() > 0) {
$journalIds = $journals->pluck('id')->toArray();
$what = strtolower($journals->first()->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index');
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', $journalIds));
return;
@ -977,7 +983,7 @@ Breadcrumbs::register(
function (BreadCrumbsGenerator $breadcrumbs, Collection $journals) {
$journalIds = $journals->pluck('id')->toArray();
$what = strtolower($journals->first()->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index');
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.delete', $journalIds));
}
);
@ -989,7 +995,7 @@ Breadcrumbs::register(
if ($journals->count() > 0) {
$journalIds = $journals->pluck('id')->toArray();
$what = strtolower($journals->first()->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index');
$breadcrumbs->push(trans('firefly.mass_bulk_journals'), route('transactions.bulk.edit', $journalIds));
return;

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
Route::group(
['namespace' => 'FireflyIII\Http\Controllers\System',
'as' => 'installer.', 'prefix' => 'install'], function () {
'as' => 'installer.', 'prefix' => 'install'], function () {
Route::get('', ['uses' => 'InstallController@index', 'as' => 'index']);
Route::post('migrate', ['uses' => 'InstallController@migrate', 'as' => 'migrate']);
Route::post('keys', ['uses' => 'InstallController@keys', 'as' => 'keys']);
@ -780,7 +780,12 @@ Route::group(
*/
Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'transactions', 'as' => 'transactions.'], function () {
Route::get('{what}/{moment?}', ['uses' => 'TransactionController@index', 'as' => 'index'])->where(['what' => 'withdrawal|deposit|transfers|transfer']);
Route::get('{what}/all', ['uses' => 'TransactionController@indexAll', 'as' => 'index.all'])->where(['what' => 'withdrawal|deposit|transfers|transfer']);
Route::get('{what}/{start_date?}/{end_date?}', ['uses' => 'TransactionController@index', 'as' => 'index'])->where(
['what' => 'withdrawal|deposit|transfers|transfer']
);
Route::get('show/{tj}', ['uses' => 'TransactionController@show', 'as' => 'show']);
Route::post('reorder', ['uses' => 'TransactionController@reorder', 'as' => 'reorder']);
Route::post('reconcile', ['uses' => 'TransactionController@reconcile', 'as' => 'reconcile']);