PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.28
Booktics – Appointment Booking Calendar for Service Businesses v1.0.28
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 / order / order-validator.php

order-validator.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.28, at core/order/order-validator.php

161 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Booktics\Order;
4
5 use Booktics\Models\Service_Model;
6 use Booktics\Models\Team_Member_Model;
7 use WP_Error;
8
9 class Order_Validator {
10 /**
11 * Validate order creation request
12 *
13 * @param array $data Order data
14 *
15 * @return true|WP_Error Returns true if valid, WP_Error otherwise
16 */
17 public function validate( array $data ) {
18 $error = new WP_Error();
19
20 // Validate basic required fields
21 $required_fields = array(
22 'items',
23 );
24
25 foreach ( $required_fields as $field ) {
26 if ( empty( $data[ $field ] ) ) {
27 /* translators: %s: Field name */
28 $error->add( 'missing_field', sprintf( __( '%s is required', 'booktics' ), $field ) );
29 }
30 }
31
32 if ( empty( $data['customer_id'] ) && empty( $data['customer']['email'] ) ) {
33 $error->add( 'missing_field', __( 'Customer email is required', 'booktics' ) );
34 }
35
36 if ( empty( $data['items'] ) || ! is_array( $data['items'] ) ) {
37 $error->add( 'invalid_items', __( 'Order must contain at least one item', 'booktics' ) );
38
39 return $error;
40 }
41
42 foreach ( $data['items'] as $item ) {
43 $item_validation = $this->validate_order_item( $item );
44 if ( is_wp_error( $item_validation ) ) {
45 return $item_validation;
46 }
47 }
48
49 return $error->has_errors() ? $error : true;
50 }
51
52 /**
53 * Validate individual order item
54 *
55 * @param array $item Order item data
56 *
57 * @return true|WP_Error Returns true if valid, WP_Error otherwise
58 */
59 private function validate_order_item( array $item ) {
60 $error = new WP_Error();
61
62 $service = ( new Service_Model() )->find( $item['service_id'] );
63 if ( ! $service ) {
64 $error->add( 'invalid_service', __( 'Invalid service selected', 'booktics' ) );
65 }
66
67 // An item may legitimately arrive without a team member when the
68 // service assigns one server-side. The item validation rules decide
69 // whether that is allowed; this check only verifies a member that was
70 // actually supplied.
71 if ( ! empty( $item['team_member_id'] ) ) {
72 $team_member = ( new Team_Member_Model() )->find( $item['team_member_id'] );
73 if ( ! $team_member ) {
74 $error->add( 'invalid_team_member', __( 'Invalid team member selected', 'booktics' ) );
75 }
76 }
77 $error = apply_filters( 'booktics_extra_service_validate', $error, $item );
78
79 return $error->has_errors() ? $error : true;
80 }
81
82 /**
83 * Validate time slot availability
84 *
85 * @param array $item Order item data
86 *
87 * @return true|WP_Error Returns true if valid, WP_Error otherwise
88 */
89 private function validate_time_slot( array $item ) {
90 $error = new WP_Error();
91
92 $args = array(
93 'post_type' => 'booktics-appointment',
94 'post_status' => 'any',
95 'posts_per_page' => 1,
96 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering appointments by meta fields
97 'meta_query' => array(
98 'relation' => 'AND',
99 array(
100 'key' => 'date',
101 'value' => $item['date'],
102 'compare' => '=',
103 ),
104 array(
105 'key' => 'team_member_id',
106 'value' => $item['team_member_id'],
107 'compare' => '=',
108 ),
109 array(
110 'relation' => 'OR',
111 // Appointment starts during requested time slot
112 array(
113 'relation' => 'AND',
114 array(
115 'key' => 'start_time',
116 'value' => $item['start_time'],
117 'compare' => '<=',
118 ),
119 array(
120 'key' => 'end_time',
121 'value' => $item['start_time'],
122 'compare' => '>',
123 ),
124 ),
125 // Appointment ends during requested time slot
126 array(
127 'relation' => 'AND',
128 array(
129 'key' => 'start_time',
130 'value' => $item['end_time'],
131 'compare' => '<',
132 ),
133 array(
134 'key' => 'end_time',
135 'value' => $item['end_time'],
136 'compare' => '>=',
137 ),
138 ),
139 ),
140 ),
141 );
142
143 $query = new \WP_Query( $args );
144
145 if ( $query->have_posts() ) {
146 $error->add(
147 'time_slot_unavailable',
148 sprintf(
149 /* translators: 1: Start time, 2: End time, 3: Date */
150 __( 'Time slot %1$s - %2$s on %3$s is not available', 'booktics' ),
151 $item['start_time'],
152 $item['end_time'],
153 $item['date']
154 )
155 );
156 }
157
158 return $error->has_errors() ? $error : true;
159 }
160 }
161