1: <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2:
3: class Appointments extends CI_Controller {
4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: public function index($appointment_hash = '') {
15: if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') {
16: $this->load->model('Settings_Model');
17: $this->load->model('Services_Model');
18: $this->load->model('Providers_Model');
19:
20: $company_name = $this->Settings_Model->get_setting('company_name');
21: $available_services = $this->Services_Model->get_available_services();
22: $available_providers = $this->Providers_Model->get_available_providers();
23:
24:
25:
26: if ($appointment_hash !== ''){
27:
28: $this->load->model('Appointments_Model');
29: $this->load->model('Customers_Model');
30:
31: $manage_mode = TRUE;
32:
33: $appointment_data = $this->Appointments_Model
34: ->get_batch(array('hash' => $appointment_hash))[0];
35: $provider_data = $this->Providers_Model
36: ->get_row($appointment_data['id_users_provider']);
37: $customer_data = $this->Customers_Model
38: ->get_row($appointment_data['id_users_customer']);
39: } else {
40:
41:
42: $manage_mode = FALSE;
43: $appointment_data = array();
44: $provider_data = array();
45: $customer_data = array();
46: }
47:
48:
49: $view_data = array (
50: 'available_services' => $available_services,
51: 'available_providers' => $available_providers,
52: 'company_name' => $company_name,
53: 'manage_mode' => $manage_mode,
54: 'appointment_data' => $appointment_data,
55: 'provider_data' => $provider_data,
56: 'customer_data' => $customer_data
57: );
58: $this->load->view('appointments/book', $view_data);
59: } else {
60:
61:
62:
63: $post_data = json_decode($_POST['post_data'], true);
64: $appointment_data = $post_data['appointment'];
65: $customer_data = $post_data['customer'];
66:
67: $this->load->model('Customers_Model');
68: $this->load->model('Appointments_Model');
69: $this->load->model('Services_Model');
70: $this->load->model('Providers_Model');
71: $this->load->model('Settings_Model');
72:
73: $customer_id = $this->Customers_Model->add($customer_data);
74: $appointment_data['id_users_customer'] = $customer_id;
75: $appointment_data['id'] = $this->Appointments_Model->add($appointment_data);
76: $appointment_data['hash'] = $this->Appointments_Model
77: ->get_value('hash', $appointment_data['id']);
78:
79:
80: $this->load->library('Notifications');
81: try {
82: if (!$post_data['manage_mode']) {
83: $customer_title = 'Your appointment has been successfully booked!';
84: $provider_title = 'A new appointment has been added to your plan.';
85: } else {
86: $customer_title = 'Appointment Changes Saved Successfully!';
87: $provider_title = 'Appointment Details Have Changed';
88: }
89:
90: $this->notifications->send_book_success(
91: $customer_data, $appointment_data, $customer_title);
92: $this->notifications->send_new_appointment(
93: $customer_data, $appointment_data, $provider_title);
94:
95: } catch (NotificationException $not_exc) {
96: $view_data['notification_error'] = '<br><br>'
97: . '<pre>An unexpected error occured while sending you an '
98: . 'email. Please backup the appointment details so that '
99: . 'you can restore them later. <br><br>Error: <br>'
100: . $not_exc->getMessage() . '</pre>';
101: }
102:
103:
104:
105: $google_sync = $this->Providers_Model->get_setting('google_sync',
106: $appointment_data['id_users_provider']);
107:
108: if ($google_sync == TRUE) {
109: $google_token = $this->Providers_Model->get_setting('google_token',
110: $appointment_data['id_users_provider']);
111:
112:
113:
114: $this->load->library('google_sync');
115:
116: if ($this->google_sync->authenticate($google_token) === TRUE) {
117: if ($manage_mode === FALSE) {
118:
119: $this->google_sync->add_appointment($appointment_data['id']);
120: } else {
121:
122: $this->google_sync->update_appointment($appointment_data['id']);
123: }
124: }
125: }
126:
127:
128: $service_data = $this->Services_Model->get_row($appointment_data['id_services']);
129: $provider_data = $this->Providers_Model->get_row($appointment_data['id_users_provider']);
130: $company_name = $this->Settings_Model->get_setting('company_name');
131:
132: $view_data = array(
133: 'appointment_data' => $appointment_data,
134: 'service_data' => $service_data,
135: 'provider_data' => $provider_data,
136: 'company_name' => $company_name
137: );
138:
139: $this->load->view('appointments/book_success', $view_data);
140: }
141: }
142:
143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153:
154: public function cancel($appointment_hash) {
155: try {
156: $this->load->model('Appointments_Model');
157: $this->load->model('Providers_Model');
158: $this->load->model('Customers_Model');
159:
160:
161: $records = $this->Appointments_Model->get_batch(array('hash' => $appointment_hash));
162: if (count($records) == 0) {
163: throw new Exception('No record matches the provided hash.');
164: }
165:
166: $appointment_data = $records[0];
167:
168:
169: if (!$this->Appointments_Model->delete($appointment_data['id'])) {
170: throw new Exception('Appointment could not be deleted from the database.');
171: }
172:
173:
174: $provider_email = $this->Providers_Model->get_value('email',
175: $appointment_data['id_users_provider']);
176: $customer_email = $this->Customers_Model->get_value('email',
177: $appointment_data['id_users_customer']);
178:
179: $this->load->library('Notifications');
180: $this->notifications->send_cancel_appointment($appointment_data, $provider_email);
181: $this->notifications->send_cancel_appointment($appointment_data, $customer_email);
182:
183:
184: if ($appointment_data['id_google_calendar'] != NULL) {
185: $google_sync = $this->Providers_Model->get_setting('google_sync',
186: $appointment_data['id_users_provider']);
187:
188: if ($google_sync == TRUE) {
189: $this->load->library('google_sync');
190:
191:
192:
193: $google_token = $this->Providers_Model->get_setting('google_token',
194: $appointment_data['id_users_provider']);
195:
196: if ($this->google_sync->authendicate($google_token) === TRUE) {
197: $this->google_sync->delete_appointment($appointment_data['id']);
198: }
199: }
200: }
201: } catch(Exception $exc) {
202:
203: $view_data['error_message'] = $exc->getMessage();
204: }
205:
206: $this->load->view('appointments/cancel');
207: }
208:
209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219:
220: public function ajax_get_available_hours() {
221: $this->load->model('Providers_Model');
222: $this->load->model('Appointments_Model');
223: $this->load->model('Settings_Model');
224:
225:
226: $working_plan = json_decode($this->Providers_Model
227: ->get_setting('working_plan', $_POST['provider_id']), true);
228:
229: $where_clause = array(
230: 'DATE(start_datetime)' => date('Y-m-d', strtotime($_POST['selected_date'])),
231: 'id_users_provider' => $_POST['provider_id']
232: );
233:
234: $reserved_appointments = $this->Appointments_Model->get_batch($where_clause);
235:
236: if ($_POST['manage_mode'] === 'true') {
237:
238:
239: foreach($reserved_appointments as $index=>$appointment) {
240: if ($appointment['id'] == $_POST['appointment_id']) {
241: unset($reserved_appointments[$index]);
242: }
243: }
244: }
245:
246:
247:
248:
249: $sel_date_working_plan = $working_plan[strtolower(date('l',
250: strtotime($_POST['selected_date'])))];
251: $empty_spaces_with_breaks = array();
252:
253: if (isset($sel_date_working_plan['breaks'])) {
254: foreach($sel_date_working_plan['breaks'] as $index=>$break) {
255:
256:
257: $last_break_index = $index - 1;
258:
259: if (count($empty_spaces_with_breaks) === 0) {
260: $start_hour = $sel_date_working_plan['start'];
261: $end_hour = $break['start'];
262: } else {
263: $start_hour = $sel_date_working_plan['breaks'][$last_break_index]['end'];
264: $end_hour = $break['start'];
265: }
266:
267: $empty_spaces_with_breaks[] = array(
268: 'start' => $start_hour,
269: 'end' => $end_hour
270: );
271: }
272:
273:
274: $empty_spaces_with_breaks[] = array(
275: 'start' => $sel_date_working_plan['breaks'][$index]['end'],
276: 'end' => $sel_date_working_plan['end']
277: );
278: }
279:
280:
281: $empty_spaces_with_appointments = array();
282: if (count($reserved_appointments) > 0) {
283: foreach($empty_spaces_with_breaks as $space) {
284: foreach($reserved_appointments as $index=>$appointment) {
285: $appointment_start = date('H:i', strtotime($appointment['start_datetime']));
286: $appointment_end = date('H:i', strtotime($appointment['end_datetime']));
287: $space_start = date('H:i', strtotime($space['start']));
288: $space_end = date('H:i', strtotime($space['end']));
289:
290: if ($space_start < $appointment_start && $space_end > $appointment_end) {
291:
292:
293:
294: $empty_spaces_with_appointments[] = array(
295: 'start' => $space_start,
296: 'end' => $appointment_start
297: );
298: $empty_spaces_with_appointments[] = array(
299: 'start' => $appointment_end,
300: 'end' => $space_end
301: );
302: } else {
303:
304:
305: $found = FALSE;
306: foreach($reserved_appointments as $appt) {
307: $appt_start = date('H:i', strtotime($appt['start_datetime']));
308: $appt_end = date('H:i', strtotime($appt['end_datetime']));
309: if ($space_start < $appt_start && $space_end > $appt_end) {
310: $found = TRUE;
311: }
312: }
313:
314:
315:
316: $empty_space = array(
317: 'start' => $space_start,
318: 'end' => $space_end
319: );
320: $already_exist = in_array($empty_space, $empty_spaces_with_appointments);
321: if ($found === FALSE && $already_exist === FALSE) {
322: $empty_spaces_with_appointments[] = $empty_space;
323: }
324: }
325: }
326: }
327: } else {
328: $empty_spaces_with_appointments = $empty_spaces_with_breaks;
329: }
330:
331: $empty_spaces = $empty_spaces_with_appointments;
332:
333:
334:
335:
336:
337: $available_hours = array();
338:
339: foreach($empty_spaces as $space) {
340: $start_hour = new DateTime($_POST['selected_date'] . ' ' . $space['start']);
341: $end_hour = new DateTime($_POST['selected_date'] . ' ' . $space['end']);
342:
343: $minutes = $start_hour->format('i');
344:
345: if ($minutes % 15 != 0) {
346:
347:
348: if ($minutes < 15) {
349: $start_hour->setTime($start_hour->format('H'), 15);
350: } else if ($minutes < 30) {
351: $start_hour->setTime($start_hour->format('H'), 30);
352: } else if ($minutes < 45) {
353: $start_hour->setTime($start_hour->format('H'), 45);
354: } else {
355: $start_hour->setTime($start_hour->format('H') + 1, 00);
356: }
357: }
358:
359: $curr_hour = $start_hour;
360:
361: $diff = $curr_hour->diff($end_hour);
362: while(($diff->h * 60 + $diff->i) > intval($_POST['service_duration'])) {
363: $available_hours[] = $curr_hour->format('H:i');
364: $curr_hour->add(new DateInterval("PT15M"));
365: $diff = $curr_hour->diff($end_hour);
366: }
367: }
368:
369:
370:
371:
372:
373:
374: if (date('m/d/Y', strtotime($_POST['selected_date'])) == date('m/d/Y')) {
375: if ($_POST['manage_mode'] === 'true') {
376: $book_advance_timeout = 0;
377: } else {
378: $book_advance_timeout = $this->Settings_Model
379: ->get_setting('book_advance_timeout');
380: }
381:
382: foreach($available_hours as $index=>$value) {
383: $available_hour = strtotime($value);
384: $current_hour = strtotime('+' . $book_advance_timeout
385: . ' minutes', strtotime('now'));
386:
387: if ($available_hour <= $current_hour) {
388: unset($available_hours[$index]);
389: }
390: }
391: }
392:
393: $available_hours = array_values($available_hours);
394:
395: echo json_encode($available_hours);
396: }
397: }
398:
399:
400: