PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.17
VikAppointments Services Booking Calendar v1.2.17
trunk 1.2.17 1.2.18 1.2.19
vikappointments / admin / controllers / reservation.php
vikappointments / admin / controllers Last commit date
analytics.php 5 months ago apiban.php 5 months ago apilog.php 5 months ago apiplugin.php 5 months ago apiuser.php 5 months ago backup.php 5 months ago calendar.php 5 months ago city.php 5 months ago closure.php 5 months ago configapp.php 5 months ago configcldays.php 5 months ago configcron.php 5 months ago configemp.php 5 months ago configsmsapi.php 5 months ago configuration.php 5 months ago conversion.php 5 months ago country.php 5 months ago coupon.php 5 months ago coupongroup.php 5 months ago cronjob.php 5 months ago cronjoblog.php 5 months ago customer.php 5 months ago customf.php 5 months ago dashboard.php 5 months ago emplocwdays.php 5 months ago employee.php 5 months ago emprates.php 5 months ago export.php 5 months ago exportres.php 5 months ago file.php 5 months ago findreservation.php 5 months ago group.php 5 months ago import.php 5 months ago index.html 5 months ago invoice.php 5 months ago langcustomf.php 5 months ago langemployee.php 5 months ago langgroup.php 5 months ago langmedia.php 5 months ago langoption.php 5 months ago langoptiongroup.php 5 months ago langpackage.php 5 months ago langpackgroup.php 5 months ago langpayment.php 5 months ago langservice.php 5 months ago langstatuscode.php 5 months ago langsubscr.php 5 months ago langtax.php 5 months ago location.php 5 months ago mailtext.php 5 months ago makerecurrence.php 5 months ago media.php 5 months ago multiorder.php 5 months ago option.php 5 months ago optiongroup.php 5 months ago package.php 5 months ago packgroup.php 5 months ago packorder.php 5 months ago payment.php 5 months ago rate.php 5 months ago reportsemp.php 5 months ago reportsser.php 5 months ago reservation.php 5 months ago restriction.php 5 months ago review.php 5 months ago service.php 5 months ago serworkday.php 5 months ago state.php 5 months ago statuscode.php 5 months ago subscription.php 5 months ago subscrorder.php 5 months ago tag.php 5 months ago tax.php 5 months ago usernote.php 5 months ago waitinglist.php 5 months ago webhook.php 5 months ago wizard.php 5 months ago
reservation.php
925 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.controllers.admin');
15
16 /**
17 * VikAppointments appointment controller.
18 *
19 * @since 1.7
20 */
21 class VikAppointmentsControllerReservation extends VAPControllerAdmin
22 {
23 /**
24 * Task used to access the creation page of a new record.
25 *
26 * @return boolean
27 */
28 public function add()
29 {
30 $app = JFactory::getApplication();
31 $user = JFactory::getUser();
32
33 $data = array();
34 $data['id_service'] = $app->input->getUint('id_ser');
35 $data['id_employee'] = $app->input->getUint('id_emp');
36 $data['people'] = $app->input->getUint('people');
37 $data['day'] = $app->input->getString('day');
38
39 if (!empty($data['day']))
40 {
41 // get employee timezone
42 $tz = $this->getModel('employee')->getTimezone($data['id_employee']);
43
44 $h = $app->input->getUint('hour', 0);
45 $m = $app->input->getUint('min', 0);
46
47 // create date instance adjusted to employee timezone
48 $date = new JDate($data['day'] . " $h:$m:00", $tz);
49
50 // get check-in UTC
51 $data['checkin_ts'] = $date->toSql();
52 }
53
54 // strip missing information
55 $data = array_filter($data);
56
57 // unset user state for being recovered again
58 $app->setUserState('vap.reservation.data', $data);
59
60 // check user permissions
61 if (!$user->authorise('core.create', 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
62 {
63 // back to main list, not authorised to create records
64 $app->enqueueMessage(JText::translate('JERROR_ALERTNOAUTHOR'), 'error');
65 $this->cancel();
66
67 return false;
68 }
69
70 $url = 'index.php?option=com_vikappointments&view=managereservation';
71
72 // check whether a custom return view has been specified
73 $from = $app->input->get('from');
74
75 if ($from)
76 {
77 $url .= '&from=' . $from;
78 }
79
80 $this->setRedirect($url);
81
82 return true;
83 }
84
85 /**
86 * Task used to access the management page of an existing record.
87 *
88 * @return boolean
89 */
90 public function edit()
91 {
92 $app = JFactory::getApplication();
93 $user = JFactory::getUser();
94
95 $data = array();
96 $data['id_service'] = $app->input->getUint('id_ser');
97 $data['id_employee'] = $app->input->getUint('id_emp');
98 $data['people'] = $app->input->getUint('people');
99 $data['day'] = $app->input->getString('day');
100
101 if (!empty($data['day']))
102 {
103 // get employee timezone
104 $tz = $this->getModel('employee')->getTimezone($data['id_employee']);
105
106 $h = $app->input->getUint('hour', 0);
107 $m = $app->input->getUint('min', 0);
108
109 // create date instance adjusted to employee timezone
110 $date = new JDate($data['day'] . " $h:$m:00", $tz);
111
112 // get check-in UTC
113 $data['checkin_ts'] = $date->toSql();
114 }
115
116 // strip missing information
117 $data = array_filter($data);
118
119 // unset user state for being recovered again
120 $app->setUserState('vap.reservation.data', $data);
121
122 // check user permissions
123 if (!$user->authorise('core.edit', 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
124 {
125 // back to main list, not authorised to edit records
126 $app->enqueueMessage(JText::translate('JERROR_ALERTNOAUTHOR'), 'error');
127 $this->cancel();
128
129 return false;
130 }
131
132 $cid = $app->input->getUint('cid', array(0));
133
134 $url = 'index.php?option=com_vikappointments&view=managereservation&cid[]=' . $cid[0];
135
136 // check whether a custom return view has been specified
137 $from = $app->input->get('from');
138
139 if ($from)
140 {
141 $url .= '&from=' . $from;
142 }
143
144 $this->setRedirect($url);
145
146 return true;
147 }
148
149 /**
150 * Task used to save the record data set in the request.
151 * After saving, the user is redirected to the main list.
152 *
153 * @return void
154 */
155 public function saveclose()
156 {
157 if ($this->save())
158 {
159 $this->cancel();
160 }
161 }
162
163 /**
164 * Task used to save the record data set in the request.
165 * After saving, the user is redirected to the creation
166 * page of a new record.
167 *
168 * @return void
169 */
170 public function savenew()
171 {
172 if ($this->save())
173 {
174 $this->setRedirect('index.php?option=com_vikappointments&view=findreservation');
175 }
176 }
177
178 /**
179 * Task used to save the record data set in the request.
180 * After saving, the user is redirected to the management
181 * page of the record that has been saved.
182 *
183 * @return boolean
184 */
185 public function save()
186 {
187 $app = JFactory::getApplication();
188 $input = $app->input;
189 $user = JFactory::getUser();
190
191 /**
192 * Added token validation.
193 *
194 * @since 1.7
195 */
196 if (!JSession::checkToken())
197 {
198 // back to main list, missing CSRF-proof token
199 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
200 $this->cancel();
201
202 return false;
203 }
204
205 $args = array();
206
207 // get order details
208 $args['id'] = $input->getUint('id', 0);
209 $args['id_payment'] = $input->getUint('id_payment', 0);
210 $args['status'] = $input->getString('status', '');
211 $args['status_comment'] = $input->getString('comment', '');
212 $args['notifycust'] = $input->getBool('notifycust', false);
213 $args['notifyemp'] = $input->getBool('notifyemp', false);
214 $args['notifywl'] = $input->getBool('notifywl', false);
215 $args['notes'] = JComponentHelper::filterText($input->getRaw('notes', ''));
216
217 // get billing details
218 $args['id_user'] = $input->getUint('id_user', 0);
219 $args['purchaser_nominative'] = $input->getString('purchaser_nominative', '');
220 $args['purchaser_mail'] = $input->getString('purchaser_mail', '');
221 $args['purchaser_phone'] = $input->getString('purchaser_phone', '');
222 $args['purchaser_prefix'] = $input->getString('purchaser_prefix', '');
223 $args['purchaser_country'] = $input->getString('purchaser_country', '');
224
225 // get service details
226 $args['id_service'] = $input->getUint('id_service', 0);
227 $args['id_employee'] = $input->getUint('id_employee', 0);
228 $args['checkin_ts'] = $input->getString('checkin_ts', '');
229 $args['duration'] = $input->getUint('duration', 0);
230 $args['sleep'] = $input->getUint('sleep', 0);
231 $args['people'] = $input->getUint('people', 1);
232
233 // get order totals
234 $args['total_cost'] = $input->getFloat('total_cost', 0);
235 $args['total_net'] = $input->getFloat('total_net', 0);
236 $args['total_tax'] = $input->getFloat('total_tax', 0);
237 $args['payment_charge'] = $input->getFloat('payment_charge', 0);
238 $args['payment_tax'] = $input->getFloat('payment_tax', 0);
239
240 // get service totals
241 $args['service_price'] = $input->getFloat('service_price', 0);
242 $args['service_net'] = $input->getFloat('service_net', 0);
243 $args['service_tax'] = $input->getFloat('service_tax', 0);
244 $args['service_gross'] = $input->getFloat('service_gross', 0);
245 $args['tax_breakdown'] = $input->getString('tax_breakdown', '');
246
247 // get actions
248 $args['add_discount'] = $input->getString('add_discount', '');
249 $args['remove_discount'] = $input->getBool('remove_discount', false);
250
251 if ($args['add_discount'] === 'manual')
252 {
253 // fetch manual discount from request
254 $args['add_discount'] = $input->get('manual_discount', [], 'array');
255 }
256
257 // check whether the model should (re)validate the availability
258 $args['validate_availability'] = $input->getBool('validate_availability', false);
259
260 // import custom fields requestor and loader (as dependency)
261 VAPLoader::import('libraries.customfields.requestor');
262
263 // get relevant custom fields only
264 $_cf = VAPCustomFieldsLoader::getInstance()
265 ->ofEmployee($args['id_employee'])
266 ->forService($args['id_service'])
267 ->noSeparator()
268 ->noRequiredCheckbox()
269 ->fetch();
270
271 // load custom fields from request
272 $args['custom_f'] = VAPCustomFieldsRequestor::loadForm($_cf, $tmp, $strict = false);
273
274 // copy uploads into the apposite column
275 $args['uploads'] = $tmp['uploads'];
276
277 // register data fetched by the custom fields so that the reservation
278 // model is able to use them for saving purposes
279 $args['fields_data'] = $tmp;
280
281 $args['attendees'] = array();
282
283 /**
284 * Recover attendees custom fields.
285 *
286 * @since 1.7
287 */
288 for ($people = 0; $people < $args['people'] - 1; $people++)
289 {
290 // reset attendee array
291 $attendee = array();
292
293 // load custom fields from request for other attendees
294 $tmp = VAPCustomFieldsRequestor::loadFormAttendee($people + 1, $_cf, $attendee, $strict = false);
295 // inject attendee custom fields within the array containing the fetched rules
296 $attendee['fields'] = $tmp;
297
298 // register attendee
299 $args['attendees'][] = $attendee;
300 }
301
302 // get selected options
303 $args['options'] = $input->get('option_json', array(), 'array');
304 // load deleted options
305 $args['deletedOptions'] = $input->get('option_deleted', array(), 'uint');
306
307 $rule = 'core.' . ($args['id'] > 0 ? 'edit' : 'create');
308
309 // check user permissions
310 if (!$user->authorise($rule, 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
311 {
312 // back to main list, not authorised to create/edit records
313 $app->enqueueMessage(JText::translate('JERROR_ALERTNOAUTHOR'), 'error');
314 $this->cancel();
315
316 return false;
317 }
318
319 if ($args['notifycust'])
320 {
321 /**
322 * Loads any additional custom text to include within the e-mail notification.
323 *
324 * @since 1.6.5
325 */
326 $custMail = array();
327 $custMail['id'] = $input->getUint('custmail_id', 0);
328 $custMail['name'] = $input->getString('custmail_name', '');
329 $custMail['position'] = $input->getString('custmail_position', '');
330 $custMail['content'] = JComponentHelper::filterText($input->getRaw('custmail_content', ''));
331
332 if (!empty($custMail['name']) && !empty($custMail['content']))
333 {
334 // create new custom e-mail template (unpublished)
335 $custMail['published'] = 0;
336
337 // get e-mail text model
338 $custMailModel = $this->getModel('mailtext');
339 // attempt to create new mail text
340 $mail_id = $custMailModel->save($custMail);
341
342 if ($mail_id)
343 {
344 // inject selected custom e-mail within order details
345 // for being retrieved while generating the notification
346 $args['mail_custom_text'] = $mail_id;
347
348 /**
349 * Added the possibility to exclude the default mail custom texts.
350 *
351 * @since 1.6.6
352 */
353 $args['exclude_default_mail_texts'] = $input->getBool('exclude_default_mail_texts', false);
354 }
355 }
356 }
357
358 // get reservation model
359 $order = $this->getModel();
360
361 if ($args['id'] == 0)
362 {
363 VAPLoader::import('libraries.models.subscriptions');
364
365 // In case the service owns a cost and the system supports the subscriptions
366 // for the customers, always recalculate the totals. Ignore subscription benefits
367 // in case of updates, because the price might have been manually changed.
368 if ($args['service_price'] > 0 && $args['id_user'] > 0 && VAPSubscriptions::has())
369 {
370 // recalculate costs by unsetting the service price
371 $order->recalculateTotals($args);
372 }
373 }
374
375 // get packages order model
376 $package = JModelVAP::getInstance('packorder');
377
378 $can_redeem_pack = false;
379
380 $approved = JHtml::fetch('vaphtml.status.isapproved', 'appointments', $args['status']);
381
382 // attempt to redeem the package only in case the service has a cost
383 // and the status is approved
384 if ($args['service_price'] > 0 && !empty($args['id_user']) && $approved)
385 {
386 $count = $package->countRemaining($args['id_service'], $args['id_user']);
387
388 // in case the count of remaining packages is equals or higher than the selected
389 // number of people, we can redeem the packages
390 if ($count >= $args['people'])
391 {
392 // we can redeem the packages
393 $can_redeem_pack = true;
394
395 // recalculate costs by unsetting the service price
396 $order->recalculateTotals($args, 0.0);
397
398 // use a different status comment, if blank
399 if (empty($args['status_comment']))
400 {
401 $args['status_comment'] = 'VAP_STATUS_PACKAGE_REDEEMED';
402 }
403 }
404 }
405
406 // try to save arguments
407 $id = $order->save($args);
408
409 if (!$id)
410 {
411 // get string error
412 $error = $order->getError(null, true);
413
414 // update user state data by refactoring the options structure
415 $data = (array) $app->getUserState('vap.reservation.data', array());
416
417 if (!empty($data['options']))
418 {
419 foreach ($data['options'] as $i => $opt)
420 {
421 if (is_string($opt))
422 {
423 // JSON decode options
424 $data['options'][$i] = json_decode($opt);
425 }
426 }
427
428 // commit changes
429 $app->setUserState('vap.reservation.data', $data);
430 }
431
432 // display error message
433 $app->enqueueMessage(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $error), 'error');
434
435 $url = 'index.php?option=com_vikappointments&view=managereservation';
436
437 if ($args['id'])
438 {
439 $url .= '&cid[]=' . $args['id'];
440 }
441
442 // redirect to new/edit page
443 $this->setRedirect($url);
444
445 return false;
446 }
447
448 if ($can_redeem_pack)
449 {
450 // finally redeem the packages
451 $redeemed = $package->usePackages($id);
452
453 if ($redeemed)
454 {
455 // display message to the user
456 $app->enqueueMessage(JText::sprintf('VAPORDERREDEEMEDPACKS', $redeemed));
457 }
458 }
459
460 // display generic successful message
461 $app->enqueueMessage(JText::translate('JLIB_APPLICATION_SAVE_SUCCESS'));
462
463 // redirect to edit page
464 $this->setRedirect('index.php?option=com_vikappointments&task=reservation.edit&cid[]=' . $id);
465
466 return true;
467 }
468
469 /**
470 * Deletes a list of records set in the request.
471 *
472 * @return boolean
473 */
474 public function delete()
475 {
476 $app = JFactory::getApplication();
477 $user = JFactory::getUser();
478
479 /**
480 * Added token validation.
481 * Both GET and POST are supported.
482 *
483 * @since 1.7
484 */
485 if (!JSession::checkToken() && !JSession::checkToken('get'))
486 {
487 // back to main list, missing CSRF-proof token
488 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
489 $this->cancel();
490
491 return false;
492 }
493
494 $cid = $app->input->get('cid', array(), 'uint');
495
496 // check user permissions
497 if (!$user->authorise('core.delete', 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
498 {
499 // back to main list, not authorised to delete records
500 $app->enqueueMessage(JText::translate('JERROR_ALERTNOAUTHOR'), 'error');
501 $this->cancel();
502
503 return false;
504 }
505
506 // delete selected records
507 $this->getModel()->delete($cid);
508
509 // back to main list
510 $this->cancel();
511
512 return true;
513 }
514
515 /**
516 * Redirects the users to the main records list.
517 *
518 * @return void
519 */
520 public function cancel()
521 {
522 $input = JFactory::getApplication()->input;
523
524 // check whether a custom return view has been specified
525 $view = $input->get('from');
526
527 if (!$view)
528 {
529 // back to appointments list by default
530 $view = 'reservations';
531 }
532
533 $this->setRedirect('index.php?option=com_vikappointments&view=' . $view);
534 }
535
536 /**
537 * Task used to send an e-mail notification to the customer
538 * of the specified appointment.
539 *
540 * @return void
541 */
542 public function notify()
543 {
544 $app = JFactory::getApplication();
545 $input = $app->input;
546 $user = JFactory::getUser();
547
548 /**
549 * Added token validation.
550 * Both GET and POST are supported.
551 *
552 * @since 1.7
553 */
554 if (!JSession::checkToken() && !JSession::checkToken('get'))
555 {
556 // back to main list, missing CSRF-proof token
557 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
558 $this->cancel();
559
560 return false;
561 }
562
563 // check user permissions
564 if (!$user->authorise('core.edit.state', 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
565 {
566 // back to main list, not authorised to send e-mail notifications
567 $app->enqueueMessage(JText::translate('JERROR_ALERTNOAUTHOR'), 'error');
568 $this->cancel();
569
570 return false;
571 }
572
573 $ids = $input->getUint('cid', array(0), 'uint');
574
575 // get appointment model
576 $model = $this->getModel();
577
578 $errors = array();
579
580 foreach ($ids as $id)
581 {
582 // try to send e-mail notification
583 if (!$model->sendEmailNotification($id))
584 {
585 // get string error
586 $error = $model->getError(null, true);
587
588 // enqueue error message
589 $errors[] = $error ? $error : JText::translate('VAPNOTIFYCUSTERR');
590 }
591 }
592
593 if ($errors)
594 {
595 // display duplicate error messages only once
596 foreach (array_unique($errors) as $err)
597 {
598 $app->enqueueMessage($err, 'error');
599 }
600 }
601 else
602 {
603 // display successful message
604 $app->enqueueMessage(JText::translate('VAPNOTIFYCUSTOK'));
605 }
606
607 // back to main list
608 $this->cancel();
609 }
610
611 /**
612 * Task used to send a SMS notification to the customer
613 * of the specified appointment.
614 *
615 * @return void
616 */
617 public function sendsms()
618 {
619 $app = JFactory::getApplication();
620 $input = $app->input;
621 $user = JFactory::getUser();
622
623 /**
624 * Added token validation.
625 * Both GET and POST are supported.
626 *
627 * @since 1.7
628 */
629 if (!JSession::checkToken() && !JSession::checkToken('get'))
630 {
631 // back to main list, missing CSRF-proof token
632 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
633 $this->cancel();
634
635 return false;
636 }
637
638 // check user permissions
639 if (!$user->authorise('core.edit.state', 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
640 {
641 // back to main list, not authorised to send SMS notifications
642 $app->enqueueMessage(JText::translate('JERROR_ALERTNOAUTHOR'), 'error');
643 $this->cancel();
644
645 return false;
646 }
647
648 $ids = $input->getUint('cid', array(0), 'uint');
649
650 // get appointment model
651 $model = $this->getModel();
652
653 $notified = 0;
654 $errors = array();
655
656 foreach ($ids as $id)
657 {
658 // try to send SMS notification
659 if ($model->sendSmsNotification($id))
660 {
661 $notified++;
662 }
663 else
664 {
665 // get string error
666 $error = $model->getError(null, true);
667
668 // enqueue error message
669 $errors[] = $error;
670 }
671 }
672
673 if ($notified)
674 {
675 // successful message
676 $app->enqueueMessage(JText::plural('VAPCUSTOMERSMSSENT', $notified));
677 }
678 else
679 {
680 // no notifications sent
681 $app->enqueueMessage(JText::plural('VAPCUSTOMERSMSSENT', $notified), 'warning');
682 }
683
684 // display any returned errors
685 if ($errors)
686 {
687 // do not display duplicate or empty errors
688 $errors = array_unique(array_filter($errors));
689
690 foreach ($errors as $err)
691 {
692 $app->enqueueMessage($err, 'error');
693 }
694 }
695
696 // back to main list
697 $this->cancel();
698 }
699
700 /**
701 * AJAX end-point used to change the status code.
702 * The task expects the following arguments to be set in request.
703 *
704 * @param integer id The appointment ID.
705 * @param string status The new status code.
706 * @param string layout The layout to use (for return).
707 *
708 * @return void
709 */
710 public function changestatusajax()
711 {
712 $input = JFactory::getApplication()->input;
713 $user = JFactory::getUser();
714
715 /**
716 * Added token validation.
717 *
718 * @since 1.7
719 */
720 if (!JSession::checkToken())
721 {
722 // missing CSRF-proof token
723 UIErrorFactory::raiseError(403, JText::translate('JINVALID_TOKEN'));
724 }
725
726 $data = array();
727 $data['id'] = $input->getUint('id');
728 $data['status'] = $input->getString('status');
729
730 // check user permissions
731 if (!$data['id'] || !$user->authorise('core.edit.state', 'com_vikappointments') || !$user->authorise('core.access.reservations', 'com_vikappointments'))
732 {
733 // not authorised to edit records
734 UIErrorFactory::raiseError(403, JText::translate('JERROR_ALERTNOAUTHOR'));
735 }
736
737 // get status code details
738 $code = JHtml::fetch('vaphtml.status.find', '*', array('code' => $data['status']), $limit = true);
739
740 if (!$code)
741 {
742 // code not found
743 UIErrorFactory::raiseError(404, JText::translate('JGLOBAL_NO_MATCHING_RESULTS'));
744 }
745
746 // register comment for status change
747 $data['status_comment'] = 'VAP_STATUS_CHANGED_FROM_LIST';
748
749 /**
750 * Always include the flag to process the waiting list.
751 * The model will then make sure that the new status is actually cancelled.
752 *
753 * @since 1.7.7
754 */
755 $data['notifywl'] = true;
756
757 $model = $this->getModel();
758
759 // update status
760 $model->save($data);
761
762 /**
763 * Automatically send a notification to the customer according to the mailing preferences.
764 *
765 * @since 1.7.7
766 */
767 if (VAPFactory::getConfig()->getBool('notifyonstatuschange'))
768 {
769 try
770 {
771 // send e-mail notification to the customer
772 $model->sendEmailNotification($data['id'], [
773 // validate e-mail rules before sending
774 'check' => true,
775 ]);
776 }
777 catch (Exception $error)
778 {
779 // go ahead silently
780 }
781 }
782
783 // render HTML
784 $code->html = JHtml::fetch('vaphtml.status.display', $code, $input->getString('layout'));
785
786 // send code to caller
787 $this->sendJSON($code);
788 }
789
790 /**
791 * AJAX end-point used return a list of employees available for the
792 * specified check-in arguments.
793 *
794 * @param integer id_employee The currently set employee ID.
795 * @param integer id_service The service ID.
796 * @param string checkin_ts The appointment check-in.
797 * @param integer people The number of attendees.
798 *
799 * @return void
800 */
801 public function employeespreviewajax()
802 {
803 $input = JFactory::getApplication()->input;
804
805 if (!JSession::checkToken())
806 {
807 // missing CSRF-proof token
808 UIErrorFactory::raiseError(403, JText::translate('JINVALID_TOKEN'));
809 }
810
811 $args = array();
812 $args['id_service'] = $input->getUint('id_service', 0);
813 $args['checkin_ts'] = $input->getString('checkin_ts', '');
814 $args['people'] = $input->getUint('people', 0);
815
816 $curr_employee = $input->getUint('id_employee', 0);
817
818 // load all employees assigned to the specified service
819 $employees = $this->getModel('service')->getEmployees($args['id_service']);
820
821 if (!$employees)
822 {
823 // no employees, raise error
824 UIErrorFactory::raiseError(404, 'No employees found');
825 }
826
827 // get reservation model
828 $model = $this->getModel();
829
830 $lookup = array();
831
832 // iterate all employees and validate availability one by one
833 foreach ($employees as $employee)
834 {
835 // prepare lookup data
836 $tmp = array(
837 'id' => $employee->id,
838 'name' => $employee->nickname,
839 );
840
841 if ($employee->id == $curr_employee)
842 {
843 // always available the currently set employee
844 $tmp['status'] = true;
845 }
846 else
847 {
848 // update search query with current employee ID
849 $args['id_employee'] = $employee->id;
850 // validate employee availability
851 $tmp['status'] = $model->isAvailable($args);
852 }
853
854 // register result
855 $lookup[] = $tmp;
856 }
857
858 // send response to caller
859 $this->sendJSON($lookup);
860 }
861
862 /**
863 * AJAX end-point used to change the check-in of the selected appointment.
864 *
865 * @param integer id The appointment ID.
866 * @param string checkin_ts The appointment check-in.
867 *
868 * @return void
869 */
870 public function changecheckinajax()
871 {
872 $input = JFactory::getApplication()->input;
873
874 if (!JSession::checkToken())
875 {
876 // missing CSRF-proof token
877 UIErrorFactory::raiseError(403, JText::translate('JINVALID_TOKEN'));
878 }
879
880 $args = array();
881 $args['id'] = $input->getUint('id', 0);
882 $args['checkin_ts'] = $input->getString('checkin_ts', '');
883 $args['duration'] = $input->getUint('duration', null);
884
885 // get reservation model
886 $model = $this->getModel();
887
888 // get reservation details
889 $item = $model->getItem($args['id']);
890
891 if (!$item)
892 {
893 // no appointment, raise error
894 UIErrorFactory::raiseError(404, 'Appointment not found');
895 }
896
897 $args['id_employee'] = $item->id_employee;
898 $args['id_service'] = $item->id_service;
899 $args['people'] = $item->people;
900 $args['sleep'] = $item->sleep;
901
902 if (!$args['duration'])
903 {
904 // use default duration
905 $args['duration'] = $item->duration;
906 }
907
908 // make sure the appointment is still available
909 $args['validate_availability'] = true;
910
911 // attempt to apply the changes
912 if (!$model->save($args))
913 {
914 // get registered error message
915 $error = $model->getError($index = null, $string = true);
916
917 // propagate error to caller
918 UIErrorFactory::raiseError(500, $error);
919 }
920
921 // send response to caller
922 $this->sendJSON(1);
923 }
924 }
925