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.

Issues (724)

Services/Internal/Support/JournalServiceTrait.php (2 issues)

1
<?php
2
/**
3
 * JournalServiceTrait.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
22
declare(strict_types=1);
23
24
namespace FireflyIII\Services\Internal\Support;
25
26
use Exception;
27
use FireflyIII\Exceptions\FireflyException;
28
use FireflyIII\Factory\AccountMetaFactory;
29
use FireflyIII\Factory\TagFactory;
30
use FireflyIII\Models\Account;
31
use FireflyIII\Models\AccountType;
32
use FireflyIII\Models\Note;
33
use FireflyIII\Models\TransactionJournal;
34
use FireflyIII\Models\TransactionType;
35
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
36
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
37
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
38
use FireflyIII\Support\NullArrayObject;
39
use Log;
40
41
/**
42
 * Trait JournalServiceTrait
43
 *
44
 */
45
trait JournalServiceTrait
46
{
47
    /** @var AccountRepositoryInterface */
48
    private $accountRepository;
49
    /** @var BudgetRepositoryInterface */
50
    private $budgetRepository;
51
    /** @var CategoryRepositoryInterface */
52
    private $categoryRepository;
53
    /** @var TagFactory */
54
    private $tagFactory;
55
56
57
    /**
58
     * @param string|null $amount
59
     *
60
     * @return string
61
     * @codeCoverageIgnore
62
     */
63
    protected function getForeignAmount(?string $amount): ?string
64
    {
65
        if (null === $amount) {
66
            Log::debug('No foreign amount info in array. Return NULL');
67
68
            return null;
69
        }
70
        if ('' === $amount) {
71
            Log::debug('Foreign amount is empty string, return NULL.');
72
73
            return null;
74
        }
75
        if (0 === bccomp('0', $amount)) {
76
            Log::debug('Foreign amount is 0.0, return NULL.');
77
78
            return null;
79
        }
80
        Log::debug(sprintf('Foreign amount is %s', $amount));
81
82
        return $amount;
83
    }
84
85
    /**
86
     * @param string $transactionType
87
     * @param string $direction
88
     * @param array  $data
89
     *
90
     * @throws FireflyException
91
     * @return Account
92
     * @codeCoverageIgnore
93
     */
94
    protected function getAccount(string $transactionType, string $direction, array $data): Account
95
    {
96
        // some debug logging:
97
        Log::debug(sprintf('Now in getAccount(%s)', $direction), $data);
98
99
        // final result:
100
        $result = null;
0 ignored issues
show
The assignment to $result is dead and can be removed.
Loading history...
101
102
        // expected type of source account, in order of preference
103
        /** @var array $array */
104
        $array         = config('firefly.expected_source_types');
105
        $expectedTypes = $array[$direction];
106
        unset($array);
107
108
        // and now try to find it, based on the type of transaction.
109
        $message = 'Based on the fact that the transaction is a %s, the %s account should be in: %s. Direction is %s.';
110
        Log::debug(sprintf($message, $transactionType, $direction, implode(', ', $expectedTypes[$transactionType]), $direction));
111
112
        $result = $this->findAccountById($data, $expectedTypes[$transactionType]);
113
        $result = $this->findAccountByName($result, $data, $expectedTypes[$transactionType]);
114
        $result = $this->findAccountByIban($result, $data, $expectedTypes[$transactionType]);
115
        $result = $this->getCashAccount($result, $data, $expectedTypes[$transactionType]);
116
        $result = $this->createAccount($result, $data, $expectedTypes[$transactionType][0]);
117
118
        return $result;
119
    }
120
121
    /**
122
     * @param string $amount
123
     *
124
     * @return string
125
     * @throws FireflyException
126
     * @codeCoverageIgnore
127
     */
128
    protected function getAmount(string $amount): string
129
    {
130
        if ('' === $amount) {
131
            throw new FireflyException(sprintf('The amount cannot be an empty string: "%s"', $amount));
132
        }
133
        if (0 === bccomp('0', $amount)) {
134
            throw new FireflyException(sprintf('The amount seems to be zero: "%s"', $amount));
135
        }
136
137
        return $amount;
138
    }
139
140
    /**
141
     * @param TransactionJournal $journal
142
     * @param NullArrayObject    $data
143
     *
144
     * @codeCoverageIgnore
145
     */
146
    protected function storeBudget(TransactionJournal $journal, NullArrayObject $data): void
147
    {
148
        if (TransactionType::WITHDRAWAL !== $journal->transactionType->type) {
149
            $journal->budgets()->sync([]);
150
151
            return;
152
        }
153
        $budget = $this->budgetRepository->findBudget($data['budget_id'], $data['budget_name']);
154
        if (null !== $budget) {
155
            Log::debug(sprintf('Link budget #%d to journal #%d', $budget->id, $journal->id));
156
            $journal->budgets()->sync([$budget->id]);
157
158
            return;
159
        }
160
        // if the budget is NULL, sync empty.
161
        $journal->budgets()->sync([]);
162
    }
163
164
    /**
165
     * @param TransactionJournal $journal
166
     * @param NullArrayObject    $data
167
     *
168
     * @codeCoverageIgnore
169
     */
170
    protected function storeCategory(TransactionJournal $journal, NullArrayObject $data): void
171
    {
172
        $category = $this->categoryRepository->findCategory($data['category_id'], $data['category_name']);
173
        if (null !== $category) {
174
            Log::debug(sprintf('Link category #%d to journal #%d', $category->id, $journal->id));
175
            $journal->categories()->sync([$category->id]);
176
177
            return;
178
        }
179
        // if the category is NULL, sync empty.
180
        $journal->categories()->sync([]);
181
    }
182
183
    /**
184
     * @param TransactionJournal $journal
185
     * @param string             $notes
186
     *
187
     * @codeCoverageIgnore
188
     */
189
    protected function storeNotes(TransactionJournal $journal, ?string $notes): void
190
    {
191
        $notes = (string)$notes;
192
        $note  = $journal->notes()->first();
193
        if ('' !== $notes) {
194
            if (null === $note) {
195
                $note = new Note;
196
                $note->noteable()->associate($journal);
197
            }
198
            $note->text = $notes;
199
            $note->save();
200
            Log::debug(sprintf('Stored notes for journal #%d', $journal->id));
201
202
            return;
203
        }
204
        if ('' === $notes && null !== $note) {
205
            // try to delete existing notes.
206
            try {
207
                $note->delete();
208
                // @codeCoverageIgnoreStart
209
            } catch (Exception $e) {
210
                Log::debug(sprintf('Could not delete journal notes: %s', $e->getMessage()));
211
            }
212
            // @codeCoverageIgnoreEnd
213
        }
214
    }
215
216
    /**
217
     * Link tags to journal.
218
     *
219
     * @param TransactionJournal $journal
220
     * @param array              $tags
221
     *
222
     * @codeCoverageIgnore
223
     */
224
    protected function storeTags(TransactionJournal $journal, ?array $tags): void
225
    {
226
227
        $this->tagFactory->setUser($journal->user);
228
        $set = [];
229
        if (!is_array($tags)) {
230
            return;
231
        }
232
        foreach ($tags as $string) {
233
            $string = (string)$string;
234
            if ('' !== $string) {
235
                $tag = $this->tagFactory->findOrCreate($string);
236
                if (null !== $tag) {
237
                    $set[] = $tag->id;
238
                }
239
            }
240
        }
241
        $journal->tags()->sync($set);
242
    }
243
244
    /**
245
     * @param array $data
246
     * @param array $types
247
     *
248
     * @return Account|null
249
     */
250
    private function findAccountById(array $data, array $types): ?Account
251
    {
252
        $search = null;
253
        // first attempt, find by ID.
254
        if (null !== $data['id']) {
255
            $search = $this->accountRepository->findNull($data['id']);
256
            if (null !== $search && in_array($search->accountType->type, $types, true)) {
257
                Log::debug(
258
                    sprintf('Found "account_id" object: #%d, "%s" of type %s', $search->id, $search->name, $search->accountType->type)
259
                );
260
            }
261
        }
262
263
        return $search;
264
    }
265
266
    /**
267
     * @param Account|null $account
268
     * @param array        $data
269
     * @param array        $types
270
     *
271
     * @return Account|null
272
     */
273
    private function findAccountByName(?Account $account, array $data, array $types): ?Account
274
    {
275
        // second attempt, find by name.
276
        if (null === $account && null !== $data['name']) {
277
            Log::debug('Found nothing by account ID.');
278
            // find by preferred type.
279
            $source = $this->accountRepository->findByName($data['name'], [$types[0]]);
280
            // or any expected type.
281
            $source = $source ?? $this->accountRepository->findByName($data['name'], $types);
282
283
            if (null !== $source) {
284
                Log::debug(sprintf('Found "account_name" object: #%d, %s', $source->id, $source->name));
285
286
                $account = $source;
287
            }
288
        }
289
290
        return $account;
291
    }
292
293
    /**
294
     * @param Account|null $account
295
     * @param array        $data
296
     * @param array        $types
297
     *
298
     * @return Account|null
299
     */
300
    private function findAccountByIban(?Account $account, array $data, array $types): ?Account
301
    {
302
        // third attempt, find by IBAN
303
        if (null === $account && null !== $data['iban']) {
304
            Log::debug('Found nothing by account name.');
305
            // find by preferred type.
306
            $source = $this->accountRepository->findByIbanNull($data['iban'], [$types[0]]);
307
            // or any expected type.
308
            $source = $source ?? $this->accountRepository->findByIbanNull($data['iban'], $types);
309
310
            if (null !== $source) {
311
                Log::debug(sprintf('Found "account_iban" object: #%d, %s', $source->id, $source->name));
312
313
                $account = $source;
314
            }
315
        }
316
317
        return $account;
318
    }
319
320
    /**
321
     * @param Account|null $account
322
     * @param array        $data
323
     * @param array        $types
324
     *
325
     * @return Account|null
326
     */
327
    private function getCashAccount(?Account $account, array $data, array $types): ?Account
328
    {
329
        // return cash account.
330
        if (null === $account && null === $data['name']
331
            && in_array(AccountType::CASH, $types, true)) {
332
            $account = $this->accountRepository->getCashAccount();
333
        }
334
335
        return $account;
336
    }
337
338
    /**
339
     * @param Account|null $account
340
     * @param array        $data
341
     * @param string       $preferredType
342
     *
343
     * @throws FireflyException
344
     * @return Account
345
     */
346
    private function createAccount(?Account $account, array $data, string $preferredType): Account
347
    {
348
        Log::debug('Now in createAccount()', $data);
349
        // return new account.
350
        if (null === $account) {
351
            $data['name'] = $data['name'] ?? '(no name)';
352
353
            // final attempt, create it.
354
            if (AccountType::ASSET === $preferredType) {
355
                throw new FireflyException('TransactionFactory: Cannot create asset account with these values', $data);
0 ignored issues
show
$data of type array is incompatible with the type integer expected by parameter $code of FireflyIII\Exceptions\Fi...xception::__construct(). ( Ignorable by Annotation )

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

355
                throw new FireflyException('TransactionFactory: Cannot create asset account with these values', /** @scrutinizer ignore-type */ $data);
Loading history...
356
            }
357
358
            $account = $this->accountRepository->store(
359
                [
360
                    'account_type_id' => null,
361
                    'account_type'    => $preferredType,
362
                    'name'            => $data['name'],
363
                    'virtual_balance' => null,
364
                    'active'          => true,
365
                    'iban'            => $data['iban'],
366
                    'currency_id'     => $data['currency_id'] ?? null,
367
                ]
368
            );
369
            // store BIC
370
            if (null !== $data['bic']) {
371
                /** @var AccountMetaFactory $metaFactory */
372
                $metaFactory = app(AccountMetaFactory::class);
373
                $metaFactory->create(['account_id' => $account->id, 'name' => 'BIC', 'data' => $data['bic']]);
374
            }
375
            // store account number
376
            if (null !== $data['number']) {
377
                /** @var AccountMetaFactory $metaFactory */
378
                $metaFactory = app(AccountMetaFactory::class);
379
                $metaFactory->create(['account_id' => $account->id, 'name' => 'account_number', 'data' => $data['bic']]);
380
            }
381
382
        }
383
384
        return $account;
385
    }
386
}
387