TransactionChecker::checkBalance()   A
last analyzed

Complexity

Conditions 5
Paths 10

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
dl 0
loc 18
ccs 13
cts 13
cp 1
rs 9.5555
c 1
b 0
f 0
cc 5
nc 10
nop 1
crap 5
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
The method getUnitOfWork() does not exist on Doctrine\Persistence\ObjectManager. It seems like you code against a sub-type of said class. However, the method does not exist in Doctrine\Persistence\ObjectManagerDecorator. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

34
        $unitOfWork = $eventArgs->getObjectManager()->/** @scrutinizer ignore-call */ getUnitOfWork();
Loading history...
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