Lines
78.95%
709 / 898
Methods
77.77%
77 / 99
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| getEntityMapping | 100.00% | 33 / 33 | 100.00% | 1 / 1 | 1 | ||
| addConditionAssigned | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | ||
| postProcess | 100.00% | 15 / 15 | 100.00% | 1 / 1 | 6 | ||
| addRequiredJoins | 100.00% | 12 / 12 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] getQueryNewProcessId | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] getLockProcessId | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] getLockAssignedWorkstationId | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addJoin | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 3 | ||
| [BO\Zmsbackend\Process\Repository\Process] addJoinAvailability | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addJoinScope | 100.00% | 11 / 11 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionDate | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionDisplayNumber | 0.00% | 0 / 2 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] calculateStatus | 0.00% | 0 / 33 | 0.00% | 0 / 1 | 506 | ||
| [BO\Zmsbackend\Process\Repository\Process] addCountValue | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionHasTelephone | 0.00% | 0 / 6 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessDeleteInterval | 100.00% | 11 / 11 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessDeleteBeforeDate | 100.00% | 11 / 11 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessExpiredIPTimeStamp | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessReminderInterval | 0.00% | 0 / 7 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessMailReminder | 100.00% | 44 / 44 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessId | 100.00% | 7 / 7 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessIdFollow | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionIgnoreSlots | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionScopeId | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionScopeIds | 45.45% | 5 / 11 | 0.00% | 0 / 1 | 4.46 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionQueueNumber | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionWorkstationId | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionTime | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionTimeframe | 0.00% | 0 / 6 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionAuthKey | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionStatus | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionIsReserved | 100.00% | 12 / 12 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionSearch | 91.66% | 22 / 24 | 0.00% | 0 / 1 | 4.01 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionProcessIdOrSearch | 96.66% | 29 / 30 | 0.00% | 0 / 1 | 3 | ||
| [BO\Zmsbackend\Process\Repository\Process] appendGeneralSearchTermGroup | 100.00% | 18 / 18 | 100.00% | 1 / 1 | 5 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionUpcomingOnly | 100.00% | 12 / 12 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addOrderByAppointmentDate | 0.00% | 0 / 4 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addOrderBySearchRelevance | 0.00% | 0 / 38 | 0.00% | 0 / 1 | 20 | ||
| [BO\Zmsbackend\Process\Repository\Process] parseSearchTerms | 78.57% | 11 / 14 | 0.00% | 0 / 1 | 6.35 | ||
| [BO\Zmsbackend\Process\Repository\Process] appendNamePartLikeGroup | 90.00% | 9 / 10 | 0.00% | 0 / 1 | 3.01 | ||
| [BO\Zmsbackend\Process\Repository\Process] isNumericSearchQuery | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] escapeLikeValue | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] escapeLikePatternForSqlLiteral | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] escapeSqlStringLiteral | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionName | 100.00% | 8 / 8 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionMail | 62.50% | 5 / 8 | 0.00% | 0 / 1 | 2.21 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionCustomTextfield | 0.00% | 0 / 8 | 0.00% | 0 / 1 | 6 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionCustomTextfield2 | 0.00% | 0 / 8 | 0.00% | 0 / 1 | 6 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionAmendment | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionRequestId | 100.00% | 8 / 8 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionScopeNameSearch | 100.00% | 23 / 23 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionServiceNameSearch | 100.00% | 16 / 16 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionDeallocate | 100.00% | 7 / 7 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesNewProcess | 100.00% | 16 / 16 | 100.00% | 1 / 1 | 6 | ||
| [BO\Zmsbackend\Process\Repository\Process] getNewDisplayNumber | 13.33% | 2 / 15 | 0.00% | 0 / 1 | 8.86 | ||
| [BO\Zmsbackend\Process\Repository\Process] checkIfDisplayNumberOnSameDateExists | 0.00% | 0 / 6 | 0.00% | 0 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesUpdateProcess | 100.00% | 13 / 13 | 100.00% | 1 / 1 | 3 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesIPAdress | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesFollowingProcessData | 100.00% | 7 / 7 | 100.00% | 1 / 1 | 3 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesAppointmentData | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesScopeData | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesStatusData | 100.00% | 28 / 28 | 100.00% | 1 / 1 | 13 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesClientData | 100.00% | 18 / 18 | 100.00% | 1 / 1 | 11 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValueDisplayNumber | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addProcessingTimeData | 40.00% | 20 / 50 | 0.00% | 0 / 1 | 96.98 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesQueueData | 100.00% | 16 / 16 | 100.00% | 1 / 1 | 10 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesWaitingTimeData | 84.61% | 33 / 39 | 0.00% | 0 / 1 | 19.18 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesWayTimeData | 100.00% | 8 / 8 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesWasMissed | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesPriority | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addValuesExternalUserId | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] removeDuplicates | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Process\Repository\Process] addConditionExternalUserId | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] __construct | 88.23% | 30 / 34 | 0.00% | 0 / 1 | 10.16 | ||
| [BO\Zmsbackend\Query\Base] __toString | n/a | 0 / 0 | n/a | 0 / 0 | 4 | ||
| [BO\Zmsbackend\Query\Base] getName | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] addSelect | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] setDistinctSelect | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] setResolveLevel | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] getResolveLevel | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] getAlias | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] getTablename | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] addTable | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] addTableAlias | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] addResolvedReferences | 100.00% | 11 / 11 | 100.00% | 1 / 1 | 3 | ||
| [BO\Zmsbackend\Query\Base] setWithEntities | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] leftJoin | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] innerJoin | 100.00% | 5 / 5 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] getSql | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] getParameters | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] getReferenceMapping | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] expression | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] addEntityMapping | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] getPrefixed | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] getPrefixedList | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] addReferenceMapping | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] addLimit | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] addValues | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [BO\Zmsbackend\Query\Base] postProcessJoins | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 2 | ||
| [BO\Zmsbackend\Query\Base] shouldLoadEntity | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 2 | ||
| 10 | class Queue extends \BO\Zmsbackend\Process\Repository\Process implements \BO\Zmsbackend\Query\MappingInterface | |
| 11 | { | |
| 12 | const string ALIAS = 'process'; | |
| 13 | ||
| 14 | /** | |
| 15 | * @return (\BO\Zmsbackend\Query\Builder\Expression|string)[] | |
| 16 | * | |
| 17 | */ | |
| 18 | #[\Override] | |
| 19 | public function getEntityMapping() | |
| 20 | { | |
| 21 | $status_expression = self::expression( | |
| 22 | 'CASE | |
| 23 | WHEN process.Name = "(abgesagt)" | |
| 24 | THEN "deleted" | |
| 25 | WHEN process.Name = "dereferenced" AND process.StandortID = 0 | |
| 26 | THEN "blocked" | |
| 27 | WHEN process.vorlaeufigeBuchung = 1 AND process.bestaetigt = 0 | |
| 28 | THEN "reserved" | |
| 29 | WHEN process.nicht_erschienen != 0 | |
| 30 | THEN "missed" | |
| 31 | WHEN process.Abholer != 0 AND process.AbholortID != 0 AND process.NutzerID = 0 | |
| 32 | THEN "pending" | |
| 33 | WHEN process.AbholortID = 0 AND process.aufruferfolgreich != 0 AND process.NutzerID != 0 | |
| 34 | THEN "processing" | |
| 35 | WHEN process.aufrufzeit != "00:00:00" AND process.NutzerID != 0 AND process.AbholortID = 0 | |
| 36 | THEN "called" | |
| 37 | WHEN process.wsm_aufnahmezeit != "00:00:00" | |
| 38 | THEN "queued" | |
| 39 | WHEN process.vorlaeufigeBuchung = 0 AND process.bestaetigt = 0 AND IPTimeStamp | |
| 40 | THEN "preconfirmed" | |
| 41 | WHEN process.vorlaeufigeBuchung = 0 AND process.bestaetigt = 1 AND IPTimeStamp | |
| 42 | THEN "confirmed" | |
| 43 | ELSE "free" | |
| 44 | END' | |
| 45 | ); | |
| 46 | return [ | |
| 47 | //'id' => 'process.BuergerID', | |
| 48 | 'status' => $status_expression, | |
| 49 | 'arrivalTime' => self::expression( | |
| 50 | 'CONCAT( | |
| 51 | `process`.`Datum`, | |
| 52 | " ", | |
| 53 | IF(`process`.`Uhrzeit`, `process`.`Uhrzeit`, `process`.`wsm_aufnahmezeit`) | |
| 54 | )' | |
| 55 | ), | |
| 56 | 'callCount' => 'process.AnzahlAufrufe', | |
| 57 | 'priority' => 'process.priority', | |
| 58 | 'callTime' => self::expression( | |
| 59 | 'CONCAT( | |
| 60 | `process`.`Datum`, | |
| 61 | " ", | |
| 62 | `process`.`aufrufzeit` | |
| 63 | )' | |
| 64 | ), | |
| 65 | 'lastCallTime' => self::expression( | |
| 66 | 'CONCAT( | |
| 67 | `process`.`Datum`, | |
| 68 | " ", | |
| 69 | `process`.`Timestamp` | |
| 70 | )' | |
| 71 | ), | |
| 72 | 'number' => self::expression( | |
| 73 | 'IF(`process`.`wartenummer`, | |
| 74 | `process`.`wartenummer`, | |
| 75 | `process`.`BuergerID` | |
| 76 | )' | |
| 77 | ), | |
| 78 | 'destination' => 'processuser.Arbeitsplatznr', | |
| 79 | 'destinationHint' => 'processuser.aufrufzusatz', | |
| 80 | 'waitingTime' => 'process.waiting_time', | |
| 81 | 'wayTime' => 'process.way_time', | |
| 82 | 'withAppointment' => self::expression( | |
| 83 | 'IF(`process`.`wartenummer`, | |
| 84 | "0", | |
| 85 | "1" | |
| 86 | )' | |
| 87 | ), | |
| 88 | ]; | |
| 89 | } | |
| 90 | ||
| 91 | /** | |
| 92 | * @return static | |
| 93 | */ | |
| 94 | #[\Override] | |
| 95 | public function addConditionAssigned() | |
| 96 | { | |
| 97 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) { | |
| 98 | $query->andWith(self::expression('process.istFolgeterminvon IS NULL OR process.istFolgeterminvon'), '=', 0); | |
| 99 | }); | |
| 100 | return $this; | |
| 101 | } | |
| 102 | ||
| 103 | ||
| 104 | #[\Override] | |
| 105 | public function postProcess($data) | |
| 106 | { | |
| 107 | if (false === strpos($data[$this->getPrefixed("callTime")], '00:00:00')) { | |
| 108 | $data[$this->getPrefixed("callTime")] = strtotime($data[$this->getPrefixed("callTime")]); | |
| 109 | } else { | |
| 110 | $data[$this->getPrefixed("callTime")] = 0; | |
| 111 | } | |
| 112 | if (false === strpos($data[$this->getPrefixed("lastCallTime")], '00:00:00')) { | |
| 113 | $data[$this->getPrefixed("lastCallTime")] = strtotime($data[$this->getPrefixed("lastCallTime")]); | |
| 114 | } else { | |
| 115 | $data[$this->getPrefixed("lastCallTime")] = 0; | |
| 116 | } | |
| 117 | if (!$data[$this->getPrefixed("waitingTime")]) { | |
| 118 | $data[$this->getPrefixed("waitingTime")] = 0; | |
| 119 | }; | |
| 120 | if (!$data[$this->getPrefixed("wayTime")]) { | |
| 121 | $data[$this->getPrefixed("wayTime")] = 0; | |
| 122 | }; | |
| 123 | $data[$this->getPrefixed("arrivalTime")] = | |
| 124 | strtotime($data[$this->getPrefixed("arrivalTime")]); | |
| 125 | $data[$this->getPrefixed("withAppointment")] = | |
| 126 | ($data[$this->getPrefixed("withAppointment")]) ? true : false; | |
| 127 | return $data; | |
| 128 | } | |
| 129 | ||
| 130 | /** | |
| 131 | * @return void | |
| 132 | */ | |
| 133 | #[\Override] | |
| 134 | protected function addRequiredJoins() | |
| 135 | { | |
| 136 | $this->leftJoin( | |
| 137 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Useraccount\Repository\Useraccount::TABLE, 'processuser'), | |
| 138 | 'process.NutzerID', | |
| 139 | '=', | |
| 140 | 'processuser.NutzerID' | |
| 141 | ); | |
| 142 | $this->leftJoin( | |
| 143 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Query\Scope::TABLE, 'processscope'), | |
| 144 | 'process.StandortID', | |
| 145 | '=', | |
| 146 | 'processscope.StandortID' | |
| 147 | ); | |
| 148 | } | |
| 149 | } |
Inherited from BO\Zmsbackend\Process\Repository\Process
| 94 | public function getQueryNewProcessId(): string | |
| 95 | { | |
| 96 | $random = rand(20, 999); | |
| 97 | return 'SELECT pseq.processId AS `nextid` | |
| 98 | FROM process_sequence pseq | |
| 99 | WHERE pseq.processId = ( | |
| 100 | SELECT ps.processID FROM `process_sequence` ps LEFT JOIN `' . self::getTablename() . '` p | |
| 101 | ON ps.processId = p.BuergerID | |
| 102 | WHERE p.`BuergerID` IS NULL | |
| 103 | LIMIT ' . $random . ',1) | |
| 104 | FOR UPDATE'; | |
| 105 | } |
| 107 | public function getLockProcessId(): string | |
| 108 | { | |
| 109 | return 'SELECT p.`BuergerID` FROM `' . self::getTablename() . '` p WHERE p.`BuergerID` = :processId FOR UPDATE'; | |
| 110 | } |
| 112 | public function getLockAssignedWorkstationId(): string | |
| 113 | { | |
| 114 | return 'SELECT p.`NutzerID` | |
| 115 | FROM `' . self::getTablename() . '` p | |
| 116 | WHERE p.`BuergerID` = :processId | |
| 117 | FOR UPDATE'; | |
| 118 | } |
| 121 | public function addJoin() | |
| 122 | { | |
| 123 | $joins = []; | |
| 124 | ||
| 125 | if ($this->shouldLoadEntity('availability')) { | |
| 126 | $joins[] = $this->addJoinAvailability(); | |
| 127 | } | |
| 128 | ||
| 129 | if ($this->shouldLoadEntity('scope')) { | |
| 130 | $joins[] = $this->addJoinScope(); | |
| 131 | } | |
| 132 | ||
| 133 | return $joins; | |
| 134 | } |
| 139 | protected function addJoinAvailability(): \BO\Zmsbackend\Availability\Repository\Availability | |
| 140 | { | |
| 141 | $this->leftJoin( | |
| 142 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Availability\Repository\Availability::TABLE, 'availability'), | |
| 143 | \BO\Zmsbackend\Availability\Repository\Availability::getJoinExpression('`process`', '`availability`') | |
| 144 | ); | |
| 145 | $joinQuery = new \BO\Zmsbackend\Availability\Repository\Availability($this, $this->getPrefixed('appointments__0__availability__')); | |
| 146 | return $joinQuery; | |
| 147 | } |
| 152 | protected function addJoinScope(): \BO\Zmsbackend\Query\Scope | |
| 153 | { | |
| 154 | $this->leftJoin( | |
| 155 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Query\Scope::TABLE, 'scope'), | |
| 156 | self::expression( | |
| 157 | 'IF(`process`.`AbholortID`, | |
| 158 | `process`.`AbholortID`, | |
| 159 | `process`.`StandortID` | |
| 160 | )' | |
| 161 | ), | |
| 162 | '=', | |
| 163 | 'scope.StandortID' | |
| 164 | ); | |
| 165 | $joinQuery = new \BO\Zmsbackend\Query\Scope($this, $this->getPrefixed('scope__')); | |
| 166 | return $joinQuery; | |
| 167 | } |
| 169 | public function addConditionDate($date): static | |
| 170 | { | |
| 171 | $this->query->where('process.Datum', '=', $date); | |
| 172 | return $this; | |
| 173 | } |
| 178 | public function addConditionDisplayNumber($displayNumber): static | |
| 179 | { | |
| 180 | $this->query->where('process.displayNumber', '=', $displayNumber); | |
| 181 | return $this; | |
| 182 | } |
| 189 | protected function calculateStatus(): string|null | |
| 190 | { | |
| 191 | if ($this->query->value('Name') === '(abgesagt)') { | |
| 192 | return 'deleted'; | |
| 193 | } | |
| 194 | ||
| 195 | if ( | |
| 196 | $this->query->value('StandortID') == 0 | |
| 197 | && $this->query->value('AbholortID') == 0 | |
| 198 | ) { | |
| 199 | return 'blocked'; | |
| 200 | } | |
| 201 | ||
| 202 | if ( | |
| 203 | $this->query->value('vorlaeufigeBuchung') == 1 | |
| 204 | && $this->query->value('bestaetigt') == 0 | |
| 205 | ) { | |
| 206 | return 'reserved'; | |
| 207 | } | |
| 208 | ||
| 209 | if ($this->query->value('nicht_erschienen') != 0) { | |
| 210 | return 'missed'; | |
| 211 | } | |
| 212 | ||
| 213 | if ($this->query->value('parked') != 0) { | |
| 214 | return 'parked'; | |
| 215 | } | |
| 216 | ||
| 217 | if ( | |
| 218 | $this->query->value('Abholer') != 0 | |
| 219 | && $this->query->value('AbholortID') != 0 | |
| 220 | && $this->query->value('NutzerID') == 0 | |
| 221 | ) { | |
| 222 | return 'pending'; | |
| 223 | } | |
| 224 | ||
| 225 | if ( | |
| 226 | $this->query->value('AbholortID') == 0 | |
| 227 | && $this->query->value('aufruferfolgreich') != 0 | |
| 228 | && $this->query->value('NutzerID') != 0 | |
| 229 | ) { | |
| 230 | return 'processing'; | |
| 231 | } | |
| 232 | ||
| 233 | if ( | |
| 234 | $this->query->value('aufrufzeit') != "00:00:00" | |
| 235 | && $this->query->value('NutzerID') != 0 | |
| 236 | && $this->query->value('AbholortID') == 0 | |
| 237 | ) { | |
| 238 | return 'called'; | |
| 239 | } | |
| 240 | ||
| 241 | if ($this->query->value('Uhrzeit') == "00:00:00") { | |
| 242 | return 'queued'; | |
| 243 | } | |
| 244 | ||
| 245 | if ( | |
| 246 | $this->query->value('vorlaeufigeBuchung') == 0 | |
| 247 | && $this->query->value('bestaetigt') == 0 | |
| 248 | ) { | |
| 249 | return 'preconfirmed'; | |
| 250 | } | |
| 251 | ||
| 252 | if ( | |
| 253 | $this->query->value('vorlaeufigeBuchung') == 0 | |
| 254 | && $this->query->value('bestaetigt') == 1 | |
| 255 | ) { | |
| 256 | return 'confirmed'; | |
| 257 | } | |
| 258 | ||
| 259 | return null; | |
| 260 | } |
| 367 | public function addCountValue(): static | |
| 368 | { | |
| 369 | $this->query->select([ | |
| 370 | 'processCount' => self::expression('COUNT(*)'), | |
| 371 | ]); | |
| 372 | return $this; | |
| 373 | } |
| 378 | public function addConditionHasTelephone(): static | |
| 379 | { | |
| 380 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) { | |
| 381 | $condition | |
| 382 | ->andWith('process.telefonnummer_fuer_rueckfragen', '!=', '') | |
| 383 | ->orWith('process.Telefonnummer', '!=', ''); | |
| 384 | }); | |
| 385 | return $this; | |
| 386 | } |
| 388 | public function addConditionProcessDeleteInterval(\DateTimeInterface $expirationDate): static | |
| 389 | { | |
| 390 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($expirationDate) { | |
| 391 | $query->andWith( | |
| 392 | self::expression( | |
| 393 | 'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)' | |
| 394 | ), | |
| 395 | '<=', | |
| 396 | $expirationDate->format('Y-m-d H:i:s') | |
| 397 | ); | |
| 398 | }); | |
| 399 | $this->query->orderBy('appointments__0__date', 'ASC'); | |
| 400 | return $this; | |
| 401 | } |
| 403 | public function addConditionProcessDeleteBeforeDate(\DateTimeInterface $date): static | |
| 404 | { | |
| 405 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($date) { | |
| 406 | $query->andWith( | |
| 407 | self::expression( | |
| 408 | 'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)' | |
| 409 | ), | |
| 410 | '<', | |
| 411 | $date->format('Y-m-d') . ' 00:00:00' | |
| 412 | ); | |
| 413 | }); | |
| 414 | $this->query->orderBy('appointments__0__date', 'ASC'); | |
| 415 | return $this; | |
| 416 | } |
| 421 | public function addConditionProcessExpiredIPTimeStamp(\DateTimeInterface $expirationDate): static | |
| 422 | { | |
| 423 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($expirationDate) { | |
| 424 | $query->andWith('process.IPTimeStamp', '<=', $expirationDate->getTimestamp()); | |
| 425 | }); | |
| 426 | $this->query->orderBy('appointments__0__date', 'ASC'); | |
| 427 | return $this; | |
| 428 | } |
| 433 | public function addConditionProcessReminderInterval(\DateTimeInterface $dateTime): static | |
| 434 | { | |
| 435 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($dateTime) { | |
| 436 | $query | |
| 437 | ->andWith('process.Erinnerungszeitpunkt', '<=', $dateTime->getTimestamp()) | |
| 438 | ->andWith('process.Erinnerungszeitpunkt', '>=', $dateTime->modify("-5 Minutes")->getTimestamp()); | |
| 439 | }); | |
| 440 | $this->query->orderBy('reminderTimestamp', 'ASC'); | |
| 441 | return $this; | |
| 442 | } |
| 444 | public function addConditionProcessMailReminder( | |
| 445 | \DateTimeInterface $now, | |
| 446 | \DateTimeInterface $lastRun, | |
| 447 | int $defaultReminderInMinutes | |
| 448 | ): static { | |
| 449 | $this->query | |
| 450 | ->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($now, $lastRun, $defaultReminderInMinutes) { | |
| 451 | $query | |
| 452 | ->andWith( | |
| 453 | self::expression( | |
| 454 | 'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)' | |
| 455 | ), | |
| 456 | '>', | |
| 457 | $lastRun->format('Y-m-d H:i:s') | |
| 458 | ) | |
| 459 | ->andWith( | |
| 460 | self::expression( | |
| 461 | 'CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`)' | |
| 462 | ), | |
| 463 | '>', | |
| 464 | $now->format('Y-m-d H:i:s') | |
| 465 | ) | |
| 466 | ->andWith( | |
| 467 | 'scopemail.send_reminder', | |
| 468 | '=', | |
| 469 | 1 | |
| 470 | ) | |
| 471 | ->andWith( | |
| 472 | 'process.EMail', | |
| 473 | '<>', | |
| 474 | "" | |
| 475 | ) | |
| 476 | ->andWith( | |
| 477 | 'process.EMailverschickt', | |
| 478 | '=', | |
| 479 | 0 | |
| 480 | ) | |
| 481 | ->andWith( | |
| 482 | self::expression( | |
| 483 | 'DATE_SUB(CONCAT(`process`.`Datum`, " ", `process`.`Uhrzeit`), INTERVAL ' | |
| 484 | . 'IFNULL(scopemail.send_reminder_minutes_before, ' . $defaultReminderInMinutes | |
| 485 | . ') MINUTE)' | |
| 486 | ), | |
| 487 | '<=', | |
| 488 | $now->format('Y-m-d H:i:s') | |
| 489 | ); | |
| 490 | }); | |
| 491 | $this->query->orderBy('appointments__0__date', 'ASC'); | |
| 492 | return $this; | |
| 493 | } |
| 495 | public function addConditionProcessId(int $processId): static | |
| 496 | { | |
| 497 | $this->query->where('process.BuergerID', '=', $processId); | |
| 498 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) { | |
| 499 | $condition | |
| 500 | ->andWith('process.istFolgeterminvon', 'IS', null) | |
| 501 | ->orWith('process.istFolgeterminvon', '=', 0); | |
| 502 | }); | |
| 503 | return $this; | |
| 504 | } |
| 506 | public function addConditionProcessIdFollow($processId): static | |
| 507 | { | |
| 508 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) use ($processId) { | |
| 509 | $condition | |
| 510 | ->andWith('process.BuergerID', '=', $processId) | |
| 511 | ->orWith('process.istFolgeterminvon', '=', $processId); | |
| 512 | }); | |
| 513 | return $this; | |
| 514 | } |
| 519 | public function addConditionIgnoreSlots(): static | |
| 520 | { | |
| 521 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) { | |
| 522 | $condition | |
| 523 | ->andWith('process.istFolgeterminvon', 'IS', null) | |
| 524 | ->orWith('process.istFolgeterminvon', '=', 0); | |
| 525 | }); | |
| 526 | return $this; | |
| 527 | } |
| 529 | public function addConditionScopeId(int $scopeId): static | |
| 530 | { | |
| 531 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($scopeId) { | |
| 532 | $query | |
| 533 | ->andWith('process.StandortID', '=', $scopeId) | |
| 534 | ->orWith('process.AbholortID', '=', $scopeId); | |
| 535 | }); | |
| 536 | return $this; | |
| 537 | } |
| 539 | public function addConditionScopeIds(array|int $scopeIds) | |
| 540 | { | |
| 541 | if (count($scopeIds) === 0) { | |
| 542 | $this->query->where(self::expression('1'), '=', 0); | |
| 543 | return $this; | |
| 544 | } | |
| 545 | ||
| 546 | if (count($scopeIds) === 1) { | |
| 547 | return $this->addConditionScopeId($scopeIds[0]); | |
| 548 | } | |
| 549 | ||
| 550 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($scopeIds) { | |
| 551 | $query | |
| 552 | ->andWith('process.StandortID', 'IN', $scopeIds) | |
| 553 | ->orWith('process.AbholortID', 'IN', $scopeIds); | |
| 554 | }); | |
| 555 | ||
| 556 | return $this; | |
| 557 | } |
| 562 | public function addConditionQueueNumber(int $queueNumber, int $queueLimit = 10000): static | |
| 563 | { | |
| 564 | ($queueLimit > $queueNumber) | |
| 565 | ? $this->query->where('process.wartenummer', '=', $queueNumber) | |
| 566 | : $this->query->where('process.BuergerID', '=', $queueNumber); | |
| 567 | return $this; | |
| 568 | } |
| 570 | public function addConditionWorkstationId($workstationId): static | |
| 571 | { | |
| 572 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($workstationId) { | |
| 573 | $query->andWith('process.NutzerID', '=', $workstationId); | |
| 574 | $query->andWith('process.StandortID', '>', 0); | |
| 575 | }); | |
| 576 | return $this; | |
| 577 | } |
| 579 | public function addConditionTime(\DateTimeInterface|null $dateTime): static | |
| 580 | { | |
| 581 | $this->query->where('process.Datum', '=', $dateTime->format('Y-m-d')); | |
| 582 | return $this; | |
| 583 | } |
| 590 | public function addConditionTimeframe(\DateTimeInterface $startDate, \DateTimeInterface $endDate): static | |
| 591 | { | |
| 592 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) use ($startDate, $endDate) { | |
| 593 | $condition | |
| 594 | ->andWith('process.Datum', '<=', $endDate->format('Y-m-d')) | |
| 595 | ->andWith('process.Datum', '>=', $startDate->format('Y-m-d')); | |
| 596 | }); | |
| 597 | return $this; | |
| 598 | } |
| 600 | public function addConditionAuthKey($authKey): static | |
| 601 | { | |
| 602 | $authKey = urldecode($authKey); | |
| 603 | $this->query->where('process.absagecode', '=', $authKey); | |
| 604 | return $this; | |
| 605 | } |
| 616 | public function addConditionStatus(string $status): static | |
| 617 | { | |
| 618 | $this->query->where('process.status', '=', $status); | |
| 619 | return $this; | |
| 620 | } |
| 625 | public function addConditionIsReserved(): static | |
| 626 | { | |
| 627 | $this->query->where('process.name', 'NOT IN', array( | |
| 628 | 'dereferenced', | |
| 629 | '(abgesagt)' | |
| 630 | )) | |
| 631 | ->where('process.vorlaeufigeBuchung', '=', 1) | |
| 632 | ->where('process.StandortID', '>', 0); | |
| 633 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) { | |
| 634 | $condition | |
| 635 | ->andWith('process.istFolgeterminvon', 'IS', null) | |
| 636 | ->orWith('process.istFolgeterminvon', '=', 0); | |
| 637 | }); | |
| 638 | return $this; | |
| 639 | } |
| 641 | public function addConditionSearch($queryString, bool $orWhere = false): static | |
| 642 | { | |
| 643 | $queryString = trim((string) $queryString); | |
| 644 | $terms = $this->parseSearchTerms($queryString); | |
| 645 | ||
| 646 | if ($terms === []) { | |
| 647 | return $this; | |
| 648 | } | |
| 649 | ||
| 650 | $condition = function ( | |
| 651 | \BO\Zmsbackend\Query\Builder\ConditionBuilder $query | |
| 652 | ) use ($terms) { | |
| 653 | foreach ($terms as $term) { | |
| 654 | $query->andWith( | |
| 655 | function ( | |
| 656 | \BO\Zmsbackend\Query\Builder\ConditionBuilder $inner | |
| 657 | ) use ($term) { | |
| 658 | $this->appendGeneralSearchTermGroup( | |
| 659 | $inner, | |
| 660 | $term['value'], | |
| 661 | $term['quoted'] | |
| 662 | ); | |
| 663 | } | |
| 664 | ); | |
| 665 | } | |
| 666 | }; | |
| 667 | ||
| 668 | if ($orWhere) { | |
| 669 | $this->query->orWhere($condition); | |
| 670 | } else { | |
| 671 | $this->query->where($condition); | |
| 672 | } | |
| 673 | ||
| 674 | return $this; | |
| 675 | } |
| 680 | public function addConditionProcessIdOrSearch($queryString): static | |
| 681 | { | |
| 682 | $queryString = trim((string) $queryString); | |
| 683 | $processId = (int) $queryString; | |
| 684 | $terms = $this->parseSearchTerms($queryString); | |
| 685 | ||
| 686 | $this->query->where(function ( | |
| 687 | \BO\Zmsbackend\Query\Builder\ConditionBuilder $group | |
| 688 | ) use ( | |
| 689 | $processId, | |
| 690 | $terms | |
| 691 | ) { | |
| 692 | $group->andWith('process.BuergerID', '=', $processId); | |
| 693 | ||
| 694 | if ($terms === []) { | |
| 695 | return; | |
| 696 | } | |
| 697 | ||
| 698 | $group->orWith(function ( | |
| 699 | \BO\Zmsbackend\Query\Builder\ConditionBuilder $search | |
| 700 | ) use ($terms) { | |
| 701 | foreach ($terms as $term) { | |
| 702 | $search->andWith( | |
| 703 | function ( | |
| 704 | \BO\Zmsbackend\Query\Builder\ConditionBuilder $inner | |
| 705 | ) use ($term) { | |
| 706 | $this->appendGeneralSearchTermGroup( | |
| 707 | $inner, | |
| 708 | $term['value'], | |
| 709 | $term['quoted'] | |
| 710 | ); | |
| 711 | } | |
| 712 | ); | |
| 713 | } | |
| 714 | }); | |
| 715 | }); | |
| 716 | ||
| 717 | return $this; | |
| 718 | } |
| 720 | private function appendGeneralSearchTermGroup(\BO\Zmsbackend\Query\Builder\ConditionBuilder $query, string $term, bool $quoted = false): void | |
| 721 | { | |
| 722 | $likeContains = '%' . $this->escapeLikeValue($term) . '%'; | |
| 723 | ||
| 724 | $useNameWordBoundary = !$quoted | |
| 725 | && !$this->isNumericSearchQuery($term) && mb_strlen($term) <= 3; | |
| 726 | ||
| 727 | if ($quoted) { | |
| 728 | $this->appendNamePartLikeGroup( | |
| 729 | $query, | |
| 730 | $term, | |
| 731 | true | |
| 732 | ); | |
| 733 | } elseif ($useNameWordBoundary) { | |
| 734 | $this->appendNamePartLikeGroup($query, $term, true, true); | |
| 735 | } else { | |
| 736 | $query->orWith('process.Name', 'LIKE', $likeContains); | |
| 737 | } | |
| 738 | ||
| 739 | $query->orWith('process.EMail', 'LIKE', $likeContains); | |
| 740 | $query->orWith('process.Telefonnummer', 'LIKE', $likeContains); | |
| 741 | $query->orWith('process.telefonnummer_fuer_rueckfragen', 'LIKE', $likeContains); | |
| 742 | $query->orWith('process.displayNumber', 'LIKE', $likeContains); | |
| 743 | $query->orWith('process.custom_text_field', 'LIKE', $likeContains); | |
| 744 | $query->orWith('process.custom_text_field2', 'LIKE', $likeContains); | |
| 745 | } |
| 747 | public function addConditionUpcomingOnly(\DateTimeInterface $now): static | |
| 748 | { | |
| 749 | $today = $now->format('Y-m-d'); | |
| 750 | $time = $now->format('H:i:s'); | |
| 751 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) use ($today, $time) { | |
| 752 | $condition | |
| 753 | ->andWith('process.Datum', '>', $today) | |
| 754 | ->orWith(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $inner) use ($today, $time) { | |
| 755 | $inner | |
| 756 | ->andWith('process.Datum', '=', $today) | |
| 757 | ->andWith('process.Uhrzeit', '>=', $time); | |
| 758 | }); | |
| 759 | }); | |
| 760 | return $this; | |
| 761 | } |
| 764 | public function addOrderByAppointmentDate(): static | |
| 765 | { | |
| 766 | $this->query->orderBy('process.Datum', 'ASC'); | |
| 767 | $this->query->orderBy('process.Uhrzeit', 'ASC'); | |
| 768 | $this->query->orderBy('process.BuergerID', 'ASC'); | |
| 769 | return $this; | |
| 770 | } |
| 773 | public function addOrderBySearchRelevance(string $queryString): static | |
| 774 | { | |
| 775 | $queryString = trim($queryString); | |
| 776 | if ($queryString === '') { | |
| 777 | return $this; | |
| 778 | } | |
| 779 | ||
| 780 | $terms = $this->parseSearchTerms($queryString); | |
| 781 | if ($terms === []) { | |
| 782 | return $this; | |
| 783 | } | |
| 784 | $fullQuery = $this->escapeLikePatternForSqlLiteral($queryString); | |
| 785 | $fullQueryExact = $this->escapeSqlStringLiteral($queryString); | |
| 786 | ||
| 787 | $allTermsAsWordsConditions = []; | |
| 788 | $allTermsInNameConditions = []; | |
| 789 | $anyTermInNameConditions = []; | |
| 790 | ||
| 791 | foreach ($terms as $term) { | |
| 792 | $escapedTerm = $this->escapeLikePatternForSqlLiteral($term['value']); | |
| 793 | $exactTerm = $this->escapeSqlStringLiteral($term['value']); | |
| 794 | $allTermsAsWordsConditions[] = "(" | |
| 795 | . "process.Name = '{$exactTerm}'" | |
| 796 | . " OR process.Name LIKE '{$escapedTerm} %'" | |
| 797 | . " OR process.Name LIKE '% {$escapedTerm}'" | |
| 798 | . " OR process.Name LIKE '% {$escapedTerm} %'" | |
| 799 | . ")"; | |
| 800 | $allTermsInNameConditions[] = "process.Name LIKE '%{$escapedTerm}%'"; | |
| 801 | $anyTermInNameConditions[] = "process.Name LIKE '%{$escapedTerm}%'"; | |
| 802 | } | |
| 803 | $allTermsAsWords = implode(' AND ', $allTermsAsWordsConditions); | |
| 804 | $allTermsInName = implode(' AND ', $allTermsInNameConditions); | |
| 805 | $anyTermInName = implode(' OR ', $anyTermInNameConditions); | |
| 806 | ||
| 807 | $this->query->orderBy(self::expression( | |
| 808 | "CASE | |
| 809 | WHEN process.Name LIKE '{$fullQueryExact}' THEN 0 | |
| 810 | WHEN process.Name LIKE '{$fullQuery} %' THEN 1 | |
| 811 | WHEN {$allTermsAsWords} THEN 2 | |
| 812 | WHEN {$allTermsInName} THEN 3 | |
| 813 | WHEN {$anyTermInName} THEN 4 | |
| 814 | ELSE 5 | |
| 815 | END" | |
| 816 | )); | |
| 817 | ||
| 818 | $this->query->orderBy('process.Datum', 'ASC'); | |
| 819 | $this->query->orderBy('process.Uhrzeit', 'ASC'); | |
| 820 | $this->query->orderBy('process.BuergerID', 'ASC'); | |
| 821 | ||
| 822 | return $this; | |
| 823 | } |
| 828 | private function parseSearchTerms(string $queryString): array | |
| 829 | { | |
| 830 | if ($queryString === '') { | |
| 831 | return []; | |
| 832 | } | |
| 833 | ||
| 834 | if (!preg_match_all('/"([^"]+)"|(\S+)/u', $queryString, $matches, PREG_SET_ORDER)) { | |
| 835 | return [['value' => $queryString, 'quoted' => false]]; | |
| 836 | } | |
| 837 | ||
| 838 | $terms = []; | |
| 839 | foreach ($matches as $match) { | |
| 840 | $value = trim($match[1] !== '' ? $match[1] : $match[2]); | |
| 841 | if ($value === '') { | |
| 842 | continue; | |
| 843 | } | |
| 844 | $terms[] = [ | |
| 845 | 'value' => $value, | |
| 846 | 'quoted' => $match[1] !== '', | |
| 847 | ]; | |
| 848 | } | |
| 849 | ||
| 850 | return $terms; | |
| 851 | } |
| 853 | private function appendNamePartLikeGroup( | |
| 854 | \BO\Zmsbackend\Query\Builder\ConditionBuilder $query, | |
| 855 | string $term, | |
| 856 | bool $wordBoundaryOnly = false, | |
| 857 | bool $includeWordPrefix = false | |
| 858 | ): void { | |
| 859 | $escaped = $this->escapeLikeValue($term); | |
| 860 | $query->orWith('process.Name', 'LIKE', $escaped . ' %'); | |
| 861 | $query->orWith('process.Name', 'LIKE', '% ' . $escaped); | |
| 862 | $query->orWith('process.Name', 'LIKE', '% ' . $escaped . ' %'); | |
| 863 | $query->orWith('process.Name', '=', $term); | |
| 864 | if ($wordBoundaryOnly) { | |
| 865 | if ($includeWordPrefix) { | |
| 866 | $query->orWith('process.Name', 'LIKE', $escaped . '%'); | |
| 867 | $query->orWith('process.Name', 'LIKE', '% ' . $escaped . '%'); | |
| 868 | } | |
| 869 | } else { | |
| 870 | $query->orWith('process.Name', 'LIKE', '%' . $escaped . '%'); | |
| 871 | } | |
| 872 | } |
| 874 | private function isNumericSearchQuery(string $queryString): bool | |
| 875 | { | |
| 876 | return (bool) preg_match('#^\d+$#', $queryString); | |
| 877 | } |
| 879 | private function escapeLikeValue(string $value): string | |
| 880 | { | |
| 881 | return str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $value); | |
| 882 | } |
| 884 | private function escapeLikePatternForSqlLiteral(string $value): string | |
| 885 | { | |
| 886 | return $this->escapeSqlStringLiteral($this->escapeLikeValue($value)); | |
| 887 | } |
| 889 | private function escapeSqlStringLiteral(string $value): string | |
| 890 | { | |
| 891 | return str_replace("'", "''", $value); | |
| 892 | } |
| 894 | public function addConditionName($name, bool $exactMatching = false): static | |
| 895 | { | |
| 896 | if ($exactMatching) { | |
| 897 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($name) { | |
| 898 | $query->andWith('process.Name', '=', $name); | |
| 899 | }); | |
| 900 | } else { | |
| 901 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($name) { | |
| 902 | $query->andWith('process.Name', 'LIKE', "%$name%"); | |
| 903 | }); | |
| 904 | } | |
| 905 | return $this; | |
| 906 | } |
| 908 | public function addConditionMail(string $mailAddress, bool $exactMatching = false): static | |
| 909 | { | |
| 910 | if ($exactMatching) { | |
| 911 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($mailAddress) { | |
| 912 | $query->andWith('process.Email', '=', $mailAddress); | |
| 913 | }); | |
| 914 | } else { | |
| 915 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($mailAddress) { | |
| 916 | $query->andWith('process.Email', 'LIKE', "%$mailAddress%"); | |
| 917 | }); | |
| 918 | } | |
| 919 | return $this; | |
| 920 | } |
| 925 | public function addConditionCustomTextfield($customText, bool $exactMatching = false): static | |
| 926 | { | |
| 927 | if ($exactMatching) { | |
| 928 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($customText) { | |
| 929 | $query->andWith('process.custom_text_field', '=', $customText); | |
| 930 | }); | |
| 931 | } else { | |
| 932 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($customText) { | |
| 933 | $query->andWith('process.custom_text_field', 'LIKE', "%$customText%"); | |
| 934 | }); | |
| 935 | } | |
| 936 | return $this; | |
| 937 | } |
| 942 | public function addConditionCustomTextfield2($customText2, bool $exactMatching = false): static | |
| 943 | { | |
| 944 | if ($exactMatching) { | |
| 945 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($customText2) { | |
| 946 | $query->andWith('process.custom_text_field2', '=', $customText2); | |
| 947 | }); | |
| 948 | } else { | |
| 949 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($customText2) { | |
| 950 | $query->andWith('process.custom_text_field2', 'LIKE', "%$customText2%"); | |
| 951 | }); | |
| 952 | } | |
| 953 | return $this; | |
| 954 | } |
| 956 | public function addConditionAmendment($amendment): static | |
| 957 | { | |
| 958 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($amendment) { | |
| 959 | $query->andWith('process.Anmerkung', 'LIKE', "%$amendment%"); | |
| 960 | }); | |
| 961 | return $this; | |
| 962 | } |
| 967 | public function addConditionRequestId($requestId): static | |
| 968 | { | |
| 969 | $this->leftJoin( | |
| 970 | new \BO\Zmsbackend\Query\Alias("buergeranliegen", 'buergeranliegen'), | |
| 971 | 'buergeranliegen.BuergerID', | |
| 972 | '=', | |
| 973 | 'process.BuergerID' | |
| 974 | ); | |
| 975 | $this->query->where('buergeranliegen.AnliegenID', '=', $requestId); | |
| 976 | return $this; | |
| 977 | } |
| 979 | public function addConditionScopeNameSearch(string $scopeName): static | |
| 980 | { | |
| 981 | $likeValue = '%' . $this->escapeLikeValue($scopeName) . '%'; | |
| 982 | $this->leftJoin( | |
| 983 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Query\Scope::TABLE, 'search_scope'), | |
| 984 | self::expression( | |
| 985 | 'IF(`process`.`AbholortID`, `process`.`AbholortID`, `process`.`StandortID`)' | |
| 986 | ), | |
| 987 | '=', | |
| 988 | 'search_scope.StandortID' | |
| 989 | ); | |
| 990 | $this->leftJoin( | |
| 991 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Provider\Repository\Provider::TABLE, 'search_scope_provider'), | |
| 992 | self::expression( | |
| 993 | 'search_scope.InfoDienstleisterID = search_scope_provider.id | |
| 994 | AND search_scope.source = search_scope_provider.source' | |
| 995 | ) | |
| 996 | ); | |
| 997 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($likeValue) { | |
| 998 | $query->orWith('search_scope.Bezeichnung', 'LIKE', $likeValue); | |
| 999 | $query->orWith('search_scope.standortinfozeile', 'LIKE', $likeValue); | |
| 1000 | $query->orWith('search_scope.standortkuerzel', 'LIKE', $likeValue); | |
| 1001 | $query->orWith('search_scope_provider.name', 'LIKE', $likeValue); | |
| 1002 | }); | |
| 1003 | ||
| 1004 | return $this; | |
| 1005 | } |
| 1007 | public function addConditionServiceNameSearch(string $serviceName): static | |
| 1008 | { | |
| 1009 | $likeValue = '%' . $this->escapeLikeValue($serviceName) . '%'; | |
| 1010 | $this->leftJoin( | |
| 1011 | new \BO\Zmsbackend\Query\Alias('buergeranliegen', 'search_request_link'), | |
| 1012 | 'search_request_link.BuergerID', | |
| 1013 | '=', | |
| 1014 | 'process.BuergerID' | |
| 1015 | ); | |
| 1016 | $this->leftJoin( | |
| 1017 | new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Request\Repository\Request::TABLE, 'search_request'), | |
| 1018 | self::expression( | |
| 1019 | 'search_request_link.AnliegenID = search_request.id | |
| 1020 | AND search_request_link.source = search_request.source' | |
| 1021 | ) | |
| 1022 | ); | |
| 1023 | $this->query->where('search_request.name', 'LIKE', $likeValue); | |
| 1024 | ||
| 1025 | return $this; | |
| 1026 | } |
| 1031 | public function addConditionDeallocate(\DateTimeInterface $now): static | |
| 1032 | { | |
| 1033 | $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $query) use ($now) { | |
| 1034 | $query | |
| 1035 | ->andWith('process.Name', '=', '(abgesagt)') | |
| 1036 | ->andWith('process.IPTimeStamp', '<', $now->getTimestamp()); | |
| 1037 | }); | |
| 1038 | $this->query->orderBy('process.IPTimeStamp', 'ASC'); | |
| 1039 | return $this; | |
| 1040 | } |
| 1042 | public function addValuesNewProcess(ProcessEntity $process, $parentProcess = 0, int $childProcessCount = 0): void | |
| 1043 | { | |
| 1044 | $values = [ | |
| 1045 | 'BuergerID' => $process->id, | |
| 1046 | 'IPTimeStamp' => $process->createTimestamp, | |
| 1047 | 'absagecode' => $process->authKey, | |
| 1048 | 'hatFolgetermine' => $childProcessCount, | |
| 1049 | 'istFolgeterminvon' => $parentProcess, | |
| 1050 | 'displayNumber' => $parentProcess === 0 && empty($process->queue['number']) | |
| 1051 | ? $this->getNewDisplayNumber($process) | |
| 1052 | : null, | |
| 1053 | 'wartenummer' => $process->queue['number'] | |
| 1054 | ]; | |
| 1055 | if ($process->toProperty()->apiclient->apiClientID->isAvailable()) { | |
| 1056 | $values['apiClientID'] = $process->apiclient->apiClientID; | |
| 1057 | } | |
| 1058 | if (isset($process->isTicketprinter) && $process->isTicketprinter) { | |
| 1059 | $values['is_ticketprinter'] = 1; | |
| 1060 | } | |
| 1061 | $this->addValues($values); | |
| 1062 | } |
| 1064 | public function getNewDisplayNumber(ProcessEntity $process) | |
| 1065 | { | |
| 1066 | if (empty($process->scope->getPreference('queue', 'displayNumberPrefix'))) { | |
| 1067 | return $process->id; | |
| 1068 | } | |
| 1069 | ||
| 1070 | $newDisplayNumber = $process->scope->getPreference('queue', 'displayNumberPrefix') . str_pad( | |
| 1071 | (new ScopeEntity())->readDisplayNumberUpdated($process->scope->id), | |
| 1072 | 4, | |
| 1073 | '0', | |
| 1074 | STR_PAD_LEFT | |
| 1075 | ); | |
| 1076 | ||
| 1077 | if ( | |
| 1078 | $this->checkIfDisplayNumberOnSameDateExists( | |
| 1079 | $process->scope->id, | |
| 1080 | $newDisplayNumber, | |
| 1081 | \DateTime::createFromFormat('U', (int) $process->getFirstAppointment()->date) | |
| 1082 | ) | |
| 1083 | ) { | |
| 1084 | return $this->getNewDisplayNumber($process); | |
| 1085 | } | |
| 1086 | ||
| 1087 | return $newDisplayNumber; | |
| 1088 | } |
| 1090 | public function checkIfDisplayNumberOnSameDateExists($scopeId, string $displayNumber, \DateTime|false $date): bool | |
| 1091 | { | |
| 1092 | $processWithDisplayNumber = (new \BO\Zmsbackend\Process\Service\Process())->readProcessWithSameDayAndDisplayNumber( | |
| 1093 | $scopeId, | |
| 1094 | $displayNumber, | |
| 1095 | $date->format('Y-m-d') | |
| 1096 | ); | |
| 1097 | ||
| 1098 | return !empty($processWithDisplayNumber->getId()); | |
| 1099 | } |
| 1101 | public function addValuesUpdateProcess( | |
| 1102 | ProcessEntity $process, | |
| 1103 | \DateTimeInterface $dateTime, | |
| 1104 | int $parentProcess = 0, | |
| 1105 | $previousStatus = null | |
| 1106 | ): void { | |
| 1107 | $this->addValuesIPAdress($process); | |
| 1108 | if (0 === $parentProcess) { | |
| 1109 | $this->addValuesClientData($process); | |
| 1110 | $this->addProcessingTimeData($process, $dateTime, $previousStatus); | |
| 1111 | $this->addValuesQueueData($process); | |
| 1112 | $this->addValuesWaitingTimeData($process, $previousStatus); | |
| 1113 | $this->addValuesWayTimeData($process); | |
| 1114 | } | |
| 1115 | if ($process->isWithAppointment()) { | |
| 1116 | $this->addValuesFollowingProcessData($process, $parentProcess); | |
| 1117 | } | |
| 1118 | $this->addValuesWasMissed($process); | |
| 1119 | $this->addValuesPriority($process); | |
| 1120 | $this->addValuesStatusData($process, $dateTime); | |
| 1121 | $this->addValuesExternalUserId($process); | |
| 1122 | } |
| 1124 | public function addValuesIPAdress(ProcessEntity $process): void | |
| 1125 | { | |
| 1126 | $data = array(); | |
| 1127 | $data['IPAdresse'] = $process->createIP; | |
| 1128 | $this->addValues($data); | |
| 1129 | } |
| 1131 | public function addValuesFollowingProcessData(ProcessEntity $process, $parentProcess): void | |
| 1132 | { | |
| 1133 | $data = array(); | |
| 1134 | if (0 === $parentProcess) { | |
| 1135 | $data['hatFolgetermine'] = (1 <= $process->getFirstAppointment()->getSlotCount()) ? | |
| 1136 | $process->getFirstAppointment()->getSlotCount() - 1 : | |
| 1137 | 0; | |
| 1138 | } else { | |
| 1139 | $data['Name'] = '(Folgetermin)'; | |
| 1140 | } | |
| 1141 | $this->addValues($data); | |
| 1142 | } |
| 1144 | public function addValuesAppointmentData( | |
| 1145 | ProcessEntity $process | |
| 1146 | ): void { | |
| 1147 | $data = array(); | |
| 1148 | $appointment = $process->getFirstAppointment(); | |
| 1149 | $datetime = $appointment->toDateTime(); | |
| 1150 | $data['Datum'] = $datetime->format('Y-m-d'); | |
| 1151 | $data['Uhrzeit'] = $datetime->format('H:i:s'); | |
| 1152 | $this->addValues($data); | |
| 1153 | } |
| 1155 | public function addValuesScopeData( | |
| 1156 | ProcessEntity $process | |
| 1157 | ): void { | |
| 1158 | $data = array(); | |
| 1159 | $data['StandortID'] = $process->getScopeId(); | |
| 1160 | $this->addValues($data); | |
| 1161 | } |
| 1163 | public function addValuesStatusData(ProcessEntity $process, \DateTimeInterface $dateTime): void | |
| 1164 | { | |
| 1165 | $data = array(); | |
| 1166 | $data['vorlaeufigeBuchung'] = ($process->status == 'reserved') ? 1 : 0; | |
| 1167 | $data['aufruferfolgreich'] = ($process->status == 'processing') ? 1 : 0; | |
| 1168 | if ($process->status == 'called') { | |
| 1169 | $data['parked'] = 0; | |
| 1170 | $data['nicht_erschienen'] = 0; | |
| 1171 | } | |
| 1172 | if ($process->status == 'pending') { | |
| 1173 | $data['AbholortID'] = $process->scope->id; | |
| 1174 | $data['Abholer'] = 1; | |
| 1175 | $data['nicht_erschienen'] = 0; | |
| 1176 | $data['parked'] = 0; | |
| 1177 | } | |
| 1178 | if ($process->status == 'queued') { | |
| 1179 | $data['nicht_erschienen'] = 0; | |
| 1180 | $data['parked'] = 0; | |
| 1181 | if ( | |
| 1182 | $process->hasArrivalTime() && | |
| 1183 | (isset($process->queue->withAppointment) && $process->queue->withAppointment) | |
| 1184 | ) { | |
| 1185 | $data['wsm_aufnahmezeit'] = $dateTime->format('H:i:s'); | |
| 1186 | } | |
| 1187 | } | |
| 1188 | if ($process->status == 'missed') { | |
| 1189 | $data['nicht_erschienen'] = 1; | |
| 1190 | } | |
| 1191 | if ($process->status == 'parked') { | |
| 1192 | $data['parked'] = 1; | |
| 1193 | } | |
| 1194 | if ($process->status == 'confirmed') { | |
| 1195 | $data['bestaetigt'] = 1; | |
| 1196 | } | |
| 1197 | if ($process->status == 'preconfirmed') { | |
| 1198 | $data['bestaetigt'] = 0; | |
| 1199 | } | |
| 1200 | $data['status'] = $process->status; | |
| 1201 | $data['parkedBy'] = $process->getParkedBy(); | |
| 1202 | ||
| 1203 | $this->addValues($data); | |
| 1204 | } |
| 1206 | protected function addValuesClientData(ProcessEntity $process): void | |
| 1207 | { | |
| 1208 | $data = array(); | |
| 1209 | $client = $process->getFirstClient(); | |
| 1210 | if ($client && $client->hasFamilyName()) { | |
| 1211 | $data['Name'] = $client->familyName; | |
| 1212 | } | |
| 1213 | if ($client && $client->hasEmail()) { | |
| 1214 | $data['EMail'] = $client->email; | |
| 1215 | } | |
| 1216 | if ($client && $client->offsetExists('telephone')) { | |
| 1217 | $data['telefonnummer_fuer_rueckfragen'] = $client->telephone; | |
| 1218 | $data['Telefonnummer'] = $client->telephone; // to stay compatible with ZMS1 | |
| 1219 | } | |
| 1220 | if ($client && $client->offsetExists('emailSendCount')) { | |
| 1221 | $data['EMailverschickt'] = ('-1' == $client->emailSendCount) ? 0 : $client->emailSendCount; | |
| 1222 | } | |
| 1223 | $data['Anmerkung'] = $process->getAmendment(); | |
| 1224 | $data['custom_text_field'] = $process->getCustomTextfield(); | |
| 1225 | $data['custom_text_field2'] = $process->getCustomTextfield2(); | |
| 1226 | $data['zustimmung_kundenbefragung'] = ($client->surveyAccepted) ? 1 : 0; | |
| 1227 | $data['Erinnerungszeitpunkt'] = $process->getReminderTimestamp(); | |
| 1228 | $data['AnzahlPersonen'] = $process->getClients()->count(); | |
| 1229 | $this->addValues($data); | |
| 1230 | } |
| 1232 | public function addValueDisplayNumber(ProcessEntity $process): void | |
| 1233 | { | |
| 1234 | $data['displayNumber'] = $process->displayNumber; | |
| 1235 | $this->addValues($data); | |
| 1236 | } |
| 1238 | protected function addProcessingTimeData(ProcessEntity $process, \DateTimeInterface $dateTime, $previousStatus = null): void | |
| 1239 | { | |
| 1240 | $data = array(); | |
| 1241 | $timeoutTime = null; | |
| 1242 | $finishTime = null; | |
| 1243 | ||
| 1244 | if ( | |
| 1245 | isset($previousStatus) && | |
| 1246 | (($process->status == 'called' && $previousStatus == 'called') || | |
| 1247 | ($process->status == 'processing' && $previousStatus == 'processing')) | |
| 1248 | ) { | |
| 1249 | $timeoutTime = $dateTime->format('Y-m-d H:i:s'); | |
| 1250 | $data['timeoutTime'] = $timeoutTime; | |
| 1251 | } elseif ($process->status == 'processing' && ($process->showUpTime === null || $process->showUpTime === '')) { | |
| 1252 | // Do not reset showUpTime on re-save (preserves Bearbeitungszeit) | |
| 1253 | $showUpTime = $dateTime->format('Y-m-d H:i:s'); | |
| 1254 | $data['showUpTime'] = $showUpTime; | |
| 1255 | } elseif ($process->status == 'finished') { | |
| 1256 | $finishTime = $dateTime->format('Y-m-d H:i:s'); | |
| 1257 | $data['finishTime'] = $finishTime; | |
| 1258 | } elseif ( | |
| 1259 | isset($previousStatus) | |
| 1260 | && in_array($previousStatus, ['called', 'processing'], true) | |
| 1261 | && in_array($process->status, ['queued', 'parked'], true) | |
| 1262 | ) { | |
| 1263 | // Drop open processing segment when leaving to queue/park so a later | |
| 1264 | // resume starts a fresh showUpTime (park-and-resume ATAF expectation). | |
| 1265 | $data['showUpTime'] = null; | |
| 1266 | $data['timeoutTime'] = null; | |
| 1267 | } | |
| 1268 | ||
| 1269 | ||
| 1270 | if (isset($finishTime) && isset($process->showUpTime)) { | |
| 1271 | $showUpDateTime = new \DateTime($process->showUpTime); | |
| 1272 | $finishTime = new \DateTime($finishTime); | |
| 1273 | ||
| 1274 | $processingTimeStr = $process->getProcessingTime(); | |
| 1275 | $previousProcessingTimeInSeconds = 0; // Default to 0 if not set | |
| 1276 | ||
| 1277 | if (!empty($processingTimeStr)) { | |
| 1278 | // Assume the format is HH:MM:SS and parse it | |
| 1279 | list($hours, $minutes, $seconds) = explode(':', $processingTimeStr); | |
| 1280 | // Convert hours, minutes, and seconds to total seconds | |
| 1281 | $previousProcessingTimeInSeconds = (int)$hours * 3600 + (int)$minutes * 60 + (int)$seconds; | |
| 1282 | } | |
| 1283 | ||
| 1284 | $interval = $showUpDateTime->diff($finishTime); | |
| 1285 | $totalSeconds = ($interval->days * 24 * 60 * 60) + ($interval->h * 60 * 60) + ($interval->i * 60) + $interval->s; | |
| 1286 | ||
| 1287 | $totalSeconds += $previousProcessingTimeInSeconds; | |
| 1288 | ||
| 1289 | $hours = intdiv($totalSeconds, 3600); | |
| 1290 | $minutes = intdiv($totalSeconds % 3600, 60); | |
| 1291 | $seconds = $totalSeconds % 60; | |
| 1292 | ||
| 1293 | $data['processing_time'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); | |
| 1294 | } elseif (isset($timeoutTime) && isset($process->showUpTime)) { | |
| 1295 | $showUpDateTime = new \DateTime($process->showUpTime); | |
| 1296 | $timeoutDateTime = new \DateTime($timeoutTime); | |
| 1297 | $processingTimeStr = $process->getProcessingTime(); | |
| 1298 | ||
| 1299 | $previousProcessingTimeInSeconds = 0; // Default to 0 if not set | |
| 1300 | if (!empty($processingTimeStr)) { | |
| 1301 | // Assume the format is HH:MM:SS and parse it | |
| 1302 | list($hours, $minutes, $seconds) = explode(':', $processingTimeStr); | |
| 1303 | // Convert hours, minutes, and seconds to total seconds | |
| 1304 | $previousProcessingTimeInSeconds = (int)$hours * 3600 + (int)$minutes * 60 + (int)$seconds; | |
| 1305 | } | |
| 1306 | $interval = $showUpDateTime->diff($timeoutDateTime); | |
| 1307 | $totalSeconds = ($interval->days * 24 * 60 * 60) + ($interval->h * 60 * 60) + ($interval->i * 60) + $interval->s; | |
| 1308 | ||
| 1309 | $totalSeconds += $previousProcessingTimeInSeconds; | |
| 1310 | ||
| 1311 | $hours = intdiv($totalSeconds, 3600); | |
| 1312 | $minutes = intdiv($totalSeconds % 3600, 60); | |
| 1313 | $seconds = $totalSeconds % 60; | |
| 1314 | ||
| 1315 | $data['processing_time'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); | |
| 1316 | } | |
| 1317 | ||
| 1318 | $this->addValues($data); | |
| 1319 | } |
| 1321 | protected function addValuesQueueData(ProcessEntity $process): void | |
| 1322 | { | |
| 1323 | $data = array(); | |
| 1324 | $appointmentTime = $process->getFirstAppointment()->toDateTime()->format('H:i:s'); | |
| 1325 | ||
| 1326 | if (isset($process->queue['callCount'])) { | |
| 1327 | $data['AnzahlAufrufe'] = (int) $process->queue['callCount']; | |
| 1328 | } | |
| 1329 | if (isset($process->queue['callTime']) && $process->queue['callTime']) { | |
| 1330 | $data['aufrufzeit'] = (new \DateTimeImmutable()) | |
| 1331 | ->setTimestamp($process->queue['callTime'])->format('H:i:s'); | |
| 1332 | } | |
| 1333 | if (isset($process->queue['lastCallTime']) && $process->queue['lastCallTime']) { | |
| 1334 | $data['Timestamp'] = (new \DateTimeImmutable()) | |
| 1335 | ->setTimestamp($process->queue['lastCallTime'])->format('H:i:s'); | |
| 1336 | } | |
| 1337 | if (isset($process->queue['arrivalTime']) && $process->queue['arrivalTime']) { | |
| 1338 | $data['wsm_aufnahmezeit'] = (new \DateTimeImmutable()) | |
| 1339 | ->setTimestamp($process->queue['arrivalTime'])->format('H:i:s'); | |
| 1340 | } | |
| 1341 | if (isset($data['wsm_aufnahmezeit']) && $data['wsm_aufnahmezeit'] == $appointmentTime) { | |
| 1342 | // Do not save arrivalTime if it is an appointment | |
| 1343 | $data['wsm_aufnahmezeit'] = 0; | |
| 1344 | } | |
| 1345 | $this->addValues($data); | |
| 1346 | } |
| 1348 | protected function addValuesWaitingTimeData(ProcessEntity $process, $previousStatus = null): void | |
| 1349 | { | |
| 1350 | $data = array(); | |
| 1351 | $hasWaitingTimeAlready = ( | |
| 1352 | isset($process->queue->waitingTime) | |
| 1353 | && $process->queue->waitingTime | |
| 1354 | && $process->queue->waitingTime !== '00:00:00' | |
| 1355 | ); | |
| 1356 | ||
| 1357 | if ( | |
| 1358 | !$hasWaitingTimeAlready | |
| 1359 | && ( | |
| 1360 | ( | |
| 1361 | // Szenario 1: Vorheriger Status ist queued, missed oder confirmed und aktueller Status ist called | |
| 1362 | in_array($previousStatus, ['queued', 'missed', 'confirmed']) | |
| 1363 | && $process->status == 'called' | |
| 1364 | && ( | |
| 1365 | ( | |
| 1366 | isset($process->queue->callCount) | |
| 1367 | && $process->queue->callCount <= 0 | |
| 1368 | ) | |
| 1369 | || ( | |
| 1370 | ($previousStatus === 'queued' || $previousStatus === 'confirmed') | |
| 1371 | && ( | |
| 1372 | !isset($process->queue->callTime) | |
| 1373 | || (int) $process->queue->callTime === 0 | |
| 1374 | ) | |
| 1375 | ) | |
| 1376 | ) | |
| 1377 | ) | |
| 1378 | || | |
| 1379 | ( | |
| 1380 | // Szenario 2: Vorheriger Status ist missed, aktueller Status ist queued, | |
| 1381 | // es gibt den Hinweis wasMissed und die Queue sowie waitingTime sind gesetzt | |
| 1382 | $previousStatus == 'missed' | |
| 1383 | && $process->status == 'queued' | |
| 1384 | && !empty($process->wasMissed) | |
| 1385 | && isset($process->queue) | |
| 1386 | && isset($process->queue->waitingTime) | |
| 1387 | ) | |
| 1388 | ) | |
| 1389 | ) { | |
| 1390 | $wartezeitInSeconds = $process->getWaitedSeconds(); | |
| 1391 | $wartezeitInSeconds = $wartezeitInSeconds > 0 ? $wartezeitInSeconds : 0; | |
| 1392 | ||
| 1393 | // Convert total seconds into HH:MM:SS format | |
| 1394 | $hours = intdiv($wartezeitInSeconds, 3600); | |
| 1395 | $minutes = intdiv($wartezeitInSeconds % 3600, 60); | |
| 1396 | $seconds = $wartezeitInSeconds % 60; | |
| 1397 | ||
| 1398 | $data['waiting_time'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); | |
| 1399 | } | |
| 1400 | ||
| 1401 | $this->addValues($data); | |
| 1402 | } |
| 1405 | protected function addValuesWayTimeData(ProcessEntity $process): void | |
| 1406 | { | |
| 1407 | $data = array(); | |
| 1408 | if ($process->status == 'processing') { | |
| 1409 | $wayTimeInSeconds = max(0, (int) $process->getWaySeconds()); | |
| 1410 | $hours = intdiv($wayTimeInSeconds, 3600); | |
| 1411 | $minutes = intdiv($wayTimeInSeconds % 3600, 60); | |
| 1412 | $seconds = $wayTimeInSeconds % 60; | |
| 1413 | $data['way_time'] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); | |
| 1414 | } | |
| 1415 | $this->addValues($data); | |
| 1416 | } |
| 1418 | protected function addValuesWasMissed(ProcessEntity $process): static | |
| 1419 | { | |
| 1420 | $data = [ | |
| 1421 | 'wasMissed' => $process->wasMissed ? 1 : 0, | |
| 1422 | ]; | |
| 1423 | ||
| 1424 | $this->addValues($data); | |
| 1425 | return $this; | |
| 1426 | } |
| 1428 | protected function addValuesPriority(ProcessEntity $process): static | |
| 1429 | { | |
| 1430 | $data = [ | |
| 1431 | 'priority' => $process->priority, | |
| 1432 | ]; | |
| 1433 | ||
| 1434 | $this->addValues($data); | |
| 1435 | return $this; | |
| 1436 | } |
| 1438 | protected function addValuesExternalUserId(ProcessEntity $process): static | |
| 1439 | { | |
| 1440 | $data = [ | |
| 1441 | 'external_user_id' => $process->externalUserId, | |
| 1442 | ]; | |
| 1443 | ||
| 1444 | $this->addValues($data); | |
| 1445 | return $this; | |
| 1446 | } |
| 1496 | public function removeDuplicates(): static | |
| 1497 | { | |
| 1498 | $this->query->groupBy('process.BuergerID'); | |
| 1499 | return $this; | |
| 1500 | } |
| 1527 | public function addConditionExternalUserId(string $externalUserId): static | |
| 1528 | { | |
| 1529 | $this->query->where('process.external_user_id', '=', $externalUserId); | |
| 1530 | return $this; | |
| 1531 | } |
Inherited from BO\Zmsbackend\Query\Base
| 96 | public function __construct( | |
| 97 | $queryType, | |
| 98 | $prefix = '', | |
| 99 | string|false $name = false, | |
| 100 | mixed $resolveLevel = null, | |
| 101 | array $withEntities = [] | |
| 102 | ) { | |
| 103 | $this->prefix = $prefix; | |
| 104 | $this->name = $name; | |
| 105 | $this->withEntities = $withEntities; | |
| 106 | $this->setResolveLevel($resolveLevel); | |
| 107 | $dialect = new MySQL(); | |
| 108 | if (self::SELECT === $queryType) { | |
| 109 | $this->query = new Select($dialect); | |
| 110 | $this->addSelect(); | |
| 111 | } elseif (self::INSERT === $queryType) { | |
| 112 | $this->query = new Insert($dialect); | |
| 113 | $this->addTable(); | |
| 114 | } elseif (self::UPDATE === $queryType) { | |
| 115 | $this->query = new Update($dialect); | |
| 116 | $this->addTableAlias(); | |
| 117 | } elseif (self::REPLACE === $queryType) { | |
| 118 | $this->query = new INSERT($dialect); | |
| 119 | $this->query->queryBaseStatement('REPLACE INTO'); | |
| 120 | $this->addTable(); | |
| 121 | } elseif (self::DELETE === $queryType) { | |
| 122 | $this->query = new Delete($dialect); | |
| 123 | $this->query->queryBaseStatement('DELETE ' . $this::getAlias() . ' FROM'); | |
| 124 | $this->addTableAlias(); | |
| 125 | } elseif ($queryType instanceof self) { | |
| 126 | $this->query = $queryType->query; | |
| 127 | // Share join-alias state with the parent query (intentional by-ref). | |
| 128 | /** @psalm-suppress UnsupportedPropertyReferenceUsage */ | |
| 129 | $this->joinedAliasList =& $queryType->joinedAliasList; | |
| 130 | $this->resolveLevel = $queryType->resolveLevel - 1; | |
| 131 | } elseif ($queryType instanceof QueryBuilder) { | |
| 132 | $this->query = $queryType; | |
| 133 | } else { | |
| 134 | throw new \InvalidArgumentException( | |
| 135 | 'Unsupported query type for ' . static::class . ': ' | |
| 136 | . (is_object($queryType) ? $queryType::class : gettype($queryType)) | |
| 137 | ); | |
| 138 | } | |
| 139 | if ($this->query instanceof Select) { | |
| 140 | $this->addRequiredJoins(); | |
| 141 | } | |
| 142 | } |
| 147 | public function __toString() | |
| 148 | { | |
| 149 | if ($this->name) { | |
| 150 | $name = $this->name . '_' . $this->prefix . (string) $this->resolveLevel; | |
| 151 | if (!isset(static::$sqlCache[$name])) { | |
| 152 | static::$sqlCache[$name] = $this->getSql(); | |
| 153 | } | |
| 154 | return static::$sqlCache[$name]; | |
| 155 | } | |
| 156 | if ($this->currentSqlString) { | |
| 157 | $sql = $this->currentSqlString; | |
| 158 | } else { | |
| 159 | $sql = $this->getSql(); | |
| 160 | } | |
| 161 | return $sql; | |
| 162 | } |
| 164 | public function getName() | |
| 165 | { | |
| 166 | return $this->name ? $this->name : get_class($this); | |
| 167 | } |
| 174 | protected function addSelect(): static | |
| 175 | { | |
| 176 | $table = $this::getTablename(); | |
| 177 | $alias = $this::getAlias(); | |
| 178 | $this->query->from($table, $alias); | |
| 179 | return $this; | |
| 180 | } |
| 182 | public function setDistinctSelect(): void | |
| 183 | { | |
| 184 | $this->query->queryBaseStatement('SELECT DISTINCT'); | |
| 185 | } |
| 187 | public function setResolveLevel(int|null $resolveLevel): static | |
| 188 | { | |
| 189 | if ($resolveLevel !== null) { | |
| 190 | $this->resolveLevel = $resolveLevel; | |
| 191 | } | |
| 192 | return $this; | |
| 193 | } |
| 195 | public function getResolveLevel() | |
| 196 | { | |
| 197 | if (null === $this->resolveLevel) { | |
| 198 | throw new \Exception("Required setting for resolveReferenceLevel missing in " . get_class($this)); | |
| 199 | } | |
| 200 | return $this->resolveLevel; | |
| 201 | } |
| 210 | public static function getAlias() | |
| 211 | { | |
| 212 | $class = get_called_class(); | |
| 213 | $alias = constant($class . '::ALIAS'); | |
| 214 | if (null === $alias) { | |
| 215 | $alias = lcfirst(preg_replace('#^.*\\\#', '', $class)); | |
| 216 | } | |
| 217 | return $alias; | |
| 218 | } |
| 225 | public static function getTablename() | |
| 226 | { | |
| 227 | $class = get_called_class(); | |
| 228 | $table = constant($class . '::TABLE'); | |
| 229 | return $table; | |
| 230 | } |
| 237 | protected function addTable(): static | |
| 238 | { | |
| 239 | $table = $this::getTablename(); | |
| 240 | $alias = $this::getAlias(); | |
| 241 | $this->query->table($table, $alias); | |
| 242 | return $this; | |
| 243 | } |
| 250 | protected function addTableAlias(): static | |
| 251 | { | |
| 252 | $table = $this::getTablename(); | |
| 253 | $alias = $this::getAlias(); | |
| 254 | $this->query->table(self::expression($table . ' ' . $alias)); | |
| 255 | return $this; | |
| 256 | } |
| 273 | public function addResolvedReferences($depth): static | |
| 274 | { | |
| 275 | $this->setResolveLevel($depth); | |
| 276 | if ($depth > 0) { | |
| 277 | $queryList = $this->addJoin(); | |
| 278 | foreach ($queryList as $query) { | |
| 279 | $query->setResolveLevel($depth); | |
| 280 | $query->setWithEntities($this->withEntities); | |
| 281 | $query->addResolvedReferences($depth - 1); | |
| 282 | $query->addEntityMapping(); | |
| 283 | } | |
| 284 | $this->joinedQueryList = $queryList; | |
| 285 | } else { | |
| 286 | $this->addReferenceMapping(); | |
| 287 | } | |
| 288 | return $this; | |
| 289 | } |
| 294 | public function setWithEntities($withEntities = []): void | |
| 295 | { | |
| 296 | $this->withEntities = $withEntities; | |
| 297 | } |
| 309 | protected function leftJoin(Alias $alias, string|Expression|null $left = null, string|null $operator = null, string|null $right = null): QueryBuilder | |
| 310 | { | |
| 311 | $aliasId = $alias->getAliasIdentifier(); | |
| 312 | if (!in_array($aliasId, $this->joinedAliasList)) { | |
| 313 | $this->joinedAliasList[] = $aliasId; | |
| 314 | $this->query->leftJoin($alias, $left, $operator, $right); | |
| 315 | } else { | |
| 316 | //throw new \Exception("Tried to add Alias ".$aliasId); | |
| 317 | } | |
| 318 | return $this->query; | |
| 319 | } |
| 321 | protected function innerJoin(Alias $alias, string|null $left = null, string|null $operator = null, string|null $right = null): QueryBuilder | |
| 322 | { | |
| 323 | $aliasId = $alias->getAliasIdentifier(); | |
| 324 | if (!in_array($aliasId, $this->joinedAliasList)) { | |
| 325 | $this->joinedAliasList[] = $aliasId; | |
| 326 | $this->query->join($alias, $left, $operator, $right); | |
| 327 | } | |
| 328 | return $this->query; | |
| 329 | } |
| 337 | public function getSql() | |
| 338 | { | |
| 339 | $this->currentSqlString = (string)$this->query; | |
| 340 | return $this->currentSqlString; | |
| 341 | } |
| 348 | public function getParameters() | |
| 349 | { | |
| 350 | return $this->query->params(); | |
| 351 | } |
| 357 | public function getReferenceMapping() | |
| 358 | { | |
| 359 | return [ | |
| 360 | ]; | |
| 361 | } |
| 368 | protected static function expression(string $string) | |
| 369 | { | |
| 370 | return new Expression($string); | |
| 371 | } |
| 379 | public function addEntityMapping(mixed $type = null): static | |
| 380 | { | |
| 381 | // Concrete query classes provide getEntityMapping(); not all declare MappingInterface. | |
| 382 | /** @psalm-suppress UndefinedMethod, TooManyArguments */ | |
| 383 | $entityMapping = $this->getPrefixedList($this->getEntityMapping($type)); | |
| 384 | $this->query->select($entityMapping); | |
| 385 | return $this; | |
| 386 | } |
| 388 | protected function getPrefixed($prefix): string | |
| 389 | { | |
| 390 | return $this->prefix . $prefix; | |
| 391 | } |
| 393 | protected function getPrefixedList(array $unprefixedList): array | |
| 394 | { | |
| 395 | $prefixed = []; | |
| 396 | foreach ($unprefixedList as $key => $value) { | |
| 397 | $prefixed[$this->getPrefixed($key)] = $value; | |
| 398 | } | |
| 399 | return $prefixed; | |
| 400 | } |
| 405 | protected function addReferenceMapping(): static | |
| 406 | { | |
| 407 | $referenceMapping = $this->getPrefixedList($this->getReferenceMapping()); | |
| 408 | $this->query->select($referenceMapping); | |
| 409 | return $this; | |
| 410 | } |
| 412 | public function addLimit(int $count, ?int $offset = null): static | |
| 413 | { | |
| 414 | $this->query->limit($count); | |
| 415 | if ($offset) { | |
| 416 | $this->query->offset($offset); | |
| 417 | } | |
| 418 | return $this; | |
| 419 | } |
| 424 | public function addValues(array $values): static | |
| 425 | { | |
| 426 | $this->query->values($values); | |
| 427 | return $this; | |
| 428 | } |
| 445 | public function postProcessJoins(array $data) | |
| 446 | { | |
| 447 | $data = $this->postProcess($data); | |
| 448 | foreach ($this->joinedQueryList as $query) { | |
| 449 | $data = $query->postProcess($data); | |
| 450 | } | |
| 451 | return $data; | |
| 452 | } |
| 454 | public function shouldLoadEntity(string $name): bool | |
| 455 | { | |
| 456 | if (empty($this->withEntities)) { | |
| 457 | return true; | |
| 458 | } | |
| 459 | ||
| 460 | return in_array($name, $this->withEntities); | |
| 461 | } |