Failed Conditions
Push — master ( a427b2...509ea4 )
by Adrien
16:44
created

Booking::getEstimatedEndDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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