PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / trunk
VikAppointments Services Booking Calendar vtrunk
trunk 1.2.17 1.2.18 1.2.19
vikappointments / admin / models / calendar.php
vikappointments / admin / models Last commit date
apiban.php 4 years ago apilog.php 2 years ago apiplugin.php 4 years ago apiuser.php 2 years ago apiuseroptions.php 2 years ago backup.php 5 months ago caldays.php 1 month ago calendar.php 1 month ago city.php 4 years ago closure.php 1 month ago configapp.php 4 years ago configcldays.php 4 years ago configcron.php 4 years ago configemp.php 4 years ago configsmsapi.php 4 years ago configuration.php 5 months ago conversion.php 4 years ago country.php 2 years ago coupon.php 2 years ago couponemployee.php 4 years ago coupongroup.php 2 years ago couponservice.php 4 years ago cronjob.php 2 years ago cronjoblog.php 4 years ago customer.php 5 months ago customf.php 2 years ago customfservice.php 4 years ago customizer.php 4 years ago empgroup.php 2 years ago employee.php 2 years ago empsettings.php 4 years ago file.php 4 years ago findreservation.php 1 month ago group.php 2 years ago import.php 4 years ago index.html 4 years ago invoice.php 1 month ago langcustomf.php 4 years ago langempgroup.php 4 years ago langemployee.php 4 years ago langgroup.php 4 years ago langmedia.php 4 years ago langoption.php 2 years ago langoptiongroup.php 4 years ago langoptionvar.php 4 years ago langpackage.php 4 years ago langpackgroup.php 4 years ago langpayment.php 4 years ago langservice.php 4 years ago langstatuscode.php 4 years ago langsubscr.php 4 years ago langtax.php 2 years ago langtaxrule.php 4 years ago location.php 2 years ago mailtext.php 2 years ago makerecurrence.php 1 month ago media.php 2 years ago multiorder.php 1 month ago option.php 1 year ago optiongroup.php 2 years ago optionvar.php 1 year ago orderstatus.php 2 years ago package.php 2 years ago packageservice.php 4 years ago packgroup.php 2 years ago packorder.php 2 years ago packorderitem.php 1 month ago payment.php 2 years ago rate.php 2 years ago reportsemp.php 5 months ago reportsser.php 5 months ago reservation.php 1 month ago resoptassoc.php 2 years ago restriction.php 2 years ago review.php 3 years ago serempassoc.php 1 year ago seroptassoc.php 4 years ago serrateassoc.php 4 years ago serrestrassoc.php 4 years ago service.php 2 years ago state.php 2 years ago statswidget.php 2 years ago statuscode.php 2 years ago subscription.php 1 month ago subscrorder.php 1 month ago tag.php 4 years ago tax.php 2 years ago taxrule.php 2 years ago updateprogram.php 4 years ago usernote.php 2 years ago waitinglist.php 1 month ago webhook.php 1 year ago worktime.php 1 month ago
calendar.php
296 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.mvc.model');
15 VAPLoader::import('libraries.availability.manager');
16 VAPLoader::import('libraries.availability.timeline.factory');
17
18 /**
19 * VikAppointments calendar model.
20 *
21 * @since 1.7
22 */
23 class VikAppointmentsModelCalendar extends JModelVAP
24 {
25 /**
26 * Returns the structure of the calendar to display
27 * as tables of months.
28 *
29 * @param array $options An array of options.
30 *
31 * @return object The resulting calendar.
32 */
33 public function getCalendar(array $options = array())
34 {
35 $config = VAPFactory::getConfig();
36
37 // get first day of the week
38 $firstday = $config->getUint('firstday');
39
40 if (empty($options['numcal']))
41 {
42 // use default amount (12 months)
43 $options['numcal'] = 12;
44 }
45
46 if (!empty($options['date']) && (empty($options['start']) || $options['date'] > $options['start']))
47 {
48 // start the calendar from the first day of the month of the provided date
49 $options['start'] = JFactory::getDate($options['date'])->format('Y-m-01');
50 }
51 else
52 {
53 // make sure the starting date is always at the beginning of the month
54 $options['start'] = JFactory::getDate($options['start'] ?? 'now')->format('Y-m-01');
55 }
56
57 $days_shift = array();
58
59 for ($i = 0; $i < 7; $i++)
60 {
61 $days_shift[$i] = (6 - ($firstday - $i) + 1) % 7;
62 /**
63 * DAY = ( (NUM_DAYS - 1) - (SHIFT - DAY_INDEX) + 1 ) % NUM_DAYS
64 *
65 * SATURDAY
66 * 0 1 2 3 4 5 6
67 * 6-(6-0)+1%7=1 6-(6-1)+1%7=2 6-(6-2)+1%7=3 6-(6-3)+1%7=4 6-(6-4)+1%7=5 6-(6-5)+1%7=6 6-(6-6)+1%7=0
68 *
69 * SUNDAY
70 * 0 1 2 3 4 5 6
71 * 6-(0-0)+1%7=0 6-(0-1)+1%7=1 6-(0-2)+1%7=2 6-(0-3)+1%7=3 6-(0-4)+1%7=4 6-(0-5)+1%7=5 6-(0-6)+1%7=6
72 *
73 * MONDAY
74 * 0 1 2 3 4 5 6
75 * 6-(1-0)+1%7=6 6-(1-1)+1%7=0 6-(1-2)+1%7=1 6-(1-3)+1%7=2 6-(1-4)+1%7=3 6-(1-5)+1%7=4 6-(1-6)+1%7=5
76 *
77 * WEDNESDAY
78 * 0 1 2 3 4 5 6
79 * 6-(3-0)+1%7=4 6-(3-1)+1%7=5 6-(3-2)+1%7=6 6-(3-3)+1%7=0 6-(3-4)+1%7=1 6-(3-5)+1%7=2 6-(3-6)+1%7=3
80 */
81 }
82
83 // set initial date at midnight
84 $date = JFactory::getDate($options['start']);
85 $date->modify('00:00:00');
86
87 $calendar = new stdClass;
88
89 // fetch head
90 $calendar->head = array();
91
92 for ($i = 0; $i < 7; $i++)
93 {
94 $day = new stdClass;
95
96 // get the day of the week that should stay at this position
97 $day->wday = VikAppointments::getShiftedDay($i, $firstday);
98
99 $day->name = new stdClass;
100 $day->name->long = $date->dayToString($day->wday, false);
101 $day->name->short = $date->dayToString($day->wday, true);
102
103 $calendar->head[] = $day;
104 }
105
106 $calendar->months = array();
107
108 if (!isset($options['admin']))
109 {
110 // flag as administrator when not specified
111 $options['admin'] = true;
112 }
113
114 // create availability search object
115 $search = VAPAvailabilityManager::getInstance($options['id_ser'], $options['id_emp'], $options);
116
117 // iterate by the number of requested calendars
118 for ($cal = 0; $cal < $options['numcal']; $cal++)
119 {
120 $month = new stdClass;
121 $month->mon = (int) $date->format('n');
122 $month->year = (int) $date->format('Y');
123
124 $month->name = new stdClass;
125 $month->name->long = $date->monthToString($month->mon, $abbr = false);
126 $month->name->short = $date->monthToString($month->mon, $abbr = true);
127
128 $month->days = array();
129 $month->days[0] = array();
130
131 // iterate until we find the first day of the month
132 for ($i = 0, $n = $days_shift[(int) $date->format('w')]; $i < $n; $i++)
133 {
134 // add null element
135 $month->days[0][] = null;
136 }
137
138 // get number of days of this month
139 $mon_num_days = (int) $date->format('t');
140
141 $seek = 0;
142
143 for ($day = 1; $day <= $mon_num_days; $day++)
144 {
145 if (count($month->days[$seek]) == 7)
146 {
147 // add a new line
148 $month->days[] = array();
149 $seek++;
150 }
151
152 $d = new stdClass;
153 $d->day = $day;
154 $d->date = $date->format('Y-m-d');
155 $d->wday = (int) $date->format('w');
156
157 // calculate the availability of this day
158 $avail = $this->checkDayAvailability($d->date, $search);
159
160 // set open/closed status
161 $d->closed = $avail === false;
162 // register availability flag
163 $d->available = (int) $avail;
164
165 // add day
166 $month->days[$seek][] = $d;
167
168 // go to next day
169 $date->modify('+1 day');
170 }
171
172 // iterate until we fill the last row
173 while (count($month->days[$seek]) < 7)
174 {
175 // add null element
176 $month->days[$seek][] = null;
177 }
178
179 $calendar->months[] = $month;
180 }
181
182 return $calendar;
183 }
184
185 /**
186 * Calculates an approximative availability for the specified
187 * date, service and employee.
188 *
189 * @param string $date The UTC date string (military format).
190 * @param mixed $search An availability search instance.
191 *
192 * @return mixed False if closed, or an integer matching the availability
193 * status (0: closed, 1: available, 2: partially available).
194 */
195 public function checkDayAvailability($date, $search)
196 {
197 if (!$search->isAdmin())
198 {
199 // make sure the date is not in the past if we
200 // are checking the availability as customers
201 if ($search->isPastTime($date))
202 {
203 // date in the past
204 return false;
205 }
206 }
207
208 // check whether there's at least an employee offering
209 // the given service on the specified day
210 $open = $search->isDayOpen($date);
211
212 if (!$open)
213 {
214 // seems to be closed on this day
215 return false;
216 }
217
218 // calculate the availability status on this date
219 return $search->isDayAvailable($date);
220 }
221
222 /**
223 * Calculates the resulting availability timeline according
224 * to the specified search options.
225 *
226 * @param array $options An array of options.
227 *
228 * @return mixed The resulting renderer.
229 */
230 public function getTimeline($options)
231 {
232 // create availability search instance
233 $search = VAPAvailabilityManager::getInstance($options['id_ser'], $options['id_emp'], $options);
234 // grant administrator access
235 $search->set('admin', true);
236
237 // define default options
238 $options['people'] = isset($options['people']) ? $options['people'] : 1;
239 $options['id_res'] = isset($options['id_res']) ? $options['id_res'] : 0;
240
241 // number of people cannot be lower than 1
242 $options['people'] = max(array(1, (int) $options['people']));
243
244 try
245 {
246 if ($search->get('id_employee'))
247 {
248 // let the factory fetches the most-appropriate parser
249 $parser = null;
250 }
251 else
252 {
253 // for find reservation, use a different parser to access a
254 // list of timelines (one for each employee)
255 $parser = 'allemployees';
256 }
257
258 // create timeline parser instance
259 $parser = VAPAvailabilityTimelineFactory::getParser($search, $parser);
260 }
261 catch (Exception $e)
262 {
263 // register exception as error
264 $this->setError($e);
265
266 return false;
267 }
268
269 // elaborate timeline
270 $timeline = $parser->getTimeline($options['date'], $options['people'], $options['id_res']);
271
272 if (!$timeline)
273 {
274 // propagate error message
275 $this->setError($parser->getError());
276
277 return false;
278 }
279
280 try
281 {
282 // create timeline renderer instance
283 $renderer = VAPAvailabilityTimelineFactory::getRenderer($timeline);
284 }
285 catch (Exception $e)
286 {
287 // register exception as error
288 $this->setError($e);
289
290 return false;
291 }
292
293 return $renderer;
294 }
295 }
296