* Finished google synchronization algorithm.

* Prepared trunk for new version.
This commit is contained in:
alextselegidis@gmail.com 2013-07-15 07:32:19 +00:00
parent 8455891262
commit c139df2135
16 changed files with 216 additions and 105 deletions

View file

@ -10,4 +10,5 @@ Main
Minor
- Display javascript ajax error messages to users.
- Provider can edit appointment from email link.

View file

@ -3,7 +3,7 @@
-- http://www.phpmyadmin.net
--
-- Φιλοξενητής: localhost
-- Χρόνος δημιουργίας: 09 Ιουλ 2013 στις 15:16:49
-- Χρόνος δημιουργίας: 15 Ιουλ 2013 στις 10:07:35
-- Έκδοση διακομιστή: 5.5.24-log
-- Έκδοση PHP: 5.4.3
@ -42,23 +42,7 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` (
KEY `id_users_customer` (`id_users_customer`),
KEY `id_services` (`id_services`),
KEY `id_users_provider` (`id_users_provider`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=25 ;
--
-- Άδειασμα δεδομένων του πίνακα `ea_appointments`
--
INSERT INTO `ea_appointments` (`id`, `book_datetime`, `start_datetime`, `end_datetime`, `notes`, `hash`, `is_unavailable`, `id_users_provider`, `id_users_customer`, `id_services`, `id_google_calendar`) VALUES
(2, '2013-06-28 13:41:37', '2013-06-28 10:00:00', '2013-06-28 15:50:00', '', 'df05e96357b1f7eb9717524d40400b92', 0, 2, 5, 1, NULL),
(3, '2013-06-28 17:03:04', '2013-06-29 09:00:00', '2013-06-29 12:50:00', '', '0493a6fef5215cd83b9eca4de63cb9e9', 0, 2, 5, 1, 'vhd5nlv9pt32caanvtu8c9c8r0'),
(7, '2013-06-29 00:48:15', '2013-06-29 12:15:00', '2013-06-29 12:35:00', '', '5774937851046f65b87617eb14c6ee97', 0, 2, 5, 1, NULL),
(15, '2013-07-03 13:34:54', '2013-07-03 15:15:00', '2013-07-03 15:35:00', '', '98c777b9ee21be6091e15c4af35f6752', 0, 2, 5, 1, 'ibcgjhj1fu484s1c4bquroqtm0'),
(16, '2013-07-03 13:45:12', '2013-07-03 15:45:00', '2013-07-03 16:05:00', '', 'b828b3bb5dbc4e50f05b05cb239bfcd4', 0, 2, 5, 1, 'c48fcvqak1pulu78is971cmutg'),
(17, '2013-07-03 13:45:46', '2013-07-03 16:15:00', '2013-07-03 16:35:00', '', '1edb1f698d8c3606d8ac3c3371604782', 0, 2, 5, 1, 'cgqaavskrvp8048hvba8i9qa28'),
(18, '2013-07-03 13:46:08', '2013-07-03 16:45:00', '2013-07-03 17:05:00', '', 'a4dacd561468e89a74267dc148690a74', 0, 2, 5, 1, 'rrtfqiok2c7i7vbuuh4hjtcp4c'),
(20, '2013-07-03 17:51:49', '2013-07-04 09:00:00', '2013-07-04 09:20:00', '', '9e9814cf15a156d8d795d1e363463c65', 0, 2, 5, 1, 'i3v1unm6miuu1ran9idbivl130'),
(23, '2013-07-03 18:35:25', '2013-07-04 13:00:00', '2013-07-04 13:20:00', '', '64d9143d6004a03d2887d4f9909fd59e', 0, 2, 5, 1, 'fquo0ibainofdpbs26j8ae3r0c'),
(24, '2013-07-05 14:00:38', '2013-07-05 10:00:00', '2013-07-05 10:20:00', '', '13db3ecb2fe7b3e8a9131a21183db62c', 0, 2, 5, 1, 'jno45dehlqh8qufilgvnvj1dl0');
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=102 ;
-- --------------------------------------------------------
@ -111,10 +95,9 @@ CREATE TABLE IF NOT EXISTS `ea_services` (
--
INSERT INTO `ea_services` (`id`, `name`, `duration`, `price`, `currency`, `description`, `id_service_categories`) VALUES
(1, 'Γενική Εξέταση', 20, '50.00', 'euro', 'Γενική εξέταση του ασθενή.', NULL),
(2, 'Εξέταση Καρδιάς', 30, '40.00', 'euro', 'Εξέταση του ασθενή για νοσήματα καρδιάς.', NULL),
(3, 'Νευρολογική Εξέταση', 20, '35.00', 'euro', 'Νευρολογική εξέταση του ασθενή.', NULL),
(9, 'General Examination', 30, '50.00', 'euro', 'This is some service description.', NULL);
(1, 'General Examination', 20, '50.00', 'euro', 'General examination of the patient.', NULL),
(2, 'Heart Examination', 30, '40.00', 'euro', 'Checkup for heart problems.', NULL),
(3, 'Neurological Examination', 20, '35.00', 'euro', 'Neurological tests for the patient.', NULL);
-- --------------------------------------------------------
@ -177,7 +160,7 @@ INSERT INTO `ea_settings` (`id`, `name`, `value`) VALUES
(1, 'company_name', 'Javation & Co'),
(2, 'company_working_plan', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}'),
(3, 'company_email', 'alextselegidis@gmail.com'),
(8, 'company_link', 'http://google.gr'),
(8, 'company_link', 'http://javation.com'),
(9, 'book_advance_timeout', '30');
-- --------------------------------------------------------
@ -208,11 +191,11 @@ CREATE TABLE IF NOT EXISTS `ea_users` (
--
INSERT INTO `ea_users` (`id`, `first_name`, `last_name`, `email`, `mobile_number`, `phone_number`, `address`, `city`, `state`, `zip_code`, `notes`, `id_roles`) VALUES
(1, 'Alex', 'Tselegidis', 'alextselegidis@gmail.com', '123456789', '123456789', 'Some Str', 'Some City', 'Some State', '12345', 'This is me making Easy!Appointments :P', 1),
(2, 'Γεώργιος', 'Παπαδόπουλος', 'alextselegidis@gmail.com', '1111111111111', '1111111111111', '', '', NULL, '', 'This is a test provider (with my email for google syncing).', 2),
(3, 'Νίκος', 'Αναστασίου', 'prov2@test.gr', '2222222222222', '2222222222222', 'Some Street 3', NULL, NULL, NULL, NULL, 2),
(4, 'Ηρώ', 'Καριοφύλη', 'prov3@test.gr', '3333333333333', '3333333333333', 'John Doe 3 ', NULL, NULL, NULL, NULL, 2),
(5, '', 'a', 'alextselegidis@yahoo.gr', NULL, 'a', '', '', NULL, '', NULL, 3);
(1, 'Ringo', 'Starr', 'alextselegidis@gmail.com', '0000000000000', '0000000000000', 'Some Str', 'Some City', 'Some State 0', '00000', 'This is me making Easy!Appointments :P', 1),
(2, 'George', 'Harrison', 'alextselegidis@gmail.com', '1111111111111', '1111111111111', 'Some Str 1', 'Some City 1', 'Some State 1', '11111', 'This is a test provider (with my email for google syncing).', 2),
(3, 'John', 'Lennon', 'prov2@test.gr', '2222222222222', '2222222222222', 'Some Str 2', 'Some City 2', 'Some State 2', '22222', NULL, 2),
(4, 'Paul', 'McCartney', 'prov3@test.gr', '3333333333333', '3333333333333', 'Some Str 3', 'Some City 3', 'Some State 3', '33333', NULL, 2),
(5, 'John', 'Doe', 'alextselegidis@yahoo.gr', NULL, '0123456789', '', '', NULL, '', 'This is my testing customer.', 3);
-- --------------------------------------------------------
@ -228,6 +211,8 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` (
`notifications` text,
`google_sync` tinyint(4) DEFAULT '0',
`google_token` text,
`sync_past_days` int(11) DEFAULT '5',
`sync_future_days` int(11) DEFAULT '5',
PRIMARY KEY (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -235,10 +220,10 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` (
-- Άδειασμα δεδομένων του πίνακα `ea_user_settings`
--
INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `working_plan`, `notifications`, `google_sync`, `google_token`) VALUES
(2, 'provider_1', 'provider_1', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 1, '{"access_token":"ya29.AHES6ZRq0T7vB1k0nueWwvYM8gQw7QapJm8_EyHaRwljzXo","token_type":"Bearer","expires_in":3600,"refresh_token":"1\\/o4GiIEXKTxm3HkWHAPGplqW2CcmGLQm7CV3iv19DrTw","created":1372844816}'),
(3, 'provider_2', 'provider_2', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL),
(4, 'provider_3', 'provider_3', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL);
INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `working_plan`, `notifications`, `google_sync`, `google_token`, `sync_past_days`, `sync_future_days`) VALUES
(2, 'provider_1', 'provider_1', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL, 5, 5),
(3, 'provider_2', 'provider_2', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL, 5, 5),
(4, 'provider_3', 'provider_3', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL, 5, 5);
--
-- Περιορισμοί για άχρηστους πίνακες

View file

@ -149,7 +149,7 @@ class Appointments extends CI_Controller {
$provider_title = 'A new appointment has been added to your plan.';
$provider_message = 'You can make changes by clicking the appointment '
. 'link below';
$provider_link = $this->config->item('base_url') . 'backend/'
$provider_link = $this->config->item('base_url') . 'backend/index/'
. $appointment['hash'];
} else {
$customer_title = 'Appointment changes have been successfully saved!';
@ -159,7 +159,7 @@ class Appointments extends CI_Controller {
$provider_title = 'Appointment details have changed.';
$provider_message = '';
$provider_link = $this->config->item('base_url') . 'backend/'
$provider_link = $this->config->item('base_url') . 'backend/index/'
. $appointment['hash'];
}

View file

@ -18,6 +18,7 @@ class Backend extends CI_Controller {
$this->load->model('appointments_model');
$this->load->model('providers_model');
$this->load->model('services_model');
$this->load->model('customers_model');
$this->load->model('settings_model');
$view['base_url'] = $this->config->item('base_url');
@ -28,7 +29,9 @@ class Backend extends CI_Controller {
if ($appointment_hash != '') {
$results = $this->appointments_model->get_batch(array('hash' => $appointment_hash));
$view['edit_appointment'] = $results[0]; // This will display the appointment edit dialog on page load.
$appointment = $results[0];
$appointment['customer'] = $this->customers_model->get_row($appointment['id_users_customer']);
$view['edit_appointment'] = $appointment; // This will display the appointment edit dialog on page load.
} else {
$view['edit_appointment'] = NULL;
}

View file

@ -73,7 +73,8 @@ class Google extends CI_Controller {
*
* @param numeric $provider_id Provider record to be synced.
*
* @task This method must be executed only by the system and noone else outside. It is a big security issue.
* @task This method must be executed only by the system and noone else outside.
* It is a big security issue.
*/
public function sync($provider_id = NULL) {
try {
@ -127,52 +128,62 @@ class Google extends CI_Controller {
$service = $this->services_model->get_row($appointment['id_services']);
$customer = $this->customers_model->get_row($appointment['id_users_customer']);
// :: APPOINTMENT WITH NO GCAL_ID -> ADD TO GCAL
// If current appointment not synced yet, add to gcal.
if ($appointment['id_google_calendar'] == NULL) {
$google_event = $this->google_sync->add_appointment($appointment, $provider,
$service, $customer, $company_settings);
$appointment['id_google_calendar'] = $google_event->id;
$this->appointments_model->add($appointment); // save gcal id
}
// :: SYNCED APPOINTMENT NOT FOUND ON GCAL -> DELETE E!A RECORD
if ($appointment['id_google_calendar'] != NULL) {
$this->appointments_model->add($appointment); // Save gcal id
} else {
// Appointment is synced with google calendar.
try {
$google_event = $this->google_sync->get_event($appointment['id_google_calendar']);
} catch(Exception $exc) {
$this->appointments_model->delete($appointment['id']);
$appointment['id_google_calendar'] = NULL; // Do not proceed with the rest sync actions.
}
}
// :: SYNCED APPOINTMENT DIFFERENT FROM GCAL EVENT -> UPDATE E!A RECORD
if ($appointment['id_google_calendar'] != NULL) {
$is_different = FALSE;
$appt_start = strtotime($appointment['start_datetime']);
$appt_end = strtotime($appointment['end_datetime']);
$event_start = strtotime($google_event->getStart()->getDateTime());
$event_end = strtotime($google_event->getEnd()->getDateTime());
if ($appt_start != $event_start
|| $appt_end != $event_end) {
$is_different = TRUE;
}
if ($is_different) {
$appointment['start_datetime'] = date('Y-m-d H:i:s', $event_start);
$appointment['end_datetime'] = date('Y-m-d H:i:s', $event_end);
$this->appointments_model->add($appointment);
}
}
// @task :: GCAL EVENT NOT FOUND ON E!A -> ADD EVENT TO E!A
// If gcal event is different from e!a appointment then update e!a record.
$is_different = FALSE;
$appt_start = strtotime($appointment['start_datetime']);
$appt_end = strtotime($appointment['end_datetime']);
$event_start = strtotime($google_event->getStart()->getDateTime());
$event_end = strtotime($google_event->getEnd()->getDateTime());
if ($appt_start != $event_start || $appt_end != $event_end) {
$is_different = TRUE;
}
if ($is_different) {
$appointment['start_datetime'] = date('Y-m-d H:i:s', $event_start);
$appointment['end_datetime'] = date('Y-m-d H:i:s', $event_end);
$this->appointments_model->add($appointment);
}
} catch(Exception $exc) {
// Appointment not found on gcal, delete from e!a.
$this->appointments_model->delete($appointment['id']);
$appointment['id_google_calendar'] = NULL;
}
}
}
// @task Sync unavailable periods with Google Calendar
// :: ADD GCAL EVENTS THAT ARE NOT PRESENT ON E!A
$events = $this->google_sync->get_sync_events($start, $end);
foreach($events->getItems() as $event) {
$results = $this->appointments_model->get_batch(array('id_google_calendar' => $event->getId()));
if (count($results) == 0) {
// Record doesn't exist in E!A, so add the event now.
$appointment = array(
'start_datetime' => date('Y-m-d H:i:s', strtotime($event->start->getDateTime())),
'end_datetime' => date('Y-m-d H:i:s', strtotime($event->end->getDateTime())),
'is_unavailable' => TRUE,
'notes' => $event->getSummary() . ' ' . $event->getDescription(),
'id_users_provider' => $provider_id,
'id_google_calendar' => $event->getId(),
'id_users_customer' => NULL,
'id_services' => NULL,
);
$this->appointments_model->add($appointment);
}
}
echo json_encode('SUCCESS');

View file

@ -29,22 +29,22 @@ class SyncException extends Exception {}
* We display only one exceptions at a time because the user needs to be able
* to display the details of each exception seperately. (In contrast with js).
*
* @param Exception $exception The exception to be displayed.
* @param Exception $exc The exception to be displayed.
* @return string Returns the html markup of the exception.
*/
function exceptionToHtml($exception) {
function exceptionToHtml($exc) {
return
'<div class="accordion" id="error-accordion">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse"
data-parent="#error-accordion" href="#error-technical">' .
$exception->getMessage() . '
$exc->getMessage() . '
</a>
</div>
<div id="error-technical" class="accordion-body collapse">
<div class="accordion-inner">
<pre>' . $exception->getTraceAsString() . '</pre>
<pre>' . $exc->getTraceAsString() . '</pre>
</div>
</div>
</div>

View file

@ -65,6 +65,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -82,7 +83,6 @@ class Unit_tests_appointments_model extends CI_Driver {
unset($db_data['hash']);
unset($db_data['book_datetime']);
unset($db_data['id_google_calendar']);
unset($db_data['is_unavailable']);
$this->CI->unit->run($appointment, $db_data, 'Test if add() appointment (insert '
. 'operation) has successfully inserted a record.');
@ -100,6 +100,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -134,6 +135,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-0WRONG5-01 12:30WRONG:00',
'end_datetime' => '2013-0WRONG5-01WRONG 13:00WRONG:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -161,6 +163,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -182,6 +185,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 08:33:45',
'end_datetime' => '2013-05-02 13:13:13',
'notes' => 'This is totally random!',
'is_unavailable' => FALSE,
'id_users_provider' => '198678',
'id_users_customer' => '194702',
'id_services' => '8766293'
@ -197,6 +201,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2WRONG013-05-01 0WRONG8:33:45',
'end_datetime' => '2013-0WRONG5-02 13:13:WRONG13',
'notes' => 'This is totally random!',
'is_unavailable' => FALSE,
'id_users_provider' => '1986WRONG78',
'id_users_customer' => '1WRONG94702',
'id_services' => '876WRONG6293'
@ -216,6 +221,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -245,6 +251,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -276,6 +283,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013WRONG-05-0WRONG1 12:WRONG30:00',
'end_datetime' => '2013-05-01 13:00:00WRONG',
'notes' => 'Some notes righWRONGt here...',
'is_unavailable' => FALSE,
'id_users_provider' => 'WRONG',
'id_users_customer' => 'WRONG',
'id_services' => 'WRONG'
@ -304,6 +312,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -375,6 +384,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -427,6 +437,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'hash' => '91de2d31f5cbb6d26a5b1b3e710d38d1',
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
@ -439,7 +450,6 @@ class Unit_tests_appointments_model extends CI_Driver {
$db_data = $this->CI->appointments_model->get_row($appointment['id']);
unset($db_data['book_datetime']);
unset($db_data['id_google_calendar']);
unset($db_data['is_unavailable']);
// Check if this is the record we seek.
$this->CI->unit->run($db_data, $appointment, 'Test get_row() method.');
@ -487,6 +497,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -537,6 +548,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -566,6 +578,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -579,6 +592,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '20WRONG13-05-01 12WRONG:30:00',
'end_datetime' => '2013-05WRONG-01 13:00WRONG:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -593,6 +607,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => 'THIS IS WRONG',
'id_users_customer' => $this->customer_id,
'id_services' => $this->service_id
@ -607,6 +622,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => 'THIS IS WRONG',
'id_services' => $this->service_id
@ -621,6 +637,7 @@ class Unit_tests_appointments_model extends CI_Driver {
'start_datetime' => '2013-05-01 12:30:00',
'end_datetime' => '2013-05-01 13:00:00',
'notes' => 'Some notes right here...',
'is_unavailable' => FALSE,
'id_users_provider' => $this->provider_id,
'id_users_customer' => $this->customer_id,
'id_services' => 'THIS IS WRONG'

View file

@ -272,6 +272,25 @@ class Google_Sync {
public function get_event($google_calendar_id) {
return $this->service->events->get('primary', $google_calendar_id);
}
/**
* Get all the events between the sync period.
*
* @param date $start The start date of sync period.
* @param date $end The end date of sync period.
* @return object Returns an array with Google_Event objects that belong on the given
* sync period (start, end).
*/
public function get_sync_events($start, $end) {
$this->CI->load->helper('general');
$params = array(
'timeMin' => date3339($start),
'timeMax' => date3339($end)
);
return $this->service->events->listEvents('primary', $params);
}
}
/* End of file google_sync.php */

View file

@ -152,7 +152,7 @@ class Appointments_Model extends CI_Model {
// If a appointment id is given, check wether the record exists
// in the database.
if (isset($appointment['id'])) {
$num_rows = $this->db->get_where('ea_appointments',
$num_rows = $this->db->get_where('ea_appointments',
array('id' => $appointment['id']))->num_rows();
if ($num_rows == 0) {
throw new Exception('Provided appointment id does not '
@ -181,23 +181,25 @@ class Appointments_Model extends CI_Model {
throw new Exception('Appointment provider id is invalid.');
}
// Check if the customer's id is valid.
$num_rows = $this->db
->select('*')
->from('ea_users')
->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'inner')
->where('ea_users.id', $appointment['id_users_customer'])
->where('ea_roles.slug', DB_SLUG_CUSTOMER)
->get()->num_rows();
if ($num_rows == 0) {
throw new Exception('Appointment customer id is invalid.');
}
// Check if the service id is valid.
$num_rows = $this->db->get_where('ea_services',
array('id' => $appointment['id_services']))->num_rows();
if ($num_rows == 0) {
throw new Exception('Appointment customer id is invalid.');
if ($appointment['is_unavailable'] == FALSE) {
// Check if the customer's id is valid.
$num_rows = $this->db
->select('*')
->from('ea_users')
->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'inner')
->where('ea_users.id', $appointment['id_users_customer'])
->where('ea_roles.slug', DB_SLUG_CUSTOMER)
->get()->num_rows();
if ($num_rows == 0) {
throw new Exception('Appointment customer id is invalid.');
}
// Check if the service id is valid.
$num_rows = $this->db->get_where('ea_services',
array('id' => $appointment['id_services']))->num_rows();
if ($num_rows == 0) {
throw new Exception('Appointment customer id is invalid.');
}
}
return TRUE;

View file

@ -196,8 +196,8 @@
if (isset($exceptions)) {
echo '<div style="margin: 10px">';
echo '<h4>Unexpected Errors</h4>';
foreach($exceptions as $exception) {
echo exceptionToHtml($exception);
foreach($exceptions as $exc) {
echo exceptionToHtml($exc);
}
echo '</div>';
}

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Easy!Appointments Backend | <?php echo $company_name; ?></title>
<title><?php echo $company_name; ?> | Easy!Appointments</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="icon" type="image/x-icon"

View file

@ -48,7 +48,7 @@ root {
#calendar-page #calendar-actions { display: inline-block; float: right; margin-top: 4px; }
#calendar-page #calendar { margin: 12px; }
#calendar-page #calendar .fc-unavailable { background-image: url('../images/unavailable.jpg');
font-size: 24px; border: none; border-radius: 0; font-weight: bold; color: #333;
font-size: 24px; border-radius: 0; font-weight: bold; color: #333;
text-shadow: 0px 1px 0px #FFF;}
#calendar-page #calendar .fc-break { background-image: url('../images/break.jpg'); }
#calendar-page #calendar .fc-custom { background-image: url('../images/custom.jpg'); }

View file

@ -66,6 +66,10 @@ var Backend = {
message = 'NO MESSAGE PROVIDED FOR THIS NOTIFICATION';
}
if (actions === undefined) {
actions = [];
}
var notificationHtml =
'<div class="notification alert">' +
'<strong>' + message + '</strong>';

View file

@ -90,7 +90,36 @@ var BackendCalendar = {
// :: DISPLAY EDIT DIALOG IF APPOINTMENT HASH IS PROVIDED
if (GlobalVariables.editAppointment != null) {
// @task Display appointment edit dialog to user.
var $dialog = $('#manage-appointment');
var appointment = GlobalVariables.editAppointment;
BackendCalendar.resetAppointmentDialog();
$dialog.find('.modal-header h3').text('Edit Appointment');
$dialog.find('#appointment-id').val(appointment['id']);
$dialog.find('#select-service').val(appointment['id_services']);
$dialog.find('#select-provider').val(appointment['id_users_provider']);
// Set the start and end datetime of the appointment.
var startDatetime = Date.parseExact(appointment['start_datetime'],
'yyyy-MM-dd HH:mm:ss').toString('dd/MM/yyyy HH:mm');
$dialog.find('#start-datetime').val(startDatetime);
var endDatetime = Date.parseExact(appointment['end_datetime'],
'yyyy-MM-dd HH:mm:ss').toString('dd/MM/yyyy HH:mm');
$dialog.find('#end-datetime').val(endDatetime);
var customer = appointment['customer'];
$dialog.find('#customer-id').val(appointment['id_users_customer']);
$dialog.find('#first-name').val(customer['first_name']);
$dialog.find('#last-name').val(customer['last_name']);
$dialog.find('#email').val(customer['email']);
$dialog.find('#phone-number').val(customer['phone_number']);
$dialog.find('#address').val(customer['address']);
$dialog.find('#city').val(customer['city']);
$dialog.find('#zip-code').val(customer['zip_code']);
$dialog.find('#notes').val(appointment['notes']);
$dialog.modal('show');
}
},
@ -140,6 +169,45 @@ var BackendCalendar = {
}
});
/**
* Event: Google Sync Button "Click"
*
* Trigger the synchronization algorithm.
*/
$('#google-sync').click(function() {
var getUrl = GlobalVariables.baseUrl + 'google/sync/' + $('#select-filter-item').val();
$.ajax({
'type': 'GET',
'url': getUrl,
'dataType': 'json',
'success': function(response) {
/////////////////////////////////////////////////
console.log('Google Sync Response:', response);
/////////////////////////////////////////////////
if (response.exceptions) {
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE);
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return;
}
if (response.warnings) {
response.warnings = GeneralFunctions.parseExceptions(response.warnings);
GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE);
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
}
Backend.displayNotification('Google synchronization completed successfully!');
$('#reload-appointments').trigger('click');
},
'error': function(jqXHR, textStatus, errorThrown) {
Backend.displayNotification('Google synchronization failed: Could not establish '
+ 'server connection.');
}
});
});
/**
* Event: Reload Button "Click"
*
@ -181,7 +249,7 @@ var BackendCalendar = {
$dialog.find('#select-service').val(appointment['id_services']);
$dialog.find('#select-provider').val(appointment['id_users_provider']);
// Set the start and end datetime of the appointment.\
// Set the start and end datetime of the appointment.
var startDatetime = Date.parseExact(appointment['start_datetime'],
'yyyy-MM-dd HH:mm:ss').toString('dd/MM/yyyy HH:mm');
$dialog.find('#start-datetime').val(startDatetime);
@ -218,7 +286,7 @@ var BackendCalendar = {
$dialog.find('#unavailable-notes').val(unavailable.notes);
}
// :: DIAPLY EDIT DIALOG
// :: DISPLAY EDIT DIALOG
$dialog.modal('show');
});
@ -751,7 +819,7 @@ var BackendCalendar = {
'start': Date.parse(unavailable.start_datetime),
'end': Date.parse(unavailable.end_datetime),
'allDay': false,
'color': '#123456',
'color': '#879DB4',
'editable': true,
'className': 'fc-unavailable fc-custom',
'data': unavailable
@ -829,7 +897,7 @@ var BackendCalendar = {
'start': Date.parse(unavailable.start_datetime),
'end': Date.parse(unavailable.end_datetime),
'allDay': false,
'color': '#123456',
'color': '#879DB4',
'editable': true,
'className': 'fc-unavailable fc-custom',
'data': unavailable

View file

@ -443,6 +443,7 @@ var FrontendBook = {
+ ' ' + $('.selected-hour').text() + ':00',
'end_datetime': FrontendBook.calcEndDatetime(),
'notes': $('#notes').val(),
'is_unavailable': false,
'id_users_provider': $('#select-provider').val(),
'id_services': $('#select-service').val()
};