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.

JournalUpdateService   F
last analyzed

Complexity

Total Complexity 80

Size/Duplication

Total Lines 694
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 80
eloc 299
c 2
b 0
f 0
dl 0
loc 694
rs 2

30 Methods

Rating   Name   Duplication   Size   Complexity  
A setData() 0 3 1
A setTransactionGroup() 0 8 1
A setTransactionJournal() 0 3 1
A __construct() 0 11 1
A getExpectedType() 0 8 3
A getDestinationTransaction() 0 7 2
A hasValidAccounts() 0 3 2
A getOriginalSourceAccount() 0 8 2
A hasFields() 0 9 3
A getValidDestinationAccount() 0 27 3
A getValidSourceAccount() 0 28 3
A getSourceTransaction() 0 8 2
A update() 0 38 2
A getOriginalDestinationAccount() 0 8 2
A updateAccounts() 0 27 2
A hasValidDestinationAccount() 0 31 2
A updateType() 0 26 4
B updateForeignAmount() 0 59 7
A updateCurrency() 0 26 3
A hasValidSourceAccount() 0 29 2
A updateMetaFields() 0 15 4
A updateBudget() 0 6 2
A updateMeta() 0 13 3
A updateBill() 0 14 5
A updateNotes() 0 6 3
A updateTags() 0 6 2
A updateAmount() 0 28 3
A updateField() 0 5 3
A updateCategory() 0 7 2
A updateMetaDateFields() 0 21 5

How to fix   Complexity   

Complex Class

Complex classes like JournalUpdateService 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 JournalUpdateService, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * JournalUpdateService.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\Update;
25
26
use Carbon\Carbon;
27
use Exception;
28
use FireflyIII\Exceptions\FireflyException;
29
use FireflyIII\Factory\TagFactory;
30
use FireflyIII\Factory\TransactionJournalMetaFactory;
31
use FireflyIII\Factory\TransactionTypeFactory;
32
use FireflyIII\Models\Account;
33
use FireflyIII\Models\Transaction;
34
use FireflyIII\Models\TransactionGroup;
35
use FireflyIII\Models\TransactionJournal;
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\Services\Internal\Support\JournalServiceTrait;
43
use FireflyIII\Support\NullArrayObject;
44
use FireflyIII\Validation\AccountValidator;
45
use Log;
46
47
/**
48
 * Class to centralise code that updates a journal given the input by system.
49
 *
50
 * Class JournalUpdateService
51
 * TODO test me
52
 */
53
class JournalUpdateService
54
{
55
    use JournalServiceTrait;
0 ignored issues
show
introduced by
The trait FireflyIII\Services\Inte...ort\JournalServiceTrait requires some properties which are not provided by FireflyIII\Services\Inte...te\JournalUpdateService: $name, $transactionType, $id, $accountType, $type, $user
Loading history...
56
57
    /** @var BillRepositoryInterface */
58
    private $billRepository;
59
    /** @var CurrencyRepositoryInterface */
60
    private $currencyRepository;
61
    /** @var array The data to update the journal with. */
62
    private $data;
63
    /** @var Account The destination account. */
64
    private $destinationAccount;
65
    /** @var Transaction */
66
    private $destinationTransaction;
67
    /** @var array All meta values that are dates. */
68
    private $metaDate;
69
    /** @var array All meta values that are strings. */
70
    private $metaString;
71
    /** @var Account Source account of the journal */
72
    private $sourceAccount;
73
    /** @var Transaction Source transaction of the journal. */
74
    private $sourceTransaction;
75
    /** @var TransactionGroup The parent group. */
76
    private $transactionGroup;
77
    /** @var TransactionJournal The journal to update. */
78
    private $transactionJournal;
79
    /** @var Account If new account info is submitted, this array will hold the valid destination. */
80
    private $validDestination;
81
    /** @var Account If new account info is submitted, this array will hold the valid source. */
82
    private $validSource;
83
84
    /**
85
     * JournalUpdateService constructor.
86
     */
87
    public function __construct()
88
    {
89
        $this->billRepository     = app(BillRepositoryInterface::class);
90
        $this->categoryRepository = app(CategoryRepositoryInterface::class);
91
        $this->budgetRepository   = app(BudgetRepositoryInterface::class);
92
        $this->tagFactory         = app(TagFactory::class);
93
        $this->accountRepository  = app(AccountRepositoryInterface::class);
94
        $this->currencyRepository = app(CurrencyRepositoryInterface::class);
95
        $this->metaString         = ['sepa_cc', 'sepa_ct_op', 'sepa_ct_id', 'sepa_db', 'sepa_country', 'sepa_ep', 'sepa_ci', 'sepa_batch_id', 'recurrence_id',
96
                                     'internal_reference', 'bunq_payment_id', 'external_id',];
97
        $this->metaDate           = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date',];
98
    }
99
100
    /**
101
     * @param array $data
102
     */
103
    public function setData(array $data): void
104
    {
105
        $this->data = $data;
106
    }
107
108
    /**
109
     * @param TransactionGroup $transactionGroup
110
     */
111
    public function setTransactionGroup(TransactionGroup $transactionGroup): void
112
    {
113
        $this->transactionGroup = $transactionGroup;
114
        $this->billRepository->setUser($transactionGroup->user);
115
        $this->categoryRepository->setUser($transactionGroup->user);
116
        $this->budgetRepository->setUser($transactionGroup->user);
117
        $this->tagFactory->setUser($transactionGroup->user);
118
        $this->accountRepository->setUser($transactionGroup->user);
119
    }
120
121
    /**
122
     * @param TransactionJournal $transactionJournal
123
     */
124
    public function setTransactionJournal(TransactionJournal $transactionJournal): void
125
    {
126
        $this->transactionJournal = $transactionJournal;
127
    }
128
129
    /**
130
     *
131
     */
132
    public function update(): void
133
    {
134
        Log::debug(sprintf('Now in JournalUpdateService for journal #%d.', $this->transactionJournal->id));
135
        // can we update account data using the new type?
136
        if ($this->hasValidAccounts()) {
137
            Log::info('-- account info is valid, now update.');
138
            // update accounts:
139
            $this->updateAccounts();
140
141
            // then also update transaction journal type ID:
142
            $this->updateType();
143
            $this->transactionJournal->refresh();
144
        }
145
        // find and update bill, if possible.
146
        $this->updateBill();
147
148
        // update journal fields.
149
        $this->updateField('description');
150
        $this->updateField('date');
151
        $this->updateField('order');
152
153
        $this->transactionJournal->save();
154
        $this->transactionJournal->refresh();
155
156
        $this->updateCategory();
157
        $this->updateBudget();
158
        $this->updateTags();
159
        $this->updateNotes();
160
        $this->updateMeta();
161
        $this->updateCurrency();
162
        $this->updateAmount();
163
        $this->updateForeignAmount();
164
165
        // TODO update hash
166
167
        app('preferences')->mark();
168
169
        $this->transactionJournal->refresh();
170
    }
171
172
    /**
173
     * Get destination transaction.
174
     *
175
     * @return Transaction
176
     */
177
    private function getDestinationTransaction(): Transaction
178
    {
179
        if (null === $this->destinationTransaction) {
180
            $this->destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first();
181
        }
182
183
        return $this->destinationTransaction;
184
    }
185
186
    /**
187
     * This method returns the current or expected type of the journal (in case of a change) based on the data in the array.
188
     *
189
     * If the array contains key 'type' and the value is correct, this is returned. Otherwise, the original type is returned.
190
     *
191
     * @return string
192
     */
193
    private function getExpectedType(): string
194
    {
195
        Log::debug('Now in getExpectedType()');
196
        if ($this->hasFields(['type'])) {
197
            return ucfirst('opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']);
198
        }
199
200
        return $this->transactionJournal->transactionType->type;
201
    }
202
203
    /**
204
     * @return Account
205
     */
206
    private function getOriginalDestinationAccount(): Account
207
    {
208
        if (null === $this->destinationAccount) {
209
            $destination              = $this->getSourceTransaction();
210
            $this->destinationAccount = $destination->account;
211
        }
212
213
        return $this->destinationAccount;
214
    }
215
216
    /**
217
     * @return Account
218
     */
219
    private function getOriginalSourceAccount(): Account
220
    {
221
        if (null === $this->sourceAccount) {
222
            $source              = $this->getSourceTransaction();
223
            $this->sourceAccount = $source->account;
224
        }
225
226
        return $this->sourceAccount;
227
    }
228
229
    /**
230
     * @return Transaction
231
     */
232
    private function getSourceTransaction(): Transaction
233
    {
234
        if (null === $this->sourceTransaction) {
235
            $this->sourceTransaction = $this->transactionJournal->transactions()->with(['account'])->where('amount', '<', 0)->first();
236
        }
237
        Log::debug(sprintf('getSourceTransaction: %s', $this->sourceTransaction->amount));
238
239
        return $this->sourceTransaction;
240
    }
241
242
    /**
243
     * Does a validation and returns the destination account. This method will break if the dest isn't really valid.
244
     *
245
     * @return Account
246
     */
247
    private function getValidDestinationAccount(): Account
248
    {
249
        Log::debug('Now in getValidDestinationAccount().');
250
251
        if (!$this->hasFields(['destination_id', 'destination_name'])) {
252
            return $this->getOriginalDestinationAccount();
253
        }
254
255
        $destInfo = [
256
            'id'     => (int)($this->data['destination_id'] ?? null),
257
            'name'   => $this->data['destination_name'] ?? null,
258
            'iban'   => $this->data['destination_iban'] ?? null,
259
            'number' => $this->data['destination_number'] ?? null,
260
            'bic'    => $this->data['destination_bic'] ?? null,
261
        ];
262
263
        // make new account validator.
264
        $expectedType = $this->getExpectedType();
265
        Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
266
        try {
267
            $result = $this->getAccount($expectedType, 'destination', $destInfo);
268
        } catch (FireflyException $e) {
269
            Log::error(sprintf('getValidDestinationAccount() threw unexpected error: %s', $e->getMessage()));
270
            $result = $this->getOriginalDestinationAccount();
271
        }
272
273
        return $result;
274
    }
275
276
    /**
277
     * Does a validation and returns the source account. This method will break if the source isn't really valid.
278
     *
279
     * @return Account
280
     */
281
    private function getValidSourceAccount(): Account
282
    {
283
        Log::debug('Now in getValidSourceAccount().');
284
285
        if (!$this->hasFields(['source_id', 'source_name'])) {
286
            return $this->getOriginalSourceAccount();
287
        }
288
289
        $sourceInfo = [
290
            'id'     => (int)($this->data['source_id'] ?? null),
291
            'name'   => $this->data['source_name'] ?? null,
292
            'iban'   => $this->data['source_iban'] ?? null,
293
            'number' => $this->data['source_number'] ?? null,
294
            'bic'    => $this->data['source_bic'] ?? null,
295
        ];
296
297
        $expectedType = $this->getExpectedType();
298
        try {
299
            $result = $this->getAccount($expectedType, 'source', $sourceInfo);
300
        } catch (FireflyException $e) {
301
            Log::error(sprintf('Cant get the valid source account: %s', $e->getMessage()));
302
303
            $result = $this->getOriginalSourceAccount();
304
        }
305
306
        Log::debug(sprintf('getValidSourceAccount() will return #%d ("%s")', $result->id, $result->name));
307
308
        return $result;
309
    }
310
311
    /**
312
     * @param array $fields
313
     *
314
     * @return bool
315
     */
316
    private function hasFields(array $fields): bool
317
    {
318
        foreach ($fields as $field) {
319
            if (array_key_exists($field, $this->data)) {
320
                return true;
321
            }
322
        }
323
324
        return false;
325
    }
326
327
    /**
328
     * @return bool
329
     */
330
    private function hasValidAccounts(): bool
331
    {
332
        return $this->hasValidSourceAccount() && $this->hasValidDestinationAccount();
333
    }
334
335
    /**
336
     * @return bool
337
     */
338
    private function hasValidDestinationAccount(): bool
339
    {
340
        Log::debug('Now in hasValidDestinationAccount().');
341
        $destId   = $this->data['destination_id'] ?? null;
342
        $destName = $this->data['destination_name'] ?? null;
343
344
        if (!$this->hasFields(['destination_id', 'destination_name'])) {
345
            $destination = $this->getOriginalDestinationAccount();
346
            $destId      = $destination->id;
347
            $destName    = $destination->name;
348
        }
349
350
        // make new account validator.
351
        $expectedType = $this->getExpectedType();
352
        Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
353
354
        // make a new validator.
355
        /** @var AccountValidator $validator */
356
        $validator = app(AccountValidator::class);
357
        $validator->setTransactionType($expectedType);
358
        $validator->setUser($this->transactionJournal->user);
359
        $validator->source = $this->getValidSourceAccount();
360
361
362
        $result = $validator->validateDestination($destId, $destName, null);
363
        Log::debug(sprintf('hasValidDestinationAccount(%d, "%s") will return %s', $destId, $destName, var_export($result, true)));
364
365
        // TODO typeOverrule: the account validator may have another opinion on the transaction type.
366
367
        // validate submitted info:
368
        return $result;
369
    }
370
371
    /**
372
     * @return bool
373
     */
374
    private function hasValidSourceAccount(): bool
375
    {
376
        Log::debug('Now in hasValidSourceAccount().');
377
        $sourceId   = $this->data['source_id'] ?? null;
378
        $sourceName = $this->data['source_name'] ?? null;
379
380
        if (!$this->hasFields(['source_id', 'source_name'])) {
381
            $sourceAccount = $this->getOriginalSourceAccount();
382
            $sourceId      = $sourceAccount->id;
383
            $sourceName    = $sourceAccount->name;
384
        }
385
386
        // make new account validator.
387
        $expectedType = $this->getExpectedType();
388
        Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
389
390
        // make a new validator.
391
        /** @var AccountValidator $validator */
392
        $validator = app(AccountValidator::class);
393
        $validator->setTransactionType($expectedType);
394
        $validator->setUser($this->transactionJournal->user);
395
396
        $result = $validator->validateSource($sourceId, $sourceName, null);
397
        Log::debug(sprintf('hasValidSourceAccount(%d, "%s") will return %s', $sourceId, $sourceName, var_export($result, true)));
398
399
        // TODO typeOverrule: the account validator may have another opinion on the transaction type.
400
401
        // validate submitted info:
402
        return $result;
403
    }
404
405
    /**
406
     * Will update the source and destination accounts of this journal. Assumes they are valid.
407
     */
408
    private function updateAccounts(): void
409
    {
410
        $source      = $this->getValidSourceAccount();
411
        $destination = $this->getValidDestinationAccount();
412
413
        // cowardly refuse to update if both accounts are the same.
414
        if ($source->id === $destination->id) {
415
            Log::error(sprintf('Source + dest accounts are equal (%d, "%s")', $source->id, $source->name));
416
417
            return;
418
        }
419
420
        $sourceTransaction = $this->getSourceTransaction();
421
        $sourceTransaction->account()->associate($source);
422
        $sourceTransaction->save();
423
424
        $destTransaction = $this->getDestinationTransaction();
425
        $destTransaction->account()->associate($destination);
426
        $destTransaction->save();
427
428
        // refresh transactions.
429
        $this->sourceTransaction->refresh();
430
        $this->destinationTransaction->refresh();
431
432
433
        Log::debug(sprintf('Will set source to #%d ("%s")', $source->id, $source->name));
434
        Log::debug(sprintf('Will set dest to #%d ("%s")', $destination->id, $destination->name));
435
    }
436
437
    /**
438
     *
439
     */
440
    private function updateAmount(): void
441
    {
442
        if (!$this->hasFields(['amount'])) {
443
            return;
444
        }
445
446
        $value = $this->data['amount'] ?? '';
447
        try {
448
            $amount = $this->getAmount($value);
449
        } catch (FireflyException $e) {
450
            Log::debug(sprintf('getAmount("%s") returns error: %s', $value, $e->getMessage()));
451
452
            return;
453
        }
454
        $sourceTransaction         = $this->getSourceTransaction();
455
        $sourceTransaction->amount = app('steam')->negative($amount);
456
        $sourceTransaction->save();
457
458
459
        $destTransaction         = $this->getDestinationTransaction();
460
        $destTransaction->amount = app('steam')->positive($amount);
461
        $destTransaction->save();
462
463
464
        // refresh transactions.
465
        $this->sourceTransaction->refresh();
466
        $this->destinationTransaction->refresh();
467
        Log::debug(sprintf('Updated amount to "%s"', $amount));
468
    }
469
470
    /**
471
     * Update journal bill information.
472
     */
473
    private function updateBill(): void
474
    {
475
        $type = $this->transactionJournal->transactionType->type;
476
        if ((
477
                array_key_exists('bill_id', $this->data)
478
                || array_key_exists('bill_name', $this->data)
479
            )
480
            && TransactionType::WITHDRAWAL === $type
481
        ) {
482
            $billId                            = (int) ($this->data['bill_id'] ?? 0);
483
            $billName                          = (string) ($this->data['bill_name'] ?? '');
484
            $bill                              = $this->billRepository->findBill($billId, $billName);
485
            $this->transactionJournal->bill_id = null === $bill ? null : $bill->id;
486
            Log::debug('Updated bill ID');
487
        }
488
    }
489
490
    /**
491
     *
492
     */
493
    private function updateBudget(): void
494
    {
495
        // update budget
496
        if ($this->hasFields(['budget_id', 'budget_name'])) {
497
            Log::debug('Will update budget.');
498
            $this->storeBudget($this->transactionJournal, new NullArrayObject($this->data));
499
        }
500
    }
501
502
    /**
503
     *
504
     */
505
    private function updateCategory(): void
506
    {
507
        // update category
508
        if ($this->hasFields(['category_id', 'category_name'])) {
509
            Log::debug('Will update category.');
510
511
            $this->storeCategory($this->transactionJournal, new NullArrayObject($this->data));
512
        }
513
    }
514
515
    /**
516
     *
517
     */
518
    private function updateCurrency(): void
519
    {
520
        // update transactions.
521
        if (!$this->hasFields(['currency_id', 'currency_code'])) {
522
            return;
523
        }
524
        $currencyId   = $this->data['currency_id'] ?? null;
525
        $currencyCode = $this->data['currency_code'] ?? null;
526
        $currency     = $this->currencyRepository->findCurrency($currencyId, $currencyCode);
527
        if (null !== $currency) {
528
            // update currency everywhere.
529
            $this->transactionJournal->transaction_currency_id = $currency->id;
530
            $this->transactionJournal->save();
531
532
            $source                          = $this->getSourceTransaction();
533
            $source->transaction_currency_id = $currency->id;
534
            $source->save();
535
536
            $dest                          = $this->getDestinationTransaction();
537
            $dest->transaction_currency_id = $currency->id;
538
            $dest->save();
539
540
            // refresh transactions.
541
            $this->sourceTransaction->refresh();
542
            $this->destinationTransaction->refresh();
543
            Log::debug(sprintf('Updated currency to #%d (%s)', $currency->id, $currency->code));
544
        }
545
    }
546
547
    /**
548
     * Update journal generic field. Cannot be set to NULL.
549
     *
550
     * @param $fieldName
551
     */
552
    private function updateField($fieldName): void
553
    {
554
        if (array_key_exists($fieldName, $this->data) && '' !== (string)$this->data[$fieldName]) {
555
            $this->transactionJournal->$fieldName = $this->data[$fieldName];
556
            Log::debug(sprintf('Updated %s', $fieldName));
557
        }
558
    }
559
560
561
    /**
562
     *
563
     */
564
    private function updateForeignAmount(): void
565
    {
566
        // amount, foreign currency.
567
        if (!$this->hasFields(['foreign_currency_id', 'foreign_currency_code', 'foreign_amount'])) {
568
            return;
569
        }
570
571
        $amount          = $this->data['foreign_amount'] ?? null;
572
        $foreignAmount   = $this->getForeignAmount($amount);
573
        $source          = $this->getSourceTransaction();
574
        $dest            = $this->getDestinationTransaction();
575
        $foreignCurrency = $source->foreignCurrency;
576
577
        // find currency in data array
578
        $newForeignId    = $this->data['foreign_currency_id'] ?? null;
579
        $newForeignCode  = $this->data['foreign_currency_code'] ?? null;
580
        $foreignCurrency = $this->currencyRepository->findCurrencyNull($newForeignId, $newForeignCode) ?? $foreignCurrency;
581
582
        // not the same as normal currency
583
        if (null !== $foreignCurrency && $foreignCurrency->id === $this->transactionJournal->transaction_currency_id) {
584
            Log::error(sprintf('Foreign currency is equal to normal currency (%s)', $foreignCurrency->code));
585
586
            return;
587
        }
588
589
        // add foreign currency info to source and destination if possible.
590
        if (null !== $foreignCurrency && null !== $foreignAmount) {
591
            $source->foreign_currency_id = $foreignCurrency->id;
592
            $source->foreign_amount      = app('steam')->negative($foreignAmount);
593
            $source->save();
594
595
596
            $dest->foreign_currency_id = $foreignCurrency->id;
597
            $dest->foreign_amount      = app('steam')->positive($foreignAmount);
598
            $dest->save();
599
600
            Log::debug(sprintf('Update foreign info to %s (#%d) %s', $foreignCurrency->code, $foreignCurrency->id, $foreignAmount));
601
602
            // refresh transactions.
603
            $this->sourceTransaction->refresh();
604
            $this->destinationTransaction->refresh();
605
606
            return;
607
        }
608
        if ('0' === $amount) {
609
            $source->foreign_currency_id = null;
610
            $source->foreign_amount      = null;
611
            $source->save();
612
613
            $dest->foreign_currency_id = null;
614
            $dest->foreign_amount      = null;
615
            $dest->save();
616
            Log::debug(sprintf('Foreign amount is "%s" so remove foreign amount info.', $amount));
617
        }
618
        Log::info('Not enough info to update foreign currency info.');
619
620
        // refresh transactions.
621
        $this->sourceTransaction->refresh();
622
        $this->destinationTransaction->refresh();
623
    }
624
625
    /**
626
     *
627
     */
628
    private function updateMeta(): void
629
    {
630
        // update meta fields.
631
        // first string
632
        if ($this->hasFields($this->metaString)) {
633
            Log::debug('Meta string fields are present.');
634
            $this->updateMetaFields();
635
        }
636
637
        // then date fields.
638
        if ($this->hasFields($this->metaDate)) {
639
            Log::debug('Meta date fields are present.');
640
            $this->updateMetaDateFields();
641
        }
642
    }
643
644
    /**
645
     *
646
     */
647
    private function updateMetaDateFields(): void
648
    {
649
        /** @var TransactionJournalMetaFactory $factory */
650
        $factory = app(TransactionJournalMetaFactory::class);
651
652
        foreach ($this->metaDate as $field) {
653
            if ($this->hasFields([$field])) {
654
                try {
655
                    $value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]);
656
                } catch (Exception $e) {
657
                    Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage()));
658
659
                    return;
660
                }
661
                Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value));
662
                $set = [
663
                    'journal' => $this->transactionJournal,
664
                    'name'    => $field,
665
                    'data'    => $value,
666
                ];
667
                $factory->updateOrCreate($set);
668
            }
669
        }
670
    }
671
672
    /**
673
     *
674
     */
675
    private function updateMetaFields(): void
676
    {
677
        /** @var TransactionJournalMetaFactory $factory */
678
        $factory = app(TransactionJournalMetaFactory::class);
679
680
        foreach ($this->metaString as $field) {
681
            if ($this->hasFields([$field])) {
682
                $value = '' === $this->data[$field] ? null : $this->data[$field];
683
                Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value));
684
                $set = [
685
                    'journal' => $this->transactionJournal,
686
                    'name'    => $field,
687
                    'data'    => $value,
688
                ];
689
                $factory->updateOrCreate($set);
690
            }
691
        }
692
    }
693
694
    /**
695
     *
696
     */
697
    private function updateNotes(): void
698
    {
699
        // update notes.
700
        if ($this->hasFields(['notes'])) {
701
            $notes = '' === (string) $this->data['notes'] ? null : $this->data['notes'];
702
            $this->storeNotes($this->transactionJournal, $notes);
703
        }
704
    }
705
706
    /**
707
     *
708
     */
709
    private function updateTags(): void
710
    {
711
        if ($this->hasFields(['tags'])) {
712
            Log::debug('Will update tags.');
713
            $tags = $this->data['tags'] ?? null;
714
            $this->storeTags($this->transactionJournal, $tags);
715
        }
716
    }
717
718
    /**
719
     * Updates journal transaction type.
720
     */
721
    private function updateType(): void
722
    {
723
        Log::debug('Now in updateType()');
724
        if ($this->hasFields(['type'])) {
725
            $type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type'];
726
            Log::debug(
727
                sprintf(
728
                    'Trying to change journal #%d from a %s to a %s.',
729
                    $this->transactionJournal->id, $this->transactionJournal->transactionType->type, $type
730
                )
731
            );
732
733
            /** @var TransactionTypeFactory $typeFactory */
734
            $typeFactory = app(TransactionTypeFactory::class);
735
            $result      = $typeFactory->find($this->data['type']);
736
            if (null !== $result) {
737
                Log::debug('Changed transaction type!');
738
                $this->transactionJournal->transaction_type_id = $result->id;
739
                $this->transactionJournal->save();
740
741
                return;
742
            }
743
744
            return;
745
        }
746
        Log::debug('No type field present.');
747
    }
748
}
749