PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.20
Booktics – Appointment Booking Calendar for Service Businesses v1.0.20
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.20, at core/appointment/services/appointment-service.php

204 lines 6.9 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 /* translators: 1: deleted count, 2: total count */
138 $message = sprintf( __( 'Deleted %1$d items of %2$d', 'booktics' ), $count, $total );
139 return array(
140 'data' => $deleted,
141 'message' => $message,
142 );
143 }
144
145 /**
146 * Reschedule an appointment.
147 * @param int $id
148 * @param array $data
149 * @return mixed (Updated appointment object or WP_Error)
150 */
151 public static function reschedule( int $id, array $data ) {
152 $appointment = Appointment_Model::find( $id );
153 if ( ! $appointment ) {
154 return new WP_Error( 'not_found', __( 'Appointment not found', 'booktics' ) );
155 }
156 $reschedule_data = array(
157 'start_time' => sanitize_text_field( $data['start_time'] ),
158 'end_time' => sanitize_text_field( $data['end_time'] ),
159 'date' => sanitize_text_field( $data['date'] ),
160 );
161 $customer_reschedule_status = booktics_get_option( 'customer_reschedule_status', array( 'enable' => false ) );
162 if ( $customer_reschedule_status['enable'] ) {
163 $reschedule_data['status'] = $customer_reschedule_status['status'];
164 }
165 $updated = $appointment->update( $reschedule_data );
166 if ( is_wp_error( $updated ) ) {
167 return new WP_Error( 'reschedule_error', __( 'Appointment reschedule error.', 'booktics' ) );
168 }
169 // Optionally fire hooks here
170 return $appointment;
171 }
172
173 /**
174 * Cancel an appointment.
175 * @param int $id
176 * @param array $data Additional data like cancel_note
177 * @return mixed (Updated appointment object or WP_Error)
178 */
179 public static function cancel( int $id, array $data = [] ) {
180 $appointment = Appointment_Model::find( $id );
181 if ( ! $appointment ) {
182 return new WP_Error( 'not_found', __( 'Appointment not found', 'booktics' ) );
183 }
184
185 $update_data = [ 'status' => 'canceled' ];
186
187 if ( ! empty( $data['cancel_note'] ) ) {
188 $update_data['cancel_note'] = sanitize_text_field( $data['cancel_note'] );
189 }
190
191 $updated = $appointment->update( $update_data );
192
193 if ( is_wp_error( $updated ) ) {
194 return new WP_Error( 'cancel_error', __( 'Appointment cancellation error.', 'booktics' ) );
195 }
196
197 // Update associated order status to canceled
198 self::sync_order_status( $appointment, 'canceled' );
199
200 // Optionally fire hooks here
201 return $appointment;
202 }
203 }
204