| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2018-05-11 10:08:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * TransactionJournalFactory.php | 
					
						
							| 
									
										
										
										
											2020-02-16 14:00:57 +01:00
										 |  |  |  * Copyright (c) 2019 james@firefly-iii.org | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * This file is part of Firefly III (https://github.com/firefly-iii). | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU Affero General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation, either version 3 of the | 
					
						
							|  |  |  |  * License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * GNU Affero General Public License for more details. | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 10:08:34 +02:00
										 |  |  | declare(strict_types=1); | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace FireflyIII\Factory; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 21:12:10 +01:00
										 |  |  | use Carbon\Carbon; | 
					
						
							| 
									
										
										
										
											2025-10-05 12:59:43 +02:00
										 |  |  | use Exception; | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  | use FireflyIII\Enums\AccountTypeEnum; | 
					
						
							| 
									
										
										
										
											2024-11-22 06:03:29 +01:00
										 |  |  | use FireflyIII\Enums\TransactionTypeEnum; | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  | use FireflyIII\Exceptions\DuplicateTransactionException; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | use FireflyIII\Exceptions\FireflyException; | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  | use FireflyIII\Models\Account; | 
					
						
							| 
									
										
										
										
											2025-10-05 12:59:43 +02:00
										 |  |  | use FireflyIII\Models\Bill; | 
					
						
							| 
									
										
										
										
											2024-01-03 17:43:05 +01:00
										 |  |  | use FireflyIII\Models\Location; | 
					
						
							| 
									
										
										
										
											2025-10-05 12:59:43 +02:00
										 |  |  | use FireflyIII\Models\PiggyBank; | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  | use FireflyIII\Models\Transaction; | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  | use FireflyIII\Models\TransactionCurrency; | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | use FireflyIII\Models\TransactionJournal; | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  | use FireflyIII\Models\TransactionJournalMeta; | 
					
						
							| 
									
										
										
										
											2025-02-09 09:30:44 +01:00
										 |  |  | use FireflyIII\Models\UserGroup; | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  | use FireflyIII\Repositories\Bill\BillRepositoryInterface; | 
					
						
							|  |  |  | use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; | 
					
						
							|  |  |  | use FireflyIII\Repositories\Category\CategoryRepositoryInterface; | 
					
						
							| 
									
										
										
										
											2025-05-04 17:41:26 +02:00
										 |  |  | use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  | use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; | 
					
						
							| 
									
										
										
										
											2019-03-08 05:47:51 +01:00
										 |  |  | use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface; | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  | use FireflyIII\Services\Internal\Destroy\JournalDestroyService; | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  | use FireflyIII\Services\Internal\Support\JournalServiceTrait; | 
					
						
							| 
									
										
										
										
											2024-11-22 06:03:29 +01:00
										 |  |  | use FireflyIII\Support\Facades\FireflyConfig; | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  | use FireflyIII\Support\NullArrayObject; | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | use FireflyIII\User; | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  | use FireflyIII\Validation\AccountValidator; | 
					
						
							| 
									
										
										
										
											2019-03-05 17:26:49 +01:00
										 |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2024-07-30 18:04:39 +02:00
										 |  |  | use Illuminate\Support\Facades\Log; | 
					
						
							| 
									
										
										
										
											2025-05-27 16:57:36 +02:00
										 |  |  | use JsonException; | 
					
						
							| 
									
										
										
										
											2025-10-05 13:03:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  | use function Safe\json_encode; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Class TransactionJournalFactory | 
					
						
							| 
									
										
										
										
											2024-01-04 15:43:51 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2025-01-03 18:16:27 +01:00
										 |  |  |  * @SuppressWarnings("PHPMD.CouplingBetweenObjects") | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | class TransactionJournalFactory | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |     use JournalServiceTrait; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-13 06:35:33 +02:00
										 |  |  |     private AccountRepositoryInterface         $accountRepository; | 
					
						
							|  |  |  |     private AccountValidator                   $accountValidator; | 
					
						
							|  |  |  |     private BillRepositoryInterface            $billRepository; | 
					
						
							|  |  |  |     private CurrencyRepositoryInterface        $currencyRepository; | 
					
						
							|  |  |  |     private bool                               $errorOnHash; | 
					
						
							|  |  |  |     private array                              $fields; | 
					
						
							|  |  |  |     private PiggyBankEventFactory              $piggyEventFactory; | 
					
						
							|  |  |  |     private PiggyBankRepositoryInterface       $piggyRepository; | 
					
						
							|  |  |  |     private TransactionTypeRepositoryInterface $typeRepository; | 
					
						
							|  |  |  |     private User                               $user; | 
					
						
							| 
									
										
										
										
											2025-05-04 17:41:26 +02:00
										 |  |  |     private UserGroup                          $userGroup; | 
					
						
							| 
									
										
										
										
											2020-07-31 12:45:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 12:29:32 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Constructor. | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2025-05-27 16:57:36 +02:00
										 |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2018-09-06 12:29:32 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public function __construct() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-11-08 18:26:40 +01:00
										 |  |  |         $this->errorOnHash        = false; | 
					
						
							|  |  |  |         $this->fields             = config('firefly.journal_meta_fields'); | 
					
						
							| 
									
										
										
										
											2019-03-08 05:47:51 +01:00
										 |  |  |         $this->currencyRepository = app(CurrencyRepositoryInterface::class); | 
					
						
							|  |  |  |         $this->typeRepository     = app(TransactionTypeRepositoryInterface::class); | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  |         $this->billRepository     = app(BillRepositoryInterface::class); | 
					
						
							|  |  |  |         $this->budgetRepository   = app(BudgetRepositoryInterface::class); | 
					
						
							|  |  |  |         $this->categoryRepository = app(CategoryRepositoryInterface::class); | 
					
						
							|  |  |  |         $this->piggyRepository    = app(PiggyBankRepositoryInterface::class); | 
					
						
							| 
									
										
										
										
											2019-03-18 16:52:49 +01:00
										 |  |  |         $this->piggyEventFactory  = app(PiggyBankEventFactory::class); | 
					
						
							|  |  |  |         $this->tagFactory         = app(TagFactory::class); | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         $this->accountValidator   = app(AccountValidator::class); | 
					
						
							|  |  |  |         $this->accountRepository  = app(AccountRepositoryInterface::class); | 
					
						
							| 
									
										
										
										
											2018-09-06 12:29:32 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |      * Store a new (set of) transaction journals. | 
					
						
							| 
									
										
										
										
											2018-07-06 19:06:08 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-08-01 17:51:52 +02:00
										 |  |  |      * @throws DuplicateTransactionException | 
					
						
							| 
									
										
										
										
											2021-09-18 10:21:29 +02:00
										 |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     public function create(array $data): Collection | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Now in TransactionJournalFactory::create()'); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         // convert to special object.
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $dataObject   = new NullArrayObject($data); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Start of TransactionJournalFactory::create()'); | 
					
						
							| 
									
										
										
										
											2022-10-30 14:24:10 +01:00
										 |  |  |         $collection   = new Collection(); | 
					
						
							| 
									
										
										
										
											2020-02-22 11:05:16 +01:00
										 |  |  |         $transactions = $dataObject['transactions'] ?? []; | 
					
						
							| 
									
										
										
										
											2022-11-02 06:25:37 +01:00
										 |  |  |         if (0 === count($transactions)) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::error('There are no transactions in the array, the TransactionJournalFactory cannot continue.'); | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 14:24:10 +01:00
										 |  |  |             return new Collection(); | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         try { | 
					
						
							|  |  |  |             /** @var array $row */ | 
					
						
							|  |  |  |             foreach ($transactions as $index => $row) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |                 Log::debug(sprintf('Now creating journal %d/%d', $index + 1, count($transactions))); | 
					
						
							| 
									
										
										
										
											2020-02-22 11:05:16 +01:00
										 |  |  |                 $journal = $this->createJournal(new NullArrayObject($row)); | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |                 if ($journal instanceof TransactionJournal) { | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |                     $collection->push($journal); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |                 if (!$journal instanceof TransactionJournal) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |                     Log::error('The createJournal() method returned NULL. This may indicate an error.'); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-08-16 17:54:38 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (DuplicateTransactionException $e) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::warning('TransactionJournalFactory::create() caught a duplicate journal in createJournal()'); | 
					
						
							|  |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  |             Log::error($e->getTraceAsString()); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |             $this->forceDeleteOnError($collection); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 07:28:43 +02:00
										 |  |  |             throw new DuplicateTransactionException($e->getMessage(), 0, $e); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (FireflyException $e) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::warning('TransactionJournalFactory::create() caught an exception.'); | 
					
						
							|  |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  |             Log::error($e->getTraceAsString()); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |             $this->forceDeleteOnError($collection); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 07:28:43 +02:00
										 |  |  |             throw new FireflyException($e->getMessage(), 0, $e); | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-23 08:10:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         return $collection; | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-12-22 17:28:42 +01:00
										 |  |  |      * TODO typeOverrule: the account validator may have another opinion on the transaction type. not sure what to do | 
					
						
							|  |  |  |      * with this. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-08-01 17:51:52 +02:00
										 |  |  |      * @throws DuplicateTransactionException | 
					
						
							|  |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 17:28:42 +01:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:53:10 +01:00
										 |  |  |      * @SuppressWarnings("PHPMD.ExcessiveMethodLength") | 
					
						
							| 
									
										
										
										
											2023-12-22 17:28:42 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     private function createJournal(NullArrayObject $row): ?TransactionJournal | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Now in TransactionJournalFactory::createJournal()'); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         $row['import_hash_v2'] = $this->hashArray($row); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         $this->errorIfDuplicate($row['import_hash_v2']); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-22 06:03:29 +01:00
										 |  |  |         // Some basic fields
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $type                  = $this->typeRepository->findTransactionType(null, $row['type']); | 
					
						
							|  |  |  |         $carbon                = $row['date'] ?? today(config('app.timezone')); | 
					
						
							|  |  |  |         $order                 = $row['order'] ?? 0; | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Log::debug('Find currency or return default.'); | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $currency              = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Find foreign currency or return NULL.'); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:33:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $foreignCurrency       = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']); | 
					
						
							|  |  |  |         $bill                  = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']); | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         $billId                = TransactionTypeEnum::WITHDRAWAL->value === $type->type && $bill instanceof Bill ? $bill->id : null; | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $description           = (string) $row['description']; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |         // Manipulate basic fields
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         $carbon->setTimezone(config('app.timezone')); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-22 06:03:29 +01:00
										 |  |  |         // 2024-11-19, overrule timezone with UTC and store it as UTC.
 | 
					
						
							| 
									
										
										
										
											2024-11-23 20:59:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-03 14:56:06 +01:00
										 |  |  |         if (true === FireflyConfig::get('utc', false)->data) { | 
					
						
							| 
									
										
										
										
											2024-11-22 06:03:29 +01:00
										 |  |  |             $carbon->setTimezone('UTC'); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-02-10 04:10:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 13:54:06 +02:00
										 |  |  |         try { | 
					
						
							|  |  |  |             // validate source and destination using a new Validator.
 | 
					
						
							|  |  |  |             $this->validateAccounts($row); | 
					
						
							|  |  |  |         } catch (FireflyException $e) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::error('Could not validate source or destination.'); | 
					
						
							|  |  |  |             Log::error($e->getMessage()); | 
					
						
							| 
									
										
										
										
											2019-07-27 13:54:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-31 07:39:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         /** create or get source and destination accounts  */ | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $sourceInfo            = [ | 
					
						
							| 
									
										
										
										
											2021-04-08 11:21:20 +02:00
										 |  |  |             'id'          => $row['source_id'], | 
					
						
							| 
									
										
										
										
											2020-04-14 17:23:58 +02:00
										 |  |  |             'name'        => $row['source_name'], | 
					
						
							|  |  |  |             'iban'        => $row['source_iban'], | 
					
						
							|  |  |  |             'number'      => $row['source_number'], | 
					
						
							|  |  |  |             'bic'         => $row['source_bic'], | 
					
						
							|  |  |  |             'currency_id' => $currency->id, | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $destInfo              = [ | 
					
						
							| 
									
										
										
										
											2021-04-08 11:21:20 +02:00
										 |  |  |             'id'          => $row['destination_id'], | 
					
						
							| 
									
										
										
										
											2020-04-14 17:23:58 +02:00
										 |  |  |             'name'        => $row['destination_name'], | 
					
						
							|  |  |  |             'iban'        => $row['destination_iban'], | 
					
						
							|  |  |  |             'number'      => $row['destination_number'], | 
					
						
							|  |  |  |             'bic'         => $row['destination_bic'], | 
					
						
							|  |  |  |             'currency_id' => $currency->id, | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Source info:', $sourceInfo); | 
					
						
							|  |  |  |         Log::debug('Destination info:', $destInfo); | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $sourceAccount         = $this->getAccount($type->type, 'source', $sourceInfo); | 
					
						
							| 
									
										
										
										
											2025-09-17 07:09:40 +02:00
										 |  |  |         $destinationAccount    = $this->getAccount($type->type, 'destination', $destInfo, $sourceAccount); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Done with getAccount(2x)'); | 
					
						
							| 
									
										
										
										
											2022-10-30 06:45:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // this is the moment for a reconciliation sanity check (again).
 | 
					
						
							| 
									
										
										
										
											2024-11-22 06:03:29 +01:00
										 |  |  |         if (TransactionTypeEnum::RECONCILIATION->value === $type->type) { | 
					
						
							| 
									
										
										
										
											2022-10-30 06:45:56 +01:00
										 |  |  |             [$sourceAccount, $destinationAccount] = $this->reconciliationSanityCheck($sourceAccount, $destinationAccount); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $currency              = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount); | 
					
						
							|  |  |  |         $foreignCurrency       = $this->compareCurrencies($currency, $foreignCurrency); | 
					
						
							|  |  |  |         $foreignCurrency       = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount); | 
					
						
							|  |  |  |         $description           = $this->getDescription($description); | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Currency is #%d "%s", foreign currency is #%d "%s"', $currency->id, $currency->code, $foreignCurrency?->id, $foreignCurrency)); | 
					
						
							|  |  |  |         Log::debug(sprintf('Date: %s (%s)', $carbon->toW3cString(), $carbon->getTimezone()->getName())); | 
					
						
							| 
									
										
										
										
											2023-01-06 21:12:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         /** Create a basic journal. */ | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $journal               = TransactionJournal::create( | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |             [ | 
					
						
							|  |  |  |                 'user_id'                 => $this->user->id, | 
					
						
							| 
									
										
										
										
											2025-02-09 09:30:44 +01:00
										 |  |  |                 'user_group_id'           => $this->userGroup->id, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |                 'transaction_type_id'     => $type->id, | 
					
						
							|  |  |  |                 'bill_id'                 => $billId, | 
					
						
							|  |  |  |                 'transaction_currency_id' => $currency->id, | 
					
						
							| 
									
										
										
										
											2020-03-17 14:57:04 +01:00
										 |  |  |                 'description'             => substr($description, 0, 1000), | 
					
						
							| 
									
										
										
										
											2024-11-06 11:12:26 +01:00
										 |  |  |                 'date'                    => $carbon, | 
					
						
							|  |  |  |                 'date_tz'                 => $carbon->format('e'), | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |                 'order'                   => $order, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |                 'tag_count'               => 0, | 
					
						
							|  |  |  |                 'completed'               => 0, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description)); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** Create two transactions. */ | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $transactionFactory    = app(TransactionFactory::class); | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         $transactionFactory->setJournal($journal); | 
					
						
							|  |  |  |         $transactionFactory->setAccount($sourceAccount); | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |         $transactionFactory->setCurrency($currency); | 
					
						
							| 
									
										
										
										
											2023-02-18 06:37:05 +01:00
										 |  |  |         $transactionFactory->setAccountInformation($sourceInfo); | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |         $transactionFactory->setForeignCurrency($foreignCurrency); | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         $transactionFactory->setReconciled($row['reconciled'] ?? false); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         try { | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             $negative = $transactionFactory->createNegative((string) $row['amount'], (string) $row['foreign_amount']); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (FireflyException $e) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::error(sprintf('Exception creating negative transaction: %s', $e->getMessage())); | 
					
						
							| 
									
										
										
										
											2025-09-10 16:07:19 +02:00
										 |  |  |             $this->forceDeleteOnError(new Collection()->push($journal)); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 07:28:43 +02:00
										 |  |  |             throw new FireflyException($e->getMessage(), 0, $e); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @var TransactionFactory $transactionFactory */ | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $transactionFactory    = app(TransactionFactory::class); | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         $transactionFactory->setJournal($journal); | 
					
						
							|  |  |  |         $transactionFactory->setAccount($destinationAccount); | 
					
						
							| 
									
										
										
										
											2023-02-18 06:37:05 +01:00
										 |  |  |         $transactionFactory->setAccountInformation($destInfo); | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |         $transactionFactory->setCurrency($currency); | 
					
						
							|  |  |  |         $transactionFactory->setForeignCurrency($foreignCurrency); | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         $transactionFactory->setReconciled($row['reconciled'] ?? false); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-30 18:04:39 +02:00
										 |  |  |         // if the foreign currency is set and is different, and the transaction type is a transfer,
 | 
					
						
							|  |  |  |         // Firefly III will save the foreign currency information in such a way that both
 | 
					
						
							|  |  |  |         // asset accounts can look at the "amount" and "transaction_currency_id" column and
 | 
					
						
							|  |  |  |         // see the currency they expect to see.
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $amount                = (string) $row['amount']; | 
					
						
							|  |  |  |         $foreignAmount         = (string) $row['foreign_amount']; | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if ($foreignCurrency instanceof TransactionCurrency && $foreignCurrency->id !== $currency->id | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |             && (TransactionTypeEnum::TRANSFER->value === $type->type || $this->isBetweenAssetAndLiability($sourceAccount, $destinationAccount)) | 
					
						
							| 
									
										
										
										
											2024-07-30 18:04:39 +02:00
										 |  |  |         ) { | 
					
						
							|  |  |  |             $transactionFactory->setCurrency($foreignCurrency); | 
					
						
							|  |  |  |             $transactionFactory->setForeignCurrency($currency); | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             $amount        = (string) $row['foreign_amount']; | 
					
						
							|  |  |  |             $foreignAmount = (string) $row['amount']; | 
					
						
							| 
									
										
										
										
											2025-07-31 20:55:30 +02:00
										 |  |  |             Log::debug('Swap primary/foreign amounts in transfer for new save method.'); | 
					
						
							| 
									
										
										
										
											2024-07-31 08:31:20 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-07-30 18:04:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         try { | 
					
						
							| 
									
										
										
										
											2024-07-30 18:04:39 +02:00
										 |  |  |             $transactionFactory->createPositive($amount, $foreignAmount); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (FireflyException $e) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::error(sprintf('Exception creating positive transaction: %s', $e->getMessage())); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |             $this->forceTrDelete($negative); | 
					
						
							| 
									
										
										
										
											2025-09-10 16:07:19 +02:00
										 |  |  |             $this->forceDeleteOnError(new Collection()->push($journal)); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 07:28:43 +02:00
										 |  |  |             throw new FireflyException($e->getMessage(), 0, $e); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $journal->completed    = true; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         $journal->save(); | 
					
						
							|  |  |  |         $this->storeBudget($journal, $row); | 
					
						
							|  |  |  |         $this->storeCategory($journal, $row); | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |         $this->storeNotes($journal, $row['notes']); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         $this->storePiggyEvent($journal, $row); | 
					
						
							|  |  |  |         $this->storeTags($journal, $row['tags']); | 
					
						
							|  |  |  |         $this->storeMetaFields($journal, $row); | 
					
						
							| 
									
										
										
										
											2024-01-03 17:43:05 +01:00
										 |  |  |         $this->storeLocation($journal, $row); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $journal; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function hashArray(NullArrayObject $row): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $dataRow = $row->getArrayCopy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         unset($dataRow['import_hash_v2'], $dataRow['original_source']); | 
					
						
							| 
									
										
										
										
											2023-12-22 17:28:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |             $json = json_encode($dataRow, JSON_THROW_ON_ERROR); | 
					
						
							| 
									
										
										
										
											2025-05-27 16:57:36 +02:00
										 |  |  |         } catch (JsonException $e) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::error(sprintf('Could not encode dataRow: %s', $e->getMessage())); | 
					
						
							| 
									
										
										
										
											2023-12-22 17:28:42 +01:00
										 |  |  |             $json = microtime(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $hash    = hash('sha256', $json); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('The hash is: %s', $hash), $dataRow); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $hash; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * If this transaction already exists, throw an error. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws DuplicateTransactionException | 
					
						
							| 
									
										
										
										
											2025-10-05 12:57:58 +02:00
										 |  |  |      * @throws JsonException | 
					
						
							|  |  |  |      * @throws \Safe\Exceptions\JsonException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |     private function errorIfDuplicate(string $hash): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('In errorIfDuplicate(%s)', $hash)); | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         if (false === $this->errorOnHash) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Will verify duplicate!'); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @var null|TransactionJournalMeta $result */ | 
					
						
							| 
									
										
										
										
											2023-01-03 06:48:53 +01:00
										 |  |  |         $result = TransactionJournalMeta::withTrashed() | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |             ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id') | 
					
						
							|  |  |  |             ->whereNotNull('transaction_journals.id') | 
					
						
							|  |  |  |             ->where('transaction_journals.user_id', $this->user->id) | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |             ->where('data', json_encode($hash, JSON_THROW_ON_ERROR)) | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |             ->with(['transactionJournal', 'transactionJournal.transactionGroup']) | 
					
						
							|  |  |  |             ->first(['journal_meta.*']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         if (null !== $result) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::warning(sprintf('Found a duplicate in errorIfDuplicate because hash %s is not unique!', $hash)); | 
					
						
							| 
									
										
										
										
											2021-10-01 04:55:33 +02:00
										 |  |  |             $journal = $result->transactionJournal()->withTrashed()->first(); | 
					
						
							|  |  |  |             $group   = $journal?->transactionGroup()->withTrashed()->first(); | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             $groupId = (int) $group?->id; | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-01 04:55:33 +02:00
										 |  |  |             throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $groupId)); | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function validateAccounts(NullArrayObject $data): void | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Now in %s', __METHOD__)); | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $transactionType  = $data['type'] ?? 'invalid'; | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $this->accountValidator->setUser($this->user); | 
					
						
							|  |  |  |         $this->accountValidator->setTransactionType($transactionType); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // validate source account.
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $array            = [ | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             'id'     => null !== $data['source_id'] ? (int) $data['source_id'] : null, | 
					
						
							|  |  |  |             'name'   => null !== $data['source_name'] ? (string) $data['source_name'] : null, | 
					
						
							|  |  |  |             'iban'   => null !== $data['source_iban'] ? (string) $data['source_iban'] : null, | 
					
						
							|  |  |  |             'number' => null !== $data['source_number'] ? (string) $data['source_number'] : null, | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $validSource      = $this->accountValidator->validateSource($array); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // do something with result:
 | 
					
						
							|  |  |  |         if (false === $validSource) { | 
					
						
							|  |  |  |             throw new FireflyException(sprintf('Source: %s', $this->accountValidator->sourceError)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Source seems valid.'); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // validate destination account
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $array            = [ | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             'id'     => null !== $data['destination_id'] ? (int) $data['destination_id'] : null, | 
					
						
							|  |  |  |             'name'   => null !== $data['destination_name'] ? (string) $data['destination_name'] : null, | 
					
						
							|  |  |  |             'iban'   => null !== $data['destination_iban'] ? (string) $data['destination_iban'] : null, | 
					
						
							|  |  |  |             'number' => null !== $data['destination_number'] ? (string) $data['destination_number'] : null, | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $validDestination = $this->accountValidator->validateDestination($array); | 
					
						
							|  |  |  |         // do something with result:
 | 
					
						
							|  |  |  |         if (false === $validDestination) { | 
					
						
							|  |  |  |             throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError)); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Set the user. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setUser(User $user): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-02-10 04:10:23 +01:00
										 |  |  |         $this->user      = $user; | 
					
						
							| 
									
										
										
										
											2025-02-09 09:30:44 +01:00
										 |  |  |         $this->userGroup = $user->userGroup; | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |         $this->currencyRepository->setUser($this->user); | 
					
						
							|  |  |  |         $this->tagFactory->setUser($user); | 
					
						
							|  |  |  |         $this->billRepository->setUser($this->user); | 
					
						
							|  |  |  |         $this->budgetRepository->setUser($this->user); | 
					
						
							|  |  |  |         $this->categoryRepository->setUser($this->user); | 
					
						
							|  |  |  |         $this->piggyRepository->setUser($this->user); | 
					
						
							|  |  |  |         $this->accountRepository->setUser($this->user); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Now in %s', __METHOD__)); | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if ($sourceAccount instanceof Account && $destinationAccount instanceof Account) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug('Both accounts exist, simply return them.'); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             return [$sourceAccount, $destinationAccount]; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if (!$destinationAccount instanceof Account) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug('Destination account is NULL, source account is not.'); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             $account = $this->accountRepository->getReconciliation($sourceAccount); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type)); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             return [$sourceAccount, $account]; | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if (!$sourceAccount instanceof Account) { // @phpstan-ignore-line
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug('Source account is NULL, destination account is not.'); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             $account = $this->accountRepository->getReconciliation($destinationAccount); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type)); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             return [$account, $destinationAccount]; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Unused fallback');  // @phpstan-ignore-line
 | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         return [$sourceAccount, $destinationAccount]; | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-02-22 18:03:31 +01:00
										 |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |     private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Now in getCurrencyByAccount()'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* | 
					
						
							|  |  |  |          * Deze functie moet bij een transactie van liability naar asset wel degelijk de currency | 
					
						
							|  |  |  |          * van de liability teruggeven en niet die van de destination. Fix voor #10265
 | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         if ($this->isBetweenAssetAndLiability($source, $destination) && TransactionTypeEnum::DEPOSIT->value === $type) { | 
					
						
							|  |  |  |             return $this->getCurrency($currency, $source); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 10:21:29 +02:00
										 |  |  |         return match ($type) { | 
					
						
							| 
									
										
										
										
											2025-01-04 07:39:16 +01:00
										 |  |  |             default                             => $this->getCurrency($currency, $source), | 
					
						
							| 
									
										
										
										
											2025-01-03 09:09:15 +01:00
										 |  |  |             TransactionTypeEnum::DEPOSIT->value => $this->getCurrency($currency, $destination), | 
					
						
							| 
									
										
										
										
											2021-09-18 10:21:29 +02:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-12 09:24:16 +02:00
										 |  |  |     private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-12 09:19:42 +02:00
										 |  |  |         Log::debug(sprintf('Now in getCurrency(#%d, "%s")', $currency?->id, $account->name)); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @var null|TransactionCurrency $preference */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $preference = $this->accountRepository->getAccountCurrency($account); | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if (null === $preference && !$currency instanceof TransactionCurrency) { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             // return user's default:
 | 
					
						
							| 
									
										
										
										
											2025-07-31 20:17:46 +02:00
										 |  |  |             return app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $result     = $preference ?? $currency; | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name)); | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         return $result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Set foreign currency to NULL if it's the same as the normal currency: | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Now in compareCurrencies("%s", "%s")', $currency?->code, $foreignCurrency?->code)); | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if (!$currency instanceof TransactionCurrency) { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if ($foreignCurrency instanceof TransactionCurrency && $foreignCurrency->id === $currency->id) { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $foreignCurrency; | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-02-22 18:03:31 +01:00
										 |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |     private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Now in getForeignByAccount("%s", #%d, "%s")', $type, $foreignCurrency?->id, $destination->name)); | 
					
						
							| 
									
										
										
										
											2025-01-03 09:05:56 +01:00
										 |  |  |         if (TransactionTypeEnum::TRANSFER->value === $type) { | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |             return $this->getCurrency($foreignCurrency, $destination); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $foreignCurrency; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function getDescription(string $description): string | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $description = '' === $description ? '(empty description)' : $description; | 
					
						
							| 
									
										
										
										
											2023-05-29 13:56:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-12 17:46:56 +02:00
										 |  |  |         return substr($description, 0, 1024); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * Force the deletion of an entire set of transaction journals and their meta object in case of | 
					
						
							|  |  |  |      * an error creating a group. | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function forceDeleteOnError(Collection $collection): void | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('forceDeleteOnError on collection size %d item(s)', $collection->count())); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $service = app(JournalDestroyService::class); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         /** @var TransactionJournal $journal */ | 
					
						
							|  |  |  |         foreach ($collection as $journal) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug(sprintf('forceDeleteOnError on journal #%d', $journal->id)); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |             $service->destroy($journal); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function forceTrDelete(Transaction $transaction): void | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $transaction->delete(); | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Link a piggy bank to this journal. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Will now store piggy event.'); | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |         $piggyBank = $this->piggyRepository->findPiggyBank((int) $data['piggy_bank_id'], $data['piggy_bank_name']); | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-27 17:02:18 +02:00
										 |  |  |         if ($piggyBank instanceof PiggyBank) { | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  |             $this->piggyEventFactory->create($journal, $piggyBank); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug('Create piggy event.'); | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug('Create no piggy event'); | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-05 17:26:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         foreach ($this->fields as $field) { | 
					
						
							|  |  |  |             $this->storeMeta($journal, $transaction, $field); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         $set     = [ | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |             'journal' => $journal, | 
					
						
							|  |  |  |             'name'    => $field, | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             'data'    => (string) ($data[$field] ?? ''), | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  |         if ($data[$field] instanceof Carbon) { | 
					
						
							|  |  |  |             $data[$field]->setTimezone(config('app.timezone')); | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug(sprintf('%s Date: %s (%s)', $field, $data[$field], $data[$field]->timezone->getName())); | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |             $set['data'] = $data[$field]->format('Y-m-d H:i:s'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data'])); | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @var TransactionJournalMetaFactory $factory */ | 
					
						
							|  |  |  |         $factory = app(TransactionJournalMetaFactory::class); | 
					
						
							|  |  |  |         $factory->updateOrCreate($set); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private function storeLocation(TransactionJournal $journal, NullArrayObject $data): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-01-26 14:33:19 +01:00
										 |  |  |         if (null !== $data['longitude'] && null !== $data['latitude'] && null !== $data['zoom_level']) { | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |             $location             = new Location(); | 
					
						
							|  |  |  |             $location->longitude  = $data['longitude']; | 
					
						
							|  |  |  |             $location->latitude   = $data['latitude']; | 
					
						
							|  |  |  |             $location->zoom_level = $data['zoom_level']; | 
					
						
							|  |  |  |             $location->locatable()->associate($journal); | 
					
						
							|  |  |  |             $location->save(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setErrorOnHash(bool $errorOnHash): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->errorOnHash = $errorOnHash; | 
					
						
							|  |  |  |         if (true === $errorOnHash) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::info('Will trigger duplication alert for this journal.'); | 
					
						
							| 
									
										
										
										
											2024-02-22 20:11:09 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-05-04 17:41:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public function setUserGroup(UserGroup $userGroup): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->userGroup = $userGroup; | 
					
						
							|  |  |  |         $this->currencyRepository->setUserGroup($userGroup); | 
					
						
							|  |  |  |         $this->tagFactory->setUserGroup($userGroup); | 
					
						
							|  |  |  |         $this->billRepository->setUserGroup($userGroup); | 
					
						
							|  |  |  |         $this->budgetRepository->setUserGroup($userGroup); | 
					
						
							|  |  |  |         $this->categoryRepository->setUserGroup($userGroup); | 
					
						
							|  |  |  |         $this->piggyRepository->setUserGroup($userGroup); | 
					
						
							|  |  |  |         $this->accountRepository->setUserGroup($userGroup); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private function isBetweenAssetAndLiability(Account $source, Account $destination): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // source is liability, destination is asset
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         if (in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug('Source is a liability account, destination is an asset account, return TRUE.'); | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // source is asset, destination is liability
 | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  |         if (in_array($destination->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $source->accountType->type) { | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             Log::debug('Destination is a liability account, source is an asset account, return TRUE.'); | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-05-11 07:01:36 +02:00
										 |  |  |         Log::debug('Not between asset and liability, return FALSE'); | 
					
						
							| 
									
										
										
										
											2025-05-11 12:59:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 08:00:38 +02:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-05 19:35:58 +01:00
										 |  |  | } |