PluginProbe
Property Hive / 1.4.53
Property Hive v1.4.53
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 1.4.62 All 260 releases
propertyhive / includes / class-ph-ajax.php

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

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