allemployees.php
4 days ago
employee.php
4 days ago
group.php
4 days ago
groupext.php
4 days ago
index.html
4 days ago
service.php
4 days ago
groupext.php
239 lines
| 1 | <?php |
| 2 | /** |
| 3 | * @package VikAppointments |
| 4 | * @subpackage core |
| 5 | * @author E4J s.r.l. |
| 6 | * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved. |
| 7 | * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL |
| 8 | * @link https://vikwp.com |
| 9 | */ |
| 10 | |
| 11 | // No direct access |
| 12 | defined('ABSPATH') or die('No script kiddies please!'); |
| 13 | |
| 14 | VAPLoader::import('libraries.availability.timeline.parser.group'); |
| 15 | |
| 16 | /** |
| 17 | * Extended group timeline parser. |
| 18 | * |
| 19 | * @since 1.7.8 |
| 20 | */ |
| 21 | class VAPAvailabilityTimelineParserGroupext extends VAPAvailabilityTimelineParserGroup |
| 22 | { |
| 23 | /** |
| 24 | * Helper method used to elaborate the resulting timeline. |
| 25 | * |
| 26 | * @param string $date The UTC date in military format. |
| 27 | * @param integer $people The number of participants. |
| 28 | * @param array $worktime A list of working times. |
| 29 | * @param array $bookings A list of booked appointments. |
| 30 | * @param object $service The service details. |
| 31 | * @param mixed &$seats An array containing the remaining seats for each time. |
| 32 | * |
| 33 | * @return array The resulting timeline. |
| 34 | */ |
| 35 | protected function elaborateTimeLine($date, $people, $worktime, $bookings, $service, &$seats = null) |
| 36 | { |
| 37 | $arr = []; |
| 38 | $seats = $seats ?? []; |
| 39 | |
| 40 | // default one specified by the configuration |
| 41 | $min_int = VAPFactory::getConfig()->getUint('minuteintervals'); |
| 42 | |
| 43 | for ($i = 0; $i < count($worktime); $i++) |
| 44 | { |
| 45 | $arr[$i] = []; |
| 46 | |
| 47 | for ($j = $worktime[$i]->fromts; ($j + $min_int) <= $worktime[$i]->endts; $j += $min_int) |
| 48 | { |
| 49 | $arr[$i][$j] = 1; |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | // fetch default system timezone |
| 54 | $tz = JFactory::getApplication()->get('offset', 'UTC'); |
| 55 | |
| 56 | // re-format check-in date for correct comparison |
| 57 | $ymd = JFactory::getDate($date)->format('Y-m-d'); |
| 58 | |
| 59 | $cont_people = 0; |
| 60 | |
| 61 | foreach ($bookings as $k => $b) |
| 62 | { |
| 63 | if (!$b->timezone) |
| 64 | { |
| 65 | // use default system timezone |
| 66 | $b->timezone = $tz; |
| 67 | } |
| 68 | |
| 69 | // increase people count |
| 70 | $cont_people += $b->people_count; |
| 71 | |
| 72 | if ($k == count($bookings) - 1 || $bookings[$k + 1]->checkin_ts != $b->checkin_ts || $bookings[$k + 1]->timezone != $b->timezone) |
| 73 | { |
| 74 | // create check-in and adjust it to the employee timezone |
| 75 | $checkin = JFactory::getDate($b->checkin_ts); |
| 76 | $checkin->setTimezone(new DateTimeZone($b->timezone)); |
| 77 | |
| 78 | // get check-in time adjusted to local timezone |
| 79 | $from = $checkin->format('H:i', $local = true); |
| 80 | // convert time string in minutes |
| 81 | $from = JHtml::fetch('vikappointments.time2min', $from); |
| 82 | |
| 83 | /** |
| 84 | * Check the day factor of a reservation to check if it is referring |
| 85 | * to the current day or if it close to the bounds of this working time. |
| 86 | * Used to support midnight reservations. |
| 87 | * |
| 88 | * @since 1.6 |
| 89 | */ |
| 90 | |
| 91 | if ($checkin->format('Y-m-d', $local = true) > $ymd) |
| 92 | { |
| 93 | // we are evaluating a reservation for the next day, so we need to increase the |
| 94 | // initial time by 1440 minutes (24 hours * 60). |
| 95 | $from += 1440; |
| 96 | } |
| 97 | else if ($checkin->format('Y-m-d', $local = true) < $ymd) |
| 98 | { |
| 99 | // we are evaluating a reservation for the previous day, so we need to decrease the |
| 100 | // initial time by 1440 minutes (24 hours * 60). |
| 101 | $from -= 1440; |
| 102 | } |
| 103 | |
| 104 | // calculate end time by adding total duration to start time |
| 105 | $to = $from + $b->duration + $b->sleep; |
| 106 | |
| 107 | for ($i = $from; $i < $to; $i += $min_int) |
| 108 | { |
| 109 | $found = false; |
| 110 | |
| 111 | for ($j = 0; $j < count($arr) && !$found; $j++) |
| 112 | { |
| 113 | // calculate the number of occupied seats |
| 114 | $real_occupancy = $service->max_capacity - ($seats[$i] ?? $service->max_capacity) + $cont_people; |
| 115 | |
| 116 | /** |
| 117 | * Try to block appointments that come from a different service or |
| 118 | * if the number of people exceeds the total capacity. |
| 119 | * |
| 120 | * @since 1.6 check if the services are different only if $arr[$j][$i] is set |
| 121 | */ |
| 122 | if (!empty($arr[$j][$i]) && ($real_occupancy + $people > $service->max_capacity || $b->id_service != $service->id || $b->closure)) |
| 123 | { |
| 124 | $found = true; |
| 125 | $arr[$j][$i] = 0; |
| 126 | } |
| 127 | |
| 128 | if ($b->id_service == $service->id && !$b->closure) |
| 129 | { |
| 130 | if (!isset($seats[$i])) |
| 131 | { |
| 132 | $seats[$i] = $service->max_capacity; |
| 133 | } |
| 134 | |
| 135 | // same service, we can display the remaining seats |
| 136 | $seats[$i] = max(0, $seats[$i] - $cont_people); |
| 137 | } |
| 138 | else |
| 139 | { |
| 140 | // booked for a different service, unset the remaining seats |
| 141 | $seats[$i] = 0; |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | /** |
| 146 | * We may have different services that display shifted |
| 147 | * timelines. This would cause an issue as previous check |
| 148 | * ignores the times that don't match the evaluated slots. |
| 149 | * |
| 150 | * We need to unset here all the times that intersect with |
| 151 | * an existing reservation, which might have been created for |
| 152 | * a different service. |
| 153 | * |
| 154 | * @since 1.6.2 |
| 155 | */ |
| 156 | if (!$found) |
| 157 | { |
| 158 | // find all slots that intersect this one |
| 159 | for ($j = 0; $j < count($arr); $j++) |
| 160 | { |
| 161 | foreach ($arr[$j] as $arr_hm => &$v) |
| 162 | { |
| 163 | if (($from < $arr_hm && $arr_hm < $to) |
| 164 | || ($arr_hm < $from && $from < $arr_hm + $service->duration + $service->sleep)) |
| 165 | { |
| 166 | /** |
| 167 | * @todo evaluate to enhance this statement, because in case |
| 168 | * an appointment uses an increased duration, the exceeding |
| 169 | * slot are entirely turned off |
| 170 | */ |
| 171 | // $v = 0; |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | $cont_people = 0; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | $n_step = $service->duration + $service->sleep; |
| 183 | |
| 184 | // array deep : elaborate each timeline |
| 185 | for ($level = 0; $level < count($arr); $level++) |
| 186 | { |
| 187 | // get all the times in the current timeline |
| 188 | $keys = array_keys($arr[$level] ?? []); |
| 189 | // insert the end working time to evaluate properly the last available time |
| 190 | $keys[] = $worktime[$level]->endts; |
| 191 | |
| 192 | for ($i = 0; $i < count($keys) - 1; $i++) |
| 193 | { |
| 194 | $last_index = -1; |
| 195 | |
| 196 | for ($j = $i + 1; $j < count($keys) && $last_index == -1; $j++) |
| 197 | { |
| 198 | /** |
| 199 | * If index is last or if current time is not available. |
| 200 | * |
| 201 | * @since 1.6 Use empty($arr[$level][$keys[$j]]) to avoid "Undefined Index" notices. |
| 202 | * These notices may be raised when the reservations were stored for certain |
| 203 | * times that don't exist anymore. |
| 204 | */ |
| 205 | // if ($keys[$j] == count($keys) -1 || $arr[$level][$keys[$j]] == 0) |
| 206 | if ($keys[$j] == count($keys) -1 || empty($arr[$level][$keys[$j]])) |
| 207 | { |
| 208 | // store last index found and stop for statement |
| 209 | $last_index = $j; |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | // if subtraction of last index found with current index is not enough |
| 214 | if ($keys[$last_index] - $keys[$i] < $n_step) |
| 215 | { |
| 216 | // if current time is still available |
| 217 | if ($arr[$level][$keys[$i]] == 1) |
| 218 | { |
| 219 | // mark current time as no more available |
| 220 | $arr[$level][$keys[$i]] = 2; |
| 221 | } |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | $timeline = array(); |
| 227 | |
| 228 | foreach ($arr as $a) |
| 229 | { |
| 230 | foreach ($a as $hour => $val) |
| 231 | { |
| 232 | $timeline[$hour] = $val; |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | return $timeline; |
| 237 | } |
| 238 | } |
| 239 |