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 ( ece0c9...2089ee )
by James
20:37 queued 10:02
created

Http/Controllers/Transaction/SingleController.php (2 issues)

Labels
Severity
1
<?php
2
/**
3
 * SingleController.php
4
 * Copyright (c) 2017 [email protected]
5
 *
6
 * This file is part of Firefly III.
7
 *
8
 * Firefly III is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Firefly III 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 General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
declare(strict_types=1);
22
23
namespace FireflyIII\Http\Controllers\Transaction;
24
25
use Carbon\Carbon;
26
use FireflyIII\Events\StoredTransactionJournal;
27
use FireflyIII\Events\UpdatedTransactionJournal;
28
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
29
use FireflyIII\Http\Controllers\Controller;
30
use FireflyIII\Http\Requests\JournalFormRequest;
31
use FireflyIII\Models\Transaction;
32
use FireflyIII\Models\TransactionJournal;
33
use FireflyIII\Models\TransactionJournalMeta;
34
use FireflyIII\Models\TransactionType;
35
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
36
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
37
use FireflyIII\Support\Http\Controllers\ModelInformation;
38
use Illuminate\Http\JsonResponse;
39
use Illuminate\Http\RedirectResponse;
40
use Illuminate\Http\Request;
41
use Log;
42
use View;
43
44
/**
45
 * Class SingleController.
46
 *
47
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
48
 */
49
class SingleController extends Controller
50
{
51
    use ModelInformation;
52
53
    /** @var AttachmentHelperInterface The attachment helper. */
54
    private $attachments;
55
    /** @var BudgetRepositoryInterface The budget repository */
56
    private $budgets;
57
    /** @var JournalRepositoryInterface Journals and transactions overview */
58
    private $repository;
59
60
    /**
61
     * SingleController constructor.
62
     */
63
    public function __construct()
64
    {
65
        parent::__construct();
66
67
        $maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
68
        $maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
69
        $uploadSize  = min($maxFileSize, $maxPostSize);
70
        app('view')->share('uploadSize', $uploadSize);
71
72
        // some useful repositories:
73
        $this->middleware(
74
            function ($request, $next) {
75
                $this->budgets     = app(BudgetRepositoryInterface::class);
76
                $this->attachments = app(AttachmentHelperInterface::class);
77
                $this->repository  = app(JournalRepositoryInterface::class);
78
79
                app('view')->share('title', (string)trans('firefly.transactions'));
80
                app('view')->share('mainTitleIcon', 'fa-repeat');
81
82
                return $next($request);
83
            }
84
        );
85
    }
86
87
    /**
88
     * CLone a transaction.
89
     *
90
     * @param TransactionJournal $journal
91
     *
92
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
93
     *
94
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
95
     */
96
    public function cloneTransaction(TransactionJournal $journal)
97
    {
98
        $source       = $this->repository->getJournalSourceAccounts($journal)->first();
99
        $destination  = $this->repository->getJournalDestinationAccounts($journal)->first();
100
        $budgetId     = $this->repository->getJournalBudgetId($journal);
101
        $categoryName = $this->repository->getJournalCategoryName($journal);
102
        $tags         = implode(',', $this->repository->getTags($journal));
103
        /** @var Transaction $transaction */
104
        $transaction   = $journal->transactions()->first();
105
        $amount        = app('steam')->positive($transaction->amount);
106
        $foreignAmount = null === $transaction->foreign_amount ? null : app('steam')->positive($transaction->foreign_amount);
107
108
        // make sure previous URI is correct:
109
        session()->put('transactions.create.fromStore', true);
110
        session()->put('transactions.create.uri', app('url')->previous());
111
112
        $preFilled = [
113
            'description'               => $journal->description,
114
            'source_id'                 => $source->id,
115
            'source_name'               => $source->name,
116
            'destination_id'            => $destination->id,
117
            'destination_name'          => $destination->name,
118
            'amount'                    => $amount,
119
            'source_amount'             => $amount,
120
            'destination_amount'        => $foreignAmount,
121
            'foreign_amount'            => $foreignAmount,
122
            'native_amount'             => $foreignAmount,
123
            'amount_currency_id_amount' => $transaction->foreign_currency_id ?? 0,
124
            'date'                      => (new Carbon())->format('Y-m-d'),
125
            'budget_id'                 => $budgetId,
126
            'category'                  => $categoryName,
127
            'tags'                      => $tags,
128
            'interest_date'             => $this->repository->getMetaField($journal, 'interest_date'),
129
            'book_date'                 => $this->repository->getMetaField($journal, 'book_date'),
130
            'process_date'              => $this->repository->getMetaField($journal, 'process_date'),
131
            'due_date'                  => $this->repository->getMetaField($journal, 'due_date'),
132
            'payment_date'              => $this->repository->getMetaField($journal, 'payment_date'),
133
            'invoice_date'              => $this->repository->getMetaField($journal, 'invoice_date'),
134
            'internal_reference'        => $this->repository->getMetaField($journal, 'internal_reference'),
135
            'notes'                     => $this->repository->getNoteText($journal),
136
        ];
137
138
        session()->flash('preFilled', $preFilled);
139
140
        return redirect(route('transactions.create', [strtolower($journal->transactionType->type)]));
141
    }
142
143
    /**
144
     * Create a new journal.
145
     *
146
     * @param Request     $request
147
     * @param string|null $what
148
     *
149
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
150
     *
151
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
152
     */
153
    public function create(Request $request, string $what = null)
154
    {
155
        $what           = strtolower($what ?? TransactionType::DEPOSIT);
156
        $what           = (string)($request->old('what') ?? $what);
157
        $budgets        = app('expandedform')->makeSelectListWithEmpty($this->budgets->getActiveBudgets());
158
        $preFilled      = session()->has('preFilled') ? session('preFilled') : [];
159
        $subTitle       = (string)trans('form.add_new_' . $what);
160
        $subTitleIcon   = 'fa-plus';
161
        $optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
162
        $source         = (int)$request->get('source');
163
164
        // grab old currency ID from old data:
165
        $currencyID                             = (int)$request->old('amount_currency_id_amount');
166
        $preFilled['amount_currency_id_amount'] = $currencyID;
167
168
        if (('withdrawal' === $what || 'transfer' === $what) && $source > 0) {
169
            $preFilled['source_id'] = $source;
170
        }
171
        if ('deposit' === $what && $source > 0) {
172
            $preFilled['destination_id'] = $source;
173
        }
174
175
        session()->put('preFilled', $preFilled);
176
177
        // put previous url in session if not redirect from store (not "create another").
178
        if (true !== session('transactions.create.fromStore')) {
179
            $this->rememberPreviousUri('transactions.create.uri');
180
        }
181
        session()->forget('transactions.create.fromStore');
182
183
        return view(
184
            'transactions.single.create',
185
            compact('subTitleIcon', 'budgets', 'what', 'subTitle', 'optionalFields', 'preFilled')
186
        );
187
    }
188
189
    /**
190
     * Show a special JSONified view of a transaction, for easier debug purposes.
191
     *
192
     * @param TransactionJournal $journal
193
     *
194
     * @codeCoverageIgnore
195
     * @return JsonResponse
196
     */
197
    public function debugShow(TransactionJournal $journal): JsonResponse
198
    {
199
        $array                 = $journal->toArray();
200
        $array['transactions'] = [];
201
        $array['meta']         = [];
202
203
        /** @var Transaction $transaction */
204
        foreach ($journal->transactions as $transaction) {
205
            $array['transactions'][] = $transaction->toArray();
206
        }
207
        /** @var TransactionJournalMeta $meta */
208
        foreach ($journal->transactionJournalMeta as $meta) {
209
            $array['meta'][] = $meta->toArray();
210
        }
211
212
        return response()->json($array);
213
    }
214
215
    /**
216
     * Shows the form that allows a user to delete a transaction journal.
217
     *
218
     * @param TransactionJournal $journal
219
     *
220
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
221
     */
222
    public function delete(TransactionJournal $journal)
223
    {
224
        Log::debug(sprintf('Start of delete view for journal #%d', $journal->id));
225
        // Covered by another controller's tests
226
        // @codeCoverageIgnoreStart
227
        if ($this->isOpeningBalance($journal)) {
228
            return $this->redirectToAccount($journal);
229
        }
230
        // @codeCoverageIgnoreEnd
231
232
        $what     = strtolower($journal->transaction_type_type ?? $journal->transactionType->type);
233
        $subTitle = (string)trans('firefly.delete_' . $what, ['description' => $journal->description]);
234
235
        // put previous url in session
236
        Log::debug('Will try to remember previous URI');
237
        $this->rememberPreviousUri('transactions.delete.uri');
238
239
        return view('transactions.single.delete', compact('journal', 'subTitle', 'what'));
240
    }
241
242
    /**
243
     * Actually destroys the journal.
244
     *
245
     * @param TransactionJournal $transactionJournal
246
     *
247
     * @return \Illuminate\Http\RedirectResponse
248
     */
249
    public function destroy(TransactionJournal $transactionJournal): RedirectResponse
250
    {
251
        // @codeCoverageIgnoreStart
252
        if ($this->isOpeningBalance($transactionJournal)) {
253
            return $this->redirectToAccount($transactionJournal);
254
        }
255
        // @codeCoverageIgnoreEnd
256
        $type = $this->repository->getTransactionType($transactionJournal);
257
        session()->flash('success', (string)trans('firefly.deleted_' . strtolower($type), ['description' => $transactionJournal->description]));
258
259
        $this->repository->destroy($transactionJournal);
260
261
        app('preferences')->mark();
262
263
        return redirect($this->getPreviousUri('transactions.delete.uri'));
264
    }
265
266
    /**
267
     * Edit a journal.
268
     *
269
     * @param TransactionJournal         $journal
270
     *
271
     * @param JournalRepositoryInterface $repository
272
     *
273
     * @return mixed
274
     *
275
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
276
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
277
     */
278
    public function edit(TransactionJournal $journal, JournalRepositoryInterface $repository)
279
    {
280
        $transactionType = $repository->getTransactionType($journal);
281
282
        // redirect to account:
283
        if ($transactionType === TransactionType::OPENING_BALANCE) {
284
            return $this->redirectToAccount($journal);
285
        }
286
        // redirect to reconcile edit:
287
        if ($transactionType === TransactionType::RECONCILIATION) {
288
            return redirect(route('accounts.reconcile.edit', [$journal->id]));
289
        }
290
291
        // redirect to split edit:
292
        if ($this->isSplitJournal($journal)) {
293
            return redirect(route('transactions.split.edit', [$journal->id]));
294
        }
295
296
        $what       = strtolower($transactionType);
297
        $budgetList = app('expandedform')->makeSelectListWithEmpty($this->budgets->getBudgets());
298
299
        // view related code
300
        $subTitle = (string)trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
301
302
        // journal related code
303
        $sourceAccounts      = $repository->getJournalSourceAccounts($journal);
304
        $destinationAccounts = $repository->getJournalDestinationAccounts($journal);
305
        $optionalFields      = app('preferences')->get('transaction_journal_optional_fields', [])->data;
306
        $pTransaction        = $repository->getFirstPosTransaction($journal);
307
        $foreignCurrency     = $pTransaction->foreignCurrency ?? $pTransaction->transactionCurrency;
308
        $preFilled           = [
309
            'date'                 => $repository->getJournalDate($journal, null), //  $journal->dateAsString()
310
            'interest_date'        => $repository->getJournalDate($journal, 'interest_date'),
311
            'book_date'            => $repository->getJournalDate($journal, 'book_date'),
312
            'process_date'         => $repository->getJournalDate($journal, 'process_date'),
313
            'category'             => $repository->getJournalCategoryName($journal),
314
            'budget_id'            => $repository->getJournalBudgetId($journal),
315
            'tags'                 => implode(',', $repository->getTags($journal)),
316
            'source_id'            => $sourceAccounts->first()->id,
317
            'source_name'          => $sourceAccounts->first()->edit_name,
318
            'destination_id'       => $destinationAccounts->first()->id,
319
            'destination_name'     => $destinationAccounts->first()->edit_name,
320
            'bill_id'              => $journal->bill_id,
321
            'bill_name'            => null === $journal->bill_id ? null : $journal->bill->name,
322
323
            // new custom fields:
324
            'due_date'             => $repository->getJournalDate($journal, 'due_date'),
325
            'payment_date'         => $repository->getJournalDate($journal, 'payment_date'),
326
            'invoice_date'         => $repository->getJournalDate($journal, 'invoice_date'),
327
            'interal_reference'    => $repository->getMetaField($journal, 'internal_reference'),
328
            'notes'                => $repository->getNoteText($journal),
329
330
            // amount fields
331
            'amount'               => $pTransaction->amount,
332
            'source_amount'        => $pTransaction->amount,
333
            'native_amount'        => $pTransaction->amount,
334
            'destination_amount'   => $pTransaction->foreign_amount,
335
            'currency'             => $pTransaction->transactionCurrency,
336
            'source_currency'      => $pTransaction->transactionCurrency,
337
            'native_currency'      => $pTransaction->transactionCurrency,
338
            'foreign_currency'     => $foreignCurrency,
339
            'destination_currency' => $foreignCurrency,
340
        ];
341
342
        // amounts for withdrawals and deposits:
343
        // amount, native_amount, source_amount, destination_amount
344
        if (null !== $pTransaction->foreign_amount && ($journal->isWithdrawal() || $journal->isDeposit())) {
345
            $preFilled['amount']   = $pTransaction->foreign_amount;
346
            $preFilled['currency'] = $pTransaction->foreignCurrency;
347
        }
348
349
        session()->flash('preFilled', $preFilled);
350
351
        // put previous url in session if not redirect from store (not "return_to_edit").
352
        if (true !== session('transactions.edit.fromUpdate')) {
353
            $this->rememberPreviousUri('transactions.edit.uri');
354
        }
355
        session()->forget('transactions.edit.fromUpdate');
356
357
        return view(
358
            'transactions.single.edit',
359
            compact('journal', 'optionalFields', 'what', 'budgetList', 'subTitle')
360
        )->with('data', $preFilled);
361
    }
362
363
    /**
364
     * Stores a new journal.
365
     *
366
     * @param JournalFormRequest         $request
367
     * @param JournalRepositoryInterface $repository
368
     *
369
     * @return RedirectResponse
370
     * @throws \FireflyIII\Exceptions\FireflyException
371
     *
372
     *
373
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
374
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
375
     */
376
    public function store(JournalFormRequest $request, JournalRepositoryInterface $repository): RedirectResponse
377
    {
378
        $doSplit       = 1 === (int)$request->get('split_journal');
379
        $createAnother = 1 === (int)$request->get('create_another');
380
        $data          = $request->getJournalData();
381
        $journal       = $repository->store($data);
382
383
384
        if (null === $journal->id) {
385
            // error!
386
            Log::error('Could not store transaction journal.');
387
            session()->flash('error', (string)trans('firefly.unknown_journal_error'));
388
389
            return redirect(route('transactions.create', [$request->input('what')]))->withInput();
390
        }
391
392
        /** @var array $files */
393
        $files = $request->hasFile('attachments') ? $request->file('attachments') : null;
394
        $this->attachments->saveAttachmentsForModel($journal, $files);
395
396
        // store the journal only, flash the rest.
397
        Log::debug(sprintf('Count of error messages is %d', $this->attachments->getErrors()->count()));
398
        if (\count($this->attachments->getErrors()->get('attachments')) > 0) {
399
            session()->flash('error', e($this->attachments->getErrors()->get('attachments')));
0 ignored issues
show
$this->attachments->getE...s()->get('attachments') of type array is incompatible with the type Illuminate\Contracts\Support\Htmlable|string expected by parameter $value of e(). ( Ignorable by Annotation )

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

399
            session()->flash('error', e(/** @scrutinizer ignore-type */ $this->attachments->getErrors()->get('attachments')));
Loading history...
400
        }
401
        // flash messages
402
        if (\count($this->attachments->getMessages()->get('attachments')) > 0) {
403
            session()->flash('info', $this->attachments->getMessages()->get('attachments'));
404
        }
405
406
        event(new StoredTransactionJournal($journal));
407
408
        session()->flash('success_uri', route('transactions.show', [$journal->id]));
409
        session()->flash('success', (string)trans('firefly.stored_journal', ['description' => $journal->description]));
410
        app('preferences')->mark();
411
412
        // @codeCoverageIgnoreStart
413
        if (true === $createAnother) {
414
            session()->put('transactions.create.fromStore', true);
415
416
            return redirect(route('transactions.create', [$request->input('what')]))->withInput();
417
        }
418
419
        if (true === $doSplit) {
420
            return redirect(route('transactions.split.edit', [$journal->id]));
421
        }
422
423
        // @codeCoverageIgnoreEnd
424
425
        return redirect($this->getPreviousUri('transactions.create.uri'));
426
    }
427
428
    /**
429
     * Update a journal.
430
     *
431
     * @param JournalFormRequest         $request
432
     * @param JournalRepositoryInterface $repository
433
     * @param TransactionJournal         $journal
434
     *
435
     * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
436
     *
437
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
438
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
439
     */
440
    public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
441
    {
442
        // @codeCoverageIgnoreStart
443
        if ($this->isOpeningBalance($journal)) {
444
            return $this->redirectToAccount($journal);
445
        }
446
        // @codeCoverageIgnoreEnd
447
448
        $data = $request->getJournalData();
449
450
        // keep current bill:
451
        $data['bill_id'] = $journal->bill_id;
452
453
        // remove it if no checkbox:
454
        if (!$request->boolean('keep_bill_id')) {
455
            $data['bill_id'] = null;
456
        }
457
458
459
        $journal = $repository->update($journal, $data);
460
        /** @var array $files */
461
        $files = $request->hasFile('attachments') ? $request->file('attachments') : null;
462
        $this->attachments->saveAttachmentsForModel($journal, $files);
463
464
        // @codeCoverageIgnoreStart
465
        if (\count($this->attachments->getErrors()->get('attachments')) > 0) {
466
            session()->flash('error', e($this->attachments->getErrors()->get('attachments')));
0 ignored issues
show
$this->attachments->getE...s()->get('attachments') of type array is incompatible with the type Illuminate\Contracts\Support\Htmlable|string expected by parameter $value of e(). ( Ignorable by Annotation )

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

466
            session()->flash('error', e(/** @scrutinizer ignore-type */ $this->attachments->getErrors()->get('attachments')));
Loading history...
467
        }
468
        if (\count($this->attachments->getMessages()->get('attachments')) > 0) {
469
            session()->flash('info', $this->attachments->getMessages()->get('attachments'));
470
        }
471
        // @codeCoverageIgnoreEnd
472
473
        event(new UpdatedTransactionJournal($journal));
474
        // update, get events by date and sort DESC
475
476
        $type = strtolower($this->repository->getTransactionType($journal));
477
        session()->flash('success', (string)trans('firefly.updated_' . $type, ['description' => $data['description']]));
478
        app('preferences')->mark();
479
480
        // @codeCoverageIgnoreStart
481
        if (1 === (int)$request->get('return_to_edit')) {
482
            session()->put('transactions.edit.fromUpdate', true);
483
484
            return redirect(route('transactions.edit', [$journal->id]))->withInput(['return_to_edit' => 1]);
485
        }
486
        // @codeCoverageIgnoreEnd
487
488
        // redirect to previous URL.
489
        return redirect($this->getPreviousUri('transactions.edit.uri'));
490
    }
491
}
492