<?php class OsVersionSpecificUpdatesHelper { /** * * Used to target a specific version during an update * * @return bool */ public static function run_version_specific_updates() { $current_db_version = OsSettingsHelper::get_db_version(); if (!$current_db_version) return false; $sqls = []; if (version_compare('1.0.2', $current_db_version) > 0) { // lower than 1.0.2 $sqls = self::get_queries_for_nullable_columns(); OsDatabaseHelper::run_queries($sqls); } if (version_compare('1.1.0', $current_db_version) > 0) { // lower than 1.1.0 $sqls = self::set_end_date_for_bookings(); OsDatabaseHelper::run_queries($sqls); } if (version_compare('1.3.0', $current_db_version) > 0) { // lower than 1.3.0 $sqls = []; $sqls[] = "UPDATE " . LATEPOINT_TABLE_BOOKINGS . " SET total_attendees = 1 WHERE total_attendees IS NULL;"; $sqls[] = "UPDATE " . LATEPOINT_TABLE_SERVICES . " SET visibility = '" . LATEPOINT_SERVICE_VISIBILITY_VISIBLE . "' WHERE visibility IS NULL OR visibility = '';"; $sqls[] = "UPDATE " . LATEPOINT_TABLE_SERVICES . " SET capacity_min = 1 WHERE capacity_min IS NULL;"; $sqls[] = "UPDATE " . LATEPOINT_TABLE_SERVICES . " SET capacity_max = 1 WHERE capacity_max IS NULL;"; OsDatabaseHelper::run_queries($sqls); } if (version_compare('1.3.1', $current_db_version) > 0) { $sqls = []; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_CUSTOMERS . " MODIFY COLUMN first_name varchar(255)"; OsDatabaseHelper::run_queries($sqls); } if (version_compare('1.3.7', $current_db_version) > 0) { $sqls = []; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_AGENTS . " MODIFY COLUMN wp_user_id int(11)"; OsDatabaseHelper::run_queries($sqls); } if (version_compare('1.4.8', $current_db_version) > 0) { update_option('latepoint_db_seeded', true); OsSettingsHelper::save_setting_by_name('timeslot_blocking_statuses', LATEPOINT_BOOKING_STATUS_APPROVED); OsSettingsHelper::save_setting_by_name('calendar_hidden_statuses', LATEPOINT_BOOKING_STATUS_CANCELLED); OsSettingsHelper::save_setting_by_name('need_action_statuses', implode(',', [LATEPOINT_BOOKING_STATUS_PENDING, LATEPOINT_BOOKING_STATUS_PAYMENT_PENDING])); $tile_info = OsSettingsHelper::get_booking_template_for_calendar(); $tile_info = OsUtilHelper::replace_single_curly_with_double($tile_info); OsSettingsHelper::save_setting_by_name('booking_template_for_calendar', $tile_info); // ------- // Update {var} to {{var}} // ------- // password reset message $content_to_replace = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('email_customer_password_reset_request_content', '')); OsSettingsHelper::save_setting_by_name('email_customer_password_reset_request_content', $content_to_replace); // new message (chat) $content_to_replace = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('email_notification_customer_has_new_message_content', '')); OsSettingsHelper::save_setting_by_name('email_notification_customer_has_new_message_content', $content_to_replace); // js tracking code $content_to_replace = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('confirmation_step_tracking_code', '')); OsSettingsHelper::save_setting_by_name('confirmation_step_tracking_code', $content_to_replace); // Google calendar $content_to_replace = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('google_calendar_event_summary_template', '')); if (!empty($content_to_replace)) OsSettingsHelper::save_setting_by_name('google_calendar_event_summary_template', $content_to_replace); $content_to_replace = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('google_calendar_event_description_template', '')); if (!empty($content_to_replace)) OsSettingsHelper::save_setting_by_name('google_calendar_event_description_template', $content_to_replace); // ------- // migrate old notification system to processes // ------- $process_actions = []; // STATUS CHANGE NOTIFICATION if (OsSettingsHelper::is_on('notifications_email')) { // email foreach (['agent', 'customer'] as $user_type) { $action = []; if (OsSettingsHelper::is_on('notification_' . $user_type . '_booking_status_changed')) { $action['type'] = 'send_email'; $action['settings']['to_email'] = '{{' . $user_type . '_full_name}} <{{' . $user_type . '_email}}>'; $action['settings']['subject'] = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('notification_' . $user_type . '_booking_status_changed_notification_subject', '')); $action['settings']['content'] = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value('notification_' . $user_type . '_booking_status_changed_notification_content', '')); $process_actions[\LatePoint\Misc\ProcessAction::generate_id()] = $action; } } if ($process_actions) { // put all under single process with multiple actions $process = new OsProcessModel(); $process->event_type = 'booking_updated'; $process->name = 'Booking status change notification'; $trigger_conditions[] = ['object' => 'old_booking', 'property' => 'old_booking__status', 'operator' => 'changed', 'value' => '']; $process_actions = OsProcessesHelper::iterate_trigger_conditions($trigger_conditions, $process_actions); $process_actions[0]['time_offset'] = []; $process->actions_json = wp_json_encode($process_actions); if (!OsProcessesHelper::check_if_process_exists($process)) $process->save(); } } $process_actions = []; // NEW BOOKING NOTIFICATION if (OsSettingsHelper::is_on('notifications_email')) { OsSettingsHelper::save_setting_by_name('notifications_email_processor', 'wp_mail'); // email foreach (['agent', 'customer'] as $user_type) { $action = []; if (OsSettingsHelper::is_on('notification_' . $user_type . '_confirmation')) { $action['type'] = 'send_email'; $action['settings']['to_email'] = '{{' . $user_type . '_email}}'; $action['settings']['subject'] = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value((($user_type == 'agent') ? 'notification_agent_new_booking_notification_subject' : 'notification_customer_booking_confirmation_subject'), '')); $action['settings']['content'] = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value((($user_type == 'agent') ? 'notification_agent_new_booking_notification_content' : 'notification_customer_booking_confirmation_content'), '')); $process_actions[\LatePoint\Misc\ProcessAction::generate_id()] = $action; } } } if (OsSettingsHelper::is_on('notifications_sms')) { OsSettingsHelper::save_setting_by_name('notifications_sms_processor', 'twilio'); // sms foreach (['agent', 'customer'] as $user_type) { $action = []; if (OsSettingsHelper::is_on('notification_sms_' . $user_type . '_confirmation')) { $action['type'] = 'send_sms'; $action['settings']['to_phone'] = '{{' . $user_type . '_phone}}'; $action['settings']['content'] = OsUtilHelper::replace_single_curly_with_double(OsSettingsHelper::get_settings_value((($user_type == 'agent') ? 'notification_sms_agent_new_booking_notification_message' : 'notification_sms_customer_booking_confirmation_message'), '')); $process_actions[\LatePoint\Misc\ProcessAction::generate_id()] = $action; } } } // webhooks for new booking // migrate webhooks for new booking into processes $webhooks = json_decode(OsSettingsHelper::get_settings_value('webhooks', ''), true); if ($webhooks) { foreach ($webhooks as $webhook) { // only process new booking if ($webhook['status'] != 'active' || $webhook['trigger'] != 'new_booking') continue; $action = []; $action['type'] = 'trigger_webhook'; $action['settings']['url'] = $webhook['url']; $process_actions[$webhook['id']] = $action; } } // CREATE NEW BOOKING PROCESSES IF THERE ARE ANY ACTIONS if ($process_actions) { // put all under single process with multiple actions $process = new OsProcessModel(); $process->event_type = 'booking_created'; $process->name = 'Booking created notification'; $process_actions = OsProcessesHelper::iterate_trigger_conditions([], $process_actions); $process_actions[0]['time_offset'] = []; $process->actions_json = wp_json_encode($process_actions); if (!OsProcessesHelper::check_if_process_exists($process)) $process->save(); } // migrate other webhooks (not new booking) into processes if ($webhooks) { $process_actions_for_triggers = ['updated_booking' => [], 'new_customer' => [], 'new_transaction' => []]; foreach ($webhooks as $webhook) { if ($webhook['status'] != 'active' || !in_array($webhook['trigger'], ['updated_booking', 'new_customer', 'new_transaction'])) continue; $process_actions_for_triggers[$webhook['trigger']][$webhook['id']] = ['type' => 'trigger_webhook', 'settings' => ['url' => $webhook['url']]]; } foreach ($process_actions_for_triggers as $webhook_trigger => $actions) { if ($actions) { $process = new OsProcessModel(); switch ($webhook_trigger) { case 'updated_booking': $process->name = 'Booking updated notification'; $process->event_type = 'booking_updated'; break; case 'new_customer': $process->name = 'New customer notification'; $process->event_type = 'customer_created'; break; case 'new_transaction': $process->name = 'New transaction notification'; $process->event_type = 'transaction_created'; break; } $process_actions = OsProcessesHelper::iterate_trigger_conditions([], $actions); $process_actions[0]['time_offset'] = []; $process->actions_json = wp_json_encode($process_actions); if (!OsProcessesHelper::check_if_process_exists($process)) $process->save(); } } } // migrate reminders into processes // old example: {"rem_0zMZzZVY":{"name":"Reminder to customer","medium":"email","receiver":"customer","value":"7","unit":"day","when":"before","subject":"Reminder","content":"<p>Testing<\/p>","id":"rem_0zMZzZVY"}} // multiple: {"rem_POtZuDDd":{"name":"Sms Reminder before","medium":"sms","receiver":"customer","value":"7","unit":"day","when":"before","subject":"","content":"<p>Testing<\/p>","id":"rem_POtZuDDd"},"rem_q4kA6JwC":{"name":"Sms Reminder after","medium":"sms","receiver":"agent","value":"7","unit":"day","when":"after","subject":"test","content":"Testing","id":"rem_q4kA6JwC"},"rem_hR6YOF3w":{"name":"Email Reminder after","medium":"email","receiver":"agent","value":"7","unit":"day","when":"after","subject":"test","content":"Testing","id":"rem_hR6YOF3w"}} $reminders = json_decode(OsSettingsHelper::get_settings_value('reminders', ''), true); if ($reminders) { $processes = []; $actions = []; foreach ($reminders as $reminder) { // create action $action = []; $action_id = \LatePoint\Misc\ProcessAction::generate_id(); $action['settings']['content'] = OsUtilHelper::replace_single_curly_with_double($reminder['content'] ?? ''); switch ($reminder['medium']) { case 'sms': $action['type'] = 'send_sms'; $action['settings']['to_phone'] = ($reminder['receiver'] == 'customer') ? '{{customer_phone}}' : '{{agent_phone}}'; break; case 'email': $action['type'] = 'send_email'; $action['settings']['to_email'] = ($reminder['receiver'] == 'customer') ? '{{customer_email}}' : '{{agent_email}}'; $action['settings']['subject'] = OsUtilHelper::replace_single_curly_with_double($reminder['subject']); break; } // generate time offset $time_offset = ['value' => $reminder['value'], 'unit' => $reminder['unit'], 'before_after' => $reminder['when']]; // attach to process if ($processes) { $existing = false; // try to find process that matches parameters for ($i = 0; $i < count($processes); $i++) { if ($processes[$i]['time_offset'] == $time_offset) { $processes[$i]['actions'][$action_id] = $action; $existing = true; break; } } // didn't find process with same time offset, create new if (!$existing) { $process = ['name' => $reminder['name'], 'event_type' => 'booking_start', 'time_offset' => $time_offset, 'actions' => []]; $process['actions'][$action_id] = $action; $processes[] = $process; } } else { $process = ['name' => $reminder['name'], 'event_type' => 'booking_start', 'time_offset' => $time_offset, 'actions' => []]; $process['actions'][$action_id] = $action; $processes[] = $process; } } if ($processes) { foreach ($processes as $process_data) { $process = new OsProcessModel(); $process->event_type = $process_data['event_type']; $process->name = $process_data['name']; $process_actions = OsProcessesHelper::iterate_trigger_conditions([], $process_data['actions']); $process_actions[0]['time_offset'] = $process_data['time_offset']; $process->actions_json = wp_json_encode($process_actions); if (!OsProcessesHelper::check_if_process_exists($process)) $process->save(); } } } // Update customer phone numbers to new E.164 format based on the country that was selected in settings $customers = new OsCustomerModel(); $customers = $customers->get_results_as_models(); foreach ($customers as $customer) { if (empty($customer->phone)) continue; $formatted_phone = OsUtilHelper::sanitize_phone_number($customer->phone, OsSettingsHelper::get_settings_value('country_phone_code', '')); if (!empty($formatted_phone)) $customer->update_attributes(['phone' => $formatted_phone]); } // update agent phone numbers $agents = new OsAgentModel(); $agents = $agents->get_results_as_models(); foreach ($agents as $agent) { if (empty($agent->phone)) continue; $formatted_phone = OsUtilHelper::sanitize_phone_number($agent->phone, OsSettingsHelper::get_settings_value('country_phone_code', '')); if (!empty($formatted_phone)) $agent->update_attributes(['phone' => $formatted_phone]); } } if (version_compare('1.4.91', $current_db_version) > 0) { $sqls = []; $has_column = OsDatabaseHelper::run_query("SHOW COLUMNS FROM " . LATEPOINT_TABLE_BOOKINGS . " LIKE 'start_datetime_gmt'"); if ($has_column) $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_BOOKINGS . " DROP COLUMN start_datetime_gmt"; $has_column = OsDatabaseHelper::run_query("SHOW COLUMNS FROM " . LATEPOINT_TABLE_BOOKINGS . " LIKE 'end_datetime_gmt'"); if ($has_column) $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_BOOKINGS . " DROP COLUMN end_datetime_gmt"; if (!empty($sqls)) OsDatabaseHelper::run_queries($sqls); } if (version_compare('2.0.0', $current_db_version) > 0) { // we used to have a typo in a column name, check if it still exists and assign its values to a correctly named column $has_typo = OsDatabaseHelper::run_query("SHOW COLUMNS FROM " . LATEPOINT_TABLE_BOOKINGS . " LIKE 'total_attendies'"); if ($has_typo) { $sqls = []; $sqls[] = "UPDATE " . LATEPOINT_TABLE_BOOKINGS . " SET total_attendees = total_attendies WHERE total_attendees IS NULL"; OsDatabaseHelper::run_queries($sqls); } // deactivate old addons that are replaced by a PRO addon $plugins_to_deactivate = [ 'latepoint-custom-fields/latepoint-custom-fields.php', 'latepoint-locations/latepoint-locations.php', 'latepoint-webhooks/latepoint-webhooks.php', 'latepoint-qr-code/latepoint-qr-code.php', 'latepoint-reminders/latepoint-reminders.php', 'latepoint-role-manager/latepoint-role-manager.php', 'latepoint-timezone-selector/latepoint-timezone-selector.php', 'latepoint-group-bookings/latepoint-group-bookings.php', 'latepoint-taxes/latepoint-taxes.php', 'latepoint-service-durations/latepoint-service-durations.php', 'latepoint-service-extras/latepoint-service-extras.php', 'latepoint-messages/latepoint-messages.php', 'latepoint-coupons/latepoint-coupons.php', ]; $deactivated_plugins = []; foreach ($plugins_to_deactivate as $plugin) { if (is_plugin_active($plugin)) { $deactivated_plugins[] = OsUtilHelper::extract_plugin_name_from_path($plugin); deactivate_plugins($plugin); } } $report = OsMigrationsHelper::migrate_from_version_4(); if($deactivated_plugins) OsSettingsHelper::save_setting_by_name('migration_version_5_deactivated_plugins', implode(', ', $deactivated_plugins)); // if wizard has not been visited yet - redirect to it add_option('latepoint_show_version_5_modal', true); } if (version_compare('2.2.5', $current_db_version) > 0) { $sqls = []; $sqls = "ALTER TABLE ".LATEPOINT_TABLE_CUSTOMERS." MODIFY COLUMN email VARCHAR(320) NULL"; OsDatabaseHelper::run_queries($sqls); } /** * Hook your updates to database that need to be run for specific version of database * * @since 1.0.0 * @hook latepoint_run_version_specific_updates * * @param {string} version of database before the update */ do_action('latepoint_run_version_specific_updates', $current_db_version); return true; } public static function set_end_date_for_bookings() { $sqls = []; $sqls[] = "UPDATE " . LATEPOINT_TABLE_BOOKINGS . " SET end_date = start_date WHERE end_date IS NULL;"; return $sqls; } public static function get_queries_for_nullable_columns() { $sqls = []; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_BOOKINGS . " MODIFY COLUMN ip_address varchar(55), MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_CUSTOMER_META . " MODIFY COLUMN meta_value text, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_SETTINGS . " MODIFY COLUMN value text, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_SERVICES . " MODIFY COLUMN short_description text, MODIFY COLUMN is_price_variable boolean, MODIFY COLUMN price_min decimal(20,4), MODIFY COLUMN price_max decimal(20,4), MODIFY COLUMN charge_amount decimal(20,4), MODIFY COLUMN is_deposit_required boolean, MODIFY COLUMN buffer_before int(11), MODIFY COLUMN buffer_after int(11), MODIFY COLUMN category_id int(11), MODIFY COLUMN order_number int(11), MODIFY COLUMN selection_image_id int(11), MODIFY COLUMN description_image_id int(11), MODIFY COLUMN bg_color varchar(20), MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_AGENTS . " MODIFY COLUMN avatar_image_id int(11), MODIFY COLUMN last_name varchar(255), MODIFY COLUMN phone varchar(255), MODIFY COLUMN password varchar(255), MODIFY COLUMN custom_hours boolean, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_STEP_SETTINGS . " MODIFY COLUMN value text, MODIFY COLUMN step varchar(50), MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_CUSTOMERS . " MODIFY COLUMN last_name varchar(255), MODIFY COLUMN phone varchar(255), MODIFY COLUMN avatar_image_id int(11), MODIFY COLUMN password varchar(255), MODIFY COLUMN activation_key varchar(255), MODIFY COLUMN account_nonse varchar(255), MODIFY COLUMN google_user_id varchar(255), MODIFY COLUMN facebook_user_id varchar(255), MODIFY COLUMN is_guest boolean, MODIFY COLUMN notes text, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime;"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_SERVICE_CATEGORIES . " MODIFY COLUMN short_description text, MODIFY COLUMN parent_id mediumint(9), MODIFY COLUMN selection_image_id int(11), MODIFY COLUMN order_number int(11), MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_CUSTOM_PRICES . " MODIFY COLUMN is_price_variable boolean, MODIFY COLUMN price_min decimal(20,4), MODIFY COLUMN price_max decimal(20,4), MODIFY COLUMN charge_amount decimal(20,4), MODIFY COLUMN is_deposit_required boolean, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_WORK_PERIODS . " MODIFY COLUMN custom_date date, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_AGENTS_SERVICES . " MODIFY COLUMN is_custom_hours BOOLEAN, MODIFY COLUMN is_custom_price BOOLEAN, MODIFY COLUMN is_custom_duration BOOLEAN, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_ACTIVITIES . " MODIFY COLUMN agent_id int(11), MODIFY COLUMN booking_id int(11), MODIFY COLUMN service_id int(11), MODIFY COLUMN customer_id int(11), MODIFY COLUMN description text, MODIFY COLUMN initiated_by varchar(100), MODIFY COLUMN initiated_by_id int(11), MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime"; $sqls[] = "ALTER TABLE " . LATEPOINT_TABLE_TRANSACTIONS . " MODIFY COLUMN notes text, MODIFY COLUMN created_at datetime, MODIFY COLUMN updated_at datetime"; return $sqls; } }