| @@ -6,10 +6,8 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace Timetics\Core\Bookings; |
| 9 | 9 | |
| 10 | -defined( 'ABSPATH' ) || exit; | |
| 11 | - | |
| 12 | 10 | use Timetics\Core\Appointments\Appointment; |
| 13 | 11 | use Timetics\Core\Customers\Customer; |
| 14 | 12 | use Timetics\Core\Integrations\Google\Service\Calendar; |
| 15 | 13 | use Timetics\Core\Staffs\Staff; |
| @@ -357,17 +355,8 @@ | ||
| 357 | 355 | return $this->get_prop( 'payment_method' ); |
| 358 | 356 | } |
| 359 | 357 | |
| 360 | 358 | /** |
| 361 | - * Get payment status | |
| 362 | - * | |
| 363 | - * @return string | |
| 364 | - */ | |
| 365 | - public function get_payment_status() { | |
| 366 | - return $this->get_prop( 'payment_status' ); | |
| 367 | - } | |
| 368 | - | |
| 369 | - /** | |
| 370 | 359 | * Get appointment |
| 371 | 360 | * |
| 372 | 361 | * @return Appointment |
| 373 | 362 | */ |
| @@ -538,9 +527,9 @@ | ||
| 538 | 527 | * |
| 539 | 528 | * @return string |
| 540 | 529 | */ |
| 541 | 530 | private function generate_randon_id() { |
| 542 | - return chr( wp_rand( ord( 'A' ), ord( 'Z' ) ) ) . wp_rand( 575639, 575639 + 400 ); | |
| 531 | + return chr( rand( ord( 'A' ), ord( 'Z' ) ) ) . rand( 575639, 575639 + 400 ); | |
| 543 | 532 | } |
| 544 | 533 | |
| 545 | 534 | // Setter. |
| 546 | 535 | |
| @@ -661,190 +650,8 @@ | ||
| 661 | 650 | return $updated; |
| 662 | 651 | } |
| 663 | 652 | |
| 664 | 653 | /** |
| 665 | - * Find the Booking_Entry (shared per-slot schedule record) this booking occupies. | |
| 666 | - * | |
| 667 | - * @param Appointment|null $meeting Optional pre-built meeting for this booking. | |
| 668 | - * @param string $start_date Slot date. Defaults to the booking's own. | |
| 669 | - * @param string $start_time Slot start. Defaults to the booking's own. | |
| 670 | - * @param string $timezone Timezone of the two above. Defaults to the booking's own. | |
| 671 | - * @return Booking_Entry|null The first matching entry, or null if none. | |
| 672 | - */ | |
| 673 | - private function find_slot_entry( $meeting = null, $start_date = '', $start_time = '', $timezone = '' ) { | |
| 674 | - $meeting = $meeting ?: new Appointment( $this->get_appointment() ); | |
| 675 | - $booking_entry = new Booking_Entry(); | |
| 676 | - | |
| 677 | - $start_date = $start_date ?: $this->get_start_date(); | |
| 678 | - $start_time = $start_time ?: $this->get_start_time(); | |
| 679 | - $timezone = $timezone ?: $this->get_timezone(); | |
| 680 | - | |
| 681 | - $date_time = timetics_convert_timezone( | |
| 682 | - $start_date . ' ' . $start_time, | |
| 683 | - $timezone, | |
| 684 | - $meeting->get_timezone() | |
| 685 | - ); | |
| 686 | - | |
| 687 | - $entries = $booking_entry->find( | |
| 688 | - [ | |
| 689 | - 'staff_id' => $this->get_staff_id(), | |
| 690 | - 'meeting_id' => $this->get_appointment(), | |
| 691 | - 'date' => $date_time->format( 'Y-m-d' ), | |
| 692 | - 'start' => $date_time->format( 'h:i a' ), | |
| 693 | - ] | |
| 694 | - ); | |
| 695 | - | |
| 696 | - return $entries ? $booking_entry->first() : null; | |
| 697 | - } | |
| 698 | - | |
| 699 | - /** | |
| 700 | - * Release the slot held by this booking. | |
| 701 | - * | |
| 702 | - * @return void | |
| 703 | - */ | |
| 704 | - public function release_slot() { | |
| 705 | - if ( ! $this->is_booking() ) { | |
| 706 | - return; | |
| 707 | - } | |
| 708 | - | |
| 709 | - // Idempotency guard: never release the same booking's slot twice. | |
| 710 | - if ( $this->get_prop( 'slot_released' ) ) { | |
| 711 | - return; | |
| 712 | - } | |
| 713 | - | |
| 714 | - $this->release_slot_at( $this->get_start_date(), $this->get_start_time() ); | |
| 715 | - | |
| 716 | - update_post_meta( $this->id, $this->meta_prefix . 'slot_released', 1 ); | |
| 717 | - } | |
| 718 | - | |
| 719 | - /** | |
| 720 | - * Take back the slot this booking released. | |
| 721 | - * | |
| 722 | - * A declined payment marks the booking failed and releases its slot, so an | |
| 723 | - * attempt the customer walks away from does not block the time forever. When | |
| 724 | - * the customer retries on that same booking the slot has to be taken back | |
| 725 | - * before any money moves, otherwise the booking finalizes while the slot still | |
| 726 | - * reads as free and the next customer can book straight over it. | |
| 727 | - * | |
| 728 | - * @return bool True when the slot is held, false when it is no longer free. | |
| 729 | - */ | |
| 730 | - public function reserve_slot() { | |
| 731 | - if ( ! $this->is_booking() ) { | |
| 732 | - return false; | |
| 733 | - } | |
| 734 | - | |
| 735 | - // Nothing was released, so the slot is still held from booking creation. | |
| 736 | - if ( ! $this->get_prop( 'slot_released' ) ) { | |
| 737 | - return true; | |
| 738 | - } | |
| 739 | - | |
| 740 | - $meeting = new Appointment( $this->get_appointment() ); | |
| 741 | - $entry = $this->find_slot_entry( $meeting ); | |
| 742 | - $seats = ! empty( $this->get_seat() ) ? (array) $this->get_seat() : []; | |
| 743 | - $taking = max( 1, count( $seats ) ); | |
| 744 | - | |
| 745 | - if ( $entry ) { | |
| 746 | - $booked = intval( $entry->get_booked() ) + $taking; | |
| 747 | - | |
| 748 | - // Someone else took the time while this booking was in the failed state. | |
| 749 | - if ( $booked > $meeting->get_effective_capacity() ) { | |
| 750 | - return false; | |
| 751 | - } | |
| 752 | - | |
| 753 | - $existing = ! empty( $entry->get_seats() ) ? (array) $entry->get_seats() : []; | |
| 754 | - | |
| 755 | - $entry->update( | |
| 756 | - [ | |
| 757 | - 'booked' => $booked, | |
| 758 | - 'seats' => array_values( array_unique( array_merge( $existing, $seats ) ) ), | |
| 759 | - ] | |
| 760 | - ); | |
| 761 | - } else { | |
| 762 | - // A one-to-one release deletes the entry outright, so recreate it. Entries | |
| 763 | - // are stored in the meeting's timezone, the booking's in the customer's. | |
| 764 | - $start = timetics_convert_timezone( $this->get_start_date() . ' ' . $this->get_start_time(), $this->get_timezone(), $meeting->get_timezone() ); | |
| 765 | - $end = timetics_convert_timezone( $this->get_start_date() . ' ' . $this->get_end_time(), $this->get_timezone(), $meeting->get_timezone() ); | |
| 766 | - | |
| 767 | - $booking_entry = new Booking_Entry(); | |
| 768 | - | |
| 769 | - $booking_entry->create( | |
| 770 | - [ | |
| 771 | - 'meeting_id' => $meeting->get_id(), | |
| 772 | - 'staff_id' => $this->get_staff_id(), | |
| 773 | - 'customer_id' => $this->get_customer(), | |
| 774 | - 'booking_id' => $this->id, | |
| 775 | - 'booked' => $taking, | |
| 776 | - 'date' => $start->format( 'Y-m-d' ), | |
| 777 | - 'start' => $start->format( 'h:i a' ), | |
| 778 | - 'end' => $end->format( 'h:i a' ), | |
| 779 | - 'seats' => $seats, | |
| 780 | - ] | |
| 781 | - ); | |
| 782 | - } | |
| 783 | - | |
| 784 | - delete_post_meta( $this->id, $this->meta_prefix . 'slot_released' ); | |
| 785 | - | |
| 786 | - return true; | |
| 787 | - } | |
| 788 | - | |
| 789 | - /** | |
| 790 | - * Release the entry for one named slot of this booking. | |
| 791 | - * | |
| 792 | - * Rescheduling saves the new time first, so the old slot has to be named | |
| 793 | - * rather than read off the booking. No idempotency guard: the booking lives | |
| 794 | - * on and may release more slots as it moves. | |
| 795 | - * | |
| 796 | - * @param string $start_date Slot date, Y-m-d. | |
| 797 | - * @param string $start_time Slot start. | |
| 798 | - * @param string $timezone Timezone of the two above. Defaults to the booking's own. | |
| 799 | - * | |
| 800 | - * @return void | |
| 801 | - */ | |
| 802 | - public function release_slot_at( $start_date, $start_time, $timezone = '' ) { | |
| 803 | - if ( ! $this->is_booking() ) { | |
| 804 | - return; | |
| 805 | - } | |
| 806 | - | |
| 807 | - $meeting = new Appointment( $this->get_appointment() ); | |
| 808 | - $entry = $this->find_slot_entry( $meeting, $start_date, $start_time, $timezone ); | |
| 809 | - | |
| 810 | - if ( ! $entry ) { | |
| 811 | - if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { | |
| 812 | - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug-only diagnostics for a missing booking entry. | |
| 813 | - error_log( | |
| 814 | - sprintf( | |
| 815 | - 'Timetics release_slot: no Booking_Entry found for booking #%d ( staff %s, meeting %s, slot %s %s ).', | |
| 816 | - $this->id, | |
| 817 | - $this->get_staff_id(), | |
| 818 | - $this->get_appointment(), | |
| 819 | - $start_date, | |
| 820 | - $start_time | |
| 821 | - ) | |
| 822 | - ); | |
| 823 | - } | |
| 824 | - | |
| 825 | - return; | |
| 826 | - } | |
| 827 | - | |
| 828 | - if ( 'one-to-one' === strtolower( $meeting->get_type() ) ) { | |
| 829 | - $entry->delete(); | |
| 830 | - | |
| 831 | - return; | |
| 832 | - } | |
| 833 | - | |
| 834 | - $booked = max( 0, intval( $entry->get_booked() ) - 1 ); | |
| 835 | - $booked_seat = ! empty( $this->get_seat() ) ? $this->get_seat() : []; | |
| 836 | - $existing_seat = ! empty( $entry->get_seats() ) ? $entry->get_seats() : []; | |
| 837 | - | |
| 838 | - $entry->update( | |
| 839 | - [ | |
| 840 | - 'booked' => $booked, | |
| 841 | - 'seats' => array_values( array_diff( $existing_seat, $booked_seat ) ), | |
| 842 | - ] | |
| 843 | - ); | |
| 844 | - } | |
| 845 | - | |
| 846 | - /** | |
| 847 | 654 | * Delete booking |
| 848 | 655 | * |
| 849 | 656 | * @return bool | WP_Error |
| 850 | 657 | */ |
| @@ -893,45 +700,46 @@ | ||
| 893 | 700 | ]; |
| 894 | 701 | |
| 895 | 702 | $args = wp_parse_args( $args, $defaults ); |
| 896 | 703 | |
| 897 | - $args = apply_filters( 'timetics/admin/bookings/all', $args, $defaults ); | |
| 704 | + $args = apply_filters( 'timetics/admin/bookings/all', $defaults, $args); | |
| 898 | 705 | |
| 899 | - $meta_query = ! empty( $args['meta_query'] ) && is_array( $args['meta_query'] ) ? $args['meta_query'] : []; | |
| 900 | - | |
| 901 | 706 | if ( ! empty( $args['start_date'] ) ) { |
| 902 | - $meta_query[] = [ | |
| 903 | - 'key' => '_tt_booking_start_date', | |
| 904 | - 'value' => $args['start_date'], | |
| 905 | - 'compare' => '>=', | |
| 906 | - 'type' => 'DATE', | |
| 707 | + //_tt_booking_start_date | |
| 708 | + $args['meta_query'] = [ | |
| 709 | + [ | |
| 710 | + 'key' => '_tt_booking_start_date', | |
| 711 | + 'value' => $args['start_date'], | |
| 712 | + 'compare' => '>=', | |
| 713 | + 'type' => 'DATE', | |
| 714 | + ], | |
| 907 | 715 | ]; |
| 908 | 716 | } |
| 909 | 717 | |
| 910 | 718 | if ( ! empty( $args['meeting'] ) ) { |
| 911 | - $meta_query[] = [ | |
| 912 | - 'key' => '_tt_booking_appointment', | |
| 913 | - 'value' => $args['meeting'], | |
| 914 | - 'compare' => '=', | |
| 719 | + // @codingStandardsIgnoreStart | |
| 720 | + $args['meta_query'] = [ | |
| 721 | + [ | |
| 722 | + 'key' => '_tt_booking_appointment', | |
| 723 | + 'value' => $args['meeting'], | |
| 724 | + 'compare' => '=', | |
| 725 | + ], | |
| 915 | 726 | ]; |
| 727 | + // @codingStandardsIgnoreEnd | |
| 916 | 728 | } |
| 917 | 729 | |
| 918 | 730 | if ( ! empty( $args['staff'] ) ) { |
| 919 | - $meta_query[] = [ | |
| 920 | - 'key' => '_tt_booking_staff', | |
| 921 | - 'value' => $args['staff'], | |
| 922 | - 'compare' => '=', | |
| 731 | + // @codingStandardsIgnoreStart | |
| 732 | + $args['meta_query'] = [ | |
| 733 | + [ | |
| 734 | + 'key' => '_tt_booking_staff', | |
| 735 | + 'value' => $args['staff'], | |
| 736 | + 'compare' => '=', | |
| 737 | + ], | |
| 923 | 738 | ]; |
| 739 | + // @codingStandardsIgnoreEnd | |
| 924 | 740 | } |
| 925 | 741 | |
| 926 | - if ( ! empty( $meta_query ) ) { | |
| 927 | - if ( count( $meta_query ) > 1 && empty( $meta_query['relation'] ) ) { | |
| 928 | - $meta_query['relation'] = 'AND'; | |
| 929 | - } | |
| 930 | - // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering bookings | |
| 931 | - $args['meta_query'] = $meta_query; | |
| 932 | - } | |
| 933 | - | |
| 934 | 742 | $post = new WP_Query( $args ); |
| 935 | 743 | |
| 936 | 744 | return [ |
| 937 | 745 | 'total' => $post->found_posts, |
| @@ -958,25 +766,37 @@ | ||
| 958 | 766 | |
| 959 | 767 | } |
| 960 | 768 | |
| 961 | 769 | public function create_appointment_event() { |
| 962 | - // No summary/description passed, so prepare_event() falls back to the | |
| 963 | - // meeting's own name and description. The booking-created email subject | |
| 964 | - // and body used to be reused here, which put the notification copy | |
| 965 | - // ("New meeting scheduled!", greeting, date and time lines) into the | |
| 966 | - // calendar entry instead of the meeting's details. | |
| 770 | + $data = [ | |
| 771 | + 'summary' => timetics_get_option( 'booking_created_customer_email_title' ), | |
| 772 | + 'description' => timetics_get_option( 'booking_created_customer_email_body' ), | |
| 773 | + ]; | |
| 774 | + | |
| 967 | 775 | $calendar = new Calendar(); |
| 968 | - $event_data = $this->prepare_event(); | |
| 776 | + $event_data = $this->prepare_event( $data ); | |
| 969 | 777 | |
| 970 | 778 | if ( ! $event_data ) { |
| 971 | 779 | return; |
| 972 | 780 | } |
| 973 | 781 | |
| 974 | - $entry = $this->find_slot_entry(); | |
| 782 | + $booking_entry = new Booking_Entry(); | |
| 783 | + $meeting = new Appointment( $this->get_appointment() ); | |
| 975 | 784 | |
| 976 | - $event = false; | |
| 785 | + $date_time = timetics_convert_timezone( $this->get_start_date() .' '. $this->get_start_time(), $this->get_timezone(), $meeting->get_timezone() ); | |
| 977 | 786 | |
| 978 | - if ( $entry ) { | |
| 787 | + $entries = $booking_entry->find( | |
| 788 | + [ | |
| 789 | + 'staff_id' => $this->get_staff_id(), | |
| 790 | + 'meeting_id' => $this->get_appointment(), | |
| 791 | + 'date' => $date_time->format('Y-m-d'), | |
| 792 | + 'start' => $date_time->format('h:i a'), | |
| 793 | + ] | |
| 794 | + ); | |
| 795 | + | |
| 796 | + if ( $entries ) { | |
| 797 | + $entry = $booking_entry->first(); | |
| 798 | + | |
| 979 | 799 | $event = $entry->get_google_event(); |
| 980 | 800 | |
| 981 | 801 | if ( ! $event ) { |
| 982 | 802 | $event = $calendar->create_event( $event_data ); |
| @@ -987,15 +807,8 @@ | ||
| 987 | 807 | } |
| 988 | 808 | |
| 989 | 809 | if ( $event ) { |
| 990 | 810 | update_post_meta( $this->id, $this->meta_prefix . 'calendar_event', $event ); |
| 991 | - | |
| 992 | - // Also record the bare event id. Google_Calendar_Sync uses this meta | |
| 993 | - // to recognise events Timetics itself created, so that they are not | |
| 994 | - // pulled back in as external events and used to block their own slot. | |
| 995 | - if ( ! empty( $event['id'] ) ) { | |
| 996 | - $this->set_google_event_id( $event['id'] ); | |
| 997 | - } | |
| 998 | 811 | } |
| 999 | 812 | } |
| 1000 | 813 | |
| 1001 | 814 | /** |
| @@ -1007,13 +820,15 @@ | ||
| 1007 | 820 | if ( ! timetics_google_setup() ) { |
| 1008 | 821 | return; |
| 1009 | 822 | } |
| 1010 | 823 | |
| 1011 | - // Same as create_appointment_event(): the meeting's name and description | |
| 1012 | - // belong in the calendar entry, not the reschedule email copy. Keeping | |
| 1013 | - // them consistent also stops a reschedule from rewriting the title. | |
| 824 | + $data = [ | |
| 825 | + 'summary' => timetics_get_option( 'booking_rescheduled_customer_email_title' ), | |
| 826 | + 'description' => timetics_get_option( 'booking_rescheduled_customer_email_body' ), | |
| 827 | + ]; | |
| 828 | + | |
| 1014 | 829 | $calendar = new Calendar(); |
| 1015 | - $event_data = $this->prepare_event(); | |
| 830 | + $event_data = $this->prepare_event( $data ); | |
| 1016 | 831 | $calendar_event = $this->get_event(); |
| 1017 | 832 | |
| 1018 | 833 | if ( ! is_array( $calendar_event ) ) { |
| 1019 | 834 | return; |
| @@ -1055,12 +870,8 @@ | ||
| 1055 | 870 | $event = $calendar->delete_event( $calendar_event['id'], $access_token ); |
| 1056 | 871 | |
| 1057 | 872 | // update calendar event data. |
| 1058 | 873 | update_post_meta( $this->id, $this->meta_prefix . 'calendar_event', $event ); |
| 1059 | - | |
| 1060 | - // The event no longer exists in Google, so drop the id used by | |
| 1061 | - // Google_Calendar_Sync to skip Timetics-created events. | |
| 1062 | - $this->set_google_event_id( '' ); | |
| 1063 | 874 | } |
| 1064 | 875 | } |
| 1065 | 876 | |
| 1066 | 877 | /** |
| @@ -1169,9 +980,8 @@ | ||
| 1169 | 980 | $query = new WP_Query([ |
| 1170 | 981 | 'post_type' => 'timetics-booking', |
| 1171 | 982 | 'post_status' => 'any', |
| 1172 | 983 | 'posts_per_page' => $per_page, |
| 1173 | - // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering bookings by appointment | |
| 1174 | 984 | 'meta_query' => [ |
| 1175 | 985 | [ |
| 1176 | 986 | 'key' => '_tt_booking_appointment', |
| 1177 | 987 | 'value' => $appointment_ids, |
| @@ -1186,63 +996,8 @@ | ||
| 1186 | 996 | ]; |
| 1187 | 997 | } |
| 1188 | 998 | |
| 1189 | 999 | /** |
| 1190 | - * Get booking ids visible to a given user. | |
| 1191 | - * | |
| 1192 | - * Union of: | |
| 1193 | - * - bookings where the user is the assigned staff (`_tt_booking_staff`) | |
| 1194 | - * - bookings whose appointment is authored by the user | |
| 1195 | - * | |
| 1196 | - * @param integer $user_id WP user id. | |
| 1197 | - * | |
| 1198 | - * @return int[] Deduped list of booking post ids. | |
| 1199 | - */ | |
| 1200 | - public static function get_visible_ids_for_user( $user_id ) { | |
| 1201 | - $user_id = (int) $user_id; | |
| 1202 | - | |
| 1203 | - if ( ! $user_id ) { | |
| 1204 | - return []; | |
| 1205 | - } | |
| 1206 | - | |
| 1207 | - $staff_ids = get_posts( [ | |
| 1208 | - 'post_type' => 'timetics-booking', | |
| 1209 | - 'post_status' => 'any', | |
| 1210 | - 'posts_per_page' => -1, | |
| 1211 | - 'fields' => 'ids', | |
| 1212 | - // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- needed to scope bookings to current staff user | |
| 1213 | - 'meta_query' => [ | |
| 1214 | - [ | |
| 1215 | - 'key' => '_tt_booking_staff', | |
| 1216 | - 'value' => $user_id, | |
| 1217 | - ], | |
| 1218 | - ], | |
| 1219 | - ] ); | |
| 1220 | - | |
| 1221 | - $appointment_ids = Appointment::get_appointment_ids_by_author( $user_id ); | |
| 1222 | - | |
| 1223 | - $appointment_booking_ids = []; | |
| 1224 | - if ( ! empty( $appointment_ids ) ) { | |
| 1225 | - $appointment_booking_ids = get_posts( [ | |
| 1226 | - 'post_type' => 'timetics-booking', | |
| 1227 | - 'post_status' => 'any', | |
| 1228 | - 'posts_per_page' => -1, | |
| 1229 | - 'fields' => 'ids', | |
| 1230 | - // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- needed to scope bookings to appointments owned by current user | |
| 1231 | - 'meta_query' => [ | |
| 1232 | - [ | |
| 1233 | - 'key' => '_tt_booking_appointment', | |
| 1234 | - 'value' => $appointment_ids, | |
| 1235 | - 'compare' => 'IN', | |
| 1236 | - ], | |
| 1237 | - ], | |
| 1238 | - ] ); | |
| 1239 | - } | |
| 1240 | - | |
| 1241 | - return array_values( array_unique( array_map( 'intval', array_merge( $staff_ids, $appointment_booking_ids ) ) ) ); | |
| 1242 | - } | |
| 1243 | - | |
| 1244 | - /** | |
| 1245 | 1000 | * Get Google Calendar Event ID for this booking |
| 1246 | 1001 | * |
| 1247 | 1002 | * @return string |
| 1248 | 1003 | */ |
| @@ -1256,28 +1011,13 @@ | ||
| 1256 | 1011 | * @param string $event_id |
| 1257 | 1012 | * @return bool |
| 1258 | 1013 | */ |
| 1259 | 1014 | public function set_google_event_id( $event_id ) { |
| 1260 | - // Written directly rather than through save_metadata(), which takes an | |
| 1261 | - // array and only accepts keys declared in $this->data — neither is true | |
| 1262 | - // here, so it silently discarded every write. | |
| 1263 | - $meta_key = $this->meta_prefix . 'google_event_id'; | |
| 1264 | - | |
| 1265 | - if ( ! $event_id ) { | |
| 1266 | - return delete_post_meta( $this->id, $meta_key ); | |
| 1267 | - } | |
| 1268 | - | |
| 1269 | - return update_post_meta( $this->id, $meta_key, $event_id ); | |
| 1015 | + return $this->save_metadata( 'google_event_id', $event_id ); | |
| 1270 | 1016 | } |
| 1271 | 1017 | |
| 1272 | 1018 | public function set_sync_status( $status ) { |
| 1273 | - $meta_key = $this->meta_prefix . 'google_calendar_sync_status'; | |
| 1274 | - | |
| 1275 | - if ( ! $status ) { | |
| 1276 | - return delete_post_meta( $this->id, $meta_key ); | |
| 1277 | - } | |
| 1278 | - | |
| 1279 | - return update_post_meta( $this->id, $meta_key, $status ); | |
| 1019 | + return $this->save_metadata( 'google_calendar_sync_status', $status ); | |
| 1280 | 1020 | } |
| 1281 | 1021 | |
| 1282 | 1022 | public function get_sync_status() { |
| 1283 | 1023 | return $this->get_metadata( 'google_calendar_sync_status' ); |
| @@ -1288,14 +1028,13 @@ | ||
| 1288 | 1028 | * @return array |
| 1289 | 1029 | */ |
| 1290 | 1030 | public function get_all_google_event_ids() { |
| 1291 | 1031 | $meta_key = $this->meta_prefix . 'google_event_id'; |
| 1292 | - | |
| 1032 | + | |
| 1293 | 1033 | $posts = get_posts( |
| 1294 | 1034 | array( |
| 1295 | 1035 | 'post_type' => 'any', |
| 1296 | 1036 | 'posts_per_page' => -1, |
| 1297 | - // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering posts by meta key | |
| 1298 | 1037 | 'meta_query' => array( |
| 1299 | 1038 | array( |
| 1300 | 1039 | 'key' => $meta_key, |
| 1301 | 1040 | 'value' => '', |
| @@ -1329,9 +1068,9 @@ | ||
| 1329 | 1068 | * @return string |
| 1330 | 1069 | */ |
| 1331 | 1070 | public function get_security_token() { |
| 1332 | 1071 | return $this->get_prop( 'security_token' ); |
| 1333 | - } | |
| 1072 | + } | |
| 1334 | 1073 | |
| 1335 | 1074 | /** |
| 1336 | 1075 | * Generate and store a secure reschedule token for a booking |
| 1337 | 1076 | * |
| @@ -1340,39 +1079,6 @@ | ||
| 1340 | 1079 | */ |
| 1341 | 1080 | public function generate_security_token() { |
| 1342 | 1081 | $token = bin2hex(random_bytes(4)); // 8 hex chars |
| 1343 | 1082 | return $token; |
| 1344 | - } | |
| 1345 | - | |
| 1346 | - /** | |
| 1347 | - * Rotate the booking's security token so the previously-issued one cannot | |
| 1348 | - * be reused (e.g. after a payment is approved). | |
| 1349 | - * | |
| 1350 | - * @return void | |
| 1351 | - */ | |
| 1352 | - public function rotate_security_token() { | |
| 1353 | - $meta_key = $this->meta_prefix . 'security_token'; | |
| 1354 | - $new_token = $this->generate_security_token(); | |
| 1355 | - update_post_meta( $this->id, $meta_key, $new_token ); | |
| 1356 | - } | |
| 1357 | - | |
| 1358 | - /** | |
| 1359 | - * Get the Stripe PaymentIntent id bound to this booking, if any. | |
| 1360 | - * | |
| 1361 | - * @return string | |
| 1362 | - */ | |
| 1363 | - public function get_stripe_payment_intent_id() { | |
| 1364 | - return (string) get_post_meta( $this->id, '_tt_stripe_payment_intent_id', true ); | |
| 1365 | - } | |
| 1366 | - | |
| 1367 | - /** | |
| 1368 | - * Bind a Stripe PaymentIntent id to this booking. Used for replay | |
| 1369 | - * protection: a second make_payment call with a different intent will be | |
| 1370 | - * rejected. | |
| 1371 | - * | |
| 1372 | - * @param string $intent_id | |
| 1373 | - * @return void | |
| 1374 | - */ | |
| 1375 | - public function set_stripe_payment_intent_id( $intent_id ) { | |
| 1376 | - update_post_meta( $this->id, '_tt_stripe_payment_intent_id', sanitize_text_field( (string) $intent_id ) ); | |
| 1377 | 1083 | } |
| 1378 | 1084 | } |