PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.4.2
LatePoint – Calendar Booking Plugin for Appointments and Events v5.4.2
5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / models / customer_model.php
latepoint / lib / models Last commit date
activity_model.php 3 months ago agent_meta_model.php 3 months ago agent_model.php 3 months ago booking_meta_model.php 3 months ago booking_model.php 3 months ago bundle_meta_model.php 3 months ago bundle_model.php 3 months ago cart_item_model.php 3 months ago cart_meta_model.php 3 months ago cart_model.php 3 months ago connector_model.php 3 months ago customer_meta_model.php 3 months ago customer_model.php 3 months ago invoice_model.php 3 months ago join_bundles_services_model.php 3 months ago location_category_model.php 3 months ago location_model.php 3 months ago meta_model.php 3 months ago model.php 3 months ago off_period_model.php 3 months ago order_intent_meta_model.php 3 months ago order_intent_model.php 3 months ago order_item_model.php 3 months ago order_meta_model.php 3 months ago order_model.php 3 months ago otp_model.php 3 months ago payment_request_model.php 3 months ago process_job_model.php 3 months ago process_model.php 3 months ago recurrence_model.php 3 months ago service_category_model.php 3 months ago service_meta_model.php 3 months ago service_model.php 3 months ago session_model.php 3 months ago settings_model.php 3 months ago step_settings_model.php 3 months ago transaction_intent_model.php 3 months ago transaction_model.php 3 months ago transaction_refund_model.php 3 months ago work_period_model.php 3 months ago
customer_model.php
518 lines
1 <?php
2
3 /**
4 * @property string $full_name
5 */
6 class OsCustomerModel extends OsModel {
7 var $id,
8 $uuid,
9 $first_name,
10 $last_name,
11 $password,
12 $email,
13 $phone,
14 $account_nonse,
15 $status,
16 $activation_key,
17 $google_user_id,
18 $facebook_user_id,
19 $avatar_image_id,
20 $is_guest,
21 $notes,
22 $admin_notes,
23 $wordpress_user_id,
24 $meta_class = 'OsCustomerMetaModel',
25 $updated_at,
26 $created_at;
27
28 function __construct( $id = false ) {
29 $this->table_name = LATEPOINT_TABLE_CUSTOMERS;
30 $this->nice_names = array(
31 'first_name' => __( 'Customer First Name', 'latepoint' ),
32 'email' => __( 'Email Address', 'latepoint' ),
33 'phone' => __( 'Phone Number', 'latepoint' ),
34 'last_name' => __( 'Customer Last Name', 'latepoint' ),
35 );
36
37 parent::__construct( $id );
38 }
39
40 public function generate_data_vars(): array {
41 return [
42 'id' => $this->id,
43 'first_name' => $this->first_name,
44 'last_name' => $this->last_name,
45 'full_name' => $this->full_name,
46 'email' => $this->email,
47 'phone' => $this->phone,
48 ];
49 }
50
51 public function get_meta_by_key( $meta_key, $default = false ) {
52 if ( $this->is_new_record() ) {
53 return $default;
54 }
55
56 $meta = new OsCustomerMetaModel();
57
58 return $meta->get_by_key( $meta_key, $this->id, $default );
59 }
60
61 /**
62 * @param int $limit
63 * @param bool $filter_allowed_records
64 *
65 * @return OsOrderModel[]
66 */
67 public function get_orders( int $limit = 0, bool $filter_allowed_records = false ): array {
68 $orders = new OsOrderModel();
69 if ( $limit ) {
70 $orders = $orders->set_limit( $limit );
71 }
72 if ( $filter_allowed_records ) {
73 $orders->filter_allowed_records();
74 }
75
76 return $orders->where( [ 'customer_id' => $this->id ] )->order_by( 'created_at desc' )->get_results_as_models();
77 }
78
79 public function get_initials() {
80 return mb_substr( $this->first_name, 0, 1 ) . mb_substr( $this->last_name, 0, 1 );
81 }
82
83 public function delete_meta_by_key( $meta_key ) {
84 if ( $this->is_new_record() ) {
85 return true;
86 }
87
88 $meta = new OsCustomerMetaModel();
89
90 return $meta->delete_by_key( $meta_key, $this->id );
91 }
92
93 public function save_meta_by_key( $meta_key, $meta_value ) {
94 if ( $this->is_new_record() ) {
95 return false;
96 }
97
98 $meta = new OsCustomerMetaModel();
99
100 return $meta->save_by_key( $meta_key, $meta_value, $this->id );
101 }
102
103 public function set_timezone_name( $timezone_name = false ) {
104 if ( ! $timezone_name ) {
105 $timezone_name = OsTimeHelper::get_timezone_name_from_session();
106 }
107 $this->save_meta_by_key( 'timezone_name', $timezone_name );
108 }
109
110 public function get_selected_timezone_name() {
111 if ( OsSettingsHelper::is_on( 'steps_show_timezone_selector' ) ) {
112 return $this->get_meta_by_key( 'timezone_name', OsTimeHelper::get_timezone_name_from_session() );
113 } else {
114 return OsTimeHelper::get_wp_timezone_name();
115 }
116 }
117
118 public function get_selected_timezone_obj() {
119 $timezone_obj = new DateTimeZone( $this->get_selected_timezone_name() );
120
121 return $timezone_obj;
122 }
123
124
125 public function delete( $id = false ) {
126 if ( ! $id && isset( $this->id ) ) {
127 $id = $this->id;
128 }
129 $bookings = new OsBookingModel();
130 $bookings_to_delete = $bookings->where( [ 'customer_id' => $id ] )->get_results_as_models();
131 if ( $bookings_to_delete ) {
132 foreach ( $bookings_to_delete as $booking ) {
133 $booking->delete();
134 }
135 }
136 $orders = new OsOrderModel();
137 $orders_to_delete = $orders->where( [ 'customer_id' => $id ] )->get_results_as_models();
138 if ( $orders_to_delete ) {
139 foreach ( $orders_to_delete as $order ) {
140 $order->delete();
141 }
142 }
143 $transactions = new OsTransactionModel();
144 $transactions_to_delete = $transactions->where( [ 'customer_id' => $id ] )->get_results_as_models();
145 if ( $transactions_to_delete ) {
146 foreach ( $transactions_to_delete as $transaction ) {
147 $transaction->delete();
148 }
149 }
150 $customer_metas = new OsCustomerMetaModel();
151 $customer_metas_to_delete = $customer_metas->where( [ 'object_id' => $id ] )->get_results_as_models();
152 if ( $customer_metas_to_delete ) {
153 foreach ( $customer_metas_to_delete as $customer_meta ) {
154 $customer_meta->delete();
155 }
156 }
157
158 return parent::delete( $id );
159 }
160
161
162 public function get_bookings( $limit = false, $filter_allowed_records = false ) {
163 $bookings = new OsBookingModel();
164 if ( $limit ) {
165 $bookings = $bookings->set_limit( $limit );
166 }
167 if ( $filter_allowed_records ) {
168 $bookings->filter_allowed_records();
169 }
170
171 return $bookings->where( [ 'customer_id' => $this->id ] )->get_results_as_models();
172 }
173
174 public function get_past_bookings( $limit = false, $filter_allowed_records = false ) {
175 $bookings = new OsBookingModel();
176 if ( $limit ) {
177 $bookings = $bookings->set_limit( $limit );
178 }
179 if ( $filter_allowed_records ) {
180 $bookings->filter_allowed_records();
181 }
182
183 return $bookings->should_not_be_cancelled()->where(
184 array(
185 'customer_id' => $this->id,
186 'OR' => array(
187 'start_date <' => OsTimeHelper::today_date( 'Y-m-d' ),
188 'AND' => array(
189 'start_date' => OsTimeHelper::today_date( 'Y-m-d' ),
190 'start_time <' => OsTimeHelper::get_current_minutes(),
191 ),
192 ),
193 )
194 )->get_results_as_models();
195 }
196
197 /**
198 * @return OsBundleModel[]
199 */
200 public function get_not_scheduled_bundles(): array {
201 $non_scheduled_bundles = [];
202 $orders = new OsOrderModel();
203 $orders = $orders->where( [ 'customer_id' => $this->id ] )->get_results_as_models();
204 if ( $orders ) {
205 foreach ( $orders as $order ) {
206 $bundles = $order->get_bundles_from_order_items();
207 if ( $bundles ) {
208 foreach ( $bundles as $order_item_id => $bundle ) {
209 $bundle_services = $bundle->get_services();
210 foreach ( $bundle_services as $bundle_service ) {
211 $bookings = new OsBookingModel();
212 $total_scheduled_bookings = $bookings->where(
213 [
214 'order_item_id' => $order_item_id,
215 'service_id' => $bundle_service->id,
216 ]
217 )->should_not_be_cancelled()->count();
218 if ( $total_scheduled_bookings < $bundle_service->join_attributes['quantity'] ) {
219 $non_scheduled_bundles[ $order_item_id ] = $bundle;
220 break;
221 }
222 }
223 }
224 }
225 }
226 }
227
228 return $non_scheduled_bundles;
229 }
230
231 public function get_cancelled_bookings( $limit = false, $filter_allowed_records = false ) {
232 $bookings = new OsBookingModel();
233 if ( $limit ) {
234 $bookings = $bookings->set_limit( $limit );
235 }
236 if ( $filter_allowed_records ) {
237 $bookings->filter_allowed_records();
238 }
239
240 return $bookings->should_be_cancelled()->order_by( 'start_date, start_time asc' )->where( [ 'customer_id' => $this->id ] )->get_results_as_models();
241 }
242
243 public function get_future_bookings( $limit = false, $filter_allowed_records = false ) {
244 $bookings = new OsBookingModel();
245 if ( $limit ) {
246 $bookings = $bookings->set_limit( $limit );
247 }
248 if ( $filter_allowed_records ) {
249 $bookings->filter_allowed_records();
250 }
251
252 return $bookings->should_not_be_cancelled()->order_by( 'start_date, start_time asc' )->where( [ 'customer_id' => $this->id ] )->should_be_in_future()->get_results_as_models();
253 }
254
255
256 public function get_future_bookings_count( $filter_allowed_records = false ) {
257 $bookings = new OsBookingModel();
258 if ( $filter_allowed_records ) {
259 $bookings->filter_allowed_records();
260 }
261
262 return $bookings->should_not_be_cancelled()->where(
263 array(
264 'customer_id' => $this->id,
265 'OR' => array(
266 'start_date >' => OsTimeHelper::today_date( 'Y-m-d' ),
267 'AND' => array(
268 'start_date' => OsTimeHelper::today_date( 'Y-m-d' ),
269 'start_time >' => OsTimeHelper::get_current_minutes(),
270 ),
271 ),
272 )
273 )->count();
274 }
275
276 public function get_total_bookings_count( $filter_allowed_records = false ) {
277 $bookings = new OsBookingModel();
278 if ( $filter_allowed_records ) {
279 $bookings->filter_allowed_records();
280 }
281
282 return $bookings->select( 'count(id) as total_bookings' )->where( array( 'customer_id' => $this->id ) )->count();
283 }
284
285
286 public function filter_allowed_records(): OsModel {
287 if ( ! OsRolesHelper::are_all_records_allowed() ) {
288 $this->select( LATEPOINT_TABLE_CUSTOMERS . '.*' )->join( LATEPOINT_TABLE_BOOKINGS, [ 'customer_id' => LATEPOINT_TABLE_CUSTOMERS . '.id' ] )->group_by( LATEPOINT_TABLE_CUSTOMERS . '.id' );
289 if ( ! OsRolesHelper::are_all_records_allowed( 'agent' ) ) {
290 $this->filter_where_conditions( [ LATEPOINT_TABLE_BOOKINGS . '.agent_id' => OsRolesHelper::get_allowed_records( 'agent' ) ] );
291 }
292 if ( ! OsRolesHelper::are_all_records_allowed( 'location' ) ) {
293 $this->filter_where_conditions( [ LATEPOINT_TABLE_BOOKINGS . '.location_id' => OsRolesHelper::get_allowed_records( 'location' ) ] );
294 }
295 if ( ! OsRolesHelper::are_all_records_allowed( 'service' ) ) {
296 $this->filter_where_conditions( [ LATEPOINT_TABLE_BOOKINGS . '.service_id' => OsRolesHelper::get_allowed_records( 'service' ) ] );
297 }
298 }
299
300 return $this;
301 }
302
303 public function primary_contact_type() {
304 $contact_type = OsAuthHelper::get_selected_customer_authentication_field_type();
305 switch ( $contact_type ) {
306 case 'phone':
307 return $this->phone;
308 break;
309 default:
310 return $this->email;
311 break;
312 }
313 }
314
315 public function update_password( $password ) {
316 // update connected wp user password
317 if ( OsAuthHelper::can_wp_users_login_as_customers() && $this->wordpress_user_id ) {
318 $is_logged_in = OsWpUserHelper::get_current_user_id() == $this->wordpress_user_id;
319 $logged_in_wp_user = $is_logged_in ? OsWpUserHelper::get_current_user() : false;
320
321 // user is getting logged out after changing a password - we need to check if the user that we are changing password for is currently logged in, if it is - make sure to log them back in after password change
322 wp_set_password( $password, $this->wordpress_user_id );
323 if ( $is_logged_in && $logged_in_wp_user ) {
324 OsAuthHelper::login_wp_user( $logged_in_wp_user );
325 }
326 }
327
328 return $this->update_attributes(
329 [
330 'password' => wp_hash_password( $password ),
331 'is_guest' => false,
332 ]
333 );
334 }
335
336 protected function get_full_name() {
337 return trim( join( ' ', array( $this->first_name, $this->last_name ) ) );
338 }
339
340 protected function get_default_status() {
341 return 'pending_verification';
342 }
343
344 protected function before_create() {
345 if ( ! isset( $this->is_guest ) ) {
346 $this->is_guest = true;
347 }
348 if ( empty( $this->status ) ) {
349 $this->status = $this->get_default_status();
350 }
351 if ( empty( $this->password ) ) {
352 $this->password = wp_hash_password( bin2hex( openssl_random_pseudo_bytes( 8 ) ) );
353 }
354 if ( empty( $this->activation_key ) ) {
355 $this->activation_key = sha1( wp_rand( 10000, 99999 ) . time() . $this->email );
356 }
357 if ( empty( $this->account_nonse ) ) {
358 $this->account_nonse = sha1( wp_rand( 10000, 99999 ) . time() . $this->activation_key );
359 }
360 }
361
362
363 public function get_avatar_url() {
364 return OsCustomerHelper::get_avatar_url( $this );
365 }
366
367 public function get_avatar_image() {
368 return OsCustomerHelper::get_avatar_image( $this );
369 }
370
371 // if this was a guest account without a set password and social login was not used, you can login just by email
372 public function can_login_without_password() {
373 return ( $this->is_guest && empty( $this->google_user_id ) && empty( $this->facebook_user_id ) );
374 }
375
376 public function prepare_data_before_it_is_set( $data ) {
377 if ( isset( $data['phone'] ) ) {
378 $data['phone'] = OsUtilHelper::sanitize_phone_number( $data['phone'] );
379 }
380
381 return $data;
382 }
383
384
385 protected function before_save() {
386 if ( empty( $this->uuid ) ) {
387 $this->uuid = OsUtilHelper::generate_uuid();
388 }
389 }
390
391 public function get_uuid(): string {
392 if ( ! $this->is_new_record() && empty( $this->uuid ) ) {
393 $this->update_attributes( [ 'uuid' => OsUtilHelper::generate_uuid() ] );
394 }
395 return $this->uuid ?? '';
396 }
397
398 protected function allowed_params( $role = 'admin' ) {
399 switch ( $role ) {
400 case 'admin':
401 $allowed_params = [
402 'id',
403 'uuid',
404 'first_name',
405 'last_name',
406 'email',
407 'phone',
408 'avatar_image_id',
409 'is_guest',
410 'notes',
411 'admin_notes',
412 'wordpress_user_id',
413 'password',
414 ];
415 break;
416 case 'customer':
417 case 'public':
418 $allowed_params = [
419 'first_name',
420 'last_name',
421 'email',
422 'phone',
423 'avatar_image_id',
424 'notes',
425 'password',
426 ];
427 break;
428 }
429
430 return $allowed_params;
431 }
432
433 protected function params_to_save( $role = 'admin' ) {
434 $params_to_save = array(
435 'id',
436 'uuid',
437 'first_name',
438 'last_name',
439 'email',
440 'phone',
441 'password',
442 'activation_key',
443 'account_nonse',
444 'avatar_image_id',
445 'status',
446 'is_guest',
447 'notes',
448 'admin_notes',
449 'wordpress_user_id',
450 'google_user_id',
451 'facebook_user_id',
452 );
453
454 return $params_to_save;
455 }
456
457 /**
458 * Validates and constructs a set of validation rules for properties.
459 *
460 * The method determines the validation rules to be applied to customer properties
461 * based on the context such as whether alternative validation is enabled, or based on
462 * default fields and specific settings. It also provides flexibility via filters to
463 * modify the resulting validation rules.
464 *
465 * @param bool $alternative_validation Indicates whether to use an alternative set of validation rules. Defaults to false.
466 *
467 * @return array An associative array where keys are property names and values are arrays of validation rules.
468 */
469 protected function properties_to_validate( $alternative_validation = false ) {
470 // if alternative validation is enabled - use a different scope of rules (useful when you don't need to run all validations for example on social login)
471 if ( $alternative_validation ) {
472 $validations = array(
473 'email' => array( 'presence', 'email', 'uniqueness' ),
474 );
475 } else {
476 $validations = array(
477 'first_name' => array( 'presence' ),
478 'last_name' => array( 'presence' ),
479 'email' => array( 'presence', 'email' ),
480 );
481
482 $default_fields = OsSettingsHelper::get_default_fields_for_customer();
483 foreach ( $default_fields as $name => $field ) {
484 if ( $field['required'] && $field['active'] ) {
485 $validations[ $name ][] = 'presence';
486 $validations[ $name ] = array_unique( $validations[ $name ] );
487 } else {
488 if ( isset( $validations[ $name ] ) ) {
489 $validations[ $name ] = array_diff( $validations[ $name ], [ 'presence' ] );
490 }
491 }
492 }
493 if ( OsAuthHelper::is_customer_auth_enabled() ) {
494 // auth enabled
495 $auth_field = OsAuthHelper::get_selected_customer_authentication_field_type();
496 if ( $auth_field == 'email' ) {
497 $validations['email'][] = 'uniqueness';
498 }
499 if ( $auth_field == 'phone' ) {
500 $validations['phone'][] = 'uniqueness';
501 }
502 } else {
503 // auth disabled
504 $merge_data = OsSettingsHelper::get_settings_value( 'default_contact_merge_behavior', 'email' );
505 if ( $merge_data == 'email' ) {
506 $validations['email'][] = 'uniqueness';
507 }
508 if ( $merge_data == 'phone' ) {
509 $validations['phone'][] = 'uniqueness';
510 }
511 }
512 $validations = apply_filters( 'latepoint_customer_model_validations', $validations );
513 }
514
515 return $validations;
516 }
517 }
518