PluginProbe
Property Hive / 1.4.46
Property Hive v1.4.46
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
propertyhive / includes / class-ph-ajax.php

class-ph-ajax.php in Property Hive 1.4.46, at includes/class-ph-ajax.php

5,215 lines 196.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
4
5 /**
6 * PropertyHive PH_AJAX
7 *
8 * AJAX Event Handler
9 *
10 * @class PH_AJAX
11 * @version 1.0.0
12 * @package PropertyHive/Classes
13 * @category Class
14 * @author PropertyHive
15 */
16 class PH_AJAX {
17
18 /**
19 * Hook into ajax events
20 */
21 public function __construct() {
22
23 // propertyhive_EVENT => nopriv
24 $ajax_events = array(
25 'add_note' => false,
26 'delete_note' => false,
27 'search_contacts' => false,
28 'search_properties' => false,
29 'search_negotiators' => false,
30 'load_existing_owner_contact' => false,
31 'load_existing_features' => false,
32 'make_property_enquiry' => true,
33 'create_contact_from_enquiry' => false,
34
35 // Dashboard components
36 'get_news' => false,
37 'get_viewings_awaiting_applicant_feedback' => false,
38
39 // Contact actions
40 'create_contact_login' => false,
41
42 // Appraisal actions
43 'get_appraisal_details_meta_box' => false,
44 'get_appraisal_actions' => false,
45 'appraisal_carried_out' => false,
46 'appraisal_cancelled' => false,
47 'appraisal_won' => false,
48 'appraisal_lost_reason' => false,
49 'appraisal_instructed' => false,
50 'appraisal_revert_pending' => false,
51 'appraisal_revert_carried_out' => false,
52 'appraisal_revert_won' => false,
53
54 // Viewing actions
55 'book_viewing_property' => false,
56 'book_viewing_contact' => false,
57 'get_viewing_details_meta_box' => false,
58 'get_viewing_actions' => false,
59 'viewing_carried_out' => false,
60 'viewing_cancelled' => false,
61 'viewing_email_applicant_booking_confirmation' => false,
62 'viewing_email_owner_booking_confirmation' => false,
63 'viewing_interested_feedback' => false,
64 'viewing_not_interested_feedback' => false,
65 'viewing_feedback_not_required' => false,
66 'viewing_revert_feedback_pending' => false,
67 'viewing_revert_pending' => false,
68 'viewing_feedback_passed_on' => false,
69 'get_property_viewings_meta_box' => false,
70 'get_contact_viewings_meta_box' => false,
71
72 // Offer actions
73 'record_offer_property' => false,
74 'record_offer_contact' => false,
75 'get_offer_details_meta_box' => false,
76 'get_offer_actions' => false,
77 'get_property_offers_meta_box' => false,
78 'offer_accepted' => false,
79 'offer_declined' => false,
80 'offer_revert_pending' => false,
81 'get_contact_offers_meta_box' => false,
82
83 // Sale actions
84 'get_sale_details_meta_box' => false,
85 'get_sale_actions' => false,
86 'get_sale_details_meta_box' => false,
87 'sale_exchanged' => false,
88 'sale_completed' => false,
89 'sale_fallen_through' => false,
90 'offer_declined' => false,
91 'get_property_sales_meta_box' => false,
92 'get_contact_sales_meta_box' => false,
93
94 'validate_save_contact' => false,
95 'applicant_registration' => true,
96 'login' => true,
97 'save_account_details' => true,
98 'save_account_requirements' => true,
99
100 'dismiss_notice_leave_review' => false,
101 'dismiss_notice_missing_search_results' => false,
102 'dismiss_notice_missing_google_maps_api_key' => false,
103 'dismiss_notice_invalid_expired_license_key' => false,
104 );
105
106 foreach ( $ajax_events as $ajax_event => $nopriv ) {
107 add_action( 'wp_ajax_propertyhive_' . $ajax_event, array( $this, $ajax_event ) );
108
109 if ( $nopriv ) {
110 add_action( 'wp_ajax_nopriv_propertyhive_' . $ajax_event, array( $this, $ajax_event ) );
111 }
112 }
113 }
114
115 public function dismiss_notice_leave_review()
116 {
117 update_option( 'propertyhive_review_prompt_due_timestamp', 0 );
118
119 // Quit out
120 die();
121 }
122
123 public function dismiss_notice_missing_search_results()
124 {
125 update_option( 'missing_search_results_notice_dismissed', 'yes' );
126
127 // Quit out
128 die();
129 }
130
131 public function dismiss_notice_missing_google_maps_api_key()
132 {
133 update_option( 'missing_google_maps_api_key_notice_dismissed', 'yes' );
134
135 // Quit out
136 die();
137 }
138
139 public function dismiss_notice_invalid_expired_license_key()
140 {
141 update_option( 'missing_invalid_expired_license_key_notice_dismissed', 'yes' );
142
143 // Quit out
144 die();
145 }
146
147 /**
148 * Output headers for JSON requests
149 */
150 private function json_headers() {
151 header( 'Content-Type: application/json; charset=utf-8' );
152 }
153
154 public function create_contact_login()
155 {
156 check_ajax_referer( 'create-login', 'security' );
157
158 $this->json_headers();
159
160 if (empty($_POST['contact_id']))
161 {
162 $return = array('error' => 'No contact selected');
163 echo json_encode( $return );
164 die();
165 }
166
167 if (empty($_POST['password']))
168 {
169 $return = array('error' => 'No password entered');
170 echo json_encode( $return );
171 die();
172 }
173
174 $contact = new PH_Contact((int)$_POST['contact_id']);
175
176 // Create user
177 $userdata = array(
178 'display_name' => get_the_title((int)$_POST['contact_id']),
179 'user_login' => sanitize_email($contact->email_address),
180 'user_email' => sanitize_email($contact->email_address),
181 'user_pass' => $_POST['password'],
182 'role' => 'property_hive_contact',
183 'show_admin_bar_front' => 'false',
184 );
185
186 $user_id = wp_insert_user( $userdata );
187
188 // On success
189 if ( ! is_wp_error( $user_id ) )
190 {
191 // Assign user ID to CPT
192 add_post_meta( (int)$_POST['contact_id'], '_user_id', $user_id );
193
194 $return = array('success' => true);
195 }
196 else
197 {
198 $return = array('error' => 'Failed to create user login');
199 }
200
201 echo json_encode( $return );
202 die();
203 }
204
205 /**
206 * Login user
207 */
208 public function login()
209 {
210 $return = array(
211 'success' => false,
212 'errors' => array(),
213 );
214
215 if ( check_ajax_referer( 'ph_login', 'security', false ) === FALSE )
216 {
217 $return['errors'][] = 'Invalid nonce';
218
219 $this->json_headers();
220 echo json_encode( $return );
221
222 // Quit out
223 die();
224 }
225
226 $creds = array(
227 'user_login' => ph_clean($_POST['email_address']),
228 'user_password' => ph_clean($_POST['password']),
229 );
230
231 $user = wp_signon( apply_filters( 'propertyhive_login_credentials', $creds ), is_ssl() );
232
233 if ( is_wp_error( $user ) )
234 {
235 //$return['errors'][] = $user->get_error_message();
236 }
237 else
238 {
239 // Check has associated contact CPT and is published
240 $args = array(
241 'post_type' => 'contact',
242 'fields' => 'ids',
243 'posts_per_page' => 1,
244 'post_status' => array( 'publish' ),
245 'meta_query' => array(
246 array(
247 'key' => '_user_id',
248 'value' => $user->ID
249 )
250 )
251 );
252
253 $contact_query = new WP_Query( $args );
254
255 if ( $contact_query->have_posts() )
256 {
257 while ( $contact_query->have_posts() )
258 {
259 $contact_query->the_post();
260
261 // Has associated published contact CPT
262 $return['success'] = true;
263
264 do_action('propertyhive_user_logged_in', get_the_ID(), $user->ID);
265 }
266 }
267
268 wp_reset_postdata();
269 }
270
271 $this->json_headers();
272 echo json_encode( $return );
273
274 // Quit out
275 die();
276 }
277
278 /**
279 * Register applicant
280 */
281 public function applicant_registration()
282 {
283 // Validate contact
284 global $post;
285
286 $return = array(
287 'success' => false,
288 'errors' => array(),
289 );
290
291 if ( check_ajax_referer( 'ph_register', 'security', false ) === FALSE )
292 {
293 $return['errors'][] = 'Invalid nonce';
294
295 $this->json_headers();
296 echo json_encode( $return );
297
298 // Quit out
299 die();
300 }
301
302 // Validate
303 $errors = array();
304
305 $form_controls = ph_get_user_details_form_fields();
306
307 $form_controls = apply_filters( 'propertyhive_user_details_form_fields', $form_controls );
308
309 $form_controls_2 = ph_get_applicant_requirements_form_fields();
310
311 $form_controls_2 = apply_filters( 'propertyhive_applicant_requirements_form_fields', $form_controls_2 );
312
313 $form_controls = array_merge( $form_controls, $form_controls_2 );
314
315 // need to improve this as duplicated in ph-shortcodes.php
316 if ( get_option( 'propertyhive_applicant_registration_form_disclaimer', '' ) != '' )
317 {
318 $disclaimer = get_option( 'propertyhive_applicant_registration_form_disclaimer', '' );
319
320 $form_controls['disclaimer'] = array(
321 'type' => 'checkbox',
322 'label' => $disclaimer,
323 'label_style' => 'width:100%;',
324 'required' => true
325 );
326 }
327
328 $form_controls = apply_filters( 'propertyhive_applicant_registration_form_fields', $form_controls );
329
330 $contact_post_id = false;
331
332 foreach ( $form_controls as $key => $control )
333 {
334 if ( isset( $control ) && isset( $control['required'] ) && $control['required'] === TRUE )
335 {
336 // This field is mandatory. Lets check we received it in the post
337 if ( ! isset( $_POST[$key] ) || ( isset( $_POST[$key] ) && empty( $_POST[$key] ) ) )
338 {
339 $errors[] = __( 'Missing required field', 'propertyhive' ) . ': ' . $key;
340 }
341 }
342 if ( isset( $control['type'] ) && $control['type'] == 'email' && isset( $_POST[$key] ) && ! empty( $_POST[$key] ) )
343 {
344 if ( ! is_email( $_POST[$key] ) )
345 {
346 $errors[] = __( 'Invalid email address provided', 'propertyhive' );
347 }
348 else
349 {
350 // Make sure this email address doesn't exist already
351 $args = array(
352 'post_type' => 'contact',
353 'posts_per_page' => 1,
354 'fields' => 'ids',
355 'post_status' => array( 'publish' ),
356 'meta_query' => array(
357 array(
358 'key' => '_email_address',
359 'value' => $_POST[$key]
360 )
361 )
362 );
363
364 $contacts_query = new WP_Query( $args );
365
366 if ( $contacts_query->have_posts() )
367 {
368 while ( $contacts_query->have_posts() )
369 {
370 $contacts_query->the_post();
371
372 $contact_post_id = get_the_ID();
373 }
374 //$errors[] = __( 'This email address is already registered', 'propertyhive' );
375 }
376 else
377 {
378 if ( email_exists( $_POST[$key] ) )
379 {
380 $errors[] = __( 'This email address is already registered to a user', 'propertyhive' );
381 }
382 }
383 wp_reset_postdata();
384 }
385 }
386 if ( $key == 'recaptcha' )
387 {
388 $secret = isset( $control['secret'] ) ? $control['secret'] : '';
389 $response = isset( $_POST['g-recaptcha-response'] ) ? ph_clean($_POST['g-recaptcha-response']) : '';
390
391 $response = wp_remote_post(
392 'https://www.google.com/recaptcha/api/siteverify',
393 array(
394 'method' => 'POST',
395 'body' => array( 'secret' => $secret, 'response' => $response ),
396 )
397 );
398 if ( is_wp_error( $response ) )
399 {
400 $errors[] = $response->get_error_message();
401 }
402 else
403 {
404 $response = json_decode($response['body'], TRUE);
405 if ( $response === FALSE )
406 {
407 $errors[] = __( 'Error decoding response from reCAPTCHA check', 'propertyhive' );
408 }
409 else
410 {
411 if ( isset($response['success']) && $response['success'] == true )
412 {
413
414 }
415 else
416 {
417 $errors[] = __( 'Failed reCAPTCHA validation', 'propertyhive' );
418 }
419 }
420 }
421 }
422 }
423
424 // Check password and password2 match
425 if ( isset( $_POST['password'] ) && isset( $_POST['password2'] ) && $_POST['password'] != $_POST['password2'] )
426 {
427 $errors[] = __( 'The passwords entered do not match', 'propertyhive' );
428 }
429
430 if ( !empty($errors) )
431 {
432 // Failed validation
433
434 $return['success'] = false;
435 $return['reason'] = 'validation';
436 $return['errors'] = $errors;
437 }
438 else
439 {
440 if ( $contact_post_id === FALSE )
441 {
442 // create CPT
443 $contact_post = array(
444 'post_title' => ph_clean($_POST['name']),
445 'post_content' => '',
446 'post_type' => 'contact',
447 'post_status' => 'publish',
448 'comment_status'=> 'closed',
449 'ping_status' => 'closed',
450 );
451
452 // Insert the post into the database
453 $contact_post_id = wp_insert_post( $contact_post );
454 }
455 else
456 {
457 // update CPT
458 $contact_post = array(
459 'ID' => $contact_post_id,
460 'post_title' => ph_clean($_POST['name']),
461 'post_status' => 'publish',
462 );
463
464 // Insert the post into the database
465 wp_update_post( $contact_post );
466 }
467
468 $forbidden_contact_methods = get_post_meta( $contact_post_id, '_forbidden_contact_methods', TRUE );
469 if ( !is_array($forbidden_contact_methods) )
470 {
471 $forbidden_contact_methods = array();
472 }
473 if ( ( $key = array_search('email', $forbidden_contact_methods) ) !== false ) {
474 unset($forbidden_contact_methods[$key]);
475 }
476 update_post_meta( $contact_post_id, '_forbidden_contact_methods', array_unique($forbidden_contact_methods) );
477
478 // Add post meta (contact details, requirements etc)
479 update_post_meta( $contact_post_id, '_email_address', sanitize_email($_POST['email_address']) );
480
481 $telephone_number = get_post_meta( $contact_post_id, '_telephone_number', TRUE );
482 if ( isset($_POST['telephone_number']) && $_POST['telephone_number'] != '' )
483 {
484 $telephone_number = $_POST['telephone_number'];
485 }
486 update_post_meta( $contact_post_id, '_telephone_number', ph_clean($telephone_number) );
487 update_post_meta( $contact_post_id, '_telephone_number_clean', ph_clean( ph_clean_telephone_number($telephone_number) ) );
488
489 $contact_types = get_post_meta( $contact_post_id, '_contact_types', TRUE );
490 if ( !is_array($contact_types) )
491 {
492 $contact_types = array();
493 }
494 if ( !in_array('applicant', $contact_types) )
495 {
496 $contact_types[] = 'applicant';
497 }
498 update_post_meta( $contact_post_id, '_contact_types', array_unique($contact_types) );
499
500 update_post_meta( $contact_post_id, '_applicant_profiles', 1 );
501
502 $applicant_profile = array();
503 $applicant_profile['department'] = $_POST['department'];
504
505 if ( $_POST['department'] == 'residential-sales' )
506 {
507 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['maximum_price']));
508
509 $applicant_profile['max_price'] = $price;
510
511 // Not used yet but could be if introducing currencies in the future.
512 $applicant_profile['max_price_actual'] = $price;
513
514 $percentage_lower = get_option( 'propertyhive_applicant_match_price_range_percentage_lower', '' );
515 $percentage_higher = get_option( 'propertyhive_applicant_match_price_range_percentage_higher', '' );
516
517 if ( $percentage_lower != '' && $percentage_higher != '' && $_POST['maximum_price'] != '' && $_POST['maximum_price'] != 0 )
518 {
519 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['maximum_price']));
520 $applicant_profile['match_price_range_lower'] = $price - ( $price * ( $percentage_lower / 100 ) );
521 $applicant_profile['match_price_range_lower_actual'] = $price - ( $price * ( $percentage_lower / 100 ) );
522
523 $applicant_profile['match_price_range_higher'] = $price + ( $price * ( $percentage_higher / 100 ) );
524 $applicant_profile['match_price_range_higher_actual'] = $price + ( $price * ( $percentage_higher / 100 ) );
525 }
526 }
527 elseif ( $_POST['department'] == 'residential-lettings' )
528 {
529 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['maximum_rent']));
530
531 $applicant_profile['max_rent'] = $price;
532 $applicant_profile['rent_frequency'] = 'pcm';
533 $price_actual = $price; // Stored in pcm
534 $applicant_profile['max_price_actual'] = $price_actual;
535 }
536
537 if ( $_POST['department'] == 'residential-sales' || $_POST['department'] == 'residential-lettings' )
538 {
539 $beds = preg_replace("/[^0-9]/", '', ph_clean($_POST['minimum_bedrooms']));
540 $applicant_profile['min_beds'] = $beds;
541
542 if ( isset($_POST['property_type']) && !empty($_POST['property_type']) )
543 {
544 $applicant_profile['property_types'] = is_array(ph_clean($_POST['property_type'])) ? ph_clean($_POST['property_type']) : array(ph_clean($_POST['property_type']));
545 }
546 }
547
548 if ( $_POST['department'] == 'commercial' )
549 {
550 $available_as = array();
551 if ( isset($_POST['available_as_sale']) && $_POST['available_as_sale'] == 'yes' )
552 {
553 $available_as[] = 'sale';
554 }
555 if ( isset($_POST['available_as_rent']) && $_POST['available_as_rent'] == 'yes' )
556 {
557 $available_as[] = 'rent';
558 }
559 $applicant_profile['available_as'] = $available_as;
560
561 $floor_area = preg_replace("/[^0-9.]/", '', ph_clean($_POST['minimum_floor_area']));
562 $applicant_profile['min_floor_area'] = $floor_area;
563 $applicant_profile['min_floor_area_actual'] = $floor_area;
564
565 $floor_area = preg_replace("/[^0-9.]/", '', ph_clean($_POST['maximum_floor_area']));
566 $applicant_profile['max_floor_area'] = $floor_area;
567 $applicant_profile['max_floor_area_actual'] = $floor_area;
568
569 if ( isset($_POST['commercial_property_type']) && !empty($_POST['commercial_property_type']) )
570 {
571 $applicant_profile['commercial_property_types'] = is_array(ph_clean($_POST['commercial_property_type'])) ? ph_clean($_POST['commercial_property_type']) : array(ph_clean($_POST['commercial_property_type']));
572 }
573 }
574
575 if ( isset($_POST['location']) && !empty($_POST['location']) )
576 {
577 $applicant_profile['locations'] = is_array(ph_clean($_POST['location'])) ? ph_clean($_POST['location']) : array(ph_clean($_POST['location']));
578 }
579
580 $applicant_profile['notes'] = ( ( isset($_POST['additional_requirements']) ) ? sanitize_textarea_field($_POST['additional_requirements']) : '' );
581
582 $applicant_profile['send_matching_properties'] = 'yes';
583 //$applicant_profile['auto_match_disabled'] = ''; // don't know what to do about this yet. Should probably look at global setting and reflect that
584
585 update_post_meta( $contact_post_id, '_applicant_profile_0', $applicant_profile );
586
587 if ( get_option( 'propertyhive_applicant_users', '' ) == 'yes' )
588 {
589 // Create user
590 $userdata = array(
591 'display_name' => ph_clean($_POST['name']),
592 'user_login' => sanitize_email($_POST['email_address']),
593 'user_email' => sanitize_email($_POST['email_address']),
594 'user_pass' => ph_clean($_POST['password']),
595 'role' => 'property_hive_contact',
596 'show_admin_bar_front' => 'false',
597 );
598
599 $user_id = wp_insert_user( $userdata );
600
601 //On success
602 if ( ! is_wp_error( $user_id ) )
603 {
604 // Assign user ID to CPT
605 add_post_meta( $contact_post_id, '_user_id', $user_id );
606
607 $return['success'] = true;
608
609 wp_set_auth_cookie( $user_id, true );
610
611 do_action( 'propertyhive_applicant_registered', $contact_post_id, $user_id );
612 }
613 else
614 {
615 $return['success'] = false;
616 $return['reason'] = 'validation';
617 $return['errors'] = array('Failed to create user. You might experience issues with logging in');
618 }
619 }
620 else
621 {
622 $return['success'] = true;
623
624 do_action( 'propertyhive_applicant_registered', $contact_post_id, 0 );
625 }
626 }
627
628 $this->json_headers();
629 echo json_encode( $return );
630
631 // Quit out
632 die();
633 }
634
635 /**
636 * Save account details
637 */
638 public function save_account_details()
639 {
640 global $wpdb, $current_user;
641
642 add_filter( 'send_email_change_email', '__return_false' );
643
644 $return = array(
645 'success' => false,
646 'errors' => array(),
647 );
648
649 // Got an issue with nonce being declined on second submission.
650 // Need to sort before putting this back in
651 /*if ( check_ajax_referer( 'ph_details', 'security', false ) === FALSE )
652 {
653 $return['errors'][] = 'Invalid nonce';
654
655 $this->json_headers();
656 echo json_encode( $return );
657
658 // Quit out
659 die();
660 }*/
661
662 // Validate
663 $errors = array();
664
665 $user_id = (int) get_current_user_id();
666 $current_user = get_user_by( 'id', $user_id );
667 if ( $user_id <= 0 )
668 {
669 $return['success'] = false;
670 $return['reason'] = 'notloggedin';
671 $return['errors'] = array('It doesn\'t appear that you\'re logged in');
672
673 $this->json_headers();
674 echo json_encode( $return );
675
676 // Quit out
677 die();
678 }
679
680 $form_controls = ph_get_user_details_form_fields();
681
682 $form_controls = apply_filters( 'propertyhive_user_details_form_fields', $form_controls );
683
684 foreach ( $form_controls as $key => $control )
685 {
686 if ( isset( $control ) && isset( $control['required'] ) && $control['required'] === TRUE )
687 {
688 // This field is mandatory. Lets check we received it in the post
689 if ( ! isset( $_POST[$key] ) || ( isset( $_POST[$key] ) && empty( $_POST[$key] ) ) && $control['type'] != 'password' )
690 {
691 $errors[] = __( 'Missing required field', 'propertyhive' ) . ': ' . $key;
692 }
693 }
694 if ( isset( $control['type'] ) && $control['type'] == 'email' && isset( $_POST[$key] ) && ! empty( $_POST[$key] ) )
695 {
696 if ( ! is_email( $_POST[$key] ) )
697 {
698 $errors[] = __( 'Invalid email address provided', 'propertyhive' );
699 }
700
701 // need to see if email address is being changed and, if so, check new email address doesn't exist already
702 }
703 }
704
705 // Check password and password2 match
706 if ( isset( $_POST['password'] ) && isset( $_POST['password2'] ) && !empty( $_POST['password'] ) && $_POST['password'] != $_POST['password2'] )
707 {
708 $errors[] = __( 'The passwords entered do not match', 'propertyhive' );
709 }
710
711 if ( !empty($errors) )
712 {
713 // Failed validation
714
715 $return['success'] = false;
716 $return['reason'] = 'validation';
717 $return['errors'] = $errors;
718 }
719 else
720 {
721 $contact = new PH_Contact( '', $user_id );
722
723 // create CPT
724 $contact_post = array(
725 'ID' => $contact->id,
726 'post_title' => ph_clean($_POST['name']),
727 );
728
729 // Update the post in the database
730 $contact_post_id = wp_update_post( $contact_post );
731
732 update_post_meta( $contact_post_id, '_email_address', sanitize_email($_POST['email_address']) );
733 if (isset($_POST['telephone_number']))
734 {
735 update_post_meta( $contact_post_id, '_telephone_number', ph_clean($_POST['telephone_number']) );
736 }
737
738 // Update user
739 $userdata = array(
740 'ID' => $user_id,
741 'display_name' => ph_clean($_POST['name']),
742 'user_email' => sanitize_email($_POST['email_address']),
743 );
744
745 if ( isset($_POST['password']) && !empty($_POST['password']) )
746 {
747 $userdata['user_pass'] = ph_clean($_POST['password']);
748 }
749
750 $user_id = wp_update_user( $userdata );
751
752 $user_roles = $current_user->roles;
753 $user_role = array_shift($user_roles);
754
755 if ( $user_role === 'property_hive_contact' )
756 {
757 // Have to update login via SQL as wp_update_user won't allow altering
758 // Only do it for property hive contacts though as admin or editor might be viewing this page
759 $wpdb->update($wpdb->users, array('user_login' => sanitize_email($_POST['email_address'])), array('ID' => $user_id));
760 }
761
762 //On success
763 if ( ! is_wp_error( $user_id ) )
764 {
765 $return['success'] = true;
766
767 wp_set_auth_cookie( $user_id, true );
768
769 do_action( 'propertyhive_account_details_updated', $contact_post_id, $user_id );
770 }
771 else
772 {
773 $return['success'] = false;
774 $return['reason'] = 'validation';
775 $return['errors'] = array('Failed to update user. Please try again');
776 }
777 }
778
779 $this->json_headers();
780 echo json_encode( $return );
781
782 // Quit out
783 die();
784 }
785
786 /**
787 * Save account requirements
788 */
789 public function save_account_requirements()
790 {
791 // Validate contact
792 global $post;
793
794 $return = array(
795 'success' => false,
796 'errors' => array(),
797 );
798
799 // Got an issue with nonce being declined on second submission.
800 // Need to sort before putting this back in
801 /*if ( check_ajax_referer( 'ph_requirements', 'security', false ) === FALSE )
802 {
803 $return['errors'][] = 'Invalid nonce';
804
805 $this->json_headers();
806 echo json_encode( $return );
807
808 // Quit out
809 die();
810 }*/
811
812 // Validate
813 $errors = array();
814
815 $user_id = (int) get_current_user_id();
816 $current_user = get_user_by( 'id', $user_id );
817 if ( $user_id <= 0 )
818 {
819 $return['success'] = false;
820 $return['reason'] = 'notloggedin';
821 $return['errors'] = array('It doesn\'t appear that you\'re logged in');
822
823 $this->json_headers();
824 echo json_encode( $return );
825
826 // Quit out
827 die();
828 }
829
830 $form_controls = ph_get_applicant_requirements_form_fields();
831
832 $form_controls = apply_filters( 'propertyhive_applicant_requirements_form_fields', $form_controls );
833
834 foreach ( $form_controls as $key => $control )
835 {
836 if ( isset( $control ) && isset( $control['required'] ) && $control['required'] === TRUE )
837 {
838 // This field is mandatory. Lets check we received it in the post
839 if ( ! isset( $_POST[$key] ) || ( isset( $_POST[$key] ) && empty( $_POST[$key] ) ) )
840 {
841 $errors[] = __( 'Missing required field', 'propertyhive' ) . ': ' . $key;
842 }
843 }
844 }
845
846 if ( !empty($errors) )
847 {
848 // Failed validation
849
850 $return['success'] = false;
851 $return['reason'] = 'validation';
852 $return['errors'] = $errors;
853 }
854 else
855 {
856 $contact = new PH_Contact( '', $user_id );
857
858 $contact_post_id = $contact->id;
859
860 $applicant_profile = array();
861 $applicant_profile['department'] = ph_clean($_POST['department']);
862
863 if ( $_POST['department'] == 'residential-sales' )
864 {
865 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['maximum_price']));
866
867 $applicant_profile['max_price'] = $price;
868
869 // Not used yet but could be if introducing currencies in the future.
870 $applicant_profile['max_price_actual'] = $price;
871 }
872 elseif ( $_POST['department'] == 'residential-lettings' )
873 {
874 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['maximum_rent']));
875
876 $applicant_profile['max_rent'] = $price;
877 $applicant_profile['rent_frequency'] = 'pcm';
878 $price_actual = $price; // Stored in pcm
879 $applicant_profile['max_price_actual'] = $price_actual;
880 }
881
882 if ( $_POST['department'] == 'residential-sales' || $_POST['department'] == 'residential-lettings' )
883 {
884 $beds = preg_replace("/[^0-9]/", '', ph_clean($_POST['minimum_bedrooms']));
885 $applicant_profile['min_beds'] = $beds;
886
887 if ( isset($_POST['property_type']) && !empty($_POST['property_type']) )
888 {
889 $applicant_profile['property_types'] = array(ph_clean($_POST['property_type']));
890 }
891 }
892
893 if ( $_POST['department'] == 'commercial' )
894 {
895 $available_as = array();
896 if ( isset($_POST['available_as_sale']) && $_POST['available_as_sale'] == 'yes' )
897 {
898 $available_as[] = 'sale';
899 }
900 if ( isset($_POST['available_as_rent']) && $_POST['available_as_rent'] == 'yes' )
901 {
902 $available_as[] = 'rent';
903 }
904 $applicant_profile['available_as'] = $available_as;
905
906 $floor_area = preg_replace("/[^0-9.]/", '', ph_clean($_POST['minimum_floor_area']));
907 $applicant_profile['min_floor_area'] = $floor_area;
908 $applicant_profile['min_floor_area_actual'] = $floor_area;
909
910 $floor_area = preg_replace("/[^0-9.]/", '', ph_clean($_POST['maximum_floor_area']));
911 $applicant_profile['max_floor_area'] = $floor_area;
912 $applicant_profile['max_floor_area_actual'] = $floor_area;
913
914 if ( isset($_POST['commercial_property_type']) && !empty($_POST['commercial_property_type']) )
915 {
916 $applicant_profile['commercial_property_types'] = array(ph_clean($_POST['commercial_property_type']));
917 }
918 }
919
920 if ( isset($_POST['location']) && !empty($_POST['location']) )
921 {
922 $applicant_profile['locations'] = array(ph_clean($_POST['location']));
923 }
924
925 $applicant_profile['notes'] = ( ( isset($_POST['additional_requirements']) ) ? sanitize_textarea_field($_POST['additional_requirements']) : '' );
926
927 $applicant_profile['send_matching_properties'] = 'yes';
928 //$applicant_profile['auto_match_disabled'] = ''; // don't know what to do about this yet. Should probably look at global setting and reflect that
929
930 update_post_meta( $contact_post_id, '_applicant_profile_0', $applicant_profile );
931
932 $return['success'] = true;
933
934 do_action( 'propertyhive_account_requirements_updated', $contact_post_id, $user_id );
935 }
936
937 $this->json_headers();
938 echo json_encode( $return );
939
940 // Quit out
941 die();
942 }
943
944 /**
945 * Load existing features
946 */
947 public function load_existing_features() {
948
949 global $post, $wpdb;
950
951 $this->json_headers();
952
953 $return = array();
954
955 $property_query = new WP_Query(array(
956 'post_type' => 'property',
957 'post_status' => 'any',
958 'nopaging' => true
959 ));
960
961 if ($property_query->have_posts())
962 {
963 while ($property_query->have_posts())
964 {
965 $property_query->the_post();
966
967 $num_property_features = get_post_meta($post->ID, '_features', TRUE);
968 if ($num_property_features == '') { $num_property_features = 0; }
969
970 for ($i = 0; $i < $num_property_features; ++$i)
971 {
972 $feature = get_post_meta($post->ID, '_feature_' . $i, TRUE);
973 if (!in_array($feature, $return) && trim($feature) != '')
974 {
975 $return[] = $feature;
976 }
977 }
978 }
979 }
980
981 echo json_encode($return);
982
983 // Quit out
984 die();
985 }
986
987 /**
988 * Load existing owner on property record
989 */
990 public function load_existing_owner_contact() {
991
992 check_ajax_referer( 'load-existing-owner-contact', 'security' );
993
994 $contact_id = (int)$_POST['contact_id'];
995
996 $contact = get_post($contact_id);
997
998 echo '<div id="existing-owner-details-' . $contact_id . '">';
999
1000 if ( !is_null( $contact ) )
1001 {
1002 echo '<p class="form-field">';
1003 echo '<label>' . __('Name', 'propertyhive') . '</label>';
1004 echo '<a href="' . get_edit_post_link( $contact_id ) . '">' . get_the_title($contact_id) . '</a>';
1005 echo '</p>';
1006
1007 $address = array();
1008 $address_elements = array( '_address_name_number', '_address_street', '_address_two', '_address_three', '_address_four', '_address_postcode' );
1009 foreach ( $address_elements as $address_element )
1010 {
1011 if ( get_post_meta($contact_id, $address_element, TRUE) != '' )
1012 {
1013 $address[] = get_post_meta($contact_id, $address_element, TRUE);
1014 }
1015 }
1016
1017 echo '<p class="form-field">';
1018 echo '<label>' . __('Address', 'propertyhive') . '</label>';
1019 echo ( ( !empty($address) ) ? implode(", ", $address) : '-' );
1020 echo '</p>';
1021
1022 echo '<p class="form-field">';
1023 echo '<label>' . __('Telephone Number', 'propertyhive') . '</label>';
1024 echo ( ( get_post_meta($contact_id, '_telephone_number', TRUE) != '' ) ? get_post_meta($contact_id, '_telephone_number', TRUE) : '-' );
1025 echo '</p>';
1026
1027 echo '<p class="form-field">';
1028 echo '<label>' . __('Email Address', 'propertyhive') . '</label>';
1029 echo ( ( get_post_meta($contact_id, '_email_address', TRUE) != '' ) ? get_post_meta($contact_id, '_email_address', TRUE) : '-' );
1030 echo '</p>';
1031 }
1032 else
1033 {
1034 echo __( 'Invalid contact record', 'propertyhive' );
1035 }
1036
1037 echo '<p class="form-field">';
1038 echo '<label></label>';
1039 echo '<a href="" class="button" id="remove-owner-contact-' . $contact_id . '">Remove Owner</a> ';
1040 echo '<a href="" class="button add-additional-owner-contact">Add Additional Owner</a>';
1041 echo '</p>';
1042
1043 echo '</div>';
1044
1045 // Quit out
1046 die();
1047
1048 }
1049
1050 /**
1051 * Search contacts via ajax
1052 */
1053 public function search_contacts() {
1054
1055 global $post;
1056
1057 check_ajax_referer( 'search-contacts', 'security' );
1058
1059 $return = array();
1060
1061 $keyword = ph_clean($_POST['keyword']);
1062
1063 if ( !empty( $keyword ) && strlen( $keyword ) > 2 )
1064 {
1065 // Get all contacts that match the name
1066 $args = array(
1067 'post_type' => 'contact',
1068 'nopaging' => true,
1069 'post_status' => array( 'publish' ),
1070 'fields' => 'ids'
1071 );
1072 if ( isset($_POST['contact_type']) && $_POST['contact_type'] != '' )
1073 {
1074 $args['meta_query'] = array(
1075 array(
1076 'key' => '_contact_types',
1077 'value' => ph_clean($_POST['contact_type']),
1078 'compare' => 'LIKE',
1079 )
1080 );
1081 }
1082
1083 add_filter( 'posts_where', array( $this, 'search_contacts_where' ), 10, 2 );
1084
1085 $contact_query = new WP_Query( $args );
1086
1087 remove_filter( 'posts_where', array( $this, 'search_contacts_where' ) );
1088
1089 if ( $contact_query->have_posts() )
1090 {
1091 while ( $contact_query->have_posts() )
1092 {
1093 $contact_query->the_post();
1094
1095 $contact = new PH_Contact( get_the_ID() );
1096
1097 $return[] = array(
1098 'ID' => get_the_ID(),
1099 'post_title' => get_the_title(get_the_ID()),
1100 'address_name_number' => $contact->_address_name_number,
1101 'address_street' => $contact->_address_street,
1102 'address_two' => $contact->_address_two,
1103 'address_three' => $contact->_address_three,
1104 'address_four' => $contact->_address_four,
1105 'address_postcode' => $contact->_address_postcode,
1106 'address_country' => $contact->_address_country,
1107 'address_full_formatted' => $contact->get_formatted_full_address('<br>'),
1108 );
1109 }
1110 }
1111
1112 wp_reset_postdata();
1113 }
1114
1115 $this->json_headers();
1116 echo json_encode( $return );
1117
1118 // Quit out
1119 die();
1120 }
1121
1122 public function search_contacts_where( $where, &$wp_query )
1123 {
1124 global $wpdb;
1125
1126 $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( ph_clean($_POST['keyword']) ) ) . '%\'';
1127
1128 return $where;
1129 }
1130
1131 /**
1132 * Search propertie via ajax
1133 */
1134 public function search_properties() {
1135
1136 global $post;
1137
1138 check_ajax_referer( 'search-properties', 'security' );
1139
1140 $return = array();
1141
1142 $keyword = ph_clean($_POST['keyword']);
1143
1144 if ( !empty( $keyword ) && strlen( $keyword ) > 2 )
1145 {
1146 // Get all contacts that match the name
1147 $args = array(
1148 'post_type' => 'property',
1149 'nopaging' => true,
1150 'post_status' => array( 'publish' ),
1151 'fields' => 'ids'
1152 );
1153
1154 $meta_query = array();
1155 if ( isset($_POST['department']) && $_POST['department'] != '' )
1156 {
1157 $meta_query[] = array(
1158 'key' => '_department',
1159 'value' => ph_clean($_POST['department']),
1160 );
1161 }
1162 if ( !empty($meta_query) )
1163 {
1164 $args['meta_query'] = $meta_query;
1165 }
1166
1167 add_filter( 'posts_join', array( $this, 'search_properties_join' ), 10, 2 );
1168 add_filter( 'posts_where', array( $this, 'search_properties_where' ), 10, 2 );
1169
1170 $property_query = new WP_Query( $args );
1171
1172 remove_filter( 'posts_join', array( $this, 'search_properties_join' ) );
1173 remove_filter( 'posts_where', array( $this, 'search_properties_where' ) );
1174
1175 if ( $property_query->have_posts() )
1176 {
1177 while ( $property_query->have_posts() )
1178 {
1179 $property_query->the_post();
1180
1181 $property = new PH_Property(get_the_ID());
1182
1183 $owner_id = $property->_owner_contact_id;
1184 $owner_name = '';
1185 if ( ( is_array($owner_id) && !empty($owner_id) ) || ( !is_array($owner_id) && $owner_id != '' ) )
1186 {
1187 if ( is_array($owner_id) )
1188 {
1189 $owner_id = reset($owner_id);
1190 }
1191 $owner_name = get_the_title($owner_id);
1192 }
1193
1194 $return[] = array(
1195 'ID' => get_the_ID(),
1196 'post_title' => $property->get_formatted_full_address(),
1197 'owner_id' => $owner_id,
1198 'owner_name' => $owner_name
1199 );
1200 }
1201 }
1202
1203 wp_reset_postdata();
1204 }
1205
1206 $this->json_headers();
1207 echo json_encode( $return );
1208
1209 // Quit out
1210 die();
1211 }
1212
1213 public function search_properties_join( $joins )
1214 {
1215 global $wpdb;
1216
1217 $joins .= " INNER JOIN {$wpdb->postmeta} AS mt1 ON {$wpdb->posts}.ID = mt1.post_id ";
1218
1219 return $joins;
1220 }
1221
1222 public function search_properties_where( $where )
1223 {
1224 $where .= " AND (
1225 (mt1.meta_key='_address_name_number' AND mt1.meta_value LIKE '" . esc_sql(ph_clean($_POST['keyword'])) . "%')
1226 OR
1227 (mt1.meta_key='_address_street' AND mt1.meta_value LIKE '" . esc_sql(ph_clean($_POST['keyword'])) . "%')
1228 OR
1229 (mt1.meta_key='_address_2' AND mt1.meta_value LIKE '" . esc_sql(ph_clean($_POST['keyword'])) . "%')
1230 OR
1231 (mt1.meta_key='_address_3' AND mt1.meta_value LIKE '" . esc_sql(ph_clean($_POST['keyword'])) . "%')
1232 OR
1233 (mt1.meta_key='_address_4' AND mt1.meta_value LIKE '" . esc_sql(ph_clean($_POST['keyword'])) . "%')
1234 OR
1235 (mt1.meta_key='_address_postcode' AND mt1.meta_value LIKE '" . esc_sql(ph_clean($_POST['keyword'])) . "%')
1236 OR
1237 (mt1.meta_key='_reference_number' AND mt1.meta_value = '" . esc_sql(ph_clean($_POST['keyword'])) . "')
1238 ) ";
1239
1240 return $where;
1241 }
1242
1243 /**
1244 * Search users/negotiators via ajax
1245 */
1246 public function search_negotiators() {
1247
1248 global $post;
1249
1250 check_ajax_referer( 'search-negotiators', 'security' );
1251
1252 $return = array();
1253
1254 $keyword = ph_clean($_POST['keyword']);
1255
1256 if ( !empty( $keyword ) && strlen( $keyword ) > 2 )
1257 {
1258 // Get all contacts that match the name
1259 $args = array(
1260 'number' => 9999,
1261 'search' => $keyword . '*',
1262 'orderby' => 'display_name',
1263 'role__not_in' => array('property_hive_contact')
1264 );
1265
1266 $user_query = new WP_User_Query( $args );
1267
1268 // Get the results
1269 $users = $user_query->get_results();
1270
1271 if ( !empty($users) )
1272 {
1273 foreach ($users as $user)
1274 {
1275 $user_data = get_userdata($user->ID);
1276
1277 $return[] = array(
1278 'ID' => $user->ID,
1279 'post_title' => $user_data->display_name
1280 );
1281 }
1282 }
1283 }
1284
1285 $this->json_headers();
1286 echo json_encode( $return );
1287
1288 // Quit out
1289 die();
1290 }
1291
1292 /**
1293 * Add note via ajax
1294 */
1295 public function add_note() {
1296
1297 check_ajax_referer( 'add-note', 'security' );
1298
1299 $post_id = (int)$_POST['post_id'];
1300
1301 if ( $post_id > 0 ) {
1302
1303 $current_user = wp_get_current_user();
1304
1305 $note = wp_kses_post( trim( stripslashes( $_POST['note'] ) ) );
1306
1307 // Add note/comment to property
1308 $comment = array(
1309 'note_type' => 'note',
1310 'note' => $note
1311 );
1312
1313 $data = array(
1314 'comment_post_ID' => $post_id,
1315 'comment_author' => $current_user->display_name,
1316 'comment_author_email' => 'propertyhive@noreply.com',
1317 'comment_author_url' => '',
1318 'comment_date' => date("Y-m-d H:i:s"),
1319 'comment_content' => serialize($comment),
1320 'comment_approved' => 1,
1321 'comment_type' => 'propertyhive_note',
1322 );
1323 $comment_id = wp_insert_comment( $data );
1324
1325 if ($comment_id !== FALSE)
1326 {
1327 $comment = get_comment($comment_id);
1328
1329 ?>
1330 <li rel="<?php echo absint( $comment_id ) ; ?>" class="note">
1331 <div class="note_content">
1332 <?php echo wpautop( wptexturize( wp_kses_post( $note ) ) ); ?>
1333 </div>
1334 <p class="meta">
1335 <abbr class="exact-date" title="<?php echo $comment->comment_date_gmt; ?> GMT"><?php printf( __( '%s ago', 'propertyhive' ), human_time_diff( strtotime( $comment->comment_date_gmt ), current_time( 'timestamp', 1 ) ) ); ?></abbr>
1336 <?php if ( $comment->comment_author !== __( 'Property Hive', 'propertyhive' ) ) printf( ' ' . __( 'by %s', 'propertyhive' ), $comment->comment_author ); ?>
1337 <a href="#" class="delete_note"><?php _e( 'Delete', 'propertyhive' ); ?></a>
1338 </p>
1339 </li>
1340 <?php
1341 }
1342 }
1343
1344 // Quit out
1345 die();
1346 }
1347
1348 /**
1349 * Delete order note via ajax
1350 */
1351 public function delete_note() {
1352
1353 check_ajax_referer( 'delete-note', 'security' );
1354
1355 $note_id = (int)$_POST['note_id'];
1356
1357 if ( $note_id > 0 ) {
1358 wp_delete_comment( $note_id );
1359 }
1360
1361 // Quit out
1362 die();
1363 }
1364
1365 /**
1366 * Delete order note via ajax
1367 */
1368 public function make_property_enquiry() {
1369
1370 global $post;
1371
1372 $return = array();
1373
1374 // Validate
1375 $errors = array();
1376 $form_controls = array();
1377
1378 if ( ! isset( $_POST['property_id'] ) || ( isset( $_POST['property_id'] ) && empty( $_POST['property_id'] ) ) )
1379 {
1380 $errors[] = __( 'Property ID is a required field and must be supplied when making an enquiry', 'propertyhive' ) . ': ' . $key;
1381 }
1382 else
1383 {
1384 //$post = get_post((int)$_POST['property_id']);
1385
1386 $form_controls = ph_get_property_enquiry_form_fields();
1387
1388 $form_controls = apply_filters( 'propertyhive_property_enquiry_form_fields', $form_controls );
1389 }
1390
1391 foreach ( $form_controls as $key => $control )
1392 {
1393 if ( isset( $control ) && isset( $control['required'] ) && $control['required'] === TRUE )
1394 {
1395 // This field is mandatory. Lets check we received it in the post
1396 if ( ! isset( $_POST[$key] ) || ( isset( $_POST[$key] ) && empty( $_POST[$key] ) ) )
1397 {
1398 $errors[] = __( 'Missing required field', 'propertyhive' ) . ': ' . $key;
1399 }
1400 }
1401 if ( isset( $control['type'] ) && $control['type'] == 'email' && isset( $_POST[$key] ) && ! empty( $_POST[$key] ) && ! is_email( $_POST[$key] ) )
1402 {
1403 $errors[] = __( 'Invalid email address provided', 'propertyhive' ) . ': ' . $key;
1404 }
1405 if ( $key == 'recaptcha' )
1406 {
1407 $secret = isset( $control['secret'] ) ? $control['secret'] : '';
1408 $response = isset( $_POST['g-recaptcha-response'] ) ? ph_clean($_POST['g-recaptcha-response']) : '';
1409
1410 $response = wp_remote_post(
1411 'https://www.google.com/recaptcha/api/siteverify',
1412 array(
1413 'method' => 'POST',
1414 'body' => array( 'secret' => $secret, 'response' => $response ),
1415 )
1416 );
1417 if ( is_wp_error( $response ) )
1418 {
1419 $errors[] = $response->get_error_message();
1420 }
1421 else
1422 {
1423 $response = json_decode($response['body'], TRUE);
1424 if ( $response === FALSE )
1425 {
1426 $errors[] = 'Error decoding response from reCAPTCHA check';
1427 }
1428 else
1429 {
1430 if ( isset($response['success']) && $response['success'] == true )
1431 {
1432
1433 }
1434 else
1435 {
1436 $errors[] = 'Failed reCAPTCHA validation';
1437 }
1438 }
1439 }
1440 }
1441 }
1442
1443 if ( !empty($errors) )
1444 {
1445 // Failed validation
1446
1447 $return['success'] = false;
1448 $return['reason'] = 'validation';
1449 $return['errors'] = $errors;
1450 }
1451 else
1452 {
1453 // Passed validation
1454 $property_ids = explode("|", ph_clean($_POST['property_id']));
1455
1456 // Get recipient email address
1457 $to = '';
1458
1459 // Try and get office's email address first, else fallback to admin email
1460 $office_id = get_post_meta((int)$property_ids[0], '_office_id', TRUE);
1461 if ( $office_id != '' )
1462 {
1463 if ( get_post_type( $office_id ) == 'office' )
1464 {
1465 $property_department = get_post_meta((int)$property_ids[0], '_department', TRUE);
1466
1467 $fields_to_check = array();
1468 switch ( $property_department )
1469 {
1470 case "residential-sales":
1471 {
1472 $fields_to_check[] = '_office_email_address_sales';
1473 $fields_to_check[] = '_office_email_address_lettings';
1474 $fields_to_check[] = '_office_email_address_commercial';
1475 break;
1476 }
1477 case "residential-lettings":
1478 {
1479 $fields_to_check[] = '_office_email_address_lettings';
1480 $fields_to_check[] = '_office_email_address_sales';
1481 $fields_to_check[] = '_office_email_address_commercial';
1482 break;
1483 }
1484 case "commercial":
1485 {
1486 $fields_to_check[] = '_office_email_address_commercial';
1487 $fields_to_check[] = '_office_email_address_lettings';
1488 $fields_to_check[] = '_office_email_address_sales';
1489 break;
1490 }
1491 }
1492
1493 foreach ( $fields_to_check as $field_to_check )
1494 {
1495 $to = get_post_meta($office_id, $field_to_check, TRUE);
1496 if ( $to != '' )
1497 {
1498 break;
1499 }
1500 }
1501 }
1502 }
1503 if ( $to == '' )
1504 {
1505 $to = get_option( 'admin_email' );
1506 }
1507
1508 if ( count($property_ids) == 1 )
1509 {
1510 $subject = __( 'New Property Enquiry', 'propertyhive' ) . ': ' . get_the_title( (int)$property_ids[0] );
1511 }
1512 else
1513 {
1514 $subject = __( 'Multiple Property Enquiry', 'propertyhive' ) . ': ' . count($property_ids) . ' Properties';
1515 }
1516 $message = __( "You have received a property enquiry via your website. Please find details of the enquiry below", 'propertyhive' ) . "\n\n";
1517
1518 $message = apply_filters( 'propertyhive_property_enquiry_pre_body', $message, $property_ids );
1519
1520 $message .= __( 'Properties', 'propertyhive' ) . ":\n";
1521 foreach ( $property_ids as $property_id )
1522 {
1523 $message .= get_the_title( (int)$property_id ) . " (" . get_permalink( (int)$property_id ) . ")\n";
1524 }
1525 $message .= "\n";
1526
1527 unset($form_controls['action']);
1528 unset($_POST['action']);
1529 unset($form_controls['property_id']); // Unset so the field doesn't get shown in the enquiry details
1530
1531 $form_controls = apply_filters( 'propertyhive_property_enquiry_body_form_fields', $form_controls );
1532
1533 foreach ($form_controls as $key => $control)
1534 {
1535 if ( isset($control['type']) && $control['type'] == 'html' ) { continue; }
1536
1537 $label = ( isset($control['label']) ) ? $control['label'] : $key;
1538 $label = ( isset($control['email_label']) ) ? $control['email_label'] : $label;
1539 $value = ( isset($_POST[$key]) ) ? sanitize_textarea_field($_POST[$key]) : '';
1540
1541 $message .= strip_tags($label) . ": " . strip_tags($value) . "\n";
1542 }
1543
1544 $from_email_address = get_option('propertyhive_email_from_address', '');
1545 if ( $from_email_address == '' )
1546 {
1547 $from_email_address = get_option('admin_email');
1548 }
1549 if ( $from_email_address == '' )
1550 {
1551 // Should never get here
1552 $from_email_address = $_POST['email_address'];
1553 }
1554
1555 $headers = array();
1556 if ( isset($_POST['name']) && ! empty($_POST['name']) )
1557 {
1558 $headers[] = 'From: ' . ph_clean( $_POST['name'] ) . ' <' . sanitize_email( $from_email_address ) . '>';
1559 }
1560 else
1561 {
1562 $headers[] = 'From: <' . sanitize_email( $from_email_address ) . '>';
1563 }
1564 if ( isset($_POST['email_address']) && sanitize_email( $_POST['email_address'] ) != '' )
1565 {
1566 $headers[] = 'Reply-To: ' . sanitize_email( $_POST['email_address'] );
1567 }
1568
1569 $to = apply_filters( 'propertyhive_property_enquiry_to', $to, $property_ids );
1570 $subject = apply_filters( 'propertyhive_property_enquiry_subject', $subject, $property_ids );
1571 $message = apply_filters( 'propertyhive_property_enquiry_body', $message, $property_ids );
1572 $headers = apply_filters( 'propertyhive_property_enquiry_headers', $headers, $property_ids );
1573
1574 $sent = wp_mail( $to, $subject, $message, $headers );
1575
1576 if ( ! $sent )
1577 {
1578 $return['success'] = false;
1579 $return['reason'] = 'nosend';
1580 $return['errors'] = $errors;
1581 }
1582 else
1583 {
1584 $return['success'] = true;
1585
1586 if ( get_option( 'propertyhive_store_property_enquiries', 'yes' ) == 'yes' )
1587 {
1588 // Now insert into enquiries section of WordPress
1589 if ( count($property_ids) == 1 )
1590 {
1591 $title = __( 'Property Enquiry', 'propertyhive' ) . ': ' . get_the_title( (int)$property_ids[0] );
1592 }
1593 else
1594 {
1595 $title = __( 'Multiple Property Enquiry', 'propertyhive' );
1596 }
1597 if ( isset($_POST['name']) && ! empty($_POST['name']) )
1598 {
1599 $title .= __( ' from ', 'propertyhive' ) . ph_clean($_POST['name']);
1600 }
1601
1602 $enquiry_post = array(
1603 'post_title' => $title,
1604 'post_content' => '',
1605 'post_type' => 'enquiry',
1606 'post_status' => 'publish',
1607 'comment_status' => 'closed',
1608 'ping_status' => 'closed',
1609 );
1610
1611 // Insert the post into the database
1612 $enquiry_post_id = wp_insert_post( $enquiry_post );
1613
1614 add_post_meta( $enquiry_post_id, '_status', 'open' );
1615 add_post_meta( $enquiry_post_id, '_source', 'website' );
1616 add_post_meta( $enquiry_post_id, '_negotiator_id', '' );
1617 add_post_meta( $enquiry_post_id, '_office_id', $office_id );
1618
1619 foreach ($_POST as $key => $value)
1620 {
1621 if ( $key == 'property_id' )
1622 {
1623 foreach ( $property_ids as $property_id )
1624 {
1625 add_post_meta( $enquiry_post_id, $key, (int)$property_id );
1626 }
1627 }
1628 else
1629 {
1630 add_post_meta( $enquiry_post_id, $key, sanitize_textarea_field($value) );
1631 }
1632 }
1633 }
1634
1635 // Send auto-responder
1636 if ( get_option( 'propertyhive_enquiry_auto_responder', '' ) == 'yes' )
1637 {
1638 // Auto-responder enabled
1639 PH()->email->send_enquiry_auto_responder( $_POST );
1640 }
1641
1642 do_action('propertyhive_property_enquiry_sent', $_POST, $to);
1643 }
1644 }
1645
1646 $this->json_headers();
1647 echo json_encode( $return );
1648
1649 // Quit out
1650 die();
1651 }
1652
1653 /**
1654 * Create contact from enquiry
1655 */
1656 public function create_contact_from_enquiry()
1657 {
1658 global $post;
1659
1660 $enquiry_post_id = ( (isset($_POST['post_id'])) ? (int)$_POST['post_id'] : '' );
1661 $nonce = ( (isset($_POST['security'])) ? ph_clean($_POST['security']) : '' );
1662
1663 if ( ! wp_verify_nonce( $nonce, 'create-content-from-enquiry-nonce-' . $enquiry_post_id ) )
1664 {
1665 // This nonce is not valid.
1666 die( json_encode( array('error' => 'Invalid nonce. Please refresh and try again') ) );
1667 }
1668
1669 $enquiry_meta = get_metadata( 'post', $enquiry_post_id );
1670
1671 $name = false;
1672 $email = false;
1673 $telephone = false;
1674
1675 foreach ($enquiry_meta as $key => $value)
1676 {
1677 if ( strpos($key, 'name') !== false )
1678 {
1679 $name = $value[0];
1680 }
1681 elseif ( strpos($key, 'email') !== false )
1682 {
1683 $email = $value[0];
1684 }
1685 elseif ( strpos($key, 'telephone') !== false )
1686 {
1687 $telephone = $value[0];
1688 }
1689 }
1690
1691 if ( $name === false || $email === false )
1692 {
1693 // This nonce is not valid.
1694 die( json_encode( array('error' => 'Name or email address not found') ) );
1695 }
1696
1697 // We've not imported this property before
1698 $postdata = array(
1699 'post_excerpt' => '',
1700 'post_content' => '',
1701 'post_title' => utf8_encode(wp_strip_all_tags( $name )),
1702 'post_status' => 'publish',
1703 'post_type' => 'contact',
1704 'ping_status' => 'closed',
1705 'comment_status' => 'closed',
1706 );
1707
1708 $contact_post_id = wp_insert_post( $postdata, true );
1709
1710 if ( is_wp_error( $contact_post_id ) )
1711 {
1712 die( json_encode( array('error' => 'Error creating contact') ) );
1713 }
1714 elseif ( $contact_post_id == 0 )
1715 {
1716 die( json_encode( array('error' => 'Error creating contact') ) );
1717 }
1718
1719 if ( $telephone !== FALSE ) {
1720 update_post_meta( $contact_post_id, '_telephone_number', ph_clean( $telephone ) );
1721 update_post_meta( $contact_post_id, '_telephone_number', ph_clean( ph_clean_telephone_number( $telephone ) ) );
1722 }
1723
1724 if ( $email !== FALSE ) { update_post_meta( $contact_post_id, '_email_address', ph_clean( $email ) ); }
1725
1726 do_action('propertyhive_create_contact_from_enquiry', $enquiry_post_id, $contact_post_id);
1727
1728 die( json_encode( array('success' => get_edit_post_link($contact_post_id, '')) ) );
1729 }
1730
1731 public function validate_save_contact()
1732 {
1733 global $post;
1734
1735 check_ajax_referer( 'contact-save-validation', 'security' );
1736
1737 $this->json_headers();
1738
1739 parse_str($_POST['form_data']);
1740
1741 $return = array('errors' => array());
1742
1743 if ( isset($_email_address) && $_email_address != '' )
1744 {
1745 $email_addresses = explode( ",", $_email_address );
1746
1747 foreach ( $email_addresses as $email_address )
1748 {
1749 $email_address = trim( $email_address );
1750
1751 if ( !is_email($email_address) )
1752 {
1753 $return['errors'][] = __( 'Email address is invalid', 'propertyhive' ) . ' - ' . $email_address;
1754 }
1755
1756 // Check it doesn't exist already
1757 $args = array(
1758 'post_type' => 'contact',
1759 'post_status' => 'any',
1760 'posts_per_page' => 1,
1761 'fields' => 'ids',
1762 'meta_query' => array(
1763 'relation' => 'OR',
1764 array(
1765 'key' => '_email_address',
1766 'value' => $email_address,
1767 'compare' => '='
1768 ),
1769 array(
1770 'key' => '_email_address',
1771 'value' => ',' . $email_address,
1772 'compare' => 'LIKE'
1773 )
1774 ,
1775 array(
1776 'key' => '_email_address',
1777 'value' => $email_address . ',',
1778 'compare' => 'LIKE'
1779 )
1780 )
1781 );
1782 if ( isset($post_ID) && $post_ID != '' )
1783 {
1784 $args['post__not_in'] = array( $post_ID );
1785 }
1786
1787 $contact_query = new WP_Query( $args );
1788
1789 if ( $contact_query->have_posts() )
1790 {
1791 while ( $contact_query->have_posts() )
1792 {
1793 $contact_query->the_post();
1794
1795 $return['errors'][] = __( 'A contact, ' . get_the_title() . ', already exists with email address', 'propertyhive' ) . ' ' . $email_address;
1796 }
1797 }
1798 }
1799 }
1800
1801 echo json_encode($return);
1802
1803 die();
1804 }
1805
1806 // Dashboard related functions
1807 public function get_news()
1808 {
1809 $this->json_headers();
1810
1811 include_once( ABSPATH . WPINC . '/feed.php' );
1812
1813 $return = array();
1814
1815 // Get a SimplePie feed object from the specified feed source.
1816 $rss = fetch_feed( 'https://wp-property-hive.com/category/property-hive-news/feed/' );
1817
1818 $maxitems = 0;
1819
1820 if ( ! is_wp_error( $rss ) ) : // Checks that the object is created correctly
1821
1822 // Figure out how many total items there are, but limit it to 5.
1823 $maxitems = $rss->get_item_quantity( 5 );
1824
1825 // Build an array of all the items, starting with element 0 (first element).
1826 $rss_items = $rss->get_items( 0, $maxitems );
1827
1828 foreach ( $rss_items as $item )
1829 {
1830 $return[] = array(
1831 'title' => esc_html( $item->get_title() ),
1832 'permalink' => esc_url( $item->get_permalink() ),
1833 'date' => $item->get_date('F d, Y')
1834 );
1835 }
1836
1837 endif;
1838
1839 echo json_encode($return);
1840
1841 die();
1842 }
1843
1844 public function get_viewings_awaiting_applicant_feedback()
1845 {
1846 global $post;
1847
1848 $this->json_headers();
1849
1850 $return = array();
1851
1852 $args = array(
1853 'post_type' => 'viewing',
1854 'fields' => 'ids',
1855 'post_status' => 'publish',
1856 'meta_query' => array(
1857 array(
1858 'key' => '_status',
1859 'value' => 'carried_out'
1860 ),
1861 array(
1862 'key' => '_feedback_status',
1863 'value' => ''
1864 )
1865 )
1866 );
1867
1868 $viewings_query = new WP_Query( $args );
1869
1870 if ( $viewings_query->have_posts() )
1871 {
1872 while ( $viewings_query->have_posts() )
1873 {
1874 $viewings_query->the_post();
1875
1876 $property_id = get_post_meta( get_the_ID(), '_property_id', TRUE );
1877 $property = new PH_Property((int)$property_id);
1878
1879 $applicant_contact_id = get_post_meta( get_the_ID(), '_applicant_contact_id', TRUE );
1880
1881 $return[] = array(
1882 'ID' => get_the_ID(),
1883 'edit_link' => get_edit_post_link( get_the_ID() ),
1884 'start_date_time' => get_post_meta( get_the_ID(), '_start_date_time', TRUE ),
1885 'start_date_time_formatted_Hi_jSFY' => date("H:i jS F Y", strtotime(get_post_meta( get_the_ID(), '_start_date_time', TRUE ))),
1886 'property_id' => $property_id,
1887 'property_address' => $property->get_formatted_full_address(),
1888 'applicant_contact_id' => $applicant_contact_id,
1889 'applicant_name' => get_the_title( $applicant_contact_id ),
1890 );
1891 }
1892 }
1893
1894 wp_reset_postdata();
1895
1896 echo json_encode($return);
1897
1898 die();
1899 }
1900
1901 public function get_appraisal_details_meta_box()
1902 {
1903 global $post;
1904
1905 check_ajax_referer( 'appraisal-details-meta-box', 'security' );
1906
1907 $post = get_post((int)$_POST['appraisal_id']);
1908
1909 $appraisal = new PH_Appraisal((int)$_POST['appraisal_id']);
1910
1911 echo '<div class="propertyhive_meta_box">';
1912
1913 echo '<div class="options_group">';
1914
1915 echo '<p class="form-field">
1916
1917 <label for="">' . __('Status', 'propertyhive') . '</label>
1918
1919 ' . ucwords(str_replace("_", " ", $appraisal->status));
1920
1921 echo '</p>';
1922
1923 if ( $appraisal->status == 'cancelled' )
1924 {
1925 $args = array(
1926 'id' => '_cancelled_reason',
1927 'label' => __( 'Reason Cancelled', 'propertyhive' ),
1928 'desc_tip' => false,
1929 'class' => '',
1930 'value' => $appraisal->cancelled_reason,
1931 'custom_attributes' => array(
1932 'style' => 'width:95%; max-width:500px;'
1933 )
1934 );
1935 propertyhive_wp_textarea_input( $args );
1936 }
1937
1938 if ( $appraisal->status == 'carried_out' || $appraisal->status == 'won' || $appraisal->status == 'instructed' )
1939 {
1940 if ( $appraisal->department == 'residential-sales' )
1941 {
1942 $args = array(
1943 'id' => '_valued_price',
1944 'label' => __( 'Valued Price', 'propertyhive' ) . ' (&pound;)',
1945 'desc_tip' => false,
1946 'class' => 'short',
1947 'value' => $appraisal->valued_price,
1948 );
1949 propertyhive_wp_text_input( $args );
1950 }
1951 elseif ( $appraisal->department == 'residential-lettings' )
1952 {
1953 $rent_frequency = $appraisal->valued_rent_frequency;
1954
1955 echo '<p class="form-field">
1956
1957 <label for="">' . __('Valued Rent', 'propertyhive') . ' (&pound;)</label>
1958
1959 <input type="text" class="" name="_valued_rent" id="_valued_rent" value="' . $appraisal->valued_rent . '" placeholder="" style="width:10%; min-width:100px;">
1960
1961 <select id="_valued_rent_frequency" name="_valued_rent_frequency" class="select" style="width:auto">
1962 <option value="pppw"' . ( ($rent_frequency == 'pppw') ? ' selected' : '') . '>' . __('Per Person Per Week', 'propertyhive') . '</option>
1963 <option value="pw"' . ( ($rent_frequency == 'pw') ? ' selected' : '') . '>' . __('Per Week', 'propertyhive') . '</option>
1964 <option value="pcm"' . ( ($rent_frequency == 'pcm' || $rent_frequency == '') ? ' selected' : '') . '>' . __('Per Calendar Month', 'propertyhive') . '</option>
1965 <option value="pq"' . ( ($rent_frequency == 'pq') ? ' selected' : '') . '>' . __('Per Quarter', 'propertyhive') . '</option>
1966 <option value="pa"' . ( ($rent_frequency == 'pa') ? ' selected' : '') . '>' . __('Per Annum', 'propertyhive') . '</option>
1967 </select>
1968
1969 </p>';
1970 }
1971 }
1972
1973 if ( $appraisal->status == 'lost' )
1974 {
1975 $args = array(
1976 'id' => '_lost_reason',
1977 'label' => __( 'Reason Lost', 'propertyhive' ),
1978 'desc_tip' => false,
1979 'class' => '',
1980 'value' => $appraisal->lost_reason,
1981 'custom_attributes' => array(
1982 'style' => 'width:95%; max-width:500px;'
1983 )
1984 );
1985 propertyhive_wp_textarea_input( $args );
1986 }
1987
1988 do_action('propertyhive_appraisal_details_fields');
1989
1990 echo '</div>';
1991
1992 echo '</div>';
1993
1994 die();
1995 }
1996
1997 public function get_appraisal_actions()
1998 {
1999 check_ajax_referer( 'appraisal-actions', 'security' );
2000
2001 $post_id = (int)$_POST['appraisal_id'];
2002
2003 $status = get_post_meta( $post_id, '_status', TRUE );
2004 $department = get_post_meta( $post_id, '_department', TRUE );
2005
2006 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_appraisal_actions_meta_box">
2007
2008 <div class="options_group" style="padding-top:8px;">';
2009
2010 $show_cancelled_meta_boxes = false;
2011 $show_carried_out_meta_boxes = false;
2012 $show_instructed_meta_boxes = false;
2013 $show_lost_meta_boxes = false;
2014
2015 $actions = array();
2016
2017 if ( $status == 'pending' )
2018 {
2019 /*$actions[] = '<a
2020 href=""
2021 class="button"
2022 style="width:100%; margin-bottom:7px; text-align:center"
2023 >' . __('Print Market Appraisal Sheet', 'propertyhive') . '</a>';
2024 if ( get_option('propertyhive_module_disabled_contacts', '') != 'yes' )
2025 {
2026 $actions[] = '<a
2027 href=""
2028 class="button"
2029 style="width:100%; margin-bottom:7px; text-align:center"
2030 >' . __('Run Potential Applicant Match', 'propertyhive') . '</a>';
2031 }*/
2032 $actions[] = '<a
2033 href="#action_panel_appraisal_carried_out"
2034 class="button button-success appraisal-action"
2035 style="width:100%; margin-bottom:7px; text-align:center"
2036 >' . __('Appraisal Carried Out', 'propertyhive') . '</a>';
2037 $actions[] = '<a
2038 href="#action_panel_appraisal_cancelled"
2039 class="button appraisal-action"
2040 style="width:100%; margin-bottom:7px; text-align:center"
2041 >' . __('Appraisal Cancelled', 'propertyhive') . '</a>';
2042
2043 $show_cancelled_meta_boxes = true;
2044 $show_carried_out_meta_boxes = true;
2045 }
2046
2047 if ( $status == 'carried_out' )
2048 {
2049 $actions[] = '<a
2050 href="#action_panel_appraisal_won"
2051 class="button button-success appraisal-action"
2052 style="width:100%; margin-bottom:7px; text-align:center"
2053 >' . __('Appraisal Won', 'propertyhive') . '</a>';
2054
2055 $actions[] = '<a
2056 href="#action_panel_appraisal_lost"
2057 class="button button-danger appraisal-action"
2058 style="width:100%; margin-bottom:7px; text-align:center"
2059 >' . __('Appraisal Lost', 'propertyhive') . '</a>';
2060
2061 $show_lost_meta_boxes = true;
2062 }
2063
2064 if ( $status == 'won' )
2065 {
2066 $actions[] = '<a
2067 href="#action_panel_appraisal_instruct"
2068 class="button button-success appraisal-action"
2069 style="width:100%; margin-bottom:7px; text-align:center"
2070 >' . __('Instruct Property', 'propertyhive') . '</a>';
2071
2072 $show_instructed_meta_boxes = true;
2073 }
2074
2075 if ( $status == 'won' || $status == 'lost' )
2076 {
2077 $actions[] = '<a
2078 href="#action_panel_appraisal_revert_carried_out"
2079 class="button appraisal-action"
2080 style="width:100%; margin-bottom:7px; text-align:center"
2081 >' . __('Revert To Carried Out', 'propertyhive') . '</a>';
2082 }
2083
2084 if ( $status == 'instructed' )
2085 {
2086 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
2087
2088 $actions[] = '<a
2089 href="' . get_edit_post_link($property_id) . '"
2090 class="button"
2091 style="width:100%; margin-bottom:7px; text-align:center"
2092 >' . __('View Instructed Property', 'propertyhive') . '</a>';
2093
2094 /*$actions[] = '<a
2095 href="#action_panel_appraisal_revert_won"
2096 class="button appraisal-action"
2097 style="width:100%; margin-bottom:7px; text-align:center"
2098 >' . __('Revert To Won', 'propertyhive') . '</a>';*/
2099 }
2100
2101 if ( $status == 'carried_out' || $status == 'cancelled' )
2102 {
2103 $actions[] = '<a
2104 href="#action_panel_appraisal_revert_pending"
2105 class="button appraisal-action"
2106 style="width:100%; margin-bottom:7px; text-align:center"
2107 >' . __('Revert To Pending', 'propertyhive') . '</a>';
2108 }
2109
2110 $actions = apply_filters( 'propertyhive_admin_appraisal_actions', $actions, $post_id );
2111
2112 if ( !empty($actions) )
2113 {
2114 echo implode("", $actions);
2115 }
2116 else
2117 {
2118 echo '<div style="text-align:center">' . __( 'No actions to display', 'propertyhive' ) . '</div>';
2119 }
2120
2121 echo '</div>
2122
2123 </div>';
2124
2125 if ( $show_cancelled_meta_boxes )
2126 {
2127 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_cancelled" style="display:none;">
2128
2129 <div class="options_group" style="padding-top:8px;">
2130
2131 <div class="form-field">
2132
2133 <label for="_appraisal_cancelled_reason">' . __( 'Reason Cancelled', 'propertyhive' ) . '</label>
2134
2135 <textarea id="_cancelled_reason" name="_cancelled_reason" style="width:100%;">' . get_post_meta( $post_id, '_cancelled_reason', TRUE ) . '</textarea>
2136
2137 </div>
2138
2139 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2140 <a class="button button-primary cancelled-reason-action-submit" href="#">' . __( 'Save', 'propertyhive' ) . '</a>
2141
2142 </div>
2143
2144 </div>';
2145 }
2146
2147 if ( $show_carried_out_meta_boxes )
2148 {
2149 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_carried_out" style="display:none;">
2150
2151 <div class="options_group" style="padding-top:8px;">';
2152
2153 if ( $department == 'residential-sales' )
2154 {
2155 echo '<div class="form-field">
2156
2157 <label for="_price">' . __( 'Valued Price (&pound;)', 'propertyhive' ) . '</label>
2158
2159 <input type="text" id="_price" name="_price" style="width:100%;" value="' . get_post_meta( $post_id, '_valued_price', TRUE ) . '">
2160
2161 </div>';
2162 }
2163 else
2164 {
2165 $rent_frequency = get_post_meta( $post_id, '_valued_rent_frequency', TRUE );
2166 echo '<div class="form-field">
2167
2168 <label for="_price">' . __( 'Valued Rent (&pound;)', 'propertyhive' ) . '</label>
2169
2170 <input type="text" id="_price" name="_price" style="width:100%;" value="' . get_post_meta( $post_id, '_valued_rent', TRUE ) . '">
2171
2172 <select id="_rent_frequency" name="_rent_frequency" class="select" style="width:100%">
2173 <option value="pppw"' . ( ($rent_frequency == 'pppw') ? ' selected' : '') . '>' . __('Per Person Per Week', 'propertyhive') . '</option>
2174 <option value="pw"' . ( ($rent_frequency == 'pw') ? ' selected' : '') . '>' . __('Per Week', 'propertyhive') . '</option>
2175 <option value="pcm"' . ( ($rent_frequency == 'pcm' || $rent_frequency == '') ? ' selected' : '') . '>' . __('Per Calendar Month', 'propertyhive') . '</option>
2176 <option value="pq"' . ( ($rent_frequency == 'pq') ? ' selected' : '') . '>' . __('Per Quarter', 'propertyhive') . '</option>
2177 <option value="pa"' . ( ($rent_frequency == 'pa') ? ' selected' : '') . '>' . __('Per Annum', 'propertyhive') . '</option>
2178 </select>
2179
2180 </div>';
2181 }
2182
2183 echo '<a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2184 <a class="button button-primary carried-out-action-submit" href="#">' . __( 'Save', 'propertyhive' ) . '</a>
2185
2186 </div>
2187
2188 </div>';
2189 }
2190
2191 if ( $show_instructed_meta_boxes )
2192 {
2193 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_instruct" style="display:none;">
2194
2195 <div class="options_group" style="padding-top:8px;">';
2196
2197 echo '<div style="margin-bottom:13px;">' . __( 'Upon instruction a new property record will be created within the \'Properties\' area.', 'propertyhive' ) . '</div>';
2198
2199 echo '<a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2200 <a class="button button-primary instructed-action-submit" href="#">' . __( 'OK', 'propertyhive' ) . '</a>
2201
2202 </div>
2203
2204 </div>';
2205 }
2206
2207 if ( $show_lost_meta_boxes )
2208 {
2209 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_lost" style="display:none;">
2210
2211 <div class="options_group" style="padding-top:8px;">
2212
2213 <div class="form-field">
2214
2215 <label for="_lost_reason">' . __( 'Reason Lost', 'propertyhive' ) . '</label>
2216
2217 <textarea id="_lost_reason" name="_lost_reason" style="width:100%;">' . get_post_meta( $post_id, '_lost_reason', TRUE ) . '</textarea>
2218
2219 </div>
2220
2221 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2222 <a class="button button-primary lost-reason-action-submit" href="#">' . wp_kses_post( __( 'Save Reason Lost', 'propertyhive' ) ) . '</a>
2223
2224 </div>
2225
2226 </div>';
2227 }
2228
2229 die();
2230 }
2231
2232 public function appraisal_carried_out()
2233 {
2234 check_ajax_referer( 'appraisal-actions', 'security' );
2235
2236 $post_id = (int)$_POST['appraisal_id'];
2237
2238 $status = get_post_meta( $post_id, '_status', TRUE );
2239
2240 if ( $status == 'pending' )
2241 {
2242 update_post_meta( $post_id, '_status', 'carried_out' );
2243
2244 if ( get_post_meta( $post_id, '_department', TRUE ) == 'residential-sales' )
2245 {
2246 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['price']));
2247 update_post_meta( $post_id, '_valued_price', $price );
2248 update_post_meta( $post_id, '_valued_price_actual', $price );
2249 }
2250 elseif ( get_post_meta( $post_id, '_department', TRUE ) == 'residential-lettings' )
2251 {
2252 $rent = preg_replace("/[^0-9]/", '', ph_clean($_POST['rent']));
2253 update_post_meta( $post_id, '_valued_rent', $rent );
2254
2255 update_post_meta( $post_id, '_valued_rent_frequency', ph_clean($_POST['rent_frequency']) );
2256
2257 switch (ph_clean($_POST['rent_frequency']))
2258 {
2259 case "pppw":
2260 {
2261 $bedrooms = get_post_meta( $postID, '_bedrooms', true );
2262 if ( ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' ) && apply_filters( 'propertyhive_pppw_to_consider_bedrooms', true ) == true )
2263 {
2264 $price = (($rent * 52) / 12) * $bedrooms;
2265 }
2266 else
2267 {
2268 $price = ($rent * 52) / 12;
2269 }
2270 break;
2271 }
2272 case "pw": { $price = ($rent * 52) / 12; break; }
2273 case "pcm": { $price = $rent; break; }
2274 case "pq": { $price = ($rent * 4) / 12; break; }
2275 case "pa": { $price = ($rent / 12); break; }
2276 }
2277 update_post_meta( $post_id, '_valued_price_actual', $price );
2278 }
2279
2280 $current_user = wp_get_current_user();
2281
2282 // Add note/comment to appraisal
2283 $comment = array(
2284 'note_type' => 'action',
2285 'action' => 'appraisal_carried_out',
2286 );
2287
2288 $data = array(
2289 'comment_post_ID' => $post_id,
2290 'comment_author' => $current_user->display_name,
2291 'comment_author_email' => 'propertyhive@noreply.com',
2292 'comment_author_url' => '',
2293 'comment_date' => date("Y-m-d H:i:s"),
2294 'comment_content' => serialize($comment),
2295 'comment_approved' => 1,
2296 'comment_type' => 'propertyhive_note',
2297 );
2298 $comment_id = wp_insert_comment( $data );
2299 }
2300
2301 die();
2302 }
2303
2304 public function appraisal_cancelled()
2305 {
2306 check_ajax_referer( 'appraisal-actions', 'security' );
2307
2308 $post_id = (int)$_POST['appraisal_id'];
2309
2310 $status = get_post_meta( $post_id, '_status', TRUE );
2311
2312 if ( $status == 'pending' )
2313 {
2314 update_post_meta( $post_id, '_status', 'cancelled' );
2315 update_post_meta( $post_id, '_cancelled_reason', sanitize_textarea_field( $_POST['cancelled_reason'] ) );
2316
2317 $current_user = wp_get_current_user();
2318
2319 // Add note/comment to appraisal
2320 $comment = array(
2321 'note_type' => 'action',
2322 'action' => 'appraisal_cancelled',
2323 );
2324
2325 $data = array(
2326 'comment_post_ID' => $post_id,
2327 'comment_author' => $current_user->display_name,
2328 'comment_author_email' => 'propertyhive@noreply.com',
2329 'comment_author_url' => '',
2330 'comment_date' => date("Y-m-d H:i:s"),
2331 'comment_content' => serialize($comment),
2332 'comment_approved' => 1,
2333 'comment_type' => 'propertyhive_note',
2334 );
2335 $comment_id = wp_insert_comment( $data );
2336 }
2337
2338 die();
2339 }
2340
2341 public function appraisal_won()
2342 {
2343 check_ajax_referer( 'appraisal-actions', 'security' );
2344
2345 $post_id = (int)$_POST['appraisal_id'];
2346
2347 $status = get_post_meta( $post_id, '_status', TRUE );
2348
2349 if ( $status == 'carried_out' )
2350 {
2351 update_post_meta( $post_id, '_status', 'won' );
2352
2353 $current_user = wp_get_current_user();
2354
2355 // Add note/comment to appraisal
2356 $comment = array(
2357 'note_type' => 'action',
2358 'action' => 'appraisal_won',
2359 );
2360
2361 $data = array(
2362 'comment_post_ID' => $post_id,
2363 'comment_author' => $current_user->display_name,
2364 'comment_author_email' => 'propertyhive@noreply.com',
2365 'comment_author_url' => '',
2366 'comment_date' => date("Y-m-d H:i:s"),
2367 'comment_content' => serialize($comment),
2368 'comment_approved' => 1,
2369 'comment_type' => 'propertyhive_note',
2370 );
2371 $comment_id = wp_insert_comment( $data );
2372 }
2373
2374 die();
2375 }
2376
2377 public function appraisal_lost_reason()
2378 {
2379 check_ajax_referer( 'appraisal-actions', 'security' );
2380
2381 $post_id = (int)$_POST['appraisal_id'];
2382
2383 $status = get_post_meta( $post_id, '_status', TRUE );
2384
2385 if ( $status == 'carried_out' )
2386 {
2387 update_post_meta( $post_id, '_status', 'lost' );
2388 update_post_meta( $post_id, '_lost_reason', sanitize_textarea_field( $_POST['lost_reason'] ) );
2389
2390 $current_user = wp_get_current_user();
2391
2392 // Add note/comment to appraisal
2393 $comment = array(
2394 'note_type' => 'action',
2395 'action' => 'appraisal_lost',
2396 );
2397
2398 $data = array(
2399 'comment_post_ID' => $post_id,
2400 'comment_author' => $current_user->display_name,
2401 'comment_author_email' => 'propertyhive@noreply.com',
2402 'comment_author_url' => '',
2403 'comment_date' => date("Y-m-d H:i:s"),
2404 'comment_content' => serialize($comment),
2405 'comment_approved' => 1,
2406 'comment_type' => 'propertyhive_note',
2407 );
2408 $comment_id = wp_insert_comment( $data );
2409 }
2410
2411 die();
2412 }
2413
2414 public function appraisal_instructed()
2415 {
2416 check_ajax_referer( 'appraisal-actions', 'security' );
2417
2418 $post_id = (int)$_POST['appraisal_id'];
2419
2420 $status = get_post_meta( $post_id, '_status', TRUE );
2421
2422 if ( $status == 'won' )
2423 {
2424 // Create property record and copy everything over
2425 $display_address = array();
2426 if ( get_post_meta( $post_id, '_address_street', TRUE ) != '' )
2427 {
2428 $display_address[] = get_post_meta( $post_id, '_address_street', TRUE );
2429 }
2430 if ( get_post_meta( $post_id, '_address_two', TRUE ) != '' )
2431 {
2432 $display_address[] = get_post_meta( $post_id, '_address_two', TRUE );
2433 }
2434 if ( get_post_meta( $post_id, '_address_three', TRUE ) != '' )
2435 {
2436 $display_address[] = get_post_meta( $post_id, '_address_three', TRUE );
2437 }
2438 else
2439 {
2440 if ( get_post_meta( $post_id, '_address_four', TRUE ) != '' )
2441 {
2442 $display_address[] = get_post_meta( $post_id, '_address_four', TRUE );
2443 }
2444 }
2445 $display_address = implode(", ", $display_address);
2446
2447 $property_post = array(
2448 'post_title' => ph_clean($display_address),
2449 'post_content' => '',
2450 'post_type' => 'property',
2451 'post_status' => 'publish',
2452 'comment_status' => 'closed',
2453 'ping_status' => 'closed',
2454 );
2455
2456 // Insert the post into the database
2457 $property_post_id = wp_insert_post( $property_post );
2458
2459 if ( is_wp_error($property_post_id) || $property_post_id == 0 )
2460 {
2461 // Failed. Don't really know at the moment how to handle this
2462
2463 $return = array('error' => 'Failed to create property post. Please try again');
2464 //echo json_encode( $return );
2465 //die();
2466 }
2467 else
2468 {
2469 // Successfully added property post
2470
2471 $department = get_post_meta( $post_id, '_department', TRUE );
2472
2473 update_post_meta( $property_post_id, '_address_name_number', get_post_meta( $post_id, '_address_name_number', TRUE ) );
2474 update_post_meta( $property_post_id, '_address_street', get_post_meta( $post_id, '_address_street', TRUE ) );
2475 update_post_meta( $property_post_id, '_address_two', get_post_meta( $post_id, '_address_two', TRUE ) );
2476 update_post_meta( $property_post_id, '_address_three', get_post_meta( $post_id, '_address_three', TRUE ) );
2477 update_post_meta( $property_post_id, '_address_four', get_post_meta( $post_id, '_address_four', TRUE ) );
2478 update_post_meta( $property_post_id, '_address_postcode', get_post_meta( $post_id, '_address_postcode', TRUE ) );
2479 update_post_meta( $property_post_id, '_address_country', get_post_meta( $post_id, '_address_country', TRUE ) );
2480
2481 if ( ini_get('allow_url_fopen') )
2482 {
2483 // No lat lng. Let's get it
2484 $address_to_geocode = array();
2485 if ( get_post_meta( $post_id, '_address_name_number', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_name_number', TRUE ); }
2486 if ( get_post_meta( $post_id, '_address_street', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_street', TRUE ); }
2487 if ( get_post_meta( $post_id, '_address_two', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_two', TRUE ); }
2488 if ( get_post_meta( $post_id, '_address_three', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_three', TRUE ); }
2489 if ( get_post_meta( $post_id, '_address_four', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_four', TRUE ); }
2490 if ( get_post_meta( $post_id, '_address_postcode', TRUE ) ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_postcode', TRUE ); }
2491
2492 $country = get_option( 'propertyhive_default_country', 'GB' );
2493 $request_url = "https://maps.googleapis.com/maps/api/geocode/xml?address=" . urlencode( implode( ", ", $address_to_geocode ) ) . "&sensor=false&region=gb"; // the request URL you'll send to google to get back your XML feed
2494
2495 $api_key = get_option('propertyhive_google_maps_api_key', '');
2496 if ( $api_key != '' ) { $request_url .= "&key=" . $api_key; }
2497
2498 $response = wp_remote_get($request_url);
2499
2500 if ( is_array( $response ) && !is_wp_error( $response ) )
2501 {
2502 $header = $response['headers']; // array of http header lines
2503 $body = $response['body']; // use the content
2504
2505 $xml = simplexml_load_string($body);
2506
2507 if ( $xml !== FALSE )
2508 {
2509 $status = $xml->status; // Get the request status as google's api can return several responses
2510
2511 if ($status == "OK")
2512 {
2513 //request returned completed time to get lat / lng for storage
2514 $lat = (string)$xml->result->geometry->location->lat;
2515 $lng = (string)$xml->result->geometry->location->lng;
2516
2517 if ($lat != '' && $lng != '')
2518 {
2519 update_post_meta( $post_id, '_latitude', $lat );
2520 update_post_meta( $post_id, '_longitude', $lng );
2521 }
2522 }
2523 }
2524 }
2525 }
2526
2527 update_post_meta( $property_post_id, '_department', $department );
2528
2529 switch ( $department )
2530 {
2531 case "residential-sales":
2532 {
2533 update_post_meta( $property_post_id, '_currency', 'GBP' );
2534
2535 $price = preg_replace("/[^0-9]/", '', get_post_meta( $post_id, '_valued_price', TRUE ));
2536 update_post_meta( $property_post_id, '_price', $price );
2537
2538 break;
2539 }
2540 case "residential-lettings":
2541 {
2542 update_post_meta( $property_post_id, '_currency', 'GBP' );
2543
2544 $rent = preg_replace("/[^0-9.]/", '', get_post_meta( $post_id, '_valued_rent', TRUE ));
2545 update_post_meta( $property_post_id, '_rent', $rent );
2546 update_post_meta( $property_post_id, '_rent_frequency', get_post_meta( $post_id, '_valued_rent_frequency', TRUE ) );
2547
2548 break;
2549 }
2550 }
2551
2552 // Store price in common currency (GBP) used for ordering
2553 $ph_countries = new PH_Countries();
2554 $ph_countries->update_property_price_actual( $property_post_id );
2555
2556 update_post_meta( $property_post_id, '_bedrooms', get_post_meta( $post_id, '_bedrooms', TRUE ) );
2557 update_post_meta( $property_post_id, '_bathrooms', get_post_meta( $post_id, '_bathrooms', TRUE ) );
2558 update_post_meta( $property_post_id, '_reception_rooms', get_post_meta( $post_id, '_reception_rooms', TRUE ) );
2559
2560 update_post_meta( $property_post_id, '_on_market', '' );
2561 update_post_meta( $property_post_id, '_featured', '' );
2562
2563 // Taxonomies
2564 wp_set_object_terms( $property_post_id, wp_get_object_terms( $post_id, 'property_type', array("fields" => "ids") ), 'property_type' );
2565 wp_set_object_terms( $property_post_id, wp_get_object_terms( $post_id, 'parking', array("fields" => "ids") ), 'parking' );
2566 wp_set_object_terms( $property_post_id, wp_get_object_terms( $post_id, 'outside_space', array("fields" => "ids") ), 'outside_space' );
2567
2568 $owner_contact_ids = get_post_meta( $post_id, '_property_owner_contact_id', TRUE );
2569 if ( !is_array($owner_contact_ids) )
2570 {
2571 $owner_contact_ids = array($owner_contact_ids);
2572 }
2573 update_post_meta( $property_post_id, '_owner_contact_id', $owner_contact_ids );
2574
2575 // Make updates to appraisal
2576 update_post_meta( $post_id, '_status', 'instructed' );
2577 update_post_meta( $post_id, '_property_id', $property_post_id );
2578
2579 //Update owner(s)
2580 foreach ( $owner_contact_ids as $owner_contact_id )
2581 {
2582 $contact_types = get_post_meta( $owner_contact_id, '_contact_types', TRUE );
2583
2584 if ( !in_array('owner', $contact_types) )
2585 {
2586 $contact_types[] = 'owner';
2587 }
2588
2589 // get appraisals where this is the owner and where not instructed
2590 $args = array(
2591 'post_type' => 'appraisal',
2592 'nopaging' => true,
2593 'meta_query' => array(
2594 array(
2595 'key' => '_property_owner_contact_id',
2596 'value' => $post->ID,
2597 'compare' => '='
2598 ),
2599 array(
2600 'key' => '_status',
2601 'value' => 'instructed',
2602 'compare' => '!='
2603 )
2604 )
2605 );
2606
2607 $appraisal_query = new WP_Query($args);
2608
2609 if (!$appraisal_query->have_posts())
2610 {
2611 // no longer a potential owner.
2612 if (($key = array_search('potentialowner', $contact_types)) !== false)
2613 {
2614 unset($contact_types[$key]);
2615 }
2616 }
2617 wp_reset_postdata();
2618
2619 update_post_meta( $owner_contact_id, '_contact_types', $contact_types );
2620 }
2621
2622 $current_user = wp_get_current_user();
2623
2624 // Add note/comment to appraisal
2625 $comment = array(
2626 'note_type' => 'action',
2627 'action' => 'appraisal_instructed',
2628 );
2629
2630 $data = array(
2631 'comment_post_ID' => $post_id,
2632 'comment_author' => $current_user->display_name,
2633 'comment_author_email' => 'propertyhive@noreply.com',
2634 'comment_author_url' => '',
2635 'comment_date' => date("Y-m-d H:i:s"),
2636 'comment_content' => serialize($comment),
2637 'comment_approved' => 1,
2638 'comment_type' => 'propertyhive_note',
2639 );
2640 $comment_id = wp_insert_comment( $data );
2641 }
2642 }
2643
2644 die();
2645 }
2646
2647 public function appraisal_revert_pending()
2648 {
2649 check_ajax_referer( 'appraisal-actions', 'security' );
2650
2651 $post_id = (int)$_POST['appraisal_id'];
2652
2653 $status = get_post_meta( $post_id, '_status', TRUE );
2654
2655 if ( $status == 'carried_out' || $status == 'cancelled' )
2656 {
2657 update_post_meta( $post_id, '_status', 'pending' );
2658
2659 $current_user = wp_get_current_user();
2660
2661 // Add note/comment to appraisal
2662 $comment = array(
2663 'note_type' => 'action',
2664 'action' => 'appraisal_revert_pending',
2665 );
2666
2667 $data = array(
2668 'comment_post_ID' => $post_id,
2669 'comment_author' => $current_user->display_name,
2670 'comment_author_email' => 'propertyhive@noreply.com',
2671 'comment_author_url' => '',
2672 'comment_date' => date("Y-m-d H:i:s"),
2673 'comment_content' => serialize($comment),
2674 'comment_approved' => 1,
2675 'comment_type' => 'propertyhive_note',
2676 );
2677 $comment_id = wp_insert_comment( $data );
2678 }
2679
2680 die();
2681 }
2682
2683 public function appraisal_revert_carried_out()
2684 {
2685 check_ajax_referer( 'appraisal-actions', 'security' );
2686
2687 $post_id = (int)$_POST['appraisal_id'];
2688
2689 $status = get_post_meta( $post_id, '_status', TRUE );
2690
2691 if ( $status == 'won' || $status == 'lost' )
2692 {
2693 update_post_meta( $post_id, '_status', 'carried_out' );
2694
2695 $current_user = wp_get_current_user();
2696
2697 // Add note/comment to appraisal
2698 $comment = array(
2699 'note_type' => 'action',
2700 'action' => 'appraisal_revert_carried_out',
2701 );
2702
2703 $data = array(
2704 'comment_post_ID' => $post_id,
2705 'comment_author' => $current_user->display_name,
2706 'comment_author_email' => 'propertyhive@noreply.com',
2707 'comment_author_url' => '',
2708 'comment_date' => date("Y-m-d H:i:s"),
2709 'comment_content' => serialize($comment),
2710 'comment_approved' => 1,
2711 'comment_type' => 'propertyhive_note',
2712 );
2713 $comment_id = wp_insert_comment( $data );
2714 }
2715
2716 die();
2717 }
2718
2719 public function appraisal_revert_won()
2720 {
2721 check_ajax_referer( 'appraisal-actions', 'security' );
2722
2723 $post_id = (int)$_POST['appraisal_id'];
2724
2725 $status = get_post_meta( $post_id, '_status', TRUE );
2726
2727 if ( $status == 'instructed' )
2728 {
2729 update_post_meta( $post_id, '_status', 'won' );
2730
2731 $current_user = wp_get_current_user();
2732
2733 // Add note/comment to appraisal
2734 $comment = array(
2735 'note_type' => 'action',
2736 'action' => 'appraisal_revert_won',
2737 );
2738
2739 $data = array(
2740 'comment_post_ID' => $post_id,
2741 'comment_author' => $current_user->display_name,
2742 'comment_author_email' => 'propertyhive@noreply.com',
2743 'comment_author_url' => '',
2744 'comment_date' => date("Y-m-d H:i:s"),
2745 'comment_content' => serialize($comment),
2746 'comment_approved' => 1,
2747 'comment_type' => 'propertyhive_note',
2748 );
2749 $comment_id = wp_insert_comment( $data );
2750 }
2751
2752 die();
2753 }
2754
2755 // Viewing related functions
2756 public function book_viewing_property()
2757 {
2758 check_ajax_referer( 'book-viewing', 'security' );
2759
2760 $this->json_headers();
2761
2762 // TO DO: Should do validation on server side also
2763 if (empty($_POST['property_id']))
2764 {
2765 $return = array('error' => 'No property selected');
2766 echo json_encode( $return );
2767 die();
2768 }
2769
2770 $property = new PH_Property((int)$_POST['property_id']);
2771
2772 $applicant_contact_ids = array();
2773
2774 // Create applicant record if required
2775 if (empty($_POST['applicant_ids']) && !empty($_POST['applicant_name']))
2776 {
2777 // Need to create contact/applicant
2778 $contact_post = array(
2779 'post_title' => ph_clean($_POST['applicant_name']),
2780 'post_content' => '',
2781 'post_type' => 'contact',
2782 'post_status' => 'publish',
2783 'comment_status' => 'closed',
2784 'ping_status' => 'closed',
2785 );
2786
2787 // Insert the post into the database
2788 $contact_post_id = wp_insert_post( $contact_post );
2789
2790 if ( is_wp_error($contact_post_id) || $contact_post_id == 0 )
2791 {
2792 $return = array('error' => 'Failed to create contact post. Please try again');
2793 echo json_encode( $return );
2794 die();
2795 }
2796
2797 update_post_meta( $contact_post_id, '_contact_types', array('applicant') );
2798
2799 update_post_meta( $contact_post_id, '_applicant_profiles', 1 );
2800 update_post_meta( $contact_post_id, '_applicant_profile_0', array( 'department' => $property->department, 'send_matching_properties' => '' ) );
2801
2802 $applicant_contact_ids[] = $contact_post_id;
2803 }
2804
2805 if (!empty($_POST['applicant_ids']) && empty($_POST['applicant_name']))
2806 {
2807 // This is an existing contact
2808 if ( !is_array($_POST['applicant_ids']) )
2809 {
2810 $_POST['applicant_ids'] = array(ph_clean($_POST['applicant_ids']));
2811 }
2812
2813 foreach ( $_POST['applicant_ids'] as $applicant_id )
2814 {
2815 $applicant_contact_ids[] = (int)$applicant_id;
2816 }
2817 }
2818
2819 $applicant_contact_ids = array_unique($applicant_contact_ids);
2820
2821 if ( empty($applicant_contact_ids) )
2822 {
2823 $return = array('error' => 'No applicant selected, or unable to create applicant record');
2824 echo json_encode( $return );
2825 die();
2826 }
2827
2828 // Make sure each of the contacts has an applicant profile of the correct department
2829 /*foreach ( $applicant_contact_ids as $applicant_contact_id )
2830 {
2831 $has_correct_profile = false;
2832
2833 // Get all existing profiles
2834 $existing_contact_types = get_post_meta( $applicant_contact_id, '_contact_types', TRUE );
2835 if ( $existing_contact_types == '' || !is_array($existing_contact_types) )
2836 {
2837 $existing_contact_types = array();
2838 }
2839 if ( in_array( 'applicant', $existing_contact_types ) )
2840 {
2841 $num_applicant_profiles = get_post_meta( $applicant_contact_id, '_applicant_profiles', TRUE );
2842 if ( $num_applicant_profiles == '' )
2843 {
2844 $num_applicant_profiles = 0;
2845 }
2846
2847 if ( $num_applicant_profiles > 0 )
2848 {
2849 for ( $i = 0; $i < $num_applicant_profiles; ++$i )
2850 {
2851 $applicant_profile = get_post_meta( $applicant_contact_id, '_applicant_profile_' . $i, TRUE );
2852 if ( $applicant_profile['department'] == $property->department )
2853 {
2854 $has_correct_profile = true;
2855 }
2856 }
2857 }
2858 }
2859
2860 if ( !$has_correct_profile )
2861 {
2862 if ( in_array( 'applicant', $existing_contact_types ) )
2863 {
2864 // Already an applicant. Just need to add profile
2865 }
2866 else
2867 {
2868 $existing_contact_types[] = 'applicant';
2869 update_post_meta( $applicant_contact_id, '_contact_types', $existing_contact_types );
2870 }
2871
2872 $num_applicant_profiles = get_post_meta( $applicant_contact_id, '_applicant_profiles', TRUE );
2873 if ( $num_applicant_profiles == '' )
2874 {
2875 $num_applicant_profiles = 0;
2876 }
2877
2878 update_post_meta( $applicant_contact_id, '_applicant_profiles', $num_applicant_profiles + 1 );
2879 update_post_meta( $applicant_contact_id, '_applicant_profile_' . $num_applicant_profiles, array( 'department' => $property->department ) );
2880 }
2881 }*/
2882
2883 // Loop through contacts and create one viewing each
2884 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
2885 foreach ( $applicant_contact_ids as $applicant_contact_id )
2886 {
2887 // Insert viewing record
2888 $viewing_post = array(
2889 'post_title' => '',
2890 'post_content' => '',
2891 'post_type' => 'viewing',
2892 'post_status' => 'publish',
2893 'comment_status' => 'closed',
2894 'ping_status' => 'closed',
2895 );
2896
2897 // Insert the post into the database
2898 $viewing_post_id = wp_insert_post( $viewing_post );
2899
2900 if ( is_wp_error($viewing_post_id) || $viewing_post_id == 0 )
2901 {
2902 $return = array('error' => 'Failed to create viewing post. Please try again');
2903 echo json_encode( $return );
2904 die();
2905 }
2906
2907 add_post_meta( $viewing_post_id, '_start_date_time', ph_clean($_POST['start_date']) . ' ' . ph_clean($_POST['start_time']) );
2908 add_post_meta( $viewing_post_id, '_duration', 30 * 60 ); // Stored in seconds. Default to 30 mins
2909 add_post_meta( $viewing_post_id, '_property_id', (int)$_POST['property_id'] );
2910 add_post_meta( $viewing_post_id, '_applicant_contact_id', $applicant_contact_id );
2911 add_post_meta( $viewing_post_id, '_status', 'pending' );
2912 add_post_meta( $viewing_post_id, '_feedback_status', '' );
2913 add_post_meta( $viewing_post_id, '_feedback', '' );
2914 add_post_meta( $viewing_post_id, '_feedback_passed_on', '' );
2915
2916 if ( !empty($_POST['negotiator_ids']) )
2917 {
2918 foreach ( $_POST['negotiator_ids'] as $negotiator_id )
2919 {
2920 add_post_meta( $viewing_post_id, '_negotiator_id', (int)$negotiator_id );
2921 }
2922 }
2923 }
2924
2925 $applicant_contacts = array();
2926 foreach ( $applicant_contact_ids as $applicant_contact_id )
2927 {
2928 $applicant_contacts[] = array(
2929 'ID' => $applicant_contact_id,
2930 'post_title' => get_the_title($applicant_contact_id),
2931 'edit_link' => get_edit_post_link( $applicant_contact_id, '' ),
2932 );
2933 }
2934
2935 $return = array('success' => array(
2936 'viewing' => array(
2937 'ID' => $viewing_post_id,
2938 'edit_link' => get_edit_post_link( $viewing_post_id, '' ),
2939 ),
2940 'applicant_contacts' => $applicant_contacts,
2941 ));
2942
2943 echo json_encode( $return );
2944
2945 die();
2946 }
2947
2948 public function book_viewing_contact()
2949 {
2950 check_ajax_referer( 'book-viewing', 'security' );
2951
2952 $this->json_headers();
2953
2954 // TO DO: Should do validation on server side also
2955 if (empty($_POST['contact_id']))
2956 {
2957 $return = array('error' => 'No contact selected');
2958 echo json_encode( $return );
2959 die();
2960 }
2961
2962 if (empty($_POST['property_ids']))
2963 {
2964 $return = array('error' => 'No property selected');
2965 echo json_encode( $return );
2966 die();
2967 }
2968
2969 // Loop through contacts and create one viewing each
2970 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
2971 foreach ( $_POST['property_ids'] as $property_id )
2972 {
2973 // Insert viewing record
2974 $viewing_post = array(
2975 'post_title' => '',
2976 'post_content' => '',
2977 'post_type' => 'viewing',
2978 'post_status' => 'publish',
2979 'comment_status' => 'closed',
2980 'ping_status' => 'closed',
2981 );
2982
2983 // Insert the post into the database
2984 $viewing_post_id = wp_insert_post( $viewing_post );
2985
2986 if ( is_wp_error($viewing_post_id) || $viewing_post_id == 0 )
2987 {
2988 $return = array('error' => 'Failed to create viewing post. Please try again');
2989 echo json_encode( $return );
2990 die();
2991 }
2992
2993 add_post_meta( $viewing_post_id, '_start_date_time', ph_clean($_POST['start_date']) . ' ' . ph_clean($_POST['start_time']) );
2994 add_post_meta( $viewing_post_id, '_duration', 30 * 60 ); // Stored in seconds. Default to 30 mins
2995 add_post_meta( $viewing_post_id, '_property_id', (int)$property_id );
2996 add_post_meta( $viewing_post_id, '_applicant_contact_id', (int)$_POST['contact_id'] );
2997 add_post_meta( $viewing_post_id, '_status', 'pending' );
2998 add_post_meta( $viewing_post_id, '_feedback_status', '' );
2999 add_post_meta( $viewing_post_id, '_feedback', '' );
3000 add_post_meta( $viewing_post_id, '_feedback_passed_on', '' );
3001
3002 if ( !empty($_POST['negotiator_ids']) )
3003 {
3004 foreach ( $_POST['negotiator_ids'] as $negotiator_id )
3005 {
3006 add_post_meta( $viewing_post_id, '_negotiator_id', (int)$negotiator_id );
3007 }
3008 }
3009 }
3010
3011 $properties = array();
3012 foreach ( $_POST['property_ids'] as $property_id )
3013 {
3014 $properties[] = array(
3015 'ID' => (int)$property_id,
3016 'post_title' => get_the_title((int)$property_id),
3017 'edit_link' => get_edit_post_link( (int)$property_id, '' ),
3018 );
3019 }
3020
3021 $return = array('success' => array(
3022 'viewing' => array(
3023 'ID' => $viewing_post_id,
3024 'edit_link' => get_edit_post_link( $viewing_post_id, '' ),
3025 ),
3026 'properties' => $properties,
3027 ));
3028
3029 echo json_encode( $return );
3030
3031 die();
3032 }
3033
3034 public function get_viewing_details_meta_box()
3035 {
3036 global $post;
3037
3038 check_ajax_referer( 'viewing-details-meta-box', 'security' );
3039
3040 $post = get_post((int)$_POST['viewing_id']);
3041
3042 $viewing = new PH_Viewing((int)$_POST['viewing_id']);
3043
3044 echo '<div class="propertyhive_meta_box">';
3045
3046 echo '<div class="options_group">';
3047
3048 echo '<p class="form-field">
3049
3050 <label for="">' . __('Status', 'propertyhive') . '</label>
3051
3052 ' . ucwords(str_replace("_", " ", $viewing->status));
3053
3054 if ( $viewing->status == 'offer_made' )
3055 {
3056 if ( get_option('propertyhive_module_disabled_offers_sales', '') != 'yes' )
3057 {
3058 $offer_id = get_post_meta( $viewing->id, '_offer_id', TRUE );
3059 if ( $offer_id != '' && get_post_status($offer_id) != 'publish' )
3060 {
3061 $offer_id = '';
3062 }
3063
3064 if ( $offer_id != '' )
3065 {
3066 echo ' (<a href="' . get_edit_post_link($offer_id) . '">' . __('View Offer', 'propertyhive') . '</a>)';
3067 }
3068 }
3069 }
3070
3071 echo '</p>';
3072
3073 if ( $viewing->status == 'cancelled' )
3074 {
3075 $args = array(
3076 'id' => '_cancelled_reason',
3077 'label' => __( 'Reason Cancelled', 'propertyhive' ),
3078 'desc_tip' => false,
3079 'class' => '',
3080 'value' => $viewing->cancelled_reason,
3081 'custom_attributes' => array(
3082 'style' => 'width:95%; max-width:500px;'
3083 )
3084 );
3085 propertyhive_wp_textarea_input( $args );
3086 }
3087
3088 if ( $viewing->status == 'carried_out' )
3089 {
3090 echo '<p class="form-field">
3091
3092 <label for="">' . __('Applicant Feedback', 'propertyhive') . '</label>';
3093
3094 switch ( $viewing->feedback_status )
3095 {
3096 case "interested":
3097 {
3098 echo 'Interested';
3099 break;
3100 }
3101 case "not_interested":
3102 {
3103 echo 'Not Interested';
3104 break;
3105 }
3106 case "not_required":
3107 {
3108 echo 'Feedback Not Required';
3109 break;
3110 }
3111 default:
3112 {
3113 echo 'Awaiting Feedback';
3114 }
3115 }
3116
3117 echo '</p>';
3118
3119 if ( $viewing->feedback_status == 'interested' || $viewing->feedback_status == 'not_interested' )
3120 {
3121 $args = array(
3122 'id' => '_feedback',
3123 'label' => __( 'Feedback', 'propertyhive' ),
3124 'desc_tip' => false,
3125 'class' => '',
3126 'value' => $viewing->feedback,
3127 'custom_attributes' => array(
3128 'style' => 'width:95%; max-width:500px;'
3129 )
3130 );
3131 propertyhive_wp_textarea_input( $args );
3132 }
3133 }
3134
3135 if ( $viewing->status == 'carried_out' && ( $viewing->feedback_status == 'interested' || $viewing->feedback_status == 'not_interested' ) )
3136 {
3137 echo '<p class="form-field">
3138
3139 <label for="">' . __('Feedback Passed On', 'propertyhive') . '</label>';
3140
3141 echo ( ($viewing->feedback_passed_on == 'yes') ? 'Yes' : 'No' );
3142
3143 echo '</p>';
3144 }
3145
3146 do_action('propertyhive_viewing_details_fields');
3147
3148 echo '</div>';
3149
3150 echo '</div>';
3151
3152 die();
3153 }
3154
3155 public function get_viewing_actions()
3156 {
3157 check_ajax_referer( 'viewing-actions', 'security' );
3158
3159 $post_id = (int)$_POST['viewing_id'];
3160
3161 $status = get_post_meta( $post_id, '_status', TRUE );
3162 $feedback_status = get_post_meta( $post_id, '_feedback_status', TRUE );
3163
3164 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_viewing_actions_meta_box">
3165
3166 <div class="options_group" style="padding-top:8px;">';
3167
3168 $show_cancelled_meta_boxes = false;
3169 $show_feedback_meta_boxes = false;
3170
3171 $actions = array();
3172
3173 if ( $status == 'pending' )
3174 {
3175 $applicant_contact_id = get_post_meta( $post_id, '_applicant_contact_id', TRUE );
3176 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3177 $applicant_email_address = get_post_meta( $applicant_contact_id, '_email_address', TRUE );
3178
3179 if ( (int)$applicant_contact_id == '' || (int)$property_id == '' || (int)$applicant_contact_id == 0 || (int)$property_id == 0 || sanitize_email($applicant_email_address) == '' )
3180 {
3181
3182 }
3183 else
3184 {
3185 $applicant_booking_confirmation_sent_at = get_post_meta( $post_id, '_applicant_booking_confirmation_sent_at', TRUE );
3186 $owner_booking_confirmation_sent_at = get_post_meta( $post_id, '_owner_booking_confirmation_sent_at', TRUE );
3187
3188 //Applicant
3189 $actions[] = '<a
3190 href="#action_panel_viewing_email_applicant_booking_confirmation"
3191 class="button viewing-action"
3192 style="width:100%; margin-bottom:7px; text-align:center"
3193 >' . ( ( $applicant_booking_confirmation_sent_at == '' ) ? __('Email Applicant Booking Confirmation', 'propertyhive') : __('Re-Email Applicant Booking Confirmation', 'propertyhive') ) . '</a>';
3194
3195 $actions[] = '<div id="viewing_applicant_confirmation_date" style="text-align:center; font-size:12px; color:#999; margin-bottom:7px;' . ( ( $applicant_booking_confirmation_sent_at == '' ) ? 'display:none' : '' ) . '">' . ( ( $applicant_booking_confirmation_sent_at != '' ) ? 'Previously sent to applicant on <span title="' . $applicant_booking_confirmation_sent_at . '">' . date("jS F", strtotime($applicant_booking_confirmation_sent_at)) : '' ) . '</span></div>';
3196
3197 // Owner/Landlord
3198 $property_department = get_post_meta( $property_id, '_department', TRUE );
3199 $owner_contact_ids = get_post_meta( $property_id, '_owner_contact_id', TRUE );
3200 $owner_or_landlord = ( $property_department == 'residential-lettings' ? 'Landlord' : 'Owner' );
3201
3202 if ( count($owner_contact_ids) > 0) {
3203
3204 $actions[] = '<a
3205 href="#action_panel_viewing_email_owner_booking_confirmation"
3206 class="button viewing-action"
3207 style="width:100%; margin-bottom:7px; text-align:center"
3208 >' . ( ( $owner_booking_confirmation_sent_at == '' ) ? __('Email ' . $owner_or_landlord . ' Booking Confirmation', 'propertyhive') : __('Re-Email ' . $owner_or_landlord . ' Booking Confirmation', 'propertyhive') ) . '</a>';
3209
3210 $actions[] = '<div id="viewing_owner_confirmation_date" style="text-align:center; font-size:12px; color:#999; margin-bottom:7px;' . ( ( $owner_booking_confirmation_sent_at == '' ) ? 'display:none' : '' ) . '">' . ( ( $owner_booking_confirmation_sent_at != '' ) ? 'Previously sent to ' . strtolower($owner_or_landlord) . ' on <span title="' . $owner_booking_confirmation_sent_at . '">' . date("jS F", strtotime($owner_booking_confirmation_sent_at)) : '' ) . '</span></div>';
3211 }
3212
3213 $actions[] = '<hr>';
3214 }
3215
3216 $actions[] = '<a
3217 href="#action_panel_viewing_carried_out"
3218 class="button button-success viewing-action"
3219 style="width:100%; margin-bottom:7px; text-align:center"
3220 >' . __('Viewing Carried Out', 'propertyhive') . '</a>';
3221 $actions[] = '<a
3222 href="#action_panel_viewing_cancelled"
3223 class="button viewing-action"
3224 style="width:100%; margin-bottom:7px; text-align:center"
3225 >' . __('Viewing Cancelled', 'propertyhive') . '</a>';
3226
3227 $show_cancelled_meta_boxes = true;
3228 }
3229
3230 if ( $status == 'carried_out' )
3231 {
3232 if ( $feedback_status == '' )
3233 {
3234 $actions[] = '<a
3235 href="#action_panel_viewing_interested"
3236 class="button button-success viewing-action"
3237 style="width:100%; margin-bottom:7px; text-align:center"
3238 >' . wp_kses_post( __('Applicant Interested', 'propertyhive') ) . '</a>';
3239
3240 $actions[] = '<a
3241 href="#action_panel_viewing_not_interested"
3242 class="button button-danger viewing-action"
3243 style="width:100%; margin-bottom:7px; text-align:center"
3244 >' . wp_kses_post( __('Applicant Not Interested', 'propertyhive') ) . '</a>';
3245
3246 $actions[] = '<a
3247 href="#action_panel_viewing_feedback_not_required"
3248 class="button viewing-action"
3249 style="width:100%; margin-bottom:7px; text-align:center"
3250 >' . wp_kses_post( __('Feedback Not Required', 'propertyhive') ) . '</a>';
3251
3252 $show_feedback_meta_boxes = true;
3253 }
3254
3255 if ( $feedback_status == 'interested' )
3256 {
3257 $actions[] = '<a
3258 href="' . trim(admin_url(), '/') . '/post-new.php?post_type=viewing&applicant_contact_id=' . get_post_meta( $post_id, '_applicant_contact_id', TRUE ) . '&property_id=' . get_post_meta( $post_id, '_property_id', TRUE ) . '&viewing_id=' . $post_id .'"
3259 class="button button-success"
3260 style="width:100%; margin-bottom:7px; text-align:center"
3261 >' . wp_kses_post( __('Book Second Viewing', 'propertyhive') ) . '</a>';
3262
3263 if ( get_option('propertyhive_module_disabled_offers_sales', '') != 'yes' )
3264 {
3265 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3266 if ( get_post_meta( $property_id, '_department', TRUE ) == 'residential-sales' )
3267 {
3268 // See if an offer has this viewing id associated with it
3269 $offer_id = get_post_meta( $post_id, '_offer_id', TRUE );
3270 if ( $offer_id != '' && get_post_status($offer_id) != 'publish' )
3271 {
3272 $offer_id = '';
3273 }
3274
3275 if ( $offer_id != '' )
3276 {
3277 $actions[] = '<a
3278 href="' . get_edit_post_link( $offer_id, '' ) . '"
3279 class="button"
3280 style="width:100%; margin-bottom:7px; text-align:center"
3281 >' . wp_kses_post( __('View Offer', 'propertyhive') ) . '</a>';
3282 }
3283 else
3284 {
3285 $actions[] = '<a
3286 href="' . wp_nonce_url( admin_url( 'post.php?post=' . $post_id . '&action=edit' ), '1', 'create_offer' ) . '"
3287 class="button button-success"
3288 style="width:100%; margin-bottom:7px; text-align:center"
3289 >' . wp_kses_post( __('Record Offer', 'propertyhive') ) . '</a>';
3290 }
3291 }
3292 }
3293 }
3294
3295 if ( get_post_meta( $post_id, '_feedback_passed_on', TRUE ) != 'yes' && ( $feedback_status == 'interested' || $feedback_status == 'not_interested' ) )
3296 {
3297 $actions[] = '<a
3298 href="#action_panel_viewing_revert_feedback_passed_on"
3299 class="button viewing-action"
3300 style="width:100%; margin-bottom:7px; text-align:center"
3301 >' . wp_kses_post( __('Feedback Passed On To Owner', 'propertyhive') ) . '</a>';
3302 }
3303
3304 if ( $feedback_status == 'interested' || $feedback_status == 'not_interested' || $feedback_status == 'not_required' )
3305 {
3306 $actions[] = '<a
3307 href="#action_panel_viewing_revert_feedback_pending"
3308 class="button viewing-action"
3309 style="width:100%; margin-bottom:7px; text-align:center"
3310 >' . wp_kses_post( __('Revert To Feedback Pending', 'propertyhive') ) . '</a>';
3311 }
3312 }
3313
3314 if ( $status == 'offer_made' )
3315 {
3316 if ( get_option('propertyhive_module_disabled_offers_sales', '') != 'yes' )
3317 {
3318 $offer_id = get_post_meta( $post_id, '_offer_id', TRUE );
3319 if ( $offer_id != '' && get_post_status($offer_id) != 'publish' )
3320 {
3321 $offer_id = '';
3322 }
3323
3324 if ( $offer_id != '' )
3325 {
3326 $actions[] = '<a
3327 href="' . get_edit_post_link( $offer_id, '' ) . '"
3328 class="button"
3329 style="width:100%; margin-bottom:7px; text-align:center"
3330 >' . wp_kses_post( __('View Offer', 'propertyhive') ) . '</a>';
3331 }
3332 }
3333 }
3334
3335 if ( ( $status == 'carried_out' && $feedback_status == '' ) || $status == 'cancelled' )
3336 {
3337 $actions[] = '<a
3338 href="#action_panel_viewing_revert_pending"
3339 class="button viewing-action"
3340 style="width:100%; margin-bottom:7px; text-align:center"
3341 >' . wp_kses_post( __('Revert To Pending', 'propertyhive') ) . '</a>';
3342 }
3343
3344 $actions = apply_filters( 'propertyhive_admin_viewing_actions', $actions, $post_id );
3345
3346 if ( !empty($actions) )
3347 {
3348 echo implode("", $actions);
3349 }
3350 else
3351 {
3352 echo '<div style="text-align:center">' . wp_kses_post( __( 'No actions to display', 'propertyhive' ) ) . '</div>';
3353 }
3354
3355 echo '</div>
3356
3357 </div>';
3358
3359 if ( $show_cancelled_meta_boxes )
3360 {
3361 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_viewing_cancelled" style="display:none;">
3362
3363 <div class="options_group" style="padding-top:8px;">
3364
3365 <div class="form-field">
3366
3367 <label for="_viewing_cancelled_reason">' . __( 'Reason Cancelled', 'propertyhive' ) . '</label>
3368
3369 <textarea id="_cancelled_reason" name="_cancelled_reason" style="width:100%;">' . get_post_meta( $post_id, '_cancelled_reason', TRUE ) . '</textarea>
3370
3371 </div>
3372
3373 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
3374 <a class="button button-primary cancelled-reason-action-submit" href="#">' . __( 'Save', 'propertyhive' ) . '</a>
3375
3376 </div>
3377
3378 </div>';
3379 }
3380
3381 if ( $show_feedback_meta_boxes )
3382 {
3383 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_viewing_interested" style="display:none;">
3384
3385 <div class="options_group" style="padding-top:8px;">
3386
3387 <div class="form-field">
3388
3389 <label for="_viewing_interested_feedback">' . __( 'Applicant Feedback', 'propertyhive' ) . '</label>
3390
3391 <textarea id="_interested_feedback" name="_interested_feedback" style="width:100%;">' . get_post_meta( $post_id, '_feedback', TRUE ) . '</textarea>
3392
3393 </div>
3394
3395 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
3396 <a class="button button-primary interested-feedback-action-submit" href="#">' . wp_kses_post( __( 'Save Feedback', 'propertyhive' ) ) . '</a>
3397
3398 </div>
3399
3400 </div>';
3401
3402 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_viewing_not_interested" style="display:none;">
3403
3404 <div class="options_group" style="padding-top:8px;">
3405
3406 <div class="form-field">
3407
3408 <label for="_viewing_not_interested_feedback">' . __( 'Applicant Feedback', 'propertyhive' ) . '</label>
3409
3410 <textarea id="_not_interested_feedback" name="_not_interested_feedback" style="width:100%;">' . get_post_meta( $post_id, '_feedback', TRUE ) . '</textarea>
3411
3412 </div>
3413
3414 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
3415 <a class="button button-primary not-interested-feedback-action-submit" href="#">' . wp_kses_post( __( 'Save Feedback', 'propertyhive' ) ) . '</a>
3416
3417 </div>
3418
3419 </div>';
3420 }
3421
3422 die();
3423 }
3424
3425 public function viewing_carried_out()
3426 {
3427 check_ajax_referer( 'viewing-actions', 'security' );
3428
3429 $post_id = (int)$_POST['viewing_id'];
3430
3431 $status = get_post_meta( $post_id, '_status', TRUE );
3432
3433 if ( $status == 'pending' )
3434 {
3435 update_post_meta( $post_id, '_status', 'carried_out' );
3436
3437 $current_user = wp_get_current_user();
3438
3439 // Add note/comment to viewing
3440 $comment = array(
3441 'note_type' => 'action',
3442 'action' => 'viewing_carried_out',
3443 );
3444
3445 $data = array(
3446 'comment_post_ID' => $post_id,
3447 'comment_author' => $current_user->display_name,
3448 'comment_author_email' => 'propertyhive@noreply.com',
3449 'comment_author_url' => '',
3450 'comment_date' => date("Y-m-d H:i:s"),
3451 'comment_content' => serialize($comment),
3452 'comment_approved' => 1,
3453 'comment_type' => 'propertyhive_note',
3454 );
3455 $comment_id = wp_insert_comment( $data );
3456 }
3457
3458 die();
3459 }
3460
3461 public function viewing_cancelled()
3462 {
3463 check_ajax_referer( 'viewing-actions', 'security' );
3464
3465 $post_id = (int)$_POST['viewing_id'];
3466
3467 $status = get_post_meta( $post_id, '_status', TRUE );
3468
3469 if ( $status == 'pending' )
3470 {
3471 update_post_meta( $post_id, '_status', 'cancelled' );
3472 update_post_meta( $post_id, '_cancelled_reason', sanitize_textarea_field( $_POST['cancelled_reason'] ) );
3473
3474 $current_user = wp_get_current_user();
3475
3476 // Add note/comment to viewing
3477 $comment = array(
3478 'note_type' => 'action',
3479 'action' => 'viewing_cancelled',
3480 );
3481
3482 $data = array(
3483 'comment_post_ID' => $post_id,
3484 'comment_author' => $current_user->display_name,
3485 'comment_author_email' => 'propertyhive@noreply.com',
3486 'comment_author_url' => '',
3487 'comment_date' => date("Y-m-d H:i:s"),
3488 'comment_content' => serialize($comment),
3489 'comment_approved' => 1,
3490 'comment_type' => 'propertyhive_note',
3491 );
3492 $comment_id = wp_insert_comment( $data );
3493 }
3494
3495 die();
3496 }
3497
3498 public function viewing_email_applicant_booking_confirmation()
3499 {
3500 check_ajax_referer( 'viewing-actions', 'security' );
3501
3502 $post_id = (int)$_POST['viewing_id'];
3503
3504 $applicant_contact_id = get_post_meta( $post_id, '_applicant_contact_id', TRUE );
3505 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3506
3507 if ( (int)$applicant_contact_id == '' || (int)$property_id == '' || (int)$applicant_contact_id == 0 || (int)$property_id == 0 )
3508 {
3509 die();
3510 }
3511
3512 $property = new PH_Property((int)$property_id);
3513
3514 $to = get_post_meta( $applicant_contact_id, '_email_address', TRUE );
3515
3516 if ( sanitize_email($to) != '' )
3517 {
3518 $subject = get_option( 'propertyhive_viewing_applicant_booking_confirmation_email_subject', '' );
3519 $body = get_option( 'propertyhive_viewing_applicant_booking_confirmation_email_body', '' );
3520
3521 $subject = str_replace('[property_address]', $property->get_formatted_full_address(), $subject);
3522 $subject = str_replace('[applicant_name]', get_the_title($applicant_contact_id), $subject);
3523 $subject = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3524 $subject = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3525
3526 $body = str_replace('[property_address]', $property->get_formatted_full_address(), $body);
3527 $body = str_replace('[applicant_name]', get_the_title($applicant_contact_id), $body);
3528 $body = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3529 $body = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3530
3531 $from = $property->office_email_address;
3532 if ( sanitize_email($from) == '' )
3533 {
3534 $from = get_bloginfo('admin_email');
3535 }
3536
3537 $headers = array();
3538 $headers[] = 'From: ' . get_bloginfo('name') . ' <' . $from . '>';
3539 $headers[] = 'Content-Type: text/plain; charset=UTF-8';
3540
3541 wp_mail($to, $subject, $body, $headers);
3542
3543 update_post_meta( $post_id, '_applicant_booking_confirmation_sent_at', date("Y-m-d H:i:s") );
3544 }
3545
3546 die();
3547 }
3548
3549 public function viewing_email_owner_booking_confirmation()
3550 {
3551 check_ajax_referer( 'viewing-actions', 'security' );
3552
3553 $post_id = (int)$_POST['viewing_id'];
3554
3555 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3556 $property_department = get_post_meta( $property_id, '_department' );
3557
3558 $applicant_contact_id = get_post_meta( $post_id, '_applicant_contact_id', TRUE );
3559 $owner_contact_ids = get_post_meta( $property_id, '_owner_contact_id', TRUE );
3560
3561 if ( $owner_contact_ids > 0 ) {
3562
3563 $owner_emails = array();
3564 $owner_names = array();
3565
3566 foreach ($owner_contact_ids as $owner_id)
3567 {
3568 $owner_email = sanitize_email( get_post_meta($owner_id, '_email_address', TRUE) );
3569 $owner_name = get_the_title($owner_id);
3570
3571 if( ! empty($owner_email) ) array_push($owner_emails, $owner_email);
3572 if( ! empty($owner_name) ) array_push($owner_names, $owner_name);
3573 }
3574
3575 $property = new PH_Property((int)$property_id);
3576
3577 $to = implode(",", $owner_emails);
3578
3579 $subject = get_option( 'propertyhive_viewing_owner_booking_confirmation_email_subject', '' );
3580 $body = get_option( 'propertyhive_viewing_owner_booking_confirmation_email_body', '' );
3581
3582 $subject = str_replace('[property_address]', $property->get_formatted_full_address(), $subject);
3583 $subject = str_replace('[owner_name]', implode(", ", $owner_names), $subject);
3584 $subject = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3585 $subject = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3586
3587 $body = str_replace('[property_address]', $property->get_formatted_full_address(), $body);
3588 $body = str_replace('[owner_name]', implode(", ", $owner_names), $body);
3589 $body = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3590 $body = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3591
3592 $from = $property->office_email_address;
3593 if ( sanitize_email($from) == '' )
3594 {
3595 $from = get_bloginfo('admin_email');
3596 }
3597
3598 $headers = array();
3599 $headers[] = 'From: ' . get_bloginfo('name') . ' <' . $from . '>';
3600 $headers[] = 'Content-Type: text/plain; charset=UTF-8';
3601
3602 wp_mail($to, $subject, $body, $headers);
3603
3604 update_post_meta( $post_id, '_owner_booking_confirmation_sent_at', date("Y-m-d H:i:s") );
3605
3606 }
3607
3608 die();
3609 }
3610
3611 public function viewing_interested_feedback()
3612 {
3613 check_ajax_referer( 'viewing-actions', 'security' );
3614
3615 $post_id = (int)$_POST['viewing_id'];
3616
3617 $status = get_post_meta( $post_id, '_status', TRUE );
3618
3619 if ( $status == 'carried_out' )
3620 {
3621 update_post_meta( $post_id, '_feedback_status', 'interested' );
3622 update_post_meta( $post_id, '_feedback', sanitize_textarea_field( $_POST['feedback'] ) );
3623
3624 $current_user = wp_get_current_user();
3625
3626 // Add note/comment to viewing
3627 $comment = array(
3628 'note_type' => 'action',
3629 'action' => 'viewing_applicant_interested',
3630 );
3631
3632 $data = array(
3633 'comment_post_ID' => $post_id,
3634 'comment_author' => $current_user->display_name,
3635 'comment_author_email' => 'propertyhive@noreply.com',
3636 'comment_author_url' => '',
3637 'comment_date' => date("Y-m-d H:i:s"),
3638 'comment_content' => serialize($comment),
3639 'comment_approved' => 1,
3640 'comment_type' => 'propertyhive_note',
3641 );
3642 $comment_id = wp_insert_comment( $data );
3643 }
3644
3645 die();
3646 }
3647
3648 public function viewing_not_interested_feedback()
3649 {
3650 check_ajax_referer( 'viewing-actions', 'security' );
3651
3652 $post_id = (int)$_POST['viewing_id'];
3653
3654 $status = get_post_meta( $post_id, '_status', TRUE );
3655
3656 if ( $status == 'carried_out' )
3657 {
3658 update_post_meta( $post_id, '_feedback_status', 'not_interested' );
3659 update_post_meta( $post_id, '_feedback', sanitize_textarea_field( $_POST['feedback'] ) );
3660
3661 $current_user = wp_get_current_user();
3662
3663 // Add note/comment to viewing
3664 $comment = array(
3665 'note_type' => 'action',
3666 'action' => 'viewing_applicant_not_interested',
3667 );
3668
3669 $data = array(
3670 'comment_post_ID' => $post_id,
3671 'comment_author' => $current_user->display_name,
3672 'comment_author_email' => 'propertyhive@noreply.com',
3673 'comment_author_url' => '',
3674 'comment_date' => date("Y-m-d H:i:s"),
3675 'comment_content' => serialize($comment),
3676 'comment_approved' => 1,
3677 'comment_type' => 'propertyhive_note',
3678 );
3679 $comment_id = wp_insert_comment( $data );
3680 }
3681
3682 die();
3683 }
3684
3685 public function viewing_feedback_not_required()
3686 {
3687 check_ajax_referer( 'viewing-actions', 'security' );
3688
3689 $post_id = (int)$_POST['viewing_id'];
3690
3691 $status = get_post_meta( $post_id, '_status', TRUE );
3692
3693 if ( $status == 'carried_out' )
3694 {
3695 update_post_meta( $post_id, '_feedback_status', 'not_required' );
3696
3697 $current_user = wp_get_current_user();
3698
3699 // Add note/comment to viewing
3700 $comment = array(
3701 'note_type' => 'action',
3702 'action' => 'viewing_feedback_not_required',
3703 );
3704
3705 $data = array(
3706 'comment_post_ID' => $post_id,
3707 'comment_author' => $current_user->display_name,
3708 'comment_author_email' => 'propertyhive@noreply.com',
3709 'comment_author_url' => '',
3710 'comment_date' => date("Y-m-d H:i:s"),
3711 'comment_content' => serialize($comment),
3712 'comment_approved' => 1,
3713 'comment_type' => 'propertyhive_note',
3714 );
3715 $comment_id = wp_insert_comment( $data );
3716 }
3717
3718 die();
3719 }
3720
3721 public function viewing_revert_feedback_pending()
3722 {
3723 check_ajax_referer( 'viewing-actions', 'security' );
3724
3725 $post_id = (int)$_POST['viewing_id'];
3726
3727 $status = get_post_meta( $post_id, '_status', TRUE );
3728
3729 if ( $status == 'carried_out' )
3730 {
3731 update_post_meta( $post_id, '_feedback_status', '' );
3732 update_post_meta( $post_id, '_feedback_passed_on', '' );
3733
3734 $current_user = wp_get_current_user();
3735
3736 // Add note/comment to viewing
3737 $comment = array(
3738 'note_type' => 'action',
3739 'action' => 'viewing_revert_feedback_pending',
3740 );
3741
3742 $data = array(
3743 'comment_post_ID' => $post_id,
3744 'comment_author' => $current_user->display_name,
3745 'comment_author_email' => 'propertyhive@noreply.com',
3746 'comment_author_url' => '',
3747 'comment_date' => date("Y-m-d H:i:s"),
3748 'comment_content' => serialize($comment),
3749 'comment_approved' => 1,
3750 'comment_type' => 'propertyhive_note',
3751 );
3752 $comment_id = wp_insert_comment( $data );
3753 }
3754
3755 die();
3756 }
3757
3758 public function viewing_revert_pending()
3759 {
3760 check_ajax_referer( 'viewing-actions', 'security' );
3761
3762 $post_id = (int)$_POST['viewing_id'];
3763
3764 $status = get_post_meta( $post_id, '_status', TRUE );
3765
3766 if ( $status == 'carried_out' || $status == 'cancelled' )
3767 {
3768 update_post_meta( $post_id, '_status', 'pending' );
3769 update_post_meta( $post_id, '_feedback_status', '' );
3770
3771 $current_user = wp_get_current_user();
3772
3773 // Add note/comment to viewing
3774 $comment = array(
3775 'note_type' => 'action',
3776 'action' => 'viewing_revert_pending',
3777 );
3778
3779 $data = array(
3780 'comment_post_ID' => $post_id,
3781 'comment_author' => $current_user->display_name,
3782 'comment_author_email' => 'propertyhive@noreply.com',
3783 'comment_author_url' => '',
3784 'comment_date' => date("Y-m-d H:i:s"),
3785 'comment_content' => serialize($comment),
3786 'comment_approved' => 1,
3787 'comment_type' => 'propertyhive_note',
3788 );
3789 $comment_id = wp_insert_comment( $data );
3790 }
3791
3792 die();
3793 }
3794
3795 public function viewing_feedback_passed_on()
3796 {
3797 check_ajax_referer( 'viewing-actions', 'security' );
3798
3799 $post_id = (int)$_POST['viewing_id'];
3800
3801 $status = get_post_meta( $post_id, '_status', TRUE );
3802
3803 if ( $status == 'carried_out' )
3804 {
3805 update_post_meta( $post_id, '_feedback_passed_on', 'yes' );
3806
3807 $current_user = wp_get_current_user();
3808
3809 // Add note/comment to viewing
3810 $comment = array(
3811 'note_type' => 'action',
3812 'action' => 'viewing_feedback_passed_on',
3813 );
3814
3815 $data = array(
3816 'comment_post_ID' => $post_id,
3817 'comment_author' => $current_user->display_name,
3818 'comment_author_email' => 'propertyhive@noreply.com',
3819 'comment_author_url' => '',
3820 'comment_date' => date("Y-m-d H:i:s"),
3821 'comment_content' => serialize($comment),
3822 'comment_approved' => 1,
3823 'comment_type' => 'propertyhive_note',
3824 );
3825 $comment_id = wp_insert_comment( $data );
3826 }
3827
3828 die();
3829 }
3830
3831 public function get_property_viewings_meta_box()
3832 {
3833 check_ajax_referer( 'get_property_viewings_meta_box', 'security' );
3834
3835 global $post;
3836
3837 echo '<div class="propertyhive_meta_box">';
3838
3839 echo '<div class="options_group">';
3840
3841 $args = array(
3842 'post_type' => 'viewing',
3843 'nopaging' => true,
3844 'orderby' => 'meta_value',
3845 'order' => 'DESC',
3846 'meta_key' => '_start_date_time',
3847 'post_status' => 'publish',
3848 'meta_query' => array(
3849 array(
3850 'key' => '_property_id',
3851 'value' => (int)$_POST['post_id']
3852 )
3853 )
3854 );
3855 $viewings_query = new WP_Query( $args );
3856
3857 if ( $viewings_query->have_posts() )
3858 {
3859 echo '<table style="width:100%">
3860 <thead>
3861 <tr>
3862 <th style="text-align:left;">' . __( 'Date', 'propertyhive' ) . ' / ' . __( 'Time', 'propertyhive' ) . '</th>
3863 <th style="text-align:left;">' . __( 'Applicant', 'propertyhive' ) . '</th>
3864 <th style="text-align:left;">' . __( 'Attending Negotiator(s)', 'propertyhive' ) . '</th>
3865 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
3866 </tr>
3867 </thead>
3868 <tbody>';
3869
3870 while ( $viewings_query->have_posts() )
3871 {
3872 $viewings_query->the_post();
3873
3874 echo '<tr>';
3875 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_the_ID(), '' ) . '">' . date("H:i jS F Y", strtotime(get_post_meta(get_the_ID(), '_start_date_time', TRUE))) . '</a></td>';
3876 echo '<td style="text-align:left;">';
3877 if ( get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE) != '' )
3878 {
3879 echo '<a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE), '' ) . '">' . get_the_title(get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE)) . '</a>';
3880 }
3881 else
3882 {
3883 echo '-';
3884 }
3885 echo '</td>';
3886 echo '<td style="text-align:left;">';
3887
3888 $negotiator_ids = get_post_meta(get_the_ID(), '_negotiator_id');
3889
3890 if (!empty($negotiator_ids))
3891 {
3892 $i = 0;
3893 foreach ($negotiator_ids as $negotiator_id)
3894 {
3895 if ( $i > 0 ) { echo ', '; }
3896
3897 $userdata = get_userdata( $negotiator_id );
3898 if ( $userdata !== FALSE )
3899 {
3900 echo $userdata->display_name;
3901 }
3902 else
3903 {
3904 echo '<em>Unknown user</em>';
3905 }
3906 ++$i;
3907 }
3908 }
3909 else
3910 {
3911 echo 'Unattended';
3912 }
3913
3914 echo '</td>';
3915 echo '<td style="text-align:left;">';
3916
3917 $status = get_post_meta(get_the_ID(), '_status', TRUE);
3918 echo ucwords(str_replace("_", " ", $status));
3919 if ( $status == 'pending' )
3920 {
3921 echo '<br>';
3922 // confirmation status
3923 if ( get_post_meta(get_the_ID(), '_all_confirmed', TRUE) == 'yes' )
3924 {
3925 echo __( 'All Parties Confirmed', 'propertyhive' );
3926 }
3927 else
3928 {
3929 echo __( 'Awaiting Confirmation', 'propertyhive' );
3930 }
3931 }
3932 if ( $status == 'carried_out' )
3933 {
3934 echo '<br>';
3935 $feedback_status = get_post_meta(get_the_ID(), '_feedback_status', TRUE);
3936 switch ( $feedback_status )
3937 {
3938 case "interested": { echo 'Applicant Interested'; break; }
3939 case "not_interested": { echo 'Applicant Not Interested'; break; }
3940 case "not_required": { echo 'Feedback Not Required'; break; }
3941 default: { echo 'Awaiting Feedback'; }
3942 }
3943
3944 if ( $feedback_status == 'interested' || $feedback_status == 'not_interested' )
3945 {
3946 $feedback_passed_on = get_post_meta(get_the_ID(), '_feedback_passed_on', TRUE);
3947 echo '<br>' . ( ($feedback_passed_on == 'yes') ? 'Feedback Passed On' : 'Feedback Not Passed On' );
3948 }
3949 }
3950 echo '</td>';
3951 echo '</tr>';
3952 }
3953
3954 echo '
3955 </tbody>
3956 </table>
3957 <br>';
3958 }
3959 else
3960 {
3961 echo '<p>' . __( 'No viewings exist for this property', 'propertyhive') . '</p>';
3962 }
3963 wp_reset_postdata();
3964
3965 do_action('propertyhive_property_viewings_fields');
3966
3967 echo '</div>';
3968
3969 echo '</div>';
3970
3971 die();
3972 }
3973
3974 public function get_contact_viewings_meta_box()
3975 {
3976 check_ajax_referer( 'get_contact_viewings_meta_box', 'security' );
3977
3978 global $post;
3979
3980 echo '<div class="propertyhive_meta_box">';
3981
3982 echo '<div class="options_group">';
3983
3984 $args = array(
3985 'post_type' => 'viewing',
3986 'nopaging' => true,
3987 'orderby' => 'meta_value',
3988 'order' => 'DESC',
3989 'post_status' => 'publish',
3990 'meta_key' => '_start_date_time',
3991 'meta_query' => array(
3992 array(
3993 'key' => '_applicant_contact_id',
3994 'value' => (int)$_POST['post_id']
3995 )
3996 )
3997 );
3998 $viewings_query = new WP_Query( $args );
3999
4000 if ( $viewings_query->have_posts() )
4001 {
4002 echo '<table style="width:100%">
4003 <thead>
4004 <tr>
4005 <th style="text-align:left;">' . __( 'Date', 'propertyhive' ) . ' / ' . __( 'Time', 'propertyhive' ) . '</th>
4006 <th style="text-align:left;">' . __( 'Property', 'propertyhive' ) . '</th>
4007 <th style="text-align:left;">' . __( 'Attending Negotiator(s)', 'propertyhive' ) . '</th>
4008 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
4009 </tr>
4010 </thead>
4011 <tbody>';
4012
4013 while ( $viewings_query->have_posts() )
4014 {
4015 $viewings_query->the_post();
4016
4017 $property = new PH_Property((int)get_post_meta(get_the_ID(), '_property_id', TRUE));
4018
4019 echo '<tr>';
4020 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_the_ID(), '') . '">' . date("H:i jS F Y", strtotime(get_post_meta(get_the_ID(), '_start_date_time', TRUE))) . '</a></td>';
4021 echo '<td style="text-align:left;">';
4022 if ( get_post_meta(get_the_ID(), '_property_id', TRUE) != '' )
4023 {
4024 echo '<a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_property_id', TRUE), '' ) . '">' . $property->get_formatted_full_address() . '</a>';
4025 }
4026 else
4027 {
4028 echo '-';
4029 }
4030 echo '</td>';
4031
4032 echo '<td style="text-align:left;">';
4033
4034 $negotiator_ids = get_post_meta(get_the_ID(), '_negotiator_id');
4035
4036 if (!empty($negotiator_ids))
4037 {
4038 $i = 0;
4039 foreach ($negotiator_ids as $negotiator_id)
4040 {
4041 if ( $i > 0 ) { echo ', '; }
4042
4043 $userdata = get_userdata( $negotiator_id );
4044 if ( $userdata !== FALSE )
4045 {
4046 echo $userdata->display_name;
4047 }
4048 else
4049 {
4050 echo '<em>Unknown user</em>';
4051 }
4052 ++$i;
4053 }
4054 }
4055 else
4056 {
4057 echo 'Unattended';
4058 }
4059
4060 echo '</td>';
4061 echo '<td style="text-align:left;">';
4062
4063 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4064 echo ucwords(str_replace("_", " ", $status));
4065 if ( $status == 'pending' )
4066 {
4067 echo '<br>';
4068 // confirmation status
4069 if ( get_post_meta(get_the_ID(), '_all_confirmed', TRUE) == 'yes' )
4070 {
4071 echo __( 'All Parties Confirmed', 'propertyhive' );
4072 }
4073 else
4074 {
4075 echo __( 'Awaiting Confirmation', 'propertyhive' );
4076 }
4077 }
4078 if ( $status == 'carried_out' )
4079 {
4080 echo '<br>';
4081 $feedback_status = get_post_meta(get_the_ID(), '_feedback_status', TRUE);
4082 switch ( get_post_meta(get_the_ID(), '_feedback_status', TRUE) )
4083 {
4084 case "interested": { echo 'Applicant Interested'; break; }
4085 case "not_interested": { echo 'Applicant Not Interested'; break; }
4086 case "not_required": { echo 'Feedback Not Required'; break; }
4087 default: { echo 'Awaiting Feedback'; }
4088 }
4089
4090 if ( $feedback_status == 'interested' || $feedback_status == 'not_interested' )
4091 {
4092 $feedback_passed_on = get_post_meta(get_the_ID(), '_feedback_passed_on', TRUE);
4093 echo '<br>' . ( ($feedback_passed_on == 'yes') ? 'Feedback Passed On' : 'Feedback Not Passed On' );
4094 }
4095 }
4096 echo '</td>';
4097 echo '</tr>';
4098 }
4099
4100 echo '
4101 </tbody>
4102 </table>
4103 <br>';
4104 }
4105 else
4106 {
4107 echo '<p>' . __( 'No viewings exist for this contact', 'propertyhive') . '</p>';
4108 }
4109 wp_reset_postdata();
4110
4111 do_action('propertyhive_contact_viewings_fields');
4112
4113 echo '</div>';
4114
4115 echo '</div>';
4116
4117 die();
4118 }
4119
4120 // Offer related functions
4121 public function record_offer_property()
4122 {
4123 check_ajax_referer( 'record-offer', 'security' );
4124
4125 $this->json_headers();
4126
4127 // TO DO: Should do validation on server side also
4128 if (empty($_POST['property_id']))
4129 {
4130 $return = array('error' => 'No property selected');
4131 echo json_encode( $return );
4132 die();
4133 }
4134
4135 $property = new PH_Property((int)$_POST['property_id']);
4136
4137 $applicant_contact_ids = array();
4138
4139 // Create applicant record if required
4140 if (empty($_POST['applicant_ids']) && !empty($_POST['applicant_name']))
4141 {
4142 // Need to create contact/applicant
4143 $contact_post = array(
4144 'post_title' => ph_clean($_POST['applicant_name']),
4145 'post_content' => '',
4146 'post_type' => 'contact',
4147 'post_status' => 'publish',
4148 'comment_status' => 'closed',
4149 'ping_status' => 'closed',
4150 );
4151
4152 // Insert the post into the database
4153 $contact_post_id = wp_insert_post( $contact_post );
4154
4155 if ( is_wp_error($contact_post_id) || $contact_post_id == 0 )
4156 {
4157 $return = array('error' => 'Failed to create contact post. Please try again');
4158 echo json_encode( $return );
4159 die();
4160 }
4161
4162 update_post_meta( $contact_post_id, '_contact_types', array('applicant') );
4163
4164 update_post_meta( $contact_post_id, '_applicant_profiles', 1 );
4165 update_post_meta( $contact_post_id, '_applicant_profile_0', array( 'department' => $property->department, 'send_matching_properties' => '' ) );
4166
4167 $applicant_contact_ids[] = $contact_post_id;
4168 }
4169
4170 if (!empty($_POST['applicant_ids']) && empty($_POST['applicant_name']))
4171 {
4172 // This is an existing contact
4173 if ( !is_array($_POST['applicant_ids']) )
4174 {
4175 $_POST['applicant_ids'] = array($_POST['applicant_ids']);
4176 }
4177
4178 foreach ( $_POST['applicant_ids'] as $applicant_id )
4179 {
4180 $applicant_contact_ids[] = (int)$applicant_id;
4181 }
4182 }
4183
4184 $applicant_contact_ids = array_unique($applicant_contact_ids);
4185
4186 if ( empty($applicant_contact_ids) )
4187 {
4188 $return = array('error' => 'No applicant selected, or unable to create applicant record');
4189 echo json_encode( $return );
4190 die();
4191 }
4192
4193 // Loop through contacts and create one offer each
4194 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
4195 foreach ( $applicant_contact_ids as $applicant_contact_id )
4196 {
4197 // Insert offer record
4198 $offer_post = array(
4199 'post_title' => '',
4200 'post_content' => '',
4201 'post_type' => 'offer',
4202 'post_status' => 'publish',
4203 'comment_status' => 'closed',
4204 'ping_status' => 'closed',
4205 );
4206
4207 // Insert the post into the database
4208 $offer_post_id = wp_insert_post( $offer_post );
4209
4210 if ( is_wp_error($offer_post_id) || $offer_post_id == 0 )
4211 {
4212 $return = array('error' => 'Failed to create offer post. Please try again');
4213 echo json_encode( $return );
4214 die();
4215 }
4216
4217 $amount = preg_replace("/[^0-9]/", '', $_POST['amount']);
4218
4219 add_post_meta( $offer_post_id, '_offer_date_time', ph_clean($_POST['offer_date']) . ' ' . ph_clean($_POST['offer_time']) );
4220 add_post_meta( $offer_post_id, '_property_id', (int)$_POST['property_id'] );
4221 add_post_meta( $offer_post_id, '_applicant_contact_id', $applicant_contact_id );
4222 add_post_meta( $offer_post_id, '_amount', $amount );
4223 add_post_meta( $offer_post_id, '_status', 'pending' );
4224 }
4225
4226 $applicant_contacts = array();
4227 foreach ( $applicant_contact_ids as $applicant_contact_id )
4228 {
4229 $applicant_contacts[] = array(
4230 'ID' => $applicant_contact_id,
4231 'post_title' => get_the_title($applicant_contact_id),
4232 'edit_link' => get_edit_post_link( $applicant_contact_id, '' ),
4233 );
4234 }
4235
4236 $return = array('success' => array(
4237 'offer' => array(
4238 'ID' => $offer_post_id,
4239 'edit_link' => get_edit_post_link( $offer_post_id, '' ),
4240 ),
4241 'applicant_contacts' => $applicant_contacts,
4242 ));
4243
4244 echo json_encode( $return );
4245
4246 die();
4247 }
4248
4249 public function record_offer_contact()
4250 {
4251 check_ajax_referer( 'record-offer', 'security' );
4252
4253 $this->json_headers();
4254
4255 // TO DO: Should do validation on server side also
4256 if (empty($_POST['contact_id']))
4257 {
4258 $return = array('error' => 'No contact selected');
4259 echo json_encode( $return );
4260 die();
4261 }
4262
4263 if (empty($_POST['property_ids']))
4264 {
4265 $return = array('error' => 'No property selected');
4266 echo json_encode( $return );
4267 die();
4268 }
4269
4270 // Loop through contacts and create one offer each
4271 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
4272 foreach ( $_POST['property_ids'] as $property_id )
4273 {
4274 // Insert offer record
4275 $offer_post = array(
4276 'post_title' => '',
4277 'post_content' => '',
4278 'post_type' => 'offer',
4279 'post_status' => 'publish',
4280 'comment_status' => 'closed',
4281 'ping_status' => 'closed',
4282 );
4283
4284 // Insert the post into the database
4285 $offer_post_id = wp_insert_post( $offer_post );
4286
4287 if ( is_wp_error($offer_post_id) || $offer_post_id == 0 )
4288 {
4289 $return = array('error' => 'Failed to create offer post. Please try again');
4290 echo json_encode( $return );
4291 die();
4292 }
4293
4294 $amount = preg_replace("/[^0-9]/", '', ph_clean($_POST['amount']));
4295
4296 add_post_meta( $offer_post_id, '_offer_date_time', ph_clean($_POST['offer_date']) . ' ' . ph_clean($_POST['offer_time']) );
4297 add_post_meta( $offer_post_id, '_property_id', (int)$property_id );
4298 add_post_meta( $offer_post_id, '_applicant_contact_id', (int)$_POST['contact_id'] );
4299 add_post_meta( $offer_post_id, '_amount', $amount );
4300 add_post_meta( $offer_post_id, '_status', 'pending' );
4301 }
4302
4303 $properties = array();
4304 foreach ( $_POST['property_ids'] as $property_id )
4305 {
4306 $properties[] = array(
4307 'ID' => (int)$property_id,
4308 'post_title' => get_the_title((int)$property_id),
4309 'edit_link' => get_edit_post_link( (int)$property_id, '' ),
4310 );
4311 }
4312
4313 $return = array('success' => array(
4314 'offer' => array(
4315 'ID' => $offer_post_id,
4316 'edit_link' => get_edit_post_link( $offer_post_id, '' ),
4317 ),
4318 'properties' => $properties,
4319 ));
4320
4321 echo json_encode( $return );
4322
4323 die();
4324 }
4325
4326 public function get_offer_details_meta_box()
4327 {
4328 global $post;
4329
4330 check_ajax_referer( 'offer-details-meta-box', 'security' );
4331
4332 $post = get_post((int)$_POST['offer_id']);
4333
4334 $offer = new PH_Offer((int)$_POST['offer_id']);
4335
4336 echo '<div class="propertyhive_meta_box">';
4337
4338 echo '<div class="options_group">';
4339
4340 if ( $offer->status != '' )
4341 {
4342 echo '<p class="form-field">
4343
4344 <label for="">' . __('Status', 'propertyhive') . '</label>
4345
4346 ' . ucwords(str_replace("_", " ", $offer->status)) . '
4347
4348 </p>';
4349 }
4350
4351 $offer_date_time = $offer->offer_date_time;
4352 if ( empty($offer_date_time) )
4353 {
4354 $offer_date_time = date("Y-m-d H:i:s");
4355 }
4356
4357 echo '<p class="form-field offer_date_time_field">
4358
4359 <label for="_offer_date">' . __('Offer Date / Time', 'propertyhive') . '</label>
4360
4361 <input type="text" id="_offer_date" name="_offer_date" class="date-picker short" placeholder="yyyy-mm-dd" style="width:120px;" value="' . date("Y-m-d", strtotime($offer_date_time)) . '">
4362 <select id="_offer_time_hours" name="_offer_time_hours" class="select short" style="width:55px">';
4363
4364 if ( empty($offer_date_time) )
4365 {
4366 $value = date("H");
4367 }
4368 else
4369 {
4370 $value = date( "H", strtotime( $offer_date_time ) );
4371 }
4372 for ( $i = 0; $i < 23; ++$i )
4373 {
4374 $j = str_pad($i, 2, '0', STR_PAD_LEFT);
4375 echo '<option value="' . $j . '"';
4376 if ($i == $value) { echo ' selected'; }
4377 echo '>' . $j . '</option>';
4378 }
4379
4380 echo '</select>
4381 :
4382 <select id="_offer_time_minutes" name="_offer_time_minutes" class="select short" style="width:55px">';
4383
4384 if ( empty($offer_date_time) )
4385 {
4386 $value = '';
4387 }
4388 else
4389 {
4390 $value = date( "i", strtotime( $offer_date_time ) );
4391 }
4392 for ( $i = 0; $i < 60; $i+=5 )
4393 {
4394 $j = str_pad($i, 2, '0', STR_PAD_LEFT);
4395 echo '<option value="' . $j . '"';
4396 if ($i == $value) { echo ' selected'; }
4397 echo '>' . $j . '</option>';
4398 }
4399
4400 echo '</select>
4401
4402 </p>';
4403
4404 $args = array(
4405 'id' => '_amount',
4406 'label' => __( 'Offer Amount', 'propertyhive' ) . ' (&pound;)',
4407 'desc_tip' => false,
4408 'class' => 'short',
4409 'value' => ( is_numeric($offer->amount) ? number_format($offer->amount) : '' ),
4410 'custom_attributes' => array(
4411 //'style' => 'width:95%; max-width:500px;'
4412 )
4413 );
4414 propertyhive_wp_text_input( $args );
4415
4416 do_action('propertyhive_offer_details_fields');
4417
4418 echo '</div>';
4419
4420 echo '</div>';
4421
4422 die();
4423 }
4424
4425 public function get_offer_actions()
4426 {
4427 check_ajax_referer( 'offer-actions', 'security' );
4428
4429 $post_id = (int)$_POST['offer_id'];
4430
4431 $status = get_post_meta( $post_id, '_status', TRUE );
4432
4433 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_offer_actions_meta_box">
4434
4435 <div class="options_group" style="padding-top:8px;">';
4436
4437 $actions = array();
4438
4439 if ( $status == 'pending' )
4440 {
4441 $actions[] = '<a
4442 href="#action_panel_offer_accepted"
4443 class="button button-success offer-action"
4444 style="width:100%; margin-bottom:7px; text-align:center"
4445 >' . wp_kses_post( __('Accept Offer', 'propertyhive') ) . '</a>';
4446 $actions[] = '<a
4447 href="#action_panel_offer_declined"
4448 class="button button-danger offer-action"
4449 style="width:100%; margin-bottom:7px; text-align:center"
4450 >' . wp_kses_post( __('Decline Offer', 'propertyhive') ) . '</a>';
4451 }
4452
4453 if ( $status == 'accepted' )
4454 {
4455 // See if a sale has this offer id associated with it
4456 $sale_id = get_post_meta( $post_id, '_sale_id', TRUE );
4457 if ( $sale_id != '' && get_post_status($sale_id) != 'publish' )
4458 {
4459 $sale_id = '';
4460 }
4461
4462 if ( $sale_id != '' )
4463 {
4464 $actions[] = '<a
4465 href="' . get_edit_post_link( $sale_id, '' ) . '"
4466 class="button"
4467 style="width:100%; margin-bottom:7px; text-align:center"
4468 >' . wp_kses_post( __('View Sale', 'propertyhive') ) . '</a>';
4469 }
4470 else
4471 {
4472 $actions[] = '<a
4473 href="' . wp_nonce_url( admin_url( 'post.php?post=' . $post_id . '&action=edit' ), '1', 'create_sale' ) . '"
4474 class="button button-success"
4475 style="width:100%; margin-bottom:7px; text-align:center"
4476 >' . wp_kses_post( __('Create Sale', 'propertyhive') ) . '</a>';
4477 }
4478 }
4479
4480 if ( $status == 'declined' )
4481 {
4482
4483 }
4484
4485 if ( $status == 'accepted' || $status == 'declined' )
4486 {
4487 $actions[] = '<a
4488 href="#action_panel_offer_revert_pending"
4489 class="button offer-action"
4490 style="width:100%; margin-bottom:7px; text-align:center"
4491 >' . wp_kses_post( __('Revert To Pending', 'propertyhive') ) . '</a>';
4492 }
4493
4494 $actions = apply_filters( 'propertyhive_admin_offer_actions', $actions, $post_id );
4495
4496 if ( !empty($actions) )
4497 {
4498 echo implode("", $actions);
4499 }
4500 else
4501 {
4502 echo '<div style="text-align:center">' . __( 'No actions to display', 'propertyhive' ) . '</div>';
4503 }
4504
4505 echo '</div>
4506
4507 </div>';
4508
4509 die();
4510 }
4511
4512 public function offer_accepted()
4513 {
4514 check_ajax_referer( 'offer-actions', 'security' );
4515
4516 $post_id = (int)$_POST['offer_id'];
4517
4518 $status = get_post_meta( $post_id, '_status', TRUE );
4519
4520 if ( $status == 'pending' )
4521 {
4522 update_post_meta( $post_id, '_status', 'accepted' );
4523
4524 $current_user = wp_get_current_user();
4525
4526 // Add note/comment to offer
4527 $comment = array(
4528 'note_type' => 'action',
4529 'action' => 'offer_accepted',
4530 );
4531
4532 $data = array(
4533 'comment_post_ID' => $post_id,
4534 'comment_author' => $current_user->display_name,
4535 'comment_author_email' => 'propertyhive@noreply.com',
4536 'comment_author_url' => '',
4537 'comment_date' => date("Y-m-d H:i:s"),
4538 'comment_content' => serialize($comment),
4539 'comment_approved' => 1,
4540 'comment_type' => 'propertyhive_note',
4541 );
4542 $comment_id = wp_insert_comment( $data );
4543 }
4544
4545 die();
4546 }
4547
4548 public function offer_declined()
4549 {
4550 check_ajax_referer( 'offer-actions', 'security' );
4551
4552 $post_id = (int)$_POST['offer_id'];
4553
4554 $status = get_post_meta( $post_id, '_status', TRUE );
4555
4556 if ( $status == 'pending' )
4557 {
4558 update_post_meta( $post_id, '_status', 'declined' );
4559
4560 $current_user = wp_get_current_user();
4561
4562 // Add note/comment to offer
4563 $comment = array(
4564 'note_type' => 'action',
4565 'action' => 'offer_declined',
4566 );
4567
4568 $data = array(
4569 'comment_post_ID' => $post_id,
4570 'comment_author' => $current_user->display_name,
4571 'comment_author_email' => 'propertyhive@noreply.com',
4572 'comment_author_url' => '',
4573 'comment_date' => date("Y-m-d H:i:s"),
4574 'comment_content' => serialize($comment),
4575 'comment_approved' => 1,
4576 'comment_type' => 'propertyhive_note',
4577 );
4578 $comment_id = wp_insert_comment( $data );
4579 }
4580
4581 die();
4582 }
4583
4584 public function offer_revert_pending()
4585 {
4586 check_ajax_referer( 'offer-actions', 'security' );
4587
4588 $post_id = (int)$_POST['offer_id'];
4589
4590 $status = get_post_meta( $post_id, '_status', TRUE );
4591
4592 if ( $status == 'accepted' || $status == 'declined' )
4593 {
4594 update_post_meta( $post_id, '_status', 'pending' );
4595
4596 $current_user = wp_get_current_user();
4597
4598 // Add note/comment to offer
4599 $comment = array(
4600 'note_type' => 'action',
4601 'action' => 'offer_revert_pending',
4602 );
4603
4604 $data = array(
4605 'comment_post_ID' => $post_id,
4606 'comment_author' => $current_user->display_name,
4607 'comment_author_email' => 'propertyhive@noreply.com',
4608 'comment_author_url' => '',
4609 'comment_date' => date("Y-m-d H:i:s"),
4610 'comment_content' => serialize($comment),
4611 'comment_approved' => 1,
4612 'comment_type' => 'propertyhive_note',
4613 );
4614 $comment_id = wp_insert_comment( $data );
4615 }
4616
4617 die();
4618 }
4619
4620 public function get_property_offers_meta_box()
4621 {
4622 check_ajax_referer( 'get_property_offers_meta_box', 'security' );
4623
4624 global $post;
4625
4626 echo '<div class="propertyhive_meta_box">';
4627
4628 echo '<div class="options_group">';
4629
4630 $args = array(
4631 'post_type' => 'offer',
4632 'nopaging' => true,
4633 'orderby' => 'meta_value',
4634 'order' => 'DESC',
4635 'meta_key' => '_offer_date_time',
4636 'post_status' => 'publish',
4637 'meta_query' => array(
4638 array(
4639 'key' => '_property_id',
4640 'value' => (int)$_POST['post_id']
4641 )
4642 )
4643 );
4644 $offers_query = new WP_Query( $args );
4645
4646 if ( $offers_query->have_posts() )
4647 {
4648 echo '<table style="width:100%">
4649 <thead>
4650 <tr>
4651 <th style="text-align:left;">' . __( 'Offer Date', 'propertyhive' ) . '</th>
4652 <th style="text-align:left;">' . __( 'Applicant', 'propertyhive' ) . '</th>
4653 <th style="text-align:left;">' . __( 'Offer Amount', 'propertyhive' ) . '</th>
4654 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
4655 </tr>
4656 </thead>
4657 <tbody>';
4658
4659 while ( $offers_query->have_posts() )
4660 {
4661 $offers_query->the_post();
4662
4663 $offer = new PH_Offer(get_the_ID());
4664
4665 echo '<tr>';
4666 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_the_ID(), '' ) . '">' . date("jS F Y", strtotime(get_post_meta(get_the_ID(), '_offer_date_time', TRUE))) . '</a></td>';
4667 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE), '' ) . '">' . get_the_title(get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE)) . '</a></td>';
4668 echo '<td style="text-align:left;">' . $offer->get_formatted_amount() . '</td>';
4669 echo '<td style="text-align:left;">';
4670 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4671 echo ucwords(str_replace("_", " ", $status));
4672 echo '</td>';
4673 echo '</tr>';
4674 }
4675
4676 echo '
4677 </tbody>
4678 </table>
4679 <br>';
4680 }
4681 else
4682 {
4683 echo '<p>' . __( 'No offers exist for this property', 'propertyhive') . '</p>';
4684 }
4685 wp_reset_postdata();
4686
4687 do_action('propertyhive_property_offers_fields');
4688
4689 echo '</div>';
4690
4691 echo '</div>';
4692
4693 die();
4694 }
4695
4696 public function get_contact_offers_meta_box()
4697 {
4698 check_ajax_referer( 'get_contact_offers_meta_box', 'security' );
4699
4700 global $post;
4701
4702 echo '<div class="propertyhive_meta_box">';
4703
4704 echo '<div class="options_group">';
4705
4706 $args = array(
4707 'post_type' => 'offer',
4708 'nopaging' => true,
4709 'orderby' => 'meta_value',
4710 'order' => 'DESC',
4711 'post_status' => 'publish',
4712 'meta_key' => '_offer_date_time',
4713 'meta_query' => array(
4714 array(
4715 'key' => '_applicant_contact_id',
4716 'value' => (int)$_POST['post_id']
4717 )
4718 )
4719 );
4720 $offers_query = new WP_Query( $args );
4721
4722 if ( $offers_query->have_posts() )
4723 {
4724 echo '<table style="width:100%">
4725 <thead>
4726 <tr>
4727 <th style="text-align:left;">' . __( 'Offer Date', 'propertyhive' ) . '</th>
4728 <th style="text-align:left;">' . __( 'Property', 'propertyhive' ) . '</th>
4729 <th style="text-align:left;">' . __( 'Property Owner', 'propertyhive' ) . '</th>
4730 <th style="text-align:left;">' . __( 'Offer Amount', 'propertyhive' ) . '</th>
4731 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
4732 </tr>
4733 </thead>
4734 <tbody>';
4735
4736 while ( $offers_query->have_posts() )
4737 {
4738 $offers_query->the_post();
4739
4740 $property = new PH_Property((int)get_post_meta(get_the_ID(), '_property_id', TRUE));
4741 $offer = new PH_Offer(get_the_ID());
4742
4743 echo '<tr>';
4744 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_the_ID(), '') . '">' . date("jS F Y", strtotime(get_post_meta(get_the_ID(), '_offer_date_time', TRUE))) . '</a></td>';
4745 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_property_id', TRUE), '' ) . '">' . $property->get_formatted_full_address() . '</a></td>';
4746 echo '<td style="text-align:left;">';
4747
4748 $owner_contact_ids = $property->_owner_contact_id;
4749 if (
4750 ( !is_array($owner_contact_ids) && $owner_contact_ids != '' && $owner_contact_ids != 0 )
4751 ||
4752 ( is_array($owner_contact_ids) && !empty($owner_contact_ids) )
4753 )
4754 {
4755 if ( !is_array($owner_contact_ids) )
4756 {
4757 $owner_contact_ids = array($owner_contact_ids);
4758 }
4759
4760 foreach ( $owner_contact_ids as $owner_contact_id )
4761 {
4762 echo get_the_title($owner_contact_id) . '<br>';
4763 echo '<div style="color:#BBB">';
4764 echo 'T: ' . get_post_meta($owner_contact_id, '_telephone_number', TRUE) . '<br>';
4765 echo 'E: ' . get_post_meta($owner_contact_id, '_email_address', TRUE);
4766 echo '</div>';
4767 }
4768 }
4769
4770 echo '</td>';
4771 echo '<td style="text-align:left;">' . $offer->get_formatted_amount() . '</td>';
4772 echo '<td style="text-align:left;">';
4773 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4774 echo ucwords(str_replace("_", " ", $status));
4775 echo '</td>';
4776 echo '</tr>';
4777 }
4778
4779 echo '
4780 </tbody>
4781 </table>
4782 <br>';
4783 }
4784 else
4785 {
4786 echo '<p>' . __( 'No offers exist for this contact', 'propertyhive') . '</p>';
4787 }
4788 wp_reset_postdata();
4789
4790 do_action('propertyhive_contact_offers_fields');
4791
4792 echo '</div>';
4793
4794 echo '</div>';
4795
4796 die();
4797 }
4798
4799 // Sale related functions
4800 public function get_sale_details_meta_box()
4801 {
4802 global $post;
4803
4804 check_ajax_referer( 'sale-details-meta-box', 'security' );
4805
4806 $post = get_post((int)$_POST['sale_id']);
4807
4808 $sale = new PH_Offer((int)$_POST['sale_id']);
4809
4810 echo '<div class="propertyhive_meta_box">';
4811
4812 echo '<div class="options_group">';
4813
4814 if ( $sale->status != '' )
4815 {
4816 echo '<p class="form-field">
4817
4818 <label for="">' . __('Status', 'propertyhive') . '</label>
4819
4820 ' . ucwords(str_replace("_", " ", $sale->status)) . '
4821
4822 </p>';
4823 }
4824
4825 $sale_date_time = $sale->sale_date_time;
4826 if ( empty($sale_date_time) )
4827 {
4828 $sale_date_time = date("Y-m-d H:i:s");
4829 }
4830
4831 echo '<p class="form-field sale_date_field">
4832
4833 <label for="_sale_date">' . __('Sale Date', 'propertyhive') . '</label>
4834
4835 <input type="text" id="_sale_date" name="_sale_date" class="date-picker short" placeholder="yyyy-mm-dd" style="width:120px;" value="' . date("Y-m-d", strtotime($sale_date_time)) . '">
4836
4837 </p>';
4838
4839 $args = array(
4840 'id' => '_amount',
4841 'label' => __( 'Sale Amount', 'propertyhive' ) . ' (&pound;)',
4842 'desc_tip' => false,
4843 'class' => 'short',
4844 'value' => ( is_numeric($sale->amount) ? number_format($sale->amount) : '' ),
4845 'custom_attributes' => array(
4846 //'style' => 'width:95%; max-width:500px;'
4847 )
4848 );
4849 propertyhive_wp_text_input( $args );
4850
4851 do_action('propertyhive_sale_details_fields');
4852
4853 echo '</div>';
4854
4855 echo '</div>';
4856
4857 die();
4858 }
4859
4860 public function get_sale_actions()
4861 {
4862 check_ajax_referer( 'sale-actions', 'security' );
4863
4864 $post_id = (int)$_POST['sale_id'];
4865
4866 $status = get_post_meta( $post_id, '_status', TRUE );
4867
4868 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_sale_actions_meta_box">
4869
4870 <div class="options_group" style="padding-top:8px;">';
4871
4872 $actions = array();
4873
4874 if ( $status == 'current' )
4875 {
4876 $actions[] = '<a
4877 href="#action_panel_sale_exchanged"
4878 class="button button-success sale-action"
4879 style="width:100%; margin-bottom:7px; text-align:center"
4880 >' . __('Sale Exchanged', 'propertyhive') . '</a>';
4881
4882 }
4883
4884 if ( $status == 'exchanged' )
4885 {
4886 $actions[] = '<a
4887 href="#action_panel_sale_completed"
4888 class="button button-success sale-action"
4889 style="width:100%; margin-bottom:7px; text-align:center"
4890 >' . __('Sale Completed', 'propertyhive') . '</a>';
4891 }
4892
4893 if ( $status == 'completed' )
4894 {
4895
4896 }
4897
4898 if ( $status == 'current' || $status == 'exchanged' )
4899 {
4900 $actions[] = '<a
4901 href="#action_panel_sale_fallen_through"
4902 class="button sale-action"
4903 style="width:100%; margin-bottom:7px; text-align:center"
4904 >' . __('Sale Fallen Through', 'propertyhive') . '</a>';
4905 }
4906
4907 $actions = apply_filters( 'propertyhive_admin_sale_actions', $actions, $post_id );
4908
4909 if ( !empty($actions) )
4910 {
4911 echo implode("", $actions);
4912 }
4913 else
4914 {
4915 echo '<div style="text-align:center">' . __( 'No actions to display', 'propertyhive' ) . '</div>';
4916 }
4917
4918 echo '</div>
4919
4920 </div>';
4921
4922 die();
4923 }
4924
4925 public function sale_exchanged()
4926 {
4927 check_ajax_referer( 'sale-actions', 'security' );
4928
4929 $post_id = (int)$_POST['sale_id'];
4930
4931 $status = get_post_meta( $post_id, '_status', TRUE );
4932
4933 if ( $status == 'current' )
4934 {
4935 update_post_meta( $post_id, '_status', 'exchanged' );
4936
4937 $current_user = wp_get_current_user();
4938
4939 // Add note/comment to sale
4940 $comment = array(
4941 'note_type' => 'action',
4942 'action' => 'sale_exchanged',
4943 );
4944
4945 $data = array(
4946 'comment_post_ID' => $post_id,
4947 'comment_author' => $current_user->display_name,
4948 'comment_author_email' => 'propertyhive@noreply.com',
4949 'comment_author_url' => '',
4950 'comment_date' => date("Y-m-d H:i:s"),
4951 'comment_content' => serialize($comment),
4952 'comment_approved' => 1,
4953 'comment_type' => 'propertyhive_note',
4954 );
4955 $comment_id = wp_insert_comment( $data );
4956 }
4957
4958 die();
4959 }
4960
4961 public function sale_completed()
4962 {
4963 check_ajax_referer( 'sale-actions', 'security' );
4964
4965 $post_id = (int)$_POST['sale_id'];
4966
4967 $status = get_post_meta( $post_id, '_status', TRUE );
4968
4969 if ( $status == 'exchanged' )
4970 {
4971 update_post_meta( $post_id, '_status', 'completed' );
4972
4973 $current_user = wp_get_current_user();
4974
4975 // Add note/comment to sale
4976 $comment = array(
4977 'note_type' => 'action',
4978 'action' => 'sale_completed',
4979 );
4980
4981 $data = array(
4982 'comment_post_ID' => $post_id,
4983 'comment_author' => $current_user->display_name,
4984 'comment_author_email' => 'propertyhive@noreply.com',
4985 'comment_author_url' => '',
4986 'comment_date' => date("Y-m-d H:i:s"),
4987 'comment_content' => serialize($comment),
4988 'comment_approved' => 1,
4989 'comment_type' => 'propertyhive_note',
4990 );
4991 $comment_id = wp_insert_comment( $data );
4992 }
4993
4994 die();
4995 }
4996
4997 public function sale_fallen_through()
4998 {
4999 check_ajax_referer( 'sale-actions', 'security' );
5000
5001 $post_id = (int)$_POST['sale_id'];
5002
5003 $status = get_post_meta( $post_id, '_status', TRUE );
5004
5005 if ( $status == 'current' || $status == 'exchanged' )
5006 {
5007 update_post_meta( $post_id, '_status', 'fallen_through' );
5008
5009 $current_user = wp_get_current_user();
5010
5011 // Add note/comment to sale
5012 $comment = array(
5013 'note_type' => 'action',
5014 'action' => 'sale_fallen_through',
5015 );
5016
5017 $data = array(
5018 'comment_post_ID' => $post_id,
5019 'comment_author' => $current_user->display_name,
5020 'comment_author_email' => 'propertyhive@noreply.com',
5021 'comment_author_url' => '',
5022 'comment_date' => date("Y-m-d H:i:s"),
5023 'comment_content' => serialize($comment),
5024 'comment_approved' => 1,
5025 'comment_type' => 'propertyhive_note',
5026 );
5027 $comment_id = wp_insert_comment( $data );
5028 }
5029
5030 die();
5031 }
5032
5033 public function get_property_sales_meta_box()
5034 {
5035 check_ajax_referer( 'get_property_sales_meta_box', 'security' );
5036
5037 global $post;
5038
5039 echo '<div class="propertyhive_meta_box">';
5040
5041 echo '<div class="options_group">';
5042
5043 $args = array(
5044 'post_type' => 'sale',
5045 'nopaging' => true,
5046 'orderby' => 'meta_value',
5047 'order' => 'DESC',
5048 'meta_key' => '_sale_date_time',
5049 'post_status' => 'publish',
5050 'meta_query' => array(
5051 array(
5052 'key' => '_property_id',
5053 'value' => (int)$_POST['post_id']
5054 )
5055 )
5056 );
5057 $sales_query = new WP_Query( $args );
5058
5059 if ( $sales_query->have_posts() )
5060 {
5061 echo '<table style="width:100%">
5062 <thead>
5063 <tr>
5064 <th style="text-align:left;">' . __( 'Sale Date', 'propertyhive' ) . '</th>
5065 <th style="text-align:left;">' . __( 'Applicant', 'propertyhive' ) . '</th>
5066 <th style="text-align:left;">' . __( 'Sale Amount', 'propertyhive' ) . '</th>
5067 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
5068 </tr>
5069 </thead>
5070 <tbody>';
5071
5072 while ( $sales_query->have_posts() )
5073 {
5074 $sales_query->the_post();
5075
5076 $sale = new PH_Sale(get_the_ID());
5077
5078 echo '<tr>';
5079 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_the_ID(), '' ) . '">' . date("jS F Y", strtotime(get_post_meta(get_the_ID(), '_sale_date_time', TRUE))) . '</a></td>';
5080 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE), '' ) . '">' . get_the_title(get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE)) . '</a></td>';
5081 echo '<td style="text-align:left;">' . $sale->get_formatted_amount() . '</td>';
5082 echo '<td style="text-align:left;">';
5083 $status = get_post_meta(get_the_ID(), '_status', TRUE);
5084 echo ucwords(str_replace("_", " ", $status));
5085 echo '</td>';
5086 echo '</tr>';
5087 }
5088
5089 echo '
5090 </tbody>
5091 </table>
5092 <br>';
5093 }
5094 else
5095 {
5096 echo '<p>' . __( 'No sales exist for this property', 'propertyhive') . '</p>';
5097 }
5098 wp_reset_postdata();
5099
5100 do_action('propertyhive_property_sales_fields');
5101
5102 echo '</div>';
5103
5104 echo '</div>';
5105
5106 die();
5107 }
5108
5109 public function get_contact_sales_meta_box()
5110 {
5111 check_ajax_referer( 'get_contact_sales_meta_box', 'security' );
5112
5113 global $post;
5114
5115 echo '<div class="propertyhive_meta_box">';
5116
5117 echo '<div class="options_group">';
5118
5119 $args = array(
5120 'post_type' => 'sale',
5121 'nopaging' => true,
5122 'orderby' => 'meta_value',
5123 'order' => 'DESC',
5124 'post_status' => 'publish',
5125 'meta_key' => '_sale_date_time',
5126 'meta_query' => array(
5127 array(
5128 'key' => '_applicant_contact_id',
5129 'value' => (int)$_POST['post_id']
5130 )
5131 )
5132 );
5133 $sales_query = new WP_Query( $args );
5134
5135 if ( $sales_query->have_posts() )
5136 {
5137 echo '<table style="width:100%">
5138 <thead>
5139 <tr>
5140 <th style="text-align:left;">' . __( 'Offer Date', 'propertyhive' ) . '</th>
5141 <th style="text-align:left;">' . __( 'Property', 'propertyhive' ) . '</th>
5142 <th style="text-align:left;">' . __( 'Property Owner', 'propertyhive' ) . '</th>
5143 <th style="text-align:left;">' . __( 'Offer Amount', 'propertyhive' ) . '</th>
5144 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
5145 </tr>
5146 </thead>
5147 <tbody>';
5148
5149 while ( $sales_query->have_posts() )
5150 {
5151 $sales_query->the_post();
5152
5153 $sale = new PH_Sale(get_the_ID());
5154
5155 $property = new PH_Property((int)get_post_meta(get_the_ID(), '_property_id', TRUE));
5156
5157 echo '<tr>';
5158 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_the_ID(), '') . '">' . date("jS F Y", strtotime(get_post_meta(get_the_ID(), '_sale_date_time', TRUE))) . '</a></td>';
5159 echo '<td style="text-align:left;"><a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_property_id', TRUE), '' ) . '">' . $property->get_formatted_full_address() . '</a></td>';
5160 echo '<td style="text-align:left;">';
5161
5162 $owner_contact_ids = $property->_owner_contact_id;
5163 if (
5164 ( !is_array($owner_contact_ids) && $owner_contact_ids != '' && $owner_contact_ids != 0 )
5165 ||
5166 ( is_array($owner_contact_ids) && !empty($owner_contact_ids) )
5167 )
5168 {
5169 if ( !is_array($owner_contact_ids) )
5170 {
5171 $owner_contact_ids = array($owner_contact_ids);
5172 }
5173
5174 foreach ( $owner_contact_ids as $owner_contact_id )
5175 {
5176 echo get_the_title($owner_contact_id) . '<br>';
5177 echo '<div style="color:#BBB">';
5178 echo 'T: ' . get_post_meta($owner_contact_id, '_telephone_number', TRUE) . '<br>';
5179 echo 'E: ' . get_post_meta($owner_contact_id, '_email_address', TRUE);
5180 echo '</div>';
5181 }
5182 }
5183
5184 echo '</td>';
5185 echo '<td style="text-align:left;">' . $sale->get_formatted_amount() . '</td>';
5186 echo '<td style="text-align:left;">';
5187 $status = get_post_meta(get_the_ID(), '_status', TRUE);
5188 echo ucwords(str_replace("_", " ", $status));
5189 echo '</td>';
5190 echo '</tr>';
5191 }
5192
5193 echo '
5194 </tbody>
5195 </table>
5196 <br>';
5197 }
5198 else
5199 {
5200 echo '<p>' . __( 'No sales exist for this contact', 'propertyhive') . '</p>';
5201 }
5202 wp_reset_postdata();
5203
5204 do_action('propertyhive_contact_sales_fields');
5205
5206 echo '</div>';
5207
5208 echo '</div>';
5209
5210 die();
5211 }
5212 }
5213
5214 new PH_AJAX();
5215