PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.15
Booktics – Appointment Booking Calendar for Service Businesses v1.0.15
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 / base / models / appointment-model.php

appointment-model.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.15, at base/models/appointment-model.php

313 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Appoint Model
4 *
5 * @package Booktics/Models
6 */
7
8 namespace Booktics\Models;
9
10 use Booktics\Abstracts\Booktics_Database;
11 use Booktics\Abstracts\Post_Model;
12 use Booktics\Models\Service_Model;
13 use Exception;
14
15 /**
16 * AppointmentModel class
17 */
18 class Appointment_Model extends Post_Model {
19 /**
20 * Store appointment data
21 *
22 * @var array
23 */
24 protected $fillable = array(
25 'id' => '',
26 'title' => '',
27 'content' => '',
28 'start_time' => '',
29 'end_time' => '',
30 'date' => '',
31 'buffer_before' => '',
32 'buffer_after' => '',
33 'duration' => '',
34 'status' => '',
35 'payment_status' => '',
36 'customer_id' => '',
37 'customer_name' => '',
38 'team_member_id' => '',
39 'service_id' => '',
40 'additional_duration_id' => '',
41 'group_booking' => array(),
42 'order_id' => '',
43 'quantity' => 0,
44 'price' => 0,
45 'subtotal' => 0,
46 'total' => 0,
47 'note' => '',
48 'source' => '',
49 'location_id' => '',
50 'location' => array(),
51 'extra_services' => array(),
52 'security_token' => '',
53 'total_attendees' => 1,
54 'timezone' => '',
55 'cancel_note' => '',
56 );
57
58 /**
59 * Accepted post statuses for appointments
60 *
61 * @var array
62 */
63 public static $accepted_statuses = array(
64 'pending',
65 'active',
66 'cancelled',
67 'canceled',
68 'completed',
69 'approved',
70 'not_now',
71 );
72
73 /**
74 * Get post type
75 *
76 * @return string Post type name
77 */
78 public function get_post_type() {
79 return 'booktics-appointment';
80 }
81
82 /**
83 * Get accepted statuses
84 *
85 * @return array Accepted statuses
86 */
87 public static function get_accepted_statuses() {
88 return self::$accepted_statuses;
89 }
90
91 /**
92 * Specify data which should be serialized to JSON.
93 *
94 * @return array
95 */
96 public function jsonSerialize(): array {
97 $data = $this->to_array();
98
99 $service = Service_Model::find( $this->service_id );
100 $db = new Booktics_Database();
101 $customer = ( new Guest_Model( $db ) )->find( array( 'id' => $this->customer_id ) );
102 $team_member = ( new Team_Member_Model() )->find( $this->team_member_id );
103
104 $appointment_data = array(
105 'service' => $service,
106 'team_member' => $team_member,
107 'customer' => $customer,
108 );
109
110 return array_merge( $data, $appointment_data );
111 }
112
113 /**
114 * Get appointments for a specific date and service/team member
115 *
116 * @param string $date
117 * @param int $team_member_id
118 *
119 * @return array
120 * @throws Exception
121 */
122 public function get_appointments_for_slot( string $date, int $team_member_id ): array {
123 $args = array(
124 'post_type' => $this->get_post_type(),
125 'post_status' => booktics_get_option( 'appointment_statuses_for_blocked_slot', array( 'publish', 'active', 'pending' ) ),
126 'posts_per_page' => - 1,
127 'meta_query' => array(
128 'relation' => 'AND',
129 array(
130 'key' => 'date',
131 'value' => $date,
132 'compare' => '=',
133 ),
134 array(
135 'key' => 'team_member_id',
136 'value' => $team_member_id,
137 'compare' => '=',
138 ),
139 ),
140 );
141
142 $query = new \WP_Query( $args );
143
144 return array_map(
145 function ( $post ) {
146 return new static( $post );
147 }, $query->posts
148 );
149 }
150
151 /**
152 * Override load_attributes to include payment status from orders
153 *
154 * @return void
155 */
156 protected function load_attributes() {
157 parent::load_attributes();
158
159 if ( $this->order_id ) {
160 $db = new Booktics_Database();
161 $order_model = ( new Order_Model( $db ) )->find( array( 'id' => $this->order_id ) );
162
163 $this->attributes['payment_status'] = $order_model->payment_status ?? 'pending';
164 } else {
165 $this->attributes['payment_status'] = 'pending';
166 }
167 }
168
169 /**
170 * Get appointments count by order ID
171 *
172 * @param int $order_id Order ID
173 *
174 * @return int Number of appointments
175 */
176 public function get_appointments_count_by_order_id( $order_id ) {
177 $args = array(
178 'post_type' => $this->get_post_type(),
179 'post_status' => array( 'publish', 'active', 'approved', 'completed', 'pending' ),
180 'posts_per_page' => - 1,
181 'meta_query' => array(
182 array(
183 'key' => 'order_id',
184 'value' => $order_id,
185 'compare' => '=',
186 ),
187 ),
188 );
189
190 $query = new \WP_Query( $args );
191
192 return $query->found_posts;
193 }
194
195 /**
196 * Get appointments count by team member ID
197 *
198 * @param int $team_member_id Team member ID
199 *
200 * @return int Number of appointments
201 */
202 public function get_appointments_count_by_team_member_id( $team_member_id ) {
203 $args = array(
204 'post_type' => $this->get_post_type(),
205 'post_status' => array( 'publish', 'active', 'pending' ),
206 'posts_per_page' => - 1,
207 'meta_query' => array(
208 array(
209 'key' => 'team_member_id',
210 'value' => $team_member_id,
211 'compare' => '=',
212 ),
213 ),
214 );
215
216 $query = new \WP_Query( $args );
217
218 return $query->found_posts;
219 }
220
221 /**
222 * Get reschedule link
223 *
224 * @return string Reschedule link
225 */
226 public function get_reschedule_link() {
227 if ( ! booktics_get_option( 'allow_customer_rescheduling', false ) ) {
228 return '';
229 }
230
231 $this->add_security_token_if_not_exists();
232
233 $service_permalink = $this->get_associated_service_permalink();
234
235 $reschedule_url = add_query_arg( [
236 'service_id' => $this->service_id,
237 'appointment_id' => $this->id,
238 'booking_action' => 'reschedule',
239 'appointment_token' => $this->security_token,
240 'order_id' => $this->order_id,
241 'team_member_id' => $this->team_member_id,
242 ], $service_permalink );
243
244 return esc_url( $reschedule_url );
245 }
246
247 /**
248 * Get cancel link
249 *
250 * @return string Cancel link
251 */
252 public function get_cancel_link() {
253 if ( ! booktics_get_option( 'allow_customer_cancellation', false ) ) {
254 return '';
255 }
256
257 $this->add_security_token_if_not_exists();
258
259 $service_permalink = $this->get_associated_service_permalink();
260
261 $cancel_url = add_query_arg( [
262 'service_id' => $this->service_id,
263 'appointment_id' => $this->id,
264 'booking_action' => 'cancel',
265 'appointment_token' => $this->security_token,
266 'order_id' => $this->order_id,
267 'team_member_id' => $this->team_member_id,
268 ], $service_permalink );
269
270 return esc_url( $cancel_url );
271 }
272
273 /**
274 * Get associated service permalink
275 *
276 * @return string Service permalink
277 */
278 private function get_associated_service_permalink() {
279 if ( ! $this->service_id ) {
280 return '';
281 }
282
283 $service = Service_Model::find( $this->service_id );
284
285 return $service->link ?? '';
286 }
287
288 /**
289 * Generate a security token for the appointment
290 * This generated token is used to verify access to the appointment rescheduling and cancellation
291 *
292 * @return string Security token
293 */
294 public function generate_security_token() {
295 $token = bin2hex( random_bytes(4) ); // 8 hex chars
296
297 return $token;
298 }
299
300 /**
301 * Check if the security token exists, if not generate and save it to the post meta.
302 * This token is used to verify access to the appointment rescheduling and cancellation.
303 *
304 * @return void
305 */
306 public function add_security_token_if_not_exists() {
307 if ( empty( $this->security_token ) ) {
308 $this->security_token = $this->generate_security_token();
309 $this->save();
310 }
311 }
312 }
313