PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.2
Timetics – Appointment Booking Calendar & Scheduling v1.0.2
1.0.62 1.0.63 1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 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.19 1.0.2 1.0.20 1.0.21 1.0.22 All 64 releases
timetics / core / bookings / api-booking.php

api-booking.php in Timetics – Appointment Booking Calendar & Scheduling 1.0.2, at core/bookings/api-booking.php

746 lines 25.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Booking api
4 *
5 * @package Timetics
6 */
7 namespace Timetics\Core\Bookings;
8
9 use Timetics\Base\Api;
10 use Timetics\Core\Appointments\Appointment;
11 use Timetics\Core\Customers\Customer;
12 use Timetics\Core\Emails\Cancel_Event_Email;
13 use Timetics\Core\Emails\New_Event_Email;
14 use Timetics\Core\Emails\Update_Event_Email;
15 use Timetics\Core\Staffs\Staff;
16 use Timetics\Utils\Singleton;
17 use WP_HTTP_Response;
18 use WP_Query;
19
20 class Api_Booking extends Api {
21 use Singleton;
22
23 /**
24 * Store api namespace
25 *
26 * @var string
27 */
28 protected $namespace = 'timetics/v1';
29
30 /**
31 * Store rest base
32 *
33 * @var string
34 */
35 protected $rest_base = 'bookings';
36
37 /**
38 * Register rest routes
39 *
40 * @return void
41 */
42 public function register_routes() {
43 /**
44 * Register route
45 *
46 * @var void
47 */
48 register_rest_route(
49 $this->namespace, $this->rest_base, [
50 [
51 'methods' => \WP_REST_Server::READABLE,
52 'callback' => [$this, 'get_items'],
53 'permission_callback' => function () {
54 return current_user_can( 'manage_timetics' );
55 },
56 ],
57 [
58 'methods' => \WP_REST_Server::CREATABLE,
59 'callback' => [$this, 'create_item'],
60 'permission_callback' => function () {
61 return true;
62 },
63 ],
64 [
65 'methods' => \WP_REST_Server::DELETABLE,
66 'callback' => [$this, 'bulk_delete'],
67 'permission_callback' => function () {
68 return current_user_can( 'edit_booking' );
69 },
70 ],
71 ]
72 );
73
74 /**
75 * Register route
76 *
77 * @var void
78 */
79 register_rest_route(
80 $this->namespace, '/' . $this->rest_base . '/(?P<booking_id>[\d]+)', [
81 [
82 'methods' => \WP_REST_Server::READABLE,
83 'callback' => [$this, 'get_item'],
84 'permission_callback' => function () {
85 return current_user_can( 'manage_timetics' );
86 },
87 ],
88 [
89 'methods' => \WP_REST_Server::EDITABLE,
90 'callback' => [$this, 'update_item'],
91 'permission_callback' => function () {
92 return true;
93 },
94 ],
95 [
96 'methods' => \WP_REST_Server::DELETABLE,
97 'callback' => [$this, 'delete_item'],
98 'permission_callback' => function () {
99 return current_user_can( 'edit_booking' );
100 },
101 ],
102 ]
103 );
104
105 register_rest_route(
106 $this->namespace, '/' . $this->rest_base . '/(?P<booking_id>[\d]+)/payment', [
107 [
108 'methods' => \WP_REST_Server::EDITABLE,
109 'callback' => [$this, 'make_payment'],
110 'permission_callback' => function () {
111 return true;
112 },
113 ],
114 ]
115 );
116
117 register_rest_route(
118 $this->namespace, $this->rest_base . '/search', [
119 [
120 'methods' => \WP_REST_Server::READABLE,
121 'callback' => [$this, 'search_items'],
122 'permission_callback' => function () {
123 return current_user_can( 'edit_posts' );
124 },
125 ],
126 ]
127 );
128
129 register_rest_route(
130 $this->namespace, $this->rest_base . '/entries', [
131 [
132 'methods' => \WP_REST_Server::READABLE,
133 'callback' => [$this, 'get_entries'],
134 'permission_callback' => function () {
135 return true;
136 },
137 ],
138 ]
139 );
140
141 register_rest_route(
142 $this->namespace, $this->rest_base . '/payment_methods', [
143 [
144 'methods' => \WP_REST_Server::READABLE,
145 'callback' => [$this, 'get_payment_methods'],
146 'permission_callback' => function () {
147 return true;
148 },
149 ],
150 ]
151 );
152 }
153
154 /**
155 * Get all bookings
156 *
157 * @param WP_Rest_Request $request
158 *
159 * @return JSON
160 */
161 public function get_items( $request ) {
162 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
163 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
164 $meeting_id = ! empty( $request['meeting_id'] ) ? intval( $request['meeting_id'] ) : 0;
165 $staff_id = ! current_user_can( 'edit_booking' ) ? get_current_user_id() : 0;
166
167 $args = [
168 'posts_per_page' => $per_page,
169 'paged' => $paged,
170 'meeting' => $meeting_id,
171 'staff' => $staff_id,
172 ];
173 $appoint = Booking::all( $args );
174
175 $items = [];
176
177 foreach ( $appoint['items'] as $item ) {
178 $items[] = $this->prepare_item( $item->ID );
179 }
180
181 $data = [
182 'success' => 1,
183 'status_code' => 200,
184 'data' => [
185 'total' => $appoint['total'],
186 'items' => $items,
187 ],
188 ];
189
190 return rest_ensure_response( $data );
191 }
192
193 /**
194 * Get single booking
195 *
196 * @param WP_Rest_Request $request
197 *
198 * @return JSON
199 */
200 public function get_item( $request ) {
201 $booking_id = (int) $request['booking_id'];
202 $booking = new Booking( $booking_id );
203
204 if ( ! $booking->is_booking() ) {
205 return [
206 'success' => 0,
207 'status_code' => 404,
208 'message' => __( 'Invalid booking id.', 'timetics' ),
209 'data' => [],
210 ];
211 }
212
213 $data = [
214 'success' => 1,
215 'status_code' => 200,
216 'data' => $this->prepare_item( $booking ),
217 ];
218
219 return rest_ensure_response( $data );
220 }
221
222 /**
223 * Create booking
224 *
225 * @param WP_Rest_Request $request
226 *
227 * @return JSON
228 */
229 public function create_item( $request ) {
230 return $this->save_bookings( $request );
231 }
232
233 /**
234 * Update booking
235 *
236 * @param WP_Rest_Request $request
237 *
238 * @return JSON
239 */
240 public function update_item( $request ) {
241 $booking_id = (int) $request['booking_id'];
242 $booking = new Booking( $booking_id );
243
244 if ( ! $booking->is_booking() ) {
245 return [
246 'status_code' => 404,
247 'message' => __( 'Invalid booking id.', 'timetics' ),
248 'data' => [],
249 ];
250 }
251
252 return $this->save_bookings( $request, $booking_id );
253 }
254
255 /**
256 * Delete booking
257 *
258 * @param WP_Rest_Request $request
259 *
260 * @return JSON
261 */
262 public function delete_item( $request ) {
263 $booking_id = (int) $request['booking_id'];
264 $booking = new Booking( $booking_id );
265
266 if ( ! $booking->is_booking() ) {
267 return [
268 'status_code' => 404,
269 'message' => __( 'Invalid booking id.', 'timetics' ),
270 'data' => [],
271 ];
272 }
273
274 $booking->delete_event();
275 $booking->delete();
276 $cancel_event_email = new Cancel_Event_Email( $booking );
277 $cancel_event_email->send();
278
279 $data = [
280 'success' => 1,
281 'status_code' => 200,
282 'message' => __( 'Successfully deleted booking', 'timetics' ),
283 'data' => [],
284 ];
285
286 return rest_ensure_response( $data );
287 }
288
289 /**
290 * Delete multiples
291 *
292 * @param WP_Rest_Request $request
293 *
294 * @return JSON
295 */
296 public function bulk_delete( $request ) {
297 $bookings = json_decode( $request->get_body(), true );
298
299 foreach ( $bookings as $booking ) {
300 $booking = new Booking( $booking );
301
302 if ( ! $booking->is_booking() ) {
303 return [
304 'success' => 0,
305 'status_code' => 404,
306 'message' => __( 'Invalid booking id.', 'timetics' ),
307 'data' => [],
308 ];
309 }
310
311 $booking->delete();
312 }
313
314 return [
315 'success' => 1,
316 'status_code' => 200,
317 'message' => __( 'Successfully deleted booking', 'timetics' ),
318 ];
319 }
320
321 /**
322 * Get payment methods
323 *
324 * @return array
325 */
326 public function get_payment_methods() {
327
328 $payment_methods = timetics_get_payment_methods();
329
330 return [
331 'success' => 1,
332 'status_code' => 200,
333 'data' => $payment_methods,
334 ];
335 }
336
337 /**
338 * Search bookings
339 *
340 * @param WP_Rest_Request $request
341 *
342 * @return JSON
343 */
344 public function search_items( $request ) {
345 // Prepare search args.
346 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
347 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
348 $search = ! empty( $request['search'] ) ? sanitize_text_field( $request['search'] ) : '';
349
350 // Get search.
351 $booking = new WP_Query(
352 array(
353 'post_type' => 'timetics-booking',
354 'posts_per_page' => $per_page,
355 'paged' => $paged,
356 'post_status' => 'any',
357
358 // @codingStandardsIgnoreStart
359 'meta_query' => array(
360 'relation' => 'OR',
361 array(
362 'key' => '_tt_booking_customer_fname',
363 'value' => $search,
364 'compare' => 'LIKE',
365 ),
366 array(
367 'key' => '_tt_booking_customer_lname',
368 'value' => $search,
369 'compare' => 'LIKE',
370 ),
371 array(
372 'key' => '_tt_booking_customer_email',
373 'value' => $search,
374 'compare' => 'LIKE',
375 ),
376 array(
377 'key' => '_tt_booking_customer_phone',
378 'value' => $search,
379 'compare' => 'LIKE',
380 ),
381 array(
382 'key' => '_tt_booking_staff_fname',
383 'value' => $search,
384 'compare' => 'LIKE',
385 ),
386 array(
387 'key' => '_tt_booking_staff_lname',
388 'value' => $search,
389 'compare' => 'LIKE',
390 ),
391 array(
392 'key' => '_tt_booking_staff_email',
393 'value' => $search,
394 'compare' => 'LIKE',
395 ),
396 array(
397 'key' => '_tt_booking_meeting_name',
398 'value' => $search,
399 'compare' => 'LIKE',
400 ),
401 array(
402 'key' => '_tt_booking_meeting_description',
403 'value' => $search,
404 'compare' => 'LIKE',
405 ),
406 array(
407 'key' => '_tt_booking_meeting_type',
408 'value' => $search,
409 'compare' => 'LIKE',
410 ),
411 ),
412 // @codingStandardsIgnoreEnd
413 )
414 );
415
416 // Prepare items for response.
417 $items = [];
418
419 foreach ( $booking->posts as $item ) {
420 $items[] = $this->prepare_item( $item->ID );
421 }
422
423 $data = [
424 'success' => 1,
425 'status' => 200,
426 'data' => [
427 'total' => $booking->found_posts,
428 'items' => $items,
429 ],
430 ];
431
432 return rest_ensure_response( $data );
433 }
434
435 /**
436 * Get all booking entries
437 *
438 * @param WP_Rest_Request $request
439 *
440 * @return JSON
441 */
442 public function get_entries( $request ) {
443 $staff_id = ! empty( $request['staff_id'] ) ? intval( $request['staff_id'] ) : 0;
444 $meeting_id = ! empty( $request['meeting_id'] ) ? intval( $request['meeting_id'] ) : 0;
445 $start_date = ! empty( $request['start_date'] ) ? sanitize_text_field( $request['start_date'] ) : 0;
446 $end_date = ! empty( $request['end_date'] ) ? sanitize_text_field( $request['end_date'] ) : 0;
447
448 $meeting = new Appointment( $meeting_id );
449
450 $days = $meeting->prepare_schedule( $start_date, $end_date, $staff_id );
451
452 $data = [
453 'today' => gmdate( 'Y-m-d' ),
454 'availability_timezone' => $meeting->get_timezone(),
455 'days' => $days,
456 ];
457
458 return [
459 'success' => true,
460 'status_code' => 200,
461 'message' => __( 'Get all entries', 'timetics' ),
462 'data' => $data,
463 ];
464 }
465
466 /**
467 * Make payment transaction for the current booking
468 *
469 * @param WP_Rest_Request $request
470 *
471 * @return JSON
472 */
473 public function make_payment( $request ) {
474 $booking_id = intval( $request['booking_id'] );
475 $booking = new Booking( $booking_id );
476 $data = json_decode( $request->get_body(), true );
477 $status = ! empty( $data['status'] ) ? sanitize_text_field( $data['status'] ) : '';
478 $post_status = 'succeeded' === $status ? 'completed' : 'pending';
479 $payment_method = ! empty( $data['payment_method'] ) ? sanitize_text_field( $data['payment_method'] ) : '';
480 $payment_details = ! empty( $data['payment_details'] ) ? $data['payment_details'] : '';
481
482 if ( ! $booking->is_booking() ) {
483 return [
484 'status_code' => 404,
485 'message' => __( 'Invalid booking id.', 'timetics' ),
486 'data' => [],
487 ];
488 }
489
490 $update = $booking->update(
491 [
492 'post_status' => $post_status,
493 'payment_status' => $status,
494 'payment_details' => $payment_details,
495 'payment_method' => $payment_method,
496 ]
497 );
498
499 if ( is_wp_error( $update ) ) {
500 $data = [
501 'success' => 0,
502 'status_code' => 409,
503 /* translators: Action */
504 'message' => $update->get_error_message(),
505 ];
506
507 return new WP_HTTP_Response( $data, 409 );
508 }
509
510 $data = [
511 'success' => 1,
512 'status_code' => 200,
513 /* translators: Action */
514 'message' => sprintf( __( 'Payment %s', 'timetics' ), $post_status ),
515 ];
516
517 return new WP_HTTP_Response( $data, 200 );
518 }
519
520 /**
521 * Save booking
522 *
523 * @param WP_Rest_Request $request
524 * @param integer $id Booking id
525 *
526 * @return JSON
527 */
528 public function save_bookings( $request, $id = 0 ) {
529 $data = json_decode( $request->get_body(), true );
530
531 $first_name = ! empty( $data['first_name'] ) ? sanitize_text_field( $data['first_name'] ) : '';
532 $last_name = ! empty( $data['last_name'] ) ? sanitize_text_field( $data['last_name'] ) : '';
533 $email = ! empty( $data['email'] ) ? sanitize_text_field( $data['email'] ) : '';
534 $phone = ! empty( $data['phone'] ) ? sanitize_text_field( $data['phone'] ) : '';
535 $city = ! empty( $data['city'] ) ? sanitize_text_field( $data['city'] ) : '';
536 $state = ! empty( $data['state'] ) ? sanitize_text_field( $data['state'] ) : '';
537 $post_code = ! empty( $data['post_code'] ) ? sanitize_text_field( $data['post_code'] ) : '';
538 $country = ! empty( $data['country'] ) ? sanitize_text_field( $data['country'] ) : '';
539 $payment_method = ! empty( $data['payment_method'] ) ? sanitize_text_field( $data['payment_method'] ) : '';
540 $address_1 = ! empty( $data['address_1'] ) ? sanitize_text_field( $data['address_1'] ) : '';
541 $address_2 = ! empty( $data['address_2'] ) ? sanitize_text_field( $data['address_2'] ) : '';
542 $appointment = ! empty( $data['appointment'] ) ? intval( $data['appointment'] ) : 0;
543 $staff = ! empty( $data['staff'] ) ? intval( $data['staff'] ) : 0;
544 $start_date = ! empty( $data['start_date'] ) ? sanitize_text_field( $data['start_date'] ) : '';
545 $date = ! empty( $data['date'] ) ? sanitize_text_field( $data['date'] ) : '';
546 $end_date = ! empty( $data['end_date'] ) ? sanitize_text_field( $data['end_date'] ) : $start_date;
547 $start_time = ! empty( $data['start_time'] ) ? sanitize_text_field( $data['start_time'] ) : '';
548 $end_time = ! empty( $data['end_time'] ) ? sanitize_text_field( $data['end_time'] ) : '';
549 $order_total = ! empty( $data['order_total'] ) ? intval( $data['order_total'] ) : 0;
550 $status = ! empty( $data['status'] ) ? sanitize_text_field( $data['status'] ) : timetics_get_option( 'default_booking_status' );
551 $location = ! empty( $data['location'] ) ? sanitize_text_field( $data['location'] ) : '';
552 $location_type = ! empty( $data['location_type'] ) ? sanitize_text_field( $data['location_type'] ) : '';
553 $description = ! empty( $data['description'] ) ? sanitize_text_field( $data['description'] ) : '';
554 $action = $id ? 'updated' : 'created';
555
556 $validate = $this->validate(
557 $data, [
558 'first_name',
559 'email',
560 'payment_method',
561 'appointment',
562 'start_date',
563 'start_time',
564 'end_time',
565 ]
566 );
567
568 if ( is_wp_error( $validate ) ) {
569 $data = [
570 'status_code' => 403,
571 'success' => 0,
572 'message' => $validate->get_error_messages(),
573 ];
574 return new WP_HTTP_Response( $data, 403 );
575 }
576
577 $customer = new Customer();
578 $meeting = new Appointment( $appointment );
579 $staff = new Staff( $staff );
580 $customer->make(
581 [
582 'first_name' => $first_name,
583 'last_name' => $last_name,
584 'email' => $email,
585 'phone' => $phone,
586 ]
587 );
588
589 $booking = new Booking( $id );
590 $booking_entry = new Booking_Entry();
591
592 $booking->set_props(
593 [
594 'customer' => $customer->get_id(),
595 'appointment' => $meeting->get_id(),
596 'staff' => $staff->get_id(),
597 'customer_fname' => $customer->get_first_name(),
598 'customer_lname' => $customer->get_last_name(),
599 'customer_email' => $customer->get_email(),
600 'customer_phone' => $customer->get_phone(),
601 'staff_fname' => $staff->get_first_name(),
602 'staff_lname' => $staff->get_last_name(),
603 'staff_email' => $staff->get_email(),
604 'meeting_name' => $meeting->get_name(),
605 'meeting_description' => $meeting->get_description(),
606 'meeting_type' => $meeting->get_type(),
607 'description' => $description,
608 'start_date' => $start_date,
609 'date' => $date,
610 'end_date' => $end_date,
611 'start_time' => $start_time,
612 'end_time' => $end_time,
613 'order_total' => $order_total,
614 'post_status' => $status,
615 'location' => $location,
616 'location_type' => $location_type,
617 ]
618 );
619
620 $booking->save();
621
622 // Create or update calendar event.
623 if ( $id ) {
624 if ( 'cancel' === $status ) {
625 $booking->delete_event();
626 $cancel_event_email = new Cancel_Event_Email( $booking );
627 $cancel_event_email->send();
628 } else {
629 $booking->update_event();
630 $update_event_email = new Update_Event_Email( $booking );
631 $update_event_email->send();
632 }
633 } else {
634 $booking->create_event();
635 $new_event_email = new New_Event_Email( $booking );
636 $new_event_email->send();
637 }
638
639 // Create booking schedule.
640 $entries = $booking_entry->find(
641 [
642 'staff_id' => $staff->get_id(),
643 'meeting_id' => $meeting->get_id(),
644 'date' => $start_date,
645 'start' => $start_time,
646 ]
647 );
648
649 if ( $entries ) {
650 $entry = $booking_entry->first();
651 $booked = intval( $entry->get_booked() ) + 1;
652
653 $booked_data = apply_filters( 'timetics_booking_update_schedule', $entry, ['booked' => $booked], $data );
654
655 $entry->update( $booked_data );
656 } else {
657 $book_entry_data = [
658 'meeting_id' => $meeting->get_id(),
659 'staff_id' => $staff->get_id(),
660 'customer_id' => $customer->get_id(),
661 'booking_id' => $booking->get_id(),
662 'booked' => 1,
663 'date' => $start_date,
664 'start' => $start_time,
665 'end' => $end_time,
666 ];
667
668 $book_entry_data = apply_filters( 'timetics_booking_schedule', $book_entry_data, $data );
669 $booking_entry->create( $book_entry_data );
670 }
671
672 // Fire when booking is completed.
673 do_action( 'timetics_after_booking_create', $booking->get_id(), $customer->get_id(), $meeting->get_id(), $data );
674
675 $data = [
676 'success' => 1,
677 'status_code' => 200,
678 /* translators: Action */
679 'message' => sprintf( __( 'Successfully %s booking', 'timetics' ), $action ),
680 'data' => $this->prepare_item( $booking ),
681 ];
682
683 return new WP_HTTP_Response( $data, 200 );
684 }
685
686 /**
687 * Prepare item for response
688 *
689 * @param integer $booking_id
690 *
691 * @return array
692 */
693 public function prepare_item( $booking_id ) {
694 $booking = new Booking( $booking_id );
695 $appointment = new Appointment( $booking->get_appointment() );
696 $staff = new Staff( $booking->get_staff_id() );
697 $customer = new Customer( $booking->get_customer_id() );
698
699 $start_date = gmdate( 'd F, Y', strtotime( $booking->get_start_date() ) );
700 $end_date = gmdate( 'd F, Y', strtotime( $booking->get_end_date() ) );
701 $date = gmdate( 'd F, Y', strtotime( $booking->get_date() ) );
702
703 $response = [
704 'id' => $booking->get_id(),
705 'random_id' => $booking->get_random_id(),
706 'status' => $booking->get_status(),
707 'order_total' => $booking->get_total(),
708 'start_date' => $start_date,
709 'end_date' => $end_date,
710 'date' => $date,
711 'start_time' => $booking->get_start_time(),
712 'end_time' => $booking->get_end_time(),
713 'location' => $booking->get_location(),
714 'location_type' => $booking->get_location_type(),
715 'description' => $booking->get_description(),
716 'customer' => [
717 'id' => $customer->get_id(),
718 'full_name' => $customer->get_display_name(),
719 'first_name' => $customer->get_first_name(),
720 'last_name' => $customer->get_last_name(),
721 'email' => $customer->get_email(),
722 ],
723 'appointment' => [
724 'id' => $appointment->get_id(),
725 'name' => $appointment->get_name(),
726 'duration' => $appointment->get_duration(),
727 'type' => $appointment->get_type(),
728 'price' => $appointment->get_price(),
729 'locations' => $appointment->get_locations(),
730 'timezone' => $appointment->get_timezone(),
731 ],
732 'staff' => [
733 'id' => $staff->get_id(),
734 'full_name' => $staff->get_display_name(),
735 'first_name' => $staff->get_first_name(),
736 'last_name' => $staff->get_last_name(),
737 'email_name' => $staff->get_email(),
738 'phone' => $staff->get_phone(),
739 'image' => $staff->get_image(),
740 ],
741 ];
742
743 return apply_filters( 'timetics_booking_json_data', $response, $booking );
744 }
745 }
746