Completed
Push — master ( 3ac846...67b859 )
by Adrien
07:43
created

Invoicer::invoicePeriodic()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 3
nop 1
dl 0
loc 25
ccs 15
cts 15
cp 1
crap 3
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Service;
6
7
use Application\Model\Account;
8
use Application\Model\Bookable;
9
use Application\Model\Booking;
10
use Application\Model\Transaction;
11
use Application\Model\TransactionLine;
12
use Application\Model\User;
13
use Application\Repository\BookingRepository;
14
use Cake\Chronos\Date;
15
use Doctrine\ORM\EntityManager;
16
17
/**
18
 * Service to create transactions for non-free booking, if needed, for all users or one user
19
 */
20
class Invoicer
21
{
22
    /**
23
     * @var EntityManager
24
     */
25
    private $entityManager;
26
27
    /**
28
     * @var int
29
     */
30
    private $count = 0;
31
32
    /**
33
     * @var BookingRepository
34
     */
35
    private $bookingRepository;
36
37 1
    public function __construct(EntityManager $entityManager)
38
    {
39 1
        $this->entityManager = $entityManager;
40 1
        $this->bookingRepository = $this->entityManager->getRepository(Booking::class);
41 1
    }
42
43 1
    public function invoicePeriodic(?User $user = null): int
44
    {
45 1
        $this->count = 0;
46 1
        $this->bookingRepository->getAclFilter()->setEnabled(false);
47 1
        $bookings = $this->bookingRepository->getAllToInvoice($user);
48
49 1
        $user = null;
50 1
        $bookingPerUser = [];
51
52
        /** @var Booking $booking */
53 1
        foreach ($bookings as $booking) {
54 1
            if ($user !== $booking->getOwner()) {
55 1
                $this->createTransaction($user, $bookingPerUser, false);
56
57 1
                $user = $booking->getOwner();
58 1
                $bookingPerUser = [];
59
            }
60
61 1
            $bookingPerUser[] = $booking;
62
        }
63 1
        $this->createTransaction($user, $bookingPerUser, false);
64
65 1
        $this->bookingRepository->getAclFilter()->setEnabled(true);
66
67 1
        return $this->count;
68
    }
69
70 6
    public function invoiceInitial(User $user, Booking $booking): void
71
    {
72 6
        $this->bookingRepository->getAclFilter()->setEnabled(false);
73
74 6
        $bookable = $booking->getBookable();
75 6
        if (!$bookable->getInitialPrice() && !$bookable->getPeriodicPrice()) {
76 1
            return;
77
        }
78
79 5
        $this->createTransaction($user, [$booking], true);
80 5
        $this->bookingRepository->getAclFilter()->setEnabled(true);
81 5
    }
82
83 6
    private function createTransaction(?User $user, array $bookings, bool $isInitial): void
84
    {
85 6
        if (!$user || !$bookings) {
86 1
            return;
87
        }
88
89 6
        $account = $this->entityManager->getRepository(Account::class)->getOrCreate($user);
90 6
        $transaction = new Transaction();
91 6
        $transaction->setTransactionDate(Date::today());
92 6
        $transaction->setName('Cotisation et services ' . Date::today()->format('Y'));
93 6
        $this->entityManager->persist($transaction);
94
95 6
        foreach ($bookings as $booking) {
96 6
            $bookable = $booking->getBookable();
97 6
            if ($isInitial) {
98 5
                $balance = $this->calculateInitialBalance($booking);
99 5
                $this->createTransactionLine($transaction, $bookable, $account, $balance, 'Paiement ponctuel');
100
            }
101
102 6
            $balance = $this->calculatePeriodicBalance($booking);
103 6
            $this->createTransactionLine($transaction, $bookable, $account, $balance, 'Paiement annuel');
104
        }
105
106 6
        ++$this->count;
107 6
    }
108
109
    /**
110
     * @param Booking $booking
111
     *
112
     * @return string
113
     */
114 5
    private function calculateInitialBalance(Booking $booking): string
115
    {
116 5
        $bookable = $booking->getBookable();
117
118
        // TODO: https://support.ecodev.ch/issues/6227
119
120 5
        return $bookable->getInitialPrice();
121
    }
122
123
    /**
124
     * @param Booking $booking
125
     *
126
     * @return string
127
     */
128 6
    private function calculatePeriodicBalance(Booking $booking): string
129
    {
130 6
        $bookable = $booking->getBookable();
131
132
        // TODO: https://support.ecodev.ch/issues/6227
133
134 6
        return $bookable->getPeriodicPrice();
135
    }
136
137 6
    private function createTransactionLine(Transaction $transaction, Bookable $bookable, Account $account, string $balance, string $name): void
138
    {
139 6
        if ($balance > 0) {
140 5
            $debit = $account;
141 5
            $credit = $bookable->getCreditAccount();
142 4
        } elseif ($balance < 0) {
143 1
            $debit = $bookable->getCreditAccount();
144 1
            $credit = $account;
145 1
            $balance = bcmul($balance, '-1'); // into positive
146
        } else {
147
            // Never create a line with 0 balance
148 3
            return;
149
        }
150
151 6
        $transactionLine = new TransactionLine();
152 6
        $this->entityManager->persist($transactionLine);
153
154 6
        $transactionLine->setName($name);
155 6
        $transactionLine->setBookable($bookable);
156 6
        $transactionLine->setDebit($debit);
157 6
        $transactionLine->setCredit($credit);
158 6
        $transactionLine->setBalance($balance);
159 6
        $transactionLine->setTransaction($transaction);
160 6
        $transactionLine->setTransactionDate(Date::today());
161 6
    }
162
}
163