PluginProbe
Property Hive / 1.4.48
Property Hive v1.4.48
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.48, at includes/class-ph-ajax.php

5,331 lines 199.9 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 .= get_the_title( (int)$property_id ) . " (" . get_permalink( (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 $from_email_address = get_option('propertyhive_email_from_address', '');
1546 if ( $from_email_address == '' )
1547 {
1548 $from_email_address = get_option('admin_email');
1549 }
1550 if ( $from_email_address == '' )
1551 {
1552 // Should never get here
1553 $from_email_address = $_POST['email_address'];
1554 }
1555
1556 $headers = array();
1557 if ( isset($_POST['name']) && ! empty($_POST['name']) )
1558 {
1559 $headers[] = 'From: ' . ph_clean( $_POST['name'] ) . ' <' . sanitize_email( $from_email_address ) . '>';
1560 }
1561 else
1562 {
1563 $headers[] = 'From: <' . sanitize_email( $from_email_address ) . '>';
1564 }
1565 if ( isset($_POST['email_address']) && sanitize_email( $_POST['email_address'] ) != '' )
1566 {
1567 $headers[] = 'Reply-To: ' . sanitize_email( $_POST['email_address'] );
1568 }
1569
1570 $to = apply_filters( 'propertyhive_property_enquiry_to', $to, $property_ids );
1571 $subject = apply_filters( 'propertyhive_property_enquiry_subject', $subject, $property_ids );
1572 $message = apply_filters( 'propertyhive_property_enquiry_body', $message, $property_ids );
1573 $headers = apply_filters( 'propertyhive_property_enquiry_headers', $headers, $property_ids );
1574
1575 $sent = wp_mail( $to, $subject, $message, $headers );
1576
1577 if ( ! $sent )
1578 {
1579 $return['success'] = false;
1580 $return['reason'] = 'nosend';
1581 $return['errors'] = $errors;
1582 }
1583 else
1584 {
1585 $return['success'] = true;
1586
1587 if ( get_option( 'propertyhive_store_property_enquiries', 'yes' ) == 'yes' )
1588 {
1589 // Now insert into enquiries section of WordPress
1590 if ( count($property_ids) == 1 )
1591 {
1592 $title = __( 'Property Enquiry', 'propertyhive' ) . ': ' . get_the_title( (int)$property_ids[0] );
1593 }
1594 else
1595 {
1596 $title = __( 'Multiple Property Enquiry', 'propertyhive' );
1597 }
1598 if ( isset($_POST['name']) && ! empty($_POST['name']) )
1599 {
1600 $title .= __( ' from ', 'propertyhive' ) . ph_clean($_POST['name']);
1601 }
1602
1603 $enquiry_post = array(
1604 'post_title' => $title,
1605 'post_content' => '',
1606 'post_type' => 'enquiry',
1607 'post_status' => 'publish',
1608 'comment_status' => 'closed',
1609 'ping_status' => 'closed',
1610 );
1611
1612 // Insert the post into the database
1613 $enquiry_post_id = wp_insert_post( $enquiry_post );
1614
1615 add_post_meta( $enquiry_post_id, '_status', 'open' );
1616 add_post_meta( $enquiry_post_id, '_source', 'website' );
1617 add_post_meta( $enquiry_post_id, '_negotiator_id', '' );
1618 add_post_meta( $enquiry_post_id, '_office_id', $office_id );
1619
1620 foreach ($_POST as $key => $value)
1621 {
1622 if ( $key == 'property_id' )
1623 {
1624 foreach ( $property_ids as $property_id )
1625 {
1626 add_post_meta( $enquiry_post_id, $key, (int)$property_id );
1627 }
1628 }
1629 else
1630 {
1631 add_post_meta( $enquiry_post_id, $key, sanitize_textarea_field($value) );
1632 }
1633 }
1634 }
1635
1636 // Send auto-responder
1637 if ( get_option( 'propertyhive_enquiry_auto_responder', '' ) == 'yes' )
1638 {
1639 // Auto-responder enabled
1640 PH()->email->send_enquiry_auto_responder( $_POST );
1641 }
1642
1643 do_action('propertyhive_property_enquiry_sent', $_POST, $to);
1644 }
1645 }
1646
1647 $this->json_headers();
1648 echo json_encode( $return );
1649
1650 // Quit out
1651 die();
1652 }
1653
1654 /**
1655 * Create contact from enquiry
1656 */
1657 public function create_contact_from_enquiry()
1658 {
1659 global $post;
1660
1661 $enquiry_post_id = ( (isset($_POST['post_id'])) ? (int)$_POST['post_id'] : '' );
1662 $nonce = ( (isset($_POST['security'])) ? ph_clean($_POST['security']) : '' );
1663
1664 if ( ! wp_verify_nonce( $nonce, 'create-content-from-enquiry-nonce-' . $enquiry_post_id ) )
1665 {
1666 // This nonce is not valid.
1667 die( json_encode( array('error' => 'Invalid nonce. Please refresh and try again') ) );
1668 }
1669
1670 $enquiry_meta = get_metadata( 'post', $enquiry_post_id );
1671
1672 $name = false;
1673 $email = false;
1674 $telephone = false;
1675
1676 foreach ($enquiry_meta as $key => $value)
1677 {
1678 if ( strpos($key, 'name') !== false )
1679 {
1680 $name = $value[0];
1681 }
1682 elseif ( strpos($key, 'email') !== false )
1683 {
1684 $email = $value[0];
1685 }
1686 elseif ( strpos($key, 'telephone') !== false )
1687 {
1688 $telephone = $value[0];
1689 }
1690 }
1691
1692 if ( $name === false || $email === false )
1693 {
1694 // This nonce is not valid.
1695 die( json_encode( array('error' => 'Name or email address not found') ) );
1696 }
1697
1698 // We've not imported this property before
1699 $postdata = array(
1700 'post_excerpt' => '',
1701 'post_content' => '',
1702 'post_title' => utf8_encode(wp_strip_all_tags( $name )),
1703 'post_status' => 'publish',
1704 'post_type' => 'contact',
1705 'ping_status' => 'closed',
1706 'comment_status' => 'closed',
1707 );
1708
1709 $contact_post_id = wp_insert_post( $postdata, true );
1710
1711 if ( is_wp_error( $contact_post_id ) )
1712 {
1713 die( json_encode( array('error' => 'Error creating contact') ) );
1714 }
1715 elseif ( $contact_post_id == 0 )
1716 {
1717 die( json_encode( array('error' => 'Error creating contact') ) );
1718 }
1719
1720 if ( $telephone !== FALSE ) {
1721 update_post_meta( $contact_post_id, '_telephone_number', ph_clean( $telephone ) );
1722 update_post_meta( $contact_post_id, '_telephone_number', ph_clean( ph_clean_telephone_number( $telephone ) ) );
1723 }
1724
1725 if ( $email !== FALSE ) { update_post_meta( $contact_post_id, '_email_address', ph_clean( $email ) ); }
1726
1727 do_action('propertyhive_create_contact_from_enquiry', $enquiry_post_id, $contact_post_id);
1728
1729 die( json_encode( array('success' => get_edit_post_link($contact_post_id, '')) ) );
1730 }
1731
1732 public function validate_save_contact()
1733 {
1734 global $post;
1735
1736 check_ajax_referer( 'contact-save-validation', 'security' );
1737
1738 $this->json_headers();
1739
1740 parse_str($_POST['form_data']);
1741
1742 $return = array('errors' => array());
1743
1744 if ( isset($_email_address) && $_email_address != '' )
1745 {
1746 $email_addresses = explode( ",", $_email_address );
1747
1748 foreach ( $email_addresses as $email_address )
1749 {
1750 $email_address = trim( $email_address );
1751
1752 if ( !is_email($email_address) )
1753 {
1754 $return['errors'][] = __( 'Email address is invalid', 'propertyhive' ) . ' - ' . $email_address;
1755 }
1756
1757 // Check it doesn't exist already
1758 $args = array(
1759 'post_type' => 'contact',
1760 'post_status' => 'any',
1761 'posts_per_page' => 1,
1762 'fields' => 'ids',
1763 'meta_query' => array(
1764 'relation' => 'OR',
1765 array(
1766 'key' => '_email_address',
1767 'value' => $email_address,
1768 'compare' => '='
1769 ),
1770 array(
1771 'key' => '_email_address',
1772 'value' => ',' . $email_address,
1773 'compare' => 'LIKE'
1774 )
1775 ,
1776 array(
1777 'key' => '_email_address',
1778 'value' => $email_address . ',',
1779 'compare' => 'LIKE'
1780 )
1781 )
1782 );
1783 if ( isset($post_ID) && $post_ID != '' )
1784 {
1785 $args['post__not_in'] = array( $post_ID );
1786 }
1787
1788 $contact_query = new WP_Query( $args );
1789
1790 if ( $contact_query->have_posts() )
1791 {
1792 while ( $contact_query->have_posts() )
1793 {
1794 $contact_query->the_post();
1795
1796 $return['errors'][] = __( 'A contact, ' . get_the_title() . ', already exists with email address', 'propertyhive' ) . ' ' . $email_address;
1797 }
1798 }
1799 }
1800 }
1801
1802 echo json_encode($return);
1803
1804 die();
1805 }
1806
1807 // Dashboard related functions
1808 public function get_news()
1809 {
1810 $this->json_headers();
1811
1812 include_once( ABSPATH . WPINC . '/feed.php' );
1813
1814 $return = array();
1815
1816 // Get a SimplePie feed object from the specified feed source.
1817 $rss = fetch_feed( 'https://wp-property-hive.com/category/property-hive-news/feed/' );
1818
1819 $maxitems = 0;
1820
1821 if ( ! is_wp_error( $rss ) ) : // Checks that the object is created correctly
1822
1823 // Figure out how many total items there are, but limit it to 5.
1824 $maxitems = $rss->get_item_quantity( 5 );
1825
1826 // Build an array of all the items, starting with element 0 (first element).
1827 $rss_items = $rss->get_items( 0, $maxitems );
1828
1829 foreach ( $rss_items as $item )
1830 {
1831 $return[] = array(
1832 'title' => esc_html( $item->get_title() ),
1833 'permalink' => esc_url( $item->get_permalink() ),
1834 'date' => $item->get_date('F d, Y')
1835 );
1836 }
1837
1838 endif;
1839
1840 echo json_encode($return);
1841
1842 die();
1843 }
1844
1845 public function get_viewings_awaiting_applicant_feedback()
1846 {
1847 global $post;
1848
1849 $this->json_headers();
1850
1851 $return = array();
1852
1853 $args = array(
1854 'post_type' => 'viewing',
1855 'fields' => 'ids',
1856 'post_status' => 'publish',
1857 'meta_query' => array(
1858 array(
1859 'key' => '_status',
1860 'value' => 'carried_out'
1861 ),
1862 array(
1863 'key' => '_feedback_status',
1864 'value' => ''
1865 )
1866 )
1867 );
1868
1869 $viewings_query = new WP_Query( $args );
1870
1871 if ( $viewings_query->have_posts() )
1872 {
1873 while ( $viewings_query->have_posts() )
1874 {
1875 $viewings_query->the_post();
1876
1877 $property_id = get_post_meta( get_the_ID(), '_property_id', TRUE );
1878 $property = new PH_Property((int)$property_id);
1879
1880 $applicant_contact_id = get_post_meta( get_the_ID(), '_applicant_contact_id', TRUE );
1881
1882 $return[] = array(
1883 'ID' => get_the_ID(),
1884 'edit_link' => get_edit_post_link( get_the_ID() ),
1885 'start_date_time' => get_post_meta( get_the_ID(), '_start_date_time', TRUE ),
1886 'start_date_time_formatted_Hi_jSFY' => date("H:i jS F Y", strtotime(get_post_meta( get_the_ID(), '_start_date_time', TRUE ))),
1887 'property_id' => $property_id,
1888 'property_address' => $property->get_formatted_full_address(),
1889 'applicant_contact_id' => $applicant_contact_id,
1890 'applicant_name' => get_the_title( $applicant_contact_id ),
1891 );
1892 }
1893 }
1894
1895 wp_reset_postdata();
1896
1897 echo json_encode($return);
1898
1899 die();
1900 }
1901
1902 public function get_my_upcoming_appointments()
1903 {
1904 global $post;
1905
1906 $this->json_headers();
1907
1908 $return = array();
1909
1910 $args = array(
1911 'post_type' => 'viewing',
1912 'fields' => 'ids',
1913 'post_status' => 'publish',
1914 'meta_query' => array(
1915 array(
1916 'key' => '_status',
1917 'value' => 'pending'
1918 ),
1919 array(
1920 'key' => '_start_date_time',
1921 'value' => date("Y-m-d H:i:s"),
1922 'compare' => '>='
1923 ),
1924 array(
1925 'key' => '_negotiator_id',
1926 'value' => get_current_user_id(),
1927 ),
1928 )
1929 );
1930
1931 $viewings_query = new WP_Query( $args );
1932
1933 if ( $viewings_query->have_posts() )
1934 {
1935 while ( $viewings_query->have_posts() )
1936 {
1937 $viewings_query->the_post();
1938
1939 $property_id = get_post_meta( get_the_ID(), '_property_id', TRUE );
1940 $property = new PH_Property((int)$property_id);
1941
1942 $return[] = array(
1943 'ID' => get_the_ID(),
1944 'edit_link' => get_edit_post_link( get_the_ID() ),
1945 'start_date_time' => get_post_meta( get_the_ID(), '_start_date_time', TRUE ),
1946 'start_date_time_formatted_Hi_jSFY' => date("H:i jS F Y", strtotime(get_post_meta( get_the_ID(), '_start_date_time', TRUE ))),
1947 'start_date_time_timestamp' => strtotime(get_post_meta( get_the_ID(), '_start_date_time', TRUE )),
1948 'title' => 'Viewing at ' . $property->get_formatted_full_address(),
1949 );
1950 }
1951 }
1952
1953 wp_reset_postdata();
1954
1955 $args = array(
1956 'post_type' => 'appraisal',
1957 'fields' => 'ids',
1958 'post_status' => 'publish',
1959 'meta_query' => array(
1960 array(
1961 'key' => '_status',
1962 'value' => 'pending'
1963 ),
1964 array(
1965 'key' => '_start_date_time',
1966 'value' => date("Y-m-d H:i:s"),
1967 'compare' => '>='
1968 ),
1969 array(
1970 'key' => '_negotiator_id',
1971 'value' => get_current_user_id(),
1972 ),
1973 )
1974 );
1975
1976 $appraisals_query = new WP_Query( $args );
1977
1978 if ( $appraisals_query->have_posts() )
1979 {
1980 while ( $appraisals_query->have_posts() )
1981 {
1982 $appraisals_query->the_post();
1983
1984 $appraisal = new PH_Appraisal(get_the_ID());
1985
1986 $return[] = array(
1987 'ID' => get_the_ID(),
1988 'edit_link' => get_edit_post_link( get_the_ID() ),
1989 'start_date_time' => get_post_meta( get_the_ID(), '_start_date_time', TRUE ),
1990 'start_date_time_formatted_Hi_jSFY' => date("H:i jS F Y", strtotime(get_post_meta( get_the_ID(), '_start_date_time', TRUE ))),
1991 'start_date_time_timestamp' => strtotime(get_post_meta( get_the_ID(), '_start_date_time', TRUE )),
1992 'title' => 'Appraisal at ' . $appraisal->get_formatted_full_address(),
1993 );
1994 }
1995 }
1996
1997 wp_reset_postdata();
1998
1999 $return = apply_filters( 'propertyhive_dashboard_my_upcoming_appointments', $return );
2000
2001 if ( !empty($return) )
2002 {
2003 $sort = array();
2004 foreach ($return as $key => $part) {
2005 $sort[$key] = strtotime($part['start_date_time']);
2006 }
2007 array_multisort($sort, SORT_ASC, $return);
2008
2009 $return = array_slice($return, 0, 10);
2010 }
2011
2012 echo json_encode($return);
2013
2014 die();
2015 }
2016
2017 public function get_appraisal_details_meta_box()
2018 {
2019 global $post;
2020
2021 check_ajax_referer( 'appraisal-details-meta-box', 'security' );
2022
2023 $post = get_post((int)$_POST['appraisal_id']);
2024
2025 $appraisal = new PH_Appraisal((int)$_POST['appraisal_id']);
2026
2027 echo '<div class="propertyhive_meta_box">';
2028
2029 echo '<div class="options_group">';
2030
2031 echo '<p class="form-field">
2032
2033 <label for="">' . __('Status', 'propertyhive') . '</label>
2034
2035 ' . ucwords(str_replace("_", " ", $appraisal->status));
2036
2037 echo '</p>';
2038
2039 if ( $appraisal->status == 'cancelled' )
2040 {
2041 $args = array(
2042 'id' => '_cancelled_reason',
2043 'label' => __( 'Reason Cancelled', 'propertyhive' ),
2044 'desc_tip' => false,
2045 'class' => '',
2046 'value' => $appraisal->cancelled_reason,
2047 'custom_attributes' => array(
2048 'style' => 'width:95%; max-width:500px;'
2049 )
2050 );
2051 propertyhive_wp_textarea_input( $args );
2052 }
2053
2054 if ( $appraisal->status == 'carried_out' || $appraisal->status == 'won' || $appraisal->status == 'instructed' )
2055 {
2056 if ( $appraisal->department == 'residential-sales' )
2057 {
2058 $args = array(
2059 'id' => '_valued_price',
2060 'label' => __( 'Valued Price', 'propertyhive' ) . ' (&pound;)',
2061 'desc_tip' => false,
2062 'class' => 'short',
2063 'value' => $appraisal->valued_price,
2064 );
2065 propertyhive_wp_text_input( $args );
2066 }
2067 elseif ( $appraisal->department == 'residential-lettings' )
2068 {
2069 $rent_frequency = $appraisal->valued_rent_frequency;
2070
2071 echo '<p class="form-field">
2072
2073 <label for="">' . __('Valued Rent', 'propertyhive') . ' (&pound;)</label>
2074
2075 <input type="text" class="" name="_valued_rent" id="_valued_rent" value="' . $appraisal->valued_rent . '" placeholder="" style="width:10%; min-width:100px;">
2076
2077 <select id="_valued_rent_frequency" name="_valued_rent_frequency" class="select" style="width:auto">
2078 <option value="pppw"' . ( ($rent_frequency == 'pppw') ? ' selected' : '') . '>' . __('Per Person Per Week', 'propertyhive') . '</option>
2079 <option value="pw"' . ( ($rent_frequency == 'pw') ? ' selected' : '') . '>' . __('Per Week', 'propertyhive') . '</option>
2080 <option value="pcm"' . ( ($rent_frequency == 'pcm' || $rent_frequency == '') ? ' selected' : '') . '>' . __('Per Calendar Month', 'propertyhive') . '</option>
2081 <option value="pq"' . ( ($rent_frequency == 'pq') ? ' selected' : '') . '>' . __('Per Quarter', 'propertyhive') . '</option>
2082 <option value="pa"' . ( ($rent_frequency == 'pa') ? ' selected' : '') . '>' . __('Per Annum', 'propertyhive') . '</option>
2083 </select>
2084
2085 </p>';
2086 }
2087 }
2088
2089 if ( $appraisal->status == 'lost' )
2090 {
2091 $args = array(
2092 'id' => '_lost_reason',
2093 'label' => __( 'Reason Lost', 'propertyhive' ),
2094 'desc_tip' => false,
2095 'class' => '',
2096 'value' => $appraisal->lost_reason,
2097 'custom_attributes' => array(
2098 'style' => 'width:95%; max-width:500px;'
2099 )
2100 );
2101 propertyhive_wp_textarea_input( $args );
2102 }
2103
2104 do_action('propertyhive_appraisal_details_fields');
2105
2106 echo '</div>';
2107
2108 echo '</div>';
2109
2110 die();
2111 }
2112
2113 public function get_appraisal_actions()
2114 {
2115 check_ajax_referer( 'appraisal-actions', 'security' );
2116
2117 $post_id = (int)$_POST['appraisal_id'];
2118
2119 $status = get_post_meta( $post_id, '_status', TRUE );
2120 $department = get_post_meta( $post_id, '_department', TRUE );
2121
2122 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_appraisal_actions_meta_box">
2123
2124 <div class="options_group" style="padding-top:8px;">';
2125
2126 $show_cancelled_meta_boxes = false;
2127 $show_carried_out_meta_boxes = false;
2128 $show_instructed_meta_boxes = false;
2129 $show_lost_meta_boxes = false;
2130
2131 $actions = array();
2132
2133 if ( $status == 'pending' )
2134 {
2135 /*$actions[] = '<a
2136 href=""
2137 class="button"
2138 style="width:100%; margin-bottom:7px; text-align:center"
2139 >' . __('Print Market Appraisal Sheet', 'propertyhive') . '</a>';
2140 if ( get_option('propertyhive_module_disabled_contacts', '') != 'yes' )
2141 {
2142 $actions[] = '<a
2143 href=""
2144 class="button"
2145 style="width:100%; margin-bottom:7px; text-align:center"
2146 >' . __('Run Potential Applicant Match', 'propertyhive') . '</a>';
2147 }*/
2148 $actions[] = '<a
2149 href="#action_panel_appraisal_carried_out"
2150 class="button button-success appraisal-action"
2151 style="width:100%; margin-bottom:7px; text-align:center"
2152 >' . __('Appraisal Carried Out', 'propertyhive') . '</a>';
2153 $actions[] = '<a
2154 href="#action_panel_appraisal_cancelled"
2155 class="button appraisal-action"
2156 style="width:100%; margin-bottom:7px; text-align:center"
2157 >' . __('Appraisal Cancelled', 'propertyhive') . '</a>';
2158
2159 $show_cancelled_meta_boxes = true;
2160 $show_carried_out_meta_boxes = true;
2161 }
2162
2163 if ( $status == 'carried_out' )
2164 {
2165 $actions[] = '<a
2166 href="#action_panel_appraisal_won"
2167 class="button button-success appraisal-action"
2168 style="width:100%; margin-bottom:7px; text-align:center"
2169 >' . __('Appraisal Won', 'propertyhive') . '</a>';
2170
2171 $actions[] = '<a
2172 href="#action_panel_appraisal_lost"
2173 class="button button-danger appraisal-action"
2174 style="width:100%; margin-bottom:7px; text-align:center"
2175 >' . __('Appraisal Lost', 'propertyhive') . '</a>';
2176
2177 $show_lost_meta_boxes = true;
2178 }
2179
2180 if ( $status == 'won' )
2181 {
2182 $actions[] = '<a
2183 href="#action_panel_appraisal_instruct"
2184 class="button button-success appraisal-action"
2185 style="width:100%; margin-bottom:7px; text-align:center"
2186 >' . __('Instruct Property', 'propertyhive') . '</a>';
2187
2188 $show_instructed_meta_boxes = true;
2189 }
2190
2191 if ( $status == 'won' || $status == 'lost' )
2192 {
2193 $actions[] = '<a
2194 href="#action_panel_appraisal_revert_carried_out"
2195 class="button appraisal-action"
2196 style="width:100%; margin-bottom:7px; text-align:center"
2197 >' . __('Revert To Carried Out', 'propertyhive') . '</a>';
2198 }
2199
2200 if ( $status == 'instructed' )
2201 {
2202 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
2203
2204 $actions[] = '<a
2205 href="' . get_edit_post_link($property_id) . '"
2206 class="button"
2207 style="width:100%; margin-bottom:7px; text-align:center"
2208 >' . __('View Instructed Property', 'propertyhive') . '</a>';
2209
2210 /*$actions[] = '<a
2211 href="#action_panel_appraisal_revert_won"
2212 class="button appraisal-action"
2213 style="width:100%; margin-bottom:7px; text-align:center"
2214 >' . __('Revert To Won', 'propertyhive') . '</a>';*/
2215 }
2216
2217 if ( $status == 'carried_out' || $status == 'cancelled' )
2218 {
2219 $actions[] = '<a
2220 href="#action_panel_appraisal_revert_pending"
2221 class="button appraisal-action"
2222 style="width:100%; margin-bottom:7px; text-align:center"
2223 >' . __('Revert To Pending', 'propertyhive') . '</a>';
2224 }
2225
2226 $actions = apply_filters( 'propertyhive_admin_appraisal_actions', $actions, $post_id );
2227
2228 if ( !empty($actions) )
2229 {
2230 echo implode("", $actions);
2231 }
2232 else
2233 {
2234 echo '<div style="text-align:center">' . __( 'No actions to display', 'propertyhive' ) . '</div>';
2235 }
2236
2237 echo '</div>
2238
2239 </div>';
2240
2241 if ( $show_cancelled_meta_boxes )
2242 {
2243 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_cancelled" style="display:none;">
2244
2245 <div class="options_group" style="padding-top:8px;">
2246
2247 <div class="form-field">
2248
2249 <label for="_appraisal_cancelled_reason">' . __( 'Reason Cancelled', 'propertyhive' ) . '</label>
2250
2251 <textarea id="_cancelled_reason" name="_cancelled_reason" style="width:100%;">' . get_post_meta( $post_id, '_cancelled_reason', TRUE ) . '</textarea>
2252
2253 </div>
2254
2255 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2256 <a class="button button-primary cancelled-reason-action-submit" href="#">' . __( 'Save', 'propertyhive' ) . '</a>
2257
2258 </div>
2259
2260 </div>';
2261 }
2262
2263 if ( $show_carried_out_meta_boxes )
2264 {
2265 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_carried_out" style="display:none;">
2266
2267 <div class="options_group" style="padding-top:8px;">';
2268
2269 if ( $department == 'residential-sales' )
2270 {
2271 echo '<div class="form-field">
2272
2273 <label for="_price">' . __( 'Valued Price (&pound;)', 'propertyhive' ) . '</label>
2274
2275 <input type="text" id="_price" name="_price" style="width:100%;" value="' . get_post_meta( $post_id, '_valued_price', TRUE ) . '">
2276
2277 </div>';
2278 }
2279 else
2280 {
2281 $rent_frequency = get_post_meta( $post_id, '_valued_rent_frequency', TRUE );
2282 echo '<div class="form-field">
2283
2284 <label for="_price">' . __( 'Valued Rent (&pound;)', 'propertyhive' ) . '</label>
2285
2286 <input type="text" id="_price" name="_price" style="width:100%;" value="' . get_post_meta( $post_id, '_valued_rent', TRUE ) . '">
2287
2288 <select id="_rent_frequency" name="_rent_frequency" class="select" style="width:100%">
2289 <option value="pppw"' . ( ($rent_frequency == 'pppw') ? ' selected' : '') . '>' . __('Per Person Per Week', 'propertyhive') . '</option>
2290 <option value="pw"' . ( ($rent_frequency == 'pw') ? ' selected' : '') . '>' . __('Per Week', 'propertyhive') . '</option>
2291 <option value="pcm"' . ( ($rent_frequency == 'pcm' || $rent_frequency == '') ? ' selected' : '') . '>' . __('Per Calendar Month', 'propertyhive') . '</option>
2292 <option value="pq"' . ( ($rent_frequency == 'pq') ? ' selected' : '') . '>' . __('Per Quarter', 'propertyhive') . '</option>
2293 <option value="pa"' . ( ($rent_frequency == 'pa') ? ' selected' : '') . '>' . __('Per Annum', 'propertyhive') . '</option>
2294 </select>
2295
2296 </div>';
2297 }
2298
2299 echo '<a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2300 <a class="button button-primary carried-out-action-submit" href="#">' . __( 'Save', 'propertyhive' ) . '</a>
2301
2302 </div>
2303
2304 </div>';
2305 }
2306
2307 if ( $show_instructed_meta_boxes )
2308 {
2309 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_instruct" style="display:none;">
2310
2311 <div class="options_group" style="padding-top:8px;">';
2312
2313 echo '<div style="margin-bottom:13px;">' . __( 'Upon instruction a new property record will be created within the \'Properties\' area.', 'propertyhive' ) . '</div>';
2314
2315 echo '<a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2316 <a class="button button-primary instructed-action-submit" href="#">' . __( 'OK', 'propertyhive' ) . '</a>
2317
2318 </div>
2319
2320 </div>';
2321 }
2322
2323 if ( $show_lost_meta_boxes )
2324 {
2325 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_appraisal_lost" style="display:none;">
2326
2327 <div class="options_group" style="padding-top:8px;">
2328
2329 <div class="form-field">
2330
2331 <label for="_lost_reason">' . __( 'Reason Lost', 'propertyhive' ) . '</label>
2332
2333 <textarea id="_lost_reason" name="_lost_reason" style="width:100%;">' . get_post_meta( $post_id, '_lost_reason', TRUE ) . '</textarea>
2334
2335 </div>
2336
2337 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
2338 <a class="button button-primary lost-reason-action-submit" href="#">' . wp_kses_post( __( 'Save Reason Lost', 'propertyhive' ) ) . '</a>
2339
2340 </div>
2341
2342 </div>';
2343 }
2344
2345 die();
2346 }
2347
2348 public function appraisal_carried_out()
2349 {
2350 check_ajax_referer( 'appraisal-actions', 'security' );
2351
2352 $post_id = (int)$_POST['appraisal_id'];
2353
2354 $status = get_post_meta( $post_id, '_status', TRUE );
2355
2356 if ( $status == 'pending' )
2357 {
2358 update_post_meta( $post_id, '_status', 'carried_out' );
2359
2360 if ( get_post_meta( $post_id, '_department', TRUE ) == 'residential-sales' )
2361 {
2362 $price = preg_replace("/[^0-9]/", '', ph_clean($_POST['price']));
2363 update_post_meta( $post_id, '_valued_price', $price );
2364 update_post_meta( $post_id, '_valued_price_actual', $price );
2365 }
2366 elseif ( get_post_meta( $post_id, '_department', TRUE ) == 'residential-lettings' )
2367 {
2368 $rent = preg_replace("/[^0-9]/", '', ph_clean($_POST['rent']));
2369 update_post_meta( $post_id, '_valued_rent', $rent );
2370
2371 update_post_meta( $post_id, '_valued_rent_frequency', ph_clean($_POST['rent_frequency']) );
2372
2373 switch (ph_clean($_POST['rent_frequency']))
2374 {
2375 case "pppw":
2376 {
2377 $bedrooms = get_post_meta( $postID, '_bedrooms', true );
2378 if ( ( $bedrooms !== FALSE && $bedrooms != 0 && $bedrooms != '' ) && apply_filters( 'propertyhive_pppw_to_consider_bedrooms', true ) == true )
2379 {
2380 $price = (($rent * 52) / 12) * $bedrooms;
2381 }
2382 else
2383 {
2384 $price = ($rent * 52) / 12;
2385 }
2386 break;
2387 }
2388 case "pw": { $price = ($rent * 52) / 12; break; }
2389 case "pcm": { $price = $rent; break; }
2390 case "pq": { $price = ($rent * 4) / 12; break; }
2391 case "pa": { $price = ($rent / 12); break; }
2392 }
2393 update_post_meta( $post_id, '_valued_price_actual', $price );
2394 }
2395
2396 $current_user = wp_get_current_user();
2397
2398 // Add note/comment to appraisal
2399 $comment = array(
2400 'note_type' => 'action',
2401 'action' => 'appraisal_carried_out',
2402 );
2403
2404 $data = array(
2405 'comment_post_ID' => $post_id,
2406 'comment_author' => $current_user->display_name,
2407 'comment_author_email' => 'propertyhive@noreply.com',
2408 'comment_author_url' => '',
2409 'comment_date' => date("Y-m-d H:i:s"),
2410 'comment_content' => serialize($comment),
2411 'comment_approved' => 1,
2412 'comment_type' => 'propertyhive_note',
2413 );
2414 $comment_id = wp_insert_comment( $data );
2415 }
2416
2417 die();
2418 }
2419
2420 public function appraisal_cancelled()
2421 {
2422 check_ajax_referer( 'appraisal-actions', 'security' );
2423
2424 $post_id = (int)$_POST['appraisal_id'];
2425
2426 $status = get_post_meta( $post_id, '_status', TRUE );
2427
2428 if ( $status == 'pending' )
2429 {
2430 update_post_meta( $post_id, '_status', 'cancelled' );
2431 update_post_meta( $post_id, '_cancelled_reason', sanitize_textarea_field( $_POST['cancelled_reason'] ) );
2432
2433 $current_user = wp_get_current_user();
2434
2435 // Add note/comment to appraisal
2436 $comment = array(
2437 'note_type' => 'action',
2438 'action' => 'appraisal_cancelled',
2439 );
2440
2441 $data = array(
2442 'comment_post_ID' => $post_id,
2443 'comment_author' => $current_user->display_name,
2444 'comment_author_email' => 'propertyhive@noreply.com',
2445 'comment_author_url' => '',
2446 'comment_date' => date("Y-m-d H:i:s"),
2447 'comment_content' => serialize($comment),
2448 'comment_approved' => 1,
2449 'comment_type' => 'propertyhive_note',
2450 );
2451 $comment_id = wp_insert_comment( $data );
2452 }
2453
2454 die();
2455 }
2456
2457 public function appraisal_won()
2458 {
2459 check_ajax_referer( 'appraisal-actions', 'security' );
2460
2461 $post_id = (int)$_POST['appraisal_id'];
2462
2463 $status = get_post_meta( $post_id, '_status', TRUE );
2464
2465 if ( $status == 'carried_out' )
2466 {
2467 update_post_meta( $post_id, '_status', 'won' );
2468
2469 $current_user = wp_get_current_user();
2470
2471 // Add note/comment to appraisal
2472 $comment = array(
2473 'note_type' => 'action',
2474 'action' => 'appraisal_won',
2475 );
2476
2477 $data = array(
2478 'comment_post_ID' => $post_id,
2479 'comment_author' => $current_user->display_name,
2480 'comment_author_email' => 'propertyhive@noreply.com',
2481 'comment_author_url' => '',
2482 'comment_date' => date("Y-m-d H:i:s"),
2483 'comment_content' => serialize($comment),
2484 'comment_approved' => 1,
2485 'comment_type' => 'propertyhive_note',
2486 );
2487 $comment_id = wp_insert_comment( $data );
2488 }
2489
2490 die();
2491 }
2492
2493 public function appraisal_lost_reason()
2494 {
2495 check_ajax_referer( 'appraisal-actions', 'security' );
2496
2497 $post_id = (int)$_POST['appraisal_id'];
2498
2499 $status = get_post_meta( $post_id, '_status', TRUE );
2500
2501 if ( $status == 'carried_out' )
2502 {
2503 update_post_meta( $post_id, '_status', 'lost' );
2504 update_post_meta( $post_id, '_lost_reason', sanitize_textarea_field( $_POST['lost_reason'] ) );
2505
2506 $current_user = wp_get_current_user();
2507
2508 // Add note/comment to appraisal
2509 $comment = array(
2510 'note_type' => 'action',
2511 'action' => 'appraisal_lost',
2512 );
2513
2514 $data = array(
2515 'comment_post_ID' => $post_id,
2516 'comment_author' => $current_user->display_name,
2517 'comment_author_email' => 'propertyhive@noreply.com',
2518 'comment_author_url' => '',
2519 'comment_date' => date("Y-m-d H:i:s"),
2520 'comment_content' => serialize($comment),
2521 'comment_approved' => 1,
2522 'comment_type' => 'propertyhive_note',
2523 );
2524 $comment_id = wp_insert_comment( $data );
2525 }
2526
2527 die();
2528 }
2529
2530 public function appraisal_instructed()
2531 {
2532 check_ajax_referer( 'appraisal-actions', 'security' );
2533
2534 $post_id = (int)$_POST['appraisal_id'];
2535
2536 $status = get_post_meta( $post_id, '_status', TRUE );
2537
2538 if ( $status == 'won' )
2539 {
2540 // Create property record and copy everything over
2541 $display_address = array();
2542 if ( get_post_meta( $post_id, '_address_street', TRUE ) != '' )
2543 {
2544 $display_address[] = get_post_meta( $post_id, '_address_street', TRUE );
2545 }
2546 if ( get_post_meta( $post_id, '_address_two', TRUE ) != '' )
2547 {
2548 $display_address[] = get_post_meta( $post_id, '_address_two', TRUE );
2549 }
2550 if ( get_post_meta( $post_id, '_address_three', TRUE ) != '' )
2551 {
2552 $display_address[] = get_post_meta( $post_id, '_address_three', TRUE );
2553 }
2554 else
2555 {
2556 if ( get_post_meta( $post_id, '_address_four', TRUE ) != '' )
2557 {
2558 $display_address[] = get_post_meta( $post_id, '_address_four', TRUE );
2559 }
2560 }
2561 $display_address = implode(", ", $display_address);
2562
2563 $property_post = array(
2564 'post_title' => ph_clean($display_address),
2565 'post_content' => '',
2566 'post_type' => 'property',
2567 'post_status' => 'publish',
2568 'comment_status' => 'closed',
2569 'ping_status' => 'closed',
2570 );
2571
2572 // Insert the post into the database
2573 $property_post_id = wp_insert_post( $property_post );
2574
2575 if ( is_wp_error($property_post_id) || $property_post_id == 0 )
2576 {
2577 // Failed. Don't really know at the moment how to handle this
2578
2579 $return = array('error' => 'Failed to create property post. Please try again');
2580 //echo json_encode( $return );
2581 //die();
2582 }
2583 else
2584 {
2585 // Successfully added property post
2586
2587 $department = get_post_meta( $post_id, '_department', TRUE );
2588
2589 update_post_meta( $property_post_id, '_address_name_number', get_post_meta( $post_id, '_address_name_number', TRUE ) );
2590 update_post_meta( $property_post_id, '_address_street', get_post_meta( $post_id, '_address_street', TRUE ) );
2591 update_post_meta( $property_post_id, '_address_two', get_post_meta( $post_id, '_address_two', TRUE ) );
2592 update_post_meta( $property_post_id, '_address_three', get_post_meta( $post_id, '_address_three', TRUE ) );
2593 update_post_meta( $property_post_id, '_address_four', get_post_meta( $post_id, '_address_four', TRUE ) );
2594 update_post_meta( $property_post_id, '_address_postcode', get_post_meta( $post_id, '_address_postcode', TRUE ) );
2595 update_post_meta( $property_post_id, '_address_country', get_post_meta( $post_id, '_address_country', TRUE ) );
2596
2597 if ( ini_get('allow_url_fopen') )
2598 {
2599 // No lat lng. Let's get it
2600 $address_to_geocode = array();
2601 if ( get_post_meta( $post_id, '_address_name_number', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_name_number', TRUE ); }
2602 if ( get_post_meta( $post_id, '_address_street', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_street', TRUE ); }
2603 if ( get_post_meta( $post_id, '_address_two', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_two', TRUE ); }
2604 if ( get_post_meta( $post_id, '_address_three', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_three', TRUE ); }
2605 if ( get_post_meta( $post_id, '_address_four', TRUE ) != '' ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_four', TRUE ); }
2606 if ( get_post_meta( $post_id, '_address_postcode', TRUE ) ) { $address_to_geocode[] = get_post_meta( $post_id, '_address_postcode', TRUE ); }
2607
2608 $country = get_option( 'propertyhive_default_country', 'GB' );
2609 $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
2610
2611 $api_key = get_option('propertyhive_google_maps_api_key', '');
2612 if ( $api_key != '' ) { $request_url .= "&key=" . $api_key; }
2613
2614 $response = wp_remote_get($request_url);
2615
2616 if ( is_array( $response ) && !is_wp_error( $response ) )
2617 {
2618 $header = $response['headers']; // array of http header lines
2619 $body = $response['body']; // use the content
2620
2621 $xml = simplexml_load_string($body);
2622
2623 if ( $xml !== FALSE )
2624 {
2625 $status = $xml->status; // Get the request status as google's api can return several responses
2626
2627 if ($status == "OK")
2628 {
2629 //request returned completed time to get lat / lng for storage
2630 $lat = (string)$xml->result->geometry->location->lat;
2631 $lng = (string)$xml->result->geometry->location->lng;
2632
2633 if ($lat != '' && $lng != '')
2634 {
2635 update_post_meta( $post_id, '_latitude', $lat );
2636 update_post_meta( $post_id, '_longitude', $lng );
2637 }
2638 }
2639 }
2640 }
2641 }
2642
2643 update_post_meta( $property_post_id, '_department', $department );
2644
2645 switch ( $department )
2646 {
2647 case "residential-sales":
2648 {
2649 update_post_meta( $property_post_id, '_currency', 'GBP' );
2650
2651 $price = preg_replace("/[^0-9]/", '', get_post_meta( $post_id, '_valued_price', TRUE ));
2652 update_post_meta( $property_post_id, '_price', $price );
2653
2654 break;
2655 }
2656 case "residential-lettings":
2657 {
2658 update_post_meta( $property_post_id, '_currency', 'GBP' );
2659
2660 $rent = preg_replace("/[^0-9.]/", '', get_post_meta( $post_id, '_valued_rent', TRUE ));
2661 update_post_meta( $property_post_id, '_rent', $rent );
2662 update_post_meta( $property_post_id, '_rent_frequency', get_post_meta( $post_id, '_valued_rent_frequency', TRUE ) );
2663
2664 break;
2665 }
2666 }
2667
2668 // Store price in common currency (GBP) used for ordering
2669 $ph_countries = new PH_Countries();
2670 $ph_countries->update_property_price_actual( $property_post_id );
2671
2672 update_post_meta( $property_post_id, '_bedrooms', get_post_meta( $post_id, '_bedrooms', TRUE ) );
2673 update_post_meta( $property_post_id, '_bathrooms', get_post_meta( $post_id, '_bathrooms', TRUE ) );
2674 update_post_meta( $property_post_id, '_reception_rooms', get_post_meta( $post_id, '_reception_rooms', TRUE ) );
2675
2676 update_post_meta( $property_post_id, '_on_market', '' );
2677 update_post_meta( $property_post_id, '_featured', '' );
2678
2679 // Taxonomies
2680 wp_set_object_terms( $property_post_id, wp_get_object_terms( $post_id, 'property_type', array("fields" => "ids") ), 'property_type' );
2681 wp_set_object_terms( $property_post_id, wp_get_object_terms( $post_id, 'parking', array("fields" => "ids") ), 'parking' );
2682 wp_set_object_terms( $property_post_id, wp_get_object_terms( $post_id, 'outside_space', array("fields" => "ids") ), 'outside_space' );
2683
2684 $owner_contact_ids = get_post_meta( $post_id, '_property_owner_contact_id', TRUE );
2685 if ( !is_array($owner_contact_ids) )
2686 {
2687 $owner_contact_ids = array($owner_contact_ids);
2688 }
2689 update_post_meta( $property_post_id, '_owner_contact_id', $owner_contact_ids );
2690
2691 // Make updates to appraisal
2692 update_post_meta( $post_id, '_status', 'instructed' );
2693 update_post_meta( $post_id, '_property_id', $property_post_id );
2694
2695 //Update owner(s)
2696 foreach ( $owner_contact_ids as $owner_contact_id )
2697 {
2698 $contact_types = get_post_meta( $owner_contact_id, '_contact_types', TRUE );
2699
2700 if ( !in_array('owner', $contact_types) )
2701 {
2702 $contact_types[] = 'owner';
2703 }
2704
2705 // get appraisals where this is the owner and where not instructed
2706 $args = array(
2707 'post_type' => 'appraisal',
2708 'nopaging' => true,
2709 'meta_query' => array(
2710 array(
2711 'key' => '_property_owner_contact_id',
2712 'value' => $post->ID,
2713 'compare' => '='
2714 ),
2715 array(
2716 'key' => '_status',
2717 'value' => 'instructed',
2718 'compare' => '!='
2719 )
2720 )
2721 );
2722
2723 $appraisal_query = new WP_Query($args);
2724
2725 if (!$appraisal_query->have_posts())
2726 {
2727 // no longer a potential owner.
2728 if (($key = array_search('potentialowner', $contact_types)) !== false)
2729 {
2730 unset($contact_types[$key]);
2731 }
2732 }
2733 wp_reset_postdata();
2734
2735 update_post_meta( $owner_contact_id, '_contact_types', $contact_types );
2736 }
2737
2738 $current_user = wp_get_current_user();
2739
2740 // Add note/comment to appraisal
2741 $comment = array(
2742 'note_type' => 'action',
2743 'action' => 'appraisal_instructed',
2744 );
2745
2746 $data = array(
2747 'comment_post_ID' => $post_id,
2748 'comment_author' => $current_user->display_name,
2749 'comment_author_email' => 'propertyhive@noreply.com',
2750 'comment_author_url' => '',
2751 'comment_date' => date("Y-m-d H:i:s"),
2752 'comment_content' => serialize($comment),
2753 'comment_approved' => 1,
2754 'comment_type' => 'propertyhive_note',
2755 );
2756 $comment_id = wp_insert_comment( $data );
2757 }
2758 }
2759
2760 die();
2761 }
2762
2763 public function appraisal_revert_pending()
2764 {
2765 check_ajax_referer( 'appraisal-actions', 'security' );
2766
2767 $post_id = (int)$_POST['appraisal_id'];
2768
2769 $status = get_post_meta( $post_id, '_status', TRUE );
2770
2771 if ( $status == 'carried_out' || $status == 'cancelled' )
2772 {
2773 update_post_meta( $post_id, '_status', 'pending' );
2774
2775 $current_user = wp_get_current_user();
2776
2777 // Add note/comment to appraisal
2778 $comment = array(
2779 'note_type' => 'action',
2780 'action' => 'appraisal_revert_pending',
2781 );
2782
2783 $data = array(
2784 'comment_post_ID' => $post_id,
2785 'comment_author' => $current_user->display_name,
2786 'comment_author_email' => 'propertyhive@noreply.com',
2787 'comment_author_url' => '',
2788 'comment_date' => date("Y-m-d H:i:s"),
2789 'comment_content' => serialize($comment),
2790 'comment_approved' => 1,
2791 'comment_type' => 'propertyhive_note',
2792 );
2793 $comment_id = wp_insert_comment( $data );
2794 }
2795
2796 die();
2797 }
2798
2799 public function appraisal_revert_carried_out()
2800 {
2801 check_ajax_referer( 'appraisal-actions', 'security' );
2802
2803 $post_id = (int)$_POST['appraisal_id'];
2804
2805 $status = get_post_meta( $post_id, '_status', TRUE );
2806
2807 if ( $status == 'won' || $status == 'lost' )
2808 {
2809 update_post_meta( $post_id, '_status', 'carried_out' );
2810
2811 $current_user = wp_get_current_user();
2812
2813 // Add note/comment to appraisal
2814 $comment = array(
2815 'note_type' => 'action',
2816 'action' => 'appraisal_revert_carried_out',
2817 );
2818
2819 $data = array(
2820 'comment_post_ID' => $post_id,
2821 'comment_author' => $current_user->display_name,
2822 'comment_author_email' => 'propertyhive@noreply.com',
2823 'comment_author_url' => '',
2824 'comment_date' => date("Y-m-d H:i:s"),
2825 'comment_content' => serialize($comment),
2826 'comment_approved' => 1,
2827 'comment_type' => 'propertyhive_note',
2828 );
2829 $comment_id = wp_insert_comment( $data );
2830 }
2831
2832 die();
2833 }
2834
2835 public function appraisal_revert_won()
2836 {
2837 check_ajax_referer( 'appraisal-actions', 'security' );
2838
2839 $post_id = (int)$_POST['appraisal_id'];
2840
2841 $status = get_post_meta( $post_id, '_status', TRUE );
2842
2843 if ( $status == 'instructed' )
2844 {
2845 update_post_meta( $post_id, '_status', 'won' );
2846
2847 $current_user = wp_get_current_user();
2848
2849 // Add note/comment to appraisal
2850 $comment = array(
2851 'note_type' => 'action',
2852 'action' => 'appraisal_revert_won',
2853 );
2854
2855 $data = array(
2856 'comment_post_ID' => $post_id,
2857 'comment_author' => $current_user->display_name,
2858 'comment_author_email' => 'propertyhive@noreply.com',
2859 'comment_author_url' => '',
2860 'comment_date' => date("Y-m-d H:i:s"),
2861 'comment_content' => serialize($comment),
2862 'comment_approved' => 1,
2863 'comment_type' => 'propertyhive_note',
2864 );
2865 $comment_id = wp_insert_comment( $data );
2866 }
2867
2868 die();
2869 }
2870
2871 // Viewing related functions
2872 public function book_viewing_property()
2873 {
2874 check_ajax_referer( 'book-viewing', 'security' );
2875
2876 $this->json_headers();
2877
2878 // TO DO: Should do validation on server side also
2879 if (empty($_POST['property_id']))
2880 {
2881 $return = array('error' => 'No property selected');
2882 echo json_encode( $return );
2883 die();
2884 }
2885
2886 $property = new PH_Property((int)$_POST['property_id']);
2887
2888 $applicant_contact_ids = array();
2889
2890 // Create applicant record if required
2891 if (empty($_POST['applicant_ids']) && !empty($_POST['applicant_name']))
2892 {
2893 // Need to create contact/applicant
2894 $contact_post = array(
2895 'post_title' => ph_clean($_POST['applicant_name']),
2896 'post_content' => '',
2897 'post_type' => 'contact',
2898 'post_status' => 'publish',
2899 'comment_status' => 'closed',
2900 'ping_status' => 'closed',
2901 );
2902
2903 // Insert the post into the database
2904 $contact_post_id = wp_insert_post( $contact_post );
2905
2906 if ( is_wp_error($contact_post_id) || $contact_post_id == 0 )
2907 {
2908 $return = array('error' => 'Failed to create contact post. Please try again');
2909 echo json_encode( $return );
2910 die();
2911 }
2912
2913 update_post_meta( $contact_post_id, '_contact_types', array('applicant') );
2914
2915 update_post_meta( $contact_post_id, '_applicant_profiles', 1 );
2916 update_post_meta( $contact_post_id, '_applicant_profile_0', array( 'department' => $property->department, 'send_matching_properties' => '' ) );
2917
2918 $applicant_contact_ids[] = $contact_post_id;
2919 }
2920
2921 if (!empty($_POST['applicant_ids']) && empty($_POST['applicant_name']))
2922 {
2923 // This is an existing contact
2924 if ( !is_array($_POST['applicant_ids']) )
2925 {
2926 $_POST['applicant_ids'] = array(ph_clean($_POST['applicant_ids']));
2927 }
2928
2929 foreach ( $_POST['applicant_ids'] as $applicant_id )
2930 {
2931 $applicant_contact_ids[] = (int)$applicant_id;
2932 }
2933 }
2934
2935 $applicant_contact_ids = array_unique($applicant_contact_ids);
2936
2937 if ( empty($applicant_contact_ids) )
2938 {
2939 $return = array('error' => 'No applicant selected, or unable to create applicant record');
2940 echo json_encode( $return );
2941 die();
2942 }
2943
2944 // Make sure each of the contacts has an applicant profile of the correct department
2945 /*foreach ( $applicant_contact_ids as $applicant_contact_id )
2946 {
2947 $has_correct_profile = false;
2948
2949 // Get all existing profiles
2950 $existing_contact_types = get_post_meta( $applicant_contact_id, '_contact_types', TRUE );
2951 if ( $existing_contact_types == '' || !is_array($existing_contact_types) )
2952 {
2953 $existing_contact_types = array();
2954 }
2955 if ( in_array( 'applicant', $existing_contact_types ) )
2956 {
2957 $num_applicant_profiles = get_post_meta( $applicant_contact_id, '_applicant_profiles', TRUE );
2958 if ( $num_applicant_profiles == '' )
2959 {
2960 $num_applicant_profiles = 0;
2961 }
2962
2963 if ( $num_applicant_profiles > 0 )
2964 {
2965 for ( $i = 0; $i < $num_applicant_profiles; ++$i )
2966 {
2967 $applicant_profile = get_post_meta( $applicant_contact_id, '_applicant_profile_' . $i, TRUE );
2968 if ( $applicant_profile['department'] == $property->department )
2969 {
2970 $has_correct_profile = true;
2971 }
2972 }
2973 }
2974 }
2975
2976 if ( !$has_correct_profile )
2977 {
2978 if ( in_array( 'applicant', $existing_contact_types ) )
2979 {
2980 // Already an applicant. Just need to add profile
2981 }
2982 else
2983 {
2984 $existing_contact_types[] = 'applicant';
2985 update_post_meta( $applicant_contact_id, '_contact_types', $existing_contact_types );
2986 }
2987
2988 $num_applicant_profiles = get_post_meta( $applicant_contact_id, '_applicant_profiles', TRUE );
2989 if ( $num_applicant_profiles == '' )
2990 {
2991 $num_applicant_profiles = 0;
2992 }
2993
2994 update_post_meta( $applicant_contact_id, '_applicant_profiles', $num_applicant_profiles + 1 );
2995 update_post_meta( $applicant_contact_id, '_applicant_profile_' . $num_applicant_profiles, array( 'department' => $property->department ) );
2996 }
2997 }*/
2998
2999 // Loop through contacts and create one viewing each
3000 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
3001 foreach ( $applicant_contact_ids as $applicant_contact_id )
3002 {
3003 // Insert viewing record
3004 $viewing_post = array(
3005 'post_title' => '',
3006 'post_content' => '',
3007 'post_type' => 'viewing',
3008 'post_status' => 'publish',
3009 'comment_status' => 'closed',
3010 'ping_status' => 'closed',
3011 );
3012
3013 // Insert the post into the database
3014 $viewing_post_id = wp_insert_post( $viewing_post );
3015
3016 if ( is_wp_error($viewing_post_id) || $viewing_post_id == 0 )
3017 {
3018 $return = array('error' => 'Failed to create viewing post. Please try again');
3019 echo json_encode( $return );
3020 die();
3021 }
3022
3023 add_post_meta( $viewing_post_id, '_start_date_time', ph_clean($_POST['start_date']) . ' ' . ph_clean($_POST['start_time']) );
3024 add_post_meta( $viewing_post_id, '_duration', 30 * 60 ); // Stored in seconds. Default to 30 mins
3025 add_post_meta( $viewing_post_id, '_property_id', (int)$_POST['property_id'] );
3026 add_post_meta( $viewing_post_id, '_applicant_contact_id', $applicant_contact_id );
3027 add_post_meta( $viewing_post_id, '_status', 'pending' );
3028 add_post_meta( $viewing_post_id, '_feedback_status', '' );
3029 add_post_meta( $viewing_post_id, '_feedback', '' );
3030 add_post_meta( $viewing_post_id, '_feedback_passed_on', '' );
3031
3032 if ( !empty($_POST['negotiator_ids']) )
3033 {
3034 foreach ( $_POST['negotiator_ids'] as $negotiator_id )
3035 {
3036 add_post_meta( $viewing_post_id, '_negotiator_id', (int)$negotiator_id );
3037 }
3038 }
3039 }
3040
3041 $applicant_contacts = array();
3042 foreach ( $applicant_contact_ids as $applicant_contact_id )
3043 {
3044 $applicant_contacts[] = array(
3045 'ID' => $applicant_contact_id,
3046 'post_title' => get_the_title($applicant_contact_id),
3047 'edit_link' => get_edit_post_link( $applicant_contact_id, '' ),
3048 );
3049 }
3050
3051 $return = array('success' => array(
3052 'viewing' => array(
3053 'ID' => $viewing_post_id,
3054 'edit_link' => get_edit_post_link( $viewing_post_id, '' ),
3055 ),
3056 'applicant_contacts' => $applicant_contacts,
3057 ));
3058
3059 echo json_encode( $return );
3060
3061 die();
3062 }
3063
3064 public function book_viewing_contact()
3065 {
3066 check_ajax_referer( 'book-viewing', 'security' );
3067
3068 $this->json_headers();
3069
3070 // TO DO: Should do validation on server side also
3071 if (empty($_POST['contact_id']))
3072 {
3073 $return = array('error' => 'No contact selected');
3074 echo json_encode( $return );
3075 die();
3076 }
3077
3078 if (empty($_POST['property_ids']))
3079 {
3080 $return = array('error' => 'No property selected');
3081 echo json_encode( $return );
3082 die();
3083 }
3084
3085 // Loop through contacts and create one viewing each
3086 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
3087 foreach ( $_POST['property_ids'] as $property_id )
3088 {
3089 // Insert viewing record
3090 $viewing_post = array(
3091 'post_title' => '',
3092 'post_content' => '',
3093 'post_type' => 'viewing',
3094 'post_status' => 'publish',
3095 'comment_status' => 'closed',
3096 'ping_status' => 'closed',
3097 );
3098
3099 // Insert the post into the database
3100 $viewing_post_id = wp_insert_post( $viewing_post );
3101
3102 if ( is_wp_error($viewing_post_id) || $viewing_post_id == 0 )
3103 {
3104 $return = array('error' => 'Failed to create viewing post. Please try again');
3105 echo json_encode( $return );
3106 die();
3107 }
3108
3109 add_post_meta( $viewing_post_id, '_start_date_time', ph_clean($_POST['start_date']) . ' ' . ph_clean($_POST['start_time']) );
3110 add_post_meta( $viewing_post_id, '_duration', 30 * 60 ); // Stored in seconds. Default to 30 mins
3111 add_post_meta( $viewing_post_id, '_property_id', (int)$property_id );
3112 add_post_meta( $viewing_post_id, '_applicant_contact_id', (int)$_POST['contact_id'] );
3113 add_post_meta( $viewing_post_id, '_status', 'pending' );
3114 add_post_meta( $viewing_post_id, '_feedback_status', '' );
3115 add_post_meta( $viewing_post_id, '_feedback', '' );
3116 add_post_meta( $viewing_post_id, '_feedback_passed_on', '' );
3117
3118 if ( !empty($_POST['negotiator_ids']) )
3119 {
3120 foreach ( $_POST['negotiator_ids'] as $negotiator_id )
3121 {
3122 add_post_meta( $viewing_post_id, '_negotiator_id', (int)$negotiator_id );
3123 }
3124 }
3125 }
3126
3127 $properties = array();
3128 foreach ( $_POST['property_ids'] as $property_id )
3129 {
3130 $properties[] = array(
3131 'ID' => (int)$property_id,
3132 'post_title' => get_the_title((int)$property_id),
3133 'edit_link' => get_edit_post_link( (int)$property_id, '' ),
3134 );
3135 }
3136
3137 $return = array('success' => array(
3138 'viewing' => array(
3139 'ID' => $viewing_post_id,
3140 'edit_link' => get_edit_post_link( $viewing_post_id, '' ),
3141 ),
3142 'properties' => $properties,
3143 ));
3144
3145 echo json_encode( $return );
3146
3147 die();
3148 }
3149
3150 public function get_viewing_details_meta_box()
3151 {
3152 global $post;
3153
3154 check_ajax_referer( 'viewing-details-meta-box', 'security' );
3155
3156 $post = get_post((int)$_POST['viewing_id']);
3157
3158 $viewing = new PH_Viewing((int)$_POST['viewing_id']);
3159
3160 echo '<div class="propertyhive_meta_box">';
3161
3162 echo '<div class="options_group">';
3163
3164 echo '<p class="form-field">
3165
3166 <label for="">' . __('Status', 'propertyhive') . '</label>
3167
3168 ' . ucwords(str_replace("_", " ", $viewing->status));
3169
3170 if ( $viewing->status == 'offer_made' )
3171 {
3172 if ( get_option('propertyhive_module_disabled_offers_sales', '') != 'yes' )
3173 {
3174 $offer_id = get_post_meta( $viewing->id, '_offer_id', TRUE );
3175 if ( $offer_id != '' && get_post_status($offer_id) != 'publish' )
3176 {
3177 $offer_id = '';
3178 }
3179
3180 if ( $offer_id != '' )
3181 {
3182 echo ' (<a href="' . get_edit_post_link($offer_id) . '">' . __('View Offer', 'propertyhive') . '</a>)';
3183 }
3184 }
3185 }
3186
3187 echo '</p>';
3188
3189 if ( $viewing->status == 'cancelled' )
3190 {
3191 $args = array(
3192 'id' => '_cancelled_reason',
3193 'label' => __( 'Reason Cancelled', 'propertyhive' ),
3194 'desc_tip' => false,
3195 'class' => '',
3196 'value' => $viewing->cancelled_reason,
3197 'custom_attributes' => array(
3198 'style' => 'width:95%; max-width:500px;'
3199 )
3200 );
3201 propertyhive_wp_textarea_input( $args );
3202 }
3203
3204 if ( $viewing->status == 'carried_out' )
3205 {
3206 echo '<p class="form-field">
3207
3208 <label for="">' . __('Applicant Feedback', 'propertyhive') . '</label>';
3209
3210 switch ( $viewing->feedback_status )
3211 {
3212 case "interested":
3213 {
3214 echo 'Interested';
3215 break;
3216 }
3217 case "not_interested":
3218 {
3219 echo 'Not Interested';
3220 break;
3221 }
3222 case "not_required":
3223 {
3224 echo 'Feedback Not Required';
3225 break;
3226 }
3227 default:
3228 {
3229 echo 'Awaiting Feedback';
3230 }
3231 }
3232
3233 echo '</p>';
3234
3235 if ( $viewing->feedback_status == 'interested' || $viewing->feedback_status == 'not_interested' )
3236 {
3237 $args = array(
3238 'id' => '_feedback',
3239 'label' => __( 'Feedback', 'propertyhive' ),
3240 'desc_tip' => false,
3241 'class' => '',
3242 'value' => $viewing->feedback,
3243 'custom_attributes' => array(
3244 'style' => 'width:95%; max-width:500px;'
3245 )
3246 );
3247 propertyhive_wp_textarea_input( $args );
3248 }
3249 }
3250
3251 if ( $viewing->status == 'carried_out' && ( $viewing->feedback_status == 'interested' || $viewing->feedback_status == 'not_interested' ) )
3252 {
3253 echo '<p class="form-field">
3254
3255 <label for="">' . __('Feedback Passed On', 'propertyhive') . '</label>';
3256
3257 echo ( ($viewing->feedback_passed_on == 'yes') ? 'Yes' : 'No' );
3258
3259 echo '</p>';
3260 }
3261
3262 do_action('propertyhive_viewing_details_fields');
3263
3264 echo '</div>';
3265
3266 echo '</div>';
3267
3268 die();
3269 }
3270
3271 public function get_viewing_actions()
3272 {
3273 check_ajax_referer( 'viewing-actions', 'security' );
3274
3275 $post_id = (int)$_POST['viewing_id'];
3276
3277 $status = get_post_meta( $post_id, '_status', TRUE );
3278 $feedback_status = get_post_meta( $post_id, '_feedback_status', TRUE );
3279
3280 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_viewing_actions_meta_box">
3281
3282 <div class="options_group" style="padding-top:8px;">';
3283
3284 $show_cancelled_meta_boxes = false;
3285 $show_feedback_meta_boxes = false;
3286
3287 $actions = array();
3288
3289 if ( $status == 'pending' )
3290 {
3291 $applicant_contact_id = get_post_meta( $post_id, '_applicant_contact_id', TRUE );
3292 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3293 $applicant_email_address = get_post_meta( $applicant_contact_id, '_email_address', TRUE );
3294
3295 if ( (int)$applicant_contact_id == '' || (int)$property_id == '' || (int)$applicant_contact_id == 0 || (int)$property_id == 0 || sanitize_email($applicant_email_address) == '' )
3296 {
3297
3298 }
3299 else
3300 {
3301 $applicant_booking_confirmation_sent_at = get_post_meta( $post_id, '_applicant_booking_confirmation_sent_at', TRUE );
3302 $owner_booking_confirmation_sent_at = get_post_meta( $post_id, '_owner_booking_confirmation_sent_at', TRUE );
3303
3304 //Applicant
3305 $actions[] = '<a
3306 href="#action_panel_viewing_email_applicant_booking_confirmation"
3307 class="button viewing-action"
3308 style="width:100%; margin-bottom:7px; text-align:center"
3309 >' . ( ( $applicant_booking_confirmation_sent_at == '' ) ? __('Email Applicant Booking Confirmation', 'propertyhive') : __('Re-Email Applicant Booking Confirmation', 'propertyhive') ) . '</a>';
3310
3311 $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>';
3312
3313 // Owner/Landlord
3314 $property_department = get_post_meta( $property_id, '_department', TRUE );
3315 $owner_contact_ids = get_post_meta( $property_id, '_owner_contact_id', TRUE );
3316 $owner_or_landlord = ( $property_department == 'residential-lettings' ? 'Landlord' : 'Owner' );
3317
3318 if ( count($owner_contact_ids) > 0) {
3319
3320 $actions[] = '<a
3321 href="#action_panel_viewing_email_owner_booking_confirmation"
3322 class="button viewing-action"
3323 style="width:100%; margin-bottom:7px; text-align:center"
3324 >' . ( ( $owner_booking_confirmation_sent_at == '' ) ? __('Email ' . $owner_or_landlord . ' Booking Confirmation', 'propertyhive') : __('Re-Email ' . $owner_or_landlord . ' Booking Confirmation', 'propertyhive') ) . '</a>';
3325
3326 $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>';
3327 }
3328
3329 $actions[] = '<hr>';
3330 }
3331
3332 $actions[] = '<a
3333 href="#action_panel_viewing_carried_out"
3334 class="button button-success viewing-action"
3335 style="width:100%; margin-bottom:7px; text-align:center"
3336 >' . __('Viewing Carried Out', 'propertyhive') . '</a>';
3337 $actions[] = '<a
3338 href="#action_panel_viewing_cancelled"
3339 class="button viewing-action"
3340 style="width:100%; margin-bottom:7px; text-align:center"
3341 >' . __('Viewing Cancelled', 'propertyhive') . '</a>';
3342
3343 $show_cancelled_meta_boxes = true;
3344 }
3345
3346 if ( $status == 'carried_out' )
3347 {
3348 if ( $feedback_status == '' )
3349 {
3350 $actions[] = '<a
3351 href="#action_panel_viewing_interested"
3352 class="button button-success viewing-action"
3353 style="width:100%; margin-bottom:7px; text-align:center"
3354 >' . wp_kses_post( __('Applicant Interested', 'propertyhive') ) . '</a>';
3355
3356 $actions[] = '<a
3357 href="#action_panel_viewing_not_interested"
3358 class="button button-danger viewing-action"
3359 style="width:100%; margin-bottom:7px; text-align:center"
3360 >' . wp_kses_post( __('Applicant Not Interested', 'propertyhive') ) . '</a>';
3361
3362 $actions[] = '<a
3363 href="#action_panel_viewing_feedback_not_required"
3364 class="button viewing-action"
3365 style="width:100%; margin-bottom:7px; text-align:center"
3366 >' . wp_kses_post( __('Feedback Not Required', 'propertyhive') ) . '</a>';
3367
3368 $show_feedback_meta_boxes = true;
3369 }
3370
3371 if ( $feedback_status == 'interested' )
3372 {
3373 $actions[] = '<a
3374 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 .'"
3375 class="button button-success"
3376 style="width:100%; margin-bottom:7px; text-align:center"
3377 >' . wp_kses_post( __('Book Second Viewing', 'propertyhive') ) . '</a>';
3378
3379 if ( get_option('propertyhive_module_disabled_offers_sales', '') != 'yes' )
3380 {
3381 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3382 if ( get_post_meta( $property_id, '_department', TRUE ) == 'residential-sales' )
3383 {
3384 // See if an offer has this viewing id associated with it
3385 $offer_id = get_post_meta( $post_id, '_offer_id', TRUE );
3386 if ( $offer_id != '' && get_post_status($offer_id) != 'publish' )
3387 {
3388 $offer_id = '';
3389 }
3390
3391 if ( $offer_id != '' )
3392 {
3393 $actions[] = '<a
3394 href="' . get_edit_post_link( $offer_id, '' ) . '"
3395 class="button"
3396 style="width:100%; margin-bottom:7px; text-align:center"
3397 >' . wp_kses_post( __('View Offer', 'propertyhive') ) . '</a>';
3398 }
3399 else
3400 {
3401 $actions[] = '<a
3402 href="' . wp_nonce_url( admin_url( 'post.php?post=' . $post_id . '&action=edit' ), '1', 'create_offer' ) . '"
3403 class="button button-success"
3404 style="width:100%; margin-bottom:7px; text-align:center"
3405 >' . wp_kses_post( __('Record Offer', 'propertyhive') ) . '</a>';
3406 }
3407 }
3408 }
3409 }
3410
3411 if ( get_post_meta( $post_id, '_feedback_passed_on', TRUE ) != 'yes' && ( $feedback_status == 'interested' || $feedback_status == 'not_interested' ) )
3412 {
3413 $actions[] = '<a
3414 href="#action_panel_viewing_revert_feedback_passed_on"
3415 class="button viewing-action"
3416 style="width:100%; margin-bottom:7px; text-align:center"
3417 >' . wp_kses_post( __('Feedback Passed On To Owner', 'propertyhive') ) . '</a>';
3418 }
3419
3420 if ( $feedback_status == 'interested' || $feedback_status == 'not_interested' || $feedback_status == 'not_required' )
3421 {
3422 $actions[] = '<a
3423 href="#action_panel_viewing_revert_feedback_pending"
3424 class="button viewing-action"
3425 style="width:100%; margin-bottom:7px; text-align:center"
3426 >' . wp_kses_post( __('Revert To Feedback Pending', 'propertyhive') ) . '</a>';
3427 }
3428 }
3429
3430 if ( $status == 'offer_made' )
3431 {
3432 if ( get_option('propertyhive_module_disabled_offers_sales', '') != 'yes' )
3433 {
3434 $offer_id = get_post_meta( $post_id, '_offer_id', TRUE );
3435 if ( $offer_id != '' && get_post_status($offer_id) != 'publish' )
3436 {
3437 $offer_id = '';
3438 }
3439
3440 if ( $offer_id != '' )
3441 {
3442 $actions[] = '<a
3443 href="' . get_edit_post_link( $offer_id, '' ) . '"
3444 class="button"
3445 style="width:100%; margin-bottom:7px; text-align:center"
3446 >' . wp_kses_post( __('View Offer', 'propertyhive') ) . '</a>';
3447 }
3448 }
3449 }
3450
3451 if ( ( $status == 'carried_out' && $feedback_status == '' ) || $status == 'cancelled' )
3452 {
3453 $actions[] = '<a
3454 href="#action_panel_viewing_revert_pending"
3455 class="button viewing-action"
3456 style="width:100%; margin-bottom:7px; text-align:center"
3457 >' . wp_kses_post( __('Revert To Pending', 'propertyhive') ) . '</a>';
3458 }
3459
3460 $actions = apply_filters( 'propertyhive_admin_viewing_actions', $actions, $post_id );
3461
3462 if ( !empty($actions) )
3463 {
3464 echo implode("", $actions);
3465 }
3466 else
3467 {
3468 echo '<div style="text-align:center">' . wp_kses_post( __( 'No actions to display', 'propertyhive' ) ) . '</div>';
3469 }
3470
3471 echo '</div>
3472
3473 </div>';
3474
3475 if ( $show_cancelled_meta_boxes )
3476 {
3477 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_viewing_cancelled" style="display:none;">
3478
3479 <div class="options_group" style="padding-top:8px;">
3480
3481 <div class="form-field">
3482
3483 <label for="_viewing_cancelled_reason">' . __( 'Reason Cancelled', 'propertyhive' ) . '</label>
3484
3485 <textarea id="_cancelled_reason" name="_cancelled_reason" style="width:100%;">' . get_post_meta( $post_id, '_cancelled_reason', TRUE ) . '</textarea>
3486
3487 </div>
3488
3489 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
3490 <a class="button button-primary cancelled-reason-action-submit" href="#">' . __( 'Save', 'propertyhive' ) . '</a>
3491
3492 </div>
3493
3494 </div>';
3495 }
3496
3497 if ( $show_feedback_meta_boxes )
3498 {
3499 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_viewing_interested" style="display:none;">
3500
3501 <div class="options_group" style="padding-top:8px;">
3502
3503 <div class="form-field">
3504
3505 <label for="_viewing_interested_feedback">' . __( 'Applicant Feedback', 'propertyhive' ) . '</label>
3506
3507 <textarea id="_interested_feedback" name="_interested_feedback" style="width:100%;">' . get_post_meta( $post_id, '_feedback', TRUE ) . '</textarea>
3508
3509 </div>
3510
3511 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
3512 <a class="button button-primary interested-feedback-action-submit" href="#">' . wp_kses_post( __( 'Save Feedback', 'propertyhive' ) ) . '</a>
3513
3514 </div>
3515
3516 </div>';
3517
3518 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="action_panel_viewing_not_interested" style="display:none;">
3519
3520 <div class="options_group" style="padding-top:8px;">
3521
3522 <div class="form-field">
3523
3524 <label for="_viewing_not_interested_feedback">' . __( 'Applicant Feedback', 'propertyhive' ) . '</label>
3525
3526 <textarea id="_not_interested_feedback" name="_not_interested_feedback" style="width:100%;">' . get_post_meta( $post_id, '_feedback', TRUE ) . '</textarea>
3527
3528 </div>
3529
3530 <a class="button action-cancel" href="#">' . __( 'Cancel', 'propertyhive' ) . '</a>
3531 <a class="button button-primary not-interested-feedback-action-submit" href="#">' . wp_kses_post( __( 'Save Feedback', 'propertyhive' ) ) . '</a>
3532
3533 </div>
3534
3535 </div>';
3536 }
3537
3538 die();
3539 }
3540
3541 public function viewing_carried_out()
3542 {
3543 check_ajax_referer( 'viewing-actions', 'security' );
3544
3545 $post_id = (int)$_POST['viewing_id'];
3546
3547 $status = get_post_meta( $post_id, '_status', TRUE );
3548
3549 if ( $status == 'pending' )
3550 {
3551 update_post_meta( $post_id, '_status', 'carried_out' );
3552
3553 $current_user = wp_get_current_user();
3554
3555 // Add note/comment to viewing
3556 $comment = array(
3557 'note_type' => 'action',
3558 'action' => 'viewing_carried_out',
3559 );
3560
3561 $data = array(
3562 'comment_post_ID' => $post_id,
3563 'comment_author' => $current_user->display_name,
3564 'comment_author_email' => 'propertyhive@noreply.com',
3565 'comment_author_url' => '',
3566 'comment_date' => date("Y-m-d H:i:s"),
3567 'comment_content' => serialize($comment),
3568 'comment_approved' => 1,
3569 'comment_type' => 'propertyhive_note',
3570 );
3571 $comment_id = wp_insert_comment( $data );
3572 }
3573
3574 die();
3575 }
3576
3577 public function viewing_cancelled()
3578 {
3579 check_ajax_referer( 'viewing-actions', 'security' );
3580
3581 $post_id = (int)$_POST['viewing_id'];
3582
3583 $status = get_post_meta( $post_id, '_status', TRUE );
3584
3585 if ( $status == 'pending' )
3586 {
3587 update_post_meta( $post_id, '_status', 'cancelled' );
3588 update_post_meta( $post_id, '_cancelled_reason', sanitize_textarea_field( $_POST['cancelled_reason'] ) );
3589
3590 $current_user = wp_get_current_user();
3591
3592 // Add note/comment to viewing
3593 $comment = array(
3594 'note_type' => 'action',
3595 'action' => 'viewing_cancelled',
3596 );
3597
3598 $data = array(
3599 'comment_post_ID' => $post_id,
3600 'comment_author' => $current_user->display_name,
3601 'comment_author_email' => 'propertyhive@noreply.com',
3602 'comment_author_url' => '',
3603 'comment_date' => date("Y-m-d H:i:s"),
3604 'comment_content' => serialize($comment),
3605 'comment_approved' => 1,
3606 'comment_type' => 'propertyhive_note',
3607 );
3608 $comment_id = wp_insert_comment( $data );
3609 }
3610
3611 die();
3612 }
3613
3614 public function viewing_email_applicant_booking_confirmation()
3615 {
3616 check_ajax_referer( 'viewing-actions', 'security' );
3617
3618 $post_id = (int)$_POST['viewing_id'];
3619
3620 $applicant_contact_id = get_post_meta( $post_id, '_applicant_contact_id', TRUE );
3621 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3622
3623 if ( (int)$applicant_contact_id == '' || (int)$property_id == '' || (int)$applicant_contact_id == 0 || (int)$property_id == 0 )
3624 {
3625 die();
3626 }
3627
3628 $property = new PH_Property((int)$property_id);
3629
3630 $to = get_post_meta( $applicant_contact_id, '_email_address', TRUE );
3631
3632 if ( sanitize_email($to) != '' )
3633 {
3634 $subject = get_option( 'propertyhive_viewing_applicant_booking_confirmation_email_subject', '' );
3635 $body = get_option( 'propertyhive_viewing_applicant_booking_confirmation_email_body', '' );
3636
3637 $subject = str_replace('[property_address]', $property->get_formatted_full_address(), $subject);
3638 $subject = str_replace('[applicant_name]', get_the_title($applicant_contact_id), $subject);
3639 $subject = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3640 $subject = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3641
3642 $body = str_replace('[property_address]', $property->get_formatted_full_address(), $body);
3643 $body = str_replace('[applicant_name]', get_the_title($applicant_contact_id), $body);
3644 $body = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3645 $body = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3646
3647 $from = $property->office_email_address;
3648 if ( sanitize_email($from) == '' )
3649 {
3650 $from = get_bloginfo('admin_email');
3651 }
3652
3653 $headers = array();
3654 $headers[] = 'From: ' . get_bloginfo('name') . ' <' . $from . '>';
3655 $headers[] = 'Content-Type: text/plain; charset=UTF-8';
3656
3657 wp_mail($to, $subject, $body, $headers);
3658
3659 update_post_meta( $post_id, '_applicant_booking_confirmation_sent_at', date("Y-m-d H:i:s") );
3660 }
3661
3662 die();
3663 }
3664
3665 public function viewing_email_owner_booking_confirmation()
3666 {
3667 check_ajax_referer( 'viewing-actions', 'security' );
3668
3669 $post_id = (int)$_POST['viewing_id'];
3670
3671 $property_id = get_post_meta( $post_id, '_property_id', TRUE );
3672 $property_department = get_post_meta( $property_id, '_department' );
3673
3674 $applicant_contact_id = get_post_meta( $post_id, '_applicant_contact_id', TRUE );
3675 $owner_contact_ids = get_post_meta( $property_id, '_owner_contact_id', TRUE );
3676
3677 if ( $owner_contact_ids > 0 ) {
3678
3679 $owner_emails = array();
3680 $owner_names = array();
3681
3682 foreach ($owner_contact_ids as $owner_id)
3683 {
3684 $owner_email = sanitize_email( get_post_meta($owner_id, '_email_address', TRUE) );
3685 $owner_name = get_the_title($owner_id);
3686
3687 if( ! empty($owner_email) ) array_push($owner_emails, $owner_email);
3688 if( ! empty($owner_name) ) array_push($owner_names, $owner_name);
3689 }
3690
3691 $property = new PH_Property((int)$property_id);
3692
3693 $to = implode(",", $owner_emails);
3694
3695 $subject = get_option( 'propertyhive_viewing_owner_booking_confirmation_email_subject', '' );
3696 $body = get_option( 'propertyhive_viewing_owner_booking_confirmation_email_body', '' );
3697
3698 $subject = str_replace('[property_address]', $property->get_formatted_full_address(), $subject);
3699 $subject = str_replace('[owner_name]', implode(", ", $owner_names), $subject);
3700 $subject = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3701 $subject = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $subject);
3702
3703 $body = str_replace('[property_address]', $property->get_formatted_full_address(), $body);
3704 $body = str_replace('[owner_name]', implode(", ", $owner_names), $body);
3705 $body = str_replace('[viewing_time]', date("H:i", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3706 $body = str_replace('[viewing_date]', date("l jS F Y", strtotime(get_post_meta( $post_id, '_start_date_time', true ))), $body);
3707
3708 $from = $property->office_email_address;
3709 if ( sanitize_email($from) == '' )
3710 {
3711 $from = get_bloginfo('admin_email');
3712 }
3713
3714 $headers = array();
3715 $headers[] = 'From: ' . get_bloginfo('name') . ' <' . $from . '>';
3716 $headers[] = 'Content-Type: text/plain; charset=UTF-8';
3717
3718 wp_mail($to, $subject, $body, $headers);
3719
3720 update_post_meta( $post_id, '_owner_booking_confirmation_sent_at', date("Y-m-d H:i:s") );
3721
3722 }
3723
3724 die();
3725 }
3726
3727 public function viewing_interested_feedback()
3728 {
3729 check_ajax_referer( 'viewing-actions', 'security' );
3730
3731 $post_id = (int)$_POST['viewing_id'];
3732
3733 $status = get_post_meta( $post_id, '_status', TRUE );
3734
3735 if ( $status == 'carried_out' )
3736 {
3737 update_post_meta( $post_id, '_feedback_status', 'interested' );
3738 update_post_meta( $post_id, '_feedback', sanitize_textarea_field( $_POST['feedback'] ) );
3739
3740 $current_user = wp_get_current_user();
3741
3742 // Add note/comment to viewing
3743 $comment = array(
3744 'note_type' => 'action',
3745 'action' => 'viewing_applicant_interested',
3746 );
3747
3748 $data = array(
3749 'comment_post_ID' => $post_id,
3750 'comment_author' => $current_user->display_name,
3751 'comment_author_email' => 'propertyhive@noreply.com',
3752 'comment_author_url' => '',
3753 'comment_date' => date("Y-m-d H:i:s"),
3754 'comment_content' => serialize($comment),
3755 'comment_approved' => 1,
3756 'comment_type' => 'propertyhive_note',
3757 );
3758 $comment_id = wp_insert_comment( $data );
3759 }
3760
3761 die();
3762 }
3763
3764 public function viewing_not_interested_feedback()
3765 {
3766 check_ajax_referer( 'viewing-actions', 'security' );
3767
3768 $post_id = (int)$_POST['viewing_id'];
3769
3770 $status = get_post_meta( $post_id, '_status', TRUE );
3771
3772 if ( $status == 'carried_out' )
3773 {
3774 update_post_meta( $post_id, '_feedback_status', 'not_interested' );
3775 update_post_meta( $post_id, '_feedback', sanitize_textarea_field( $_POST['feedback'] ) );
3776
3777 $current_user = wp_get_current_user();
3778
3779 // Add note/comment to viewing
3780 $comment = array(
3781 'note_type' => 'action',
3782 'action' => 'viewing_applicant_not_interested',
3783 );
3784
3785 $data = array(
3786 'comment_post_ID' => $post_id,
3787 'comment_author' => $current_user->display_name,
3788 'comment_author_email' => 'propertyhive@noreply.com',
3789 'comment_author_url' => '',
3790 'comment_date' => date("Y-m-d H:i:s"),
3791 'comment_content' => serialize($comment),
3792 'comment_approved' => 1,
3793 'comment_type' => 'propertyhive_note',
3794 );
3795 $comment_id = wp_insert_comment( $data );
3796 }
3797
3798 die();
3799 }
3800
3801 public function viewing_feedback_not_required()
3802 {
3803 check_ajax_referer( 'viewing-actions', 'security' );
3804
3805 $post_id = (int)$_POST['viewing_id'];
3806
3807 $status = get_post_meta( $post_id, '_status', TRUE );
3808
3809 if ( $status == 'carried_out' )
3810 {
3811 update_post_meta( $post_id, '_feedback_status', 'not_required' );
3812
3813 $current_user = wp_get_current_user();
3814
3815 // Add note/comment to viewing
3816 $comment = array(
3817 'note_type' => 'action',
3818 'action' => 'viewing_feedback_not_required',
3819 );
3820
3821 $data = array(
3822 'comment_post_ID' => $post_id,
3823 'comment_author' => $current_user->display_name,
3824 'comment_author_email' => 'propertyhive@noreply.com',
3825 'comment_author_url' => '',
3826 'comment_date' => date("Y-m-d H:i:s"),
3827 'comment_content' => serialize($comment),
3828 'comment_approved' => 1,
3829 'comment_type' => 'propertyhive_note',
3830 );
3831 $comment_id = wp_insert_comment( $data );
3832 }
3833
3834 die();
3835 }
3836
3837 public function viewing_revert_feedback_pending()
3838 {
3839 check_ajax_referer( 'viewing-actions', 'security' );
3840
3841 $post_id = (int)$_POST['viewing_id'];
3842
3843 $status = get_post_meta( $post_id, '_status', TRUE );
3844
3845 if ( $status == 'carried_out' )
3846 {
3847 update_post_meta( $post_id, '_feedback_status', '' );
3848 update_post_meta( $post_id, '_feedback_passed_on', '' );
3849
3850 $current_user = wp_get_current_user();
3851
3852 // Add note/comment to viewing
3853 $comment = array(
3854 'note_type' => 'action',
3855 'action' => 'viewing_revert_feedback_pending',
3856 );
3857
3858 $data = array(
3859 'comment_post_ID' => $post_id,
3860 'comment_author' => $current_user->display_name,
3861 'comment_author_email' => 'propertyhive@noreply.com',
3862 'comment_author_url' => '',
3863 'comment_date' => date("Y-m-d H:i:s"),
3864 'comment_content' => serialize($comment),
3865 'comment_approved' => 1,
3866 'comment_type' => 'propertyhive_note',
3867 );
3868 $comment_id = wp_insert_comment( $data );
3869 }
3870
3871 die();
3872 }
3873
3874 public function viewing_revert_pending()
3875 {
3876 check_ajax_referer( 'viewing-actions', 'security' );
3877
3878 $post_id = (int)$_POST['viewing_id'];
3879
3880 $status = get_post_meta( $post_id, '_status', TRUE );
3881
3882 if ( $status == 'carried_out' || $status == 'cancelled' )
3883 {
3884 update_post_meta( $post_id, '_status', 'pending' );
3885 update_post_meta( $post_id, '_feedback_status', '' );
3886
3887 $current_user = wp_get_current_user();
3888
3889 // Add note/comment to viewing
3890 $comment = array(
3891 'note_type' => 'action',
3892 'action' => 'viewing_revert_pending',
3893 );
3894
3895 $data = array(
3896 'comment_post_ID' => $post_id,
3897 'comment_author' => $current_user->display_name,
3898 'comment_author_email' => 'propertyhive@noreply.com',
3899 'comment_author_url' => '',
3900 'comment_date' => date("Y-m-d H:i:s"),
3901 'comment_content' => serialize($comment),
3902 'comment_approved' => 1,
3903 'comment_type' => 'propertyhive_note',
3904 );
3905 $comment_id = wp_insert_comment( $data );
3906 }
3907
3908 die();
3909 }
3910
3911 public function viewing_feedback_passed_on()
3912 {
3913 check_ajax_referer( 'viewing-actions', 'security' );
3914
3915 $post_id = (int)$_POST['viewing_id'];
3916
3917 $status = get_post_meta( $post_id, '_status', TRUE );
3918
3919 if ( $status == 'carried_out' )
3920 {
3921 update_post_meta( $post_id, '_feedback_passed_on', 'yes' );
3922
3923 $current_user = wp_get_current_user();
3924
3925 // Add note/comment to viewing
3926 $comment = array(
3927 'note_type' => 'action',
3928 'action' => 'viewing_feedback_passed_on',
3929 );
3930
3931 $data = array(
3932 'comment_post_ID' => $post_id,
3933 'comment_author' => $current_user->display_name,
3934 'comment_author_email' => 'propertyhive@noreply.com',
3935 'comment_author_url' => '',
3936 'comment_date' => date("Y-m-d H:i:s"),
3937 'comment_content' => serialize($comment),
3938 'comment_approved' => 1,
3939 'comment_type' => 'propertyhive_note',
3940 );
3941 $comment_id = wp_insert_comment( $data );
3942 }
3943
3944 die();
3945 }
3946
3947 public function get_property_viewings_meta_box()
3948 {
3949 check_ajax_referer( 'get_property_viewings_meta_box', 'security' );
3950
3951 global $post;
3952
3953 echo '<div class="propertyhive_meta_box">';
3954
3955 echo '<div class="options_group">';
3956
3957 $args = array(
3958 'post_type' => 'viewing',
3959 'nopaging' => true,
3960 'orderby' => 'meta_value',
3961 'order' => 'DESC',
3962 'meta_key' => '_start_date_time',
3963 'post_status' => 'publish',
3964 'meta_query' => array(
3965 array(
3966 'key' => '_property_id',
3967 'value' => (int)$_POST['post_id']
3968 )
3969 )
3970 );
3971 $viewings_query = new WP_Query( $args );
3972
3973 if ( $viewings_query->have_posts() )
3974 {
3975 echo '<table style="width:100%">
3976 <thead>
3977 <tr>
3978 <th style="text-align:left;">' . __( 'Date', 'propertyhive' ) . ' / ' . __( 'Time', 'propertyhive' ) . '</th>
3979 <th style="text-align:left;">' . __( 'Applicant', 'propertyhive' ) . '</th>
3980 <th style="text-align:left;">' . __( 'Attending Negotiator(s)', 'propertyhive' ) . '</th>
3981 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
3982 </tr>
3983 </thead>
3984 <tbody>';
3985
3986 while ( $viewings_query->have_posts() )
3987 {
3988 $viewings_query->the_post();
3989
3990 echo '<tr>';
3991 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>';
3992 echo '<td style="text-align:left;">';
3993 if ( get_post_meta(get_the_ID(), '_applicant_contact_id', TRUE) != '' )
3994 {
3995 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>';
3996 }
3997 else
3998 {
3999 echo '-';
4000 }
4001 echo '</td>';
4002 echo '<td style="text-align:left;">';
4003
4004 $negotiator_ids = get_post_meta(get_the_ID(), '_negotiator_id');
4005
4006 if (!empty($negotiator_ids))
4007 {
4008 $i = 0;
4009 foreach ($negotiator_ids as $negotiator_id)
4010 {
4011 if ( $i > 0 ) { echo ', '; }
4012
4013 $userdata = get_userdata( $negotiator_id );
4014 if ( $userdata !== FALSE )
4015 {
4016 echo $userdata->display_name;
4017 }
4018 else
4019 {
4020 echo '<em>Unknown user</em>';
4021 }
4022 ++$i;
4023 }
4024 }
4025 else
4026 {
4027 echo 'Unattended';
4028 }
4029
4030 echo '</td>';
4031 echo '<td style="text-align:left;">';
4032
4033 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4034 echo ucwords(str_replace("_", " ", $status));
4035 if ( $status == 'pending' )
4036 {
4037 echo '<br>';
4038 // confirmation status
4039 if ( get_post_meta(get_the_ID(), '_all_confirmed', TRUE) == 'yes' )
4040 {
4041 echo __( 'All Parties Confirmed', 'propertyhive' );
4042 }
4043 else
4044 {
4045 echo __( 'Awaiting Confirmation', 'propertyhive' );
4046 }
4047 }
4048 if ( $status == 'carried_out' )
4049 {
4050 echo '<br>';
4051 $feedback_status = get_post_meta(get_the_ID(), '_feedback_status', TRUE);
4052 switch ( $feedback_status )
4053 {
4054 case "interested": { echo 'Applicant Interested'; break; }
4055 case "not_interested": { echo 'Applicant Not Interested'; break; }
4056 case "not_required": { echo 'Feedback Not Required'; break; }
4057 default: { echo 'Awaiting Feedback'; }
4058 }
4059
4060 if ( $feedback_status == 'interested' || $feedback_status == 'not_interested' )
4061 {
4062 $feedback_passed_on = get_post_meta(get_the_ID(), '_feedback_passed_on', TRUE);
4063 echo '<br>' . ( ($feedback_passed_on == 'yes') ? 'Feedback Passed On' : 'Feedback Not Passed On' );
4064 }
4065 }
4066 echo '</td>';
4067 echo '</tr>';
4068 }
4069
4070 echo '
4071 </tbody>
4072 </table>
4073 <br>';
4074 }
4075 else
4076 {
4077 echo '<p>' . __( 'No viewings exist for this property', 'propertyhive') . '</p>';
4078 }
4079 wp_reset_postdata();
4080
4081 do_action('propertyhive_property_viewings_fields');
4082
4083 echo '</div>';
4084
4085 echo '</div>';
4086
4087 die();
4088 }
4089
4090 public function get_contact_viewings_meta_box()
4091 {
4092 check_ajax_referer( 'get_contact_viewings_meta_box', 'security' );
4093
4094 global $post;
4095
4096 echo '<div class="propertyhive_meta_box">';
4097
4098 echo '<div class="options_group">';
4099
4100 $args = array(
4101 'post_type' => 'viewing',
4102 'nopaging' => true,
4103 'orderby' => 'meta_value',
4104 'order' => 'DESC',
4105 'post_status' => 'publish',
4106 'meta_key' => '_start_date_time',
4107 'meta_query' => array(
4108 array(
4109 'key' => '_applicant_contact_id',
4110 'value' => (int)$_POST['post_id']
4111 )
4112 )
4113 );
4114 $viewings_query = new WP_Query( $args );
4115
4116 if ( $viewings_query->have_posts() )
4117 {
4118 echo '<table style="width:100%">
4119 <thead>
4120 <tr>
4121 <th style="text-align:left;">' . __( 'Date', 'propertyhive' ) . ' / ' . __( 'Time', 'propertyhive' ) . '</th>
4122 <th style="text-align:left;">' . __( 'Property', 'propertyhive' ) . '</th>
4123 <th style="text-align:left;">' . __( 'Attending Negotiator(s)', 'propertyhive' ) . '</th>
4124 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
4125 </tr>
4126 </thead>
4127 <tbody>';
4128
4129 while ( $viewings_query->have_posts() )
4130 {
4131 $viewings_query->the_post();
4132
4133 $property = new PH_Property((int)get_post_meta(get_the_ID(), '_property_id', TRUE));
4134
4135 echo '<tr>';
4136 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>';
4137 echo '<td style="text-align:left;">';
4138 if ( get_post_meta(get_the_ID(), '_property_id', TRUE) != '' )
4139 {
4140 echo '<a href="' . get_edit_post_link( get_post_meta(get_the_ID(), '_property_id', TRUE), '' ) . '">' . $property->get_formatted_full_address() . '</a>';
4141 }
4142 else
4143 {
4144 echo '-';
4145 }
4146 echo '</td>';
4147
4148 echo '<td style="text-align:left;">';
4149
4150 $negotiator_ids = get_post_meta(get_the_ID(), '_negotiator_id');
4151
4152 if (!empty($negotiator_ids))
4153 {
4154 $i = 0;
4155 foreach ($negotiator_ids as $negotiator_id)
4156 {
4157 if ( $i > 0 ) { echo ', '; }
4158
4159 $userdata = get_userdata( $negotiator_id );
4160 if ( $userdata !== FALSE )
4161 {
4162 echo $userdata->display_name;
4163 }
4164 else
4165 {
4166 echo '<em>Unknown user</em>';
4167 }
4168 ++$i;
4169 }
4170 }
4171 else
4172 {
4173 echo 'Unattended';
4174 }
4175
4176 echo '</td>';
4177 echo '<td style="text-align:left;">';
4178
4179 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4180 echo ucwords(str_replace("_", " ", $status));
4181 if ( $status == 'pending' )
4182 {
4183 echo '<br>';
4184 // confirmation status
4185 if ( get_post_meta(get_the_ID(), '_all_confirmed', TRUE) == 'yes' )
4186 {
4187 echo __( 'All Parties Confirmed', 'propertyhive' );
4188 }
4189 else
4190 {
4191 echo __( 'Awaiting Confirmation', 'propertyhive' );
4192 }
4193 }
4194 if ( $status == 'carried_out' )
4195 {
4196 echo '<br>';
4197 $feedback_status = get_post_meta(get_the_ID(), '_feedback_status', TRUE);
4198 switch ( get_post_meta(get_the_ID(), '_feedback_status', TRUE) )
4199 {
4200 case "interested": { echo 'Applicant Interested'; break; }
4201 case "not_interested": { echo 'Applicant Not Interested'; break; }
4202 case "not_required": { echo 'Feedback Not Required'; break; }
4203 default: { echo 'Awaiting Feedback'; }
4204 }
4205
4206 if ( $feedback_status == 'interested' || $feedback_status == 'not_interested' )
4207 {
4208 $feedback_passed_on = get_post_meta(get_the_ID(), '_feedback_passed_on', TRUE);
4209 echo '<br>' . ( ($feedback_passed_on == 'yes') ? 'Feedback Passed On' : 'Feedback Not Passed On' );
4210 }
4211 }
4212 echo '</td>';
4213 echo '</tr>';
4214 }
4215
4216 echo '
4217 </tbody>
4218 </table>
4219 <br>';
4220 }
4221 else
4222 {
4223 echo '<p>' . __( 'No viewings exist for this contact', 'propertyhive') . '</p>';
4224 }
4225 wp_reset_postdata();
4226
4227 do_action('propertyhive_contact_viewings_fields');
4228
4229 echo '</div>';
4230
4231 echo '</div>';
4232
4233 die();
4234 }
4235
4236 // Offer related functions
4237 public function record_offer_property()
4238 {
4239 check_ajax_referer( 'record-offer', 'security' );
4240
4241 $this->json_headers();
4242
4243 // TO DO: Should do validation on server side also
4244 if (empty($_POST['property_id']))
4245 {
4246 $return = array('error' => 'No property selected');
4247 echo json_encode( $return );
4248 die();
4249 }
4250
4251 $property = new PH_Property((int)$_POST['property_id']);
4252
4253 $applicant_contact_ids = array();
4254
4255 // Create applicant record if required
4256 if (empty($_POST['applicant_ids']) && !empty($_POST['applicant_name']))
4257 {
4258 // Need to create contact/applicant
4259 $contact_post = array(
4260 'post_title' => ph_clean($_POST['applicant_name']),
4261 'post_content' => '',
4262 'post_type' => 'contact',
4263 'post_status' => 'publish',
4264 'comment_status' => 'closed',
4265 'ping_status' => 'closed',
4266 );
4267
4268 // Insert the post into the database
4269 $contact_post_id = wp_insert_post( $contact_post );
4270
4271 if ( is_wp_error($contact_post_id) || $contact_post_id == 0 )
4272 {
4273 $return = array('error' => 'Failed to create contact post. Please try again');
4274 echo json_encode( $return );
4275 die();
4276 }
4277
4278 update_post_meta( $contact_post_id, '_contact_types', array('applicant') );
4279
4280 update_post_meta( $contact_post_id, '_applicant_profiles', 1 );
4281 update_post_meta( $contact_post_id, '_applicant_profile_0', array( 'department' => $property->department, 'send_matching_properties' => '' ) );
4282
4283 $applicant_contact_ids[] = $contact_post_id;
4284 }
4285
4286 if (!empty($_POST['applicant_ids']) && empty($_POST['applicant_name']))
4287 {
4288 // This is an existing contact
4289 if ( !is_array($_POST['applicant_ids']) )
4290 {
4291 $_POST['applicant_ids'] = array($_POST['applicant_ids']);
4292 }
4293
4294 foreach ( $_POST['applicant_ids'] as $applicant_id )
4295 {
4296 $applicant_contact_ids[] = (int)$applicant_id;
4297 }
4298 }
4299
4300 $applicant_contact_ids = array_unique($applicant_contact_ids);
4301
4302 if ( empty($applicant_contact_ids) )
4303 {
4304 $return = array('error' => 'No applicant selected, or unable to create applicant record');
4305 echo json_encode( $return );
4306 die();
4307 }
4308
4309 // Loop through contacts and create one offer each
4310 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
4311 foreach ( $applicant_contact_ids as $applicant_contact_id )
4312 {
4313 // Insert offer record
4314 $offer_post = array(
4315 'post_title' => '',
4316 'post_content' => '',
4317 'post_type' => 'offer',
4318 'post_status' => 'publish',
4319 'comment_status' => 'closed',
4320 'ping_status' => 'closed',
4321 );
4322
4323 // Insert the post into the database
4324 $offer_post_id = wp_insert_post( $offer_post );
4325
4326 if ( is_wp_error($offer_post_id) || $offer_post_id == 0 )
4327 {
4328 $return = array('error' => 'Failed to create offer post. Please try again');
4329 echo json_encode( $return );
4330 die();
4331 }
4332
4333 $amount = preg_replace("/[^0-9]/", '', $_POST['amount']);
4334
4335 add_post_meta( $offer_post_id, '_offer_date_time', ph_clean($_POST['offer_date']) . ' ' . ph_clean($_POST['offer_time']) );
4336 add_post_meta( $offer_post_id, '_property_id', (int)$_POST['property_id'] );
4337 add_post_meta( $offer_post_id, '_applicant_contact_id', $applicant_contact_id );
4338 add_post_meta( $offer_post_id, '_amount', $amount );
4339 add_post_meta( $offer_post_id, '_status', 'pending' );
4340 }
4341
4342 $applicant_contacts = array();
4343 foreach ( $applicant_contact_ids as $applicant_contact_id )
4344 {
4345 $applicant_contacts[] = array(
4346 'ID' => $applicant_contact_id,
4347 'post_title' => get_the_title($applicant_contact_id),
4348 'edit_link' => get_edit_post_link( $applicant_contact_id, '' ),
4349 );
4350 }
4351
4352 $return = array('success' => array(
4353 'offer' => array(
4354 'ID' => $offer_post_id,
4355 'edit_link' => get_edit_post_link( $offer_post_id, '' ),
4356 ),
4357 'applicant_contacts' => $applicant_contacts,
4358 ));
4359
4360 echo json_encode( $return );
4361
4362 die();
4363 }
4364
4365 public function record_offer_contact()
4366 {
4367 check_ajax_referer( 'record-offer', 'security' );
4368
4369 $this->json_headers();
4370
4371 // TO DO: Should do validation on server side also
4372 if (empty($_POST['contact_id']))
4373 {
4374 $return = array('error' => 'No contact selected');
4375 echo json_encode( $return );
4376 die();
4377 }
4378
4379 if (empty($_POST['property_ids']))
4380 {
4381 $return = array('error' => 'No property selected');
4382 echo json_encode( $return );
4383 die();
4384 }
4385
4386 // Loop through contacts and create one offer each
4387 // At the moment it's a 1-to-1 relationship, but might support multiple in the future
4388 foreach ( $_POST['property_ids'] as $property_id )
4389 {
4390 // Insert offer record
4391 $offer_post = array(
4392 'post_title' => '',
4393 'post_content' => '',
4394 'post_type' => 'offer',
4395 'post_status' => 'publish',
4396 'comment_status' => 'closed',
4397 'ping_status' => 'closed',
4398 );
4399
4400 // Insert the post into the database
4401 $offer_post_id = wp_insert_post( $offer_post );
4402
4403 if ( is_wp_error($offer_post_id) || $offer_post_id == 0 )
4404 {
4405 $return = array('error' => 'Failed to create offer post. Please try again');
4406 echo json_encode( $return );
4407 die();
4408 }
4409
4410 $amount = preg_replace("/[^0-9]/", '', ph_clean($_POST['amount']));
4411
4412 add_post_meta( $offer_post_id, '_offer_date_time', ph_clean($_POST['offer_date']) . ' ' . ph_clean($_POST['offer_time']) );
4413 add_post_meta( $offer_post_id, '_property_id', (int)$property_id );
4414 add_post_meta( $offer_post_id, '_applicant_contact_id', (int)$_POST['contact_id'] );
4415 add_post_meta( $offer_post_id, '_amount', $amount );
4416 add_post_meta( $offer_post_id, '_status', 'pending' );
4417 }
4418
4419 $properties = array();
4420 foreach ( $_POST['property_ids'] as $property_id )
4421 {
4422 $properties[] = array(
4423 'ID' => (int)$property_id,
4424 'post_title' => get_the_title((int)$property_id),
4425 'edit_link' => get_edit_post_link( (int)$property_id, '' ),
4426 );
4427 }
4428
4429 $return = array('success' => array(
4430 'offer' => array(
4431 'ID' => $offer_post_id,
4432 'edit_link' => get_edit_post_link( $offer_post_id, '' ),
4433 ),
4434 'properties' => $properties,
4435 ));
4436
4437 echo json_encode( $return );
4438
4439 die();
4440 }
4441
4442 public function get_offer_details_meta_box()
4443 {
4444 global $post;
4445
4446 check_ajax_referer( 'offer-details-meta-box', 'security' );
4447
4448 $post = get_post((int)$_POST['offer_id']);
4449
4450 $offer = new PH_Offer((int)$_POST['offer_id']);
4451
4452 echo '<div class="propertyhive_meta_box">';
4453
4454 echo '<div class="options_group">';
4455
4456 if ( $offer->status != '' )
4457 {
4458 echo '<p class="form-field">
4459
4460 <label for="">' . __('Status', 'propertyhive') . '</label>
4461
4462 ' . ucwords(str_replace("_", " ", $offer->status)) . '
4463
4464 </p>';
4465 }
4466
4467 $offer_date_time = $offer->offer_date_time;
4468 if ( empty($offer_date_time) )
4469 {
4470 $offer_date_time = date("Y-m-d H:i:s");
4471 }
4472
4473 echo '<p class="form-field offer_date_time_field">
4474
4475 <label for="_offer_date">' . __('Offer Date / Time', 'propertyhive') . '</label>
4476
4477 <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)) . '">
4478 <select id="_offer_time_hours" name="_offer_time_hours" class="select short" style="width:55px">';
4479
4480 if ( empty($offer_date_time) )
4481 {
4482 $value = date("H");
4483 }
4484 else
4485 {
4486 $value = date( "H", strtotime( $offer_date_time ) );
4487 }
4488 for ( $i = 0; $i < 23; ++$i )
4489 {
4490 $j = str_pad($i, 2, '0', STR_PAD_LEFT);
4491 echo '<option value="' . $j . '"';
4492 if ($i == $value) { echo ' selected'; }
4493 echo '>' . $j . '</option>';
4494 }
4495
4496 echo '</select>
4497 :
4498 <select id="_offer_time_minutes" name="_offer_time_minutes" class="select short" style="width:55px">';
4499
4500 if ( empty($offer_date_time) )
4501 {
4502 $value = '';
4503 }
4504 else
4505 {
4506 $value = date( "i", strtotime( $offer_date_time ) );
4507 }
4508 for ( $i = 0; $i < 60; $i+=5 )
4509 {
4510 $j = str_pad($i, 2, '0', STR_PAD_LEFT);
4511 echo '<option value="' . $j . '"';
4512 if ($i == $value) { echo ' selected'; }
4513 echo '>' . $j . '</option>';
4514 }
4515
4516 echo '</select>
4517
4518 </p>';
4519
4520 $args = array(
4521 'id' => '_amount',
4522 'label' => __( 'Offer Amount', 'propertyhive' ) . ' (&pound;)',
4523 'desc_tip' => false,
4524 'class' => 'short',
4525 'value' => ( is_numeric($offer->amount) ? number_format($offer->amount) : '' ),
4526 'custom_attributes' => array(
4527 //'style' => 'width:95%; max-width:500px;'
4528 )
4529 );
4530 propertyhive_wp_text_input( $args );
4531
4532 do_action('propertyhive_offer_details_fields');
4533
4534 echo '</div>';
4535
4536 echo '</div>';
4537
4538 die();
4539 }
4540
4541 public function get_offer_actions()
4542 {
4543 check_ajax_referer( 'offer-actions', 'security' );
4544
4545 $post_id = (int)$_POST['offer_id'];
4546
4547 $status = get_post_meta( $post_id, '_status', TRUE );
4548
4549 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_offer_actions_meta_box">
4550
4551 <div class="options_group" style="padding-top:8px;">';
4552
4553 $actions = array();
4554
4555 if ( $status == 'pending' )
4556 {
4557 $actions[] = '<a
4558 href="#action_panel_offer_accepted"
4559 class="button button-success offer-action"
4560 style="width:100%; margin-bottom:7px; text-align:center"
4561 >' . wp_kses_post( __('Accept Offer', 'propertyhive') ) . '</a>';
4562 $actions[] = '<a
4563 href="#action_panel_offer_declined"
4564 class="button button-danger offer-action"
4565 style="width:100%; margin-bottom:7px; text-align:center"
4566 >' . wp_kses_post( __('Decline Offer', 'propertyhive') ) . '</a>';
4567 }
4568
4569 if ( $status == 'accepted' )
4570 {
4571 // See if a sale has this offer id associated with it
4572 $sale_id = get_post_meta( $post_id, '_sale_id', TRUE );
4573 if ( $sale_id != '' && get_post_status($sale_id) != 'publish' )
4574 {
4575 $sale_id = '';
4576 }
4577
4578 if ( $sale_id != '' )
4579 {
4580 $actions[] = '<a
4581 href="' . get_edit_post_link( $sale_id, '' ) . '"
4582 class="button"
4583 style="width:100%; margin-bottom:7px; text-align:center"
4584 >' . wp_kses_post( __('View Sale', 'propertyhive') ) . '</a>';
4585 }
4586 else
4587 {
4588 $actions[] = '<a
4589 href="' . wp_nonce_url( admin_url( 'post.php?post=' . $post_id . '&action=edit' ), '1', 'create_sale' ) . '"
4590 class="button button-success"
4591 style="width:100%; margin-bottom:7px; text-align:center"
4592 >' . wp_kses_post( __('Create Sale', 'propertyhive') ) . '</a>';
4593 }
4594 }
4595
4596 if ( $status == 'declined' )
4597 {
4598
4599 }
4600
4601 if ( $status == 'accepted' || $status == 'declined' )
4602 {
4603 $actions[] = '<a
4604 href="#action_panel_offer_revert_pending"
4605 class="button offer-action"
4606 style="width:100%; margin-bottom:7px; text-align:center"
4607 >' . wp_kses_post( __('Revert To Pending', 'propertyhive') ) . '</a>';
4608 }
4609
4610 $actions = apply_filters( 'propertyhive_admin_offer_actions', $actions, $post_id );
4611
4612 if ( !empty($actions) )
4613 {
4614 echo implode("", $actions);
4615 }
4616 else
4617 {
4618 echo '<div style="text-align:center">' . __( 'No actions to display', 'propertyhive' ) . '</div>';
4619 }
4620
4621 echo '</div>
4622
4623 </div>';
4624
4625 die();
4626 }
4627
4628 public function offer_accepted()
4629 {
4630 check_ajax_referer( 'offer-actions', 'security' );
4631
4632 $post_id = (int)$_POST['offer_id'];
4633
4634 $status = get_post_meta( $post_id, '_status', TRUE );
4635
4636 if ( $status == 'pending' )
4637 {
4638 update_post_meta( $post_id, '_status', 'accepted' );
4639
4640 $current_user = wp_get_current_user();
4641
4642 // Add note/comment to offer
4643 $comment = array(
4644 'note_type' => 'action',
4645 'action' => 'offer_accepted',
4646 );
4647
4648 $data = array(
4649 'comment_post_ID' => $post_id,
4650 'comment_author' => $current_user->display_name,
4651 'comment_author_email' => 'propertyhive@noreply.com',
4652 'comment_author_url' => '',
4653 'comment_date' => date("Y-m-d H:i:s"),
4654 'comment_content' => serialize($comment),
4655 'comment_approved' => 1,
4656 'comment_type' => 'propertyhive_note',
4657 );
4658 $comment_id = wp_insert_comment( $data );
4659 }
4660
4661 die();
4662 }
4663
4664 public function offer_declined()
4665 {
4666 check_ajax_referer( 'offer-actions', 'security' );
4667
4668 $post_id = (int)$_POST['offer_id'];
4669
4670 $status = get_post_meta( $post_id, '_status', TRUE );
4671
4672 if ( $status == 'pending' )
4673 {
4674 update_post_meta( $post_id, '_status', 'declined' );
4675
4676 $current_user = wp_get_current_user();
4677
4678 // Add note/comment to offer
4679 $comment = array(
4680 'note_type' => 'action',
4681 'action' => 'offer_declined',
4682 );
4683
4684 $data = array(
4685 'comment_post_ID' => $post_id,
4686 'comment_author' => $current_user->display_name,
4687 'comment_author_email' => 'propertyhive@noreply.com',
4688 'comment_author_url' => '',
4689 'comment_date' => date("Y-m-d H:i:s"),
4690 'comment_content' => serialize($comment),
4691 'comment_approved' => 1,
4692 'comment_type' => 'propertyhive_note',
4693 );
4694 $comment_id = wp_insert_comment( $data );
4695 }
4696
4697 die();
4698 }
4699
4700 public function offer_revert_pending()
4701 {
4702 check_ajax_referer( 'offer-actions', 'security' );
4703
4704 $post_id = (int)$_POST['offer_id'];
4705
4706 $status = get_post_meta( $post_id, '_status', TRUE );
4707
4708 if ( $status == 'accepted' || $status == 'declined' )
4709 {
4710 update_post_meta( $post_id, '_status', 'pending' );
4711
4712 $current_user = wp_get_current_user();
4713
4714 // Add note/comment to offer
4715 $comment = array(
4716 'note_type' => 'action',
4717 'action' => 'offer_revert_pending',
4718 );
4719
4720 $data = array(
4721 'comment_post_ID' => $post_id,
4722 'comment_author' => $current_user->display_name,
4723 'comment_author_email' => 'propertyhive@noreply.com',
4724 'comment_author_url' => '',
4725 'comment_date' => date("Y-m-d H:i:s"),
4726 'comment_content' => serialize($comment),
4727 'comment_approved' => 1,
4728 'comment_type' => 'propertyhive_note',
4729 );
4730 $comment_id = wp_insert_comment( $data );
4731 }
4732
4733 die();
4734 }
4735
4736 public function get_property_offers_meta_box()
4737 {
4738 check_ajax_referer( 'get_property_offers_meta_box', 'security' );
4739
4740 global $post;
4741
4742 echo '<div class="propertyhive_meta_box">';
4743
4744 echo '<div class="options_group">';
4745
4746 $args = array(
4747 'post_type' => 'offer',
4748 'nopaging' => true,
4749 'orderby' => 'meta_value',
4750 'order' => 'DESC',
4751 'meta_key' => '_offer_date_time',
4752 'post_status' => 'publish',
4753 'meta_query' => array(
4754 array(
4755 'key' => '_property_id',
4756 'value' => (int)$_POST['post_id']
4757 )
4758 )
4759 );
4760 $offers_query = new WP_Query( $args );
4761
4762 if ( $offers_query->have_posts() )
4763 {
4764 echo '<table style="width:100%">
4765 <thead>
4766 <tr>
4767 <th style="text-align:left;">' . __( 'Offer Date', 'propertyhive' ) . '</th>
4768 <th style="text-align:left;">' . __( 'Applicant', 'propertyhive' ) . '</th>
4769 <th style="text-align:left;">' . __( 'Offer Amount', 'propertyhive' ) . '</th>
4770 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
4771 </tr>
4772 </thead>
4773 <tbody>';
4774
4775 while ( $offers_query->have_posts() )
4776 {
4777 $offers_query->the_post();
4778
4779 $offer = new PH_Offer(get_the_ID());
4780
4781 echo '<tr>';
4782 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>';
4783 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>';
4784 echo '<td style="text-align:left;">' . $offer->get_formatted_amount() . '</td>';
4785 echo '<td style="text-align:left;">';
4786 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4787 echo ucwords(str_replace("_", " ", $status));
4788 echo '</td>';
4789 echo '</tr>';
4790 }
4791
4792 echo '
4793 </tbody>
4794 </table>
4795 <br>';
4796 }
4797 else
4798 {
4799 echo '<p>' . __( 'No offers exist for this property', 'propertyhive') . '</p>';
4800 }
4801 wp_reset_postdata();
4802
4803 do_action('propertyhive_property_offers_fields');
4804
4805 echo '</div>';
4806
4807 echo '</div>';
4808
4809 die();
4810 }
4811
4812 public function get_contact_offers_meta_box()
4813 {
4814 check_ajax_referer( 'get_contact_offers_meta_box', 'security' );
4815
4816 global $post;
4817
4818 echo '<div class="propertyhive_meta_box">';
4819
4820 echo '<div class="options_group">';
4821
4822 $args = array(
4823 'post_type' => 'offer',
4824 'nopaging' => true,
4825 'orderby' => 'meta_value',
4826 'order' => 'DESC',
4827 'post_status' => 'publish',
4828 'meta_key' => '_offer_date_time',
4829 'meta_query' => array(
4830 array(
4831 'key' => '_applicant_contact_id',
4832 'value' => (int)$_POST['post_id']
4833 )
4834 )
4835 );
4836 $offers_query = new WP_Query( $args );
4837
4838 if ( $offers_query->have_posts() )
4839 {
4840 echo '<table style="width:100%">
4841 <thead>
4842 <tr>
4843 <th style="text-align:left;">' . __( 'Offer Date', 'propertyhive' ) . '</th>
4844 <th style="text-align:left;">' . __( 'Property', 'propertyhive' ) . '</th>
4845 <th style="text-align:left;">' . __( 'Property Owner', 'propertyhive' ) . '</th>
4846 <th style="text-align:left;">' . __( 'Offer Amount', 'propertyhive' ) . '</th>
4847 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
4848 </tr>
4849 </thead>
4850 <tbody>';
4851
4852 while ( $offers_query->have_posts() )
4853 {
4854 $offers_query->the_post();
4855
4856 $property = new PH_Property((int)get_post_meta(get_the_ID(), '_property_id', TRUE));
4857 $offer = new PH_Offer(get_the_ID());
4858
4859 echo '<tr>';
4860 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>';
4861 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>';
4862 echo '<td style="text-align:left;">';
4863
4864 $owner_contact_ids = $property->_owner_contact_id;
4865 if (
4866 ( !is_array($owner_contact_ids) && $owner_contact_ids != '' && $owner_contact_ids != 0 )
4867 ||
4868 ( is_array($owner_contact_ids) && !empty($owner_contact_ids) )
4869 )
4870 {
4871 if ( !is_array($owner_contact_ids) )
4872 {
4873 $owner_contact_ids = array($owner_contact_ids);
4874 }
4875
4876 foreach ( $owner_contact_ids as $owner_contact_id )
4877 {
4878 echo get_the_title($owner_contact_id) . '<br>';
4879 echo '<div style="color:#BBB">';
4880 echo 'T: ' . get_post_meta($owner_contact_id, '_telephone_number', TRUE) . '<br>';
4881 echo 'E: ' . get_post_meta($owner_contact_id, '_email_address', TRUE);
4882 echo '</div>';
4883 }
4884 }
4885
4886 echo '</td>';
4887 echo '<td style="text-align:left;">' . $offer->get_formatted_amount() . '</td>';
4888 echo '<td style="text-align:left;">';
4889 $status = get_post_meta(get_the_ID(), '_status', TRUE);
4890 echo ucwords(str_replace("_", " ", $status));
4891 echo '</td>';
4892 echo '</tr>';
4893 }
4894
4895 echo '
4896 </tbody>
4897 </table>
4898 <br>';
4899 }
4900 else
4901 {
4902 echo '<p>' . __( 'No offers exist for this contact', 'propertyhive') . '</p>';
4903 }
4904 wp_reset_postdata();
4905
4906 do_action('propertyhive_contact_offers_fields');
4907
4908 echo '</div>';
4909
4910 echo '</div>';
4911
4912 die();
4913 }
4914
4915 // Sale related functions
4916 public function get_sale_details_meta_box()
4917 {
4918 global $post;
4919
4920 check_ajax_referer( 'sale-details-meta-box', 'security' );
4921
4922 $post = get_post((int)$_POST['sale_id']);
4923
4924 $sale = new PH_Offer((int)$_POST['sale_id']);
4925
4926 echo '<div class="propertyhive_meta_box">';
4927
4928 echo '<div class="options_group">';
4929
4930 if ( $sale->status != '' )
4931 {
4932 echo '<p class="form-field">
4933
4934 <label for="">' . __('Status', 'propertyhive') . '</label>
4935
4936 ' . ucwords(str_replace("_", " ", $sale->status)) . '
4937
4938 </p>';
4939 }
4940
4941 $sale_date_time = $sale->sale_date_time;
4942 if ( empty($sale_date_time) )
4943 {
4944 $sale_date_time = date("Y-m-d H:i:s");
4945 }
4946
4947 echo '<p class="form-field sale_date_field">
4948
4949 <label for="_sale_date">' . __('Sale Date', 'propertyhive') . '</label>
4950
4951 <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)) . '">
4952
4953 </p>';
4954
4955 $args = array(
4956 'id' => '_amount',
4957 'label' => __( 'Sale Amount', 'propertyhive' ) . ' (&pound;)',
4958 'desc_tip' => false,
4959 'class' => 'short',
4960 'value' => ( is_numeric($sale->amount) ? number_format($sale->amount) : '' ),
4961 'custom_attributes' => array(
4962 //'style' => 'width:95%; max-width:500px;'
4963 )
4964 );
4965 propertyhive_wp_text_input( $args );
4966
4967 do_action('propertyhive_sale_details_fields');
4968
4969 echo '</div>';
4970
4971 echo '</div>';
4972
4973 die();
4974 }
4975
4976 public function get_sale_actions()
4977 {
4978 check_ajax_referer( 'sale-actions', 'security' );
4979
4980 $post_id = (int)$_POST['sale_id'];
4981
4982 $status = get_post_meta( $post_id, '_status', TRUE );
4983
4984 echo '<div class="propertyhive_meta_box propertyhive_meta_box_actions" id="propertyhive_sale_actions_meta_box">
4985
4986 <div class="options_group" style="padding-top:8px;">';
4987
4988 $actions = array();
4989
4990 if ( $status == 'current' )
4991 {
4992 $actions[] = '<a
4993 href="#action_panel_sale_exchanged"
4994 class="button button-success sale-action"
4995 style="width:100%; margin-bottom:7px; text-align:center"
4996 >' . __('Sale Exchanged', 'propertyhive') . '</a>';
4997
4998 }
4999
5000 if ( $status == 'exchanged' )
5001 {
5002 $actions[] = '<a
5003 href="#action_panel_sale_completed"
5004 class="button button-success sale-action"
5005 style="width:100%; margin-bottom:7px; text-align:center"
5006 >' . __('Sale Completed', 'propertyhive') . '</a>';
5007 }
5008
5009 if ( $status == 'completed' )
5010 {
5011
5012 }
5013
5014 if ( $status == 'current' || $status == 'exchanged' )
5015 {
5016 $actions[] = '<a
5017 href="#action_panel_sale_fallen_through"
5018 class="button sale-action"
5019 style="width:100%; margin-bottom:7px; text-align:center"
5020 >' . __('Sale Fallen Through', 'propertyhive') . '</a>';
5021 }
5022
5023 $actions = apply_filters( 'propertyhive_admin_sale_actions', $actions, $post_id );
5024
5025 if ( !empty($actions) )
5026 {
5027 echo implode("", $actions);
5028 }
5029 else
5030 {
5031 echo '<div style="text-align:center">' . __( 'No actions to display', 'propertyhive' ) . '</div>';
5032 }
5033
5034 echo '</div>
5035
5036 </div>';
5037
5038 die();
5039 }
5040
5041 public function sale_exchanged()
5042 {
5043 check_ajax_referer( 'sale-actions', 'security' );
5044
5045 $post_id = (int)$_POST['sale_id'];
5046
5047 $status = get_post_meta( $post_id, '_status', TRUE );
5048
5049 if ( $status == 'current' )
5050 {
5051 update_post_meta( $post_id, '_status', 'exchanged' );
5052
5053 $current_user = wp_get_current_user();
5054
5055 // Add note/comment to sale
5056 $comment = array(
5057 'note_type' => 'action',
5058 'action' => 'sale_exchanged',
5059 );
5060
5061 $data = array(
5062 'comment_post_ID' => $post_id,
5063 'comment_author' => $current_user->display_name,
5064 'comment_author_email' => 'propertyhive@noreply.com',
5065 'comment_author_url' => '',
5066 'comment_date' => date("Y-m-d H:i:s"),
5067 'comment_content' => serialize($comment),
5068 'comment_approved' => 1,
5069 'comment_type' => 'propertyhive_note',
5070 );
5071 $comment_id = wp_insert_comment( $data );
5072 }
5073
5074 die();
5075 }
5076
5077 public function sale_completed()
5078 {
5079 check_ajax_referer( 'sale-actions', 'security' );
5080
5081 $post_id = (int)$_POST['sale_id'];
5082
5083 $status = get_post_meta( $post_id, '_status', TRUE );
5084
5085 if ( $status == 'exchanged' )
5086 {
5087 update_post_meta( $post_id, '_status', 'completed' );
5088
5089 $current_user = wp_get_current_user();
5090
5091 // Add note/comment to sale
5092 $comment = array(
5093 'note_type' => 'action',
5094 'action' => 'sale_completed',
5095 );
5096
5097 $data = array(
5098 'comment_post_ID' => $post_id,
5099 'comment_author' => $current_user->display_name,
5100 'comment_author_email' => 'propertyhive@noreply.com',
5101 'comment_author_url' => '',
5102 'comment_date' => date("Y-m-d H:i:s"),
5103 'comment_content' => serialize($comment),
5104 'comment_approved' => 1,
5105 'comment_type' => 'propertyhive_note',
5106 );
5107 $comment_id = wp_insert_comment( $data );
5108 }
5109
5110 die();
5111 }
5112
5113 public function sale_fallen_through()
5114 {
5115 check_ajax_referer( 'sale-actions', 'security' );
5116
5117 $post_id = (int)$_POST['sale_id'];
5118
5119 $status = get_post_meta( $post_id, '_status', TRUE );
5120
5121 if ( $status == 'current' || $status == 'exchanged' )
5122 {
5123 update_post_meta( $post_id, '_status', 'fallen_through' );
5124
5125 $current_user = wp_get_current_user();
5126
5127 // Add note/comment to sale
5128 $comment = array(
5129 'note_type' => 'action',
5130 'action' => 'sale_fallen_through',
5131 );
5132
5133 $data = array(
5134 'comment_post_ID' => $post_id,
5135 'comment_author' => $current_user->display_name,
5136 'comment_author_email' => 'propertyhive@noreply.com',
5137 'comment_author_url' => '',
5138 'comment_date' => date("Y-m-d H:i:s"),
5139 'comment_content' => serialize($comment),
5140 'comment_approved' => 1,
5141 'comment_type' => 'propertyhive_note',
5142 );
5143 $comment_id = wp_insert_comment( $data );
5144 }
5145
5146 die();
5147 }
5148
5149 public function get_property_sales_meta_box()
5150 {
5151 check_ajax_referer( 'get_property_sales_meta_box', 'security' );
5152
5153 global $post;
5154
5155 echo '<div class="propertyhive_meta_box">';
5156
5157 echo '<div class="options_group">';
5158
5159 $args = array(
5160 'post_type' => 'sale',
5161 'nopaging' => true,
5162 'orderby' => 'meta_value',
5163 'order' => 'DESC',
5164 'meta_key' => '_sale_date_time',
5165 'post_status' => 'publish',
5166 'meta_query' => array(
5167 array(
5168 'key' => '_property_id',
5169 'value' => (int)$_POST['post_id']
5170 )
5171 )
5172 );
5173 $sales_query = new WP_Query( $args );
5174
5175 if ( $sales_query->have_posts() )
5176 {
5177 echo '<table style="width:100%">
5178 <thead>
5179 <tr>
5180 <th style="text-align:left;">' . __( 'Sale Date', 'propertyhive' ) . '</th>
5181 <th style="text-align:left;">' . __( 'Applicant', 'propertyhive' ) . '</th>
5182 <th style="text-align:left;">' . __( 'Sale Amount', 'propertyhive' ) . '</th>
5183 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
5184 </tr>
5185 </thead>
5186 <tbody>';
5187
5188 while ( $sales_query->have_posts() )
5189 {
5190 $sales_query->the_post();
5191
5192 $sale = new PH_Sale(get_the_ID());
5193
5194 echo '<tr>';
5195 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>';
5196 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>';
5197 echo '<td style="text-align:left;">' . $sale->get_formatted_amount() . '</td>';
5198 echo '<td style="text-align:left;">';
5199 $status = get_post_meta(get_the_ID(), '_status', TRUE);
5200 echo ucwords(str_replace("_", " ", $status));
5201 echo '</td>';
5202 echo '</tr>';
5203 }
5204
5205 echo '
5206 </tbody>
5207 </table>
5208 <br>';
5209 }
5210 else
5211 {
5212 echo '<p>' . __( 'No sales exist for this property', 'propertyhive') . '</p>';
5213 }
5214 wp_reset_postdata();
5215
5216 do_action('propertyhive_property_sales_fields');
5217
5218 echo '</div>';
5219
5220 echo '</div>';
5221
5222 die();
5223 }
5224
5225 public function get_contact_sales_meta_box()
5226 {
5227 check_ajax_referer( 'get_contact_sales_meta_box', 'security' );
5228
5229 global $post;
5230
5231 echo '<div class="propertyhive_meta_box">';
5232
5233 echo '<div class="options_group">';
5234
5235 $args = array(
5236 'post_type' => 'sale',
5237 'nopaging' => true,
5238 'orderby' => 'meta_value',
5239 'order' => 'DESC',
5240 'post_status' => 'publish',
5241 'meta_key' => '_sale_date_time',
5242 'meta_query' => array(
5243 array(
5244 'key' => '_applicant_contact_id',
5245 'value' => (int)$_POST['post_id']
5246 )
5247 )
5248 );
5249 $sales_query = new WP_Query( $args );
5250
5251 if ( $sales_query->have_posts() )
5252 {
5253 echo '<table style="width:100%">
5254 <thead>
5255 <tr>
5256 <th style="text-align:left;">' . __( 'Offer Date', 'propertyhive' ) . '</th>
5257 <th style="text-align:left;">' . __( 'Property', 'propertyhive' ) . '</th>
5258 <th style="text-align:left;">' . __( 'Property Owner', 'propertyhive' ) . '</th>
5259 <th style="text-align:left;">' . __( 'Offer Amount', 'propertyhive' ) . '</th>
5260 <th style="text-align:left;">' . __( 'Status', 'propertyhive' ) . '</th>
5261 </tr>
5262 </thead>
5263 <tbody>';
5264
5265 while ( $sales_query->have_posts() )
5266 {
5267 $sales_query->the_post();
5268
5269 $sale = new PH_Sale(get_the_ID());
5270
5271 $property = new PH_Property((int)get_post_meta(get_the_ID(), '_property_id', TRUE));
5272
5273 echo '<tr>';
5274 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>';
5275 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>';
5276 echo '<td style="text-align:left;">';
5277
5278 $owner_contact_ids = $property->_owner_contact_id;
5279 if (
5280 ( !is_array($owner_contact_ids) && $owner_contact_ids != '' && $owner_contact_ids != 0 )
5281 ||
5282 ( is_array($owner_contact_ids) && !empty($owner_contact_ids) )
5283 )
5284 {
5285 if ( !is_array($owner_contact_ids) )
5286 {
5287 $owner_contact_ids = array($owner_contact_ids);
5288 }
5289
5290 foreach ( $owner_contact_ids as $owner_contact_id )
5291 {
5292 echo get_the_title($owner_contact_id) . '<br>';
5293 echo '<div style="color:#BBB">';
5294 echo 'T: ' . get_post_meta($owner_contact_id, '_telephone_number', TRUE) . '<br>';
5295 echo 'E: ' . get_post_meta($owner_contact_id, '_email_address', TRUE);
5296 echo '</div>';
5297 }
5298 }
5299
5300 echo '</td>';
5301 echo '<td style="text-align:left;">' . $sale->get_formatted_amount() . '</td>';
5302 echo '<td style="text-align:left;">';
5303 $status = get_post_meta(get_the_ID(), '_status', TRUE);
5304 echo ucwords(str_replace("_", " ", $status));
5305 echo '</td>';
5306 echo '</tr>';
5307 }
5308
5309 echo '
5310 </tbody>
5311 </table>
5312 <br>';
5313 }
5314 else
5315 {
5316 echo '<p>' . __( 'No sales exist for this contact', 'propertyhive') . '</p>';
5317 }
5318 wp_reset_postdata();
5319
5320 do_action('propertyhive_contact_sales_fields');
5321
5322 echo '</div>';
5323
5324 echo '</div>';
5325
5326 die();
5327 }
5328 }
5329
5330 new PH_AJAX();
5331