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:
70: $customer_id = $this->Customers_Model->add($customer_data);
71: $appointment_data['id_users_customer'] = $customer_id;
72: $appointment_data['id'] = $this->Appointments_Model->add($appointment_data);
73: $appointment_data['hash'] = $this->Appointments_Model
74: ->get_value('hash', $appointment_data['id']);
75:
76:
77: $this->load->library('Notifications');
78: try {
79: if (!$post_data['manage_mode']) {
80: $customer_title = 'Your appointment has been successfully booked!';
81: $provider_title = 'A new appointment has been added to your plan.';
82: } else {
83: $customer_title = 'Appointment changes saved successfully!';
84: $provider_title = 'Appointment details have changed.';
85: }
86:
87: $this->notifications->send_book_success(
88: $customer_data, $appointment_data, $customer_title);
89: $this->notifications->send_new_appointment(
90: $customer_data, $appointment_data, $provider_title);
91:
92: } catch (NotificationException $not_exc) {
93: $view_data['notification_error'] = '<br><br>'
94: . '<pre>An unexpected error occured while sending you an '
95: . 'email. Please backup the appointment details so that '
96: . 'you can restore them later. <br><br>Error: <br>'
97: . $not_exc->getMessage() . '</pre>';
98: }
99:
100:
101: $view_data['appointment_id'] = $appointment_data['id'];
102: $this->load->view('appointments/book_success', $view_data);
103: }
104: }
105:
106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116:
117: public function cancel($appointment_hash) {
118: try {
119: $this->load->model('Appointments_Model');
120: $this->load->model('Providers_Model');
121: $this->load->model('Customers_Model');
122:
123:
124: $records = $this->Appointments_Model->get_batch(array('hash' => $appointment_hash));
125: if (count($records) == 0) {
126: throw new Exception('No record matches the provided hash.');
127: }
128:
129: $appointment_data = $records[0];
130:
131:
132: if (!$this->Appointments_Model->delete($appointment_data['id'])) {
133: throw new Exception('Appointment could not be deleted from the database.');
134: }
135:
136:
137: $provider_email = $this->Providers_Model->get_value('email',
138: $appointment_data['id_users_provider']);
139: $customer_email = $this->Customers_Model->get_value('email',
140: $appointment_data['id_users_customer']);
141:
142: $this->load->library('Notifications');
143: $this->notifications->send_cancel_appointment($appointment_data, $provider_email);
144: $this->notifications->send_cancel_appointment($appointment_data, $customer_email);
145:
146: } catch(Exception $exc) {
147:
148: $view_data['error_message'] = $exc->getMessage();
149: }
150:
151: $this->load->view('appointments/cancel');
152: }
153:
154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164:
165: public function ajax_get_available_hours() {
166: $this->load->model('Providers_Model');
167: $this->load->model('Appointments_Model');
168: $this->load->model('Settings_Model');
169:
170:
171: $working_plan = json_decode($this->Providers_Model
172: ->get_setting('working_plan', $_POST['provider_id']), true);
173:
174: $where_clause = array(
175: 'DATE(start_datetime)' => date('Y-m-d', strtotime($_POST['selected_date'])),
176: 'id_users_provider' => $_POST['provider_id']
177: );
178:
179: $reserved_appointments = $this->Appointments_Model->get_batch($where_clause);
180:
181: if ($_POST['manage_mode'] === 'true') {
182:
183:
184: foreach($reserved_appointments as $index=>$appointment) {
185: if ($appointment['id'] == $_POST['appointment_id']) {
186: unset($reserved_appointments[$index]);
187: }
188: }
189: }
190:
191:
192:
193:
194: $sel_date_working_plan = $working_plan[strtolower(date('l',
195: strtotime($_POST['selected_date'])))];
196: $empty_spaces_with_breaks = array();
197:
198: if (isset($sel_date_working_plan['breaks'])) {
199: foreach($sel_date_working_plan['breaks'] as $index=>$break) {
200:
201:
202: $last_break_index = $index - 1;
203:
204: if (count($empty_spaces_with_breaks) === 0) {
205: $start_hour = $sel_date_working_plan['start'];
206: $end_hour = $break['start'];
207: } else {
208: $start_hour = $sel_date_working_plan['breaks'][$last_break_index]['end'];
209: $end_hour = $break['start'];
210: }
211:
212: $empty_spaces_with_breaks[] = array(
213: 'start' => $start_hour,
214: 'end' => $end_hour
215: );
216: }
217:
218:
219: $empty_spaces_with_breaks[] = array(
220: 'start' => $sel_date_working_plan['breaks'][$index]['end'],
221: 'end' => $sel_date_working_plan['end']
222: );
223: }
224:
225:
226: $empty_spaces_with_appointments = array();
227: if (count($reserved_appointments) > 0) {
228: foreach($empty_spaces_with_breaks as $space) {
229: foreach($reserved_appointments as $index=>$appointment) {
230: $appointment_start = date('H:i', strtotime($appointment['start_datetime']));
231: $appointment_end = date('H:i', strtotime($appointment['end_datetime']));
232: $space_start = date('H:i', strtotime($space['start']));
233: $space_end = date('H:i', strtotime($space['end']));
234:
235: if ($space_start < $appointment_start && $space_end > $appointment_end) {
236:
237:
238:
239: $empty_spaces_with_appointments[] = array(
240: 'start' => $space_start,
241: 'end' => $appointment_start
242: );
243: $empty_spaces_with_appointments[] = array(
244: 'start' => $appointment_end,
245: 'end' => $space_end
246: );
247: } else {
248:
249:
250: $found = FALSE;
251: foreach($reserved_appointments as $appt) {
252: $appt_start = date('H:i', strtotime($appt['start_datetime']));
253: $appt_end = date('H:i', strtotime($appt['end_datetime']));
254: if ($space_start < $appt_start && $space_end > $appt_end) {
255: $found = TRUE;
256: }
257: }
258:
259:
260:
261: $empty_space = array(
262: 'start' => $space_start,
263: 'end' => $space_end
264: );
265: $already_exist = in_array($empty_space, $empty_spaces_with_appointments);
266: if ($found === FALSE && $already_exist === FALSE) {
267: $empty_spaces_with_appointments[] = $empty_space;
268: }
269: }
270: }
271: }
272: } else {
273: $empty_spaces_with_appointments = $empty_spaces_with_breaks;
274: }
275:
276: $empty_spaces = $empty_spaces_with_appointments;
277:
278:
279:
280:
281:
282: $available_hours = array();
283:
284: foreach($empty_spaces as $space) {
285: $start_hour = new DateTime($_POST['selected_date'] . ' ' . $space['start']);
286: $end_hour = new DateTime($_POST['selected_date'] . ' ' . $space['end']);
287:
288: $minutes = $start_hour->format('i');
289:
290: if ($minutes % 15 != 0) {
291:
292:
293: if ($minutes < 15) {
294: $start_hour->setTime($start_hour->format('H'), 15);
295: } else if ($minutes < 30) {
296: $start_hour->setTime($start_hour->format('H'), 30);
297: } else if ($minutes < 45) {
298: $start_hour->setTime($start_hour->format('H'), 45);
299: } else {
300: $start_hour->setTime($start_hour->format('H') + 1, 00);
301: }
302: }
303:
304: $curr_hour = $start_hour;
305:
306: $diff = $curr_hour->diff($end_hour);
307: while(($diff->h * 60 + $diff->i) > intval($_POST['service_duration'])) {
308: $available_hours[] = $curr_hour->format('H:i');
309: $curr_hour->add(new DateInterval("PT15M"));
310: $diff = $curr_hour->diff($end_hour);
311: }
312: }
313:
314:
315:
316:
317:
318:
319: if (date('m/d/Y', strtotime($_POST['selected_date'])) == date('m/d/Y')) {
320: if ($_POST['manage_mode'] === 'true') {
321: $book_advance_timeout = 0;
322: } else {
323: $book_advance_timeout = $this->Settings_Model
324: ->get_setting('book_advance_timeout');
325: }
326:
327: foreach($available_hours as $index=>$value) {
328: $available_hour = strtotime($value);
329: $current_hour = strtotime('+' . $book_advance_timeout
330: . ' minutes', strtotime('now'));
331:
332: if ($available_hour <= $current_hour) {
333: unset($available_hours[$index]);
334: }
335: }
336: }
337:
338: $available_hours = array_values($available_hours);
339:
340: echo json_encode($available_hours);
341: }
342:
343: 344: 345: 346: 347: 348: 349: 350: 351: 352:
353: public function google_sync($appointment_id) {
354: try {
355: $this->load->library('Google_Sync');
356: $this->google_sync->sync_appointment($appointment_id);
357: $view_data['message'] = 'Your appointment has been successfully added'
358: . 'to Google Calendar!';
359: $view_data['image'] = 'success.png';
360: } catch (Exception $exc) {
361: $view_data['message'] = 'An unexpected error occured during the sync '
362: . 'operation: <br/><pre>' . $exc->getMessage() . '<br/>'
363: . $exc->getTraceAsString() . '</pre>';
364: $view_data['image'] = 'error.png';
365: }
366:
367: $this->load->view('appointments/google_sync', $view_data);
368: }
369: }
370:
371:
372: