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.
Passed
Push — master ( 075c06...6b2b2a )
by James
20:26 queued 10:33
created

app/Http/Controllers/Chart/CategoryController.php (1 issue)

Severity
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\Chart;
24
25
use Carbon\Carbon;
26
use Exception;
27
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
28
use FireflyIII\Http\Controllers\Controller;
29
use FireflyIII\Models\AccountType;
30
use FireflyIII\Models\Category;
31
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
32
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
33
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
34
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
35
use FireflyIII\Support\CacheProperties;
36
use FireflyIII\Support\Chart\Category\WholePeriodChartGenerator;
37
use FireflyIII\Support\Http\Controllers\AugumentData;
38
use FireflyIII\Support\Http\Controllers\ChartGeneration;
39
use FireflyIII\Support\Http\Controllers\DateCalculation;
40
use Illuminate\Http\JsonResponse;
41
use Illuminate\Support\Collection;
42
43
/**
44
 * Class CategoryController.
45
 */
46
class CategoryController extends Controller
47
{
48
    use DateCalculation, AugumentData, ChartGeneration;
0 ignored issues
show
The trait FireflyIII\Support\Http\Controllers\AugumentData requires some properties which are not provided by FireflyIII\Http\Controll...hart\CategoryController: $name, $id, $start_date, $end_date
Loading history...
49
    /** @var GeneratorInterface Chart generation methods. */
50
    protected $generator;
51
52
    /**
53
     * CategoryController constructor.
54
     *
55
     * @codeCoverageIgnore
56
     */
57
    public function __construct()
58
    {
59
        parent::__construct();
60
        // create chart generator:
61
        $this->generator = app(GeneratorInterface::class);
62
    }
63
64
65
    /**
66
     * Show an overview for a category for all time, per month/week/year.
67
     * TODO test method, for category refactor.
68
     *
69
     * @param Category $category
70
     *
71
     * @return JsonResponse
72
     */
73
    public function all(Category $category): JsonResponse
74
    {
75
        // cache results:
76
        $cache = new CacheProperties;
77
        $cache->addProperty('chart.category.all');
78
        $cache->addProperty($category->id);
79
        if ($cache->has()) {
80
            return response()->json($cache->get()); // @codeCoverageIgnore
81
        }
82
        /** @var CategoryRepositoryInterface $repository */
83
        $repository = app(CategoryRepositoryInterface::class);
84
        $start      = $repository->firstUseDate($category) ?? $this->getDate();
85
        $range      = app('preferences')->get('viewRange', '1M')->data;
86
        $start      = app('navigation')->startOfPeriod($start, $range);
87
        $end        = $this->getDate();
88
89
        //Log::debug(sprintf('Full range is %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
90
91
        /** @var WholePeriodChartGenerator $generator */
92
        $generator = app(WholePeriodChartGenerator::class);
93
        $chartData = $generator->generate($category, $start, $end);
94
        $data      = $this->generator->multiSet($chartData);
95
        $cache->store($data);
96
97
        return response()->json($data);
98
    }
99
100
101
    /**
102
     * Shows the category chart on the front page.
103
     * TODO test method, for category refactor.
104
     *
105
     * @return JsonResponse
106
     */
107
    public function frontPage(): JsonResponse
108
    {
109
        $start = session('start', Carbon::now()->startOfMonth());
110
        $end   = session('end', Carbon::now()->endOfMonth());
111
        // chart properties for cache:
112
        $cache = new CacheProperties;
113
        $cache->addProperty($start);
114
        $cache->addProperty($end);
115
        $cache->addProperty('chart.category.frontpage');
116
        if ($cache->has()) {
117
            return response()->json($cache->get()); // @codeCoverageIgnore
118
        }
119
120
        // currency repos:
121
        /** @var CategoryRepositoryInterface $repository */
122
        $repository = app(CategoryRepositoryInterface::class);
123
124
        /** @var AccountRepositoryInterface $accountRepository */
125
        $accountRepository = app(AccountRepositoryInterface::class);
126
127
        /** @var OperationsRepositoryInterface $opsRepository */
128
        $opsRepository = app(OperationsRepositoryInterface::class);
129
130
        /** @var NoCategoryRepositoryInterface $noCatRepository */
131
        $noCatRepository = app(NoCategoryRepositoryInterface::class);
132
133
        $chartData  = [];
134
        $currencies = [];
135
        $tempData   = [];
136
        $categories = $repository->getCategories();
137
        $accounts   = $accountRepository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
138
139
        /** @var Category $category */
140
        foreach ($categories as $category) {
141
            $collection = new Collection([$category]);
142
            $spent      = $opsRepository->sumExpenses($start, $end, $accounts, $collection);
143
            //$spentArray = $opsRepository->spentInPeriodPerCurrency(new Collection([$category]), $accounts, $start, $end);
144
            foreach ($spent as $currency) {
145
                $currencyId              = $currency['currency_id'];
146
                $currencies[$currencyId] = $currencies[$currencyId] ?? [
147
                        'currency_id'             => $currencyId,
148
                        'currency_name'           => $currency['currency_name'],
149
                        'currency_symbol'         => $currency['currency_symbol'],
150
                        'currency_code'           => $currency['currency_code'],
151
                        'currency_decimal_places' => $currency['currency_decimal_places'],
152
                    ];
153
                $tempData[]              = [
154
                    'name'        => $category->name,
155
                    'sum'         => $currency['sum'],
156
                    'sum_float'   => round($currency['sum'], $currency['currency_decimal_places']),
157
                    'currency_id' => $currencyId,
158
                ];
159
            }
160
        }
161
162
        // no category per currency:
163
        $noCategory = $noCatRepository->sumExpenses($start, $end);
164
165
        foreach ($noCategory as $currency) {
166
            $currencyId              = $currency['currency_id'];
167
            $currencies[$currencyId] = $currencies[$currencyId] ?? [
168
                    'currency_id'             => $currency['currency_id'],
169
                    'currency_name'           => $currency['currency_name'],
170
                    'currency_symbol'         => $currency['currency_symbol'],
171
                    'currency_code'           => $currency['currency_code'],
172
                    'currency_decimal_places' => $currency['currency_decimal_places'],
173
                ];
174
            $tempData[]              = [
175
                'name'        => trans('firefly.no_category'),
176
                'sum'         => $currency['sum'],
177
                'sum_float'   => round($currency['sum'], $currency['currency_decimal_places']),
178
                'currency_id' => $currency['currency_id'],
179
            ];
180
        }
181
182
        // sort temp array by amount.
183
        $amounts = array_column($tempData, 'sum_float');
184
        array_multisort($amounts, SORT_DESC, $tempData);
185
186
        // loop all found currencies and build the data array for the chart.
187
        /** @var array $currency */
188
        foreach ($currencies as $currency) {
189
            $dataSet                             = [
190
                'label'           => sprintf('%s (%s)', (string)trans('firefly.spent'), $currency['currency_name']),
191
                'type'            => 'bar',
192
                'currency_symbol' => $currency['currency_symbol'],
193
                'entries'         => $this->expandNames($tempData),
194
            ];
195
            $chartData[$currency['currency_id']] = $dataSet;
196
        }
197
198
        // loop temp data and place data in correct array:
199
        foreach ($tempData as $entry) {
200
            $currencyId                               = $entry['currency_id'];
201
            $name                                     = $entry['name'];
202
            $chartData[$currencyId]['entries'][$name] = bcmul($entry['sum'], '-1');
203
        }
204
        $data = $this->generator->multiSet($chartData);
205
        $cache->store($data);
206
207
        return response()->json($data);
208
    }
209
210
    /**
211
     * Chart report.
212
     * TODO test method, for category refactor.
213
     *
214
     * @param Category   $category
215
     * @param Collection $accounts
216
     * @param Carbon     $start
217
     * @param Carbon     $end
218
     *
219
     * @return JsonResponse
220
     */
221
    public function reportPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
222
    {
223
        $cache = new CacheProperties;
224
        $cache->addProperty($start);
225
        $cache->addProperty($end);
226
        $cache->addProperty('chart.category.period');
227
        $cache->addProperty($accounts->pluck('id')->toArray());
228
        $cache->addProperty($category);
229
        if ($cache->has()) {
230
            return response()->json($cache->get());// @codeCoverageIgnore
231
        }
232
233
        /** @var OperationsRepositoryInterface $opsRepository */
234
        $opsRepository = app(OperationsRepositoryInterface::class);
235
236
237
        // this gives us all currencies
238
        $collection = new Collection([$category]);
239
        $expenses   = $opsRepository->listExpenses($start, $end, null, $collection);
240
        $income     = $opsRepository->listIncome($start, $end, null, $collection);
241
        $currencies = array_unique(array_merge(array_keys($income), array_keys($expenses)));
242
        $periods    = app('navigation')->listOfPeriods($start, $end);
243
        $format     = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
244
        $chartData  = [];
245
        // make empty data array:
246
        // double foreach (bad) to make empty array:
247
        foreach ($currencies as $currencyId) {
248
            $currencyInfo = $expenses[$currencyId] ?? $income[$currencyId];
249
            $outKey       = sprintf('%d-out', $currencyId);
250
            $inKey        = sprintf('%d-in', $currencyId);
251
            $chartData[$outKey]
252
                          = [
253
                'label'           => sprintf('%s (%s)', (string)trans('firefly.spent'), $currencyInfo['currency_name']),
254
                'entries'         => [],
255
                'type'            => 'bar',
256
                'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
257
            ];
258
259
            $chartData[$inKey]
260
                = [
261
                'label'           => sprintf('%s (%s)', (string)trans('firefly.earned'), $currencyInfo['currency_name']),
262
                'entries'         => [],
263
                'type'            => 'bar',
264
                'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
265
            ];
266
267
268
            // loop empty periods:
269
            foreach (array_keys($periods) as $period) {
270
                $label                                 = $periods[$period];
271
                $chartData[$outKey]['entries'][$label] = '0';
272
                $chartData[$inKey]['entries'][$label]  = '0';
273
            }
274
            // loop income and expenses for this category.:
275
            $outSet = $expenses[$currencyId]['categories'][$category->id] ?? ['transaction_journals' => []];
276
            foreach ($outSet['transaction_journals'] as $journal) {
277
                $amount                               = app('steam')->positive($journal['amount']);
278
                $date                                 = $journal['date']->formatLocalized($format);
279
                $chartData[$outKey]['entries'][$date] = $chartData[$outKey]['entries'][$date] ?? '0';
280
281
                $chartData[$outKey]['entries'][$date] = bcadd($amount, $chartData[$outKey]['entries'][$date]);
282
            }
283
284
            $inSet = $income[$currencyId]['categories'][$category->id] ?? ['transaction_journals' => []];
285
            foreach ($inSet['transaction_journals'] as $journal) {
286
                $amount                              = app('steam')->positive($journal['amount']);
287
                $date                                = $journal['date']->formatLocalized($format);
288
                $chartData[$inKey]['entries'][$date] = $chartData[$inKey]['entries'][$date] ?? '0';
289
                $chartData[$inKey]['entries'][$date] = bcadd($amount, $chartData[$inKey]['entries'][$date]);
290
            }
291
        }
292
293
        $data = $this->generator->multiSet($chartData);
294
        $cache->store($data);
295
296
        return response()->json($data);
297
    }
298
299
300
    /**
301
     * Chart for period for transactions without a category.
302
     * TODO test me.
303
     *
304
     * @param Collection $accounts
305
     * @param Carbon     $start
306
     * @param Carbon     $end
307
     *
308
     * @return JsonResponse
309
     */
310
    public function reportPeriodNoCategory(Collection $accounts, Carbon $start, Carbon $end): JsonResponse
311
    {
312
        $cache = new CacheProperties;
313
        $cache->addProperty($start);
314
        $cache->addProperty($end);
315
        $cache->addProperty('chart.category.period.no-cat');
316
        $cache->addProperty($accounts->pluck('id')->toArray());
317
        if ($cache->has()) {
318
            return response()->json($cache->get()); // @codeCoverageIgnore
319
        }
320
321
        /** @var NoCategoryRepositoryInterface $noCatRepository */
322
        $noCatRepository = app(NoCategoryRepositoryInterface::class);
323
324
        // this gives us all currencies
325
        $expenses   = $noCatRepository->listExpenses($start, $end, $accounts);
326
        $income     = $noCatRepository->listIncome($start, $end, $accounts);
327
        $currencies = array_unique(array_merge(array_keys($income), array_keys($expenses)));
328
        $periods    = app('navigation')->listOfPeriods($start, $end);
329
        $format     = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
330
        $chartData  = [];
331
        // make empty data array:
332
        // double foreach (bad) to make empty array:
333
        foreach ($currencies as $currencyId) {
334
            $currencyInfo = $expenses[$currencyId] ?? $income[$currencyId];
335
            $outKey       = sprintf('%d-out', $currencyId);
336
            $inKey        = sprintf('%d-in', $currencyId);
337
338
            $chartData[$outKey]
339
                = [
340
                'label'           => sprintf('%s (%s)', (string)trans('firefly.spent'), $currencyInfo['currency_name']),
341
                'entries'         => [],
342
                'type'            => 'bar',
343
                'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
344
            ];
345
346
            $chartData[$inKey]
347
                = [
348
                'label'           => sprintf('%s (%s)', (string)trans('firefly.earned'), $currencyInfo['currency_name']),
349
                'entries'         => [],
350
                'type'            => 'bar',
351
                'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
352
            ];
353
354
            // loop empty periods:
355
            foreach (array_keys($periods) as $period) {
356
                $label                                 = $periods[$period];
357
                $chartData[$outKey]['entries'][$label] = '0';
358
                $chartData[$inKey]['entries'][$label]  = '0';
359
            }
360
            // loop income and expenses:
361
            $outSet = $expenses[$currencyId] ?? ['transaction_journals' => []];
362
            foreach ($outSet['transaction_journals'] as $journal) {
363
                $amount                               = app('steam')->positive($journal['amount']);
364
                $date                                 = $journal['date']->formatLocalized($format);
365
                $chartData[$outKey]['entries'][$date] = $chartData[$outKey]['entries'][$date] ?? '0';
366
                $chartData[$outKey]['entries'][$date] = bcadd($amount, $chartData[$outKey]['entries'][$date]);
367
            }
368
369
            $inSet = $income[$currencyId] ?? ['transaction_journals' => []];
370
            foreach ($inSet['transaction_journals'] as $journal) {
371
                $amount                              = app('steam')->positive($journal['amount']);
372
                $date                                = $journal['date']->formatLocalized($format);
373
                $chartData[$inKey]['entries'][$date] = $chartData[$inKey]['entries'][$date] ?? '0';
374
                $chartData[$inKey]['entries'][$date] = bcadd($amount, $chartData[$inKey]['entries'][$date]);
375
            }
376
        }
377
        $data = $this->generator->multiSet($chartData);
378
        $cache->store($data);
379
380
        return response()->json($data);
381
    }
382
383
    /**
384
     * Chart for a specific period.
385
     * TODO test method, for category refactor.
386
     *
387
     * @param Category                    $category
388
     * @param                             $date
389
     *
390
     * @return JsonResponse
391
     */
392
    public function specificPeriod(Category $category, Carbon $date): JsonResponse
393
    {
394
        $range = app('preferences')->get('viewRange', '1M')->data;
395
        $start = app('navigation')->startOfPeriod($date, $range);
396
        $end   = session()->get('end');
397
        if ($end < $start) {
398
            [$end, $start] = [$start, $end]; // @codeCoverageIgnore
399
        }
400
401
        $cache = new CacheProperties;
402
        $cache->addProperty($start);
403
        $cache->addProperty($end);
404
        $cache->addProperty($category->id);
405
        $cache->addProperty('chart.category.period-chart');
406
407
408
        if ($cache->has()) {
409
            return response()->json($cache->get()); // @codeCoverageIgnore
410
        }
411
412
        /** @var GeneratorInterface $generator */
413
        $generator = app(GeneratorInterface::class);
414
415
        /** @var WholePeriodChartGenerator $chartGenerator */
416
        $chartGenerator = app(WholePeriodChartGenerator::class);
417
        $chartData      = $chartGenerator->generate($category, $start, $end);
418
        $data           = $generator->multiSet($chartData);
419
420
        $cache->store($data);
421
422
        return response()->json($data);
423
    }
424
425
    /**
426
     * @return Carbon
427
     */
428
    private function getDate(): Carbon
429
    {
430
        $carbon = null;
431
        try {
432
            $carbon = new Carbon;
433
        } catch (Exception $e) {
434
            $e->getMessage();
435
        }
436
437
        return $carbon;
438
    }
439
}
440