Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.89% covered (warning)
85.89%
280 / 326
69.01% covered (warning)
69.01%
49 / 71
CRAP
0.00% covered (danger)
0.00%
0 / 1
Process
85.89% covered (warning)
85.89%
280 / 326
69.01% covered (warning)
69.01%
49 / 71
222.50
0.00% covered (danger)
0.00%
0 / 1
 getDefaults
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
 createFromScope
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 getRequests
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 getRequestIds
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDisplayNumber
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRequestCSV
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addScope
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addQueue
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 addRequests
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 updateRequests
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 hasScopeAdmin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sendAdminMailOnConfirmation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 sendAdminMailOnDeleted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 sendAdminMailOnUpdated
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 shouldSendAdminMailOnClerkMail
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 withUpdatedData
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 addAppointmentFromRequest
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 addClientFromForm
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
 setStatus
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getReminderTimestamp
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 addReminderTimestamp
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getAppointments
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 getClients
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
4.07
 hasAppointment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isWithAppointment
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 hasProcessCredentials
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
4
 withReassignedCredentials
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 hasQueueNumber
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
 getQueueNumber
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addAppointment
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getScopeId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCurrentScope
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAmendment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getShowUpTime
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getWaitingTime
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getProcessingTime
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFinishTime
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addAmendment
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getCustomTextfield
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addCustomTextfield
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getCustomTextfield2
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addCustomTextfield2
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 addPriority
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 getAuthKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPriority
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setRandomAuthKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setCallTime
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 getCallTimeString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCallTime
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getFirstClient
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getFirstAppointment
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 setStatusBySettings
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
5.03
 setClientsCount
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 withoutPersonalData
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 withLessData
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
1 / 1
20
 toCalendar
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 toQueue
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
6.02
 hasArrivalTime
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getArrivalTime
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
4.32
 setArrivalTime
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getWaitedSeconds
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getWaitedMinutes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getWaySeconds
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getWayMinutes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setWasMissed
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getWasMissed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 toDerefencedAmendment
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 toDerefencedCustomTextfield
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 toDerefencedCustomTextfield2
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 __toString
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3namespace BO\Zmsentities;
4
5use BO\Zmsentities\Helper\Property;
6
7/**
8 * @SuppressWarnings(Complexity)
9 * @SuppressWarnings(Coupling)
10 * @SuppressWarnings(Public)
11 *
12 */
13class Process extends Schema\Entity
14{
15    public const PRIMARY = 'id';
16    public const STATUS_FREE = 'free';
17    public const STATUS_RESERVED = 'reserved';
18    public const STATUS_CONFIRMED = 'confirmed';
19    public const STATUS_PRECONFIRMED = 'preconfirmed';
20    public const STATUS_QUEUED = 'queued';
21    public const STATUS_CALLED = 'called';
22    public const STATUS_PROCESSING = 'processing';
23    public const STATUS_PENDING = 'pending';
24    public const STATUS_PICKUP = 'pickup';
25    public const STATUS_FINISHED = 'finished';
26    public const STATUS_MISSED = 'missed';
27    public const STATUS_PARKED = 'parked';
28    public const STATUS_ARCHIVED = 'archived';
29    public const STATUS_DELETED = 'deleted';
30    public const STATUS_ANONYMIZED = 'anonymized';
31    public const STATUS_BLOCKED = 'blocked';
32    public const STATUS_CONFLICT = 'conflict';
33    public static $schema = "process.json";
34    public function getDefaults()
35    {
36        return [
37            'amendment' => '',
38            'customTextfield' => '',
39            'customTextfield2' => '',
40            'appointments' => new Collection\AppointmentList(),
41            'apiclient' => new Apiclient(),
42            'authKey' => '',
43            'captchaToken' => '',
44            'clients' => new Collection\ClientList(),
45            'createIP' => '',
46            'createTimestamp' => time(),
47            'id' => 0,
48            'archiveId' => 0,
49            'queue' => new Queue(),
50            'reminderTimestamp' => 0,
51            'requests' => new Collection\RequestList(),
52            'scope' => new Scope(),
53            'status' => 'free',
54            'displayNumber' => '',
55            'dbstatus' => 'free',
56            'lastChange' => time(),
57            'wasMissed' => false,
58            'priority' => null,
59        ];
60    }
61
62    public static function createFromScope(Scope $scope, \DateTimeInterface $dateTime)
63    {
64        $appointment = new Appointment();
65        $appointment->addScope($scope->id);
66        $appointment->addSlotCount(0);
67        $appointment->addDate($dateTime->modify('00:00:00')->getTimestamp());
68        $process = new static();
69        $process->scope = $scope;
70        $process->setStatus('queued');
71        $process->addAppointment($appointment);
72        return $process;
73    }
74
75    /**
76     * @return Collection\RequestList
77     *
78     */
79    public function getRequests()
80    {
81        if (!$this->requests instanceof Collection\RequestList) {
82            $requestList = new Collection\RequestList();
83            foreach ($this->requests as $request) {
84                $request = ($request instanceof Request) ? $request : new Request($request);
85                $requestList->addEntity($request);
86            }
87            $this->requests = $requestList;
88        }
89        return $this->requests;
90    }
91
92    public function getRequestIds()
93    {
94        return $this->getRequests()->getIds();
95    }
96
97    public function getDisplayNumber()
98    {
99        return $this->displayNumber;
100    }
101
102    public function getRequestCSV()
103    {
104        return $this->getRequests()->getIdsCsv();
105    }
106
107    public function addScope($scopeId)
108    {
109        $this->scope = new Scope(array('id' => $scopeId));
110        return $this;
111    }
112
113    public function addQueue($number, \DateTimeInterface $dateTime)
114    {
115        $this->queue = new Queue(array(
116            'number' => $number,
117            'arrivalTime' => $dateTime->getTimestamp(),
118            'priority' => $this->getPriority()
119        ));
120        return $this;
121    }
122
123    public function addRequests($source, $requestCSV)
124    {
125        $requestList = $this->getRequests();
126        foreach (explode(',', $requestCSV) as $id) {
127            if (!$requestList->hasRequests($id)) {
128                $this->requests[] = new Request(array(
129                    'source' => $source,
130                    'id' => $id
131                ));
132            }
133        }
134        return $this;
135    }
136
137    public function updateRequests($source, $requestCSV = '')
138    {
139        $this->requests = new Collection\RequestList();
140        if ($requestCSV) {
141            foreach (explode(',', $requestCSV) as $id) {
142                $this->requests->addEntity(new Request(array(
143                            'source' => $source,
144                            'id' => $id
145                        )));
146            }
147        }
148        return $this;
149    }
150
151    public function hasScopeAdmin()
152    {
153        return ('' != $this->toProperty()->scope->contact->email->get());
154    }
155
156    public function sendAdminMailOnConfirmation()
157    {
158        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnAppointment->get());
159    }
160
161    public function sendAdminMailOnDeleted()
162    {
163        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnDeleted->get());
164    }
165
166    public function sendAdminMailOnUpdated()
167    {
168        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnUpdated->get());
169    }
170
171    public function shouldSendAdminMailOnClerkMail()
172    {
173        return (bool) ((int) $this->toProperty()->scope->preferences->client->adminMailOnMailSent->get());
174    }
175
176    public function withUpdatedData($requestData, \DateTimeInterface $dateTime, $scope = null, $notice = '')
177    {
178        $this->scope = ($scope) ? $scope : $this->scope;
179        $this->addAppointmentFromRequest($requestData, $dateTime);
180        $requestCsv = isset($requestData['requests']) ? implode(',', $requestData['requests']) : 0;
181        $this->updateRequests($scope->getSource(), $requestCsv);
182        $this->addClientFromForm($requestData);
183        $this->addReminderTimestamp($requestData, $dateTime);
184        $this->addAmendment($requestData, $notice);
185        $this->addCustomTextfield($requestData);
186        $this->addCustomTextfield2($requestData);
187        $this->addPriority($requestData);
188        return $this;
189    }
190
191    public function addAppointmentFromRequest($requestData, \DateTimeInterface $dateTime)
192    {
193        $this->appointments = null;
194        if (isset($requestData['selecteddate'])) {
195            $dateTime = new \DateTime($requestData['selecteddate']);
196        }
197        if (isset($requestData['selectedtime'])) {
198            $time = explode('-', $requestData['selectedtime']);
199            $dateTime->setTime($time[0], $time[1]);
200        }
201
202        $appointment = (new Appointment())
203            ->addDate($dateTime->getTimestamp())
204            ->addScope($this->scope['id']);
205        if (isset($requestData['slotCount'])) {
206            $appointment->addSlotCount($requestData['slotCount']);
207        }
208        $this->addAppointment($appointment);
209        return $this;
210    }
211
212    public function addClientFromForm($requestData)
213    {
214        $client = new Client();
215        foreach ($requestData as $key => $value) {
216            if (null !== $value && $client->offsetExists($key)) {
217                $client[$key] = (isset($value['value'])) ? $value['value'] : $value;
218            }
219        }
220        $this->clients = array();
221        $this->clients[] = $client;
222        return $this;
223    }
224
225    public function setStatus($status)
226    {
227        $this->status = $status;
228        return $this;
229    }
230
231    public function getStatus()
232    {
233        return $this->status;
234    }
235
236    public function getReminderTimestamp()
237    {
238        $timestamp = $this->toProperty()->reminderTimestamp->get();
239        return ($timestamp) ? $timestamp : 0;
240    }
241
242    public function addReminderTimestamp($input, \DateTimeInterface $dateTime)
243    {
244        $this->reminderTimestamp = (
245            Property::__keyExists('headsUpTime', $input) &&
246            $input['headsUpTime'] > 0
247        ) ? $dateTime->getTimestamp() - $input['headsUpTime'] : 0;
248        return $this;
249    }
250
251    /**
252     * @return \BO\Zmsentities\Collection\AppointmentList
253     *
254     */
255    public function getAppointments()
256    {
257        if (!$this['appointments'] instanceof Collection\AppointmentList) {
258            $this['appointments'] = new Collection\AppointmentList($this['appointments']);
259            foreach ($this['appointments'] as $index => $appointment) {
260                if (!$appointment instanceof Appointment) {
261                    $this['appointments'][$index] = new Appointment($appointment);
262                }
263            }
264        }
265        return $this['appointments'];
266    }
267
268    /**
269     * @return \BO\Zmsentities\Collection\ClientList
270     *
271     */
272    public function getClients()
273    {
274        if (!$this['clients'] instanceof Collection\ClientList) {
275            $this['clients'] = new Collection\ClientList($this['clients']);
276            foreach ($this['clients'] as $index => $client) {
277                if (!$client instanceof Client) {
278                    $this['clients'][$index] = new Client($client);
279                }
280            }
281        }
282        return $this['clients'];
283    }
284
285    public function hasAppointment($date, $scopeId)
286    {
287        return $this->getAppointments()->hasDateScope($date, $scopeId);
288    }
289
290    /**
291     * check if process is with appointment and not only queued
292     * return Boolean
293     */
294    public function isWithAppointment()
295    {
296        $appointment = $this->getFirstAppointment();
297        if ($appointment->hasTime()) {
298            return true;
299        }
300        return (1 == $this->toProperty()->queue->withAppointment->get());
301    }
302
303    public function hasProcessCredentials()
304    {
305        return (isset($this['id']) && isset($this['authKey']) && $this['id'] && $this['authKey']);
306    }
307
308    public function withReassignedCredentials($process)
309    {
310        $this->id = $process->getId();
311        $this->authKey = $process->getAuthKey();
312        return $this;
313    }
314
315    public function hasQueueNumber()
316    {
317        return (isset($this['queue']) && isset($this['queue']['number']) && $this['queue']['number']);
318    }
319
320    public function getQueueNumber()
321    {
322        return $this['queue']['number'];
323    }
324
325    public function addAppointment(Appointment $newappointment)
326    {
327        $this->appointments[] = $newappointment;
328        return $this;
329    }
330
331    /**
332     * Reminder: A process might have multiple scopes. Each appointment can
333     * have his own scope. The scope in $this->scope is the current/next scope.
334     * This function returns the original scope ID and ignores internal scope
335     * which are used for processing like to pick up documents
336     *
337     */
338    public function getScopeId()
339    {
340        //TK 2020-09-28 changed because pickup and pending processes have assigned pickup scope
341        //as current scope - see zmsdb Query/Process EntityMapping
342        return $this->toProperty()->scope->id->get();
343    }
344
345    public function getCurrentScope(): Scope
346    {
347        return $this->getProperty('scope');
348    }
349
350    public function getAmendment()
351    {
352        return $this->toProperty()->amendment->get();
353    }
354
355    /*public function getShowUpTime()
356    {
357        return $this->toProperty()->showUpTime->get();
358    }*/
359
360    public function getShowUpTime($default = 'now', $timezone = null)
361    {
362        $showUpTime = $this->toProperty()->showUpTime->get();
363        $showDateTime = Helper\DateTime::create($default, $timezone);
364        if ($showUpTime) {
365            list($hours, $minutes, $seconds) = explode(':', $showUpTime);
366            $showDateTime = $showDateTime->setTime(intval($hours), intval($minutes), intval($seconds));
367        }
368        return $showDateTime;
369    }
370
371    public function getWaitingTime()
372    {
373        return $this->toProperty()->queue->waitingTime->get();
374    }
375
376    public function getProcessingTime()
377    {
378        return $this->toProperty()->processingTime->get();
379    }
380
381    public function getFinishTime()
382    {
383        return $this->toProperty()->finishTime->get();
384    }
385
386    public function addAmendment($input, $notice = '')
387    {
388        $this->amendment = $notice;
389        $this->amendment .= (isset($input['amendment']) && $input['amendment']) ? $input['amendment'] : '';
390        trim($this->amendment);
391        return $this;
392    }
393
394    public function getCustomTextfield()
395    {
396        return $this->toProperty()->customTextfield->get();
397    }
398
399    public function addCustomTextfield($input)
400    {
401        $this->customTextfield .= (
402            isset($input['customTextfield']) && $input['customTextfield']
403        ) ? $input['customTextfield'] : '';
404        trim($this->customTextfield);
405        return $this;
406    }
407
408    public function getCustomTextfield2()
409    {
410        return $this->toProperty()->customTextfield2->get();
411    }
412
413    public function addCustomTextfield2($input)
414    {
415        $this->customTextfield2 .= (
416            isset($input['customTextfield2']) && $input['customTextfield2']
417        ) ? $input['customTextfield2'] : '';
418        trim($this->customTextfield2);
419        return $this;
420    }
421
422    public function addPriority($input)
423    {
424        $this->priority = isset($input['priority']) && $input['priority'] ? $input['priority'] : null;
425
426        return $this;
427    }
428
429    public function getAuthKey()
430    {
431        return $this->toProperty()->authKey->get();
432    }
433
434    public function getPriority()
435    {
436        return (int) $this->toProperty()->priority->get();
437    }
438
439    public function setRandomAuthKey()
440    {
441        $this->authKey = substr(md5(rand()), 0, 4);
442    }
443
444    public function setCallTime($dateTime = null)
445    {
446        $this->queue['callTime'] = ($dateTime) ? $dateTime->getTimestamp() : 0;
447        return $this;
448    }
449
450    public function getCallTimeString()
451    {
452        return $this->getCallTime()->format('H:i:s');
453    }
454
455    public function getCallTime($default = 'now', $timezone = null)
456    {
457        $callTime = $this->toProperty()->queue->callTime->get();
458        $callDateTime = Helper\DateTime::create($default, $timezone);
459        if ($callTime) {
460            $callDateTime = $callDateTime->setTimestamp($callTime);
461        }
462        return $callDateTime;
463    }
464
465    public function getFirstClient()
466    {
467        $client = $this->getClients()->getFirst();
468        if (!$client) {
469            $client = new Client();
470            $this->clients->addEntity($client);
471        }
472        return $client;
473    }
474
475    public function getFirstAppointment(): Appointment
476    {
477        $appointment = $this->getAppointments()->getFirst();
478        if (!$appointment) {
479            $appointment = new Appointment();
480            $appointment->scope = $this->scope;
481            $this->appointments->addEntity($appointment);
482        }
483        return $appointment;
484    }
485
486    public function setStatusBySettings()
487    {
488        $scope = new Scope($this->scope);
489        if ('called' == $this->status && $this->queue['callCount'] > $scope->getPreference('queue', 'callCountMax')) {
490            $this->status = 'missed';
491        } elseif ('parked' == $this->status) {
492            $this->status = 'parked';
493        } elseif ('pickup' == $this->status) {
494            $this->status = 'queued';
495        } else {
496            $this->status = 'confirmed';
497        }
498        return $this;
499    }
500
501    public function setClientsCount($count)
502    {
503        $clientList = $this->getClients();
504        while ($clientList->count() < $count) {
505            $clientList->addEntity(new Client());
506        }
507        return $this;
508    }
509
510
511    public function withoutPersonalData()
512    {
513        $entity = clone $this;
514        if ($this->toProperty()->clients->isAvailable()) {
515            $client = $entity->getFirstClient();
516            unset($client['familyName']);
517            unset($client['email']);
518        }
519        return $entity;
520    }
521
522    /**
523     * Reduce data of dereferenced entities to a required minimum
524     *
525     */
526    public function withLessData(array $keepArray = [])
527    {
528        $entity = clone $this;
529        if (!in_array('availability', $keepArray)) {
530            foreach ($entity['appointments'] as $appointment) {
531                if ($appointment->toProperty()->scope->isAvailable()) {
532                    $scopeId = $appointment['scope']['id'];
533                    $appointment['scope'] = [
534                        'id' => $scopeId,
535                        'provider' => $appointment['scope']['provider'] ?? [],
536                        'shortName' => $appointment['scope']['shortName'] ?? ''
537                    ];
538                }
539                if ($appointment->toProperty()->availability->isAvailable()) {
540                    unset($appointment['availability']);
541                }
542            }
543        }
544
545        unset($entity['createTimestamp']);
546        unset($entity['createIP']);
547        if ($entity->toProperty()->scope->status->isAvailable()) {
548            unset($entity['scope']['status']);
549        }
550
551        if ($entity->status == 'free') {
552// delete keys
553            foreach (['authKey', 'queue', 'requests',] as $key) {
554                if (!in_array($key, $keepArray) && $entity->toProperty()->$key->isAvailable()) {
555                    unset($entity[$key]);
556                }
557            }
558            // delete if empty
559            foreach (['amendment', 'id', 'authKey', 'archiveId', 'reminderTimestamp',] as $key) {
560                if (!in_array($key, $keepArray) && $entity->toProperty()->$key->isAvailable() && !$entity[$key]) {
561                    unset($entity[$key]);
562                }
563            }
564            if (!in_array('provider', $keepArray) && $entity->toProperty()->scope->provider->data->isAvailable()) {
565                unset($entity['scope']['provider']['data']);
566            }
567        }
568
569        if (!in_array('dayoff', $keepArray) && $entity->toProperty()->scope->dayoff->isAvailable()) {
570            unset($entity['scope']['dayoff']);
571        }
572        if (!in_array('scope', $keepArray) && $entity->toProperty()->scope->preferences->isAvailable()) {
573            unset($entity['scope']['preferences']);
574        }
575        return $entity;
576    }
577
578    public function toCalendar()
579    {
580        $calendar = new Calendar();
581        $dateTime = $this->getFirstAppointment()->toDateTime();
582        $day = new Day();
583        $day->setDateTime($dateTime);
584        $calendar->firstDay = $day;
585        $calendar->lastDay = $day;
586        $calendar->requests = clone $this->getRequests();
587        $calendar->scopes = new Collection\ScopeList([$this->scope]);
588        return $calendar;
589    }
590
591    public function toQueue(\DateTimeInterface $dateTime)
592    {
593        $queue = new Queue($this->queue);
594        $queue->withAppointment = ($this->getFirstAppointment()->hasTime()) ? true : false;
595        $queue->waitingTime = ($queue->waitingTime) ? $queue->waitingTime : 0;
596        $queue->wayTime = ($queue->wayTime) ? $queue->wayTime : 0;
597        if ($queue->withAppointment) {
598            $queue->number = !empty($this->getDisplayNumber())
599                ? $this->getDisplayNumber()
600                : $this->id;
601        } else {
602            $queue->number = $this->toProperty()->queue->number->get();
603        }
604        $queue->displayNumber = $this->getDisplayNumber();
605        $queue->arrivalTime = $this->getArrivalTime($dateTime)->getTimestamp();
606        $queue->priority = $this->priority;
607        return $queue->setProcess($this);
608    }
609
610    public function hasArrivalTime()
611    {
612        $arrivalTime = 0;
613        if ($this->isWithAppointment()) {
614            $arrivalTime = $this->getFirstAppointment()->date;
615        } else {
616            $arrivalTime = $this->toProperty()->queue->arrivalTime->get();
617        }
618        return ($arrivalTime) ? true : false;
619    }
620
621    public function getArrivalTime($default = 'now', $timezone = null)
622    {
623        $queueArrivalTime = $this->toProperty()->queue->arrivalTime->get();
624
625        if ($queueArrivalTime) {
626            // Falls der Queue-Wert vorhanden ist â€“ auch wenn ein Termin existiert â€“ verwende diesen (dabei ist handelt es sich, um verpasste Termine)
627            $arrivalTime = $queueArrivalTime;
628        } elseif ($this->isWithAppointment()) {
629            $arrivalTime = $this->getFirstAppointment()->date;
630        } else {
631            $arrivalTime = 0;
632        }
633
634        $arrivalTime = (int)$arrivalTime;
635        $arrivalDateTime = Helper\DateTime::create($default, $timezone);
636        if ($arrivalTime) {
637            $arrivalDateTime = $arrivalDateTime->setTimestamp($arrivalTime);
638        }
639        return $arrivalDateTime;
640    }
641
642    public function setArrivalTime(\DateTimeInterface $dateTime = null)
643    {
644        $this->queue['arrivalTime'] = ($dateTime) ? $dateTime->getTimestamp() : 0;
645        return $this;
646    }
647
648    /**
649     * Calculate real waiting time, only available after called
650     */
651    public function getWaitedSeconds($defaultTime = 'now')
652    {
653        return $this->getCallTime($defaultTime)->getTimestamp() - $this->getArrivalTime($defaultTime)->getTimestamp();
654    }
655
656    public function getWaitedMinutes($defaultTime = 'now')
657    {
658        return $this->getWaitedSeconds($defaultTime) / 60;
659    }
660
661    public function getWaySeconds($defaultTime = 'now')
662    {
663        return $this->getShowUpTime($defaultTime)->getTimestamp() - $this->getCallTime($defaultTime)->getTimestamp();
664    }
665
666    public function getWayMinutes($defaultTime = 'now')
667    {
668        return $this->getWaySeconds($defaultTime) / 60;
669    }
670
671    public function setWasMissed(bool $bool)
672    {
673        $this->wasMissed = $bool;
674        $this->status = self::STATUS_MISSED;
675        return $this;
676    }
677
678    public function getWasMissed(): bool
679    {
680        return (bool) $this->wasMissed;
681    }
682
683    public function toDerefencedAmendment()
684    {
685        $lastChange = (new \DateTimeImmutable())->setTimestamp($this->createTimestamp)->format('c');
686        return var_export(array(
687                'BuergerID' => $this->id,
688                'StandortID' => $this->scope['id'],
689                'Anmerkung' => null,
690                'IPTimeStamp' => $this->createTimestamp,
691                'LastChange' => $lastChange,
692            ), 1);
693    }
694
695    public function toDerefencedCustomTextfield()
696    {
697        $lastChange = (new \DateTimeImmutable())->setTimestamp($this->createTimestamp)->format('c');
698        return var_export(array(
699                'BuergerID' => $this->id,
700                'StandortID' => $this->scope['id'],
701                'CustomTextfield' => null,
702                'IPTimeStamp' => $this->createTimestamp,
703                'LastChange' => $lastChange,
704            ), 1);
705    }
706
707    public function toDerefencedCustomTextfield2()
708    {
709        $lastChange = (new \DateTimeImmutable())->setTimestamp($this->createTimestamp)->format('c');
710        return var_export(array(
711                'BuergerID' => $this->id,
712                'StandortID' => $this->scope['id'],
713                'CustomTextfield2' => null,
714                'IPTimeStamp' => $this->createTimestamp,
715                'LastChange' => $lastChange,
716            ), 1);
717    }
718
719    public function __toString()
720    {
721        $string = "process#";
722        $string .= $this->getDisplayNumber() ?: $this->id ?: $this->archiveId;
723        $string .= ":" . $this->authKey;
724        $string .= " (" . $this->status . ")";
725        $string .= " " . $this->getFirstAppointment()->toDateTime()->format('c');
726        $string .= " " . ($this->isWithAppointment() ? "appoint" : "arrival:" . $this->getArrivalTime()->format('c'));
727        $string .= " " . $this->getFirstAppointment()->slotCount . "slots";
728        $string .= "*" . count($this->appointments);
729        foreach ($this->getRequests() as $request) {
730            $string .= " " . $request['source'] . "." . $request['id'];
731        }
732        $string .= " scope." . $this['scope']['id'];
733        $string .= " ~" . base_convert($this['lastChange'], 10, 35);
734        $string .= " client:" . $this['apiclient']['shortname'];
735        $string .= " token:" . ($this['captchaToken'] ?? '(none)');
736        return $string;
737    }
738}