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 / customer / controllers / customer-controller.php

customer-controller.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.12, at core/customer/controllers/customer-controller.php

612 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Booktics\Customer\Controllers;
4
5 use Booktics\Abstracts\Base_Rest_Controller;
6 use Booktics\Abstracts\Booktics_Database;
7 use Booktics\Abstracts\User_Model;
8 use Booktics\Customer\Handlers\Customer_Event_Handler;
9 use Booktics\Models\Appointment_Model;
10 use Booktics\Models\Customer_Model;
11 use Booktics\Models\Guest_Model;
12 use Booktics\Models\Order_Model;
13 use Booktics\Models\Payment_Model;
14 use WP_Error;
15 use WP_HTTP_Response;
16 use WP_REST_Response;
17 use WP_REST_Server;
18
19 /**
20 * Customer controller
21 *
22 * @package Booktics/Customer
23 */
24 class Customer_Controller extends Base_Rest_Controller {
25
26 /**
27 * Store namespace of api
28 *
29 * @var string
30 */
31 protected $namespace = 'booktics/v1';
32
33 /**
34 * Store base url
35 *
36 * @var string
37 */
38 protected $base = 'customers';
39
40 /**
41 *
42 *
43 * @return void
44 */
45 public function register_routes(): void {
46 register_rest_route(
47 $this->namespace, $this->base, array(
48 array(
49 'methods' => WP_REST_Server::CREATABLE,
50 'callback' => array( $this, 'create_item' ),
51 'permission_callback' => array(
52 $this,
53 'create_customer_permission',
54 ),
55 ),
56 array(
57 'methods' => WP_REST_Server::READABLE,
58 'callback' => array( $this, 'get_items' ),
59 'permission_callback' => array(
60 $this,
61 'get_customer_permission',
62 ),
63 ),
64 array(
65 'methods' => WP_REST_Server::DELETABLE,
66 'callback' => array( $this, 'delete_items' ),
67 'permission_callback' => array(
68 $this,
69 'delete_customer_permission',
70 ),
71 ),
72 )
73 );
74
75 register_rest_route(
76 $this->namespace, $this->base . '/profile', array(
77 array(
78 'methods' => WP_REST_Server::READABLE,
79 'callback' => array( $this, 'get_profile' ),
80 'permission_callback' => array(
81 $this,
82 'customer_profile_permission',
83 ),
84 ),
85 )
86 );
87
88 register_rest_route(
89 $this->namespace, '/' . $this->base . '/(?P<id>[\d]+)', array(
90 array(
91 'methods' => WP_REST_Server::EDITABLE,
92 'callback' => array( $this, 'update_item' ),
93 'permission_callback' => array(
94 $this,
95 'update_customer_permission',
96 ),
97 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
98 ),
99 array(
100 'methods' => WP_REST_Server::DELETABLE,
101 'callback' => array( $this, 'delete_item' ),
102 'permission_callback' => array(
103 $this,
104 'delete_customer_permission',
105 ),
106 ),
107 array(
108 'method' => WP_REST_Server::READABLE,
109 'callback' => array( $this, 'get_item' ),
110 'permission_callback' => array(
111 $this,
112 'get_customer_permission',
113 ),
114 ),
115 )
116 );
117
118 register_rest_route(
119 $this->namespace, '/' . $this->base . '/(?P<id>[\d]+)/connect', array(
120 array(
121 'methods' => WP_REST_Server::EDITABLE,
122 'callback' => array( $this, 'connect_customer' ),
123 'permission_callback' => array(
124 $this,
125 'update_customer_permission',
126 ),
127 ),
128 )
129 );
130
131 register_rest_route(
132 $this->namespace, '/' . $this->base . '/(?P<id>[\d]+)/disconnect', array(
133 array(
134 'methods' => WP_REST_Server::EDITABLE,
135 'callback' => array( $this, 'disconnect_customer' ),
136 'permission_callback' => array(
137 $this,
138 'update_customer_permission',
139 ),
140 ),
141 )
142 );
143 }
144
145 /**
146 * Check if a given request has access to create items.
147 *
148 * @param $request Full data about the request.
149 */
150 public function create_customer_permission( $request ) {
151 return current_user_can( 'manage_options' );
152 }
153
154 /**
155 * Prepare and validate customer data
156 *
157 * @param $request
158 *
159 * @return array|bool|WP_Error
160 */
161 protected function prepare_customer_data( $request ) {
162 $input_data = json_decode( $request->get_body(), true );
163
164 $validate = booktics_validate(
165 $input_data, array(
166 'name' => array(
167 'required',
168 ),
169 'email' => array(
170 'required',
171 'unique:' . booktics_get_table_name( 'booktics_guests' ) . ',email',
172 ),
173 )
174 );
175
176 if ( is_wp_error( $validate ) ) {
177 return $validate;
178 }
179
180 return array(
181 'name' => $input_data['name'],
182 'email' => $input_data['email'],
183 'user_login' => User_Model::generate_username( $input_data['email'] ),
184 'phone' => $input_data['phone'],
185 );
186 }
187
188 /**
189 * Store new customer data
190 *
191 * @param $request
192 *
193 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
194 */
195 public function create_item( $request ) {
196 $prepared_data = $this->prepare_customer_data( $request );
197 if ( is_wp_error( $prepared_data ) ) {
198 return $this->error(
199 $prepared_data->get_error_message(),
200 422,
201 'Validation',
202 $prepared_data->errors
203 );
204 }
205
206 $db = new Booktics_Database();
207 $customer = ( new Guest_Model( $db ) )->create( $prepared_data );
208 $image_url = $request->get_param( 'image' );
209 if ( $image_url ) {
210 $customer->update( array( 'image' => esc_url_raw( $image_url ) ) );
211 }
212
213 if ( ! $customer ) {
214 return $this->error( __( 'Customer create error', 'booktics' ), 500 );
215 }
216
217 do_action( 'booktics_customer_created', $customer, $request );
218
219 return $this->response( $customer, __( 'Successfully created customer', 'booktics' ), 201 );
220 }
221
222 /**
223 * Check if a given request has access to get all customer
224 *
225 * @param $request
226 *
227 * @return bool
228 */
229 public function get_customer_permission( $request ) {
230 return true;
231 }
232
233 /**
234 * Get paginated list items for customer
235 *
236 * @param $request
237 *
238 * @return WP_Error|WP_HTTP_Response|WP_REST_Response
239 */
240 public function get_items( $request ) {
241 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
242 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
243 $name = ! empty( $request['name'] ) ? trim( $request['name'] ) : '';
244 $email = ! empty( $request['email'] ) ? trim( $request['email'] ) : '';
245 $phone = ! empty( $request['phone'] ) ? trim( $request['phone'] ) : '';
246 $user_name = ! empty( $request['user_name'] ) ? trim( $request['user_name'] ) : '';
247 $search = ! empty( $request['search'] ) ? trim( $request['search'] ) : '';
248
249 $db = new Booktics_Database();
250 $customers = ( new Guest_Model( $db ) )->query();
251
252 $args = array(
253 'name' => array( 'LIKE', $name ),
254 'email' => array( 'LIKE', $email ),
255 'phone' => array( 'LIKE', $phone ),
256 'user_login' => array( 'LIKE', $user_name ),
257 );
258
259 foreach ( $args as $key => $value ) {
260 if ( $value[1] ) {
261 $customers->where( $key, $value[0], $value[1] );
262 }
263 }
264
265 if ( $search ) {
266 $customers->where( 'name', 'LIKE', $search )
267 ->or_where( 'email', 'LIKE', $search )
268 ->or_where( 'phone', 'LIKE', $search );
269 }
270
271 $customers = $customers->paginate( $paged, $per_page );
272 foreach ( $customers['items'] as &$customer ) {
273 $customer = ( new Guest_Model( $db ) )->with_virtual_attributes( $customer );
274 }
275
276 return $this->response( $customers, __( 'Successfully fetched customer', 'booktics' ) );
277 }
278
279 /**
280 * Checks if a given request has access to delete a team member.
281 *
282 * @param $request
283 *
284 * @return bool
285 */
286 public function delete_customer_permission( $request ) {
287 return current_user_can( 'manage_options' );
288 }
289
290 /**
291 * Delete a customer
292 *
293 * @param $request
294 *
295 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
296 */
297 public function delete_item( $request ) {
298 $id = intval( $request['id'] );
299
300 $db = new Booktics_Database();
301 $order_model = new Order_Model( $db );
302 $orders = $order_model->get( array( 'customer_id' => $id ) );
303 foreach ( $orders['items'] as $order ) {
304 $appointment_model = new Appointment_Model();
305 $appointments = $appointment_model->where( 'order_id', $order->id );
306 foreach ( $appointments as $appointment ) {
307 $appointment->delete();
308 }
309 $payment_model = new Payment_Model( $db );
310 $payments = $payment_model->get( array( 'order_id' => $order->id ) );
311 foreach ( $payments['items'] as $payment ) {
312 ( new Payment_Model( $db ) )->delete( $payment->id );
313 }
314 $order_model->delete( $order->id );
315 }
316
317 $guest_model = ( new Guest_Model( $db ) );
318 $guest = $guest_model->find( array( 'id' => $id ) );
319
320 if ( $guest->wp_user_id ) {
321 $customer = new Customer_Model( $guest->wp_user_id );
322 $customer->delete();
323 }
324
325 $deleted = $guest_model->delete( $id );
326 if ( ! $deleted ) {
327 return $this->error( __( 'Customer delete error', 'booktics' ), 500 );
328 }
329
330 do_action( 'booktics_customers_deleted', $request );
331
332 return $this->response( array(), __( 'Successfully deleted customer', 'booktics' ) );
333 }
334
335 /**
336 * Delete multiple customer
337 *
338 * @param $request
339 *
340 * @return array|WP_Error|WP_HTTP_Response
341 */
342 public function delete_items( $request ) {
343 $ids = ! empty( $request['ids'] ) ? $request['ids'] : array();
344
345 if ( ! $ids ) {
346 return $this->error( __( 'Customer ids cannot be empty', 'booktics' ), 500 );
347 }
348 $count = 0;
349 $db = new Booktics_Database();
350 foreach ( $ids as $id ) {
351 // Delete all orders (and their related appointments and payments) for this customer
352 $order_model = new Order_Model( $db );
353 $orders = $order_model->get( array( 'customer_id' => $id ) );
354 foreach ( $orders['items'] as $order ) {
355 // Delete related appointments
356 $appointment_model = new Appointment_Model();
357 $appointments = $appointment_model->where( 'order_id', $order->id );
358 foreach ( $appointments as $appointment ) {
359 $appointment->delete();
360 }
361 // Delete related payments
362 $payment_model = new Payment_Model( $db );
363 $payments = $payment_model->get( array( 'order_id' => $order->id ) );
364 foreach ( $payments['items'] as $payment ) {
365 ( new Payment_Model( $db ) )->delete( $payment->id );
366 }
367 // Delete the order
368 $order_model->delete( $order->id );
369 }
370 $guest_model = ( new Guest_Model( $db ) );
371 $guest = $guest_model->find( array( 'id' => $id ) );
372 if ( $guest->wp_user_id ) {
373 $customer = new Customer_Model( $guest->wp_user_id );
374 $customer->delete();
375 }
376 if ( $guest_model->delete( $id ) ) {
377 ++$count;
378 }
379 }
380 if ( $count == 0 ) {
381 return $this->error( __( 'Customer delete error', 'booktics' ), 500 );
382 }
383
384 do_action( 'booktics_customers_deleted', $request );
385
386 return $this->response( array(), __( 'Successfully deleted customer', 'booktics' ) );
387 }
388
389 /**
390 * Get single customer
391 *
392 * @param $request
393 *
394 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
395 */
396 public function get_item( $request ) {
397 $id = intval( $request['id'] );
398 $db = new Booktics_Database();
399 $customer = ( new Guest_Model( $db ) )->find( array( 'id' => $id ) );
400 if ( ! $customer ) {
401 return $this->error( __( 'Customer not found', 'booktics' ), 404 );
402 }
403
404 $orders = ( new Order_Model( $db ) )->get( array( 'customer_id' => $id ) );
405 $customer->orders = array_map(
406 function ( $order ) {
407 $booking_count = ( new Appointment_Model() )
408 ->get_appointments_count_by_order_id( $order->id );
409
410 return array(
411 'date' => $order->created_at ? gmdate( 'j F, Y', strtotime( $order->created_at ) ) : '',
412 'total_booking' => $booking_count,
413 'total_amount' => $order->total,
414 );
415 }, $orders['items']
416 );
417
418 return $this->response( $customer, __( 'Customer found successfully', 'booktics' ) );
419 }
420
421 /**
422 * Checks if a given request has access to update a customer.
423 *
424 * @param $request
425 *
426 * @return bool True if the request has access to update the item, WP_Error object otherwise.
427 */
428 public function update_customer_permission( $request ) {
429 return current_user_can( 'manage_options' );
430 }
431
432 /**
433 * Prepare data for customer update
434 *
435 * @param $request
436 *
437 * @return array|bool|WP_Error
438 */
439 public function prepare_customer_update( $request ) {
440 $input_data = json_decode( $request->get_body(), true );
441
442 $validation_rules = array(
443 'first_name' => array(
444 'required',
445 ),
446 'email' => array(
447 'required',
448 'unique:' . booktics_get_table_name( 'booktics_guests' ) . ',email,' . $request['id'],
449 ),
450 );
451 $update_validation_rules = array();
452 $validated_data = array();
453
454 if ( ! is_array( $input_data ) ) {
455 return new WP_Error(
456 'invalid_input_data',
457 'Invalid data'
458 );
459 }
460
461 foreach ( $input_data as $key => $value ) {
462 $validated_data[ $key ] = $value;
463 }
464
465 $validate = booktics_validate( $input_data, $update_validation_rules );
466
467 if ( is_wp_error( $validate ) ) {
468 return $validate;
469 }
470
471 return $validated_data;
472 }
473
474 /**
475 * @param $request
476 *
477 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
478 */
479 public function update_item( $request ) {
480 if ( ! isset( $request['id'] ) ) {
481 return $this->error( 'Invalid customer id', 400 );
482 }
483 $prepared_data = $this->prepare_customer_update( $request );
484
485 if ( is_wp_error( $prepared_data ) ) {
486 return $this->error( __( 'Customer validation error', 'booktics' ), 422, 'Validation', $prepared_data->errors );
487 }
488
489 $db = new Booktics_Database();
490 $customer = ( new Guest_Model( $db ) )->update( $request['id'], $prepared_data );
491 $image_url = $request->get_param( 'image' );
492 if ( $image_url ) {
493 ( new Guest_Model( $db ) )->update( $request['id'], array( 'image' => esc_url_raw( $image_url ) ) );
494 }
495
496 if ( ! $customer ) {
497 return $this->error( __( 'Customer update error', 'booktics' ), 500 );
498 }
499
500 do_action( 'booktics_customer_updated', $customer, $request );
501 $customer = ( new Guest_Model( $db ) )->find( array( 'id' => $request['id'] ) );
502
503 return $this->response( $customer, __( 'Successfully updated customer', 'booktics' ) );
504 }
505
506 /**
507 * Check if a given request has access to get customer profile.
508 *
509 * @param $request
510 *
511 * @return bool
512 */
513 public function customer_profile_permission( $request ) {
514 return true;
515 }
516
517 /**
518 * Get customer profile
519 *
520 * @param $request
521 *
522 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
523 */
524 public function get_profile( $request ) {
525 $user_id = get_current_user_id();
526 $db = new Booktics_Database();
527 $customer = ( new Guest_Model( $db ) )->find( array( 'wp_user_id' => $user_id ) );
528 $args = array(
529 'meta_query' => array(
530 array(
531 'key' => 'customer_id',
532 'value' => $customer->id,
533 'compare' => '=',
534 ),
535 ),
536 );
537
538 $appointments = ( new Appointment_Model() )->all( $args );
539 $customer->appointments = $appointments;
540
541 return $this->response( $customer, __( 'Successfully fetched customer profile', 'booktics' ) );
542 }
543
544 /**
545 * Connect a guest to a customer
546 *
547 * @param $request
548 *
549 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
550 */
551 public function connect_customer( $request ) {
552 $id = intval( $request['id'] );
553 $db = new Booktics_Database();
554 $guest = ( new Guest_Model( $db ) )->find( array( 'id' => $id ) );
555
556 if ( ! $guest ) {
557 return $this->error( __( 'Customer not found', 'booktics' ), 404 );
558 }
559
560 if ( $guest->wp_user_id ) {
561 return $this->error( __( 'Customer already connected', 'booktics' ), 400 );
562 }
563
564 $customer_model = ( new Customer_Model() );
565 $customer_id = $customer_model->save(
566 array(
567 'user_login' => $guest->user_login,
568 'user_email' => $guest->email,
569 'first_name' => $guest->first_name ?? '',
570 'last_name' => $guest->last_name ?? '',
571 'display_name' => $guest->display_name ?? '',
572 'phone' => $guest->phone ?? '',
573 )
574 );
575
576 if ( is_wp_error( $customer_id ) ) {
577 return $this->error( __( 'Customer create error', 'booktics' ), 500 );
578 }
579 ( new Customer_Event_Handler() )->on_customer_create( $customer_id );
580
581 ( new Guest_Model( $db ) )->update( $id, array( 'wp_user_id' => $customer_id ) );
582 $guest = ( new Guest_Model( $db ) )->find( array( 'id' => $id ) );
583 return $this->response( $guest, __( 'Successfully connected customer', 'booktics' ) );
584 }
585
586
587 /**
588 * Disconnect a guest from a customer
589 *
590 * @param $request
591 *
592 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
593 */
594 public function disconnect_customer( $request ) {
595 $id = intval( $request['id'] );
596 $db = new Booktics_Database();
597 $guest = ( new Guest_Model( $db ) )->find( array( 'id' => $id ) );
598
599 if ( ! $guest ) {
600 return $this->error( __( 'Customer not found', 'booktics' ), 404 );
601 }
602 if ( $guest->wp_user_id ) {
603 $customer = new Customer_Model( $guest->wp_user_id );
604 $customer->delete();
605 }
606
607 ( new Guest_Model( $db ) )->update( $id, array( 'wp_user_id' => null ) );
608 $guest = ( new Guest_Model( $db ) )->find( array( 'id' => $id ) );
609 return $this->response( $guest, __( 'Successfully disconnected customer', 'booktics' ) );
610 }
611 }
612