1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Application\Service; |
||
6 | |||
7 | use Application\Model\Transaction; |
||
8 | use Application\Model\TransactionLine; |
||
9 | use Doctrine\Common\EventSubscriber; |
||
10 | use Doctrine\ORM\Event\OnFlushEventArgs; |
||
11 | use Doctrine\ORM\Events; |
||
12 | use Ecodev\Felix\Api\Exception; |
||
13 | use Ecodev\Felix\Format; |
||
14 | use Money\Money; |
||
15 | use WeakMap; |
||
16 | |||
17 | /** |
||
18 | * Automatically check that transaction and all their transaction lines are balanced. |
||
19 | */ |
||
20 | class TransactionChecker implements EventSubscriber |
||
21 | { |
||
22 | 2 | public function getSubscribedEvents(): array |
|
23 | { |
||
24 | 2 | return [Events::onFlush]; |
|
25 | } |
||
26 | |||
27 | /** |
||
28 | * Records all products whose stock may have changed. |
||
29 | */ |
||
30 | 46 | public function onFlush(OnFlushEventArgs $eventArgs): void |
|
31 | { |
||
32 | /** @var WeakMap<Transaction, true> $transactions */ |
||
33 | 46 | $transactions = new WeakMap(); |
|
34 | 46 | $unitOfWork = $eventArgs->getObjectManager()->getUnitOfWork(); |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
35 | 46 | foreach ($unitOfWork->getScheduledEntityInsertions() as $entity) { |
|
36 | 28 | $this->record($transactions, $entity); |
|
37 | } |
||
38 | |||
39 | 46 | foreach ($unitOfWork->getScheduledEntityUpdates() as $entity) { |
|
40 | 26 | $this->record($transactions, $entity); |
|
41 | } |
||
42 | |||
43 | 46 | foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) { |
|
44 | 7 | $this->record($transactions, $entity); |
|
45 | } |
||
46 | |||
47 | 46 | foreach ($transactions as $transaction => $v) { |
|
48 | 16 | $this->checkBalance($transaction); |
|
49 | } |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Record all transactions that must be checked. |
||
54 | * |
||
55 | * @param WeakMap<Transaction, true> $transactions $transactions |
||
56 | */ |
||
57 | 46 | private function record(WeakMap $transactions, object $entity): void |
|
58 | { |
||
59 | 46 | if ($entity instanceof Transaction) { |
|
60 | 13 | $transactions[$entity] = true; |
|
61 | 45 | } elseif ($entity instanceof TransactionLine) { |
|
62 | 15 | $transactions[$entity->getTransaction()] = true; |
|
63 | } |
||
64 | } |
||
65 | |||
66 | 16 | private function checkBalance(Transaction $transaction): void |
|
67 | { |
||
68 | 16 | $totalDebit = Money::CHF(0); |
|
69 | 16 | $totalCredit = Money::CHF(0); |
|
70 | 16 | foreach ($transaction->getTransactionLines() as $line) { |
|
71 | 16 | if ($line->getDebit()) { |
|
72 | 16 | $totalDebit = $totalDebit->add($line->getBalance()); |
|
73 | } |
||
74 | 16 | if ($line->getCredit()) { |
|
75 | 16 | $totalCredit = $totalCredit->add($line->getBalance()); |
|
76 | } |
||
77 | } |
||
78 | |||
79 | 16 | if (!$totalDebit->equals($totalCredit)) { |
|
80 | 2 | throw new Exception(_tr('Transaction %id% non-équilibrée, débits: %totalDebit%, crédits: %totalCredit%', [ |
|
81 | 2 | 'id' => $transaction->getId() ?? 'NEW', |
|
82 | 2 | 'totalDebit' => Format::money($totalDebit), |
|
83 | 2 | 'totalCredit' => Format::money($totalCredit), |
|
84 | 2 | ])); |
|
85 | } |
||
86 | } |
||
87 | } |
||
88 |