GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

CategoryController::topExpenses()   A
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 40
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 28
c 0
b 0
f 0
dl 0
loc 40
rs 9.1608
cc 5
nc 8
nop 4
1
<?php
2
/**
3
 * CategoryController.php
4
 * Copyright (c) 2019 [email protected]
5
 *
6
 * This file is part of Firefly III (https://github.com/firefly-iii).
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
declare(strict_types=1);
22
23
namespace FireflyIII\Http\Controllers\Report;
24
25
use Carbon\Carbon;
26
use FireflyIII\Http\Controllers\Controller;
27
use FireflyIII\Models\Account;
28
use FireflyIII\Models\Category;
29
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
30
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
31
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
32
use FireflyIII\Support\CacheProperties;
33
use FireflyIII\Support\Http\Controllers\BasicDataSupport;
34
use Illuminate\Contracts\View\Factory;
35
use Illuminate\Support\Collection;
36
use Illuminate\View\View;
37
use Log;
38
use Throwable;
39
40
/**
41
 * Class CategoryController.
42
 */
43
class CategoryController extends Controller
44
{
45
    use BasicDataSupport;
46
47
48
    /** @var OperationsRepositoryInterface */
49
    private $opsRepository;
50
51
    /**
52
     * ExpenseReportController constructor.
53
     *
54
     * @codeCoverageIgnore
55
     */
56
    public function __construct()
57
    {
58
        parent::__construct();
59
        $this->middleware(
60
            function ($request, $next) {
61
                $this->opsRepository = app(OperationsRepositoryInterface::class);
62
63
                return $next($request);
64
            }
65
        );
66
    }
67
68
    /**
69
     * @param Collection $accounts
70
     * @param Collection $categories
71
     * @param Carbon     $start
72
     * @param Carbon     $end
73
     *
74
     * @return Factory|View
75
     */
76
    public function accountPerCategory(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
77
    {
78
        $spent  = $this->opsRepository->listExpenses($start, $end, $accounts, $categories);
79
        $earned = $this->opsRepository->listIncome($start, $end, $accounts, $categories);
80
        $report = [];
81
        /** @var Account $account */
82
        foreach ($accounts as $account) {
83
            $accountId          = $account->id;
84
            $report[$accountId] = $report[$accountId] ?? [
85
                    'name'       => $account->name,
86
                    'id'         => $account->id,
87
                    'iban'       => $account->iban,
88
                    'currencies' => [],
89
                ];
90
        }
91
92
        // loop expenses.
93
        foreach ($spent as $currency) {
94
            $currencyId = $currency['currency_id'];
95
96
            /** @var array $category */
97
            foreach ($currency['categories'] as $category) {
98
                foreach ($category['transaction_journals'] as $journal) {
99
                    $sourceAccountId                                     = $journal['source_account_id'];
100
                    $report[$sourceAccountId]['currencies'][$currencyId] = $report[$sourceAccountId]['currencies'][$currencyId] ?? [
101
                            'currency_id'             => $currency['currency_id'],
102
                            'currency_symbol'         => $currency['currency_symbol'],
103
                            'currency_name'           => $currency['currency_name'],
104
                            'currency_decimal_places' => $currency['currency_decimal_places'],
105
                            'categories'              => [],
106
                        ];
107
108
                    $report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]
109
                                                                                                                 = $report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]
110
                                                                                                                   ??
111
                                                                                                                   [
112
                                                                                                                       'spent'  => '0',
113
                                                                                                                       'earned' => '0',
114
                                                                                                                       'sum'    => '0',
115
                                                                                                                   ];
116
                    $report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]['spent'] = bcadd(
117
                        $report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]['spent'],
118
                        $journal['amount']
119
                    );
120
                    $report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]['sum']   = bcadd(
121
                        $report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]['sum'],
122
                        $journal['amount']
123
                    );
124
                }
125
            }
126
        }
127
128
129
        // loop income.
130
        foreach ($earned as $currency) {
131
            $currencyId = $currency['currency_id'];
132
133
            /** @var array $category */
134
            foreach ($currency['categories'] as $category) {
135
                foreach ($category['transaction_journals'] as $journal) {
136
                    $destinationId = $journal['destination_account_id'];
137
                    $report[$destinationId]['currencies'][$currencyId]
138
                                   = $report[$destinationId]['currencies'][$currencyId]
139
                                     ?? [
140
                                         'currency_id'             => $currency['currency_id'],
141
                                         'currency_symbol'         => $currency['currency_symbol'],
142
                                         'currency_name'           => $currency['currency_name'],
143
                                         'currency_decimal_places' => $currency['currency_decimal_places'],
144
                                         'categories'              => [],
145
                                     ];
146
147
148
                    $report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]
149
                                                                                                                = $report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]
150
                                                                                                                  ??
151
                                                                                                                  [
152
                                                                                                                      'spent'  => '0',
153
                                                                                                                      'earned' => '0',
154
                                                                                                                      'sum'    => '0',
155
                                                                                                                  ];
156
                    $report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]['earned'] = bcadd(
157
                        $report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]['earned'],
158
                        $journal['amount']
159
                    );
160
                    $report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]['sum']    = bcadd(
161
                        $report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]['sum'],
162
                        $journal['amount']
163
                    );
164
                }
165
            }
166
        }
167
168
        return view('reports.category.partials.account-per-category', compact('report', 'categories'));
169
    }
170
171
    /**
172
     * @param Collection $accounts
173
     * @param Collection $categories
174
     * @param Carbon     $start
175
     * @param Carbon     $end
176
     *
177
     * @return Factory|View
178
     */
179
    public function accounts(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
180
    {
181
        $spent  = $this->opsRepository->listExpenses($start, $end, $accounts, $categories);
182
        $earned = $this->opsRepository->listIncome($start, $end, $accounts, $categories);
183
        $report = [];
184
        $sums   = [];
185
        /** @var Account $account */
186
        foreach ($accounts as $account) {
187
            $accountId          = $account->id;
188
            $report[$accountId] = $report[$accountId] ?? [
189
                    'name'       => $account->name,
190
                    'id'         => $account->id,
191
                    'iban'       => $account->iban,
192
                    'currencies' => [],
193
                ];
194
        }
195
196
        // loop expenses.
197
        foreach ($spent as $currency) {
198
            $currencyId        = $currency['currency_id'];
199
            $sums[$currencyId] = $sums[$currencyId] ?? [
200
                    'currency_id'             => $currency['currency_id'],
201
                    'currency_symbol'         => $currency['currency_symbol'],
202
                    'currency_name'           => $currency['currency_name'],
203
                    'currency_decimal_places' => $currency['currency_decimal_places'],
204
                    'spent_sum'               => '0',
205
                    'earned_sum'              => '0',
206
                    'total_sum'               => '0',
207
                ];
208
            foreach ($currency['categories'] as $category) {
209
                foreach ($category['transaction_journals'] as $journal) {
210
                    $sourceAccountId                                              = $journal['source_account_id'];
211
                    $report[$sourceAccountId]['currencies'][$currencyId]          = $report[$sourceAccountId]['currencies'][$currencyId] ?? [
212
                            'currency_id'             => $currency['currency_id'],
213
                            'currency_symbol'         => $currency['currency_symbol'],
214
                            'currency_name'           => $currency['currency_name'],
215
                            'currency_decimal_places' => $currency['currency_decimal_places'],
216
                            'spent'                   => '0',
217
                            'earned'                  => '0',
218
                            'sum'                     => '0',
219
                        ];
220
                    $report[$sourceAccountId]['currencies'][$currencyId]['spent'] = bcadd(
221
                        $report[$sourceAccountId]['currencies'][$currencyId]['spent'],
222
                        $journal['amount']
223
                    );
224
                    $report[$sourceAccountId]['currencies'][$currencyId]['sum']   = bcadd(
225
                        $report[$sourceAccountId]['currencies'][$currencyId]['sum'],
226
                        $journal['amount']
227
                    );
228
                    $sums[$currencyId]['spent_sum']                               = bcadd($sums[$currencyId]['spent_sum'], $journal['amount']);
229
                    $sums[$currencyId]['total_sum']                               = bcadd($sums[$currencyId]['total_sum'], $journal['amount']);
230
                }
231
            }
232
        }
233
234
        // loop income.
235
        foreach ($earned as $currency) {
236
            $currencyId        = $currency['currency_id'];
237
            $sums[$currencyId] = $sums[$currencyId] ?? [
238
                    'currency_id'             => $currency['currency_id'],
239
                    'currency_symbol'         => $currency['currency_symbol'],
240
                    'currency_name'           => $currency['currency_name'],
241
                    'currency_decimal_places' => $currency['currency_decimal_places'],
242
                    'spent_sum'               => '0',
243
                    'earned_sum'              => '0',
244
                    'total_sum'               => '0',
245
                ];
246
            foreach ($currency['categories'] as $category) {
247
                foreach ($category['transaction_journals'] as $journal) {
248
                    $destinationAccountId                                               = $journal['destination_account_id'];
249
                    $report[$destinationAccountId]['currencies'][$currencyId]           = $report[$destinationAccountId]['currencies'][$currencyId] ?? [
250
                            'currency_id'             => $currency['currency_id'],
251
                            'currency_symbol'         => $currency['currency_symbol'],
252
                            'currency_name'           => $currency['currency_name'],
253
                            'currency_decimal_places' => $currency['currency_decimal_places'],
254
                            'spent'                   => '0',
255
                            'earned'                  => '0',
256
                            'sum'                     => '0',
257
                        ];
258
                    $report[$destinationAccountId]['currencies'][$currencyId]['earned'] = bcadd(
259
                        $report[$destinationAccountId]['currencies'][$currencyId]['earned'],
260
                        $journal['amount']
261
                    );
262
                    $report[$destinationAccountId]['currencies'][$currencyId]['sum']    = bcadd(
263
                        $report[$destinationAccountId]['currencies'][$currencyId]['sum'],
264
                        $journal['amount']
265
                    );
266
                    $sums[$currencyId]['earned_sum']                                    = bcadd($sums[$currencyId]['earned_sum'], $journal['amount']);
267
                    $sums[$currencyId]['total_sum']                                     = bcadd($sums[$currencyId]['total_sum'], $journal['amount']);
268
                }
269
            }
270
        }
271
272
        return view('reports.category.partials.accounts', compact('sums', 'report'));
273
    }
274
275
    /**
276
     * @param Collection $accounts
277
     * @param Collection $categories
278
     * @param Carbon     $start
279
     * @param Carbon     $end
280
     *
281
     * @return array|string
282
     */
283
    public function avgExpenses(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
284
    {
285
        $spent  = $this->opsRepository->listExpenses($start, $end, $accounts, $categories);
286
        $result = [];
287
        foreach ($spent as $currency) {
288
            $currencyId = $currency['currency_id'];
0 ignored issues
show
Unused Code introduced by
The assignment to $currencyId is dead and can be removed.
Loading history...
289
            foreach ($currency['categories'] as $category) {
290
                foreach ($category['transaction_journals'] as $journal) {
291
                    $destinationId = $journal['destination_account_id'];
292
                    $key           = sprintf('%d-%d', $destinationId, $currency['currency_id']);
293
                    $result[$key]  = $result[$key] ?? [
294
                            'transactions'             => 0,
295
                            'sum'                      => '0',
296
                            'avg'                      => '0',
297
                            'avg_float'                => 0,
298
                            'destination_account_name' => $journal['destination_account_name'],
299
                            'destination_account_id'   => $journal['destination_account_id'],
300
                            'currency_id'              => $currency['currency_id'],
301
                            'currency_name'            => $currency['currency_name'],
302
                            'currency_symbol'          => $currency['currency_symbol'],
303
                            'currency_decimal_places'  => $currency['currency_decimal_places'],
304
                        ];
305
                    $result[$key]['transactions']++;
306
                    $result[$key]['sum']       = bcadd($journal['amount'], $result[$key]['sum']);
307
                    $result[$key]['avg']       = bcdiv($result[$key]['sum'], (string) $result[$key]['transactions']);
308
                    $result[$key]['avg_float'] = (float) $result[$key]['avg'];
309
                }
310
            }
311
        }
312
        // sort by amount_float
313
        // sort temp array by amount.
314
        $amounts = array_column($result, 'avg_float');
315
        array_multisort($amounts, SORT_ASC, $result);
316
317
        try {
318
            $result = view('reports.category.partials.avg-expenses', compact('result'))->render();
319
            // @codeCoverageIgnoreStart
320
        } catch (Throwable $e) {
321
            Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
322
            $result = sprintf('Could not render view: %s', $e->getMessage());
323
        }
324
325
        return $result;
326
    }
327
328
    /**
329
     * @param Collection $accounts
330
     * @param Collection $categories
331
     * @param Carbon     $start
332
     * @param Carbon     $end
333
     *
334
     * @return array|string
335
     */
336
    public function avgIncome(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
337
    {
338
        $spent  = $this->opsRepository->listIncome($start, $end, $accounts, $categories);
339
        $result = [];
340
        foreach ($spent as $currency) {
341
            $currencyId = $currency['currency_id'];
0 ignored issues
show
Unused Code introduced by
The assignment to $currencyId is dead and can be removed.
Loading history...
342
            foreach ($currency['categories'] as $category) {
343
                foreach ($category['transaction_journals'] as $journal) {
344
                    $sourceId     = $journal['source_account_id'];
345
                    $key          = sprintf('%d-%d', $sourceId, $currency['currency_id']);
346
                    $result[$key] = $result[$key] ?? [
347
                            'transactions'            => 0,
348
                            'sum'                     => '0',
349
                            'avg'                     => '0',
350
                            'avg_float'               => 0,
351
                            'source_account_name'     => $journal['source_account_name'],
352
                            'source_account_id'       => $journal['source_account_id'],
353
                            'currency_id'             => $currency['currency_id'],
354
                            'currency_name'           => $currency['currency_name'],
355
                            'currency_symbol'         => $currency['currency_symbol'],
356
                            'currency_decimal_places' => $currency['currency_decimal_places'],
357
                        ];
358
                    $result[$key]['transactions']++;
359
                    $result[$key]['sum']       = bcadd($journal['amount'], $result[$key]['sum']);
360
                    $result[$key]['avg']       = bcdiv($result[$key]['sum'], (string) $result[$key]['transactions']);
361
                    $result[$key]['avg_float'] = (float) $result[$key]['avg'];
362
                }
363
            }
364
        }
365
        // sort by amount_float
366
        // sort temp array by amount.
367
        $amounts = array_column($result, 'avg_float');
368
        array_multisort($amounts, SORT_DESC, $result);
369
370
        try {
371
            $result = view('reports.category.partials.avg-income', compact('result'))->render();
372
            // @codeCoverageIgnoreStart
373
        } catch (Throwable $e) {
374
            Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
375
            $result = sprintf('Could not render view: %s', $e->getMessage());
376
        }
377
378
        return $result;
379
    }
380
381
    /**
382
     * @param Collection $accounts
383
     * @param Collection $categories
384
     * @param Carbon     $start
385
     * @param Carbon     $end
386
     *
387
     * @return Factory|View
388
     */
389
    public function categories(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
390
    {
391
        $spent  = $this->opsRepository->listExpenses($start, $end, $accounts, $categories);
392
        $earned = $this->opsRepository->listIncome($start, $end, $accounts, $categories);
393
        $sums   = [];
394
        $report = [];
395
        /** @var Category $category */
396
        foreach ($categories as $category) {
397
            $categoryId          = $category->id;
398
            $report[$categoryId] = $report[$categoryId] ?? [
399
                    'name'       => $category->name,
400
                    'id'         => $category->id,
401
                    'currencies' => [],
402
                ];
403
        }
404
        foreach ($spent as $currency) {
405
            $currencyId        = $currency['currency_id'];
406
            $sums[$currencyId] = $sums[$currencyId] ?? [
407
                    'currency_id'             => $currency['currency_id'],
408
                    'currency_symbol'         => $currency['currency_symbol'],
409
                    'currency_name'           => $currency['currency_name'],
410
                    'currency_decimal_places' => $currency['currency_decimal_places'],
411
                    'earned_sum'              => '0',
412
                    'spent_sum'               => '0',
413
                    'total_sum'               => '0',
414
                ];
415
            /** @var array $category */
416
            foreach ($currency['categories'] as $category) {
417
                $categoryId = $category['id'];
418
419
                foreach ($category['transaction_journals'] as $journal) {
420
                    // add currency info to report array:
421
                    $report[$categoryId]['currencies'][$currencyId]          = $report[$categoryId]['currencies'][$currencyId] ?? [
422
                            'spent'                   => '0',
423
                            'earned'                  => '0',
424
                            'sum'                     => '0',
425
                            'currency_id'             => $currency['currency_id'],
426
                            'currency_symbol'         => $currency['currency_symbol'],
427
                            'currency_name'           => $currency['currency_name'],
428
                            'currency_decimal_places' => $currency['currency_decimal_places'],
429
                        ];
430
                    $report[$categoryId]['currencies'][$currencyId]['spent'] = bcadd(
431
                        $report[$categoryId]['currencies'][$currencyId]['spent'],
432
                        $journal['amount']
433
                    );
434
                    $report[$categoryId]['currencies'][$currencyId]['sum']   = bcadd(
435
                        $report[$categoryId]['currencies'][$currencyId]['sum'],
436
                        $journal['amount']
437
                    );
438
439
                    $sums[$currencyId]['spent_sum'] = bcadd($sums[$currencyId]['spent_sum'], $journal['amount']);
440
                    $sums[$currencyId]['total_sum'] = bcadd($sums[$currencyId]['total_sum'], $journal['amount']);
441
                }
442
            }
443
        }
444
445
        foreach ($earned as $currency) {
446
            $currencyId        = $currency['currency_id'];
447
            $sums[$currencyId] = $sums[$currencyId] ?? [
448
                    'currency_id'             => $currency['currency_id'],
449
                    'currency_symbol'         => $currency['currency_symbol'],
450
                    'currency_name'           => $currency['currency_name'],
451
                    'currency_decimal_places' => $currency['currency_decimal_places'],
452
                    'earned_sum'              => '0',
453
                    'spent_sum'               => '0',
454
                    'total_sum'               => '0',
455
                ];
456
            /** @var array $category */
457
            foreach ($currency['categories'] as $category) {
458
                $categoryId = $category['id'];
459
460
                foreach ($category['transaction_journals'] as $journal) {
461
                    // add currency info to report array:
462
                    $report[$categoryId]['currencies'][$currencyId]           = $report[$categoryId]['currencies'][$currencyId] ?? [
463
                            'spent'                   => '0',
464
                            'earned'                  => '0',
465
                            'sum'                     => '0',
466
                            'currency_id'             => $currency['currency_id'],
467
                            'currency_symbol'         => $currency['currency_symbol'],
468
                            'currency_name'           => $currency['currency_name'],
469
                            'currency_decimal_places' => $currency['currency_decimal_places'],
470
                        ];
471
                    $report[$categoryId]['currencies'][$currencyId]['earned'] = bcadd(
472
                        $report[$categoryId]['currencies'][$currencyId]['earned'],
473
                        $journal['amount']
474
                    );
475
                    $report[$categoryId]['currencies'][$currencyId]['sum']    = bcadd(
476
                        $report[$categoryId]['currencies'][$currencyId]['sum'],
477
                        $journal['amount']
478
                    );
479
480
                    $sums[$currencyId]['earned_sum'] = bcadd($sums[$currencyId]['earned_sum'], $journal['amount']);
481
                    $sums[$currencyId]['total_sum']  = bcadd($sums[$currencyId]['total_sum'], $journal['amount']);
482
                }
483
            }
484
        }
485
486
        return view('reports.category.partials.categories', compact('sums', 'report'));
487
    }
488
489
    /**
490
     * Show overview of expenses in category.
491
     *
492
     * @param Collection $accounts
493
     * @param Carbon     $start
494
     * @param Carbon     $end
495
     *
496
     * @return mixed|string
497
     */
498
    public function expenses(Collection $accounts, Carbon $start, Carbon $end)
499
    {
500
        $cache = new CacheProperties;
501
        $cache->addProperty($start);
502
        $cache->addProperty($end);
503
        $cache->addProperty('category-period-expenses-report');
504
        $cache->addProperty($accounts->pluck('id')->toArray());
505
        if ($cache->has()) {
506
            return $cache->get(); // @codeCoverageIgnore
507
        }
508
        /** @var CategoryRepositoryInterface $repository */
509
        $repository = app(CategoryRepositoryInterface::class);
0 ignored issues
show
Unused Code introduced by
The assignment to $repository is dead and can be removed.
Loading history...
510
511
        /** @var OperationsRepositoryInterface $opsRepository */
512
        $opsRepository = app(OperationsRepositoryInterface::class);
513
514
        /** @var NoCategoryRepositoryInterface $noCatRepos */
515
        $noCatRepos = app(NoCategoryRepositoryInterface::class);
516
517
        // depending on the carbon format (a reliable way to determine the general date difference)
518
        // change the "listOfPeriods" call so the entire period gets included correctly.
519
        $format = app('navigation')->preferredCarbonFormat($start, $end);
520
521
        if ('Y' === $format) {
522
            $start->startOfYear();
523
        }
524
        if ('Y-m' === $format) {
525
            $start->startOfMonth();
526
        }
527
528
        $periods = app('navigation')->listOfPeriods($start, $end);
529
        $data    = [];
530
        $with    = $opsRepository->listExpenses($start, $end, $accounts);
531
        $without = $noCatRepos->listExpenses($start, $end, $accounts);
532
        foreach ([$with, $without] as $set) {
533
            foreach ($set as $currencyId => $currencyRow) {
534
                foreach ($currencyRow['categories'] as $categoryId => $categoryRow) {
535
                    $key        = sprintf('%d-%d', $currencyId, $categoryId);
536
                    $data[$key] = $data[$key] ?? [
537
                            'id'                      => $categoryRow['id'],
538
                            'title'                   => sprintf('%s (%s)', $categoryRow['name'], $currencyRow['currency_name']),
539
                            'currency_id'             => $currencyRow['currency_id'],
540
                            'currency_symbol'         => $currencyRow['currency_symbol'],
541
                            'currency_name'           => $currencyRow['currency_name'],
542
                            'currency_code'           => $currencyRow['currency_code'],
543
                            'currency_decimal_places' => $currencyRow['currency_decimal_places'],
544
                            'sum'                     => '0',
545
                            'entries'                 => [],
546
547
                        ];
548
                    foreach ($categoryRow['transaction_journals'] as $journalId => $journal) {
549
                        $date                         = $journal['date']->format($format);
550
                        $data[$key]['entries'][$date] = $data[$key]['entries'][$date] ?? '0';
551
                        $data[$key]['entries'][$date] = bcadd($data[$key]['entries'][$date], $journal['amount']);
552
                        $data[$key]['sum']            = bcadd($data[$key]['sum'], $journal['amount']);
553
                    }
554
                }
555
            }
556
        }
557
558
        $cache->store($data);
559
560
        $report = $data;
561
562
        try {
563
            $result = view('reports.partials.category-period', compact('report', 'periods'))->render();
564
            // @codeCoverageIgnoreStart
565
        } catch (Throwable $e) {
566
            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
567
            $result = sprintf('An error prevented Firefly III from rendering: %s. Apologies.', $e->getMessage());
568
        }
569
        // @codeCoverageIgnoreEnd
570
571
        $cache->store($result);
572
573
        return $result;
574
    }
575
576
    /**
577
     * Show overview of income in category.
578
     *
579
     * @param Collection $accounts
580
     *
581
     * @param Carbon     $start
582
     * @param Carbon     $end
583
     *
584
     * @return string
585
     */
586
    public function income(Collection $accounts, Carbon $start, Carbon $end): string
587
    {
588
        $cache = new CacheProperties;
589
        $cache->addProperty($start);
590
        $cache->addProperty($end);
591
        $cache->addProperty('category-period-income-report');
592
        $cache->addProperty($accounts->pluck('id')->toArray());
593
        if ($cache->has()) {
594
            return $cache->get(); // @codeCoverageIgnore
595
        }
596
597
        /** @var OperationsRepositoryInterface $opsRepository */
598
        $opsRepository = app(OperationsRepositoryInterface::class);
599
600
        /** @var NoCategoryRepositoryInterface $noCatRepos */
601
        $noCatRepos = app(NoCategoryRepositoryInterface::class);
602
603
        // depending on the carbon format (a reliable way to determine the general date difference)
604
        // change the "listOfPeriods" call so the entire period gets included correctly.
605
        $format = app('navigation')->preferredCarbonFormat($start, $end);
606
607
        if ('Y' === $format) {
608
            $start->startOfYear();
609
        }
610
        if ('Y-m' === $format) {
611
            $start->startOfMonth();
612
        }
613
614
        $periods = app('navigation')->listOfPeriods($start, $end);
615
        $data    = [];
616
        $with    = $opsRepository->listIncome($start, $end, $accounts);
617
        $without = $noCatRepos->listIncome($start, $end, $accounts);
618
        foreach ([$with, $without] as $set) {
619
            foreach ($set as $currencyId => $currencyRow) {
620
                foreach ($currencyRow['categories'] as $categoryId => $categoryRow) {
621
                    $key        = sprintf('%d-%d', $currencyId, $categoryId);
622
                    $data[$key] = $data[$key] ?? [
623
                            'id'                      => $categoryRow['id'],
624
                            'title'                   => sprintf('%s (%s)', $categoryRow['name'], $currencyRow['currency_name']),
625
                            'currency_id'             => $currencyRow['currency_id'],
626
                            'currency_symbol'         => $currencyRow['currency_symbol'],
627
                            'currency_name'           => $currencyRow['currency_name'],
628
                            'currency_code'           => $currencyRow['currency_code'],
629
                            'currency_decimal_places' => $currencyRow['currency_decimal_places'],
630
                            'sum'                     => '0',
631
                            'entries'                 => [],
632
633
                        ];
634
                    foreach ($categoryRow['transaction_journals'] as $journalId => $journal) {
635
                        $date                         = $journal['date']->format($format);
636
                        $data[$key]['entries'][$date] = $data[$key]['entries'][$date] ?? '0';
637
                        $data[$key]['entries'][$date] = bcadd($data[$key]['entries'][$date], $journal['amount']);
638
                        $data[$key]['sum']            = bcadd($data[$key]['sum'], $journal['amount']);
639
                    }
640
                }
641
            }
642
        }
643
        $cache->store($data);
644
645
        $report = $data;
646
647
        try {
648
            $result = view('reports.partials.category-period', compact('report', 'periods'))->render();
649
            // @codeCoverageIgnoreStart
650
        } catch (Throwable $e) {
651
            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
652
            $result = sprintf('An error prevented Firefly III from rendering: %s. Apologies.', $e->getMessage());
653
        }
654
        // @codeCoverageIgnoreEnd
655
656
        $cache->store($result);
657
658
        return $result;
659
    }
660
661
    /**
662
     * Show overview of operations.
663
     *
664
     * @param Collection $accounts
665
     * @param Carbon     $start
666
     * @param Carbon     $end
667
     *
668
     * @return mixed|string
669
     *
670
     */
671
    public function operations(Collection $accounts, Carbon $start, Carbon $end)
672
    {
673
        // chart properties for cache:
674
        $cache = new CacheProperties;
675
        $cache->addProperty($start);
676
        $cache->addProperty($end);
677
        $cache->addProperty('category-report');
678
        $cache->addProperty($accounts->pluck('id')->toArray());
679
        if ($cache->has()) {
680
            return $cache->get(); // @codeCoverageIgnore
681
        }
682
683
        /** @var CategoryRepositoryInterface $repository */
684
        $repository = app(CategoryRepositoryInterface::class);
0 ignored issues
show
Unused Code introduced by
The assignment to $repository is dead and can be removed.
Loading history...
685
686
        /** @var OperationsRepositoryInterface $opsRepository */
687
        $opsRepository = app(OperationsRepositoryInterface::class);
688
689
        /** @var NoCategoryRepositoryInterface $noCatRepository */
690
        $noCatRepository = app(NoCategoryRepositoryInterface::class);
691
692
        $earnedWith    = $opsRepository->listIncome($start, $end, $accounts);
693
        $spentWith     = $opsRepository->listExpenses($start, $end, $accounts);
694
        $earnedWithout = $noCatRepository->listIncome($start, $end, $accounts);
695
        $spentWithout  = $noCatRepository->listExpenses($start, $end, $accounts);
696
697
        $report = [
698
            'categories' => [],
699
            'sums'       => [],
700
        ];
701
702
        // needs four for-each loops.
703
        foreach ([$earnedWith, $spentWith, $earnedWithout, $spentWithout] as $data) {
704
            foreach ($data as $currencyId => $currencyRow) {
705
                $report['sums'][$currencyId] = $report['sums'][$currencyId] ?? [
706
                        'spent'                   => '0',
707
                        'earned'                  => '0',
708
                        'sum'                     => '0',
709
                        'currency_id'             => $currencyRow['currency_id'],
710
                        'currency_symbol'         => $currencyRow['currency_symbol'],
711
                        'currency_name'           => $currencyRow['currency_name'],
712
                        'currency_code'           => $currencyRow['currency_code'],
713
                        'currency_decimal_places' => $currencyRow['currency_decimal_places'],
714
                    ];
715
716
717
                foreach ($currencyRow['categories'] as $categoryId => $categoryRow) {
718
                    $key                        = sprintf('%s-%s', $currencyId, $categoryId);
719
                    $report['categories'][$key] = $report['categories'][$key] ?? [
720
                            'id'                      => $categoryId,
721
                            'title'                   => $categoryRow['name'],
722
                            'currency_id'             => $currencyRow['currency_id'],
723
                            'currency_symbol'         => $currencyRow['currency_symbol'],
724
                            'currency_name'           => $currencyRow['currency_name'],
725
                            'currency_code'           => $currencyRow['currency_code'],
726
                            'currency_decimal_places' => $currencyRow['currency_decimal_places'],
727
                            'spent'                   => '0',
728
                            'earned'                  => '0',
729
                            'sum'                     => '0',
730
                        ];
731
                    // loop journals:
732
                    foreach ($categoryRow['transaction_journals'] as $journal) {
733
                        // sum of sums
734
                        $report['sums'][$currencyId]['sum'] = bcadd($report['sums'][$currencyId]['sum'], $journal['amount']);
735
                        // sum of spent:
736
                        $report['sums'][$currencyId]['spent'] = -1 === bccomp($journal['amount'], '0') ? bcadd(
737
                            $report['sums'][$currencyId]['spent'],
738
                            $journal['amount']
739
                        ) : $report['sums'][$currencyId]['spent'];
740
                        // sum of earned
741
                        $report['sums'][$currencyId]['earned'] = 1 === bccomp($journal['amount'], '0') ? bcadd(
742
                            $report['sums'][$currencyId]['earned'],
743
                            $journal['amount']
744
                        ) : $report['sums'][$currencyId]['earned'];
745
746
                        // sum of category
747
                        $report['categories'][$key]['sum'] = bcadd($report['categories'][$key]['sum'], $journal['amount']);
748
                        // total spent in category
749
                        $report['categories'][$key]['spent'] = -1 === bccomp($journal['amount'], '0') ? bcadd(
750
                            $report['categories'][$key]['spent'],
751
                            $journal['amount']
752
                        ) : $report['categories'][$key]['spent'];
753
                        // total earned in category
754
                        $report['categories'][$key]['earned'] = 1 === bccomp($journal['amount'], '0') ? bcadd(
755
                            $report['categories'][$key]['earned'],
756
                            $journal['amount']
757
                        ) : $report['categories'][$key]['earned'];
758
                    }
759
                }
760
            }
761
        }
762
763
        // @codeCoverageIgnoreStart
764
        try {
765
            $result = view('reports.partials.categories', compact('report'))->render();
766
            $cache->store($result);
767
        } catch (Throwable $e) {
768
            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
769
            $result = sprintf('An error prevented Firefly III from rendering: %s. Apologies.', $e->getMessage());
770
        }
771
772
        // @codeCoverageIgnoreEnd
773
774
        return $result;
775
    }
776
777
    /**
778
     * @param Collection $accounts
779
     * @param Collection $categories
780
     * @param Carbon     $start
781
     * @param Carbon     $end
782
     *
783
     * @return array|string
784
     */
785
    public function topExpenses(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
786
    {
787
        $spent  = $this->opsRepository->listExpenses($start, $end, $accounts, $categories);
788
        $result = [];
789
        foreach ($spent as $currency) {
790
            $currencyId = $currency['currency_id'];
0 ignored issues
show
Unused Code introduced by
The assignment to $currencyId is dead and can be removed.
Loading history...
791
            foreach ($currency['categories'] as $category) {
792
                foreach ($category['transaction_journals'] as $journal) {
793
                    $result[] = [
794
                        'description'              => $journal['description'],
795
                        'transaction_group_id'     => $journal['transaction_group_id'],
796
                        'amount_float'             => (float) $journal['amount'],
797
                        'amount'                   => $journal['amount'],
798
                        'date'                     => $journal['date']->formatLocalized($this->monthAndDayFormat),
799
                        'destination_account_name' => $journal['destination_account_name'],
800
                        'destination_account_id'   => $journal['destination_account_id'],
801
                        'currency_id'              => $currency['currency_id'],
802
                        'currency_name'            => $currency['currency_name'],
803
                        'currency_symbol'          => $currency['currency_symbol'],
804
                        'currency_decimal_places'  => $currency['currency_decimal_places'],
805
                        'category_id'              => $category['id'],
806
                        'category_name'            => $category['name'],
807
                    ];
808
                }
809
            }
810
        }
811
        // sort by amount_float
812
        // sort temp array by amount.
813
        $amounts = array_column($result, 'amount_float');
814
        array_multisort($amounts, SORT_ASC, $result);
815
816
        try {
817
            $result = view('reports.category.partials.top-expenses', compact('result'))->render();
818
            // @codeCoverageIgnoreStart
819
        } catch (Throwable $e) {
820
            Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
821
            $result = sprintf('Could not render view: %s', $e->getMessage());
822
        }
823
824
        return $result;
825
    }
826
827
    /**
828
     * @param Collection $accounts
829
     * @param Collection $categories
830
     * @param Carbon     $start
831
     * @param Carbon     $end
832
     *
833
     * @return array|string
834
     */
835
    public function topIncome(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
836
    {
837
        $spent  = $this->opsRepository->listIncome($start, $end, $accounts, $categories);
838
        $result = [];
839
        foreach ($spent as $currency) {
840
            $currencyId = $currency['currency_id'];
0 ignored issues
show
Unused Code introduced by
The assignment to $currencyId is dead and can be removed.
Loading history...
841
            foreach ($currency['categories'] as $category) {
842
                foreach ($category['transaction_journals'] as $journal) {
843
                    $result[] = [
844
                        'description'             => $journal['description'],
845
                        'transaction_group_id'    => $journal['transaction_group_id'],
846
                        'amount_float'            => (float) $journal['amount'],
847
                        'amount'                  => $journal['amount'],
848
                        'date'                    => $journal['date']->formatLocalized($this->monthAndDayFormat),
849
                        'source_account_name'     => $journal['source_account_name'],
850
                        'source_account_id'       => $journal['source_account_id'],
851
                        'currency_id'             => $currency['currency_id'],
852
                        'currency_name'           => $currency['currency_name'],
853
                        'currency_symbol'         => $currency['currency_symbol'],
854
                        'currency_decimal_places' => $currency['currency_decimal_places'],
855
                        'category_id'             => $category['id'],
856
                        'category_name'           => $category['name'],
857
                    ];
858
                }
859
            }
860
        }
861
        // sort by amount_float
862
        // sort temp array by amount.
863
        $amounts = array_column($result, 'amount_float');
864
        array_multisort($amounts, SORT_DESC, $result);
865
866
        try {
867
            $result = view('reports.category.partials.top-income', compact('result'))->render();
868
            // @codeCoverageIgnoreStart
869
        } catch (Throwable $e) {
870
            Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
871
            $result = sprintf('Could not render view: %s', $e->getMessage());
872
        }
873
874
        return $result;
875
    }
876
877
    /**
878
     * @param array $array
879
     *
880
     * @return bool
881
     */
882
    private function noAmountInArray(array $array): bool
0 ignored issues
show
Unused Code introduced by
The method noAmountInArray() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
883
    {
884
        if (0 === count($array)) {
885
            return true;
886
        }
887
888
        return false;
889
    }
890
}
891