Failed Conditions
Push — master ( 8e0455...8a9c79 )
by Sam
07:46
created

Booking::terminate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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