| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2019-03-08 05:47:51 +01:00
										 |  |  | use Exception; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2023-01-03 06:48:53 +01:00
										 |  |  | use FireflyIII\Models\Preference; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  | use FireflyIII\Models\TransactionType; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2019-03-08 05:47:51 +01: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; | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2023-04-01 07:04:42 +02:00
										 |  |  | use Illuminate\Support\Facades\Log; | 
					
						
							| 
									
										
										
										
											2023-05-29 13:56:55 +02:00
										 |  |  | use JsonException; | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Class TransactionJournalFactory | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											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
										 |  |  |      * | 
					
						
							|  |  |  |      * @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
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param array $data | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-03-17 14:57:04 +01:00
										 |  |  |      * @return Collection | 
					
						
							| 
									
										
										
										
											2020-08-01 17:51:52 +02:00
										 |  |  |      * @throws DuplicateTransactionException | 
					
						
							| 
									
										
										
										
											2021-09-18 10:21:29 +02:00
										 |  |  |      * @throws FireflyException | 
					
						
							|  |  |  |      * @throws JsonException | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     public function create(array $data): Collection | 
					
						
							| 
									
										
										
										
											2018-02-16 16:43:25 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-10-04 17:11:59 +02:00
										 |  |  |         Log::debug('Now in TransactionJournalFactory::create()'); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         // convert to special object.
 | 
					
						
							| 
									
										
										
										
											2020-02-22 11:05:16 +01:00
										 |  |  |         $dataObject = new NullArrayObject($data); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 15:12:47 +01: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)) { | 
					
						
							| 
									
										
										
										
											2019-03-18 16:52:49 +01: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
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         try { | 
					
						
							|  |  |  |             /** @var array $row */ | 
					
						
							|  |  |  |             foreach ($transactions as $index => $row) { | 
					
						
							|  |  |  |                 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)); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |                 if (null !== $journal) { | 
					
						
							|  |  |  |                     $collection->push($journal); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (null === $journal) { | 
					
						
							|  |  |  |                     Log::error('The createJournal() method returned NULL. This may indicate an error.'); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-08-16 17:54:38 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (DuplicateTransactionException $e) { | 
					
						
							| 
									
										
										
										
											2022-10-30 14:44:49 +01:00
										 |  |  |             app('log')->warning('TransactionJournalFactory::create() caught a duplicate journal in createJournal()'); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  |             Log::error($e->getTraceAsString()); | 
					
						
							|  |  |  |             $this->forceDeleteOnError($collection); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2022-10-30 14:44:49 +01:00
										 |  |  |             app('log')->warning('TransactionJournalFactory::create() caught an exception.'); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  |             Log::error($e->getTraceAsString()); | 
					
						
							|  |  |  |             $this->forceDeleteOnError($collection); | 
					
						
							| 
									
										
										
										
											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-05-29 13:56:55 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param NullArrayObject $row | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-03-17 14:57:04 +01:00
										 |  |  |      * @return TransactionJournal|null | 
					
						
							| 
									
										
										
										
											2020-08-01 17:51:52 +02:00
										 |  |  |      * @throws DuplicateTransactionException | 
					
						
							|  |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2021-09-18 10:20:19 +02:00
										 |  |  |      * @throws JsonException | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     private function createJournal(NullArrayObject $row): ?TransactionJournal | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $row['import_hash_v2'] = $this->hashArray($row); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         $this->errorIfDuplicate($row['import_hash_v2']); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         /** Some basic fields */ | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         $type            = $this->typeRepository->findTransactionType(null, $row['type']); | 
					
						
							| 
									
										
										
										
											2020-09-11 07:12:33 +02:00
										 |  |  |         $carbon          = $row['date'] ?? today(config('app.timezone')); | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |         $order           = $row['order'] ?? 0; | 
					
						
							| 
									
										
										
										
											2022-12-11 07:17:59 +01:00
										 |  |  |         $currency        = $this->currencyRepository->findCurrency((int)$row['currency_id'], $row['currency_code']); | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |         $foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']); | 
					
						
							| 
									
										
										
										
											2022-12-11 07:17:59 +01:00
										 |  |  |         $bill            = $this->billRepository->findBill((int)$row['bill_id'], $row['bill_name']); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         $billId          = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null; | 
					
						
							| 
									
										
										
										
											2022-12-11 07:17:59 +01:00
										 |  |  |         $description     = (string)$row['description']; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** Manipulate basic fields */ | 
					
						
							|  |  |  |         $carbon->setTimezone(config('app.timezone')); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 13:54:06 +02:00
										 |  |  |         try { | 
					
						
							|  |  |  |             // validate source and destination using a new Validator.
 | 
					
						
							|  |  |  |             $this->validateAccounts($row); | 
					
						
							|  |  |  |         } catch (FireflyException $e) { | 
					
						
							| 
									
										
										
										
											2019-08-16 17:54:38 +02:00
										 |  |  |             Log::error('Could not validate source or destination.'); | 
					
						
							| 
									
										
										
										
											2019-07-27 13:54:06 +02:00
										 |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-31 07:39:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-08 18:26:40 +01:00
										 |  |  |         // typeOverrule: the account validator may have another opinion on the transaction type.
 | 
					
						
							|  |  |  |         // not sure what to do with this.
 | 
					
						
							| 
									
										
										
										
											2020-03-31 07:39:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         /** create or get source and destination accounts  */ | 
					
						
							|  |  |  |         $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
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $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
										 |  |  |         ]; | 
					
						
							|  |  |  |         Log::debug('Source info:', $sourceInfo); | 
					
						
							|  |  |  |         Log::debug('Destination info:', $destInfo); | 
					
						
							| 
									
										
										
										
											2020-04-14 17:23:58 +02:00
										 |  |  |         Log::debug('Now calling getAccount for the source.'); | 
					
						
							|  |  |  |         $sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo); | 
					
						
							|  |  |  |         Log::debug('Now calling getAccount for the destination.'); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         $destinationAccount = $this->getAccount($type->type, 'destination', $destInfo); | 
					
						
							| 
									
										
										
										
											2020-04-14 17:23:58 +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).
 | 
					
						
							|  |  |  |         if (TransactionType::RECONCILIATION === $type->type) { | 
					
						
							|  |  |  |             [$sourceAccount, $destinationAccount] = $this->reconciliationSanityCheck($sourceAccount, $destinationAccount); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-01 17:51:52 +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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 21:12:10 +01:00
										 |  |  |         Log::debug(sprintf('Date: %s (%s)', $carbon->toW3cString(), $carbon->getTimezone()->getName())); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         /** Create a basic journal. */ | 
					
						
							|  |  |  |         $journal = TransactionJournal::create( | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 'user_id'                 => $this->user->id, | 
					
						
							| 
									
										
										
										
											2023-08-01 19:38:53 +02:00
										 |  |  |                 'user_group_id'           => $this->user->user_group_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), | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |                 'date'                    => $carbon->format('Y-m-d H:i:s'), | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |                 'order'                   => $order, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |                 'tag_count'               => 0, | 
					
						
							|  |  |  |                 'completed'               => 0, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         Log::debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** Create two transactions. */ | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         $transactionFactory = app(TransactionFactory::class); | 
					
						
							|  |  |  |         $transactionFactory->setUser($this->user); | 
					
						
							|  |  |  |         $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); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         try { | 
					
						
							| 
									
										
										
										
											2022-12-11 07:17:59 +01:00
										 |  |  |             $negative = $transactionFactory->createNegative((string)$row['amount'], (string)$row['foreign_amount']); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (FireflyException $e) { | 
					
						
							|  |  |  |             Log::error('Exception creating negative transaction.'); | 
					
						
							|  |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  |             Log::error($e->getTraceAsString()); | 
					
						
							|  |  |  |             $this->forceDeleteOnError(new Collection([$journal])); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |         // and the destination one:
 | 
					
						
							|  |  |  |         /** @var TransactionFactory $transactionFactory */ | 
					
						
							|  |  |  |         $transactionFactory = app(TransactionFactory::class); | 
					
						
							|  |  |  |         $transactionFactory->setUser($this->user); | 
					
						
							|  |  |  |         $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); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         try { | 
					
						
							| 
									
										
										
										
											2022-12-11 07:17:59 +01:00
										 |  |  |             $transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } catch (FireflyException $e) { | 
					
						
							|  |  |  |             Log::error('Exception creating positive transaction.'); | 
					
						
							|  |  |  |             Log::error($e->getMessage()); | 
					
						
							|  |  |  |             Log::error($e->getTraceAsString()); | 
					
						
							| 
									
										
										
										
											2022-10-30 14:44:49 +01:00
										 |  |  |             app('log')->warning('Delete negative transaction.'); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |             $this->forceTrDelete($negative); | 
					
						
							|  |  |  |             $this->forceDeleteOnError(new Collection([$journal])); | 
					
						
							| 
									
										
										
										
											2021-04-07 07:28:43 +02:00
										 |  |  |             throw new FireflyException($e->getMessage(), 0, $e); | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |         // verify that journal has two transactions. Otherwise, delete and cancel.
 | 
					
						
							|  |  |  |         $journal->completed = true; | 
					
						
							|  |  |  |         $journal->save(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** Link all other data to the journal. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** Link budget */ | 
					
						
							|  |  |  |         $this->storeBudget($journal, $row); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** Link category */ | 
					
						
							|  |  |  |         $this->storeCategory($journal, $row); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** Set notes */ | 
					
						
							| 
									
										
										
										
											2019-04-06 08:10:50 +02:00
										 |  |  |         $this->storeNotes($journal, $row['notes']); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** Set piggy bank */ | 
					
						
							|  |  |  |         $this->storePiggyEvent($journal, $row); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** Set tags */ | 
					
						
							|  |  |  |         $this->storeTags($journal, $row['tags']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** set all meta fields */ | 
					
						
							|  |  |  |         $this->storeMetaFields($journal, $row); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $journal; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param NullArrayObject $row | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return string | 
					
						
							|  |  |  |      * @throws JsonException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private function hashArray(NullArrayObject $row): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $dataRow = $row->getArrayCopy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         unset($dataRow['import_hash_v2'], $dataRow['original_source']); | 
					
						
							|  |  |  |         $json = json_encode($dataRow, JSON_THROW_ON_ERROR); | 
					
						
							|  |  |  |         $hash = hash('sha256', $json); | 
					
						
							|  |  |  |         Log::debug(sprintf('The hash is: %s', $hash), $dataRow); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $hash; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * If this transaction already exists, throw an error. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param string $hash | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @throws DuplicateTransactionException | 
					
						
							| 
									
										
										
										
											2021-09-18 10:20:19 +02:00
										 |  |  |      * @throws JsonException | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     private function errorIfDuplicate(string $hash): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-22 11:05:16 +01:00
										 |  |  |         Log::debug(sprintf('In errorIfDuplicate(%s)', $hash)); | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         if (false === $this->errorOnHash) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-01-03 06:48:53 +01:00
										 |  |  |         Log::debug('Will verify duplicate!'); | 
					
						
							|  |  |  |         /** @var TransactionJournalMeta|null $result */ | 
					
						
							|  |  |  |         $result = TransactionJournalMeta::withTrashed() | 
					
						
							|  |  |  |                                         ->where('data', json_encode($hash, JSON_THROW_ON_ERROR)) | 
					
						
							|  |  |  |                                         ->with(['transactionJournal', 'transactionJournal.transactionGroup']) | 
					
						
							|  |  |  |                                         ->first(); | 
					
						
							| 
									
										
										
										
											2019-10-26 07:49:12 +02:00
										 |  |  |         if (null !== $result) { | 
					
						
							| 
									
										
										
										
											2022-10-30 14:44:49 +01:00
										 |  |  |             app('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(); | 
					
						
							|  |  |  |             $groupId = $group?->id; | 
					
						
							|  |  |  |             if (null === $group) { | 
					
						
							|  |  |  |                 $groupId = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             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
										 |  |  |      * @param NullArrayObject $data | 
					
						
							| 
									
										
										
										
											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
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         Log::debug(sprintf('Now in %s', __METHOD__)); | 
					
						
							|  |  |  |         $transactionType = $data['type'] ?? 'invalid'; | 
					
						
							|  |  |  |         $this->accountValidator->setUser($this->user); | 
					
						
							|  |  |  |         $this->accountValidator->setTransactionType($transactionType); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // validate source account.
 | 
					
						
							|  |  |  |         $array       = [ | 
					
						
							|  |  |  |             'id'     => $data['source_id'] ? (int)$data['source_id'] : null, | 
					
						
							|  |  |  |             'name'   => $data['source_name'] ? (string)$data['source_name'] : null, | 
					
						
							|  |  |  |             'iban'   => $data['source_iban'] ? (string)$data['source_iban'] : null, | 
					
						
							|  |  |  |             'number' => $data['source_number'] ? (string)$data['source_number'] : null, | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |         $validSource = $this->accountValidator->validateSource($array); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // do something with result:
 | 
					
						
							|  |  |  |         if (false === $validSource) { | 
					
						
							|  |  |  |             throw new FireflyException(sprintf('Source: %s', $this->accountValidator->sourceError)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Log::debug('Source seems valid.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // validate destination account
 | 
					
						
							|  |  |  |         $array = [ | 
					
						
							|  |  |  |             'id'     => $data['destination_id'] ? (int)$data['destination_id'] : null, | 
					
						
							|  |  |  |             'name'   => $data['destination_name'] ? (string)$data['destination_name'] : null, | 
					
						
							|  |  |  |             'iban'   => $data['destination_iban'] ? (string)$data['destination_iban'] : null, | 
					
						
							|  |  |  |             'number' => $data['destination_number'] ? (string)$data['destination_number'] : null, | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $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
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * Set the user. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param User $user | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     public function setUser(User $user): void | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $this->user = $user; | 
					
						
							|  |  |  |         $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); | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param Account|null $sourceAccount | 
					
						
							|  |  |  |      * @param Account|null $destinationAccount | 
					
						
							| 
									
										
										
										
											2023-07-15 16:02:42 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @return array | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         Log::debug(sprintf('Now in %s', __METHOD__)); | 
					
						
							|  |  |  |         if (null !== $sourceAccount && null !== $destinationAccount) { | 
					
						
							|  |  |  |             Log::debug('Both accounts exist, simply return them.'); | 
					
						
							|  |  |  |             return [$sourceAccount, $destinationAccount]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (null !== $sourceAccount && null === $destinationAccount) { | 
					
						
							|  |  |  |             Log::debug('Destination account is NULL, source account is not.'); | 
					
						
							|  |  |  |             $account = $this->accountRepository->getReconciliation($sourceAccount); | 
					
						
							|  |  |  |             Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type)); | 
					
						
							|  |  |  |             return [$sourceAccount, $account]; | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         if (null === $sourceAccount && null !== $destinationAccount) { | 
					
						
							|  |  |  |             Log::debug('Source account is NULL, destination account is not.'); | 
					
						
							|  |  |  |             $account = $this->accountRepository->getReconciliation($destinationAccount); | 
					
						
							|  |  |  |             Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type)); | 
					
						
							|  |  |  |             return [$account, $destinationAccount]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Log::debug('Unused fallback'); | 
					
						
							|  |  |  |         return [$sourceAccount, $destinationAccount]; | 
					
						
							| 
									
										
										
										
											2022-12-29 19:41:57 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param string                   $type | 
					
						
							|  |  |  |      * @param TransactionCurrency|null $currency | 
					
						
							|  |  |  |      * @param Account                  $source | 
					
						
							|  |  |  |      * @param Account                  $destination | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @return TransactionCurrency | 
					
						
							| 
									
										
										
										
											2023-02-22 18:03:31 +01:00
										 |  |  |      * @throws FireflyException | 
					
						
							|  |  |  |      * @throws JsonException | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +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
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-02-18 06:37:05 +01:00
										 |  |  |         Log::debug('Now in getCurrencyByAccount()'); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 10:21:29 +02:00
										 |  |  |         return match ($type) { | 
					
						
							| 
									
										
										
										
											2023-07-15 16:02:42 +02:00
										 |  |  |             default                  => $this->getCurrency($currency, $source), | 
					
						
							| 
									
										
										
										
											2021-09-18 10:21:29 +02:00
										 |  |  |             TransactionType::DEPOSIT => $this->getCurrency($currency, $destination), | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2020-03-12 05:06:42 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param TransactionCurrency|null $currency | 
					
						
							|  |  |  |      * @param Account                  $account | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @return TransactionCurrency | 
					
						
							|  |  |  |      * @throws FireflyException | 
					
						
							|  |  |  |      * @throws JsonException | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         Log::debug('Now in getCurrency()'); | 
					
						
							|  |  |  |         /** @var Preference|null $preference */ | 
					
						
							|  |  |  |         $preference = $this->accountRepository->getAccountCurrency($account); | 
					
						
							|  |  |  |         if (null === $preference && null === $currency) { | 
					
						
							|  |  |  |             // return user's default:
 | 
					
						
							|  |  |  |             return app('amount')->getDefaultCurrencyByUser($this->user); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         $result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency(); | 
					
						
							|  |  |  |         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: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param TransactionCurrency|null $currency | 
					
						
							|  |  |  |      * @param TransactionCurrency|null $foreignCurrency | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return TransactionCurrency|null | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (null === $currency) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (null !== $foreignCurrency && $foreignCurrency->id === $currency->id) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $foreignCurrency; | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param string                   $type | 
					
						
							|  |  |  |      * @param TransactionCurrency|null $foreignCurrency | 
					
						
							|  |  |  |      * @param Account                  $destination | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @return TransactionCurrency|null | 
					
						
							| 
									
										
										
										
											2023-02-22 18:03:31 +01:00
										 |  |  |      * @throws FireflyException | 
					
						
							|  |  |  |      * @throws JsonException | 
					
						
							| 
									
										
										
										
											2020-03-17 16:46:00 +01:00
										 |  |  |      */ | 
					
						
							|  |  |  |     private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (TransactionType::TRANSFER === $type) { | 
					
						
							|  |  |  |             return $this->getCurrency($foreignCurrency, $destination); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $foreignCurrency; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param string $description | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @return string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											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-06-21 12:34:58 +02:00
										 |  |  |         return substr($description, 0, 255); | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Collection $collection | 
					
						
							| 
									
										
										
										
											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
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         Log::debug(sprintf('forceDeleteOnError on collection size %d item(s)', $collection->count())); | 
					
						
							|  |  |  |         $service = app(JournalDestroyService::class); | 
					
						
							|  |  |  |         /** @var TransactionJournal $journal */ | 
					
						
							|  |  |  |         foreach ($collection as $journal) { | 
					
						
							|  |  |  |             Log::debug(sprintf('forceDeleteOnError on journal #%d', $journal->id)); | 
					
						
							|  |  |  |             $service->destroy($journal); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-31 13:36:49 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param Transaction $transaction | 
					
						
							| 
									
										
										
										
											2019-03-17 17:05:16 +01: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. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param TransactionJournal $journal | 
					
						
							|  |  |  |      * @param NullArrayObject    $data | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Log::debug('Will now store piggy event.'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 07:17:59 +01:00
										 |  |  |         $piggyBank = $this->piggyRepository->findPiggyBank((int)$data['piggy_bank_id'], $data['piggy_bank_name']); | 
					
						
							| 
									
										
										
										
											2019-08-30 07:28:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (null !== $piggyBank) { | 
					
						
							|  |  |  |             $this->piggyEventFactory->create($journal, $piggyBank); | 
					
						
							|  |  |  |             Log::debug('Create piggy event.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Log::debug('Create no piggy event'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-05 17:26:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |      * @param TransactionJournal $journal | 
					
						
							|  |  |  |      * @param NullArrayObject    $transaction | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +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); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-29 13:56:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param TransactionJournal $journal | 
					
						
							|  |  |  |      * @param NullArrayObject    $data | 
					
						
							|  |  |  |      * @param string             $field | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $set = [ | 
					
						
							|  |  |  |             'journal' => $journal, | 
					
						
							|  |  |  |             'name'    => $field, | 
					
						
							|  |  |  |             'data'    => (string)($data[$field] ?? ''), | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         if ($data[$field] instanceof Carbon) { | 
					
						
							|  |  |  |             $data[$field]->setTimezone(config('app.timezone')); | 
					
						
							|  |  |  |             Log::debug(sprintf('%s Date: %s (%s)', $field, $data[$field], $data[$field]->timezone->getName())); | 
					
						
							|  |  |  |             $set['data'] = $data[$field]->format('Y-m-d H:i:s'); | 
					
						
							| 
									
										
										
										
											2023-05-29 13:56:55 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data'])); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         /** @var TransactionJournalMetaFactory $factory */ | 
					
						
							|  |  |  |         $factory = app(TransactionJournalMetaFactory::class); | 
					
						
							|  |  |  |         $factory->updateOrCreate($set); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param bool $errorOnHash | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setErrorOnHash(bool $errorOnHash): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->errorOnHash = $errorOnHash; | 
					
						
							|  |  |  |         if (true === $errorOnHash) { | 
					
						
							|  |  |  |             Log::info('Will trigger duplication alert for this journal.'); | 
					
						
							| 
									
										
										
										
											2019-06-04 20:42:11 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-05 19:35:58 +01:00
										 |  |  | } |