Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
CRAP | |
100.00% |
1 / 1 |
| ProcessStatusFree | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
| buildDaysCondition | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace BO\Zmsbackend\Process\Repository; |
| 4 | |
| 5 | /** |
| 6 | * |
| 7 | */ |
| 8 | class ProcessStatusFree extends \BO\Zmsbackend\Query\Base |
| 9 | { |
| 10 | /** |
| 11 | * Shared free-process query used by zmsadmin / classic free-slot APIs (same semantics as next). |
| 12 | * |
| 13 | * see also \BO\Zmsbackend\Day\Repository\Day::QUERY_DAYLIST_JOIN |
| 14 | */ |
| 15 | const QUERY_SELECT_PROCESSLIST_DAYS = ' |
| 16 | SELECT |
| 17 | -- tmp_avail.*, |
| 18 | "free" AS status, |
| 19 | CONCAT(year, "-", month, "-", day, " ", time) AS appointments__0__date, |
| 20 | slotsRequired AS appointments__0__slotCount, |
| 21 | scopeID AS scope__id |
| 22 | FROM |
| 23 | (SELECT |
| 24 | COUNT(slotID) as ancestorCount, |
| 25 | IF(MIN(available - confirmed) > 0, MIN(available - confirmed), 0) as free, |
| 26 | tmp_ancestor.* |
| 27 | FROM (SELECT |
| 28 | IFNULL(COUNT(p.slotID), 0) confirmed, |
| 29 | IF(:slotType = "intern", s.intern, |
| 30 | IF(:slotType = "public", s.`public`, 0) |
| 31 | ) available, |
| 32 | IF(a.erlaubemehrfachslots, c.slotsRequired, :forceRequiredSlots) slotsRequired, |
| 33 | s.*, |
| 34 | cc.id |
| 35 | FROM |
| 36 | calendarscope c |
| 37 | INNER JOIN slot s |
| 38 | ON c.scopeID = s.scopeID |
| 39 | %s |
| 40 | AND s.status = "free" |
| 41 | LEFT JOIN oeffnungszeit a ON s.availabilityID = a.OeffnungszeitID |
| 42 | LEFT JOIN slot_hiera h ON h.ancestorID = s.slotID |
| 43 | AND h.ancestorLevel <= IF(a.erlaubemehrfachslots, c.slotsRequired, :forceRequiredSlots) |
| 44 | INNER JOIN slot s2 on h.slotID = s2.slotID and s2.status = "free" |
| 45 | LEFT JOIN slot_process p ON h.slotID = p.slotID |
| 46 | LEFT JOIN closures cc ON (s.scopeID = cc.StandortID AND s.year = cc.year AND s.month = cc.month and s.day = cc.day) |
| 47 | GROUP BY s.slotID, h.slotID |
| 48 | HAVING cc.id IS NULL |
| 49 | ) AS tmp_ancestor |
| 50 | GROUP BY slotID |
| 51 | HAVING ancestorCount >= slotsRequired |
| 52 | ) AS tmp_avail |
| 53 | INNER JOIN slot_sequence sq ON sq.slotsequence <= tmp_avail.free |
| 54 | '; |
| 55 | |
| 56 | /** |
| 57 | * Citizen calendar-availability free-process query only. |
| 58 | * |
| 59 | * Occupancy is pre-aggregated from slot_process (same approach as Day::QUERY_DAYLIST_JOIN_AVAILABILITY). |
| 60 | * |
| 61 | * see also \BO\Zmsbackend\Day\Repository\Day::QUERY_DAYLIST_JOIN_AVAILABILITY |
| 62 | */ |
| 63 | const QUERY_SELECT_PROCESSLIST_DAYS_AVAILABILITY = ' |
| 64 | SELECT |
| 65 | -- tmp_avail.*, |
| 66 | "free" AS status, |
| 67 | CONCAT(year, "-", month, "-", day, " ", time) AS appointments__0__date, |
| 68 | slotsRequired AS appointments__0__slotCount, |
| 69 | scopeID AS scope__id |
| 70 | FROM |
| 71 | (SELECT |
| 72 | COUNT(slotID) as ancestorCount, |
| 73 | IF(MIN(available - confirmed) > 0, MIN(available - confirmed), 0) as free, |
| 74 | tmp_ancestor.* |
| 75 | FROM (SELECT |
| 76 | IFNULL(occ.confirmed, 0) confirmed, |
| 77 | IF(:slotType = "intern", s.intern, |
| 78 | IF(:slotType = "public", s.`public`, 0) |
| 79 | ) available, |
| 80 | IF(a.erlaubemehrfachslots, c.slotsRequired, :forceRequiredSlots) slotsRequired, |
| 81 | s.*, |
| 82 | cc.id |
| 83 | FROM |
| 84 | calendarscope c |
| 85 | INNER JOIN slot s |
| 86 | ON c.scopeID = s.scopeID |
| 87 | %s |
| 88 | AND s.status = "free" |
| 89 | LEFT JOIN oeffnungszeit a ON s.availabilityID = a.OeffnungszeitID |
| 90 | LEFT JOIN slot_hiera h ON h.ancestorID = s.slotID |
| 91 | AND h.ancestorLevel <= IF(a.erlaubemehrfachslots, c.slotsRequired, :forceRequiredSlots) |
| 92 | INNER JOIN slot s2 on h.slotID = s2.slotID and s2.status = "free" |
| 93 | LEFT JOIN ( |
| 94 | SELECT p.slotID, COUNT(*) AS confirmed |
| 95 | FROM slot_process p |
| 96 | INNER JOIN slot s_occ |
| 97 | ON s_occ.slotID = p.slotID |
| 98 | INNER JOIN calendarscope c_occ |
| 99 | ON c_occ.scopeID = s_occ.scopeID |
| 100 | AND c_occ.year = s_occ.year |
| 101 | AND c_occ.month = s_occ.month |
| 102 | GROUP BY p.slotID |
| 103 | ) occ ON occ.slotID = h.slotID |
| 104 | LEFT JOIN closures cc ON (s.scopeID = cc.StandortID AND s.year = cc.year AND s.month = cc.month and s.day = cc.day) |
| 105 | WHERE cc.id IS NULL |
| 106 | ) AS tmp_ancestor |
| 107 | GROUP BY slotID |
| 108 | HAVING ancestorCount >= slotsRequired |
| 109 | ) AS tmp_avail |
| 110 | INNER JOIN slot_sequence sq ON sq.slotsequence <= tmp_avail.free |
| 111 | '; |
| 112 | |
| 113 | const GROUPBY_SELECT_PROCESSLIST_DAY = 'GROUP BY scope__id, appointments__0__date'; |
| 114 | |
| 115 | public static function buildDaysCondition($days) |
| 116 | { |
| 117 | $sql = 'AND ('; |
| 118 | $sqlPats = []; |
| 119 | |
| 120 | foreach ($days as $day) { |
| 121 | $sqlPats[] = '(c.year = ' . $day->format('Y') . ' |
| 122 | AND c.month = ' . $day->format('m') . ' |
| 123 | AND s.day = ' . $day->format('d') . ' |
| 124 | AND c.year = s.year |
| 125 | AND c.month = s.month)'; |
| 126 | } |
| 127 | |
| 128 | return $sql . implode(' OR ', $sqlPats) . ')'; |
| 129 | } |
| 130 | } |