PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.8
VikBooking Hotel Booking Engine & PMS v1.6.8
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
vikbooking / admin / controllers / bookings.php

bookings.php in VikBooking Hotel Booking Engine & PMS 1.6.8, at admin/controllers/bookings.php

427 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * VikBooking bookings controller.
16 *
17 * @since 1.16.0 (J) - 1.6.0 (WP)
18 */
19 class VikBookingControllerBookings extends JControllerAdmin
20 {
21 /**
22 * AJAX endpoint to search for an extra service name.
23 *
24 * @return void
25 */
26 public function search_service()
27 {
28 if (!JSession::checkToken()) {
29 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
30 }
31
32 $dbo = JFactory::getDbo();
33
34 $service_name = VikRequest::getString('service_name', '', 'request');
35 $max_results = VikRequest::getInt('max_results', 10, 'request');
36
37 $sql_term = $dbo->quote("%{$service_name}%");
38 $sql_clause = !empty($service_name) ? 'LIKE ' . $sql_term : 'IS NOT NULL';
39
40 $q = "SELECT `or`.`idorder`, `or`.`idroom`, `or`.`adults`, `or`.`children`, `or`.`extracosts`, `o`.`days` AS `nights`, `o`.`ts`, `r`.`name` AS `room_name`
41 FROM `#__vikbooking_ordersrooms` AS `or`
42 LEFT JOIN `#__vikbooking_orders` AS `o` ON `or`.`idorder`=`o`.`id`
43 LEFT JOIN `#__vikbooking_rooms` AS `r` ON `or`.`idroom`=`r`.`id`
44 WHERE `or`.`extracosts` {$sql_clause}
45 ORDER BY `or`.`idorder` DESC";
46 $dbo->setQuery($q, 0, $max_results);
47 $dbo->execute();
48 if (!$dbo->getNumRows()) {
49 // no results
50 VBOHttpDocument::getInstance()->json([]);
51 }
52
53 $results = $dbo->loadAssocList();
54
55 $matching_services = [];
56
57 foreach ($results as $k => $result) {
58 $extra_services = json_decode($result['extracosts'], true);
59 if (empty($extra_services)) {
60 continue;
61 }
62 foreach ($extra_services as $extra_service) {
63 if (empty($service_name) || stristr($extra_service['name'], $service_name) !== false || stristr($service_name, $extra_service['name']) !== false) {
64 // matching service found
65 $matching_service = $result;
66 unset($matching_service['extracosts']);
67 $matching_service['service'] = $extra_service;
68 $matching_service['service']['format_cost'] = VikBooking::getCurrencySymb() . ' ' . VikBooking::numberFormat($extra_service['cost']);
69 $matching_service['format_dt'] = VikBooking::formatDateTs($result['ts']);
70 // push result
71 $matching_services[] = $matching_service;
72 if (count($matching_services) >= $max_results) {
73 break 2;
74 }
75 }
76 }
77 }
78
79 // output the JSON encoded list of matching results found
80 VBOHttpDocument::getInstance()->json($matching_services);
81 }
82
83 /**
84 * AJAX endpoint to count the number of uses for various coupon codes.
85 *
86 * @return void
87 */
88 public function coupons_use_count()
89 {
90 if (!JSession::checkToken()) {
91 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
92 }
93
94 $dbo = JFactory::getDbo();
95
96 $coupon_codes = VikRequest::getVar('coupon_codes', array());
97
98 $use_counts = [];
99
100 foreach ($coupon_codes as $coupon_code) {
101 $q = "SELECT COUNT(*) FROM `#__vikbooking_orders` WHERE `coupon` LIKE " . $dbo->quote("%;{$coupon_code}");
102 $dbo->setQuery($q);
103 $dbo->execute();
104 $use_counts[] = [
105 'code' => $coupon_code,
106 'count' => (int)$dbo->loadResult(),
107 ];
108 }
109
110 // output the JSON encoded list of coupon use counts
111 VBOHttpDocument::getInstance()->json($use_counts);
112 }
113
114 /**
115 * AJAX endpoint to dynamically search for customers. Compatible with select2.
116 *
117 * @return void
118 */
119 public function customers_search()
120 {
121 if (!JSession::checkToken()) {
122 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
123 }
124
125 $dbo = JFactory::getDbo();
126
127 $term = VikRequest::getString('term', '', 'request');
128
129 $response = [
130 'results' => [],
131 'pagination' => [
132 'more' => false,
133 ],
134 ];
135
136 if (empty($term)) {
137 // output the JSON object with no results
138 VBOHttpDocument::getInstance()->json($response);
139 }
140
141 $sql_term = $dbo->quote("%{$term}%");
142
143 $q = "SELECT `c`.`id`, `c`.`first_name`, `c`.`last_name`, `c`.`country`,
144 (SELECT COUNT(*) FROM `#__vikbooking_customers_orders` AS `co` WHERE `co`.`idcustomer`=`c`.`id`) AS `tot_bookings`
145 FROM `#__vikbooking_customers` AS `c`
146 WHERE CONCAT_WS(' ', `c`.`first_name`, `c`.`last_name`) LIKE {$sql_term}
147 OR `email` LIKE {$sql_term}
148 ORDER BY `c`.`first_name` ASC, `c`.`last_name` ASC;";
149 $dbo->setQuery($q);
150 $dbo->execute();
151
152 if ($dbo->getNumRows()) {
153 $customers = $dbo->loadAssocList();
154 foreach ($customers as $k => $customer) {
155 $customers[$k]['text'] = trim($customer['first_name'] . ' ' . $customer['last_name']) . ' (' . $customer['tot_bookings'] . ')';
156 }
157 // push results found
158 $response['results'] = $customers;
159 }
160
161 // output the JSON encoded object with results found
162 VBOHttpDocument::getInstance()->json($response);
163 }
164
165 /**
166 * Regular task to update the status of a cancelled booking to pending (stand-by).
167 *
168 * @return void
169 */
170 public function set_to_pending()
171 {
172 $dbo = JFactory::getDbo();
173 $app = JFactory::getApplication();
174
175 $bid = $app->input->getInt('bid', 0);
176
177 if (!JSession::checkToken() && !JSession::checkToken('get')) {
178 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
179 $app->redirect('index.php?option=com_vikbooking&task=editorder&cid[]=' . $bid);
180 $app->close();
181 }
182
183 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid;
184 $dbo->setQuery($q, 0, 1);
185 $dbo->execute();
186 if (!$dbo->getNumRows()) {
187 $app->enqueueMessage('Booking not found', 'error');
188 $app->redirect('index.php?option=com_vikbooking&task=orders');
189 $app->close();
190 }
191
192 $booking = $dbo->loadAssoc();
193 if ($booking['status'] != 'cancelled') {
194 $app->enqueueMessage('Booking status must be -Cancelled-', 'error');
195 $app->redirect('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id']);
196 $app->close();
197 }
198
199 $q = "UPDATE `#__vikbooking_orders` SET `status`='standby' WHERE `id`=" . $booking['id'];
200 $dbo->setQuery($q);
201 $dbo->execute();
202
203 $app->enqueueMessage(JText::translate('JLIB_APPLICATION_SAVE_SUCCESS'));
204 $app->redirect('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id']);
205 $app->close();
206 }
207
208 /**
209 * AJAX endpoint to assign a room index to a room booking record.
210 *
211 * @return void
212 */
213 public function set_room_booking_subunit()
214 {
215 if (!JSession::checkToken()) {
216 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
217 }
218
219 $dbo = JFactory::getDbo();
220 $app = JFactory::getApplication();
221
222 $bid = $app->input->getInt('bid', 0);
223 $rid = $app->input->getInt('rid', 0);
224 $orkey = $app->input->getInt('orkey', 0);
225 $rindex = $app->input->getInt('rindex', 0);
226
227 if (empty($bid) || empty($rid)) {
228 VBOHttpDocument::getInstance()->close(500, 'Missing request values');
229 }
230
231 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid;
232 $dbo->setQuery($q, 0, 1);
233 $booking = $dbo->loadAssoc();
234 if (!$booking) {
235 VBOHttpDocument::getInstance()->close(404, 'Booking not found');
236 }
237
238 $booking_rooms = VikBooking::loadOrdersRoomsData($booking['id']);
239 if (!$booking_rooms) {
240 VBOHttpDocument::getInstance()->close(500, 'No rooms booking found');
241 }
242
243 if (!isset($booking_rooms[$orkey]) || $booking_rooms[$orkey]['idroom'] != $rid) {
244 VBOHttpDocument::getInstance()->close(500, 'Invalid room booking record');
245 }
246
247 // update room record
248 $room_record = new stdClass;
249 $room_record->id = $booking_rooms[$orkey]['id'];
250 $room_record->roomindex = $rindex;
251
252 $dbo->updateObject('#__vikbooking_ordersrooms', $room_record, 'id');
253
254 // build list of affected nights
255 $nights_list_ymd = [];
256 $from_checkin_info = getdate($booking['checkin']);
257 for ($n = 0; $n < $booking['days']; $n++) {
258 // push affected night
259 $nights_list_ymd[] = date('Y-m-d', mktime(0, 0, 0, $from_checkin_info['mon'], ($from_checkin_info['mday'] + $n), $from_checkin_info['year']));
260 }
261
262 // build return values
263 $response = [
264 'bid' => $booking['id'],
265 'rid' => $booking_rooms[$orkey]['idroom'],
266 'rindex' => $rindex,
267 'from' => date('Y-m-d', $booking['checkin']),
268 'to' => date('Y-m-d', $booking['checkout']),
269 'nights' => $nights_list_ymd,
270 ];
271
272 // output the JSON encoded object
273 VBOHttpDocument::getInstance()->json($response);
274 }
275
276 /**
277 * AJAX endpoint to swap one sub-unit index with another for the same room ID and dates.
278 *
279 * @return void
280 *
281 * @since 1.16.2 (J) - 1.6.2 (WP)
282 */
283 public function swap_room_subunits()
284 {
285 if (!JSession::checkToken()) {
286 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
287 }
288
289 $dbo = JFactory::getDbo();
290 $app = JFactory::getApplication();
291
292 $bid_one = $app->input->getInt('bid_one', 0);
293 $bid_two = $app->input->getInt('bid_two', 0);
294 $rid = $app->input->getInt('rid', 0);
295 $index_one = $app->input->getInt('index_one', 0);
296 $index_two = $app->input->getInt('index_two', 0);
297 $checkin = $app->input->getString('checkin', '');
298
299 if (!$bid_one || !$bid_two || !$rid || !$index_one || !$index_two) {
300 VBOHttpDocument::getInstance()->close(500, 'Missing request values');
301 }
302
303 // collect the booking information
304 $booking_one = VikBooking::getBookingInfoFromID($bid_one);
305 $booking_two = VikBooking::getBookingInfoFromID($bid_two);
306 if (!$booking_one || !$booking_two) {
307 VBOHttpDocument::getInstance()->close(500, 'Could not find the involved reservations');
308 }
309
310 // get room reservation records
311 $rooms_one = VikBooking::loadOrdersRoomsData($bid_one);
312 $rooms_two = VikBooking::loadOrdersRoomsData($bid_two);
313 if (!$rooms_one || !$rooms_two) {
314 VBOHttpDocument::getInstance()->close(500, 'Could not find the involved room reservation records');
315 }
316
317 // find the record IDs involved and room name
318 $update_id_one = null;
319 $update_id_two = null;
320 $room_name = '';
321
322 foreach ($rooms_one as $room_one) {
323 if ($room_one['idroom'] == $rid && $room_one['roomindex'] == $index_one) {
324 $update_id_one = $room_one['id'];
325 $room_name = $room_one['room_name'];
326 break;
327 }
328 }
329
330 foreach ($rooms_two as $room_two) {
331 if ($room_two['idroom'] == $rid && $room_two['roomindex'] == $index_two) {
332 $update_id_two = $room_two['id'];
333 $room_name = $room_two['room_name'];
334 break;
335 }
336 }
337
338 if (!$update_id_one || !$update_id_two) {
339 VBOHttpDocument::getInstance()->close(500, 'Could not find the involved room reservation record IDs');
340 }
341
342 // swap first room record
343 $q = $dbo->getQuery(true);
344
345 $q->update($dbo->qn('#__vikbooking_ordersrooms'))
346 ->set($dbo->qn('roomindex') . ' = ' . $index_two)
347 ->where($dbo->qn('id') . ' = ' . (int)$update_id_one);
348
349 $dbo->setQuery($q);
350 $dbo->execute();
351
352 $result = (bool)$dbo->getAffectedRows();
353
354 // swap second room record
355 $q = $dbo->getQuery(true);
356
357 $q->update($dbo->qn('#__vikbooking_ordersrooms'))
358 ->set($dbo->qn('roomindex') . ' = ' . $index_one)
359 ->where($dbo->qn('id') . ' = ' . (int)$update_id_two);
360
361 $dbo->setQuery($q);
362 $dbo->execute();
363
364 $result = $result || (bool)$dbo->getAffectedRows();
365
366 if (!$result) {
367 VBOHttpDocument::getInstance()->close(500, 'No records were updated for the involved room reservation IDs');
368 }
369
370 // update history records
371 $user = JFactory::getUser();
372 VikBooking::getBookingHistoryInstance()->setBid($booking_one['id'])->store('MB', JText::sprintf('VBO_SWAP_ROOMS_LOG', $room_name, $index_one, $index_two) . " ({$user->name})");
373 if ($booking_one['id'] != $booking_two['id']) {
374 VikBooking::getBookingHistoryInstance()->setBid($booking_two['id'])->store('MB', JText::sprintf('VBO_SWAP_ROOMS_LOG', $room_name, $index_two, $index_one) . " ({$user->name})");
375 }
376
377 // output the JSON encoded response object
378 VBOHttpDocument::getInstance()->json([
379 'swap_from' => $index_one,
380 'swap_to' => $index_two,
381 ]);
382 }
383
384 /**
385 * AJAX endpoint to remove the type flag (i.e. "overbooking") from a booking ID.
386 *
387 * @return void
388 */
389 public function delete_type_flag()
390 {
391 if (!JSession::checkToken()) {
392 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
393 }
394
395 $dbo = JFactory::getDbo();
396 $app = JFactory::getApplication();
397
398 $bid = $app->input->getUInt('bid', 0);
399 $flag = $app->input->getString('flag', '');
400
401 if (!$bid) {
402 VBOHttpDocument::getInstance()->close(404, JText::translate('VBPEDITBUSYONE'));
403 }
404
405 $q = $dbo->getQuery(true);
406
407 $q->update($dbo->qn('#__vikbooking_orders'))
408 ->set($dbo->qn('type') . ' = ' . $dbo->q(''))
409 ->where($dbo->qn('id') . ' = ' . $bid);
410
411 $dbo->setQuery($q);
412 $dbo->execute();
413
414 if (!(bool)$dbo->getAffectedRows()) {
415 VBOHttpDocument::getInstance()->close(500, 'Could not update the booking record');
416 }
417
418 if (!strcasecmp($flag, 'overbooking')) {
419 // update history records
420 $user = JFactory::getUser();
421 VikBooking::getBookingHistoryInstance($bid)->store('OB', JText::translate('VBO_OVERBOOKING_FLAG_REMOVED') . " ({$user->name})");
422 }
423
424 VBOHttpDocument::getInstance()->json([$bid => 'ok']);
425 }
426 }
427