Ecodev /
my-ichtus
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Application\Repository; |
||
| 6 | |||
| 7 | use Application\DBAL\Types\AccountTypeType; |
||
| 8 | use Application\Model\Account; |
||
| 9 | use Application\Model\User; |
||
| 10 | use Doctrine\ORM\Query; |
||
| 11 | use Ecodev\Felix\Repository\LimitedAccessSubQuery; |
||
| 12 | use Exception; |
||
| 13 | use Money\Money; |
||
| 14 | |||
| 15 | /** |
||
| 16 | * Class AccountRepository. |
||
| 17 | * |
||
| 18 | * @method null|Account findOneByCode(int $code) |
||
| 19 | */ |
||
| 20 | class AccountRepository extends AbstractRepository implements LimitedAccessSubQuery |
||
| 21 | { |
||
| 22 | final public const ACCOUNT_ID_FOR_BANK = 10025; |
||
| 23 | |||
| 24 | /** |
||
| 25 | * In memory max code that keep being incremented if we create several account at once without flushing in DB. |
||
| 26 | */ |
||
| 27 | private ?int $maxCode = null; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * Clear all caches. |
||
| 31 | */ |
||
| 32 | 136 | public function clearCache(): void |
|
| 33 | { |
||
| 34 | 136 | $this->maxCode = null; |
|
| 35 | } |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Returns pure SQL to get ID of all objects that are accessible to given user. |
||
| 39 | * |
||
| 40 | * @param null|User $user |
||
| 41 | */ |
||
| 42 | 23 | public function getAccessibleSubQuery(?\Ecodev\Felix\Model\User $user): string |
|
| 43 | { |
||
| 44 | 23 | if (!$user) { |
|
| 45 | 1 | return '-1'; |
|
| 46 | } |
||
| 47 | |||
| 48 | 22 | if (in_array($user->getRole(), [ |
|
| 49 | User::ROLE_TRAINER, |
||
| 50 | User::ROLE_ACCOUNTING_VERIFICATOR, |
||
| 51 | User::ROLE_RESPONSIBLE, |
||
| 52 | User::ROLE_ADMINISTRATOR, |
||
| 53 | ], true)) { |
||
| 54 | 11 | return $this->getAllIdsQuery(); |
|
| 55 | } |
||
| 56 | |||
| 57 | 11 | if ($user->getRole() === User::ROLE_FORMATION_RESPONSIBLE) { |
|
| 58 | 1 | return $this->getAllIdsForAnyOwner(); |
|
| 59 | } |
||
| 60 | |||
| 61 | 10 | return $this->getAllIdsForFamilyQuery($user); |
|
| 62 | } |
||
| 63 | |||
| 64 | /** |
||
| 65 | * Unsecured way to get a account from its ID. |
||
| 66 | * |
||
| 67 | * This should only be used in tests or controlled environment. |
||
| 68 | */ |
||
| 69 | 5 | public function getOneById(int $id): Account |
|
| 70 | { |
||
| 71 | 5 | $account = $this->getAclFilter()->runWithoutAcl(fn () => $this->findOneById($id)); |
|
| 72 | |||
| 73 | 5 | if (!$account) { |
|
| 74 | 1 | throw new Exception('Account #' . $id . ' not found'); |
|
| 75 | } |
||
| 76 | |||
| 77 | 5 | return $account; |
|
| 78 | } |
||
| 79 | |||
| 80 | /** |
||
| 81 | * This will return, and potentially create, an account for the given user. |
||
| 82 | */ |
||
| 83 | 30 | public function getOrCreate(User $user): Account |
|
| 84 | { |
||
| 85 | global $container; |
||
| 86 | |||
| 87 | // If an account already exists, because getOrCreate was called once before without flushing in between, |
||
| 88 | // then can return immediately |
||
| 89 | 30 | if ($user->getAccount()) { |
|
| 90 | 17 | return $user->getAccount(); |
|
| 91 | } |
||
| 92 | |||
| 93 | // If user have an owner, then create account for the owner instead |
||
| 94 | 15 | if ($user->getOwner()) { |
|
| 95 | $user = $user->getOwner(); |
||
| 96 | } |
||
| 97 | |||
| 98 | 15 | $account = $this->getAclFilter()->runWithoutAcl(fn () => $this->findOneByOwner($user)); |
|
| 99 | |||
| 100 | 15 | if (!$account) { |
|
| 101 | 15 | $account = new Account(); |
|
| 102 | 15 | $this->getEntityManager()->persist($account); |
|
| 103 | 15 | $account->setOwner($user); |
|
| 104 | 15 | $account->setType(AccountTypeType::LIABILITY); |
|
| 105 | 15 | $account->setName($user->getName()); |
|
| 106 | |||
| 107 | 15 | $config = $container->get('config'); |
|
| 108 | 15 | $parentCode = (int) $config['accounting']['customerDepositsAccountCode']; |
|
| 109 | 15 | $parent = $this->getAclFilter()->runWithoutAcl(fn () => $this->findOneByCode($parentCode)); |
|
| 110 | |||
| 111 | // Find the max account code, using the liability parent code as prefix |
||
| 112 | 15 | if (!$this->maxCode) { |
|
| 113 | 15 | $maxQuery = 'SELECT MAX(code) FROM account WHERE code LIKE ' . $this->getEntityManager()->getConnection()->quote($parent->getCode() . '%'); |
|
| 114 | 15 | $this->maxCode = (int) $this->getEntityManager()->getConnection()->fetchOne($maxQuery); |
|
| 115 | |||
| 116 | // If there is no child account yet, reserve enough digits for many users |
||
| 117 | 15 | if ($this->maxCode === $parent->getCode()) { |
|
| 118 | 1 | $this->maxCode = $parent->getCode() * 10000; |
|
| 119 | } |
||
| 120 | } |
||
| 121 | |||
| 122 | 15 | $nextCode = ++$this->maxCode; |
|
| 123 | 15 | $account->setCode($nextCode); |
|
| 124 | |||
| 125 | 15 | $account->setParent($parent); |
|
| 126 | } |
||
| 127 | |||
| 128 | 15 | return $account; |
|
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Sum balance by account type. |
||
| 133 | * |
||
| 134 | * @API\Input(type="AccountType") |
||
| 135 | */ |
||
| 136 | 2 | public function totalBalanceByType(string $accountType): Money |
|
| 137 | { |
||
| 138 | 2 | $qb = $this->getEntityManager()->getConnection()->createQueryBuilder() |
|
| 139 | 2 | ->select('SUM(balance)') |
|
| 140 | 2 | ->from($this->getClassMetadata()->getTableName()) |
|
| 141 | 2 | ->where('type = :type'); |
|
| 142 | |||
| 143 | 2 | $qb->setParameter('type', $accountType); |
|
| 144 | |||
| 145 | 2 | $result = $qb->executeQuery(); |
|
| 146 | |||
| 147 | 2 | return Money::CHF($result->fetchOne()); |
|
| 148 | } |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Update all accounts' balance. |
||
| 152 | */ |
||
| 153 | 1 | public function updateAccountsBalance(): void |
|
| 154 | { |
||
| 155 | 1 | $connection = $this->getEntityManager()->getConnection(); |
|
| 156 | 1 | $sql = 'CALL update_account_balance(0)'; |
|
| 157 | 1 | $connection->executeQuery($sql); |
|
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * Return the next available Account code. |
||
| 162 | */ |
||
| 163 | public function getNextCodeAvailable(): int |
||
| 164 | { |
||
| 165 | $qb = _em()->getConnection()->createQueryBuilder() |
||
| 166 | ->select('IFNULL(MAX(a.code) + 1, 1)') |
||
| 167 | ->from('account', 'a'); |
||
| 168 | |||
| 169 | return (int) $qb->execute()->fetchOne(); |
||
|
0 ignored issues
–
show
|
|||
| 170 | } |
||
| 171 | |||
| 172 | 1 | public function getRootAccountsQuery(): Query |
|
| 173 | { |
||
| 174 | 1 | $qb = $this->createQueryBuilder('account') |
|
| 175 | 1 | ->andWhere('account.parent IS NULL') |
|
| 176 | 1 | ->orderBy('account.code'); |
|
| 177 | |||
| 178 | 1 | return $qb->getQuery(); |
|
| 179 | } |
||
| 180 | |||
| 181 | 2 | public function deleteAccountOfNonFamilyOwnerWithoutAnyTransactions(): int |
|
| 182 | { |
||
| 183 | 2 | $sql = <<<STRING |
|
| 184 | DELETE account FROM account |
||
| 185 | INNER JOIN user ON account.owner_id = user.id |
||
| 186 | AND user.owner_id IS NOT NULL |
||
| 187 | AND user.owner_id != user.id |
||
| 188 | WHERE |
||
| 189 | account.id NOT IN (SELECT credit_id FROM transaction_line WHERE credit_id IS NOT NULL) |
||
| 190 | AND account.id NOT IN (SELECT debit_id FROM transaction_line WHERE debit_id IS NOT NULL) |
||
| 191 | STRING; |
||
| 192 | |||
| 193 | 2 | $count = $this->getEntityManager()->getConnection()->executeStatement($sql); |
|
| 194 | |||
| 195 | 2 | return $count; |
|
| 196 | } |
||
| 197 | } |
||
| 198 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.