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