PluginProbe
Property Hive / 1.4.49
Property Hive v1.4.49
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.49, at includes/class-ph-ajax.php

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