Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.02% covered (warning)
89.02%
519 / 583
80.85% covered (warning)
80.85%
38 / 47
CRAP
0.00% covered (danger)
0.00%
0 / 1
Process
89.02% covered (warning)
89.02%
519 / 583
80.85% covered (warning)
80.85%
38 / 47
170.05
0.00% covered (danger)
0.00%
0 / 1
 getQueryNewProcessId
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getLockProcessId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addJoin
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 addJoinAvailability
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 addJoinScope
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 getEntityMapping
100.00% covered (success)
100.00%
62 / 62
100.00% covered (success)
100.00%
1 / 1
1
 addCountValue
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 addConditionHasTelephone
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 addConditionProcessDeleteInterval
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 addConditionProcessExpiredIPTimeStamp
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 addConditionProcessReminderInterval
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 addConditionProcessMailReminder
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
1 / 1
1
 addConditionProcessId
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 addConditionProcessIdFollow
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 addConditionIgnoreSlots
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 addConditionScopeId
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 addConditionQueueNumber
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 addConditionWorkstationId
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 addConditionTime
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addConditionTimeframe
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 addConditionAuthKey
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 addConditionAssigned
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addConditionStatus
97.18% covered (success)
97.18%
69 / 71
0.00% covered (danger)
0.00%
0 / 1
16
 addConditionIsReserved
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 addConditionSearch
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 addConditionName
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 addConditionMail
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
2.21
 addConditionCustomTextfield
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 addConditionAmendment
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 addConditionRequestId
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 addConditionDeallocate
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 addValuesNewProcess
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 addValuesUpdateProcess
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 addValuesIPAdress
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 addValuesFollowingProcessData
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 addValuesAppointmentData
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 addValuesScopeData
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 addValuesStatusData
87.50% covered (warning)
87.50%
28 / 32
0.00% covered (danger)
0.00%
0 / 1
14.38
 addValuesClientData
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
16
 addProcessingTimeData
30.43% covered (danger)
30.43%
14 / 46
0.00% covered (danger)
0.00%
0 / 1
79.98
 addValuesQueueData
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
11
 addValuesWaitingTimeData
62.50% covered (warning)
62.50%
10 / 16
0.00% covered (danger)
0.00%
0 / 1
17.38
 addValuesWayTimeData
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
3.58
 addValuesWasMissed
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 postProcess
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
7
 removeDuplicates
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addRequiredJoins
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsdb\Query;
4
5/**
6 * @SuppressWarnings(Methods)
7 * @SuppressWarnings(Complexity)
8 */
9class Process extends Base implements MappingInterface
10{
11    /**
12     *     * @var String TABLE mysql table reference
13     */
14    const TABLE = 'buerger';
15
16    const QUERY_DEREFERENCED = "UPDATE `buerger` process LEFT JOIN `standort` s USING(StandortID)
17        SET
18            process.Anmerkung = ?,
19            process.custom_text_field = ?,
20            process.StandortID = 0,
21            process.AbholortID = 0,
22            process.Abholer = 0,
23            process.Name = 'dereferenced',
24            process.IPadresse = '',
25            process.IPTimeStamp = 0,
26            process.NutzerID = 0,
27            process.vorlaeufigeBuchung = 0,
28            process.bestaetigt = 1,
29            process.absagecode = 'deref!0',
30            process.EMail = '',
31            process.NutzerID = 0
32        WHERE
33            (process.BuergerID = ? AND process.absagecode = ?)
34            OR process.istFolgeterminvon = ?
35        ";
36
37    const QUERY_CANCELED = "
38        UPDATE `buerger` process LEFT JOIN `standort` s USING(StandortID)
39            SET
40                process.Anmerkung = CONCAT(
41                    'Abgesagter Termin gebucht am: ',
42                    FROM_UNIXTIME(process.IPTimeStamp,'%d.%m.%Y, %H:%i'),' Uhr | ',
43                    IFNULL(process.Anmerkung,'')
44                ),              
45                process.Name = '(abgesagt)',
46                process.IPadresse = '',
47                process.IPTimeStamp = :canceledTimestamp + (IFNULL(s.loeschdauer, 15) * 60),
48                process.NutzerID = 0,
49                process.vorlaeufigeBuchung = 1,
50                process.absagecode = RIGHT(MD5(CONCAT(process.absagecode, 'QUERY_CANCELED')), 4)
51            WHERE
52                (process.BuergerID = :processId AND process.absagecode = :authKey)
53                OR process.istFolgeterminvon = :processId
54        ";
55
56    const QUERY_DELETE = "DELETE FROM `buerger`
57        WHERE
58            BuergerID = ?
59            OR istFolgeterminvon = ?
60        ";
61
62    const QUERY_REASSIGN_PROCESS_CREDENTIALS = "UPDATE `buerger` process
63       SET 
64            process.BuergerID = :newProcessId, 
65            process.absagecode = :newAuthKey
66        WHERE BuergerID = :processId
67    ";
68
69    const QUERY_REASSIGN_PROCESS_REQUESTS = "UPDATE `buergeranliegen` requests
70        SET 
71            requests.BuergerID = :newProcessId
72        WHERE BuergerID = :processId
73    ";
74
75    const QUERY_REASSIGN_FOLLWING_PROCESS = "UPDATE `buerger` process
76        SET process.istFolgeterminvon = :newProcessId
77        WHERE istFolgeterminvon = :processId
78    ";
79
80    const QUERY_UPDATE_FOLLOWING_PROCESS = "UPDATE buerger 
81        SET vorlaeufigeBuchung = :reserved 
82        WHERE istFolgeterminvon = :processID
83        ";
84
85    public function getQueryNewProcessId()
86    {
87        $random = rand(20, 999);
88        return 'SELECT pseq.processId AS `nextid`
89            FROM process_sequence pseq
90            WHERE pseq.processId = (
91                SELECT ps.processID FROM `process_sequence` ps LEFT JOIN `' . self::getTablename() . '` p
92                    ON ps.processId = p.BuergerID
93                WHERE p.`BuergerID` IS NULL
94                LIMIT ' . $random . ',1)
95            FOR UPDATE';
96    }
97
98    public function getLockProcessId()
99    {
100        return 'SELECT p.`BuergerID` FROM `' . self::getTablename() . '` p WHERE p.`BuergerID` = :processId FOR UPDATE';
101    }
102
103    public function addJoin()
104    {
105        return [
106            $this->addJoinAvailability(),
107            $this->addJoinScope(),
108        ];
109    }
110
111    /**
112     * Add Availability to the dataset
113     */
114    protected function addJoinAvailability()
115    {
116        $this->leftJoin(
117            new Alias(Availability::TABLE, 'availability'),
118            Availability::getJoinExpression('`process`', '`availability`')
119        );
120        $joinQuery = new Availability($this, $this->getPrefixed('appointments__0__availability__'));
121        return $joinQuery;
122    }
123
124    /**
125     * Add Scope to the dataset
126     */
127    protected function addJoinScope()
128    {
129        $this->leftJoin(
130            new Alias(Scope::TABLE, 'scope'),
131            self::expression(
132                'IF(`process`.`AbholortID`,
133                    `process`.`AbholortID`,
134                    `process`.`StandortID`
135                )'
136            ),
137            '=',
138            'scope.StandortID'
139        );
140        $joinQuery = new Scope($this, $this->getPrefixed('scope__'));
141        return $joinQuery;
142    }
143
144    public function getEntityMapping()
145    {
146        $status_expression = self::expression(
147            'CASE
148                WHEN process.Name = "(abgesagt)"
149                    THEN "deleted"
150                WHEN process.StandortID = 0 AND process.AbholortID = 0
151                    THEN "blocked"
152                WHEN process.vorlaeufigeBuchung = 1 AND process.bestaetigt = 0 
153                    THEN "reserved"
154                WHEN process.nicht_erschienen != 0
155                    THEN "missed"
156                WHEN process.parked != 0
157                    THEN "parked"
158                WHEN process.Abholer != 0 AND process.AbholortID != 0 AND process.NutzerID = 0
159                    THEN "pending"
160                WHEN process.AbholortID != 0 AND process.NutzerID != 0
161                    THEN "pickup"
162                WHEN process.AbholortID = 0 AND process.aufruferfolgreich != 0 AND process.NutzerID != 0
163                    THEN "processing"
164                WHEN process.aufrufzeit != "00:00:00" AND process.NutzerID != 0 AND process.AbholortID = 0
165                    THEN "called"
166                WHEN process.Uhrzeit = "00:00:00"
167                    THEN "queued"
168                WHEN process.vorlaeufigeBuchung = 0 AND process.bestaetigt = 0 
169                    THEN "preconfirmed"
170                WHEN process.vorlaeufigeBuchung = 0 AND process.bestaetigt = 1
171                    THEN "confirmed"
172                ELSE "free"
173            END'
174        );
175        return [
176            'amendment' => 'process.Anmerkung',
177            'id' => 'process.BuergerID',
178            'appointments__0__date' => self::expression(
179                'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)'
180            ),
181            'scope__id' => self::expression(
182                'IF(`process`.`AbholortID`,
183                    `process`.`AbholortID`,
184                    `process`.`StandortID`
185)'
186            ),
187            'appointments__0__scope__id' => 'process.StandortID',
188            // 'appointments__0__slotCount' => 'process.hatFolgetermine',
189            'appointments__0__slotCount' => self::expression('process.hatFolgetermine + 1'),
190            'authKey' => 'process.absagecode',
191            'clients__0__email' => 'process.EMail',
192            'clients__0__emailSendCount' => 'process.EMailverschickt',
193            'clients__0__familyName' => 'process.Name',
194            'clients__0__notificationsSendCount' => 'process.SMSverschickt',
195            'clients__0__surveyAccepted' => 'process.zustimmung_kundenbefragung',
196            'clients__0__telephone' => self::expression(
197                'IF(`process`.`telefonnummer_fuer_rueckfragen`!="",
198                    `process`.`telefonnummer_fuer_rueckfragen`,
199                    `process`.`Telefonnummer`
200                )'
201            ),
202            'customTextfield' => 'process.custom_text_field',
203            'createIP' => 'process.IPAdresse',
204            'createTimestamp' => 'process.IPTimeStamp',
205            'lastChange' => 'process.updateTimestamp',
206            'showUpTime' => 'process.showUpTime',
207            'processingTime' => 'process.processingTime',
208            'timeoutTime' => 'process.timeoutTime',
209            'finishTime' => 'process.finishTime',
210            'status' => $status_expression,
211            'queue__status' => $status_expression,
212            'queue__arrivalTime' => self::expression(
213                'CONCAT(
214                    `process`.`Datum`,
215                    " ",
216                    IF(`process`.`wsm_aufnahmezeit`, `process`.`wsm_aufnahmezeit`, `process`.`Uhrzeit`)
217                )'
218            ),
219            'queue__callCount' => 'process.AnzahlAufrufe',
220            'queue__callTime' => 'process.aufrufzeit',
221            'queue__lastCallTime' => 'process.Timestamp',
222            'queue__number' => self::expression(
223                'IF(`process`.`wartenummer`,
224                    `process`.`wartenummer`,
225                    `process`.`BuergerID`
226                )'
227            ),
228            'queue__destination' => self::expression(
229                'IF(`process`.`AbholortID`,
230                    `processscope`.`ausgabeschaltername`,
231                    `processuser`.`Arbeitsplatznr`
232)'
233            ),
234            'queue__destinationHint' => 'processuser.aufrufzusatz',
235            'queue__waitingTime' => 'process.wartezeit',
236            'queue__wayTime' => 'process.wegezeit',
237            'queue__withAppointment' => self::expression(
238                'IF(`process`.`wartenummer`,
239                    "0",
240                    "1"
241                )'
242            ),
243            'reminderTimestamp' => 'process.Erinnerungszeitpunkt',
244            '__clientsCount' => 'process.AnzahlPersonen',
245            'wasMissed' => 'process.wasMissed'
246        ];
247    }
248
249    public function addCountValue()
250    {
251        $this->query->select([
252            'processCount' => self::expression('COUNT(*)'),
253        ]);
254        return $this;
255    }
256
257    public function addConditionHasTelephone()
258    {
259        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) {
260            $condition
261                ->andWith('process.telefonnummer_fuer_rueckfragen', '!=', '')
262                ->orWith('process.Telefonnummer', '!=', '');
263        });
264        return $this;
265    }
266
267    public function addConditionProcessDeleteInterval(\DateTimeInterface $expirationDate)
268    {
269        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($expirationDate) {
270            $query->andWith(
271                self::expression(
272                    'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)'
273                ),
274                '<=',
275                $expirationDate->format('Y-m-d H:i:s')
276            );
277        });
278        $this->query->orderBy('appointments__0__date', 'ASC');
279        return $this;
280    }
281
282    public function addConditionProcessExpiredIPTimeStamp(\DateTimeInterface $expirationDate)
283    {
284        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($expirationDate) {
285            $query->andWith('process.IPTimeStamp', '<=', $expirationDate->getTimestamp());
286        });
287        $this->query->orderBy('appointments__0__date', 'ASC');
288        return $this;
289    }
290
291    public function addConditionProcessReminderInterval(\DateTimeInterface $dateTime)
292    {
293        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($dateTime) {
294            $query
295                ->andWith('process.Erinnerungszeitpunkt', '<=', $dateTime->getTimestamp())
296                ->andWith('process.Erinnerungszeitpunkt', '>=', $dateTime->modify("-5 Minutes")->getTimestamp());
297        });
298        $this->query->orderBy('reminderTimestamp', 'ASC');
299        return $this;
300    }
301
302    public function addConditionProcessMailReminder(
303        \DateTimeInterface $now,
304        \DateTimeInterface $lastRun,
305        $defaultReminderInMinutes
306    ) {
307        $this->query
308            ->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($now, $lastRun, $defaultReminderInMinutes) {
309                $query
310                    ->andWith(
311                        self::expression(
312                            'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)'
313                        ),
314                        '>',
315                        $lastRun->format('Y-m-d H:i:s')
316                    )
317                    ->andWith(
318                        self::expression(
319                            'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)'
320                        ),
321                        '>',
322                        $now->format('Y-m-d H:i:s')
323                    )
324                    ->andWith(
325                        'scopemail.send_reminder',
326                        '=',
327                        1
328                    )
329                    ->andWith(
330                        'process.EMail',
331                        '<>',
332                        ""
333                    )
334                    ->andWith(
335                        'process.EMailverschickt',
336                        '=',
337                        0
338                    )
339                    ->andWith(
340                        self::expression(
341                            'DATE_SUB(CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`), INTERVAL '
342                                . 'IFNULL(scopemail.send_reminder_minutes_before, ' . $defaultReminderInMinutes
343                                . ') MINUTE)'
344                        ),
345                        '<=',
346                        $now->format('Y-m-d H:i:s')
347                    );
348            });
349        $this->query->orderBy('appointments__0__date', 'ASC');
350        return $this;
351    }
352
353    public function addConditionProcessId($processId)
354    {
355        $this->query->where('process.BuergerID', '=', $processId);
356        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) {
357            $condition
358                ->andWith('process.istFolgeterminvon', 'IS', null)
359                ->orWith('process.istFolgeterminvon', '=', 0);
360        });
361        return $this;
362    }
363
364    public function addConditionProcessIdFollow($processId)
365    {
366        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) use ($processId) {
367            $condition
368                ->andWith('process.BuergerID', '=', $processId)
369                ->orWith('process.istFolgeterminvon', '=', $processId);
370        });
371        return $this;
372    }
373
374    public function addConditionIgnoreSlots()
375    {
376        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) {
377            $condition
378                ->andWith('process.istFolgeterminvon', 'IS', null)
379                ->orWith('process.istFolgeterminvon', '=', 0);
380        });
381        return $this;
382    }
383
384    public function addConditionScopeId($scopeId)
385    {
386        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($scopeId) {
387            $query
388                ->andWith('process.StandortID', '=', $scopeId)
389                ->orWith('process.AbholortID', '=', $scopeId);
390        });
391        return $this;
392    }
393
394    public function addConditionQueueNumber($queueNumber, $queueLimit = 10000)
395    {
396        ($queueLimit > $queueNumber)
397            ? $this->query->where('process.wartenummer', '=', $queueNumber)
398            : $this->query->where('process.BuergerID', '=', $queueNumber);
399        return $this;
400    }
401
402    public function addConditionWorkstationId($workstationId)
403    {
404        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($workstationId) {
405            $query->andWith('process.NutzerID', '=', $workstationId);
406            $query->andWith('process.StandortID', '>', 0);
407        });
408        return $this;
409    }
410
411    public function addConditionTime($dateTime)
412    {
413        $this->query->where('process.Datum', '=', $dateTime->format('Y-m-d'));
414        return $this;
415    }
416
417    /**
418     * Identify processes between two dates
419     */
420    public function addConditionTimeframe(\DateTimeInterface $startDate, \DateTimeInterface $endDate)
421    {
422        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) use ($startDate, $endDate) {
423            $condition
424                ->andWith('process.Datum', '<=', $endDate->format('Y-m-d'))
425                ->andWith('process.Datum', '>=', $startDate->format('Y-m-d'));
426        });
427        return $this;
428    }
429
430    public function addConditionAuthKey($authKey)
431    {
432        $authKey = urldecode($authKey);
433        $this->query
434            ->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) use ($authKey) {
435                $condition
436                    ->andWith('process.absagecode', '=', $authKey)
437                    ->orWith('process.Name', '=', $authKey);
438            });
439        return $this;
440    }
441
442    public function addConditionAssigned()
443    {
444        $this->query->where('process.StandortID', '!=', "0");
445        return $this;
446    }
447
448    public function addConditionStatus($status, $scopeId = 0)
449    {
450        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($status, $scopeId) {
451            if ('deleted' == $status) {
452                $query
453                    ->andWith('process.Name', '=', '(abgesagt)');
454            }
455            if ('blocked' == $status) {
456                $query
457                    ->andWith('process.StandortID', '=', 0)
458                    ->andWith('process.AbholortID', '=', 0);
459            }
460            if ('reserved' == $status) {
461                $query
462                    ->andWith('process.name', '!=', '(abgesagt)')
463                    ->andWith('process.vorlaeufigeBuchung', '=', 1)
464                    ->andWith('process.StandortID', '!=', 0)
465                    ->andWith('process.istFolgeterminvon', 'is', null);
466            }
467            if ('missed' == $status) {
468                $query->andWith('process.nicht_erschienen', '!=', 0)
469                    ->andWith('process.StandortID', '!=', 0);
470            }
471            if ('parked' == $status) {
472                $query
473                    ->andWith('process.parked', '!=', 0)
474                    ->andWith('process.StandortID', '!=', 0);
475            }
476            if ('pending' == $status) {
477                $query
478                    ->andWith('process.StandortID', '!=', 0)
479                    ->andWith('process.Abholer', '!=', 0)
480                    ->andWith('process.NutzerID', '=', 0);
481                if (0 != $scopeId) {
482                    $query->andWith('process.AbholortID', '=', $scopeId);
483                } else {
484                    $query->andWith('process.AbholortID', '!=', 0);
485                }
486            }
487            if ('processing' == $status) {
488                $query
489                    ->andWith('process.aufruferfolgreich', '!=', 0)
490                    ->andWith('process.NutzerID', '!=', 0)
491                    ->andWith('process.StandortID', '!=', 0);
492            }
493            if ('pickup' == $status) {
494                $query
495                    ->andWith('process.StandortID', '!=', 0)
496                    ->andWith('process.NutzerID', '!=', 0);
497                if (0 != $scopeId) {
498                    $query->andWith('process.AbholortID', '=', $scopeId);
499                } else {
500                    $query->andWith('process.AbholortID', '!=', 0);
501                }
502            }
503            if ('called' == $status) {
504                $query
505                    ->andWith('process.aufrufzeit', '!=', '00:00:00')
506                    ->andWith('process.NutzerID', '!=', 0)
507                    ->andWith('process.StandortID', '!=', 0)
508                    ->andWith('process.AbholortID', '=', 0);
509            }
510            if ('queued' == $status) {
511                $query->andWith('process.Uhrzeit', '=', '00:00:00')
512                    ->andWith('process.StandortID', '!=', 0)
513                    ->andWith('process.AbholortID', '=', 0);
514                ;
515            }
516            if ('confirmed' == $status) {
517                $query
518                    ->andWith('process.vorlaeufigeBuchung', '=', 0)
519                    ->andWith('process.Abholer', '=', 0)
520                    ->andWith('process.Uhrzeit', '!=', '00:00:00')
521                    ->andWith('process.bestaetigt', '=', 1)
522                    ->andWith('process.IPTimeStamp', '!=', 0);
523            }
524            if ('preconfirmed' == $status) {
525                $query
526                    ->andWith('process.vorlaeufigeBuchung', '=', 0)
527                    ->andWith('process.Abholer', '=', 0)
528                    ->andWith('process.StandortID', '!=', 0)
529                    ->andWith('process.Uhrzeit', '!=', '00:00:00')
530                    ->andWith('process.bestaetigt', '=', 0)
531                    ->andWith('process.IPTimeStamp', '!=', 0);
532                if (0 != $scopeId) {
533                    $query
534                        ->andWith('process.StandortID', '=', $scopeId);
535                }
536            }
537        });
538        return $this;
539    }
540
541    public function addConditionIsReserved()
542    {
543        $this->query->where('process.name', 'NOT IN', array(
544            'dereferenced',
545            '(abgesagt)'
546        ))
547            ->where('process.vorlaeufigeBuchung', '=', 1)
548            ->where('process.StandortID', '>', 0);
549        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $condition) {
550            $condition
551                ->andWith('process.istFolgeterminvon', 'IS', null)
552                ->orWith('process.istFolgeterminvon', '=', 0);
553        });
554        return $this;
555    }
556
557    public function addConditionSearch($queryString, $orWhere = false)
558    {
559        $condition = function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($queryString) {
560            $queryString = trim($queryString);
561            $query->orWith('process.Name', 'LIKE', "%$queryString%");
562            $query->orWith('process.EMail', 'LIKE', "%$queryString%");
563            $query->orWith('process.Telefonnummer', 'LIKE', "%$queryString%");
564            $query->orWith('process.telefonnummer_fuer_rueckfragen', 'LIKE', "%$queryString%");
565        };
566        if ($orWhere) {
567            $this->query->orWhere($condition);
568        } else {
569            $this->query->where($condition);
570        }
571        return $this;
572    }
573
574    public function addConditionName($name, $exactMatching = false)
575    {
576        if ($exactMatching) {
577            $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($name) {
578                $query->andWith('process.Name', '=', $name);
579            });
580        } else {
581            $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($name) {
582                $query->andWith('process.Name', 'LIKE', "%$name%");
583            });
584        }
585        return $this;
586    }
587
588    public function addConditionMail($mailAddress, $exactMatching = false)
589    {
590        if ($exactMatching) {
591            $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($mailAddress) {
592                $query->andWith('process.Email', '=', $mailAddress);
593            });
594        } else {
595            $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($mailAddress) {
596                $query->andWith('process.Email', 'LIKE', "%$mailAddress%");
597            });
598        }
599        return $this;
600    }
601
602    public function addConditionCustomTextfield($customText, $exactMatching = false)
603    {
604        if ($exactMatching) {
605            $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($customText) {
606                $query->andWith('process.custom_text_field', '=', $customText);
607            });
608        } else {
609            $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($customText) {
610                $query->andWith('process.custom_text_field', 'LIKE', "%$customText%");
611            });
612        }
613        return $this;
614    }
615
616    public function addConditionAmendment($amendment)
617    {
618        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($amendment) {
619            $query->andWith('process.Anmerkung', 'LIKE', "%$amendment%");
620        });
621        return $this;
622    }
623
624    /**
625     * Add Requests Join
626     */
627    public function addConditionRequestId($requestId)
628    {
629        $this->leftJoin(
630            new Alias("buergeranliegen", 'buergeranliegen'),
631            'buergeranliegen.BuergerID',
632            '=',
633            'process.BuergerID'
634        );
635        $this->query->where('buergeranliegen.AnliegenID', '=', $requestId);
636        return $this;
637    }
638
639    /**
640     * add condition to get process if deallocation time < now
641     */
642    public function addConditionDeallocate($now)
643    {
644        $this->query->where(function (\BO\Zmsdb\Query\Builder\ConditionBuilder $query) use ($now) {
645            $query
646                ->andWith('process.Name', '=', '(abgesagt)')
647                ->andWith('process.IPTimeStamp', '<', $now->getTimestamp());
648        });
649        $this->query->orderBy('process.IPTimeStamp', 'ASC');
650        return $this;
651    }
652
653    public function addValuesNewProcess(\BO\Zmsentities\Process $process, $parentProcess = 0, $childProcessCount = 0)
654    {
655        $values = [
656            'BuergerID' => $process->id,
657            'IPTimeStamp' => $process->createTimestamp,
658            'absagecode' => $process->authKey,
659            'hatFolgetermine' => $childProcessCount,
660            'istFolgeterminvon' => $parentProcess,
661            'wartenummer' => $process->queue['number']
662        ];
663        if ($process->toProperty()->apiclient->apiClientID->isAvailable()) {
664            $values['apiClientID'] = $process->apiclient->apiClientID;
665        }
666        $this->addValues($values);
667    }
668
669    public function addValuesUpdateProcess(
670        \BO\Zmsentities\Process $process,
671        \DateTimeInterface $dateTime,
672        $parentProcess = 0,
673        $previousStatus = null
674    ) {
675        $this->addValuesIPAdress($process);
676        $this->addValuesStatusData($process, $dateTime);
677        if (0 === $parentProcess) {
678            $this->addValuesClientData($process);
679            $this->addProcessingTimeData($process, $dateTime, $previousStatus);
680            $this->addValuesQueueData($process);
681            $this->addValuesWaitingTimeData($process, $previousStatus);
682            $this->addValuesWayTimeData($process);
683        }
684        if ($process->isWithAppointment()) {
685            $this->addValuesFollowingProcessData($process, $parentProcess);
686        }
687        $this->addValuesWasMissed($process);
688    }
689
690    public function addValuesIPAdress($process)
691    {
692        $data = array();
693        $data['IPAdresse'] = $process['createIP'];
694        $this->addValues($data);
695    }
696
697    public function addValuesFollowingProcessData($process, $parentProcess)
698    {
699        $data = array();
700        if (0 === $parentProcess) {
701            $data['hatFolgetermine'] = (1 <= $process->getFirstAppointment()->getSlotCount()) ?
702                $process->getFirstAppointment()->getSlotCount() - 1 :
703                0;
704        } else {
705            $data['Name'] = '(Folgetermin)';
706        }
707        $this->addValues($data);
708    }
709
710    public function addValuesAppointmentData(
711        \BO\Zmsentities\Process $process
712    ) {
713        $data = array();
714        $appointment = $process->getFirstAppointment();
715        if (null !== $appointment) {
716            $datetime = $appointment->toDateTime();
717            $data['Datum'] = $datetime->format('Y-m-d');
718            $data['Uhrzeit'] = $datetime->format('H:i:s');
719        }
720        $this->addValues($data);
721    }
722
723    public function addValuesScopeData(
724        \BO\Zmsentities\Process $process
725    ) {
726        $data = array();
727        $data['StandortID'] = $process->getScopeId();
728        $this->addValues($data);
729    }
730
731    public function addValuesStatusData($process, \DateTimeInterface $dateTime)
732    {
733        $data = array();
734        $data['vorlaeufigeBuchung'] = ($process['status'] == 'reserved') ? 1 : 0;
735        $data['aufruferfolgreich'] = ($process['status'] == 'processing') ? 1 : 0;
736        if ($process->status == 'called') {
737            $data['parked'] = 0;
738            $data['nicht_erschienen'] = 0;
739        }
740        if ($process->status == 'pending') {
741            $data['AbholortID'] = $process->scope['id'];
742            $data['Abholer'] = 1;
743            $data['nicht_erschienen'] = 0;
744            $data['parked'] = 0;
745        }
746        if ($process->status == 'pickup') {
747            $data['AbholortID'] = $process->scope['id'];
748            $data['Abholer'] = 1;
749            $data['Timestamp'] = 0;
750            $data['nicht_erschienen'] = 0;
751            $data['parked'] = 0;
752        }
753        if ($process->status == 'queued') {
754            $data['nicht_erschienen'] = 0;
755            $data['parked'] = 0;
756            if (
757                $process->hasArrivalTime() &&
758                (isset($process->queue['withAppointment']) && $process->queue['withAppointment'])
759            ) {
760                $data['wsm_aufnahmezeit'] = $dateTime->format('H:i:s');
761            }
762        }
763        if ($process->status == 'missed') {
764            $data['nicht_erschienen'] = 1;
765        }
766        if ($process->status == 'parked') {
767            $data['parked'] = 1;
768        }
769        if ($process->status == 'confirmed') {
770            $data['bestaetigt'] = 1;
771        }
772        if ($process->status == 'preconfirmed') {
773            $data['bestaetigt'] = 0;
774        }
775
776        $this->addValues($data);
777    }
778
779    protected function addValuesClientData($process)
780    {
781        $data = array();
782        $client = $process->getFirstClient();
783        if ($client && $client->hasFamilyName()) {
784            $data['Name'] = $client->familyName;
785        }
786        if ($client && $client->hasEmail()) {
787            $data['EMail'] = $client->email;
788        }
789        if ($client && $client->offsetExists('telephone')) {
790            $data['telefonnummer_fuer_rueckfragen'] = $client->telephone;
791            $data['Telefonnummer'] = $client->telephone; // to stay compatible with ZMS1
792        }
793        if ($client && $client->offsetExists('emailSendCount')) {
794            $data['EMailverschickt'] = ('-1' == $client->emailSendCount) ? 0 : $client->emailSendCount;
795        }
796        if ($client && $client->offsetExists('notificationsSendCount')) {
797            $data['SMSverschickt'] = ('-1' == $client->notificationsSendCount) ? 0 : $client->notificationsSendCount;
798        }
799        if ($process->getAmendment()) {
800            $data['Anmerkung'] = $process->getAmendment();
801        }
802        if ($process->getCustomTextfield()) {
803            $data['custom_text_field'] = $process->getCustomTextfield();
804        }
805        $data['zustimmung_kundenbefragung'] = ($client->surveyAccepted) ? 1 : 0;
806        $data['Erinnerungszeitpunkt'] = $process->getReminderTimestamp();
807        $data['AnzahlPersonen'] = $process->getClients()->count();
808        $this->addValues($data);
809    }
810
811    protected function addProcessingTimeData($process, \DateTimeInterface $dateTime, $previousStatus = null)
812    {
813        $data = array();
814        $timeoutTime = null;
815        $showUpTime = null;
816        $finishTime = null;
817
818        if (
819            isset($previousStatus) &&
820            (($process->status == 'called' && $previousStatus == 'called') ||
821                ($process->status == 'processing' && $previousStatus == 'processing'))
822        ) {
823            $timeoutTime = $dateTime->format('Y-m-d H:i:s');
824            $data['timeoutTime'] = $timeoutTime;
825        } elseif ($process->status == 'processing') {
826            $showUpTime = $dateTime->format('Y-m-d H:i:s');
827            $data['showUpTime'] = $showUpTime;
828        } elseif ($process->status == 'finished') {
829            $finishTime = $dateTime->format('Y-m-d H:i:s');
830            $data['finishTime'] = $finishTime;
831        }
832
833
834        if (isset($finishTime) && isset($process->showUpTime)) {
835            $showUpDateTime = new \DateTime($process->showUpTime);
836            $finishTime = new \DateTime($finishTime);
837
838            $processingTimeStr = $process->getProcessingTime();
839            $previousProcessingTimeInSeconds = 0; // Default to 0 if not set
840
841            if (!empty($processingTimeStr)) {
842                // Assume the format is HH:MM:SS and parse it
843                list($hours, $minutes, $seconds) = explode(':', $processingTimeStr);
844                // Convert hours, minutes, and seconds to total seconds
845                $previousProcessingTimeInSeconds = (int)$hours * 3600 + (int)$minutes * 60 + (int)$seconds;
846            }
847
848            $interval = $showUpDateTime->diff($finishTime);
849            $totalSeconds = ($interval->days * 24 * 60 * 60) + ($interval->h * 60 * 60) + ($interval->i * 60) + $interval->s;
850
851            $totalSeconds += $previousProcessingTimeInSeconds;
852
853            $hours = intdiv($totalSeconds, 3600);
854            $minutes = intdiv($totalSeconds % 3600, 60);
855            $seconds = $totalSeconds % 60;
856
857            $data['processingTime'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
858        } elseif (isset($timeoutTime) && isset($process->showUpTime)) {
859            $showUpDateTime = new \DateTime($process->showUpTime);
860            $timeoutDateTime = new \DateTime($timeoutTime);
861            $processingTimeStr = $process->getProcessingTime();
862
863            $previousProcessingTimeInSeconds = 0; // Default to 0 if not set
864            if (!empty($processingTimeStr)) {
865                // Assume the format is HH:MM:SS and parse it
866                list($hours, $minutes, $seconds) = explode(':', $processingTimeStr);
867                // Convert hours, minutes, and seconds to total seconds
868                $previousProcessingTimeInSeconds = (int)$hours * 3600 + (int)$minutes * 60 + (int)$seconds;
869            }
870            $interval = $showUpDateTime->diff($timeoutDateTime);
871            $totalSeconds = ($interval->days * 24 * 60 * 60) + ($interval->h * 60 * 60) + ($interval->i * 60) + $interval->s;
872
873            $totalSeconds += $previousProcessingTimeInSeconds;
874
875            $hours = intdiv($totalSeconds, 3600);
876            $minutes = intdiv($totalSeconds % 3600, 60);
877            $seconds = $totalSeconds % 60;
878
879            $data['processingTime'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
880        }
881
882        $this->addValues($data);
883    }
884
885    protected function addValuesQueueData($process)
886    {
887        $data = array();
888        $appointmentTime = $process->getFirstAppointment()->toDateTime()->format('H:i:s');
889
890        if (isset($process->queue['callCount']) && $process->queue['callCount']) {
891            $data['AnzahlAufrufe'] = $process->queue['callCount'];
892        }
893        if (isset($process->queue['callTime']) && $process->queue['callTime']) {
894            $data['aufrufzeit'] = (new \DateTimeImmutable())
895                ->setTimestamp($process->queue['callTime'])->format('H:i:s');
896        }
897        if (isset($process->queue['lastCallTime']) && $process->queue['lastCallTime']) {
898            $data['Timestamp'] = (new \DateTimeImmutable())
899                ->setTimestamp($process->queue['lastCallTime'])->format('H:i:s');
900        }
901        if (isset($process->queue['arrivalTime']) && $process->queue['arrivalTime']) {
902            $data['wsm_aufnahmezeit'] = (new \DateTimeImmutable())
903                ->setTimestamp($process->queue['arrivalTime'])->format('H:i:s');
904        }
905        if (isset($data['wsm_aufnahmezeit']) && $data['wsm_aufnahmezeit'] == $appointmentTime) {
906            // Do not save arrivalTime if it is an appointment
907            $data['wsm_aufnahmezeit'] = 0;
908        }
909        $this->addValues($data);
910    }
911
912    protected function addValuesWaitingTimeData($process, $previousStatus = null)
913    {
914        $data = array();
915
916        if (
917            (
918                // Szenario 1: Vorheriger Status ist queued, missed oder confirmed und aktueller Status ist called
919                in_array($previousStatus, ['queued', 'missed', 'confirmed'])
920                && $process['status'] == 'called'
921                && ($process->queue['callCount'] <= 0 || !empty($process['wasMissed']))
922            )
923            ||
924            (
925                // Szenario 2: Vorheriger Status ist missed, aktueller Status ist queued,
926                // es gibt den Hinweis wasMissed und die Queue sowie waitingTime sind gesetzt
927                $previousStatus == 'missed'
928                && $process['status'] == 'queued'
929                && !empty($process['wasMissed'])
930                && isset($process->queue)
931                && isset($process->queue->waitingTime)
932            )
933        ) {
934            $wartezeitInSeconds = $process->getWaitedSeconds();
935            $wartezeitInSeconds = $wartezeitInSeconds > 0 ? $wartezeitInSeconds : 0;
936
937            // Convert total seconds into HH:MM:SS format
938            $hours = intdiv($wartezeitInSeconds, 3600);
939            $minutes = intdiv($wartezeitInSeconds % 3600, 60);
940            $seconds = $wartezeitInSeconds % 60;
941
942            $data['wartezeit'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
943        }
944
945        $this->addValues($data);
946    }
947
948
949    protected function addValuesWayTimeData($process)
950    {
951        $data = array();
952        if ($process['status'] == 'processing') {
953            $wegezeit = $process->getWayMinutes();
954            $data['wegezeit'] = $wegezeit > 0 ? $wegezeit : 0;
955        }
956        $this->addValues($data);
957    }
958
959    protected function addValuesWasMissed($process)
960    {
961        $data = [
962            'wasMissed' => $process->wasMissed ? 1 : 0,
963        ];
964
965        $this->addValues($data);
966        return $this;
967    }
968
969    public function postProcess($data)
970    {
971        $data[$this->getPrefixed("appointments__0__date")] =
972            strtotime($data[$this->getPrefixed("appointments__0__date")]);
973        if ('00:00:00' != $data[$this->getPrefixed("queue__callTime")]) {
974            $time = explode(':', $data[$this->getPrefixed("queue__callTime")]);
975            $data[$this->getPrefixed("queue__callTime")] = (new \DateTimeImmutable())
976                ->setTimestamp($data[$this->getPrefixed("appointments__0__date")])
977                ->setTime($time[0], $time[1], $time[2])
978                ->getTimestamp();
979        } else {
980            $data[$this->getPrefixed("queue__callTime")] = 0;
981        }
982        if ('00:00:00' != $data[$this->getPrefixed("queue__lastCallTime")]) {
983            $time = explode(':', $data[$this->getPrefixed("queue__lastCallTime")]);
984            $data[$this->getPrefixed("queue__lastCallTime")] = (new \DateTimeImmutable())
985                ->setTimestamp($data[$this->getPrefixed("appointments__0__date")])
986                ->setTime($time[0], $time[1], $time[2])
987                ->getTimestamp();
988        } else {
989            $data[$this->getPrefixed("queue__lastCallTime")] = 0;
990        }
991        $data[$this->getPrefixed("queue__arrivalTime")] =
992            strtotime($data[$this->getPrefixed("queue__arrivalTime")]);
993        if (
994            isset($data[$this->getPrefixed('scope__provider__data')])
995            && $data[$this->getPrefixed('scope__provider__data')]
996        ) {
997            $data[$this->getPrefixed('scope__provider__data')] =
998                json_decode($data[$this->getPrefixed('scope__provider__data')], true);
999        }
1000        if (isset($data[$this->getPrefixed('__clientsCount')])) {
1001            $clientsCount = $data[$this->getPrefixed('__clientsCount')];
1002            unset($data[$this->getPrefixed('__clientsCount')]);
1003            while (--$clientsCount > 0) {
1004                $data[$this->getPrefixed('clients__' . $clientsCount . '__familyName')] = 'Unbekannt';
1005            }
1006        }
1007        $data[$this->getPrefixed("lastChange")] =
1008            (new \DateTimeImmutable($data[$this->getPrefixed("lastChange")] .
1009                \BO\Zmsdb\Connection\Select::$connectionTimezone))->getTimestamp();
1010        return $data;
1011    }
1012
1013    public function removeDuplicates()
1014    {
1015        $this->query->groupBy('process.BuergerID');
1016        return $this;
1017    }
1018
1019    protected function addRequiredJoins()
1020    {
1021        $this->leftJoin(
1022            new Alias(Useraccount::TABLE, 'processuser'),
1023            'process.NutzerID',
1024            '=',
1025            'processuser.NutzerID'
1026        );
1027
1028        $this->leftJoin(
1029            new Alias(Scope::TABLE, 'processscope'),
1030            'process.StandortID',
1031            '=',
1032            'processscope.StandortID'
1033        );
1034    }
1035}