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 ( a70b7c...7d482a )
by James
21:49 queued 11:38
created

app/Api/V1/Controllers/SummaryController.php (10 issues)

Labels
Severity
1
<?php
2
3
/**
4
 * SummaryController.php
5
 * Copyright (c) 2019 [email protected]
6
 *
7
 * This file is part of Firefly III.
8
 *
9
 * Firefly III is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * Firefly III is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
declare(strict_types=1);
24
25
namespace FireflyIII\Api\V1\Controllers;
26
27
28
use Carbon\Carbon;
29
use FireflyIII\Exceptions\FireflyException;
30
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
31
use FireflyIII\Helpers\Report\NetWorthInterface;
32
use FireflyIII\Models\Account;
33
use FireflyIII\Models\AccountType;
34
use FireflyIII\Models\Transaction;
35
use FireflyIII\Models\TransactionCurrency;
36
use FireflyIII\Models\TransactionType;
37
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
38
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
39
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
40
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
41
use FireflyIII\User;
42
use Illuminate\Http\JsonResponse;
43
use Illuminate\Http\Request;
44
use Illuminate\Support\Collection;
45
46
/**
47
 * Class SummaryController
48
 */
49
class SummaryController extends Controller
50
{
51
    /** @var AccountRepositoryInterface */
52
    private $accountRepository;
53
    /** @var BillRepositoryInterface */
54
    private $billRepository;
55
    /** @var BudgetRepositoryInterface */
56
    private $budgetRepository;
57
    /** @var CurrencyRepositoryInterface */
58
    private $currencyRepos;
59
60
    /**
61
     * AccountController constructor.
62
     */
63
    public function __construct()
64
    {
65
        parent::__construct();
66
        $this->middleware(
67
            function ($request, $next) {
68
                /** @var User $user */
69
                $user                    = auth()->user();
70
                $this->currencyRepos     = app(CurrencyRepositoryInterface::class);
71
                $this->billRepository    = app(BillRepositoryInterface::class);
72
                $this->budgetRepository  = app(BudgetRepositoryInterface::class);
73
                $this->accountRepository = app(AccountRepositoryInterface::class);
74
75
                $this->billRepository->setUser($user);
76
                $this->currencyRepos->setUser($user);
77
                $this->budgetRepository->setUser($user);
78
                $this->accountRepository->setUser($user);
79
80
81
                return $next($request);
82
            }
83
        );
84
    }
85
86
    /**
87
     * @param Request $request
88
     *
89
     * @return JsonResponse
90
     * @throws FireflyException
91
     */
92
    public function basic(Request $request): JsonResponse
93
    {
94
        // parameters for boxes:
95
        $start = (string)$request->get('start');
96
        $end   = (string)$request->get('end');
97
        if ('' === $start || '' === $end) {
98
            throw new FireflyException('Start and end are mandatory parameters.');
99
        }
100
        $start = Carbon::createFromFormat('Y-m-d', $start);
101
        $end   = Carbon::createFromFormat('Y-m-d', $end);
102
        // balance information:
103
        $balanceData  = $this->getBalanceInformation($start, $end);
0 ignored issues
show
It seems like $start can also be of type false; however, parameter $start of FireflyIII\Api\V1\Contro...getBalanceInformation() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
        $balanceData  = $this->getBalanceInformation(/** @scrutinizer ignore-type */ $start, $end);
Loading history...
It seems like $end can also be of type false; however, parameter $end of FireflyIII\Api\V1\Contro...getBalanceInformation() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
        $balanceData  = $this->getBalanceInformation($start, /** @scrutinizer ignore-type */ $end);
Loading history...
104
        $billData     = $this->getBillInformation($start, $end);
0 ignored issues
show
It seems like $start can also be of type false; however, parameter $start of FireflyIII\Api\V1\Contro...r::getBillInformation() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
        $billData     = $this->getBillInformation(/** @scrutinizer ignore-type */ $start, $end);
Loading history...
It seems like $end can also be of type false; however, parameter $end of FireflyIII\Api\V1\Contro...r::getBillInformation() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
        $billData     = $this->getBillInformation($start, /** @scrutinizer ignore-type */ $end);
Loading history...
105
        $spentData    = $this->getLeftToSpendInfo($start, $end);
0 ignored issues
show
It seems like $start can also be of type false; however, parameter $start of FireflyIII\Api\V1\Contro...r::getLeftToSpendInfo() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
        $spentData    = $this->getLeftToSpendInfo(/** @scrutinizer ignore-type */ $start, $end);
Loading history...
It seems like $end can also be of type false; however, parameter $end of FireflyIII\Api\V1\Contro...r::getLeftToSpendInfo() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
        $spentData    = $this->getLeftToSpendInfo($start, /** @scrutinizer ignore-type */ $end);
Loading history...
106
        $networthData = $this->getNetWorthInfo($start, $end);
0 ignored issues
show
It seems like $start can also be of type false; however, parameter $start of FireflyIII\Api\V1\Contro...ller::getNetWorthInfo() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

106
        $networthData = $this->getNetWorthInfo(/** @scrutinizer ignore-type */ $start, $end);
Loading history...
It seems like $end can also be of type false; however, parameter $end of FireflyIII\Api\V1\Contro...ller::getNetWorthInfo() does only seem to accept Carbon\Carbon, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

106
        $networthData = $this->getNetWorthInfo($start, /** @scrutinizer ignore-type */ $end);
Loading history...
107
        $total        = array_merge($balanceData, $billData, $spentData, $networthData);
108
109
        // TODO: liabilities with icon line-chart
110
111
        return response()->json($total);
112
113
    }
114
115
    /**
116
     * Check if date is outside session range.
117
     *
118
     * @param Carbon $date
119
     *
120
     * @param Carbon $start
121
     * @param Carbon $end
122
     *
123
     * @return bool
124
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
125
     */
126
    protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
127
    {
128
        $result = false;
129
        if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
130
            $result = true;
131
        }
132
        // start and end in the past? use $end
133
        if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
134
            $result = true;
135
        }
136
137
        return $result;
138
    }
139
140
    /**
141
     * This method will scroll through the results of the spentInPeriodMc() array and return the correct info.
142
     *
143
     * @param array               $spentInfo
144
     * @param TransactionCurrency $currency
145
     *
146
     * @return float
147
     */
148
    private function findInSpentArray(array $spentInfo, TransactionCurrency $currency): float
149
    {
150
        foreach ($spentInfo as $array) {
151
            if ($array['currency_id'] === $currency->id) {
152
                return $array['amount'];
153
            }
154
        }
155
156
        return 0.0;
157
    }
158
159
    /**
160
     * @param Carbon $start
161
     * @param Carbon $end
162
     *
163
     * @return array
164
     */
165
    private function getBalanceInformation(Carbon $start, Carbon $end): array
166
    {
167
        // prep some arrays:
168
        $incomes  = [];
169
        $expenses = [];
170
        $sums     = [];
171
        $return   = [];
172
173
        // collect income of user:
174
        /** @var TransactionCollectorInterface $collector */
175
        $collector = app(TransactionCollectorInterface::class);
176
        $collector->setAllAssetAccounts()->setRange($start, $end)
177
                  ->setTypes([TransactionType::DEPOSIT])
178
                  ->withOpposingAccount();
179
        $set = $collector->getTransactions();
180
        /** @var Transaction $transaction */
181
        foreach ($set as $transaction) {
182
            $currencyId           = (int)$transaction->transaction_currency_id;
183
            $incomes[$currencyId] = $incomes[$currencyId] ?? '0';
184
            $incomes[$currencyId] = bcadd($incomes[$currencyId], $transaction->transaction_amount);
185
            $sums[$currencyId]    = $sums[$currencyId] ?? '0';
186
            $sums[$currencyId]    = bcadd($sums[$currencyId], $transaction->transaction_amount);
187
        }
188
189
        // collect expenses:
190
        /** @var TransactionCollectorInterface $collector */
191
        $collector = app(TransactionCollectorInterface::class);
192
        $collector->setAllAssetAccounts()->setRange($start, $end)
193
                  ->setTypes([TransactionType::WITHDRAWAL])
194
                  ->withOpposingAccount();
195
        $set = $collector->getTransactions();
196
        /** @var Transaction $transaction */
197
        foreach ($set as $transaction) {
198
            $currencyId            = (int)$transaction->transaction_currency_id;
199
            $expenses[$currencyId] = $expenses[$currencyId] ?? '0';
200
            $expenses[$currencyId] = bcadd($expenses[$currencyId], $transaction->transaction_amount);
201
            $sums[$currencyId]     = $sums[$currencyId] ?? '0';
202
            $sums[$currencyId]     = bcadd($sums[$currencyId], $transaction->transaction_amount);
203
        }
204
205
        // format amounts:
206
        $keys = array_keys($sums);
207
        foreach ($keys as $currencyId) {
208
            $currency = $this->currencyRepos->findNull($currencyId);
209
            if (null === $currency) {
210
                continue;
211
            }
212
            // create objects for big array.
213
            $return[] = [
214
                'key'                     => sprintf('balance-in-%s', $currency->code),
215
                'title'                   => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
216
                'monetary_value'          => round($sums[$currencyId] ?? 0, $currency->decimal_places),
217
                'currency_id'             => $currency->id,
218
                'currency_code'           => $currency->code,
219
                'currency_symbol'         => $currency->symbol,
220
                'currency_decimal_places' => $currency->decimal_places,
221
                'value_parsed'            => app('amount')->formatAnything($currency, $sums[$currencyId] ?? '0', false),
222
                'local_icon'              => 'balance-scale',
223
                'sub_title'               => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false) .
224
                                             ' + ' . app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
225
            ];
226
            $return[] = [
227
                'key'                     => sprintf('spent-in-%s', $currency->code),
228
                'title'                   => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
229
                'monetary_value'          => round($expenses[$currencyId] ?? 0, $currency->decimal_places),
230
                'currency_id'             => $currency->id,
231
                'currency_code'           => $currency->code,
232
                'currency_symbol'         => $currency->symbol,
233
                'currency_decimal_places' => $currency->decimal_places,
234
                'value_parsed'            => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false),
235
                'local_icon'              => 'balance-scale',
236
                'sub_title'               => '',
237
            ];
238
            $return[] = [
239
                'key'                     => sprintf('earned-in-%s', $currency->code),
240
                'title'                   => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
241
                'monetary_value'          => round($incomes[$currencyId] ?? 0, $currency->decimal_places),
242
                'currency_id'             => $currency->id,
243
                'currency_code'           => $currency->code,
244
                'currency_symbol'         => $currency->symbol,
245
                'currency_decimal_places' => $currency->decimal_places,
246
                'value_parsed'            => app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
247
                'local_icon'              => 'balance-scale',
248
                'sub_title'               => '',
249
            ];
250
        }
251
252
        return $return;
253
    }
254
255
    /**
256
     * @param Carbon $start
257
     * @param Carbon $end
258
     *
259
     * @return array
260
     */
261
    private function getBillInformation(Carbon $start, Carbon $end): array
262
    {
263
        /*
264
         * Since both this method and the chart use the exact same data, we can suffice
265
         * with calling the one method in the bill repository that will get this amount.
266
         */
267
        $paidAmount   = $this->billRepository->getBillsPaidInRangePerCurrency($start, $end);
268
        $unpaidAmount = $this->billRepository->getBillsUnpaidInRangePerCurrency($start, $end);
269
        $return       = [];
270
        foreach ($paidAmount as $currencyId => $amount) {
271
            $amount   = bcmul($amount, '-1');
272
            $currency = $this->currencyRepos->findNull((int)$currencyId);
273
            if (null === $currency) {
274
                continue;
275
            }
276
            $return[] = [
277
                'key'                     => sprintf('bills-paid-in-%s', $currency->code),
278
                'title'                   => trans('firefly.box_bill_paid_in_currency', ['currency' => $currency->symbol]),
279
                'monetary_value'          => round($amount, $currency->decimal_places),
0 ignored issues
show
$amount of type string is incompatible with the type double expected by parameter $val of round(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

279
                'monetary_value'          => round(/** @scrutinizer ignore-type */ $amount, $currency->decimal_places),
Loading history...
280
                'currency_id'             => $currency->id,
281
                'currency_code'           => $currency->code,
282
                'currency_symbol'         => $currency->symbol,
283
                'currency_decimal_places' => $currency->decimal_places,
284
                'value_parsed'            => app('amount')->formatAnything($currency, $amount, false),
285
                'local_icon'              => 'check',
286
                'sub_title'               => '',
287
            ];
288
        }
289
290
        foreach ($unpaidAmount as $currencyId => $amount) {
291
            $amount   = bcmul($amount, '-1');
292
            $currency = $this->currencyRepos->findNull((int)$currencyId);
293
            if (null === $currency) {
294
                continue;
295
            }
296
            $return[] = [
297
                'key'                     => sprintf('bills-unpaid-in-%s', $currency->code),
298
                'title'                   => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $currency->symbol]),
299
                'monetary_value'          => round($amount, $currency->decimal_places),
300
                'currency_id'             => $currency->id,
301
                'currency_code'           => $currency->code,
302
                'currency_symbol'         => $currency->symbol,
303
                'currency_decimal_places' => $currency->decimal_places,
304
                'value_parsed'            => app('amount')->formatAnything($currency, $amount, false),
305
                'local_icon'              => 'calendar-o',
306
                'sub_title'               => '',
307
            ];
308
        }
309
310
        return $return;
311
    }
312
313
    /**
314
     * @param Carbon $start
315
     * @param Carbon $end
316
     *
317
     * @return array
318
     */
319
    private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
320
    {
321
        $return    = [];
322
        $today     = new Carbon;
323
        $available = $this->budgetRepository->getAvailableBudgetWithCurrency($start, $end);
324
        $budgets   = $this->budgetRepository->getActiveBudgets();
325
        $spentInfo = $this->budgetRepository->spentInPeriodMc($budgets, new Collection, $start, $end);
326
        foreach ($available as $currencyId => $amount) {
327
            $currency = $this->currencyRepos->findNull($currencyId);
328
            if (null === $currency) {
329
                continue;
330
            }
331
            $spentInCurrency = (string)$this->findInSpentArray($spentInfo, $currency);
332
            $leftToSpend     = bcadd($amount, $spentInCurrency);
333
334
            $days   = $today->diffInDays($end) + 1;
335
            $perDay = '0';
336
            if (0 !== $days && bccomp($leftToSpend, '0') > -1) {
337
                $perDay = bcdiv($leftToSpend, (string)$days);
338
            }
339
340
            $return[] = [
341
                'key'                     => sprintf('left-to-spend-in-%s', $currency->code),
342
                'title'                   => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currency->symbol]),
343
                'monetary_value'          => round($leftToSpend, $currency->decimal_places),
0 ignored issues
show
$leftToSpend of type string is incompatible with the type double expected by parameter $val of round(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

343
                'monetary_value'          => round(/** @scrutinizer ignore-type */ $leftToSpend, $currency->decimal_places),
Loading history...
344
                'currency_id'             => $currency->id,
345
                'currency_code'           => $currency->code,
346
                'currency_symbol'         => $currency->symbol,
347
                'currency_decimal_places' => $currency->decimal_places,
348
                'value_parsed'            => app('amount')->formatAnything($currency, $leftToSpend, false),
349
                'local_icon'              => 'money',
350
                'sub_title'               => (string)trans('firefly.box_spend_per_day', ['amount' => app('amount')->formatAnything($currency, $perDay, false)]),
351
            ];
352
        }
353
354
        return $return;
355
    }
356
357
    /**
358
     * @param Carbon $start
359
     * @param Carbon $end
360
     *
361
     * @return array
362
     */
363
    private function getNetWorthInfo(Carbon $start, Carbon $end): array
364
    {
365
        /** @var User $user */
366
        $user = auth()->user();
367
        $date = Carbon::now()->startOfDay();
368
369
370
        // start and end in the future? use $end
371
        if ($this->notInDateRange($date, $start, $end)) {
372
            /** @var Carbon $date */
373
            $date = session('end', Carbon::now()->endOfMonth());
374
        }
375
376
        /** @var NetWorthInterface $netWorthHelper */
377
        $netWorthHelper = app(NetWorthInterface::class);
378
        $netWorthHelper->setUser($user);
379
        $allAccounts = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE]);
380
381
        // filter list on preference of being included.
382
        $filtered = $allAccounts->filter(
383
            function (Account $account) {
384
                $includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
385
386
                return null === $includeNetWorth ? true : '1' === $includeNetWorth;
387
            }
388
        );
389
390
        $netWorthSet = $netWorthHelper->getNetWorthByCurrency($filtered, $date);
391
        $return      = [];
392
        foreach ($netWorthSet as $index => $data) {
393
            /** @var TransactionCurrency $currency */
394
            $currency = $data['currency'];
395
            $amount   = round($data['balance'], $currency->decimal_places);
396
            if (0.0 === $amount) {
397
                continue;
398
            }
399
            // return stuff
400
            $return[] = [
401
                'key'                     => sprintf('net-worth-in-%s', $currency->code),
402
                'title'                   => trans('firefly.box_net_worth_in_currency', ['currency' => $currency->symbol]),
403
                'monetary_value'          => $amount,
404
                'currency_id'             => $currency->id,
405
                'currency_code'           => $currency->code,
406
                'currency_symbol'         => $currency->symbol,
407
                'currency_decimal_places' => $currency->decimal_places,
408
                'value_parsed'            => app('amount')->formatAnything($currency, $data['balance'], false),
409
                'local_icon'              => 'line-chart',
410
                'sub_title'               => '',
411
            ];
412
        }
413
414
        return $return;
415
    }
416
417
}
418