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.

TransactionJournalFactory   C
last analyzed

Complexity

Total Complexity 54

Size/Duplication

Total Lines 570
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 54
eloc 259
dl 0
loc 570
rs 6.4799
c 1
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
B create() 0 40 7
A __construct() 0 33 2
A setUser() 0 11 1
A compareCurrencies() 0 10 4
A storeMeta() 0 13 1
A setErrorOnHash() 0 5 2
A errorIfDuplicate() 0 17 4
A hashArray() 0 16 2
A forceTrDelete() 0 8 2
A storeMetaFields() 0 4 2
A validateAccounts() 0 23 5
A getCurrencyByAccount() 0 10 4
A forceDeleteOnError() 0 8 2
A getDescription() 0 5 2
B createJournal() 0 157 6
A storePiggyEvent() 0 18 3
A getForeignByAccount() 0 7 2
A getCurrency() 0 12 3

How to fix   Complexity   

Complex Class

Complex classes like TransactionJournalFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TransactionJournalFactory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * TransactionJournalFactory.php
5
 * Copyright (c) 2019 [email protected]
6
 *
7
 * This file is part of Firefly III (https://github.com/firefly-iii).
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program 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 Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
declare(strict_types=1);
24
25
namespace FireflyIII\Factory;
26
27
use Carbon\Carbon;
28
use Exception;
29
use FireflyIII\Exceptions\DuplicateTransactionException;
30
use FireflyIII\Exceptions\FireflyException;
31
use FireflyIII\Models\Account;
32
use FireflyIII\Models\Transaction;
33
use FireflyIII\Models\TransactionCurrency;
34
use FireflyIII\Models\TransactionJournal;
35
use FireflyIII\Models\TransactionJournalMeta;
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\Category\CategoryRepositoryInterface;
41
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
42
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
43
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
44
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
45
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
46
use FireflyIII\Support\NullArrayObject;
47
use FireflyIII\User;
48
use FireflyIII\Validation\AccountValidator;
49
use Illuminate\Support\Collection;
50
use Log;
51
52
/**
53
 * Class TransactionJournalFactory
54
 */
55
class TransactionJournalFactory
56
{
57
    use JournalServiceTrait;
0 ignored issues
show
introduced by
The trait FireflyIII\Services\Inte...ort\JournalServiceTrait requires some properties which are not provided by FireflyIII\Factory\TransactionJournalFactory: $name, $transactionType, $id, $accountType, $type
Loading history...
58
59
    /** @var AccountRepositoryInterface */
60
    private $accountRepository;
61
    /** @var AccountValidator */
62
    private $accountValidator;
63
    /** @var BillRepositoryInterface */
64
    private $billRepository;
65
    /** @var CurrencyRepositoryInterface */
66
    private $currencyRepository;
67
    /** @var bool */
68
    private $errorOnHash;
69
    /** @var array */
70
    private $fields;
71
    /** @var PiggyBankEventFactory */
72
    private $piggyEventFactory;
73
    /** @var PiggyBankRepositoryInterface */
74
    private $piggyRepository;
75
    /** @var TransactionFactory */
76
    private $transactionFactory;
77
    /** @var TransactionTypeRepositoryInterface */
78
    private $typeRepository;
79
    /** @var User The user */
80
    private $user;
81
82
    /**
83
     * Constructor.
84
     *
85
     * @throws Exception
86
     * @codeCoverageIgnore
87
     */
88
    public function __construct()
89
    {
90
        $this->errorOnHash = false;
91
        $this->fields      = [
92
            // sepa
93
            'sepa_cc', 'sepa_ct_op', 'sepa_ct_id',
94
            'sepa_db', 'sepa_country', 'sepa_ep',
95
            'sepa_ci', 'sepa_batch_id',
96
97
            // dates
98
            'interest_date', 'book_date', 'process_date',
99
            'due_date', 'payment_date', 'invoice_date',
100
101
            // others
102
            'recurrence_id', 'internal_reference', 'bunq_payment_id',
103
            'import_hash', 'import_hash_v2', 'external_id', 'original_source'];
104
105
106
        if ('testing' === config('app.env')) {
107
            Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
108
        }
109
110
        $this->currencyRepository = app(CurrencyRepositoryInterface::class);
111
        $this->typeRepository     = app(TransactionTypeRepositoryInterface::class);
112
        $this->transactionFactory = app(TransactionFactory::class);
113
        $this->billRepository     = app(BillRepositoryInterface::class);
114
        $this->budgetRepository   = app(BudgetRepositoryInterface::class);
115
        $this->categoryRepository = app(CategoryRepositoryInterface::class);
116
        $this->piggyRepository    = app(PiggyBankRepositoryInterface::class);
117
        $this->piggyEventFactory  = app(PiggyBankEventFactory::class);
118
        $this->tagFactory         = app(TagFactory::class);
119
        $this->accountValidator   = app(AccountValidator::class);
120
        $this->accountRepository  = app(AccountRepositoryInterface::class);
121
    }
122
123
    /**
124
     * Store a new (set of) transaction journals.
125
     *
126
     * @param array $data
127
     *
128
     * @throws DuplicateTransactionException
129
     * @throws FireflyException
130
     * @return Collection
131
     */
132
    public function create(array $data): Collection
133
    {
134
        // convert to special object.
135
        $dataObject = new NullArrayObject($data);
136
137
        Log::debug('Start of TransactionJournalFactory::create()');
138
        $collection   = new Collection;
139
        $transactions = $dataObject['transactions'] ?? [];
140
        if (0 === count($transactions)) {
141
            Log::error('There are no transactions in the array, the TransactionJournalFactory cannot continue.');
142
143
            return new Collection;
144
        }
145
        try {
146
            /** @var array $row */
147
            foreach ($transactions as $index => $row) {
148
                Log::debug(sprintf('Now creating journal %d/%d', $index + 1, count($transactions)));
149
                $journal = $this->createJournal(new NullArrayObject($row));
150
                if (null !== $journal) {
151
                    $collection->push($journal);
152
                }
153
                if (null === $journal) {
154
                    Log::error('The createJournal() method returned NULL. This may indicate an error.');
155
                }
156
            }
157
        } catch (DuplicateTransactionException $e) {
158
            Log::warning('TransactionJournalFactory::create() caught a duplicate journal in createJournal()');
159
            Log::error($e->getMessage());
160
            Log::error($e->getTraceAsString());
161
            $this->forceDeleteOnError($collection);
162
            throw new DuplicateTransactionException($e->getMessage());
163
        } catch (FireflyException $e) {
164
            Log::warning('TransactionJournalFactory::create() caught an exception.');
165
            Log::error($e->getMessage());
166
            Log::error($e->getTraceAsString());
167
            $this->forceDeleteOnError($collection);
168
            throw new FireflyException($e->getMessage());
169
        }
170
171
        return $collection;
172
    }
173
174
    /**
175
     * @param bool $errorOnHash
176
     */
177
    public function setErrorOnHash(bool $errorOnHash): void
178
    {
179
        $this->errorOnHash = $errorOnHash;
180
        if (true === $errorOnHash) {
181
            Log::info('Will trigger duplication alert for this journal.');
182
        }
183
    }
184
185
    /**
186
     * Set the user.
187
     *
188
     * @param User $user
189
     */
190
    public function setUser(User $user): void
191
    {
192
        $this->user = $user;
193
        $this->currencyRepository->setUser($this->user);
194
        $this->tagFactory->setUser($user);
195
        $this->transactionFactory->setUser($this->user);
196
        $this->billRepository->setUser($this->user);
197
        $this->budgetRepository->setUser($this->user);
198
        $this->categoryRepository->setUser($this->user);
199
        $this->piggyRepository->setUser($this->user);
200
        $this->accountRepository->setUser($this->user);
201
    }
202
203
    /**
204
     * @param TransactionJournal $journal
205
     * @param NullArrayObject    $data
206
     * @param string             $field
207
     */
208
    protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
209
    {
210
        $set = [
211
            'journal' => $journal,
212
            'name'    => $field,
213
            'data'    => (string) ($data[$field] ?? ''),
214
        ];
215
216
        Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data']));
217
218
        /** @var TransactionJournalMetaFactory $factory */
219
        $factory = app(TransactionJournalMetaFactory::class);
220
        $factory->updateOrCreate($set);
221
    }
222
223
    /**
224
     * Set foreign currency to NULL if it's the same as the normal currency:
225
     *
226
     * @param TransactionCurrency      $currency
227
     * @param TransactionCurrency|null $foreignCurrency
228
     *
229
     * @return TransactionCurrency|null
230
     */
231
    private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency
232
    {
233
        if (null === $currency) {
234
            return null;
235
        }
236
        if (null !== $foreignCurrency && $foreignCurrency->id === $currency->id) {
237
            return null;
238
        }
239
240
        return $foreignCurrency;
241
    }
242
243
    /**
244
     * @param NullArrayObject $row
245
     *
246
     * @throws FireflyException
247
     * @throws DuplicateTransactionException
248
     * @return TransactionJournal|null
249
     */
250
    private function createJournal(NullArrayObject $row): ?TransactionJournal
251
    {
252
        $row['import_hash_v2'] = $this->hashArray($row);
253
254
        $this->errorIfDuplicate($row['import_hash_v2']);
0 ignored issues
show
Bug introduced by
It seems like $row['import_hash_v2'] can also be of type null; however, parameter $hash of FireflyIII\Factory\Trans...ory::errorIfDuplicate() does only seem to accept string, 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

254
        $this->errorIfDuplicate(/** @scrutinizer ignore-type */ $row['import_hash_v2']);
Loading history...
255
256
        /** Some basic fields */
257
        $type            = $this->typeRepository->findTransactionType(null, $row['type']);
258
        $carbon          = $row['date'] ?? new Carbon;
259
        $order           = $row['order'] ?? 0;
260
        $currency        = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']);
261
        $foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']);
262
        $bill            = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']);
263
        $billId          = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null;
264
        $description     = app('steam')->cleanString((string) $row['description']);
0 ignored issues
show
Bug introduced by
The method cleanString() does not exist on FireflyIII\Support\Facades\Steam. ( Ignorable by Annotation )

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

264
        $description     = app('steam')->/** @scrutinizer ignore-call */ cleanString((string) $row['description']);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
265
266
        /** Manipulate basic fields */
267
        $carbon->setTimezone(config('app.timezone'));
268
269
        try {
270
            // validate source and destination using a new Validator.
271
            $this->validateAccounts($row);
272
        } catch (FireflyException $e) {
273
            Log::error('Could not validate source or destination.');
274
            Log::error($e->getMessage());
275
276
            return null;
277
        }
278
279
        // TODO typeOverrule: the account validator may have another opinion on the transaction type.
280
281
        /** create or get source and destination accounts  */
282
        $sourceInfo = [
283
            'id'          => (int) $row['source_id'],
284
            'name'        => $row['source_name'],
285
            'iban'        => $row['source_iban'],
286
            'number'      => $row['source_number'],
287
            'bic'         => $row['source_bic'],
288
            'currency_id' => $currency->id,
289
        ];
290
291
        $destInfo = [
292
            'id'          => (int) $row['destination_id'],
293
            'name'        => $row['destination_name'],
294
            'iban'        => $row['destination_iban'],
295
            'number'      => $row['destination_number'],
296
            'bic'         => $row['destination_bic'],
297
            'currency_id' => $currency->id,
298
        ];
299
        Log::debug('Source info:', $sourceInfo);
300
        Log::debug('Destination info:', $destInfo);
301
        Log::debug('Now calling getAccount for the source.');
302
        $sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
303
        Log::debug('Now calling getAccount for the destination.');
304
        $destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
305
        Log::debug('Done with getAccount(2x)');
306
        $currency           = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount);
307
        $foreignCurrency    = $this->compareCurrencies($currency, $foreignCurrency);
308
        $foreignCurrency    = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount);
309
        $description        = $this->getDescription($description);
310
311
        /** Create a basic journal. */
312
        $journal = TransactionJournal::create(
313
            [
314
                'user_id'                 => $this->user->id,
315
                'transaction_type_id'     => $type->id,
316
                'bill_id'                 => $billId,
317
                'transaction_currency_id' => $currency->id,
318
                'description'             => substr($description, 0, 1000),
319
                'date'                    => $carbon->format('Y-m-d H:i:s'),
320
                'order'                   => $order,
321
                'tag_count'               => 0,
322
                'completed'               => 0,
323
            ]
324
        );
325
        Log::debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description));
326
327
        /** Create two transactions. */
328
        /** @var TransactionFactory $transactionFactory */
329
        $transactionFactory = app(TransactionFactory::class);
330
        $transactionFactory->setUser($this->user);
331
        $transactionFactory->setJournal($journal);
332
        $transactionFactory->setAccount($sourceAccount);
333
        $transactionFactory->setCurrency($currency);
334
        $transactionFactory->setForeignCurrency($foreignCurrency);
335
        $transactionFactory->setReconciled($row['reconciled'] ?? false);
336
        try {
337
            $negative = $transactionFactory->createNegative((string) $row['amount'], (string) $row['foreign_amount']);
338
        } catch (FireflyException $e) {
339
            Log::error('Exception creating negative transaction.');
340
            Log::error($e->getMessage());
341
            Log::error($e->getTraceAsString());
342
            $this->forceDeleteOnError(new Collection([$journal]));
343
            throw new FireflyException($e->getMessage());
344
        }
345
346
        // and the destination one:
347
        /** @var TransactionFactory $transactionFactory */
348
        $transactionFactory = app(TransactionFactory::class);
349
        $transactionFactory->setUser($this->user);
350
        $transactionFactory->setJournal($journal);
351
        $transactionFactory->setAccount($destinationAccount);
352
        $transactionFactory->setCurrency($currency);
353
        $transactionFactory->setForeignCurrency($foreignCurrency);
354
        $transactionFactory->setReconciled($row['reconciled'] ?? false);
355
        try {
356
            $transactionFactory->createPositive((string) $row['amount'], (string) $row['foreign_amount']);
357
        } catch (FireflyException $e) {
358
            Log::error('Exception creating positive transaction.');
359
            Log::error($e->getMessage());
360
            Log::error($e->getTraceAsString());
361
            Log::warning('Delete negative transaction.');
362
            $this->forceTrDelete($negative);
363
            $this->forceDeleteOnError(new Collection([$journal]));
364
            throw new FireflyException($e->getMessage());
365
        }
366
367
368
        // verify that journal has two transactions. Otherwise, delete and cancel.
369
        // TODO this can't be faked so it can't be tested.
370
        //        $count = $journal->transactions()->count();
371
        //        if (2 !== $count) {
372
        //            // @codeCoverageIgnoreStart
373
        //            Log::error(sprintf('The journal unexpectedly has %d transaction(s). This is not OK. Cancel operation.', $count));
374
        //            try {
375
        //                $journal->delete();
376
        //            } catch (Exception $e) {
377
        //                Log::debug(sprintf('Dont care: %s.', $e->getMessage()));
378
        //            }
379
        //
380
        //            return null;
381
        //            // @codeCoverageIgnoreEnd
382
        //        }
383
        $journal->completed = true;
384
        $journal->save();
385
386
        /** Link all other data to the journal. */
387
388
        /** Link budget */
389
        $this->storeBudget($journal, $row);
390
391
        /** Link category */
392
        $this->storeCategory($journal, $row);
393
394
        /** Set notes */
395
        $this->storeNotes($journal, $row['notes']);
396
397
        /** Set piggy bank */
398
        $this->storePiggyEvent($journal, $row);
399
400
        /** Set tags */
401
        $this->storeTags($journal, $row['tags']);
402
403
        /** set all meta fields */
404
        $this->storeMetaFields($journal, $row);
405
406
        return $journal;
407
    }
408
409
    /**
410
     * If this transaction already exists, throw an error.
411
     *
412
     * @param string $hash
413
     *
414
     * @throws DuplicateTransactionException
415
     */
416
    private function errorIfDuplicate(string $hash): void
417
    {
418
        Log::debug(sprintf('In errorIfDuplicate(%s)', $hash));
419
        if (false === $this->errorOnHash) {
420
            return;
421
        }
422
        $result = null;
423
        if ($this->errorOnHash) {
424
            Log::debug('Will verify duplicate!');
425
            /** @var TransactionJournalMeta $result */
426
            $result = TransactionJournalMeta::where('data', json_encode($hash, JSON_THROW_ON_ERROR))
427
                                            ->with(['transactionJournal', 'transactionJournal.transactionGroup'])
428
                                            ->first();
429
        }
430
        if (null !== $result) {
431
            Log::warning('Found a duplicate!');
432
            throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id));
433
        }
434
    }
435
436
    /**
437
     * Force the deletion of an entire set of transaction journals and their meta object in case of
438
     * an error creating a group.
439
     *
440
     * @param Collection $collection
441
     */
442
    private function forceDeleteOnError(Collection $collection): void
443
    {
444
        Log::debug(sprintf('forceDeleteOnError on collection size %d item(s)', $collection->count()));
445
        $service = app(JournalDestroyService::class);
446
        /** @var TransactionJournal $journal */
447
        foreach ($collection as $journal) {
448
            Log::debug(sprintf('forceDeleteOnError on journal #%d', $journal->id));
449
            $service->destroy($journal);
450
        }
451
    }
452
453
    /**
454
     * @param Transaction $transaction
455
     */
456
    private function forceTrDelete(Transaction $transaction): void
457
    {
458
        try {
459
            $transaction->delete();
460
        } catch (Exception $e) {
461
            Log::error($e->getMessage());
462
            Log::error($e->getTraceAsString());
463
            Log::error('Could not delete negative transaction.');
464
        }
465
    }
466
467
    /**
468
     * @param TransactionCurrency|null $currency
469
     * @param Account                  $account
470
     *
471
     * @return TransactionCurrency
472
     */
473
    private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
474
    {
475
        Log::debug('Now in getCurrency()');
476
        $preference = $this->accountRepository->getAccountCurrency($account);
477
        if (null === $preference && null === $currency) {
478
            // return user's default:
479
            return app('amount')->getDefaultCurrencyByUser($this->user);
480
        }
481
        $result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency();
0 ignored issues
show
Bug introduced by
The method getSystemCurrency() does not exist on FireflyIII\Support\Facades\Amount. ( Ignorable by Annotation )

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

481
        $result = ($preference ?? $currency) ?? app('amount')->/** @scrutinizer ignore-call */ getSystemCurrency();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
482
        Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
483
484
        return $result;
485
    }
486
487
    /**
488
     * @param string                   $type
489
     * @param TransactionCurrency|null $currency
490
     * @param Account                  $source
491
     * @param Account                  $destination
492
     *
493
     * @return TransactionCurrency
494
     */
495
    private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency
496
    {
497
        Log::debug('Now ingetCurrencyByAccount()');
498
        switch ($type) {
499
            default:
500
            case TransactionType::WITHDRAWAL:
501
            case TransactionType::TRANSFER:
502
                return $this->getCurrency($currency, $source);
503
            case TransactionType::DEPOSIT:
504
                return $this->getCurrency($currency, $destination);
505
506
        }
507
    }
508
509
    /**
510
     * @param string $description
511
     *
512
     * @return string
513
     */
514
    private function getDescription(string $description): string
515
    {
516
        $description = '' === $description ? '(empty description)' : $description;
517
518
        return substr($description, 0, 255);
519
    }
520
521
    /**
522
     * @param string                   $type
523
     * @param TransactionCurrency|null $foreignCurrency
524
     * @param Account                  $destination
525
     *
526
     * @return TransactionCurrency|null
527
     */
528
    private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency
529
    {
530
        if (TransactionType::TRANSFER === $type) {
531
            return $this->getCurrency($foreignCurrency, $destination);
532
        }
533
534
        return $foreignCurrency;
535
    }
536
537
    /**
538
     * @param NullArrayObject $row
539
     *
540
     * @return string
541
     */
542
    private function hashArray(NullArrayObject $row): string
543
    {
544
        $dataRow = $row->getArrayCopy();
545
546
        unset($dataRow['import_hash_v2'], $dataRow['original_source']);
547
        $json = json_encode($dataRow, JSON_THROW_ON_ERROR, 512);
548
        if (false === $json) {
549
            // @codeCoverageIgnoreStart
550
            $json = json_encode((string) microtime(), JSON_THROW_ON_ERROR, 512);
551
            Log::error(sprintf('Could not hash the original row! %s', json_last_error_msg()), $dataRow);
552
            // @codeCoverageIgnoreEnd
553
        }
554
        $hash = hash('sha256', $json);
555
        Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
556
557
        return $hash;
558
    }
559
560
    /**
561
     * @param TransactionJournal $journal
562
     * @param NullArrayObject    $transaction
563
     */
564
    private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
565
    {
566
        foreach ($this->fields as $field) {
567
            $this->storeMeta($journal, $transaction, $field);
568
        }
569
    }
570
571
    /**
572
     * Link a piggy bank to this journal.
573
     *
574
     * @param TransactionJournal $journal
575
     * @param NullArrayObject    $data
576
     */
577
    private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void
578
    {
579
        Log::debug('Will now store piggy event.');
580
        if (!$journal->isTransfer()) {
581
            Log::debug('Journal is not a transfer, do nothing.');
582
583
            return;
584
        }
585
586
        $piggyBank = $this->piggyRepository->findPiggyBank((int) $data['piggy_bank_id'], $data['piggy_bank_name']);
587
588
        if (null !== $piggyBank) {
589
            $this->piggyEventFactory->create($journal, $piggyBank);
590
            Log::debug('Create piggy event.');
591
592
            return;
593
        }
594
        Log::debug('Create no piggy event');
595
    }
596
597
    /**
598
     * @param NullArrayObject $data
599
     *
600
     * @throws FireflyException
601
     */
602
    private function validateAccounts(NullArrayObject $data): void
603
    {
604
        $transactionType = $data['type'] ?? 'invalid';
605
        $this->accountValidator->setUser($this->user);
606
        $this->accountValidator->setTransactionType($transactionType);
607
608
        // validate source account.
609
        $sourceId    = isset($data['source_id']) ? (int) $data['source_id'] : null;
610
        $sourceName  = $data['source_name'] ?? null;
611
        $validSource = $this->accountValidator->validateSource($sourceId, $sourceName, null);
612
613
        // do something with result:
614
        if (false === $validSource) {
615
            throw new FireflyException(sprintf('Source: %s', $this->accountValidator->sourceError)); // @codeCoverageIgnore
616
        }
617
        Log::debug('Source seems valid.');
618
        // validate destination account
619
        $destinationId    = isset($data['destination_id']) ? (int) $data['destination_id'] : null;
620
        $destinationName  = (string)($data['destination_name'] ?? null);
621
        $validDestination = $this->accountValidator->validateDestination($destinationId, $destinationName, null);
622
        // do something with result:
623
        if (false === $validDestination) {
624
            throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError)); // @codeCoverageIgnore
625
        }
626
    }
627
628
629
}
630