Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
ProcessStatusFree
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
1 / 1
 buildDaysCondition
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace BO\Zmsbackend\Process\Repository;
4
5/**
6 *
7 */
8class 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}