diff --git a/CHANGELOG.md b/CHANGELOG.md index e5209043..9b315ae4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - #441: Added time format selection - #452: Provide more information when errors occur during the installation. +## Changed + +- #494: French translation corrections/improvements. + ## Fixed - #433: Selected date when editing an appointment @@ -24,6 +28,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - #455: French Spelling - #459: Aggregate Appointment API crashes when a break was added - #461: Invalid working plan parsing for foreign languages on day view of the default calendar view. +- #475: Booking page date selection is broken with any_provider option selected. +- #483: In backend, calendar for providers become unselectable if switched to calendar for service. +- #491: Replace hardcoded string with translation in appointment details email template. +- #495: Database migration fixes (from 1.2.1 to 1.3.x). +- #497: Backend settings are not being displayed on page load when the user is not an admin. ## [1.3.0] diff --git a/src/application/controllers/Appointments.php b/src/application/controllers/Appointments.php index 76f0ce6f..2fffbf9f 100755 --- a/src/application/controllers/Appointments.php +++ b/src/application/controllers/Appointments.php @@ -615,48 +615,9 @@ class Appointments extends CI_Controller { ? [$_REQUEST['appointment_id']] : []; - // Handle the "Any Provider" case. - if ($provider_id === ANY_PROVIDER) - { - $provider_id = $this->_search_any_provider($service_id, $selected_date_string); + $provider_list = ($provider_id === ANY_PROVIDER) ? $this->_search_providers_by_service($service_id) : [$provider_id] ; - if ($provider_id === null) { - $current_date = new DateTime($selected_date_string); - $current_date->add(new DateInterval('P1D')); - - do - { - $provider_id = $this->_search_any_provider($service_id, $current_date->format('Y-m-d H:i:s')); - - if ($provider_id) - { - break; - } - - $current_date->add(new DateInterval('P1D')); - } while ((int)$current_date->format('d') <= $number_of_days_in_month); - } - - if ($provider_id === NULL) - { - // No provider is available in the selected date. - for ($i = 1; $i <= $number_of_days_in_month; $i++) - { - $current_date = new DateTime($selected_date->format('Y-m') . '-' . $i); - $unavailable_dates[] = $current_date->format('Y-m-d'); - } - - $this->output - ->set_content_type('application/json') - ->set_output(json_encode($unavailable_dates)); - - return; - } - } - - // Get the provider record. $this->load->model('providers_model'); - $provider = $this->providers_model->get_row($provider_id); // Get the service record. $this->load->model('services_model'); @@ -673,19 +634,29 @@ class Appointments extends CI_Controller { continue; } - $empty_periods = $this->_get_provider_available_time_periods($provider_id, - $service_id, - $current_date->format('Y-m-d'), $exclude_appointments); - - $available_hours = $this->_calculate_available_hours($empty_periods, $current_date->format('Y-m-d'), - $service['duration'], $manage_mode, $service['availabilities_type']); - - if ($service['attendants_number'] > 1) + // Finding at least one slot of availablity + foreach ($provider_list as $curr_provider_id) { - $available_hours = $this->_get_multiple_attendants_hours($current_date->format('Y-m-d'), $service, - $provider); + // Get the provider record. + $curr_provider = $this->providers_model->get_row($curr_provider_id); + + $empty_periods = $this->_get_provider_available_time_periods($curr_provider_id, + $service_id, + $current_date->format('Y-m-d'), $exclude_appointments); + + $available_hours = $this->_calculate_available_hours($empty_periods, $current_date->format('Y-m-d'), + $service['duration'], $manage_mode, $service['availabilities_type']); + if (! empty($available_hours)) break; + + if ($service['attendants_number'] > 1) + { + $available_hours = $this->_get_multiple_attendants_hours($current_date->format('Y-m-d'), $service, + $curr_provider); + if (! empty($available_hours)) break; + } } + // No availability amongst all the provider if (empty($available_hours)) { $unavailable_dates[] = $current_date->format('Y-m-d'); @@ -1016,7 +987,7 @@ class Appointments extends CI_Controller { if ($service['attendants_number'] > 1) { - $available_hours = $this->_get_multiple_attendants_hours($this->input->post('selected_date'), $service, + $available_hours = $this->_get_multiple_attendants_hours($selected_date, $service, $provider); } @@ -1032,6 +1003,36 @@ class Appointments extends CI_Controller { return $provider_id; } + /** + * Search for any provider that can handle the requested service. + * + * This method will return the database ID of the providers affected to the requested service. + * + * @param numeric $service_id The requested service ID. + * + * @return array Returns the ID of the provider that can provide the requested service. + */ + protected function _search_providers_by_service($service_id) + { + $this->load->model('providers_model'); + $available_providers = $this->providers_model->get_available_providers(); + $provider_list = array(); + + foreach ($available_providers as $provider) + { + foreach ($provider['services'] as $provider_service_id) + { + if ($provider_service_id === $service_id) + { + // Check if the provider is affected to the selected service. + $provider_list[] = $provider['id']; + } + } + } + + return $provider_list; + } + /** * Calculate the available appointment hours. * diff --git a/src/application/language/french/translations_lang.php b/src/application/language/french/translations_lang.php index e01e9da0..3b908a97 100755 --- a/src/application/language/french/translations_lang.php +++ b/src/application/language/french/translations_lang.php @@ -56,7 +56,7 @@ $lang['appointment_not_found'] = 'Rendez-vous introuvable !'; $lang['appointment_does_not_exist_in_db'] = 'Le rendez-vous demandé n\'existe plus dans la base de données système.'; $lang['display_calendar'] = 'Afficher le calendrier.'; $lang['calendar'] = 'Calendrier'; -$lang['users'] = 'Utilisateur'; +$lang['users'] = 'Utilisateurs'; $lang['settings'] = 'Paramètres'; $lang['log_out'] = 'Déconnexion'; $lang['synchronize'] = 'Synchronisation'; @@ -251,7 +251,7 @@ $lang['december'] = 'Décembre'; $lang['previous'] = 'Précédent'; // @TODO check -e form $lang['next'] = 'Suivant'; // @TODO check -e form $lang['now'] = 'Maintenant'; -$lang['select_time'] = 'Choisir l\'heure'; +$lang['select_time'] = 'Choisir l\'Heure'; $lang['time'] = 'Heure du RDV'; // @TODO to check ; was 'Temps' $lang['hour'] = 'Heure'; $lang['minute'] = 'Minute'; @@ -272,11 +272,11 @@ $lang['customer_notifications'] = 'Notifications aux clients'; $lang['customer_notifications_hint'] = 'Définit si les clients reçoivent des notifications par email chaque fois qu\'il y a un changement d\'horaire de l\'un de leurs rendez-vous.'; $lang['date_format'] = 'Format des Dates'; $lang['date_format_hint'] = 'Change le format d\'affichage des dates (D - Jour, M - Mois, Y - Année).'; -$lang['time_format'] = 'Time Format'; -$lang['time_format_hint'] = 'Change the time display format (H - Hours, M - Minutes).'; +$lang['time_format'] = 'Format de l\'Heure'; +$lang['time_format_hint'] = 'Change le format d\'affichage de l\'Heure (H - Heures, M - Minutes).'; $lang['google_analytics_code_hint'] = 'Renseignez l\'ID Google Analytics à utiliser dans la page des réservations.'; -$lang['availabilities_type'] = 'Availabilities Type'; +$lang['availabilities_type'] = 'Type de disponibilités'; $lang['flexible'] = 'Flexible'; -$lang['fixed'] = 'Fixed'; -$lang['attendants_number'] = 'Attendants Number'; -$lang['reset_working_plan'] = 'Reset the working plan back to the default values.'; +$lang['fixed'] = 'Fixe'; +$lang['attendants_number'] = 'Nombre de participants'; +$lang['reset_working_plan'] = 'Restaurer les valeurs d\'origine du planning de travail.'; diff --git a/src/application/migrations/009_change_column_types.php b/src/application/migrations/009_change_column_types.php index 8c881b93..185a40ef 100644 --- a/src/application/migrations/009_change_column_types.php +++ b/src/application/migrations/009_change_column_types.php @@ -218,6 +218,9 @@ class Migration_Change_column_types extends CI_Migration { $this->db->query('ALTER TABLE `ea_user_settings` ADD CONSTRAINT `ea_user_settings_ibfk_1` FOREIGN KEY (`id_users`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'); + + // Change charset of ea_secretaries_providers table for databases created with EA! 1.2.1 version + $this->db->query('ALTER TABLE ea_secretaries_providers CONVERT TO CHARACTER SET utf8'); } public function down() diff --git a/src/assets/js/backend_calendar_default_view.js b/src/assets/js/backend_calendar_default_view.js index 1c19f8d5..9053b9b6 100755 --- a/src/assets/js/backend_calendar_default_view.js +++ b/src/assets/js/backend_calendar_default_view.js @@ -218,6 +218,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {}; $('#calendar').fullCalendar('option', 'editable', false); } else { $('#google-sync, #enable-sync, #insert-appointment, #insert-unavailable').prop('disabled', false); + $('#calendar').fullCalendar('option', 'selectable', true); $('#calendar').fullCalendar('option', 'editable', true); // If the user has already the sync enabled then apply the proper style changes. diff --git a/src/assets/js/backend_settings.js b/src/assets/js/backend_settings.js index 9d8f250a..d66b6c10 100644 --- a/src/assets/js/backend_settings.js +++ b/src/assets/js/backend_settings.js @@ -102,8 +102,8 @@ window.BackendSettings = window.BackendSettings || {}; if (bindEventHandlers) { _bindEventHandlers(); - $('#settings-page .nav li').first().addClass('active'); - $('#settings-page .nav li').first().find('a').trigger('click'); + var $link = $('#settings-page .nav li').not('.hidden').first().find('a'); + $link.tab('show'); } // Apply Privileges diff --git a/src/assets/js/backend_users_admins.js b/src/assets/js/backend_users_admins.js index 8d9f49a0..95ed5967 100644 --- a/src/assets/js/backend_users_admins.js +++ b/src/assets/js/backend_users_admins.js @@ -102,8 +102,7 @@ $('#admins .record-details').find('select').prop('disabled', false); $('#admin-password, #admin-password-confirm').removeClass('required'); $('#admin-notifications').prop('disabled', false); - - $('#filter-admins .filter').prop('disabled', true); + $('#filter-admins button').prop('disabled', true); $('#filter-admins .results').css('color', '#AAA'); }); diff --git a/src/assets/sql/structure.sql b/src/assets/sql/structure.sql index dbaab393..78ccf943 100644 --- a/src/assets/sql/structure.sql +++ b/src/assets/sql/structure.sql @@ -2,16 +2,16 @@ SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; CREATE TABLE IF NOT EXISTS `ea_appointments` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `id` INT(11) NOT NULL AUTO_INCREMENT, `book_datetime` DATETIME, `start_datetime` DATETIME, `end_datetime` DATETIME, `notes` TEXT, `hash` TEXT, `is_unavailable` TINYINT(4) DEFAULT '0', - `id_users_provider` BIGINT(20) UNSIGNED, - `id_users_customer` BIGINT(20) UNSIGNED, - `id_services` BIGINT(20) UNSIGNED, + `id_users_provider` INT(11), + `id_users_customer` INT(11), + `id_services` INT(11), `id_google_calendar` TEXT, PRIMARY KEY (`id`), KEY `id_users_customer` (`id_users_customer`), @@ -29,15 +29,15 @@ CREATE TABLE `ea_migrations` ( DEFAULT CHARSET = utf8; CREATE TABLE IF NOT EXISTS `ea_roles` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(256), `slug` VARCHAR(256), `is_admin` TINYINT(4), - `appointments` INT(4), - `customers` INT(4), - `services` INT(4), - `users` INT(4), - `system_settings` INT(4), + `appointments` INT(11), + `customers` INT(11), + `services` INT(11), + `users` INT(11), + `system_settings` INT(11), `user_settings` INT(11), PRIMARY KEY (`id`) ) @@ -46,8 +46,8 @@ CREATE TABLE IF NOT EXISTS `ea_roles` ( CREATE TABLE IF NOT EXISTS `ea_secretaries_providers` ( - `id_users_secretary` BIGINT(20) UNSIGNED NOT NULL, - `id_users_provider` BIGINT(20) UNSIGNED NOT NULL, + `id_users_secretary` INT(11) NOT NULL, + `id_users_provider` INT(11) NOT NULL, PRIMARY KEY (`id_users_secretary`, `id_users_provider`), KEY `id_users_secretary` (`id_users_secretary`), KEY `id_users_provider` (`id_users_provider`) @@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS `ea_secretaries_providers` ( CREATE TABLE IF NOT EXISTS `ea_services` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(256), `duration` INT(11), `price` DECIMAL(10, 2), @@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS `ea_services` ( `description` TEXT, `availabilities_type` VARCHAR(32) DEFAULT 'flexible', `attendants_number` INT(11) DEFAULT '1', - `id_service_categories` BIGINT(20) UNSIGNED, + `id_service_categories` INT(11), PRIMARY KEY (`id`), KEY `id_service_categories` (`id_service_categories`) ) @@ -74,8 +74,8 @@ CREATE TABLE IF NOT EXISTS `ea_services` ( CREATE TABLE IF NOT EXISTS `ea_services_providers` ( - `id_users` BIGINT(20) UNSIGNED NOT NULL, - `id_services` BIGINT(20) UNSIGNED NOT NULL, + `id_users` INT(11) NOT NULL, + `id_services` INT(11) NOT NULL, PRIMARY KEY (`id_users`, `id_services`), KEY `id_services` (`id_services`) ) @@ -84,7 +84,7 @@ CREATE TABLE IF NOT EXISTS `ea_services_providers` ( CREATE TABLE IF NOT EXISTS `ea_service_categories` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(256), `description` TEXT, PRIMARY KEY (`id`) @@ -94,7 +94,7 @@ CREATE TABLE IF NOT EXISTS `ea_service_categories` ( CREATE TABLE IF NOT EXISTS `ea_settings` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(512), `value` LONGTEXT, PRIMARY KEY (`id`) @@ -104,7 +104,7 @@ CREATE TABLE IF NOT EXISTS `ea_settings` ( CREATE TABLE IF NOT EXISTS `ea_users` ( - `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `id` INT(11) NOT NULL AUTO_INCREMENT, `first_name` VARCHAR(256), `last_name` VARCHAR(512), `email` VARCHAR(512), @@ -115,7 +115,7 @@ CREATE TABLE IF NOT EXISTS `ea_users` ( `state` VARCHAR(128), `zip_code` VARCHAR(64), `notes` TEXT, - `id_roles` BIGINT(20) UNSIGNED NOT NULL, + `id_roles` INT(11) NOT NULL, PRIMARY KEY (`id`), KEY `id_roles` (`id_roles`) ) @@ -124,7 +124,7 @@ CREATE TABLE IF NOT EXISTS `ea_users` ( CREATE TABLE IF NOT EXISTS `ea_user_settings` ( - `id_users` BIGINT(20) UNSIGNED NOT NULL, + `id_users` INT(11) NOT NULL, `username` VARCHAR(256), `password` VARCHAR(512), `salt` VARCHAR(512), diff --git a/src/engine/Notifications/Email.php b/src/engine/Notifications/Email.php index be5263e9..edb1ea3e 100755 --- a/src/engine/Notifications/Email.php +++ b/src/engine/Notifications/Email.php @@ -242,7 +242,7 @@ class Email { '$appointment_service' => $service['name'], '$appointment_provider' => $provider['first_name'] . ' ' . $provider['last_name'], '$appointment_date' => date($date_format . ' ' . $timeFormat, strtotime($appointment['start_datetime'])), - '$appointment_duration' => $service['duration'] . ' minutes', + '$appointment_duration' => $service['duration'] . ' ' . $this->framework->lang->line('minutes'), '$company_link' => $company['company_link'], '$company_name' => $company['company_name'], '$customer_name' => $customer['first_name'] . ' ' . $customer['last_name'],