PluginProbe
Property Hive / 1.4.59
Property Hive v1.4.59
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.59, at includes/class-ph-ajax.php

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