Completed
Push — master ( 1cdf46...d8c9d1 )
by Adrien
07:48
created

Booking::getEndDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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