[Back] <?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;
}
}