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

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

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