| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2022-12-29 19:42:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-20 12:41:23 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * AccountRepository.php | 
					
						
							| 
									
										
										
										
											2020-02-16 14:00:57 +01:00
										 |  |  |  * Copyright (c) 2019 james@firefly-iii.org | 
					
						
							| 
									
										
										
										
											2016-05-20 12:41:23 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * This file is part of Firefly III (https://github.com/firefly-iii). | 
					
						
							| 
									
										
										
										
											2016-10-05 06:52:15 +02: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. | 
					
						
							| 
									
										
										
										
											2017-10-21 08:40:00 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-10-02 06:37:26 +02:00
										 |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2017-10-21 08:40:00 +02: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. | 
					
						
							| 
									
										
										
										
											2017-10-21 08:40:00 +02: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/>. | 
					
						
							| 
									
										
										
										
											2016-05-20 12:41:23 +02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-04-09 07:44:22 +02:00
										 |  |  | declare(strict_types=1); | 
					
						
							| 
									
										
										
										
											2016-05-20 08:57:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  | namespace FireflyIII\Repositories\Account; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-21 12:16:41 +01:00
										 |  |  | use Carbon\Carbon; | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  | use FireflyIII\Enums\AccountTypeEnum; | 
					
						
							| 
									
										
										
										
											2025-01-03 09:11:20 +01:00
										 |  |  | use FireflyIII\Enums\TransactionTypeEnum; | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | use FireflyIII\Exceptions\FireflyException; | 
					
						
							| 
									
										
										
										
											2018-02-21 21:06:59 +01:00
										 |  |  | use FireflyIII\Factory\AccountFactory; | 
					
						
							| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  | use FireflyIII\Models\Account; | 
					
						
							| 
									
										
										
										
											2019-08-24 07:56:08 +02:00
										 |  |  | use FireflyIII\Models\AccountMeta; | 
					
						
							| 
									
										
										
										
											2016-10-10 08:03:03 +02:00
										 |  |  | use FireflyIII\Models\AccountType; | 
					
						
							| 
									
										
										
										
											2020-05-07 06:44:01 +02:00
										 |  |  | use FireflyIII\Models\Attachment; | 
					
						
							| 
									
										
										
										
											2019-12-30 12:12:08 +01:00
										 |  |  | use FireflyIII\Models\Location; | 
					
						
							| 
									
										
										
										
											2018-12-15 07:59:49 +01:00
										 |  |  | use FireflyIII\Models\TransactionCurrency; | 
					
						
							| 
									
										
										
										
											2019-06-16 13:16:04 +02:00
										 |  |  | use FireflyIII\Models\TransactionGroup; | 
					
						
							| 
									
										
										
										
											2016-10-10 08:03:03 +02:00
										 |  |  | use FireflyIII\Models\TransactionJournal; | 
					
						
							| 
									
										
										
										
											2018-02-21 18:42:15 +01:00
										 |  |  | use FireflyIII\Services\Internal\Destroy\AccountDestroyService; | 
					
						
							| 
									
										
										
										
											2018-02-21 20:34:24 +01:00
										 |  |  | use FireflyIII\Services\Internal\Update\AccountUpdateService; | 
					
						
							| 
									
										
										
										
											2024-05-18 06:42:09 +02:00
										 |  |  | use FireflyIII\Support\Facades\Steam; | 
					
						
							| 
									
										
										
										
											2025-02-23 12:28:27 +01:00
										 |  |  | use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface; | 
					
						
							| 
									
										
										
										
											2025-02-09 09:30:44 +01:00
										 |  |  | use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; | 
					
						
							| 
									
										
										
										
											2021-03-07 16:19:14 +01:00
										 |  |  | use Illuminate\Database\Eloquent\Builder as EloquentBuilder; | 
					
						
							| 
									
										
										
										
											2018-07-24 20:49:25 +02:00
										 |  |  | use Illuminate\Database\Eloquent\Relations\HasMany; | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2025-02-23 12:28:27 +01:00
										 |  |  | use Illuminate\Support\Facades\Storage; | 
					
						
							| 
									
										
										
										
											2025-05-27 16:57:36 +02:00
										 |  |  | use Override; | 
					
						
							| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-27 17:06:15 +02:00
										 |  |  | use function Safe\json_encode; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2017-11-15 12:25:49 +01:00
										 |  |  |  * Class AccountRepository. | 
					
						
							| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-02-23 12:28:27 +01:00
										 |  |  | class AccountRepository implements AccountRepositoryInterface, UserGroupInterface | 
					
						
							| 
									
										
										
										
											2015-02-09 07:23:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-02-09 09:30:44 +01:00
										 |  |  |     use UserGroupTrait; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-09 08:20:29 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Moved here from account CRUD. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-02-23 16:21:28 +01:00
										 |  |  |     public function destroy(Account $account, ?Account $moveTo): bool | 
					
						
							| 
									
										
										
										
											2016-10-09 08:20:29 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-02-21 18:42:15 +01:00
										 |  |  |         /** @var AccountDestroyService $service */ | 
					
						
							|  |  |  |         $service = app(AccountDestroyService::class); | 
					
						
							|  |  |  |         $service->destroy($account, $moveTo); | 
					
						
							| 
									
										
										
										
											2016-10-09 08:20:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-03 22:35:41 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Find account with same name OR same IBAN or both, but not the same type or ID. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function expandWithDoubles(Collection $accounts): Collection | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-10-30 14:24:28 +01:00
										 |  |  |         $result = new Collection(); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-03 22:35:41 +02:00
										 |  |  |         /** @var Account $account */ | 
					
						
							|  |  |  |         foreach ($accounts as $account) { | 
					
						
							|  |  |  |             $byName = $this->user->accounts()->where('name', $account->name) | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |                 ->where('id', '!=', $account->id)->first() | 
					
						
							|  |  |  |             ; | 
					
						
							| 
									
										
										
										
											2019-09-03 22:35:41 +02:00
										 |  |  |             if (null !== $byName) { | 
					
						
							|  |  |  |                 $result->push($account); | 
					
						
							|  |  |  |                 $result->push($byName); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-03 22:35:41 +02:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (null !== $account->iban) { | 
					
						
							|  |  |  |                 $byIban = $this->user->accounts()->where('iban', $account->iban) | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |                     ->where('id', '!=', $account->id)->first() | 
					
						
							|  |  |  |                 ; | 
					
						
							| 
									
										
										
										
											2019-09-03 22:35:41 +02:00
										 |  |  |                 if (null !== $byIban) { | 
					
						
							|  |  |  |                     $result->push($account); | 
					
						
							|  |  |  |                     $result->push($byIban); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-03 22:35:41 +02:00
										 |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $result->push($account); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  |     public function findByAccountNumber(string $number, array $types): ?Account | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $dbQuery = $this->user | 
					
						
							|  |  |  |             ->accounts() | 
					
						
							|  |  |  |             ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') | 
					
						
							|  |  |  |             ->where('accounts.active', true) | 
					
						
							|  |  |  |             ->where( | 
					
						
							| 
									
										
										
										
											2025-01-04 19:43:58 +01:00
										 |  |  |                 static function (EloquentBuilder $q1) use ($number): void { | 
					
						
							| 
									
										
										
										
											2025-05-27 17:06:15 +02:00
										 |  |  |                     $json = json_encode($number); | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  |                     $q1->where('account_meta.name', '=', 'account_number'); | 
					
						
							|  |  |  |                     $q1->where('account_meta.data', '=', $json); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  |             $dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); | 
					
						
							|  |  |  |             $dbQuery->whereIn('account_types.type', $types); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-04 07:39:16 +01:00
										 |  |  |         /** @var null|Account */ | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  |         return $dbQuery->first(['accounts.*']); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     public function findByIbanNull(string $iban, array $types): ?Account | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-05-18 06:49:29 +02:00
										 |  |  |         $iban  = Steam::filterSpaces($iban); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         $query = $this->user->accounts()->where('iban', '!=', '')->whereNotNull('iban'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |             $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); | 
					
						
							|  |  |  |             $query->whereIn('account_types.type', $types); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-04 07:39:16 +01:00
										 |  |  |         /** @var null|Account */ | 
					
						
							| 
									
										
										
										
											2021-06-30 06:17:38 +02:00
										 |  |  |         return $query->where('iban', $iban)->first(['accounts.*']); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function findByName(string $name, array $types): ?Account | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $query   = $this->user->accounts(); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |             $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); | 
					
						
							|  |  |  |             $query->whereIn('account_types.type', $types); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug(sprintf('Searching for account named "%s" (of user #%d) of the following type(s)', $name, $this->user->id), ['types' => $types]); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 07:29:39 +02:00
										 |  |  |         $query->where('accounts.name', $name); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /** @var null|Account $account */ | 
					
						
							| 
									
										
										
										
											2021-07-10 07:29:39 +02:00
										 |  |  |         $account = $query->first(['accounts.*']); | 
					
						
							|  |  |  |         if (null === $account) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug(sprintf('There is no account with name "%s" of types', $name), $types); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 07:29:39 +02:00
										 |  |  |             return null; | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug(sprintf('Found #%d (%s) with type id %d', $account->id, $account->name, $account->account_type_id)); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 07:29:39 +02:00
										 |  |  |         return $account; | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-27 16:57:36 +02:00
										 |  |  |     #[Override]
 | 
					
						
							| 
									
										
										
										
											2025-03-08 19:55:21 +01:00
										 |  |  |     public function getAccountBalances(Account $account): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $account->accountBalances; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-04 17:30:47 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Return account type or null if not found. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getAccountTypeByType(string $type): ?AccountType | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-04-05 10:56:08 +02:00
										 |  |  |         return AccountType::whereType(ucfirst($type))->first(); | 
					
						
							| 
									
										
										
										
											2018-08-04 17:30:47 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     public function getAccountsById(array $accountIds): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $query = $this->user->accounts(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($accountIds)) { | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |             $query->whereIn('accounts.id', $accountIds); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-24 16:41:58 +02:00
										 |  |  |         $query->orderBy('accounts.order', 'ASC'); | 
					
						
							| 
									
										
										
										
											2019-06-23 05:53:01 +02:00
										 |  |  |         $query->orderBy('accounts.active', 'DESC'); | 
					
						
							| 
									
										
										
										
											2019-06-10 20:14:00 +02:00
										 |  |  |         $query->orderBy('accounts.name', 'ASC'); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 16:41:58 +02:00
										 |  |  |         return $query->get(['accounts.*']); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getActiveAccountsByType(array $types): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $query = $this->user->accounts()->with( | 
					
						
							| 
									
										
										
										
											2025-01-04 09:15:39 +01:00
										 |  |  |             [  // @phpstan-ignore-line
 | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |                 'accountmeta' => static function (HasMany $query): void { | 
					
						
							|  |  |  |                     $query->where('name', 'account_role'); | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 'attachments', | 
					
						
							| 
									
										
										
										
											2022-12-29 19:42:26 +01:00
										 |  |  |             ] | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         ); | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |             $query->accountTypeIn($types); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-05-01 20:04:58 +02:00
										 |  |  |         $query->where('active', true); | 
					
						
							| 
									
										
										
										
											2019-06-10 20:14:00 +02:00
										 |  |  |         $query->orderBy('accounts.account_type_id', 'ASC'); | 
					
						
							| 
									
										
										
										
											2020-07-24 16:41:58 +02:00
										 |  |  |         $query->orderBy('accounts.order', 'ASC'); | 
					
						
							| 
									
										
										
										
											2019-06-10 20:14:00 +02:00
										 |  |  |         $query->orderBy('accounts.name', 'ASC'); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-19 19:17:14 +02:00
										 |  |  |         return $query->get(['accounts.*']); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |     public function getAttachments(Account $account): Collection | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $set  = $account->attachments()->get(); | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-23 12:28:27 +01:00
										 |  |  |         /** @var Storage $disk */ | 
					
						
							|  |  |  |         $disk = Storage::disk('upload'); | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $set->each( | 
					
						
							| 
									
										
										
										
											2025-01-04 09:15:39 +01:00
										 |  |  |             static function (Attachment $attachment) use ($disk) { // @phpstan-ignore-line
 | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |                 $notes                   = $attachment->notes()->first(); | 
					
						
							|  |  |  |                 $attachment->file_exists = $disk->exists($attachment->fileName()); | 
					
						
							| 
									
										
										
										
											2023-11-05 09:40:45 +01:00
										 |  |  |                 $attachment->notes_text  = null !== $notes ? $notes->text : ''; | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return $attachment; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     public function getCashAccount(): Account | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @var AccountType $type */ | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $type    = AccountType::where('type', AccountTypeEnum::CASH->value)->first(); | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         /** @var AccountFactory $factory */ | 
					
						
							|  |  |  |         $factory = app(AccountFactory::class); | 
					
						
							|  |  |  |         $factory->setUser($this->user); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $factory->findOrCreate('Cash account', $type->type); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  |     public function getCreditTransactionGroup(Account $account): ?TransactionGroup | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-10-30 14:24:28 +01:00
										 |  |  |         $journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->where('transactions.account_id', $account->id) | 
					
						
							|  |  |  |             ->transactionTypes([TransactionTypeEnum::LIABILITY_CREDIT->value]) | 
					
						
							|  |  |  |             ->first(['transaction_journals.*']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-04 06:30:22 +02:00
										 |  |  |         return $journal?->transactionGroup; | 
					
						
							| 
									
										
										
										
											2021-09-18 10:26:12 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |     public function getInactiveAccountsByType(array $types): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $query = $this->user->accounts()->with( | 
					
						
							| 
									
										
										
										
											2025-01-04 09:15:39 +01:00
										 |  |  |             [ // @phpstan-ignore-line
 | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |                 'accountmeta' => static function (HasMany $query): void { | 
					
						
							|  |  |  |                     $query->where('name', 'account_role'); | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-12-29 19:42:26 +01:00
										 |  |  |             ] | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |         ); | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |             $query->accountTypeIn($types); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         $query->where('active', 0); | 
					
						
							|  |  |  |         $query->orderBy('accounts.account_type_id', 'ASC'); | 
					
						
							|  |  |  |         $query->orderBy('accounts.order', 'ASC'); | 
					
						
							|  |  |  |         $query->orderBy('accounts.name', 'ASC'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $query->get(['accounts.*']); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getLocation(Account $account): ?Location | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-01-04 07:39:16 +01:00
										 |  |  |         /** @var null|Location */ | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |         return $account->locations()->first(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-19 19:39:02 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Get note text or null. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getNoteText(Account $account): ?string | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-04 06:30:22 +02:00
										 |  |  |         return $account->notes()->first()?->text; | 
					
						
							| 
									
										
										
										
											2018-03-19 19:39:02 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 22:14:53 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Returns the amount of the opening balance for this account. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2025-08-01 06:12:36 +02:00
										 |  |  |     public function getOpeningBalanceAmount(Account $account, bool $convertToPrimary): ?string | 
					
						
							| 
									
										
										
										
											2018-02-16 22:14:53 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $journal     = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') | 
					
						
							|  |  |  |             ->where('transactions.account_id', $account->id) | 
					
						
							|  |  |  |             ->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value, TransactionTypeEnum::LIABILITY_CREDIT->value]) | 
					
						
							|  |  |  |             ->first(['transaction_journals.*']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2018-02-16 22:14:53 +01:00
										 |  |  |         if (null === $journal) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         $transaction = $journal->transactions()->where('account_id', $account->id)->first(); | 
					
						
							|  |  |  |         if (null === $transaction) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-08-01 06:12:36 +02:00
										 |  |  |         if ($convertToPrimary) { | 
					
						
							| 
									
										
										
										
											2025-01-15 18:54:49 +01:00
										 |  |  |             return $transaction->native_amount ?? '0'; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-02-16 22:14:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 19:41:37 +01:00
										 |  |  |         return $transaction->amount; | 
					
						
							| 
									
										
										
										
											2018-02-16 22:14:53 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Return date of opening balance as string or null. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getOpeningBalanceDate(Account $account): ?string | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-06-04 06:30:22 +02:00
										 |  |  |         return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->where('transactions.account_id', $account->id) | 
					
						
							|  |  |  |             ->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value, TransactionTypeEnum::LIABILITY_CREDIT->value]) | 
					
						
							|  |  |  |             ->first(['transaction_journals.*'])?->date->format('Y-m-d H:i:s') | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2018-02-16 22:14:53 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-24 07:56:08 +02:00
										 |  |  |     public function getOpeningBalanceGroup(Account $account): ?TransactionGroup | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $journal = $this->getOpeningBalance($account); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 17:27:01 +01:00
										 |  |  |         return $journal?->transactionGroup; | 
					
						
							| 
									
										
										
										
											2019-08-24 07:56:08 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     public function getOpeningBalance(Account $account): ?TransactionJournal | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->where('transactions.account_id', $account->id) | 
					
						
							|  |  |  |             ->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value]) | 
					
						
							|  |  |  |             ->first(['transaction_journals.*']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-09 13:09:43 +01:00
										 |  |  |     public function getPiggyBanks(Account $account): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $account->piggyBanks()->get(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     public function getReconciliation(Account $account): ?Account | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |         if (AccountTypeEnum::ASSET->value !== $account->accountType->type) { | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |             throw new FireflyException(sprintf('%s is not an asset account.', $account->name)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-07-31 20:24:19 +02:00
										 |  |  |         $currency = $this->getAccountCurrency($account) ?? app('amount')->getPrimaryCurrency(); | 
					
						
							| 
									
										
										
										
											2020-08-09 08:56:15 +02:00
										 |  |  |         $name     = trans('firefly.reconciliation_account_name', ['name' => $account->name, 'currency' => $currency->code]); | 
					
						
							| 
									
										
										
										
											2020-02-29 13:58:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         /** @var AccountType $type */ | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $type     = AccountType::where('type', AccountTypeEnum::RECONCILIATION->value)->first(); | 
					
						
							| 
									
										
										
										
											2023-11-04 06:52:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |         /** @var null|Account $current */ | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $current  = $this->user->accounts()->where('account_type_id', $type->id) | 
					
						
							|  |  |  |             ->where('name', $name) | 
					
						
							|  |  |  |             ->first() | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2019-08-03 19:17:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 18:02:06 +04:00
										 |  |  |         if (null !== $current) { | 
					
						
							|  |  |  |             return $current; | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-05 18:02:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $data     = [ | 
					
						
							| 
									
										
										
										
											2021-04-05 21:52:55 +02:00
										 |  |  |             'account_type_id'   => null, | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |             'account_type_name' => AccountTypeEnum::RECONCILIATION->value, | 
					
						
							| 
									
										
										
										
											2021-04-05 21:52:55 +02:00
										 |  |  |             'active'            => true, | 
					
						
							|  |  |  |             'name'              => $name, | 
					
						
							|  |  |  |             'currency_id'       => $currency->id, | 
					
						
							|  |  |  |             'currency_code'     => $currency->code, | 
					
						
							| 
									
										
										
										
											2020-05-05 18:02:06 +04:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         /** @var AccountFactory $factory */ | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $factory  = app(AccountFactory::class); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |         $factory->setUser($account->user); | 
					
						
							| 
									
										
										
										
											2020-05-05 18:02:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 20:32:04 +02:00
										 |  |  |         return $factory->create($data); | 
					
						
							| 
									
										
										
										
											2018-07-23 21:49:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     public function getAccountCurrency(Account $account): ?TransactionCurrency | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $type       = $account->accountType->type; | 
					
						
							|  |  |  |         $list       = config('firefly.valid_currency_account_types'); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // return null if not in this list.
 | 
					
						
							|  |  |  |         if (!in_array($type, $list, true)) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |         $currencyId = (int) $this->getMetaValue($account, 'currency_id'); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         if ($currencyId > 0) { | 
					
						
							|  |  |  |             return TransactionCurrency::find($currencyId); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Return meta value for account. Null if not found. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getMetaValue(Account $account, string $field): ?string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $result = $account->accountMeta->filter( | 
					
						
							| 
									
										
										
										
											2025-05-04 13:55:42 +02:00
										 |  |  |             static fn (AccountMeta $meta) => strtolower($meta->name) === strtolower($field) | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         ); | 
					
						
							|  |  |  |         if (0 === $result->count()) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (1 === $result->count()) { | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             return (string) $result->first()->data; | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function count(array $types): int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->user->accounts()->accountTypeIn($types)->count(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function find(int $accountId): ?Account | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-01-04 07:39:16 +01:00
										 |  |  |         /** @var null|Account */ | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         return $this->user->accounts()->find($accountId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |     public function getUsedCurrencies(Account $account): Collection | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-12-25 11:59:15 +01:00
										 |  |  |         $info        = $account->transactions()->distinct()->groupBy('transaction_currency_id')->get(['transaction_currency_id'])->toArray(); | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |         $currencyIds = []; | 
					
						
							|  |  |  |         foreach ($info as $entry) { | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             $currencyIds[] = (int) $entry['transaction_currency_id']; | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         $currencyIds = array_unique($currencyIds); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return TransactionCurrency::whereIn('id', $currencyIds)->get(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 21:18:15 +02:00
										 |  |  |     public function isLiability(Account $account): bool | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |         return in_array($account->accountType->type, [AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], true); | 
					
						
							| 
									
										
										
										
											2018-08-22 21:18:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |     public function maxOrder(string $type): int | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $sets     = [ | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |             AccountTypeEnum::ASSET->value    => [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value], | 
					
						
							|  |  |  |             AccountTypeEnum::EXPENSE->value  => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::BENEFICIARY->value], | 
					
						
							|  |  |  |             AccountTypeEnum::REVENUE->value  => [AccountTypeEnum::REVENUE->value], | 
					
						
							|  |  |  |             AccountTypeEnum::LOAN->value     => [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value], | 
					
						
							|  |  |  |             AccountTypeEnum::DEBT->value     => [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value], | 
					
						
							|  |  |  |             AccountTypeEnum::MORTGAGE->value => [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value], | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  |         if (array_key_exists(ucfirst($type), $sets)) { | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |             $order = (int) $this->getAccountsByType($sets[ucfirst($type)])->max('order'); | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |             app('log')->debug(sprintf('Return max order of "%s" set: %d', $type, $order)); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return $order; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |         $specials = [AccountTypeEnum::CASH->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::RECONCILIATION->value]; | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $order    = (int) $this->getAccountsByType($specials)->max('order'); | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |         app('log')->debug(sprintf('Return max order of "%s" set (specials!): %d', $type, $order)); | 
					
						
							| 
									
										
										
										
											2021-03-21 09:15:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $order; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |     public function getAccountsByType(array $types, ?array $sort = []): Collection | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |         $res   = array_intersect([AccountTypeEnum::ASSET->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value], $types); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         $query = $this->user->accounts(); | 
					
						
							|  |  |  |         if (0 !== count($types)) { | 
					
						
							|  |  |  |             $query->accountTypeIn($types); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // add sort parameters. At this point they're filtered to allowed fields to sort by:
 | 
					
						
							|  |  |  |         if (0 !== count($sort)) { | 
					
						
							|  |  |  |             foreach ($sort as $param) { | 
					
						
							|  |  |  |                 $query->orderBy($param[0], $param[1]); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (0 === count($sort)) { | 
					
						
							|  |  |  |             if (0 !== count($res)) { | 
					
						
							|  |  |  |                 $query->orderBy('accounts.order', 'ASC'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $query->orderBy('accounts.active', 'DESC'); | 
					
						
							|  |  |  |             $query->orderBy('accounts.name', 'ASC'); | 
					
						
							| 
									
										
										
										
											2025-02-19 06:21:27 +01:00
										 |  |  |             $query->orderBy('accounts.account_type_id', 'ASC'); | 
					
						
							|  |  |  |             $query->orderBy('accounts.id', 'ASC'); | 
					
						
							| 
									
										
										
										
											2023-06-21 12:34:58 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $query->get(['accounts.*']); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Returns the date of the very first transaction in this account. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function oldestJournalDate(Account $account): ?Carbon | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $journal = $this->oldestJournal($account); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $journal?->date; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 14:59:58 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Returns the date of the very first transaction in this account. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function oldestJournal(Account $account): ?TransactionJournal | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |         /** @var null|TransactionJournal $first */ | 
					
						
							| 
									
										
										
										
											2022-03-29 14:59:58 +02:00
										 |  |  |         $first = $account->transactions() | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') | 
					
						
							|  |  |  |             ->orderBy('transaction_journals.date', 'ASC') | 
					
						
							|  |  |  |             ->orderBy('transaction_journals.order', 'DESC') | 
					
						
							|  |  |  |             ->where('transaction_journals.user_id', $this->user->id) | 
					
						
							|  |  |  |             ->orderBy('transaction_journals.id', 'ASC') | 
					
						
							|  |  |  |             ->first(['transaction_journals.id']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2022-03-29 14:59:58 +02:00
										 |  |  |         if (null !== $first) { | 
					
						
							| 
									
										
										
										
											2025-01-05 07:31:26 +01:00
										 |  |  |             /** @var null|TransactionJournal */ | 
					
						
							| 
									
										
										
										
											2023-11-05 19:41:37 +01:00
										 |  |  |             return TransactionJournal::find($first->id); | 
					
						
							| 
									
										
										
										
											2022-03-29 14:59:58 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-27 16:57:36 +02:00
										 |  |  |     #[Override]
 | 
					
						
							| 
									
										
										
										
											2025-05-04 17:41:26 +02:00
										 |  |  |     public function periodCollection(Account $account, Carbon $start, Carbon $end): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $account->transactions() | 
					
						
							|  |  |  |             ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') | 
					
						
							|  |  |  |             ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') | 
					
						
							|  |  |  |             ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id') | 
					
						
							|  |  |  |             ->leftJoin('transaction_currencies as foreign_currencies', 'foreign_currencies.id', '=', 'transactions.foreign_currency_id') | 
					
						
							|  |  |  |             ->where('transaction_journals.date', '>=', $start) | 
					
						
							|  |  |  |             ->where('transaction_journals.date', '<=', $end) | 
					
						
							|  |  |  |             ->get([ | 
					
						
							|  |  |  |                 // currencies
 | 
					
						
							|  |  |  |                 'transaction_currencies.id as currency_id', | 
					
						
							|  |  |  |                 'transaction_currencies.code as currency_code', | 
					
						
							|  |  |  |                 'transaction_currencies.name as currency_name', | 
					
						
							|  |  |  |                 'transaction_currencies.symbol as currency_symbol', | 
					
						
							|  |  |  |                 'transaction_currencies.decimal_places as currency_decimal_places', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // foreign
 | 
					
						
							|  |  |  |                 'foreign_currencies.id as foreign_currency_id', | 
					
						
							|  |  |  |                 'foreign_currencies.code as foreign_currency_code', | 
					
						
							|  |  |  |                 'foreign_currencies.name as foreign_currency_name', | 
					
						
							|  |  |  |                 'foreign_currencies.symbol as foreign_currency_symbol', | 
					
						
							|  |  |  |                 'foreign_currencies.decimal_places as foreign_currency_decimal_places', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // fields
 | 
					
						
							| 
									
										
										
										
											2025-08-08 20:59:24 +02:00
										 |  |  |                 'transaction_journals.date', | 
					
						
							|  |  |  |                 'transaction_types.type', | 
					
						
							|  |  |  |                 'transaction_journals.transaction_currency_id', | 
					
						
							|  |  |  |                 'transactions.amount', | 
					
						
							| 
									
										
										
										
											2025-08-09 20:10:40 +02:00
										 |  |  |                 'transactions.native_amount as pc_amount', | 
					
						
							| 
									
										
										
										
											2025-08-08 21:03:45 +02:00
										 |  |  |                 'transactions.foreign_amount', | 
					
						
							|  |  |  |             ]) | 
					
						
							| 
									
										
										
										
											2025-08-09 20:29:01 +02:00
										 |  |  |             ->toArray() | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2025-05-04 17:41:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-13 12:01:01 +01:00
										 |  |  |     public function resetAccountOrder(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $sets = [ | 
					
						
							| 
									
										
										
										
											2025-01-03 09:15:52 +01:00
										 |  |  |             [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value], | 
					
						
							|  |  |  |             // [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::BENEFICIARY->value],
 | 
					
						
							|  |  |  |             // [AccountTypeEnum::REVENUE->value],
 | 
					
						
							|  |  |  |             [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value], | 
					
						
							|  |  |  |             // [AccountTypeEnum::CASH->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::RECONCILIATION->value],
 | 
					
						
							| 
									
										
										
										
											2021-03-13 12:01:01 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  |         foreach ($sets as $set) { | 
					
						
							|  |  |  |             $list  = $this->getAccountsByType($set); | 
					
						
							|  |  |  |             $index = 1; | 
					
						
							|  |  |  |             foreach ($list as $account) { | 
					
						
							| 
									
										
										
										
											2021-03-28 11:46:23 +02:00
										 |  |  |                 if (false === $account->active) { | 
					
						
							| 
									
										
										
										
											2021-03-27 15:28:11 +01:00
										 |  |  |                     $account->order = 0; | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-27 15:28:11 +01:00
										 |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |                 if ($index !== (int) $account->order) { | 
					
						
							| 
									
										
										
										
											2023-10-29 06:33:43 +01:00
										 |  |  |                     app('log')->debug(sprintf('Account #%d ("%s"): order should %d be but is %d.', $account->id, $account->name, $index, $account->order)); | 
					
						
							| 
									
										
										
										
											2021-03-13 12:01:01 +01:00
										 |  |  |                     $account->order = $index; | 
					
						
							|  |  |  |                     $account->save(); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-12-20 19:35:52 +01:00
										 |  |  |                 ++$index; | 
					
						
							| 
									
										
										
										
											2021-03-13 12:01:01 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-07-26 03:57:35 +02:00
										 |  |  |         // reset the rest to zero.
 | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |         $all  = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value]; | 
					
						
							| 
									
										
										
										
											2024-07-29 05:06:54 +02:00
										 |  |  |         $this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->whereNotIn('account_types.type', $all) | 
					
						
							|  |  |  |             ->update(['order' => 0]) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 08:43:12 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @throws FireflyException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function update(Account $account, array $data): Account | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @var AccountUpdateService $service */ | 
					
						
							|  |  |  |         $service = app(AccountUpdateService::class); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $service->update($account, $data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-21 06:20:31 +02:00
										 |  |  |     public function searchAccount(string $query, array $types, int $limit): Collection | 
					
						
							| 
									
										
										
										
											2019-03-02 14:12:09 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-08-29 17:53:25 +02:00
										 |  |  |         $dbQuery = $this->user->accounts() | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->where('active', true) | 
					
						
							|  |  |  |             ->orderBy('accounts.order', 'ASC') | 
					
						
							|  |  |  |             ->orderBy('accounts.account_type_id', 'ASC') | 
					
						
							|  |  |  |             ->orderBy('accounts.name', 'ASC') | 
					
						
							|  |  |  |             ->with(['accountType']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2019-05-04 20:58:43 +02:00
										 |  |  |         if ('' !== $query) { | 
					
						
							| 
									
										
										
										
											2019-11-10 07:26:49 +01:00
										 |  |  |             // split query on spaces just in case:
 | 
					
						
							|  |  |  |             $parts = explode(' ', $query); | 
					
						
							| 
									
										
										
										
											2020-08-09 08:56:15 +02:00
										 |  |  |             foreach ($parts as $part) { | 
					
						
							| 
									
										
										
										
											2019-11-10 07:26:49 +01:00
										 |  |  |                 $search = sprintf('%%%s%%', $part); | 
					
						
							| 
									
										
										
										
											2024-10-10 06:30:05 +02:00
										 |  |  |                 $dbQuery->whereLike('name', $search); | 
					
						
							| 
									
										
										
										
											2019-11-10 07:26:49 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-05-04 20:58:43 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2019-03-02 14:12:09 +01:00
										 |  |  |             $dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); | 
					
						
							|  |  |  |             $dbQuery->whereIn('account_types.type', $types); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-21 06:20:31 +02:00
										 |  |  |         return $dbQuery->take($limit)->get(['accounts.*']); | 
					
						
							| 
									
										
										
										
											2019-03-02 14:12:09 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-22 12:24:01 +02:00
										 |  |  |     public function searchAccountNr(string $query, array $types, int $limit): Collection | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $dbQuery = $this->user->accounts()->distinct() | 
					
						
							| 
									
										
										
										
											2025-03-14 17:45:16 +01:00
										 |  |  |             ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') | 
					
						
							|  |  |  |             ->where('accounts.active', true) | 
					
						
							|  |  |  |             ->orderBy('accounts.order', 'ASC') | 
					
						
							|  |  |  |             ->orderBy('accounts.account_type_id', 'ASC') | 
					
						
							|  |  |  |             ->orderBy('accounts.name', 'ASC') | 
					
						
							|  |  |  |             ->with(['accountType', 'accountMeta']) | 
					
						
							|  |  |  |         ; | 
					
						
							| 
									
										
										
										
											2020-08-22 12:24:01 +02:00
										 |  |  |         if ('' !== $query) { | 
					
						
							|  |  |  |             // split query on spaces just in case:
 | 
					
						
							|  |  |  |             $parts = explode(' ', $query); | 
					
						
							|  |  |  |             foreach ($parts as $part) { | 
					
						
							|  |  |  |                 $search = sprintf('%%%s%%', $part); | 
					
						
							| 
									
										
										
										
											2021-03-07 16:19:14 +01:00
										 |  |  |                 $dbQuery->where( | 
					
						
							| 
									
										
										
										
											2025-01-04 19:43:58 +01:00
										 |  |  |                     static function (EloquentBuilder $q1) use ($search): void { | 
					
						
							| 
									
										
										
										
											2024-10-14 05:14:52 +02:00
										 |  |  |                         $q1->whereLike('accounts.iban', $search); | 
					
						
							| 
									
										
										
										
											2021-03-07 16:19:14 +01:00
										 |  |  |                         $q1->orWhere( | 
					
						
							| 
									
										
										
										
											2023-12-21 05:07:26 +01:00
										 |  |  |                             static function (EloquentBuilder $q2) use ($search): void { | 
					
						
							| 
									
										
										
										
											2021-03-07 16:19:14 +01:00
										 |  |  |                                 $q2->where('account_meta.name', '=', 'account_number'); | 
					
						
							| 
									
										
										
										
											2024-10-10 06:30:05 +02:00
										 |  |  |                                 $q2->whereLike('account_meta.data', $search); | 
					
						
							| 
									
										
										
										
											2021-03-07 16:19:14 +01:00
										 |  |  |                             } | 
					
						
							|  |  |  |                         ); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2020-08-22 12:24:01 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-11-04 05:11:05 +01:00
										 |  |  |         if (0 !== count($types)) { | 
					
						
							| 
									
										
										
										
											2020-08-22 12:24:01 +02:00
										 |  |  |             $dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); | 
					
						
							|  |  |  |             $dbQuery->whereIn('account_types.type', $types); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $dbQuery->take($limit)->get(['accounts.*']); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-03-07 16:19:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-29 13:56:55 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |      * @throws FireflyException | 
					
						
							| 
									
										
										
										
											2023-12-22 20:12:38 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-03-12 06:20:01 +01:00
										 |  |  |     public function store(array $data): Account | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @var AccountFactory $factory */ | 
					
						
							|  |  |  |         $factory = app(AccountFactory::class); | 
					
						
							|  |  |  |         $factory->setUser($this->user); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $factory->create($data); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-03-29 08:14:32 +02:00
										 |  |  | } |