PluginProbe
Property Hive / 1.4.57
Property Hive v1.4.57
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.57, at includes/class-ph-ajax.php

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