Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
40 / 40 |
|
100.00% |
12 / 12 |
CRAP | |
100.00% |
1 / 1 |
Shift | |
100.00% |
40 / 40 |
|
100.00% |
12 / 12 |
23 | |
100.00% |
1 / 1 |
neededAngelTypes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
schedule | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
scheduleShift | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
shiftEntries | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
shiftType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
location | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
createdBy | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
updatedBy | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
nextShift | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
previousShift | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
isNightShift | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
9 | |||
getNightShiftMultiplier | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Engelsystem\Models\Shifts; |
6 | |
7 | use Carbon\Carbon; |
8 | use Engelsystem\Models\BaseModel; |
9 | use Engelsystem\Models\Location; |
10 | use Engelsystem\Models\User\User; |
11 | use Illuminate\Database\Eloquent\Collection; |
12 | use Illuminate\Database\Eloquent\Factories\HasFactory; |
13 | use Illuminate\Database\Eloquent\Relations\BelongsTo; |
14 | use Illuminate\Database\Eloquent\Relations\HasMany; |
15 | use Illuminate\Database\Eloquent\Relations\HasOne; |
16 | use Illuminate\Database\Eloquent\Relations\HasOneThrough; |
17 | use Illuminate\Database\Query\Builder as QueryBuilder; |
18 | |
19 | /** |
20 | * @property int $id |
21 | * @property string $title |
22 | * @property string $description |
23 | * @property string $url |
24 | * @property Carbon $start |
25 | * @property Carbon $end |
26 | * @property int $shift_type_id |
27 | * @property int $location_id |
28 | * @property string|null $transaction_id |
29 | * @property int $created_by |
30 | * @property int|null $updated_by |
31 | * @property Carbon|null $created_at |
32 | * @property Carbon|null $updated_at |
33 | * |
34 | * @property-read Collection|NeededAngelType[] $neededAngelTypes |
35 | * @property-read Schedule $schedule |
36 | * @property-read ScheduleShift $scheduleShift |
37 | * @property-read Collection|ShiftEntry[] $shiftEntries |
38 | * @property-read ShiftType $shiftType |
39 | * @property-read Location $location |
40 | * @property-read User $createdBy |
41 | * @property-read User|null $updatedBy |
42 | * |
43 | * @method static QueryBuilder|Shift[] whereId($value) |
44 | * @method static QueryBuilder|Shift[] whereTitle($value) |
45 | * @method static QueryBuilder|Shift[] whereDescription($value) |
46 | * @method static QueryBuilder|Shift[] whereUrl($value) |
47 | * @method static QueryBuilder|Shift[] whereStart($value) |
48 | * @method static QueryBuilder|Shift[] whereEnd($value) |
49 | * @method static QueryBuilder|Shift[] whereShiftTypeId($value) |
50 | * @method static QueryBuilder|Shift[] whereLocationId($value) |
51 | * @method static QueryBuilder|Shift[] whereTransactionId($value) |
52 | * @method static QueryBuilder|Shift[] whereCreatedBy($value) |
53 | * @method static QueryBuilder|Shift[] whereUpdatedBy($value) |
54 | * @method static QueryBuilder|Shift[] whereCreatedAt($value) |
55 | * @method static QueryBuilder|Shift[] whereUpdatedAt($value) |
56 | */ |
57 | class Shift extends BaseModel |
58 | { |
59 | use HasFactory; |
60 | |
61 | /** @var array<string, string|null> default attributes */ |
62 | protected $attributes = [ // phpcs:ignore |
63 | 'description' => '', |
64 | 'url' => '', |
65 | 'transaction_id' => null, |
66 | 'updated_by' => null, |
67 | ]; |
68 | |
69 | /** @var bool enable timestamps */ |
70 | public $timestamps = true; // phpcs:ignore |
71 | |
72 | /** @var array<string, string> */ |
73 | protected $casts = [ // phpcs:ignore |
74 | 'shift_type_id' => 'integer', |
75 | 'location_id' => 'integer', |
76 | 'created_by' => 'integer', |
77 | 'updated_by' => 'integer', |
78 | 'start' => 'datetime', |
79 | 'end' => 'datetime', |
80 | ]; |
81 | |
82 | /** @var array<string> Values that are mass assignable */ |
83 | protected $fillable = [ // phpcs:ignore |
84 | 'title', |
85 | 'description', |
86 | 'url', |
87 | 'start', |
88 | 'end', |
89 | 'shift_type_id', |
90 | 'location_id', |
91 | 'transaction_id', |
92 | 'created_by', |
93 | 'updated_by', |
94 | ]; |
95 | |
96 | public function neededAngelTypes(): HasMany |
97 | { |
98 | return $this->hasMany(NeededAngelType::class); |
99 | } |
100 | |
101 | public function schedule(): HasOneThrough |
102 | { |
103 | return $this->hasOneThrough(Schedule::class, ScheduleShift::class, null, 'id', null, 'schedule_id'); |
104 | } |
105 | |
106 | public function scheduleShift(): HasOne |
107 | { |
108 | return $this->hasOne(ScheduleShift::class); |
109 | } |
110 | |
111 | public function shiftEntries(): HasMany |
112 | { |
113 | return $this->hasMany(ShiftEntry::class); |
114 | } |
115 | |
116 | public function shiftType(): BelongsTo |
117 | { |
118 | return $this->belongsTo(ShiftType::class); |
119 | } |
120 | |
121 | public function location(): BelongsTo |
122 | { |
123 | return $this->belongsTo(Location::class); |
124 | } |
125 | |
126 | public function createdBy(): BelongsTo |
127 | { |
128 | return $this->belongsTo(User::class, 'created_by'); |
129 | } |
130 | |
131 | public function updatedBy(): BelongsTo |
132 | { |
133 | return $this->belongsTo(User::class, 'updated_by'); |
134 | } |
135 | |
136 | /** |
137 | * get next shift with same shift type and location |
138 | */ |
139 | public function nextShift(): Shift|null |
140 | { |
141 | $query = Shift::query(); |
142 | if (Shift::whereTitle($this->title)->where('start', '>', $this->start)->exists()) { |
143 | $query = $query->where('title', $this->title); |
144 | } |
145 | return $query |
146 | ->where('shift_type_id', $this->shiftType->id) |
147 | ->where('location_id', $this->location->id) |
148 | ->where('start', '>', $this->start) |
149 | ->orderBy('start') |
150 | ->first(); |
151 | } |
152 | |
153 | /** |
154 | * get previous shift with same shift type and location |
155 | */ |
156 | public function previousShift(): Shift|null |
157 | { |
158 | $query = Shift::query(); |
159 | if (Shift::whereTitle($this->title)->where('end', '<', $this->end)->exists()) { |
160 | $query = $query->where('title', $this->title); |
161 | } |
162 | return $query |
163 | ->where('shift_type_id', $this->shiftType->id) |
164 | ->where('location_id', $this->location->id) |
165 | ->where('end', '<', $this->end) |
166 | ->orderBy('end', 'desc') |
167 | ->first(); |
168 | } |
169 | |
170 | /** |
171 | * Check if the shift is a night shift |
172 | */ |
173 | public function isNightShift(): bool |
174 | { |
175 | $config = config('night_shifts'); |
176 | |
177 | /** @see \Engelsystem\Helpers\Goodie::shiftScoreQuery to keep them in sync */ |
178 | return $config['enabled'] && ( |
179 | // Starts during night |
180 | $this->start->hour >= $config['start'] && $this->start->hour < $config['end'] |
181 | // Ends during night |
182 | || ( |
183 | $this->end->hour > $config['start'] |
184 | || $this->end->hour == $config['start'] && $this->end->minute > 0 |
185 | ) && $this->end->hour <= $config['end'] |
186 | // Starts before and ends after night |
187 | || $this->start->hour <= $config['start'] && $this->end->hour >= $config['end'] |
188 | ); |
189 | } |
190 | |
191 | /** |
192 | * Calculate the shifts night multiplier |
193 | */ |
194 | public function getNightShiftMultiplier(): float |
195 | { |
196 | if (!$this->isNightShift()) { |
197 | return 1; |
198 | } |
199 | |
200 | return config('night_shifts')['multiplier']; |
201 | } |
202 | } |