1382 lines
47 KiB
PHP
1382 lines
47 KiB
PHP
<?php
|
|
/**
|
|
* Simply Schedule Appointment Revision Model.
|
|
*
|
|
* @since 6.1.0
|
|
* @package Simply_Schedule_Appointments
|
|
*/
|
|
|
|
/**
|
|
* Simply Schedule Appointment Revision Model.
|
|
*
|
|
* @since 6.1.0
|
|
*/
|
|
class SSA_Revision_Model extends SSA_Db_Model {
|
|
protected $slug = 'revision';
|
|
protected $version = '3.7.6';
|
|
/**
|
|
* Parent plugin class.
|
|
*
|
|
* @since 6.1.0
|
|
*
|
|
* @var Simply_Schedule_Appointments
|
|
*/
|
|
protected $plugin = null;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @since 6.1.0
|
|
*
|
|
* @param Simply_Schedule_Appointments $plugin Main plugin object.
|
|
*/
|
|
public function __construct( $plugin ) {
|
|
|
|
parent::__construct( $plugin );
|
|
|
|
$this->hooks();
|
|
}
|
|
|
|
/**
|
|
* Initiate our hooks.
|
|
*
|
|
* @since 6.1.0
|
|
*/
|
|
public function hooks() {
|
|
add_action( 'ssa/appointment/booked', array( $this, 'insert_revision_booked_appointment' ), 10, 3 );
|
|
add_action( 'ssa/appointment/edited', array( $this, 'insert_revision_edited_appointment' ), 10, 3 );
|
|
add_action( 'ssa/appointment/rescheduled', array( $this, 'insert_revision_rescheduled_appointment' ), 10, 3 );
|
|
add_action( 'ssa/appointment/abandoned', array( $this, 'insert_revision_abandoned_appointment' ), 10, 3 );
|
|
add_action( 'ssa/appointment/canceled', array( $this, 'insert_revision_canceled_appointment' ), 10, 3 );
|
|
add_action( 'ssa/appointment/pending', array( $this, 'insert_revision_pending_appointment' ), 10, 3 );
|
|
|
|
// Add revision on appointment no show/reverted
|
|
add_action( 'ssa/appointment/no_show', array( $this, 'insert_revision_no_show_appointment' ), 10, 3 );
|
|
add_action( 'ssa/appointment/no_show_reverted', array( $this, 'insert_revision_no_show_reverted_appointment' ), 10, 3 );
|
|
|
|
// Add revision first assigned to team member
|
|
add_action( 'ssa/appointment/after_insert', array( $this, 'maybe_insert_revision_assigned_appointment' ), 1000, 2 );
|
|
|
|
// Add revision record whenever an appointment is reassigned
|
|
add_action( 'ssa/appointment/after_update', array( $this, 'maybe_insert_revision_reassigned_appointment' ), 1000, 3 );
|
|
|
|
|
|
// scheduled cleanup
|
|
add_action( 'init', array( $this, 'schedule_async_actions' ) );
|
|
add_action( 'ssa/revisions/cleanup', array( $this, 'cleanup_revisions' ), 10, 0 );
|
|
|
|
// Notifications
|
|
add_action( 'ssa/notification/scheduled', array( $this, 'insert_revision_on_notification_scheduled' ), 10, 9 );
|
|
add_action( 'ssa/notification/sent', array( $this, 'insert_revision_on_notification_sent' ), 10, 8 );
|
|
|
|
//Appointment Types revisions
|
|
add_action( 'ssa/appointment_type/after_insert', array( $this, 'insert_revision_created_appointment_type' ), 1000, 3 );
|
|
add_action( 'ssa/appointment_type/after_delete', array( $this, 'insert_revision_deleted_appointment_type' ), 1000, 3 );
|
|
add_action( 'ssa/appointment_type/after_update', array( $this, 'insert_revision_updated_appointment_type' ), 1000, 3 );
|
|
}
|
|
|
|
/**
|
|
* Scheduling the revisions cleanup async action
|
|
*
|
|
* @return void
|
|
*/
|
|
public function schedule_async_actions() {
|
|
if( ssa_should_skip_async_logic() ) {
|
|
return;
|
|
}
|
|
|
|
// below functions wrap the action scheduler methods, make all the needed checks and log any failures
|
|
if ( false === ssa_has_scheduled_action( 'ssa/revisions/cleanup' ) ) {
|
|
ssa_schedule_recurring_action( strtotime( 'now' ), DAY_IN_SECONDS, 'ssa/revisions/cleanup' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* revisions scheduled cleanup
|
|
*
|
|
* @return void
|
|
*/
|
|
public function cleanup_revisions() {
|
|
$revisions = $this->query(
|
|
array(
|
|
'date_created_max' => date( 'Y-m-d H:i:s', strtotime( '-3 months' ) ),
|
|
)
|
|
);
|
|
|
|
// get ids of revisions as an array
|
|
$revisions_ids = wp_list_pluck( $revisions, 'id' );
|
|
if ( ! empty( $revisions_ids ) ) {
|
|
// delete all corresponding revision_meta rows
|
|
$this->plugin->revision_meta_model->bulk_delete(
|
|
array(
|
|
'revision_id' => $revisions_ids,
|
|
)
|
|
);
|
|
// delete revisions rows
|
|
$this->bulk_delete(
|
|
array(
|
|
'id' => $revisions_ids,
|
|
) );
|
|
}
|
|
|
|
$this->check_orphaned_revisions_meta();
|
|
}
|
|
|
|
/**
|
|
* Check for orphaned revisions meta, that their revision_id doesn't exist and delete them
|
|
* TODO: Consider removing this function in the future
|
|
*
|
|
* @return void
|
|
*/
|
|
public function check_orphaned_revisions_meta() {
|
|
// make sure to query all the revisions entries
|
|
$revisions = $this->query(
|
|
array(
|
|
'number' => -1,
|
|
'orderby' => 'id',
|
|
'order' => 'ASC',
|
|
'fields' => ['id']
|
|
)
|
|
);
|
|
|
|
if ( empty( $revisions ) ) {
|
|
return; // This should be a new site with no appointments yet.
|
|
}
|
|
|
|
$revisions = wp_list_pluck( $revisions, 'id', 'id' );
|
|
|
|
$revision_meta = $this->plugin->revision_meta_model->query(
|
|
array(
|
|
'number' => 50,
|
|
'orderby' => 'id',
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
if ( empty( $revision_meta ) ) {
|
|
return;
|
|
}
|
|
|
|
$revision_meta = wp_list_pluck( $revision_meta, 'id', 'revision_id' );
|
|
|
|
$revisons_ids_to_delete = array();
|
|
foreach ( $revision_meta as $revison_id => $id ) {
|
|
if ( ! isset( $revisions[ $revison_id ] ) ) {
|
|
$revisons_ids_to_delete[] = $revison_id;
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $revisons_ids_to_delete ) ) {
|
|
$this->plugin->revision_meta_model->bulk_delete(
|
|
array(
|
|
'revision_id' => $revisons_ids_to_delete,
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
public function has_many() {
|
|
return array(
|
|
// TODO check correct name
|
|
'Revision_Meta_Values' => array(
|
|
'model' => $this->plugin->revision_meta_model,
|
|
'foreign_key' => 'revision_id',
|
|
),
|
|
);
|
|
}
|
|
|
|
protected $schema = array(
|
|
'result' => array(
|
|
'field' => 'result',
|
|
'label' => 'Result',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'VARCHAR', // 'success', 'failure', or 'warning'
|
|
'mysql_length' => '8',
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
// foreign key
|
|
'appointment_id' => array(
|
|
'field' => 'appointment_id',
|
|
'label' => 'Appointment ID',
|
|
'default_value' => 0,
|
|
'format' => '%d',
|
|
'mysql_type' => 'BIGINT',
|
|
'mysql_length' => 20,
|
|
'mysql_unsigned' => true,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// foreign key
|
|
'appointment_type_id' => array(
|
|
'field' => 'appointment_type_id',
|
|
'label' => 'Appointment Type ID',
|
|
'default_value' => 0,
|
|
'format' => '%d',
|
|
'mysql_type' => 'BIGINT',
|
|
'mysql_length' => 20,
|
|
'mysql_unsigned' => true,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// foreign key
|
|
'user_id' => array(
|
|
'field' => 'user_id',
|
|
'label' => 'Customer ID',
|
|
'default_value' => 0,
|
|
'format' => '%d',
|
|
'mysql_type' => 'BIGINT',
|
|
'mysql_length' => 20,
|
|
'mysql_unsigned' => true,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// foreign key
|
|
'staff_id' => array(
|
|
'field' => 'staff_id',
|
|
'label' => 'Staff ID',
|
|
'default_value' => 0,
|
|
'format' => '%d',
|
|
'mysql_type' => 'BIGINT',
|
|
'mysql_length' => 20,
|
|
'mysql_unsigned' => true,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// foreign key
|
|
'payment_id' => array(
|
|
'field' => 'payment_id',
|
|
'label' => 'Payment ID',
|
|
'default_value' => 0,
|
|
'format' => '%d',
|
|
'mysql_type' => 'BIGINT',
|
|
'mysql_length' => 20,
|
|
'mysql_unsigned' => true,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// foreign key
|
|
'async_action_id' => array(
|
|
'field' => 'async_action_id',
|
|
'label' => 'Async Action ID',
|
|
'default_value' => 0,
|
|
'format' => '%d',
|
|
'mysql_type' => 'BIGINT',
|
|
'mysql_length' => 20,
|
|
'mysql_unsigned' => true,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// allows filtering/looking at what happened in a certain timeframe
|
|
'date_created' => array(
|
|
'field' => 'date_created',
|
|
'label' => 'Date Created',
|
|
'default_value' => false,
|
|
'format' => '%s',
|
|
'mysql_type' => 'DATETIME',
|
|
'mysql_length' => '',
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => true,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// action ( edit, cancel, etc...)
|
|
'action' => array(
|
|
'field' => 'action',
|
|
'label' => 'Action',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'VARCHAR',
|
|
'mysql_length' => '32',
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// action_title ( Appointment Canceled, Appointment Booked, etc...)
|
|
'action_title' => array(
|
|
'field' => 'action_title',
|
|
'label' => 'Action Title',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'TINYTEXT',
|
|
'mysql_length' => false,
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// event summary
|
|
'action_summary' => array(
|
|
'field' => 'action_summary',
|
|
'label' => 'Action Summary',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'TEXT',
|
|
'mysql_length' => false,
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
'summary_vars' => array(
|
|
'field' => 'summary_vars',
|
|
'label' => 'Summary Variables',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'TEXT',
|
|
'mysql_length' => false,
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
'encoder' => 'json_serialize',
|
|
),
|
|
|
|
// context ( booking, settings, syncing etc...)
|
|
'context' => array(
|
|
'field' => 'context',
|
|
'label' => 'Context',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'VARCHAR',
|
|
'mysql_length' => '32',
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
// better filtering, also cross context filtering, like web meetings across several contexts (google, zoom,, etc)
|
|
'sub_context' => array(
|
|
'field' => 'sub_context',
|
|
'label' => 'Sub Context',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'VARCHAR',
|
|
'mysql_length' => '32',
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => false,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
|
|
'stack_trace' => array(
|
|
'field' => 'stack_trace',
|
|
'label' => 'Stack Trace',
|
|
'default_value' => '',
|
|
'format' => '%s',
|
|
'mysql_type' => 'TEXT',
|
|
'mysql_length' => false,
|
|
'mysql_unsigned' => false,
|
|
'mysql_allow_null' => true,
|
|
'mysql_extra' => '',
|
|
'cache_key' => false,
|
|
),
|
|
);
|
|
|
|
|
|
// below fields are indexed to use in filtering, like getting all events of a certain appointment_id
|
|
public $indexes = array(
|
|
'appointment_id' => array( 'appointment_id' ),
|
|
'appointment_type_id' => array( 'appointment_type_id' ),
|
|
'user_id' => array( 'user_id' ),
|
|
'staff_id' => array( 'staff_id' ),
|
|
'async_action_id' => array( 'async_action_id' ),
|
|
'date_created' => array( 'date_created' ),
|
|
'action' => array( 'action' ),
|
|
'context' => array( 'context' ),
|
|
'sub_context' => array( 'sub_context' ),
|
|
);
|
|
|
|
|
|
public function get_items_permissions_check( $request ) {
|
|
|
|
if ( current_user_can( 'ssa_manage_others_appointments' ) ) {
|
|
return true;
|
|
}
|
|
|
|
if ( current_user_can( 'ssa_manage_appointments' ) ) {
|
|
return true;
|
|
}
|
|
|
|
if (current_user_can( 'ssa_manage_appointment_types' ) ) {
|
|
return true;
|
|
}
|
|
|
|
if ( true === parent::get_item_permissions_check( $request ) ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// TODO IMPORTANT: if each action only has one foreign id populated, 2 or more of the below where conditions will eliminate every result
|
|
public function filter_where_conditions( $where, $args ) {
|
|
global $wpdb;
|
|
if ( ! empty( $args['appointment_id'] ) ) {
|
|
if( is_array( $args['appointment_id'] ) ) {
|
|
$appointment_ids = implode( ',', array_map('intval', $args['appointment_id'] ) );
|
|
} else {
|
|
$appointment_ids = intval( $args['appointment_id'] );
|
|
}
|
|
$where .= " AND `appointment_id` IN( $appointment_ids ) ";
|
|
}
|
|
|
|
if ( ! empty( $args['appointment_type_id'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND appointment_type_id=%d', sanitize_text_field( $args['appointment_type_id'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['user_id'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND user_id=%d', sanitize_text_field( $args['user_id'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['staff_id'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND staff_id=%d', sanitize_text_field( $args['staff_id'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['async_action_id'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND async_action_id=%d', sanitize_text_field( $args['async_action_id'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['date_created'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND date_created=%s', sanitize_text_field( $args['date_created'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['action'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND action=%s', sanitize_text_field( $args['action'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['context'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND context=%s', sanitize_text_field( $args['context'] ) );
|
|
}
|
|
|
|
if ( ! empty( $args['sub_context'] ) ) {
|
|
$where .= $wpdb->prepare( ' AND sub_context=%s', sanitize_text_field( $args['sub_context'] ) );
|
|
}
|
|
|
|
return $where;
|
|
|
|
}
|
|
|
|
// =================================================================================
|
|
//
|
|
// Section: Revision insertion function definitions
|
|
//
|
|
// Pattern: functions restructure the data available then pass it to insert_revision
|
|
// ==================================================================================
|
|
|
|
/**
|
|
* When it's first assigned to a team member
|
|
*
|
|
* @param integer $appointment_id
|
|
* @param array $data
|
|
* @return void
|
|
*/
|
|
public function maybe_insert_revision_assigned_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
|
|
if ( empty( $data_after['staff_ids'] ) || ! empty( $data_before ) ) return;
|
|
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'assigned',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before,
|
|
'staff_ids' => $data_after['staff_ids']
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function maybe_insert_revision_reassigned_appointment( $appointment_id, $data_after, $data_before ) {
|
|
|
|
if ( SSA_Appointment_Model::is_appointment_reassigned( $data_after, $data_before ) ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'reassigned',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before,
|
|
'staff_ids' => $data_after['staff_ids']
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
}
|
|
|
|
public function insert_revision_gcal_after_sync( $result, $appointment_id, $action, $action_summary, $calendar_id, $calendar_event_id, $event = null ) {
|
|
$revision_meta = array(
|
|
'calendar_id' => $calendar_id,
|
|
'calendar_event_id' => $calendar_event_id,
|
|
);
|
|
|
|
if ( ! empty( $event ) ) {
|
|
$revision_meta['event'] = (array) $event;
|
|
}
|
|
|
|
// below: hints for WP.org to pick up phrases for translation
|
|
// __( 'Could not find existing event details for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
// __( 'Error while creating event for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
// __( 'Deleted group event for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
// __( 'Deleted individual event for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
// __( 'Exception occured while doing sync for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
// __( 'Inserted GCAL event for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
// __( 'Updated GCAL event for appointment ID {{ appointment_id }}', 'simply-schedule-appointments' );
|
|
|
|
$this->insert_revision(
|
|
array(
|
|
'result' => $result,
|
|
'appointment_id' => $appointment_id,
|
|
'action' => $action,
|
|
'action_title' => $this->get_action_title( $action, $result ),
|
|
'action_summary' => $action_summary,
|
|
'summary_vars' => array(),
|
|
'context' => 'gcal',
|
|
'sub_context' => 'sync',
|
|
),
|
|
$revision_meta
|
|
);
|
|
}
|
|
|
|
// insert revisions opt out notification
|
|
public function insert_revision_opt_out_notification( $appointment_id, $data_after ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'opt_out_notification',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => array(),
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_abandoned_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'abandoned',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_edited_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'edited',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_rescheduled_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
// Formatting the appointment date and time
|
|
$date_format = SSA_Utils::localize_default_date_strings( 'F j, Y' );
|
|
$time_format = SSA_Utils::localize_default_date_strings( 'g:i a' );
|
|
|
|
$business_previous_start_date = $this->plugin->utils->get_datetime_as_local_datetime( $data_before['start_date'] )->format( $date_format );
|
|
$business_previous_start_time = $this->plugin->utils->get_datetime_as_local_datetime( $data_before['start_date'] )->format( $time_format );
|
|
|
|
$business_start_date = $this->plugin->utils->get_datetime_as_local_datetime( $data_after['start_date'] )->format( $date_format );
|
|
$business_start_time = $this->plugin->utils->get_datetime_as_local_datetime( $data_after['start_date'] )->format( $time_format );
|
|
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'rescheduled',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before,
|
|
'business_previous_start_date' => $business_previous_start_date,
|
|
'business_previous_start_time' => $business_previous_start_time,
|
|
'business_start_date' => $business_start_date,
|
|
'business_start_time' => $business_start_time,
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_booked_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
$action = empty( $data_before ) ? 'first_booked' : 'booked';
|
|
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => $action,
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_canceled_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'canceled',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_pending_appointment( $appointment_id, $data_after, $data_before = null ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => $data_after['status'], // pending_form or pending_payment
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => null
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_no_show_appointment( $appointment_id, $data_after, $meta_data ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'no_show',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => null
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_no_show_reverted_appointment( $appointment_id, $data_after, $meta_data ) {
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'no_show_reverted',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => null
|
|
);
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_appointment( $params ) {
|
|
|
|
if ( empty( $params['action'] || empty( $this->get_action_title( $params['action'] ) ) ) ) {
|
|
return;
|
|
}
|
|
|
|
// below: hints for WP.org to pick up phrases for translation
|
|
// __( '{{ user }} changed the appointment status to {{ action }}', 'simply-schedule-appointments' );
|
|
$revision = array(
|
|
'result' => $params['result'],
|
|
'appointment_id' => $params['appointment_id'],
|
|
'action' => $params['action'],
|
|
'action_title' => $this->get_action_title( $params['action'] ),
|
|
'action_summary' => $this->get_action_summary( $params['action'] ),
|
|
'summary_vars' => array(
|
|
'user' => $this->get_user_name(),
|
|
'staff' => empty( $params['staff_ids'] ) ? array() : $params['staff_ids'],
|
|
'action' => $params['action'],
|
|
'action_noun' => empty( $params['action_noun'] ) ? null : $params['action_noun'],
|
|
'action_verb' => empty( $params['action_verb'] ) ? null : $params['action_verb'],
|
|
'recipient_type'=> isset($params['recipient_type']) ? $params['recipient_type'] : null,
|
|
'notification_type'=> isset($params['notification_type']) ? $params['notification_type'] : null,
|
|
'notification_date'=> isset($params['notification_date']) ? $params['notification_date'] : null,
|
|
'notification_time'=> isset($params['notification_time']) ? $params['notification_time'] : null,
|
|
'business_previous_start_date' => isset( $params['business_previous_start_date'] ) ? $params['business_previous_start_date'] : null,
|
|
'business_previous_start_time' => isset( $params['business_previous_start_time'] ) ? $params['business_previous_start_time'] : null,
|
|
'business_start_date' => isset( $params['business_start_date'] ) ? $params['business_start_date'] : null,
|
|
'business_start_time' => isset( $params['business_start_time'] ) ? $params['business_start_time'] : null,
|
|
'notification_cancelation_reason' => isset( $params['notification_cancelation_reason'] ) ? $params['notification_cancelation_reason'] : null,
|
|
'notification_title' => isset( $params['notification_title'] ) ? $params['notification_title'] : null,
|
|
),
|
|
'context' => 'booking',
|
|
);
|
|
|
|
// in the revision_meta
|
|
// only set meta_value_before if it has a value.
|
|
// because if the field is set to null, the db will not insert the record.
|
|
$revision_meta = array();
|
|
|
|
// append appointment status changes
|
|
if ( ! isset( $params['data_after']['status'] ) && isset( $params['data_before']['status'] ) ) {
|
|
// If status is not set we assume it didn't change
|
|
$params['data_after']['status'] = $params['data_before']['status'];
|
|
}
|
|
|
|
$revision_meta['status']['meta_value'] = $params['data_after']['status'];
|
|
|
|
if ( isset( $params['data_before']['status'] ) ) {
|
|
$revision_meta['status']['meta_value_before'] = $params['data_before']['status'];
|
|
}
|
|
|
|
// append appointment raw data changes
|
|
$revision_meta['raw_data']['meta_value'] = $params['data_after'];
|
|
if ( isset( $params['data_before'] ) ) {
|
|
$revision_meta['raw_data']['meta_value_before'] = $params['data_before'];
|
|
}
|
|
|
|
// insert revision
|
|
$this->insert_revision( $revision, $revision_meta );
|
|
}
|
|
|
|
// signarture of function that renders the action summary
|
|
// $this->plugin->templates->render_template_string('{{ user }} changed the appointment status to {{ action }}',['user'=>'name','action'=>'action'])
|
|
|
|
// =========================================================================
|
|
//
|
|
// main re-usable function - use to insert revisions and revisions meta data
|
|
//
|
|
// =========================================================================
|
|
public function insert_revision( $revision = array(), $revision_meta = array() ) {
|
|
if ( ! isset( $revision['result'] ) ) {
|
|
ssa_debug_log( 'must specify result to create revision', 10 );
|
|
ssa_debug_log( print_r( $revision, true ), 10 ); //phpcs:ignore
|
|
return;
|
|
}
|
|
if (
|
|
! isset( $revision['appointment_id'] ) &&
|
|
! isset( $revision['appointment_type_id'] ) &&
|
|
! isset( $revision['staff_id'] ) &&
|
|
! isset( $revision['payment_id'] ) &&
|
|
! isset( $revision['async_action_id'] ) ) {
|
|
ssa_debug_log( 'must reference at least one foreign key to create revision', 10 );
|
|
ssa_debug_log( print_r( $revision, true ), 10 ); //phpcs:ignore
|
|
return;
|
|
}
|
|
if ( ! isset( $revision['action'] ) ) {
|
|
ssa_debug_log( "action field must be set to create revision\n", 10 );
|
|
ssa_debug_log( print_r( $revision, true ), 10 ); //phpcs:ignore
|
|
return;
|
|
}
|
|
if ( ! isset( $revision['action_summary'] ) ) {
|
|
ssa_debug_log( "action_summary field must be set to create revision\n", 10 );
|
|
ssa_debug_log( print_r( $revision, true ), 10 ); //phpcs:ignore
|
|
return;
|
|
}
|
|
if ( ! isset( $revision['context'] ) ) {
|
|
ssa_debug_log( "context field must be set to create revision\n", 10 );
|
|
ssa_debug_log( print_r( $revision, true ), 10 ); //phpcs:ignore
|
|
return;
|
|
}
|
|
|
|
// Call & get the stack trace for each revision before insert
|
|
$stack_trace = ssa_get_stack_trace();
|
|
|
|
// merge with default values
|
|
$revision = wp_parse_args(
|
|
$revision,
|
|
array(
|
|
'user_id' => get_current_user_id(),
|
|
'summary_vars' => array(),
|
|
'stack_trace' => $this->parse_stack_trace_before_insert( $stack_trace )
|
|
)
|
|
);
|
|
|
|
// pass on an array of meta data to be batch inserted under this revision's id in the meta table
|
|
if ( ! empty( $revision_meta ) ) {
|
|
$revision['meta_data'] = $revision_meta;
|
|
}
|
|
|
|
// insert revision and get its id
|
|
$revision_id = $this->insert( $revision );
|
|
|
|
return $revision_id;
|
|
}
|
|
|
|
public function prepare_item_for_response( $item, $recursive = 0 ) {
|
|
$item = parent::prepare_item_for_response( $item, $recursive );
|
|
|
|
if ( $recursive >= 0 ) {
|
|
$item['action_title'] = __( $item['action_title'], 'simply-schedule-appointments' );
|
|
$item['action_summary_populated'] = $this->popuplate_action_summary_for_response( $item );
|
|
}
|
|
|
|
return $item;
|
|
}
|
|
|
|
public function get_action_title( $action, $result = 'success' ) {
|
|
// Only get/edit action titles here
|
|
$action_titles = array(
|
|
'synced_successfully' => 'Appointment Synced',
|
|
'failed_to_sync' => 'Appointment Failed to Sync',
|
|
'first_booked' => 'Appointment Booked',
|
|
'booked' => 'Appointment Booked',
|
|
'canceled' => 'Appointment Canceled',
|
|
'rescheduled' => 'Appointment Rescheduled',
|
|
'edited' => 'Appointment Edited',
|
|
'abandoned' => 'Appointment Abandoned',
|
|
'pending_payment' => 'Appointment\'s Payment Pending',
|
|
'pending_form' => 'Appointment\'s Form Pending',
|
|
'no_show' => 'Marked as No Show',
|
|
'no_show_reverted' => 'No Show Reverted',
|
|
'assigned' => 'Appointment Assigned',
|
|
'reassigned' => 'Appointment Reassigned',
|
|
'notification_scheduled' => 'Notification Scheduled',
|
|
'notification_with_duration' => 'Notification Scheduled',
|
|
'reminder' => 'Notification Scheduled',
|
|
'notification_sent' => 'Notification Sent',
|
|
'notification_canceled' => 'Notification Canceled',
|
|
'notification_not_sent' => 'Notification Not Sent',
|
|
'publish' => 'Appointment Type Created',
|
|
'delete' => 'Appointment Type Deleted',
|
|
'recover' => 'Appointment Type Recovered',
|
|
'title_changed' => 'Title Changed',
|
|
'min_booking_notice_changed' => 'Notice Required Changed',
|
|
'buffer_before_changed' => 'Buffer Before Changed',
|
|
'buffer_after_changed' => 'Buffer After Changed',
|
|
'max_event_count_changed' => 'Per Day Limit Changed',
|
|
'status_changed' => 'Appointment Type Recovered',
|
|
'capacity_changed' => 'Capacity Changed',
|
|
'capacity_type_changed' => 'Capacity Type Changed',
|
|
'timezone_style_changed' => 'Timezone Changed',
|
|
'duration_changed' => 'Duration Changed',
|
|
'label_id_changed' => 'Label Color changed',
|
|
'slug_changed' => 'Slug changed',
|
|
'instructions_changed' => 'Instructions changed',
|
|
'availability_increment_changed' => 'Availability Start Times Changed',
|
|
'availability_type_changed' => 'Availability Type Changed',
|
|
'availability_changed'=> 'Availability Schedule Changed',
|
|
'web_meetings_changed'=> 'Web Meetings Changed',
|
|
'booking_flow_settings_changed'=> 'Booking Flow Changed',
|
|
'customer_information_changed'=> 'Customer Information Changed',
|
|
'staff_changed' => 'Team Members Changed',
|
|
'staff_ids_changed' => 'Team Members Staff Changed',
|
|
'staff_capacity_changed' => 'Staff Capacity Changed',
|
|
'has_max_capacity_changed' => 'Max Capacity Changed',
|
|
'reminder_sent' => 'Notification Sent',
|
|
'reminder_not_sent'=>'Notification Not Sent',
|
|
'max_booking_notice_changed' => 'Max Booking Notice Changed',
|
|
'shared_calendar_event_changed' => 'Shared Calendar Event Changed',
|
|
'opt_out_notification' => 'Opt Out Notification',
|
|
);
|
|
|
|
// Update the array below whenever needed
|
|
if ( in_array( $action, array( 'sync_appointment_to_calendar' ) ) ) {
|
|
return $result === 'success' ? $action_titles['synced_successfully'] : $action_titles['failed_to_sync'];
|
|
}
|
|
|
|
if ( isset( $action_titles[ $action ] ) ) {
|
|
return $action_titles[$action];
|
|
}
|
|
|
|
// We shouldn't really end up here
|
|
ssa_debug_log( "Action `$action` does not exist in get_action_title\n", 5 );
|
|
return;
|
|
}
|
|
|
|
public function create_item_permissions_check( $request ) {
|
|
// only ssa code should interact with this class
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if a given request has access to update a specific item
|
|
*
|
|
* @param WP_REST_Request $request Full data about the request.
|
|
* @return WP_Error|bool
|
|
*/
|
|
public function update_item_permissions_check( $request ) {
|
|
// only ssa code should interact with this class
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check and return the logged in user name
|
|
* Otherwise return 'A logged out user'
|
|
*
|
|
* @param array $data
|
|
* @return string
|
|
*/
|
|
public function get_user_name() {
|
|
|
|
$current_user = wp_get_current_user();
|
|
|
|
// We don't have a logged in user
|
|
if ( empty( $current_user->ID ) ) {
|
|
return __( 'A logged out user', 'simply-schedule-appointments');
|
|
}
|
|
|
|
// First check if who's booking/editing is a staff member
|
|
if( class_exists( 'SSA_Staff_Model' ) ) {
|
|
$staff_id = $this->plugin->staff_model->get_staff_id_for_user_id( $current_user->ID );
|
|
|
|
if( ! empty( $staff_id ) ) {
|
|
$staff = new SSA_Staff_Object( $staff_id );
|
|
return $staff->display_name;
|
|
}
|
|
}
|
|
|
|
if( ! empty( $current_user->display_name ) ) {
|
|
return $current_user->display_name;
|
|
}
|
|
|
|
if( ! empty( $current_user->user_login ) ) {
|
|
return $current_user->user_login;
|
|
}
|
|
|
|
// Just in case if all have failed
|
|
return __( 'A logged out user', 'simply-schedule-appointments');
|
|
|
|
}
|
|
|
|
public function popuplate_action_summary_for_response( $item ) {
|
|
/* translators: If found, between double curly braces {{ Should not be translated }}. Actions: booked, canceled, pending_payment.. */
|
|
$action_summary = esc_html__( $item['action_summary'], 'simply-schedule-appointments' );
|
|
$summary_vars = $item['summary_vars'];
|
|
|
|
// Regular expression to match placeholders wrapped inside double curly braces
|
|
$pattern = '/{{\s*(.*?)\s*}}/';
|
|
|
|
// Check if the action_summary contains placeholders
|
|
if ( preg_match( $pattern, $action_summary ) ) {
|
|
// Replace the placeholders with actual values
|
|
$action_summary = preg_replace_callback($pattern, function($matches) use ($summary_vars) {
|
|
$placeholder = $matches[1];
|
|
// Check if the placeholder corresponds to a valid variable name
|
|
if ( isset( $summary_vars[ $placeholder ] ) ) {
|
|
if ( $placeholder === 'action' ) {
|
|
// Only allow translations for actions
|
|
return __( $summary_vars[ $placeholder ], 'simply-schedule-appointments' );
|
|
}
|
|
if ( $placeholder === 'staff' ) {
|
|
$staff_ids = $summary_vars[ $placeholder ];
|
|
$staff_names = array();
|
|
|
|
foreach ( $staff_ids as $staff_id ) {
|
|
$name = SSA_Staff_Model::get_staff_name_by_id( $staff_id );
|
|
array_push($staff_names, $name);
|
|
}
|
|
if ( empty( $staff_names ) ) {
|
|
return __( 'no one', 'simply-schedule-appointments' );
|
|
}
|
|
return implode(", ", $staff_names);
|
|
}
|
|
return $summary_vars[ $placeholder ];
|
|
} else {
|
|
// Placeholder does not correspond to a valid variable name
|
|
return $matches[0]; // return the original placeholder
|
|
}
|
|
}, $action_summary );
|
|
}
|
|
return $action_summary;
|
|
|
|
}
|
|
|
|
public function get_action_summary( $action = '' ) {
|
|
switch ( $action ) {
|
|
case 'first_booked':
|
|
return 'Appointment booked by {{ user }}';
|
|
case 'assigned':
|
|
return 'Appointment assigned to {{ staff }}';
|
|
case 'reassigned':
|
|
return 'Appointment reassigned to {{ staff }}';
|
|
case 'edited':
|
|
return 'Appointment edited by {{ user }}';
|
|
case 'rescheduled':
|
|
return 'Appointment rescheduled by {{ user }} from {{ business_previous_start_date }} at {{ business_previous_start_time }} to {{ business_start_date }} at {{ business_start_time }}';
|
|
case 'booked':
|
|
case 'canceled':
|
|
case 'abandoned':
|
|
case 'pending_payment':
|
|
case 'pending_form':
|
|
return '{{ user }} changed the appointment status to {{ action }}';
|
|
case 'no_show':
|
|
return 'Appointment marked as no show by {{ user }}';
|
|
case 'no_show_reverted':
|
|
return 'No show Status reverted by {{ user }}';
|
|
case 'notification_scheduled':
|
|
return 'The notification was scheduled to inform the {{ recipient_type }} that an {{ action_noun }} has been {{ action_verb }}.';
|
|
case 'notification_with_duration':
|
|
return 'The notification was scheduled to be sent on {{ notification_date }} at {{ notification_time }} to inform the {{ recipient_type }} that an {{ action_noun }} has been {{ action_verb }}.';
|
|
case 'reminder':
|
|
return 'The notification was scheduled to be sent on {{ notification_date }} at {{ notification_time }} to remind the {{ recipient_type }} about the appointment.';
|
|
case 'notification_sent':
|
|
return 'The notification was sent by {{ notification_type }} to inform the {{ recipient_type }} that an {{ action_noun }} has been {{ action_verb }}.';
|
|
case 'notification_not_sent':
|
|
return "The notification by {{ notification_type }}, to inform the {{ recipient_type }} that an {{ action_noun }} has been {{ action_verb }}, could not be sent";
|
|
case 'publish':
|
|
return 'Appointment Type created by {{ user }}';
|
|
case 'delete':
|
|
return 'Appointment Type deleted by {{ user }}';
|
|
case 'recover':
|
|
return 'Appointment Type recovered by {{ user }}';
|
|
case 'title_changed':
|
|
return '{{ user }} changed the appointment type title from {{ old_field }} to {{ new_field }}';
|
|
case 'min_booking_notice_changed':
|
|
return '{{ user }} changed the notice required from {{ old_field }} to {{ new_field }}';
|
|
case 'max_booking_notice_changed':
|
|
return '{{ user }} changed how far in advance customers can book an appointment from {{ old_field }} to {{ new_field }}';
|
|
case 'shared_calendar_event_changed':
|
|
return '{{ user }} changed the shared event settings for google calendar';
|
|
case 'buffer_before_changed':
|
|
return '{{ user }} changed the buffer before from {{ old_field }} to {{ new_field }}';
|
|
case 'buffer_after_changed':
|
|
return '{{ user }} changed the buffer after from {{ old_field }} to {{ new_field }}';
|
|
case 'max_event_count_changed':
|
|
return '{{ user }} changed the maximum number of appointments from {{ old_field }} to {{ new_field }}';
|
|
case 'status_changed':
|
|
return '{{ user }} recovered this appointment type';
|
|
case 'capacity_changed':
|
|
return '{{ user }} changed the capacity from {{ old_field }} to {{ new_field }}';
|
|
case 'capacity_type_changed':
|
|
return '{{ user }} changed the capacity type from {{ old_field }} to {{ new_field }}';
|
|
case 'timezone_style_changed':
|
|
return '{{ user }} changed the timezone from {{ old_field }} to {{ new_field }}';
|
|
case 'duration_changed':
|
|
return '{{ user }} changed the duration form {{ old_field }} to {{ new_field }}';
|
|
case 'label_id_changed':
|
|
return '{{ user }} changed the label color';
|
|
case 'slug_changed':
|
|
return '{{ user }} changed the slug from {{ old_field }} to {{ new_field }}';
|
|
case 'instructions_changed':
|
|
return '{{ user }} changed the instructions to {{ new_field }}';
|
|
case 'availability_type_changed':
|
|
return '{{ user }} changed the availability type from {{ old_field }} to {{ new_field }}';
|
|
case 'availability_changed':
|
|
return '{{ user }} changed the availability schedule';
|
|
case 'availability_increment_changed':
|
|
return '{{ user }} changed the appointment start times from {{ old_field }} to {{ new_field }}';
|
|
case 'web_meetings_changed':
|
|
return '{{ user }} changed the web meetings settings';
|
|
case 'booking_flow_settings_changed':
|
|
return '{{ user }} changed the booking flow settings';
|
|
case 'customer_information_changed':
|
|
return '{{ user }} changed the customer information fields';
|
|
case 'staff_changed':
|
|
return '{{ user }} changed the team member booking rules';
|
|
case 'staff_ids_changed':
|
|
return '{{ user }} changed the team members staff';
|
|
case 'staff_capacity_changed':
|
|
return '{{ user }} changed the team members staff capacity';
|
|
case 'has_max_capacity_changed':
|
|
return '{{ user }} switched the maximum capacity option ';
|
|
case 'reminder_sent':
|
|
return 'The notification was sent by {{ notification_type }} to remind the {{ recipient_type }} about the appointment';
|
|
case 'reminder_not_sent':
|
|
return 'The notification by {{ notification_type }} to remind the {{ recipient_type }} about the appointment could not be sent';
|
|
case 'opt_out_notification':
|
|
return 'The user has not opted to receive notifications';
|
|
case 'notification_canceled':
|
|
return 'The "{{ notification_title }}" ({{ notification_type }}) notification to the {{ recipient_type }} was canceled for the following reason: {{ notification_cancelation_reason }}';
|
|
default:
|
|
return '{{ user }} changed the appointment status to {{ action }}';
|
|
}
|
|
}
|
|
|
|
public function parse_stack_trace_before_insert( $string = '' ) {
|
|
$pattern = '/#(\d+)\s+(.*)/';
|
|
preg_match_all( $pattern, $string, $matches, PREG_SET_ORDER );
|
|
|
|
$output = '';
|
|
|
|
foreach ( $matches as $match ) {
|
|
$order = $match[1];
|
|
|
|
// Skip first two traces since these would always be for [0] -> ssa_get_stack_trace() and [1]-> SSA_Revision_Model->insert_revision
|
|
if ( $order <= 1 ) {
|
|
continue;
|
|
}
|
|
|
|
// Skip traces over 18 level deep
|
|
if ( $order > 18 ) {
|
|
break;
|
|
}
|
|
|
|
$output .= $match[0]."\n";
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
public function insert_revision_on_notification_sent( $appointment_id, $response, $action_noun, $action_verb, $recipient_type,$notification_type,$data_after, $data_before) {
|
|
if ($response === true || (is_array($response) && !in_array(false, $response))){
|
|
$res = 'success';
|
|
if($action_noun == 'appointment_start'){
|
|
$action = 'reminder_sent';
|
|
}
|
|
else{
|
|
$action = 'notification_sent';}
|
|
}
|
|
else{
|
|
$res = 'failure';
|
|
if($action_noun == 'appointment_start'){
|
|
$action = 'reminder_not_sent';
|
|
}
|
|
else{
|
|
$action = 'notification_not_sent';
|
|
}
|
|
}
|
|
// Insert revision for notification sent
|
|
$params = array(
|
|
'result' => $res,
|
|
'action' => $action,
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before,
|
|
'action_noun' => $action_noun,
|
|
'action_verb' => $action_verb,
|
|
'recipient_type' => $recipient_type,
|
|
'notification_type' => $notification_type
|
|
);
|
|
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
|
|
public function insert_revision_on_notification_canceled( $appointment_id, $data) {
|
|
$defaults = [
|
|
'data_after' => [],
|
|
'data_before' => [],
|
|
'recipient_type' => '',
|
|
'notification_type' => '',
|
|
'notification_title' => '',
|
|
'notification_cancelation_reason' => '',
|
|
];
|
|
|
|
$data = array_merge($defaults, $data);
|
|
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'notification_canceled',
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data['data_after'],
|
|
'data_before' => $data['data_before'],
|
|
'recipient_type' => $data['recipient_type'],
|
|
'notification_type' => $data['notification_type'],
|
|
'notification_title'=> $data['notification_title'],
|
|
'notification_cancelation_reason'=> $data['notification_cancelation_reason'],
|
|
);
|
|
|
|
$this->insert_revision_appointment( $params );
|
|
}
|
|
|
|
public function insert_revision_on_notification_scheduled( $appointment_id, $action_noun, $action_verb, $notification_date, $notification_time, $duration, $recipient_type, $data_after, $data_before) {
|
|
if($duration > 0){
|
|
if($action_noun == 'appointment_start'){
|
|
$action = 'reminder';
|
|
}else{
|
|
$action = 'notification_with_duration';
|
|
}
|
|
}else{
|
|
if($action_noun == 'appointment_start'){
|
|
return ;
|
|
}else{
|
|
$action = 'notification_scheduled';
|
|
}
|
|
}
|
|
// Insert revision for notification scheduled
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => $action,
|
|
'appointment_id' => $appointment_id,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before,
|
|
'action_noun' => $action_noun,
|
|
'action_verb' => $action_verb,
|
|
'recipient_type' => $recipient_type,
|
|
'notification_date' => $notification_date,
|
|
'notification_time' => $notification_time,
|
|
);
|
|
|
|
$this->insert_revision_appointment( $params );
|
|
$username = $this->get_user_name();
|
|
}
|
|
|
|
public function insert_revision_appointment_type( $params ) {
|
|
|
|
if( empty( $params['action'] ) || empty( $this->get_action_title( $params['action'] ) ) ) {
|
|
return; // This is not a supported action
|
|
}
|
|
|
|
$revision = array(
|
|
'result' => $params['result'],
|
|
'appointment_type_id' => $params['appointment_type_id'],
|
|
'action' => $params['action'],
|
|
'action_title' => $this->get_action_title( $params['action'] ),
|
|
'action_summary' => $this->get_action_summary( $params['action'] ),
|
|
'summary_vars' => array(
|
|
'user' => $this->get_user_name(),
|
|
'old_field' => $params['old_field'],
|
|
'new_field' => $params['new_field']
|
|
),
|
|
'context' => 'appointment type',
|
|
);
|
|
|
|
// in the revision_meta
|
|
// only set meta_value_before if it has a value.
|
|
// because if the field is set to null, the db will not insert the record.
|
|
$revision_meta = array();
|
|
|
|
// append appointment status changes
|
|
if ( ! isset( $params['data_after']['status'] ) && isset( $params['data_before']['status'] ) ) {
|
|
// If status is not set we assume it didn't change
|
|
$params['data_after']['status'] = $params['data_before']['status'];
|
|
}
|
|
|
|
$revision_meta['status']['meta_value'] = $params['data_after']['status'];
|
|
|
|
if ( isset( $params['data_before']['status'] ) ) {
|
|
$revision_meta['status']['meta_value_before'] = $params['data_before']['status'];
|
|
}
|
|
|
|
// append appointment raw data changes
|
|
$revision_meta['raw_data']['meta_value'] = $params['data_after'];
|
|
if ( isset( $params['data_before'] ) ) {
|
|
$revision_meta['raw_data']['meta_value_before'] = $params['data_before'];
|
|
}
|
|
|
|
// insert revision
|
|
$this->insert_revision( $revision, $revision_meta );
|
|
}
|
|
|
|
public function insert_revision_created_appointment_type( $appointment_type_id, $data_after, $data_before = null) {
|
|
|
|
if( gettype($data_after) !== 'array' ){
|
|
$data_after = array();
|
|
}
|
|
|
|
if( gettype($data_before) !== 'array' ){
|
|
$data_before = array();
|
|
}
|
|
|
|
$data_after['status'] = 'publish';
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'publish',
|
|
'appointment_type_id' => $appointment_type_id,
|
|
'old_field' => '',
|
|
'new_field' => 'published',
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
$this->insert_revision_appointment_type( $params );
|
|
}
|
|
|
|
public function insert_revision_deleted_appointment_type( $appointment_type_id, $data_after, $data_before) {
|
|
|
|
if( gettype($data_after) !== 'array' ){
|
|
$data_after = array();
|
|
}
|
|
|
|
if( gettype($data_before) !== 'array' ){
|
|
$data_before = array();
|
|
}
|
|
|
|
$data_after['status'] = 'delete';
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => 'delete',
|
|
'appointment_type_id' => $appointment_type_id,
|
|
'old_field' => 'published',
|
|
'new_field' => 'deleted',
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
|
|
$this->insert_revision_appointment_type( $params );
|
|
}
|
|
|
|
public function insert_revision_updated_appointment_type( $appointment_type_id, $data_after, $data_before ) {
|
|
if(empty($data_after) || empty($data_before)){
|
|
return;
|
|
}
|
|
$changed_fields = $this->get_appt_type_changed_fields($data_after,$data_before);
|
|
foreach($changed_fields as $changed_field){
|
|
|
|
if ( empty( $data_after[ $changed_field ] ) || empty( $data_before[ $changed_field ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$old_field = $data_before[$changed_field];
|
|
$new_field = $data_after[$changed_field];
|
|
if($changed_field !== 'capacity' && $changed_field !== 'max_event_count'){
|
|
if (is_numeric($old_field) && is_int($old_field + 0)) {
|
|
$old_field = $this->display_duration($old_field);
|
|
}
|
|
if (is_numeric($new_field) && is_int($new_field + 0)) {
|
|
$new_field = $this->display_duration($new_field);
|
|
}
|
|
}
|
|
|
|
$params = array(
|
|
'result' => 'success',
|
|
'action' => $changed_field.'_changed',
|
|
'appointment_type_id' => $appointment_type_id,
|
|
'old_field' => $old_field ,
|
|
'new_field' => $new_field,
|
|
'data_after' => $data_after,
|
|
'data_before' => $data_before
|
|
);
|
|
$this->insert_revision_appointment_type( $params );
|
|
}
|
|
}
|
|
|
|
public function get_appt_type_changed_fields($data_after,$data_before){
|
|
$changed_fields =[];
|
|
|
|
foreach( $data_after as $key => $field ) {
|
|
if ( empty( $data_before[ $key ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
// No Need to record the re-ordering of appointment types
|
|
if ( $key === 'display_order'){
|
|
continue;
|
|
}
|
|
|
|
if( $data_before [ $key ] !== $field ) {
|
|
if ( $key === 'custom_customer_information') {
|
|
$key = 'customer_information';
|
|
}
|
|
$changed_fields[] = $key;
|
|
}
|
|
}
|
|
|
|
return $changed_fields;
|
|
}
|
|
|
|
//convert minutes to hours / days / weeks
|
|
public function display_duration($duration) {
|
|
$minutes = intval($duration);
|
|
|
|
if ($minutes === 0) {
|
|
return '0';
|
|
}
|
|
|
|
$type = 'minute';
|
|
$num = $minutes;
|
|
|
|
if ($minutes % (7 * 24 * 60) === 0) {
|
|
$num = $minutes / (7 * 24 * 60);
|
|
$type = 'week';
|
|
} elseif ($minutes % (24 * 60) === 0) {
|
|
$num = $minutes / (24 * 60);
|
|
$type = 'day';
|
|
} elseif ($minutes % 60 === 0) {
|
|
$num = $minutes / 60;
|
|
$type = 'hour';
|
|
}
|
|
|
|
$displayType = $num === 1 ? $type : $type . 's';
|
|
return $num . ' ' . $displayType;
|
|
}
|
|
|
|
}
|
|
|
|
|