Failed Conditions
Push — master ( 3cf6df...56f0b0 )
by Adrien
07:17
created

Accounting::checkFamilyMembersShareSameAccount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3.8821

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 11
ccs 2
cts 9
cp 0.2222
crap 3.8821
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Service;
6
7
use Application\DBAL\Types\AccountTypeType;
8
use Application\Model\Account;
9
use Application\Model\Transaction;
10
use Application\Model\User;
11
use Application\Repository\AccountRepository;
12
use Application\Repository\TransactionRepository;
13
use Application\Repository\UserRepository;
14
use Doctrine\ORM\EntityManager;
15
use Ecodev\Felix\Format;
16
use Throwable;
17
18
/**
19
 * Service to process accounting tasks
20
 */
21
class Accounting
22
{
23
    private EntityManager $entityManager;
24
25
    private TransactionRepository $transactionRepository;
26
27
    private AccountRepository $accountRepository;
28
29
    private UserRepository $userRepository;
30
31
    private bool $hasError = false;
32
33 1
    public function __construct(EntityManager $entityManager)
34
    {
35 1
        $this->entityManager = $entityManager;
36 1
        $this->transactionRepository = $this->entityManager->getRepository(Transaction::class);
37 1
        $this->accountRepository = $this->entityManager->getRepository(Account::class);
38 1
        $this->userRepository = $this->entityManager->getRepository(User::class);
39 1
    }
40
41
    /**
42
     * Check and print various things about accounting.
43
     *
44
     * @return bool `true` if errors are found
45
     */
46 1
    public function check(): bool
47
    {
48
        // Update all accounts' balance from transactions
49 1
        $this->accountRepository->updateAccountBalance();
50
51 1
        $this->checkAccounts();
52 1
        $this->checkTransactionsAreBalanced();
53 1
        $this->checkMissingAccountsForUsers();
54 1
        $this->checkUnnecessaryAccounts();
55 1
        $this->checkFamilyMembersShareSameAccount();
56
57 1
        return $this->hasError;
58
    }
59
60
    /**
61
     * Print the error message and remember that at least one error was found
62
     */
63
    private function error(string $message): void
64
    {
65
        if (!$this->hasError) {
66
            echo PHP_EOL;
67
        }
68
69
        echo $message . PHP_EOL;
70
        $this->hasError = true;
71
    }
72
73 1
    private function checkAccounts(): void
74
    {
75 1
        $assets = $this->accountRepository->totalBalanceByType(AccountTypeType::ASSET);
76 1
        $liabilities = $this->accountRepository->totalBalanceByType(AccountTypeType::LIABILITY);
77 1
        $revenue = $this->accountRepository->totalBalanceByType(AccountTypeType::REVENUE);
78 1
        $expense = $this->accountRepository->totalBalanceByType(AccountTypeType::EXPENSE);
79 1
        $equity = $this->accountRepository->totalBalanceByType(AccountTypeType::EQUITY);
80
81 1
        $income = $revenue->subtract($expense);
82
83 1
        $discrepancy = $assets->subtract($income)->subtract($liabilities->add($equity));
84
85
        echo '
86 1
Produits  : ' . Format::money($revenue) . '
87 1
Charges   : ' . Format::money($expense) . '
88 1
' . ($income->isNegative() ? 'Déficit   : ' : 'Bénéfice  : ') . Format::money($income) . '
89 1
Actifs    : ' . Format::money($assets) . '
90 1
Passifs   : ' . Format::money($liabilities) . '
91 1
Capital   : ' . Format::money($equity) . '
92 1
Écart     : ' . Format::money($discrepancy) . PHP_EOL;
93
94 1
        if (!$discrepancy->isZero()) {
95
            $this->error(sprintf('ERREUR: écart de %s au bilan des comptes', Format::money($discrepancy)));
96
        }
97 1
    }
98
99 1
    private function checkTransactionsAreBalanced(): void
100
    {
101 1
        foreach (_em()->getRepository(Transaction::class)->findAll() as $transaction) {
102
            try {
103 1
                $transaction->checkBalance();
104
            } catch (Throwable $e) {
105
                $this->error($e->getMessage());
106
            }
107
        }
108 1
    }
109
110 1
    private function checkMissingAccountsForUsers(): void
111
    {
112
        // Create missing accounts for users
113 1
        foreach ($this->userRepository->getAllFamilyOwners() as $user) {
114 1
            if (!$user->getAccount()) {
115 1
                $account = $this->accountRepository->getOrCreate($user);
116 1
                echo sprintf('Création du compte %d pour l\'utilisateur %d...', $account->getCode(), $user->getId()) . PHP_EOL;
117 1
                _em()->flush();
118
            }
119
        }
120 1
    }
121
122 1
    private function checkUnnecessaryAccounts(): void
123
    {
124 1
        $deletedAccount = $this->accountRepository->deleteAccountOfNonFamilyOwnerWithoutAnyTransactions();
125 1
        if ($deletedAccount) {
126
            // Strictly speaking this is not an error, but we would like to be informed by email when it happens
127
            $this->error("$deletedAccount compte(s) été effacé parce qu'il appartenait à un utilisateur qui n'était pas chef de famille et que le compte avait aucune transaction");
128
        }
129 1
    }
130
131 1
    private function checkFamilyMembersShareSameAccount(): void
132
    {
133
        // Make sure users of the same family share the same account
134 1
        foreach ($this->userRepository->getAllNonFamilyOwnersWithAccount() as $user) {
135
            $this->error(
136
                sprintf(
137
                    'User#%d (%s) ne devrait pas avoir son propre compte débiteur mais partager celui du User#%d (%s)',
138
                    $user->getId(),
139
                    $user->getName(),
140
                    $user->getOwner()->getId(),
141
                    $user->getOwner()->getName()
142
                )
143
            );
144
        }
145 1
    }
146
}
147