PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
← All changes | admin/helpers/src/model/reservation.php +210 -22 1.8.13 → 1.8.16 View file →
@@ -755,12 +755,21 @@
755 755 $q->where($dbo->qn('o.custmail') . ' = ' . $dbo->q($filters['email']));
756 756 }
757 757
758 758 if (($filters['phone'] ?? null)) {
759 - $q->where(sprintf('REPLACE(%s, \' \', \'\') LIKE REPLACE(%s, \' \', \'\')',
760 - $dbo->qn('o.phone'),
761 - $dbo->q('%' . $filters['phone'])
762 - ));
759 + $q->where(
760 + sprintf(
761 + '(%s OR %s)',
762 + sprintf('REPLACE(%s, \' \', \'\') LIKE REPLACE(%s, \' \', \'\')',
763 + $dbo->qn('o.phone'),
764 + $dbo->q('%' . $filters['phone'])
765 + ),
766 + sprintf('REPLACE(%s, \' \', \'\') LIKE REPLACE(%s, \' \', \'\')',
767 + $dbo->qn('o.phone_alias'),
768 + $dbo->q('%' . $filters['phone_alias'])
769 + )
770 + )
771 + );
763 772 }
764 773
765 774 if (($filters['date_range']['type'] ?? null) && (($filters['date_range']['start'] ?? null) || ($filters['date_range']['end'] ?? null))) {
766 775 // search by date range
@@ -1064,8 +1073,90 @@
1064 1073 return (bool) $dbo->getAffectedRows();
1065 1074 }
1066 1075
1067 1076 /**
1077 + * Updates the registration status for the provided booking.
1078 + *
1079 + * @param int $status Registration status to set.
1080 + * @param ?int $bookingId Optional booking ID to update.
1081 + *
1082 + * @return bool
1083 + *
1084 + * @throws Exception
1085 + *
1086 + * @since 1.18.15 (J) - 1.8.15 (WP)
1087 + */
1088 + public function updateRegistration(int $status, ?int $bookingId = null)
1089 + {
1090 + $dbo = JFactory::getDbo();
1091 +
1092 + if (!$bookingId) {
1093 + // get the internal booking record
1094 + $booking = $this->getBooking();
1095 + $bookingId = $booking['id'] ?? null;
1096 + }
1097 +
1098 + if (empty($bookingId)) {
1099 + throw new Exception('Missing booking ID.', 400);
1100 + }
1101 +
1102 + $knownStatuses = [-1, 0, 1, 2];
1103 +
1104 + if (!in_array($status, $knownStatuses, true)) {
1105 + throw new InvalidArgumentException('Invalid registration status.', 400);
1106 + }
1107 +
1108 + // update booking record
1109 + $dbo->setQuery(
1110 + $dbo->getQuery(true)
1111 + ->update($dbo->qn('#__vikbooking_orders'))
1112 + ->set($dbo->qn('checked') . ' = ' . $status)
1113 + ->where($dbo->qn('id') . ' = ' . $bookingId)
1114 + );
1115 + $dbo->execute();
1116 +
1117 + return (bool) $dbo->getAffectedRows();
1118 + }
1119 +
1120 + /**
1121 + * Updates the booking-level phone number or alias phone number (masked phone).
1122 + *
1123 + * @param ?string $phone The phone number value to set, even null to unset.
1124 + * @param bool $isAlias Whether to update the real or alias phone number.
1125 + * @param ?int $bookingId Optional booking ID to update.
1126 + *
1127 + * @return bool
1128 + *
1129 + * @throws Exception
1130 + *
1131 + * @since 1.18.16 (J) - 1.8.16 (WP)
1132 + */
1133 + public function updatePhoneNumber(?string $phone, bool $isAlias = false, ?int $bookingId = null)
1134 + {
1135 + $dbo = JFactory::getDbo();
1136 +
1137 + if (!$bookingId) {
1138 + // get the internal booking record
1139 + $booking = $this->getBooking();
1140 + $bookingId = $booking['id'] ?? null;
1141 + }
1142 +
1143 + if (empty($bookingId)) {
1144 + throw new Exception('Missing booking ID.', 400);
1145 + }
1146 +
1147 + $dbo->setQuery(
1148 + $dbo->getQuery(true)
1149 + ->update('#__vikbooking_orders')
1150 + ->set($dbo->qn($isAlias ? 'phone_alias' : 'phone') . ' = ' . ($phone ? $dbo->q($phone) : 'NULL'))
1151 + ->where($dbo->qn('id') . ' = ' . (int) $bookingId)
1152 + );
1153 + $dbo->execute();
1154 +
1155 + return (bool) $dbo->getAffectedRows();
1156 + }
1157 +
1158 + /**
1068 1159 * Modifies the requested booking ID according to the provided options.
1069 1160 * This method does not support all rate plan options like for the creation of a
1070 1161 * new booking. This is a method for making quick updates concerning a room switch,
1071 1162 * a change of stay dates, new booking total amount, guests, add extra services etc..
@@ -1805,8 +1896,11 @@
1805 1896 $units_minus_oper[$or['idroom']] = 0;
1806 1897 }
1807 1898 }
1808 1899
1900 + // list of room-units pool
1901 + $roomUnits = [];
1902 +
1809 1903 // check availability for each room involved
1810 1904 foreach ($roomBooking as $ind => $or) {
1811 1905 // determine proper values for this room
1812 1906 $room_stay_checkin = $booking['checkin'];
@@ -1822,8 +1916,11 @@
1822 1916
1823 1917 // get room record
1824 1918 $room_record = VikBooking::getRoomInfo($or['idroom']);
1825 1919
1920 + // set room (total) units
1921 + $roomUnits[$or['idroom']] = (int) ($room_record['units'] ?? 1);
1922 +
1826 1923 // check if the room is available
1827 1924 if (!VikBooking::roomBookable($or['idroom'], (($room_record['units'] ?? 0) - $units_minus_oper[$or['idroom']]), $room_stay_checkin, $room_stay_checkout)) {
1828 1925 $allbook = false;
1829 1926 $notavail[] = $room_record['name'] ?? '?';
@@ -1847,26 +1944,31 @@
1847 1944 $room_stay_checkout = $room_stay_dates[$ind]['checkout_ts'] ?: $room_stay_dates[$ind]['checkout'];
1848 1945 $room_stay_realback = $turnover_secs + $room_stay_checkout;
1849 1946 }
1850 1947
1851 - // build busy record
1852 - $busy_record = new stdClass;
1853 - $busy_record->idroom = (int) $or['idroom'];
1854 - $busy_record->checkin = (int) $room_stay_checkin;
1855 - $busy_record->checkout = (int) $room_stay_checkout;
1856 - $busy_record->realback = (int) $room_stay_realback;
1948 + // determine the room units to occupy (to support closure re-confirmations)
1949 + $bookUnitsCount = (int) (intval($booking['closure'] ?? 0) ? ($roomUnits[$or['idroom']] ?? 1) : 1);
1857 1950
1858 - // store busy record and obtain the newly created ID
1859 - $dbo->insertObject('#__vikbooking_busy', $busy_record, 'id');
1860 - $lid = $busy_record->id ?? 0;
1951 + for ($bi = 1; $bi <= $bookUnitsCount; $bi++) {
1952 + // build busy record
1953 + $busy_record = new stdClass;
1954 + $busy_record->idroom = (int) $or['idroom'];
1955 + $busy_record->checkin = (int) $room_stay_checkin;
1956 + $busy_record->checkout = (int) $room_stay_checkout;
1957 + $busy_record->realback = (int) $room_stay_realback;
1861 1958
1862 - // build busy relation record
1863 - $obusy_record = new stdClass;
1864 - $obusy_record->idorder = (int) $booking['id'];
1865 - $obusy_record->idbusy = (int) $lid;
1959 + // store busy record and obtain the newly created ID
1960 + $dbo->insertObject('#__vikbooking_busy', $busy_record, 'id');
1961 + $lid = $busy_record->id ?? 0;
1866 1962
1867 - // store busy relation record
1868 - $dbo->insertObject('#__vikbooking_ordersbusy', $obusy_record, 'id');
1963 + // build busy relation record
1964 + $obusy_record = new stdClass;
1965 + $obusy_record->idorder = (int) $booking['id'];
1966 + $obusy_record->idbusy = (int) $lid;
1967 +
1968 + // store busy relation record
1969 + $dbo->insertObject('#__vikbooking_ordersbusy', $obusy_record, 'id');
1970 + }
1869 1971 }
1870 1972
1871 1973 // delete temporarily locked records, if any
1872 1974 $dbo->setQuery(
@@ -2150,8 +2252,36 @@
2150 2252 foreach ($booking_rooms as $booking_room) {
2151 2253 $rooms_units_counter[$booking_room['idroom']] = ($rooms_counter[$booking_room['idroom']] ?? -1) + 1;
2152 2254 }
2153 2255
2256 + // check if the booking modification involves other rooms
2257 + $roomsPool = $this->getRoomsPool();
2258 + $oldRoomIds = array_map('intval', array_column($booking_rooms, 'idroom'));
2259 + $newRoomIds = array_values(array_unique(array_map('intval', array_column($roomsPool, 'id'))));
2260 + $diffIds = array_diff($newRoomIds, $oldRoomIds);
2261 + foreach ($diffIds as $newId) {
2262 + $unitsRequested = 0;
2263 + $totUnits = 0;
2264 + foreach ($roomsPool as $roomData) {
2265 + if ($newId == $roomData['id']) {
2266 + $unitsRequested++;
2267 + $totUnits = (int) ($roomData['units'] ?? 1);
2268 + }
2269 + }
2270 + if (!$unitsRequested) {
2271 + continue;
2272 + }
2273 +
2274 + // update units counter map for multiple units requested
2275 + $rooms_units_counter[$newId] = $unitsRequested - 1;
2276 +
2277 + // push additional room for availability validation
2278 + $booking_rooms[] = [
2279 + 'idroom' => $newId,
2280 + 'tot_units' => $totUnits,
2281 + ];
2282 + }
2283 +
2154 2284 // check the availability for each room booked
2155 2285 $rooms_parsed = [];
2156 2286 foreach ($booking_rooms as $booking_room) {
2157 2287 if (in_array($booking_room['idroom'], $rooms_parsed)) {
@@ -2879,8 +3009,11 @@
2879 3009 $email = !empty($inj_customer['email']) ? $inj_customer['email'] : '';
2880 3010 $country = !empty($inj_customer['country']) ? $inj_customer['country'] : '';
2881 3011 $phone = !empty($inj_customer['phone']) ? $inj_customer['phone'] : '';
2882 3012 $gender = !empty($inj_customer['gender']) ? $inj_customer['gender'] : '';
3013 + $address = !empty($inj_customer['address']) ? $inj_customer['address'] : '';
3014 + $city = !empty($inj_customer['city']) ? $inj_customer['city'] : '';
3015 + $zip = !empty($inj_customer['zip']) ? $inj_customer['zip'] : '';
2883 3016
2884 3017 // custom fields
2885 3018 $q = "SELECT * FROM `#__vikbooking_custfields` ORDER BY `ordering` ASC;";
2886 3019 $dbo->setQuery($q);
@@ -2916,8 +3049,23 @@
2916 3049 // inject the customer gender value
2917 3050 $customer_extrainfo['gender'] = strtoupper($gender);
2918 3051 }
2919 3052
3053 + if (!empty($address)) {
3054 + // inject extra info
3055 + $customer_extrainfo['address'] = strlen((string) $address) > 200 ? substr($address, 0, 200) : $address;
3056 + }
3057 +
3058 + if (!empty($city)) {
3059 + // inject extra info
3060 + $customer_extrainfo['city'] = strlen((string) $city) > 50 ? substr($city, 0, 50) : $city;
3061 + }
3062 +
3063 + if (!empty($zip)) {
3064 + // inject extra info
3065 + $customer_extrainfo['zip'] = strlen((string) $zip) > 10 ? substr($zip, 0, 10) : $zip;
3066 + }
3067 +
2920 3068 $cpin = VikBooking::getCPinInstance();
2921 3069 $cpin->is_admin = true;
2922 3070 $cpin->setCustomerExtraInfo($customer_extrainfo);
2923 3071 $cpin->saveCustomerDetails($first_name, $last_name, $email, $phone, $country, $customer_cfields);
@@ -3267,8 +3415,12 @@
3267 3415 $customer_data = ($inj_customer['data'] ?? null) ?: '';
3268 3416 $customer_email = ($inj_customer['email'] ?? null) ?: '';
3269 3417 $country_code = ($inj_customer['country'] ?? null) ?: '';
3270 3418 $phone_number = ($inj_customer['phone'] ?? null) ?: '';
3419 + $phone_alias = ($inj_customer['phone_alias'] ?? null) ?: '';
3420 + $address = ($inj_customer['address'] ?? null) ?: '';
3421 + $city = ($inj_customer['city'] ?? null) ?: '';
3422 + $zip = ($inj_customer['zip'] ?? null) ?: '';
3271 3423
3272 3424 if ($set_closed) {
3273 3425 // get the possibly custom "customer notes"
3274 3426 $customer_notes = $customer_data;
@@ -3290,14 +3442,25 @@
3290 3442 }
3291 3443 if ($customer_email) {
3292 3444 $customer_data .= "eMail: {$customer_email}\n";
3293 3445 }
3446 + if ($phone_number) {
3447 + $customer_data .= "Phone: {$phone_number}\n";
3448 + } elseif ($phone_alias) {
3449 + $customer_data .= "Phone-alias: {$phone_alias}\n";
3450 + }
3294 3451 if ($country_code) {
3295 3452 $customer_data .= "Country: {$country_code}\n";
3296 3453 }
3297 - if ($phone_number) {
3298 - $customer_data .= "Phone: {$phone_number}\n";
3454 + if ($address) {
3455 + $customer_data .= "Address: {$address}\n";
3299 3456 }
3457 + if ($city) {
3458 + $customer_data .= "City: {$city}\n";
3459 + }
3460 + if ($zip) {
3461 + $customer_data .= "Zip: {$zip}\n";
3462 + }
3300 3463 $customer_data = rtrim($customer_data, "\n");
3301 3464 }
3302 3465
3303 3466 // ensure the country code is in the right format
@@ -3364,8 +3527,11 @@
3364 3527 // attempt to get the default payment method
3365 3528 if (!$paymentmeth && ($auto_paymeth || $status == 'standby')) {
3366 3529 // get the default payment method, if any
3367 3530 $paymentmeth = $this->getDefaultPaymentMethod($auto_paymeth);
3531 + } elseif ($paymentmeth && is_int($paymentmeth)) {
3532 + // convert the payment integer ID into a string with the actual record name
3533 + $paymentmeth = $this->getPaymentMethodValue($paymentmeth);
3368 3534 }
3369 3535
3370 3536 if ($bookingId) {
3371 3537 // when updating, delete all room booking records involved
@@ -3403,8 +3569,9 @@
3403 3569 $booking->tot_city_taxes = $set_city_tax ?: ($this->get('tot_city_taxes') ? ((float) $this->get('tot_city_taxes')) : null);
3404 3570 $booking->tot_fees = $set_fees ?: ($this->get('tot_fees') ? ((float) $this->get('tot_fees')) : null);
3405 3571 $booking->tot_damage_dep = $this->get('tot_damage_dep') ? ((float) $this->get('tot_damage_dep')) : null;
3406 3572 $booking->phone = $phone_number;
3573 + $booking->phone_alias = $phone_alias ?: null;
3407 3574 $booking->cmms = $this->get('cmms') ? ((float) $this->get('cmms')) : null;
3408 3575 $booking->closure = ($status == 'standby' ? 0 : ($set_closed || $units_closed ? 1 : 0));
3409 3576 $booking->payable = $this->get('payable') ? ((float) $this->get('payable')) : null;
3410 3577 $booking->refund = $this->get('refund') ? ((float) $this->get('refund')) : null;
@@ -3511,10 +3678,10 @@
3511 3678 }
3512 3679 }
3513 3680
3514 3681 // store room booking records
3682 + $room_indexes_usemap = [];
3515 3683 foreach ($rooms_pool as $rind => $nowroom) {
3516 - $room_indexes_usemap = [];
3517 3684 for ($r = 1; $r <= $or_forend; $r++) {
3518 3685 // determine room-level stay dates
3519 3686 $room_stay_checkin = $nowroom['checkin_ts'] ?? $roomsData[$rind]['checkin'] ?? $checkin_ts;
3520 3687 $room_stay_checkout = $nowroom['checkout_ts'] ?? $roomsData[$rind]['checkout'] ?? $checkout_ts;
@@ -3852,6 +4019,27 @@
3852 4019 }
3853 4020
3854 4021 // nothing was found
3855 4022 return '';
4023 + }
4024 +
4025 + /**
4026 + * Given a payment method record ID, returns the string
4027 + * in the format for saving it along the reservation.
4028 + *
4029 + * @param int $id The record ID.
4030 + *
4031 + * @return ?string ID=Name calculated value, or null.
4032 + *
4033 + * @since 1.18.15 (J) - 1.8.15 (WP)
4034 + */
4035 + protected function getPaymentMethodValue(int $id)
4036 + {
4037 + $record = VBOMvcModel::getInstance('payment')->getItem($id);
4038 +
4039 + if ($record) {
4040 + return sprintf('%s=%s', $record->id, $record->name);
4041 + }
4042 +
4043 + return null;
3856 4044 }
3857 4045 }