Failed Conditions
Push — master ( cf8a07...08b179 )
by Adrien
11:32
created

Booking   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 254
Duplicated Lines 0 %

Test Coverage

Coverage 84.81%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 56
dl 0
loc 254
ccs 67
cts 79
cp 0.8481
rs 9.84
c 1
b 0
f 0
wmc 32

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getParticipantCount() 0 3 1
A __construct() 0 2 1
A setOwner() 0 13 3
A getStatus() 0 3 1
A setEstimatedEndDate() 0 3 1
A getEndDate() 0 3 1
A setEndDate() 0 3 1
A getBookable() 0 3 1
A getStartDate() 0 3 1
A terminate() 0 7 3
A getEndComment() 0 3 1
A setStatus() 0 4 1
A setParticipantCount() 0 3 1
A setEndComment() 0 3 1
A getEstimatedEndDate() 0 3 1
A getPeriodicPrice() 0 10 2
A setBookable() 0 13 3
A setStartComment() 0 3 1
A setDestination() 0 3 1
A setStartDate() 0 3 1
A getStartComment() 0 3 1
A getDestination() 0 3 1
A invoiceInitial() 0 11 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\DBAL\Types\BookingStatusType;
8
use Application\Service\Invoicer;
9
use Application\Traits\HasRemarks;
10
use Cake\Chronos\Chronos;
11
use Doctrine\ORM\Mapping as ORM;
12
use Ecodev\Felix\Model\Traits\HasInternalRemarks;
13
use GraphQL\Doctrine\Annotation as API;
14
use Money\Money;
15
16
/**
17
 * A booking linking a user and a bookable
18
 *
19
 * @ORM\Entity(repositoryClass="Application\Repository\BookingRepository")
20
 * @ORM\AssociationOverrides({
21
 *     @ORM\AssociationOverride(name="owner", inversedBy="bookings")
22
 * })
23
 * @API\Sorting({
24
 *     "Application\Api\Input\Sorting\Bookable"
25
 * })
26
 */
27
class Booking extends AbstractModel
28
{
29
    use HasRemarks;
30
    use HasInternalRemarks;
31
32
    /**
33
     * @var string
34
     *
35
     * @ORM\Column(type="BookingStatus", length=10, options={"default" = BookingStatusType::APPLICATION})
36
     */
37
    private $status = BookingStatusType::APPLICATION;
38
39
    /**
40
     * @var int
41
     * @ORM\Column(type="integer", options={"unsigned" = true, "default" = 1})
42
     */
43
    private $participantCount = 1;
44
45
    /**
46
     * @var string
47
     *
48
     * @ORM\Column(type="string", length=50, options={"default" = ""})
49
     */
50
    private $destination = '';
51
52
    /**
53
     * @var string
54
     *
55
     * @ORM\Column(type="text", length=65535, options={"default" = ""})
56
     */
57
    private $startComment = '';
58
59
    /**
60
     * @var string
61
     *
62
     * @ORM\Column(type="text", length=65535, options={"default" = ""})
63
     */
64
    private $endComment = '';
65
66
    /**
67
     * @var Chronos
68
     *
69
     * @ORM\Column(type="datetime")
70
     */
71
    private $startDate;
72
73
    /**
74
     * @var Chronos
75
     *
76
     * @ORM\Column(type="datetime", nullable=true)
77
     */
78
    private $endDate;
79
80
    /**
81
     * @var string
82
     *
83
     * @ORM\Column(type="string", length=50, options={"default" = ""})
84
     */
85
    private $estimatedEndDate = '';
86
87
    /**
88
     * @var null|Bookable
89
     *
90
     * @ORM\ManyToOne(targetEntity="Bookable", inversedBy="bookings")
91
     * @ORM\JoinColumns({
92
     *     @ORM\JoinColumn(onDelete="CASCADE")
93
     * })
94
     */
95
    private $bookable;
96
97
    /**
98
     * Constructor
99
     */
100 25
    public function __construct()
101
    {
102 25
    }
103
104 18
    public function setOwner(?User $owner = null): void
105
    {
106 18
        if ($this->getOwner()) {
107 4
            $this->getOwner()->bookingRemoved($this);
108
        }
109
110 18
        parent::setOwner($owner);
111
112 18
        if ($this->getOwner()) {
113 16
            $this->getOwner()->bookingAdded($this);
114
        }
115
116 18
        $this->invoiceInitial();
117 18
    }
118
119
    /**
120
     * Total count of participant, at least 1.
121
     */
122
    public function getParticipantCount(): int
123
    {
124
        return $this->participantCount;
125
    }
126
127 2
    public function setParticipantCount(int $participantCount): void
128
    {
129 2
        $this->participantCount = $participantCount;
130 2
    }
131
132
    public function getDestination(): string
133
    {
134
        return $this->destination;
135
    }
136
137 2
    public function setDestination(string $destination): void
138
    {
139 2
        $this->destination = $destination;
140 2
    }
141
142
    public function getStartComment(): string
143
    {
144
        return $this->startComment;
145
    }
146
147 2
    public function setStartComment(string $startComment): void
148
    {
149 2
        $this->startComment = $startComment;
150 2
    }
151
152
    public function getEndComment(): string
153
    {
154
        return $this->endComment;
155
    }
156
157 3
    public function setEndComment(string $endComment): void
158
    {
159 3
        $this->endComment = $endComment;
160 3
    }
161
162
    public function getStartDate(): Chronos
163
    {
164
        return $this->startDate;
165
    }
166
167 3
    public function setStartDate(Chronos $startDate): void
168
    {
169 3
        $this->startDate = $startDate;
170 3
    }
171
172 8
    public function getEndDate(): ?Chronos
173
    {
174 8
        return $this->endDate;
175
    }
176
177 6
    public function setEndDate(?Chronos $endDate): void
178
    {
179 6
        $this->endDate = $endDate;
180 6
    }
181
182
    public function getEstimatedEndDate(): string
183
    {
184
        return $this->estimatedEndDate;
185
    }
186
187 2
    public function setEstimatedEndDate(string $estimatedEndDate): void
188
    {
189 2
        $this->estimatedEndDate = $estimatedEndDate;
190 2
    }
191
192
    /**
193
     * Get bookable, may be null for "my own material" case
194
     */
195 45
    public function getBookable(): ?Bookable
196
    {
197 45
        return $this->bookable;
198
    }
199
200
    /**
201
     * Set bookable
202
     */
203 13
    public function setBookable(?Bookable $bookable): void
204
    {
205 13
        if ($this->bookable) {
206 1
            $this->bookable->bookingRemoved($this);
207
        }
208
209 13
        $this->bookable = $bookable;
210
211 13
        if ($this->bookable) {
212 13
            $this->bookable->bookingAdded($this);
213
        }
214
215 13
        $this->invoiceInitial();
216 13
    }
217
218
    /**
219
     * @API\Field(type="BookingStatus")
220
     */
221 10
    public function getStatus(): string
222
    {
223 10
        return $this->status;
224
    }
225
226
    /**
227
     * @API\Input(type="BookingStatus")
228
     */
229 10
    public function setStatus(string $status): void
230
    {
231 10
        $this->status = $status;
232 10
        $this->invoiceInitial();
233 10
    }
234
235
    /**
236
     * Mark the booking as terminated with an optional comment,
237
     * but only if not already terminated
238
     */
239 4
    public function terminate(?string $comment): void
240
    {
241
        // Booking can only be terminated once
242 4
        if (!$this->getEndDate()) {
243 4
            $this->setEndDate(new Chronos());
244 4
            if ($comment) {
245 1
                $this->setEndComment($comment);
246
            }
247
        }
248 4
    }
249
250
    /**
251
     * If the booking is complete, will make initial invoicing
252
     */
253 22
    private function invoiceInitial(): void
254
    {
255 22
        if (!$this->getOwner() || !$this->getBookable()) {
256 22
            return;
257
        }
258
259
        global $container;
260
261
        /** @var Invoicer $invoicer */
262 8
        $invoicer = $container->get(Invoicer::class);
263 8
        $invoicer->invoiceInitial($this->getOwner(), $this);
264 8
    }
265
266
    /**
267
     * Returns the next invoicable periodic price
268
     *
269
     * In case it uses shared admin_only bookables, the price is divided by the number of usages
270
     */
271 8
    public function getPeriodicPrice(): Money
272
    {
273 8
        $bookable = $this->getBookable();
274 8
        $bookings = $bookable->getPeriodicPriceDividerBookings();
275
276 8
        if (!$bookings) {
277 7
            return $bookable->getPeriodicPrice();
278
        }
279
280 2
        return $bookable->getPeriodicPrice()->divide(count($bookings));
281
    }
282
}
283