PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.1
VikBooking Hotel Booking Engine & PMS v1.7.1
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.7.1, at admin/controllers/bookings.php

768 lines 22.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 $customers = $dbo->loadAssocList();
151
152 if ($customers) {
153 foreach ($customers as $k => $customer) {
154 $customers[$k]['text'] = trim($customer['first_name'] . ' ' . $customer['last_name']) . ' (' . $customer['tot_bookings'] . ')';
155 }
156 // push results found
157 $response['results'] = $customers;
158 }
159
160 // output the JSON encoded object with results found
161 VBOHttpDocument::getInstance()->json($response);
162 }
163
164 /**
165 * AJAX endpoint to dynamically search for rooms. Compatible with select2.
166 *
167 * @return void
168 *
169 * @since 1.16.10 (J) - 1.6.10 (WP)
170 */
171 public function rooms_search()
172 {
173 if (!JSession::checkToken()) {
174 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
175 }
176
177 $dbo = JFactory::getDbo();
178 $app = JFactory::getApplication();
179
180 $term = $app->input->getString('term', '');
181
182 $response = [
183 'results' => [],
184 'pagination' => [
185 'more' => false,
186 ],
187 ];
188
189 if (empty($term)) {
190 // output the JSON object with no results
191 VBOHttpDocument::getInstance($app)->json($response);
192 }
193
194 $dbo->setQuery(
195 $dbo->getQuery(true)
196 ->select([
197 $dbo->qn('id'),
198 $dbo->qn('name', 'text'),
199 ])
200 ->from($dbo->qn('#__vikbooking_rooms'))
201 ->where($dbo->qn('name') . ' LIKE ' . $dbo->q("%{$term}%"))
202 ->order($dbo->qn('avail') . ' DESC')
203 ->order($dbo->qn('name') . ' ASC')
204 );
205
206 // set results found
207 $response['results'] = $dbo->loadAssocList();
208
209 // output the JSON encoded object with results found
210 VBOHttpDocument::getInstance()->json($response);
211 }
212
213 /**
214 * Regular task to update the status of a cancelled booking to pending (stand-by).
215 *
216 * @return void
217 */
218 public function set_to_pending()
219 {
220 $dbo = JFactory::getDbo();
221 $app = JFactory::getApplication();
222
223 $bid = $app->input->getInt('bid', 0);
224
225 if (!JSession::checkToken() && !JSession::checkToken('get')) {
226 $app->enqueueMessage(JText::translate('JINVALID_TOKEN'), 'error');
227 $app->redirect('index.php?option=com_vikbooking&task=editorder&cid[]=' . $bid);
228 $app->close();
229 }
230
231 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid;
232 $dbo->setQuery($q, 0, 1);
233 $dbo->execute();
234 if (!$dbo->getNumRows()) {
235 $app->enqueueMessage('Booking not found', 'error');
236 $app->redirect('index.php?option=com_vikbooking&task=orders');
237 $app->close();
238 }
239
240 $booking = $dbo->loadAssoc();
241 if ($booking['status'] != 'cancelled') {
242 $app->enqueueMessage('Booking status must be -Cancelled-', 'error');
243 $app->redirect('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id']);
244 $app->close();
245 }
246
247 $q = "UPDATE `#__vikbooking_orders` SET `status`='standby' WHERE `id`=" . $booking['id'];
248 $dbo->setQuery($q);
249 $dbo->execute();
250
251 $app->enqueueMessage(JText::translate('JLIB_APPLICATION_SAVE_SUCCESS'));
252 $app->redirect('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id']);
253 $app->close();
254 }
255
256 /**
257 * AJAX endpoint to assign a room index to a room booking record.
258 *
259 * @return void
260 */
261 public function set_room_booking_subunit()
262 {
263 if (!JSession::checkToken()) {
264 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
265 }
266
267 $dbo = JFactory::getDbo();
268 $app = JFactory::getApplication();
269
270 $bid = $app->input->getInt('bid', 0);
271 $rid = $app->input->getInt('rid', 0);
272 $orkey = $app->input->getInt('orkey', 0);
273 $rindex = $app->input->getInt('rindex', 0);
274
275 if (empty($bid) || empty($rid)) {
276 VBOHttpDocument::getInstance()->close(500, 'Missing request values');
277 }
278
279 $q = "SELECT * FROM `#__vikbooking_orders` WHERE `id`=" . $bid;
280 $dbo->setQuery($q, 0, 1);
281 $booking = $dbo->loadAssoc();
282 if (!$booking) {
283 VBOHttpDocument::getInstance()->close(404, 'Booking not found');
284 }
285
286 $booking_rooms = VikBooking::loadOrdersRoomsData($booking['id']);
287 if (!$booking_rooms) {
288 VBOHttpDocument::getInstance()->close(500, 'No rooms booking found');
289 }
290
291 if (!isset($booking_rooms[$orkey]) || $booking_rooms[$orkey]['idroom'] != $rid) {
292 VBOHttpDocument::getInstance()->close(500, 'Invalid room booking record');
293 }
294
295 // update room record
296 $room_record = new stdClass;
297 $room_record->id = $booking_rooms[$orkey]['id'];
298 $room_record->roomindex = $rindex;
299
300 $dbo->updateObject('#__vikbooking_ordersrooms', $room_record, 'id');
301
302 // build list of affected nights
303 $nights_list_ymd = [];
304 $from_checkin_info = getdate($booking['checkin']);
305 for ($n = 0; $n < $booking['days']; $n++) {
306 // push affected night
307 $nights_list_ymd[] = date('Y-m-d', mktime(0, 0, 0, $from_checkin_info['mon'], ($from_checkin_info['mday'] + $n), $from_checkin_info['year']));
308 }
309
310 // build return values
311 $response = [
312 'bid' => $booking['id'],
313 'rid' => $booking_rooms[$orkey]['idroom'],
314 'rindex' => $rindex,
315 'from' => date('Y-m-d', $booking['checkin']),
316 'to' => date('Y-m-d', $booking['checkout']),
317 'nights' => $nights_list_ymd,
318 ];
319
320 // output the JSON encoded object
321 VBOHttpDocument::getInstance()->json($response);
322 }
323
324 /**
325 * AJAX endpoint to swap one sub-unit index with another for the same room ID and dates.
326 *
327 * @return void
328 *
329 * @since 1.16.2 (J) - 1.6.2 (WP)
330 */
331 public function swap_room_subunits()
332 {
333 if (!JSession::checkToken()) {
334 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
335 }
336
337 $dbo = JFactory::getDbo();
338 $app = JFactory::getApplication();
339
340 $bid_one = $app->input->getInt('bid_one', 0);
341 $bid_two = $app->input->getInt('bid_two', 0);
342 $rid = $app->input->getInt('rid', 0);
343 $index_one = $app->input->getInt('index_one', 0);
344 $index_two = $app->input->getInt('index_two', 0);
345 $checkin = $app->input->getString('checkin', '');
346
347 if (!$bid_one || !$bid_two || !$rid || !$index_one || !$index_two) {
348 VBOHttpDocument::getInstance()->close(500, 'Missing request values');
349 }
350
351 // collect the booking information
352 $booking_one = VikBooking::getBookingInfoFromID($bid_one);
353 $booking_two = VikBooking::getBookingInfoFromID($bid_two);
354 if (!$booking_one || !$booking_two) {
355 VBOHttpDocument::getInstance()->close(404, 'Could not find the involved reservations');
356 }
357
358 // get room reservation records
359 $rooms_one = VikBooking::loadOrdersRoomsData($bid_one);
360 $rooms_two = VikBooking::loadOrdersRoomsData($bid_two);
361 if (!$rooms_one || !$rooms_two) {
362 VBOHttpDocument::getInstance()->close(404, 'Could not find the involved room reservation records');
363 }
364
365 // find the record IDs involved and room name
366 $update_id_one = null;
367 $update_id_two = null;
368 $room_name = '';
369
370 foreach ($rooms_one as $room_one) {
371 if ($room_one['idroom'] == $rid && $room_one['roomindex'] == $index_one) {
372 $update_id_one = $room_one['id'];
373 $room_name = $room_one['room_name'];
374 break;
375 }
376 }
377
378 foreach ($rooms_two as $room_two) {
379 if ($room_two['idroom'] == $rid && $room_two['roomindex'] == $index_two) {
380 $update_id_two = $room_two['id'];
381 $room_name = $room_two['room_name'];
382 break;
383 }
384 }
385
386 if (!$update_id_one || !$update_id_two) {
387 VBOHttpDocument::getInstance()->close(500, 'Could not find the involved room reservation record IDs');
388 }
389
390 // swap first room record
391 $q = $dbo->getQuery(true);
392
393 $q->update($dbo->qn('#__vikbooking_ordersrooms'))
394 ->set($dbo->qn('roomindex') . ' = ' . $index_two)
395 ->where($dbo->qn('id') . ' = ' . (int)$update_id_one);
396
397 $dbo->setQuery($q);
398 $dbo->execute();
399
400 $result = (bool)$dbo->getAffectedRows();
401
402 // swap second room record
403 $q = $dbo->getQuery(true);
404
405 $q->update($dbo->qn('#__vikbooking_ordersrooms'))
406 ->set($dbo->qn('roomindex') . ' = ' . $index_one)
407 ->where($dbo->qn('id') . ' = ' . (int)$update_id_two);
408
409 $dbo->setQuery($q);
410 $dbo->execute();
411
412 $result = $result || (bool)$dbo->getAffectedRows();
413
414 if (!$result) {
415 VBOHttpDocument::getInstance()->close(500, 'No records were updated for the involved room reservation IDs');
416 }
417
418 // update history records
419 $user = JFactory::getUser();
420 VikBooking::getBookingHistoryInstance()->setBid($booking_one['id'])->store('MB', JText::sprintf('VBO_SWAP_ROOMS_LOG', $room_name, $index_one, $index_two) . " ({$user->name})");
421 if ($booking_one['id'] != $booking_two['id']) {
422 VikBooking::getBookingHistoryInstance()->setBid($booking_two['id'])->store('MB', JText::sprintf('VBO_SWAP_ROOMS_LOG', $room_name, $index_two, $index_one) . " ({$user->name})");
423 }
424
425 // output the JSON encoded response object
426 VBOHttpDocument::getInstance()->json([
427 'swap_from' => $index_one,
428 'swap_to' => $index_two,
429 ]);
430 }
431
432 /**
433 * AJAX endpoint to remove the type flag (i.e. "overbooking") from a booking ID.
434 *
435 * @return void
436 */
437 public function delete_type_flag()
438 {
439 if (!JSession::checkToken()) {
440 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
441 }
442
443 $dbo = JFactory::getDbo();
444 $app = JFactory::getApplication();
445
446 $bid = $app->input->getUInt('bid', 0);
447 $flag = $app->input->getString('flag', '');
448
449 if (!$bid) {
450 VBOHttpDocument::getInstance()->close(404, JText::translate('VBPEDITBUSYONE'));
451 }
452
453 $q = $dbo->getQuery(true);
454
455 $q->update($dbo->qn('#__vikbooking_orders'))
456 ->set($dbo->qn('type') . ' = ' . $dbo->q(''))
457 ->where($dbo->qn('id') . ' = ' . $bid);
458
459 $dbo->setQuery($q);
460 $dbo->execute();
461
462 if (!(bool)$dbo->getAffectedRows()) {
463 VBOHttpDocument::getInstance()->close(500, 'Could not update the booking record');
464 }
465
466 if (!strcasecmp($flag, 'overbooking')) {
467 // update history records
468 $user = JFactory::getUser();
469 VikBooking::getBookingHistoryInstance($bid)->store('OB', JText::translate('VBO_OVERBOOKING_FLAG_REMOVED') . " ({$user->name})");
470 }
471
472 VBOHttpDocument::getInstance()->json([$bid => 'ok']);
473 }
474
475 /**
476 * AJAX endpoint to set the AI options related to automatic guest review for a booking.
477 *
478 * @return void
479 *
480 * @since 1.16.10 (J) - 1.6.10 (WP)
481 */
482 public function set_ai_auto_guest_review_opt()
483 {
484 if (!JSession::checkToken()) {
485 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
486 }
487
488 $dbo = JFactory::getDbo();
489 $app = JFactory::getApplication();
490
491 $bid = $app->input->getInt('bid', 0);
492 $opt = $app->input->get('opt', [], 'array');
493
494 if (!$bid || !$opt) {
495 VBOHttpDocument::getInstance()->close(500, 'Missing request values');
496 }
497
498 // ensure the booking exists
499 $booking = VikBooking::getBookingInfoFromID($bid);
500 if (!$booking) {
501 VBOHttpDocument::getInstance()->close(404, 'Could not find the involved reservation');
502 }
503
504 // get AI options for this booking
505 $booking_ai_opts = (array) VBOFactory::getConfig()->getArray('ai_auto_guest_review_opt_' . $booking['id'], []);
506
507 // update the requested options
508 foreach ($opt as $param => $val) {
509 if (is_bool($val) || is_numeric($val)) {
510 $val = (int) $val;
511 }
512 // set new option value
513 $booking_ai_opts[$param] = $val;
514 }
515
516 // update AI options for this booking
517 VBOFactory::getConfig()->set('ai_auto_guest_review_opt_' . $booking['id'], $booking_ai_opts);
518
519 // return the new preferences
520 VBOHttpDocument::getInstance()->json($booking_ai_opts);
521 }
522
523 /**
524 * AJAX endpoint to register a new taking (payment).
525 *
526 * @return void
527 *
528 * @since 1.16.10 (J) - 1.6.10 (WP)
529 */
530 public function add_taking()
531 {
532 if (!JSession::checkToken()) {
533 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
534 }
535
536 $dbo = JFactory::getDbo();
537 $app = JFactory::getApplication();
538
539 $bid = $app->input->getInt('bid', 0);
540 $amount = $app->input->getFloat('amount', 0);
541 $payid = $app->input->getInt('payid', 0);
542 $descr = $app->input->getString('descr', '');
543
544 if (!$bid || !$amount || $amount < 0) {
545 VBOHttpDocument::getInstance()->close(500, 'Missing or invalid request values.');
546 }
547
548 // ensure the booking exists
549 $booking = VikBooking::getBookingInfoFromID($bid);
550 if (!$booking) {
551 VBOHttpDocument::getInstance()->close(404, 'Could not find the involved reservation.');
552 }
553
554 $new_tot_paid = $booking['totpaid'] + $amount;
555
556 // update booking record
557 $dbo->setQuery(
558 $dbo->getQuery(true)
559 ->update($dbo->qn('#__vikbooking_orders'))
560 ->set($dbo->qn('totpaid') . ' = ' . $dbo->q($new_tot_paid))
561 ->where($dbo->qn('id') . ' = ' . (int) $booking['id'])
562 );
563 $dbo->execute();
564
565 // update booking history
566 $extra_data = new stdClass;
567 $extra_data->register_new = 1;
568 $extra_data->amount_paid = $amount;
569 $extra_data->payment_method = $descr;
570 if (!empty($payid)) {
571 $pay_info = VikBooking::getPayment($payid);
572 if ($pay_info) {
573 $extra_data->payment_method = $pay_info['name'];
574 }
575 }
576 VikBooking::getBookingHistoryInstance($booking['id'])
577 ->setExtraData($extra_data)
578 ->store(
579 'PU',
580 JText::sprintf('VBOPREVAMOUNTPAID', VikBooking::numberFormat($booking['totpaid']) . (!empty($extra_data->payment_method) ? ' (' . $extra_data->payment_method . ')' : ''))
581 );
582
583 // process completed
584 VBOHttpDocument::getInstance()->json([
585 'url' => VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id'], false),
586 ]);
587 }
588
589 /**
590 * AJAX endpoint to update a taking (payment) and related history record.
591 *
592 * @return void
593 *
594 * @since 1.16.10 (J) - 1.6.10 (WP)
595 */
596 public function update_taking()
597 {
598 if (!JSession::checkToken()) {
599 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
600 }
601
602 $dbo = JFactory::getDbo();
603 $app = JFactory::getApplication();
604
605 $bid = $app->input->getInt('bid', 0);
606 $hid = $app->input->getInt('hid', 0);
607 $amount = $app->input->getFloat('amount', 0);
608 $descr = $app->input->getString('descr', '');
609 $htype = $app->input->getString('htype', 'PU');
610
611 if (!$bid || !$hid || !$amount || $amount < 0) {
612 VBOHttpDocument::getInstance()->close(500, 'Missing or invalid request values.');
613 }
614
615 // ensure the booking exists
616 $booking = VikBooking::getBookingInfoFromID($bid);
617 if (!$booking) {
618 VBOHttpDocument::getInstance()->close(404, 'Could not find the involved reservation.');
619 }
620
621 // access the current history record
622 $q = $dbo->getQuery(true)
623 ->select('*')
624 ->from($dbo->qn('#__vikbooking_orderhistory'))
625 ->where($dbo->qn('id') . ' = ' . (int) $hid)
626 ->where($dbo->qn('idorder') . ' = ' . (int) $booking['id'])
627 ->where($dbo->qn('type') . ' = ' . $dbo->q($htype));
628 $dbo->setQuery($q, 0, 1);
629 $history = $dbo->loadAssoc();
630
631 if (!$history) {
632 VBOHttpDocument::getInstance()->close(404, 'Could not find the history record to update.');
633 }
634
635 // get previous amount paid
636 $history_data = (object) json_decode(($history['data'] ?: '{}'));
637 $prev_amount_paid = $history_data->amount_paid ?? 0;
638
639 // calculate new amount paid
640 if ($prev_amount_paid > $amount) {
641 $new_tot_paid = $booking['totpaid'] - ($prev_amount_paid - $amount);
642 } else {
643 $new_tot_paid = $booking['totpaid'] + ($amount - $prev_amount_paid);
644 }
645
646 // update booking record
647 $dbo->setQuery(
648 $dbo->getQuery(true)
649 ->update($dbo->qn('#__vikbooking_orders'))
650 ->set($dbo->qn('totpaid') . ' = ' . $dbo->q($new_tot_paid))
651 ->where($dbo->qn('id') . ' = ' . (int) $booking['id'])
652 );
653 $dbo->execute();
654
655 // get currently logged user
656 $user = JFactory::getUser();
657 $uname = $user->name;
658
659 // update history extra data
660 $history_data->register_new = 1;
661 $history_data->updated = JFactory::getDate()->toSql();
662 $history_data->updated_by = $uname;
663 $history_data->amount_paid = $amount;
664 $history_data->payment_method = $descr;
665
666 // set new record description
667 $new_descr = trim($history['descr'] . "\n* " . JText::sprintf('VBO_MODIFIED_ON_SMT', JFactory::getDate()->toSql(true) . ' (' . $uname . ')'));
668
669 // update history record
670 $dbo->setQuery(
671 $dbo->getQuery(true)
672 ->update($dbo->qn('#__vikbooking_orderhistory'))
673 ->set($dbo->qn('descr') . ' = ' . $dbo->q($new_descr))
674 ->set($dbo->qn('totpaid') . ' = ' . $dbo->q($new_tot_paid))
675 ->set($dbo->qn('data') . ' = ' . $dbo->q(json_encode($history_data)))
676 ->where($dbo->qn('id') . ' = ' . (int) $history['id'])
677 );
678 $dbo->execute();
679
680 // process completed
681 VBOHttpDocument::getInstance()->json([
682 'url' => VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id'], false),
683 ]);
684 }
685
686 /**
687 * AJAX endpoint to delete a booking history event.
688 *
689 * @return void
690 *
691 * @since 1.16.10 (J) - 1.6.10 (WP)
692 */
693 public function delete_history_record()
694 {
695 if (!JSession::checkToken()) {
696 VBOHttpDocument::getInstance()->close(403, JText::translate('JINVALID_TOKEN'));
697 }
698
699 $dbo = JFactory::getDbo();
700 $app = JFactory::getApplication();
701
702 $bid = $app->input->getInt('bid', 0);
703 $hid = $app->input->getInt('hid', 0);
704 $htype = $app->input->getString('htype', 'PU');
705
706 if (!$bid || !$hid) {
707 VBOHttpDocument::getInstance()->close(500, 'Missing or invalid request values.');
708 }
709
710 // ensure the booking exists
711 $booking = VikBooking::getBookingInfoFromID($bid);
712 if (!$booking) {
713 VBOHttpDocument::getInstance()->close(404, 'Could not find the involved reservation.');
714 }
715
716 // access the current history record
717 $q = $dbo->getQuery(true)
718 ->select('*')
719 ->from($dbo->qn('#__vikbooking_orderhistory'))
720 ->where($dbo->qn('id') . ' = ' . (int) $hid)
721 ->where($dbo->qn('idorder') . ' = ' . (int) $booking['id'])
722 ->where($dbo->qn('type') . ' = ' . $dbo->q($htype));
723 $dbo->setQuery($q, 0, 1);
724 $history = $dbo->loadAssoc();
725
726 if (!$history) {
727 VBOHttpDocument::getInstance()->close(404, 'Could not find the history record to update.');
728 }
729
730 // get previous amount paid
731 $history_data = (object) json_decode(($history['data'] ?: '{}'));
732 $prev_amount_paid = $history_data->amount_paid ?? 0;
733
734 // calculate new amount paid
735 $new_tot_paid = $booking['totpaid'];
736 if ($prev_amount_paid) {
737 $new_tot_paid = $booking['totpaid'] - $prev_amount_paid;
738 }
739
740 // update booking record
741 $dbo->setQuery(
742 $dbo->getQuery(true)
743 ->update($dbo->qn('#__vikbooking_orders'))
744 ->set($dbo->qn('totpaid') . ' = ' . $dbo->q($new_tot_paid))
745 ->where($dbo->qn('id') . ' = ' . (int) $booking['id'])
746 );
747 $dbo->execute();
748
749 // delete history record
750 $dbo->setQuery(
751 $dbo->getQuery(true)
752 ->delete($dbo->qn('#__vikbooking_orderhistory'))
753 ->where($dbo->qn('id') . ' = ' . (int) $hid)
754 ->where($dbo->qn('idorder') . ' = ' . (int) $booking['id'])
755 ->where($dbo->qn('type') . ' = ' . $dbo->q($htype))
756 );
757
758 $dbo->execute();
759 $aff_rows = $dbo->getAffectedRows();
760
761 // process completed
762 VBOHttpDocument::getInstance()->json([
763 'rows' => $aff_rows,
764 'url' => VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikbooking&task=editorder&cid[]=' . $booking['id'], false),
765 ]);
766 }
767 }
768