diff --git a/app/Helpers/Collector/JournalCollector.php b/app/Helpers/Collector/JournalCollector.php index f4fa3d2e6e..032cc8d708 100644 --- a/app/Helpers/Collector/JournalCollector.php +++ b/app/Helpers/Collector/JournalCollector.php @@ -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) { diff --git a/app/Helpers/Filter/CountAttachmentsFilter.php b/app/Helpers/Filter/CountAttachmentsFilter.php new file mode 100644 index 0000000000..9ca0e79438 --- /dev/null +++ b/app/Helpers/Filter/CountAttachmentsFilter.php @@ -0,0 +1,67 @@ +. + */ + +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; + } +} \ No newline at end of file diff --git a/app/Helpers/Filter/SplitIndicatorFilter.php b/app/Helpers/Filter/SplitIndicatorFilter.php new file mode 100644 index 0000000000..73116232e1 --- /dev/null +++ b/app/Helpers/Filter/SplitIndicatorFilter.php @@ -0,0 +1,67 @@ +. + */ + +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; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 113062dc37..b59de1fcbf 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -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'), ] ); } diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php index 2212ead0df..668cb64f1e 100644 --- a/app/Http/Controllers/CategoryController.php +++ b/app/Http/Controllers/CategoryController.php @@ -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'], ] ); } diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 2b7178c678..d1727bb020 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -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])) { diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index f965a5c8e9..027300de00 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -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 { diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 6970b7b4b1..7fafc5d844 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -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(); } diff --git a/app/Support/Twig/Extension/Transaction.php b/app/Support/Twig/Extension/Transaction.php index 9e8c7bb071..042f28fb39 100644 --- a/app/Support/Twig/Extension/Transaction.php +++ b/app/Support/Twig/Extension/Transaction.php @@ -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('%s', 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('%s', 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('%s', 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('%s', 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('%s', 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('%s', 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('%s', 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('%s', 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('', Lang::choice('firefly.nr_of_attachments', $count, ['count' => $count])); - - return $res; - } - $res = ''; + if (is_int($transaction->attachmentCount) && $transaction->attachmentCount > 0) { + $res = sprintf( + '', 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('', 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 = ''; } @@ -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 = ''; - - return $res; + $res = ''; + if ($transaction->is_split === true) { + $res = '!!!'; } - $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 = ''; + } + } return $res; } diff --git a/resources/views/partials/transaction-row.twig b/resources/views/partials/transaction-row.twig index 2b54a0bad0..9f392268ee 100644 --- a/resources/views/partials/transaction-row.twig +++ b/resources/views/partials/transaction-row.twig @@ -35,34 +35,31 @@ + {{ transaction|transactionAmount }} {{ transaction.date.formatLocalized(monthAndDayFormat) }} + - {# all source accounts #} {{ transaction|transactionSourceAccount }} + - {# all destination accounts #} {{ transaction|transactionDestinationAccount }} - {# Do NOT hide the budget? #} {% if not hideBudgets %} {{ transaction|transactionBudgets }} {% endif %} - {# Do NOT hide the category? #} {% if not hideCategories %} {{ transaction|transactionCategories }} {% endif %} - - {# Do NOT hide the bill? #} {% if not hideBills %} {% if transaction.bill_id %} diff --git a/resources/views/transactions/index.twig b/resources/views/transactions/index.twig index 9a105e30cb..daeeed551f 100644 --- a/resources/views/transactions/index.twig +++ b/resources/views/transactions/index.twig @@ -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 %}
-

{{ 'showEverything'|_ }}

+

{{ 'showEverything'|_ }}

{% endif %} @@ -38,7 +38,7 @@ {% if periods.count > 0 %}

- {{ 'show_all_no_filter'|_ }} + {{ 'show_all_no_filter'|_ }}

{% else %}

@@ -56,10 +56,9 @@ {% for period in periods %} {% if period.sum != 0 %} - -

+
@@ -91,7 +90,6 @@ {% endfor %} -
{% endif %} @@ -105,7 +103,7 @@ {% if periods.count > 0 %}
{% endif %} diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php index 59bc68c19b..a06f33150c 100644 --- a/routes/breadcrumbs.php +++ b/routes/breadcrumbs.php @@ -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; diff --git a/routes/web.php b/routes/web.php index a53e147996..084fcd6dd9 100755 --- a/routes/web.php +++ b/routes/web.php @@ -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']);