PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.12
Booktics – Appointment Booking Calendar for Service Businesses v1.0.12
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
booktics / core / appointment / services / appointment-service.php

appointment-service.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.12, at core/appointment/services/appointment-service.php

203 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Booktics\Appointment\Services;
3
4 use Booktics\Abstracts\Booktics_Database;
5 use WP_Error;
6 use Booktics\Utils\Singleton;
7 use Booktics\Models\Appointment_Model;
8 use Booktics\Models\Guest_Model;
9 use Booktics\Models\Order_Model;
10
11 class Appointment_Service {
12
13 use Singleton;
14
15 /**
16 * Create a new appointment.
17 * @param array $data
18 * @return mixed (Appointment object or WP_Error)
19 */
20 public static function create( array $data ) {
21 // Sanitize and prepare data as needed
22 $appointment = Appointment_Model::create( $data );
23 if ( $appointment && ! is_wp_error( $appointment ) ) {
24 // Ensure a security token is always present for new appointments
25 $appointment->add_security_token_if_not_exists();
26 }
27 return $appointment;
28 }
29
30 /**
31 * Update an existing appointment.
32 * @param int $id
33 * @param array $data
34 * @return mixed (Updated appointment object or WP_Error)
35 */
36 public static function update( int $id, array $data ) {
37 $appointment = Appointment_Model::find( $id );
38 if ( ! $appointment ) {
39 return new WP_Error( 'not_found', __( 'Appointment not found', 'booktics' ) );
40 }
41
42 // Store original status to check if it's being changed
43 $original_status = $appointment->status;
44 $new_status = isset( $data['status'] ) ? $data['status'] : null;
45
46 // Optionally handle customer update
47 if ( ! empty( $data['customer'] ) ) {
48 $db = new Booktics_Database();
49 $customer = ( new Guest_Model( $db ) )->find( array( 'id' => $appointment->customer_id ) );
50 if ( $customer ) {
51 $updated_customer = ( new Guest_Model( $db ) )
52 ->update( $appointment->customer_id, $data['customer'] );
53 unset( $data['customer'] );
54 $appointment->customer = $updated_customer;
55 }
56 }
57
58 $updated_appointment = $appointment->update( $data );
59 if ( is_wp_error( $updated_appointment ) ) {
60 return $updated_appointment;
61 }
62
63 // Update associated order status if appointment status changed
64 if ( $new_status && $new_status !== $original_status ) {
65 self::sync_order_status( $appointment, $new_status );
66 }
67
68 return $updated_appointment;
69 }
70
71 /**
72 * Update associated order status when appointment status changes
73 *
74 * @param object $appointment The appointment object
75 * @param string $new_status The new status to set for the order
76 * @return void
77 */
78 private static function sync_order_status( $appointment, string $new_status ) {
79 // Get order_id using fillable property accessor with post meta fallback
80 $order_id = $appointment->order_id ?: get_post_meta( $appointment->id, 'order_id', true );
81
82 if ( empty( $order_id ) ) {
83 return;
84 }
85
86 $db = new Booktics_Database();
87 $order_model = new Order_Model( $db );
88 $order = $order_model->find( array( 'id' => $order_id ) );
89
90 if ( ! $order || is_wp_error( $order ) ) {
91 return;
92 }
93
94 $order_model->update( $order_id, array( 'status' => $new_status ) );
95 }
96
97 /**
98 * Delete an appointment by ID.
99 * @param int $id
100 * @return mixed (Deleted appointment object or WP_Error)
101 */
102 public static function delete( int $id ) {
103 $appointment = Appointment_Model::find( $id );
104 if ( ! $appointment ) {
105 return new WP_Error( 'not_found', __( 'Appointment not found', 'booktics' ) );
106 }
107 $deleted = $appointment->delete();
108 if ( is_wp_error( $deleted ) ) {
109 return $deleted;
110 }
111 return $appointment;
112 }
113
114 /**
115 * Delete multiple appointments by IDs.
116 * @param array $ids
117 * @return array|WP_Error
118 */
119 public static function delete_many( array $ids ) {
120 if ( ! is_array( $ids ) ) {
121 return new WP_Error( 'invalid_ids', __( 'Ids should be an array of items ids', 'booktics' ) );
122 }
123 $count = 0;
124 $total = count( $ids );
125 $deleted = array();
126 foreach ( $ids as $id ) {
127 $appointment = Appointment_Model::find( $id );
128 if ( $appointment ) {
129 $appointment->delete();
130 $deleted[] = $appointment;
131 ++$count;
132 }
133 }
134 if ( $count === 0 ) {
135 return new WP_Error( 'none_deleted', __( 'No item deleted.', 'booktics' ) );
136 }
137 $message = sprintf( 'Deleted %d items of %d', $count, $total );
138 return array(
139 'data' => $deleted,
140 'message' => $message,
141 );
142 }
143
144 /**
145 * Reschedule an appointment.
146 * @param int $id
147 * @param array $data
148 * @return mixed (Updated appointment object or WP_Error)
149 */
150 public static function reschedule( int $id, array $data ) {
151 $appointment = Appointment_Model::find( $id );
152 if ( ! $appointment ) {
153 return new WP_Error( 'not_found', __( 'Appointment not found', 'booktics' ) );
154 }
155 $reschedule_data = array(
156 'start_time' => sanitize_text_field( $data['start_time'] ),
157 'end_time' => sanitize_text_field( $data['end_time'] ),
158 'date' => sanitize_text_field( $data['date'] ),
159 );
160 $customer_reschedule_status = booktics_get_option( 'customer_reschedule_status', array( 'enable' => false ) );
161 if ( $customer_reschedule_status['enable'] ) {
162 $reschedule_data['status'] = $customer_reschedule_status['status'];
163 }
164 $updated = $appointment->update( $reschedule_data );
165 if ( is_wp_error( $updated ) ) {
166 return new WP_Error( 'reschedule_error', __( 'Appointment reschedule error.', 'booktics' ) );
167 }
168 // Optionally fire hooks here
169 return $appointment;
170 }
171
172 /**
173 * Cancel an appointment.
174 * @param int $id
175 * @param array $data Additional data like cancel_note
176 * @return mixed (Updated appointment object or WP_Error)
177 */
178 public static function cancel( int $id, array $data = [] ) {
179 $appointment = Appointment_Model::find( $id );
180 if ( ! $appointment ) {
181 return new WP_Error( 'not_found', __( 'Appointment not found', 'booktics' ) );
182 }
183
184 $update_data = [ 'status' => 'canceled' ];
185
186 if ( ! empty( $data['cancel_note'] ) ) {
187 $update_data['cancel_note'] = sanitize_text_field( $data['cancel_note'] );
188 }
189
190 $updated = $appointment->update( $update_data );
191
192 if ( is_wp_error( $updated ) ) {
193 return new WP_Error( 'cancel_error', __( 'Appointment cancellation error.', 'booktics' ) );
194 }
195
196 // Update associated order status to canceled
197 self::sync_order_status( $appointment, 'canceled' );
198
199 // Optionally fire hooks here
200 return $appointment;
201 }
202 }
203