Passed
Push — master ( a056d8...a2923e )
by Adrien
10:19
created

testHydrateLinesAndFlushMustThrowWithALineWithoutAnyAccount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApplicationTest\Repository;
6
7
use Application\Model\Account;
8
use Application\Model\Transaction;
9
use Application\Model\TransactionLine;
10
use Application\Model\User;
11
use Application\Repository\TransactionRepository;
12
use ApplicationTest\Traits\LimitedAccessSubQuery;
13
use Cake\Chronos\Chronos;
14
use Money\Money;
15
16
class TransactionRepositoryTest extends AbstractRepositoryTest
17
{
18
    use LimitedAccessSubQuery;
19
20
    private TransactionRepository $repository;
21
22
    protected function setUp(): void
23
    {
24
        parent::setUp();
25
        $this->repository = $this->getEntityManager()->getRepository(Transaction::class);
26
    }
27
28
    public function providerGetAccessibleSubQuery(): iterable
29
    {
30
        $all = [8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007];
31
32
        $family = [8000, 8002, 8002, 8003, 8004, 8006];
33
        yield ['anonymous', []];
34
        yield ['bookingonly', []];
35
        yield ['individual', $family];
36
        yield ['member', $family];
37
        yield ['responsible', $all];
38
        yield ['administrator', $all];
39
    }
40
41
    public function testHydrateLinesAndFlush(): void
42
    {
43
        /** @var User $user */
44
        $user = $this->getEntityManager()->getRepository(User::class)->getOneByLoginOrEmail('administrator');
45
        User::setCurrent($user);
46
47
        $credit = $user->getAccount();
48
        $debit = $this->getEntityManager()->getRepository(Account::class)->findOneBy(['code' => 10101]);
49
50
        $transaction = new Transaction();
51
        $transaction->setName('foo');
52
        $transaction->setTransactionDate(Chronos::now());
53
        $line = new TransactionLine();
54
        $line->setTransaction($transaction);
55
56
        self::assertTrue($transaction->getTransactionLines()->contains($line));
57
        $lines = [
58
            [
59
                'balance' => Money::CHF(500),
60
                'transactionDate' => Chronos::now(),
61
                'credit' => $credit,
62
                'debit' => $debit,
63
            ],
64
        ];
65
66
        $this->repository->hydrateLinesAndFlush($transaction, $lines);
67
68
        self::assertTrue(Money::CHF(500)->equals($credit->getBalance()), 'credit account balance must have been refreshed from DB');
69
        self::assertTrue(Money::CHF(819250)->equals($debit->getBalance()), 'debit account balance must have been refreshed from DB');
70
        self::assertFalse($transaction->getTransactionLines()->contains($line), 'original line must have been deleted');
71
        self::assertCount(1, $transaction->getTransactionLines(), 'one line');
72
73
        $line = $transaction->getTransactionLines()->first();
74
        self::assertTrue(Money::CHF(500)->equals($line->getBalance()));
75
        self::assertSame($credit, $line->getCredit());
76
        self::assertSame($debit, $line->getDebit());
77
    }
78
79
    public function testHydrateLinesAndFlushMustThrowWithoutAnyLines(): void
80
    {
81
        $transaction = new Transaction();
82
83
        $this->expectExceptionMessage('A Transaction must have at least one TransactionLine');
84
        $this->repository->hydrateLinesAndFlush($transaction, []);
85
    }
86
87
    public function testHydrateLinesAndFlushMustThrowWithALineWithoutAnyAccount(): void
88
    {
89
        $transaction = new Transaction();
90
        $this->expectExceptionMessage('Cannot create a TransactionLine without any account');
91
        $this->repository->hydrateLinesAndFlush($transaction, [[]]);
92
    }
93
94
    public function testHydrateLinesAndFlushMustThrowWithUnbalancedLines(): void
95
    {
96
        /** @var User $user */
97
        $user = $this->getEntityManager()->getRepository(User::class)->getOneByLoginOrEmail('administrator');
98
        User::setCurrent($user);
99
100
        $debit = $this->getEntityManager()->getRepository(Account::class)->findOneBy(['code' => 10101]);
101
        $credit = $this->getEntityManager()->getRepository(Account::class)->findOneBy(['code' => 10202]);
102
103
        $transaction = new Transaction();
104
        $transaction->setName('banque à poste');
105
        $transaction->setRemarks('montants erronés');
106
        $transaction->setTransactionDate(Chronos::now());
107
        $line = new TransactionLine();
108
        $line->setTransaction($transaction);
109
110
        $lines = [
111
            [
112
                'balance' => Money::CHF(100000),
113
                'transactionDate' => Chronos::now(),
114
                'debit' => $debit,
115
            ],
116
            [
117
                'balance' => Money::CHF(90000),
118
                'credit' => $credit,
119
            ],
120
        ];
121
122
        $this->expectExceptionMessage('Transaction NEW non-équilibrée, débits: 1000.00, crédits: 900.00');
123
        $this->repository->hydrateLinesAndFlush($transaction, $lines);
124
    }
125
126
    public function testTriggers(): void
127
    {
128
        $account1 = 10096;
129
        $account2 = 10037;
130
131
        $this->assertAccountBalance($account1, 5000, 'initial balance');
132
        $this->assertAccountBalance($account2, 10000, 'initial balance');
133
134
        $connection = $this->getEntityManager()->getConnection();
135
        $count = $connection->delete('transaction', ['id' => 8000]);
136
137
        self::assertSame(1, $count);
138
        $this->assertAccountBalance($account1, 15000, 'balance should be increased after deletion');
139
        $this->assertAccountBalance($account2, 0, 'balance should be decreased after deletion');
140
    }
141
142
    public function testFlushWithFastTransactionLineTriggersWithTransaction(): void
143
    {
144
        $account1 = 10096;
145
        $account2 = 10037;
146
147
        $this->assertAccountBalance($account1, 5000, 'initial balance');
148
        $this->assertAccountBalance($account2, 10000, 'initial balance');
149
150
        // DELETE
151
        $this->setCurrentUser('administrator');
152
        $transaction = _em()->getReference(Transaction::class, 8000);
153
        $this->getEntityManager()->remove($transaction);
154
        $this->repository->flushWithFastTransactionLineTriggers();
155
156
        $this->assertAccountBalance($account1, 15000, 'balance should be increased after deletion');
157
        $this->assertAccountBalance($account2, 0, 'balance should be decreased after deletion');
158
    }
159
160
    public function testFlushWithFastTransactionLineTriggersWithTransactionLine(): void
161
    {
162
        $account1 = 10096;
163
        $account2 = 10037;
164
165
        $this->assertAccountBalance($account1, 5000, 'initial balance');
166
        $this->assertAccountBalance($account2, 10000, 'initial balance');
167
168
        // UPDATE
169
        $this->setCurrentUser('administrator');
170
        /** @var TransactionLine $transactionLine */
171
        $transactionLine = _em()->getReference(TransactionLine::class, 14000);
172
        $transactionLine->setBalance(Money::CHF(1));
173
        $this->repository->flushWithFastTransactionLineTriggers();
174
175
        $this->assertAccountBalance($account1, 14999, 'balance should be increased after update');
176
        $this->assertAccountBalance($account2, 1, 'balance should be decreased after update');
177
178
        // DELETE
179
        $this->getEntityManager()->remove($transactionLine);
180
        $this->repository->flushWithFastTransactionLineTriggers();
181
182
        $this->assertAccountBalance($account1, 15000, 'balance should be increased after deletion');
183
        $this->assertAccountBalance($account2, 0, 'balance should be decreased after deletion');
184
185
        // INSERT
186
        $transactionLine = new TransactionLine();
187
        $this->getEntityManager()->persist($transactionLine);
188
        $transactionLine->setBalance(Money::CHF(5));
189
        $transactionLine->setTransactionDate(Chronos::now());
190
        $transactionLine->setTransaction($this->getEntityManager()->getReference(Transaction::class, 8000));
191
        $transactionLine->setDebit($this->getEntityManager()->getReference(Account::class, $account1));
192
        $transactionLine->setCredit($this->getEntityManager()->getReference(Account::class, $account2));
193
194
        $this->repository->flushWithFastTransactionLineTriggers();
195
196
        $this->assertAccountBalance($account1, 14995, 'balance should be increased after insertion');
197
        $this->assertAccountBalance($account2, 5, 'balance should be decreased after insertion');
198
    }
199
}
200