PluginProbe
Easy Hotel – Powerful Hotel Booking / 2.0.4
Easy Hotel – Powerful Hotel Booking v2.0.4
2.0.8 2.0.7 2.0.6 2.0.5 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.9.9 1.9.8 1.9.7 1.9.6 1.9.5 1.9.4 1.9.3 1.9.2 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 All 110 releases
easy-hotel / admin / includes / classes / class.admin-booking.php

class.admin-booking.php in Easy Hotel – Powerful Hotel Booking 2.0.4, at admin/includes/classes/class.admin-booking.php

453 lines 18.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly.
3 class ESHB_Admin_Booking {
4 public function __construct() {
5 add_action( 'wp_after_insert_post', [$this, 'create_order_after_save_booking_post'], 10, 3 );
6 add_action( 'save_post_eshb_booking', [$this, 'eshb_update_booking_title_on_save'], 10, 3 );
7 add_filter( 'eshb_eshb_booking_metaboxes_save', [$this, 'update_booking_metaboxes'], 10, 3 );
8 }
9
10 function update_booking_metaboxes ($data, $post_id, $obj) {
11
12 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action') ) ) {
13 $new_status = '';
14 }else{
15 $new_status = !empty($_POST['post_status']) ? sanitize_text_field( wp_unslash( $_POST['post_status'] ) ) : '';
16 }
17
18 $order_id = get_post_meta($post_id, '_order_post_created', true);
19
20 $eshb_booking_metaboxes = $data;
21
22 $assigned_order_id = $eshb_booking_metaboxes['order_id'] ?? false;
23
24 if(!empty($new_status)){
25 $eshb_booking_metaboxes['booking_status'] = $new_status;
26 }
27 $eshb_booking_metaboxes['order_id'] = $order_id;
28
29 return $eshb_booking_metaboxes;
30 }
31
32 function create_woocommerce_order($product_id, $subtotal, $total_paid = 0, $address = '', $status = 'processing', $item_meta = []) {
33 // 1. Create the order
34 $order = wc_create_order();
35
36 // 2. Add products (product_id, quantity)
37 $item_id = $order->add_product( wc_get_product( $product_id ), 1 );
38
39 // 3. Calculate totals
40 $order->calculate_totals();
41
42 // 4. Set customer billing details
43 if ( ! empty($address) && is_array($address) ) {
44 $order->set_address( $address, 'billing' );
45 }
46
47 // 5. Set payment method
48 $order->set_payment_method( 'cod' );
49
50 // 6. Get the line item object
51 $item = $order->get_item( $item_id );
52
53 // 7. Set a custom line subtotal/total if needed
54 if ( $item && $item instanceof WC_Order_Item_Product ) {
55
56 // Set custom item totals (without tax)
57 $item->set_subtotal( $subtotal );
58 $item->set_total( $subtotal );
59
60 // --- Add/Update line item meta ---
61 // Pass associative array: ['_internal_note' => 'x', 'room_type' => 'Deluxe']
62 if ( ! empty( $item_meta ) && is_array( $item_meta ) ) {
63 foreach ( $item_meta as $key => $value ) {
64 // update_meta_data prevents duplicate keys; use add_meta_data for duplicates
65 $item->update_meta_data( $key, $value );
66 }
67 }
68
69 // Save the line item with meta and totals
70 $item->save();
71 }
72
73
74 // 8. Set the order total
75 $order->set_total( $total_paid ); // without tax
76
77 // 9. Add custom order meta (loop through meta_data array)
78 if ( ! empty($meta_data) && is_array($meta_data) ) {
79 foreach ($meta_data as $key => $value) {
80 $order->update_meta_data($key, $value);
81 }
82 }
83
84 // 10. (Optional) Set status
85 $order->update_status( $status, 'Order created programmatically.' );
86
87 // 11. Save order with meta
88 $order->save();
89
90 return $order->get_id(); // Returns the order ID
91 }
92
93 function update_woocommerce_order($order_id, $subtotal = '', $total_paid = '', $status = 'processing', $product_id = '', $address = '', $item_meta = []) {
94 // 1. Get the order
95 $order = wc_get_order( $order_id );
96
97 if ( !$order ) {
98 return false; // Order not found
99 }
100
101 // 2. Update products (product_id, quantity)
102 if( !empty($product_id) ) {
103
104 // Remove existing items if needed
105 $items = $order->get_items();
106
107 if ( ! empty( $items ) ) {
108 $first_item = reset( $items ); // Get the first item object
109 $order->remove_item( $first_item->get_id() );
110 }
111
112 $item_id = $order->add_product( wc_get_product( $product_id ), 1 ); // 123 = Product ID, 2 = Qty
113 }
114
115 // If no product_id is provided, we assume the order already has items and we won't add a new one.
116 $item_id = !empty($item_id) ? $item_id : array_key_first($order->get_items());
117
118 // 3. Calculate totals
119 $order->calculate_totals();
120
121 // 4. Set customer billing details
122 if( !empty($address) ) {
123 // Ensure address is an array
124 if ( !is_array($address) ) {
125 $address = [];
126 }
127 $order->set_address( $address, 'billing' );
128 }
129
130
131 // 5. Set payment method
132 //$order->set_payment_method( 'cod' ); // cod = Cash on Delivery
133
134 // 6. Get the line item object
135 $item = $order->get_item( $item_id );
136
137 // 7. Set a custom line subtotal/total if needed
138 if ( $item && $item instanceof WC_Order_Item_Product ) {
139
140 if( !is_numeric($subtotal) ) {
141 $subtotal = $order->get_subtotal(); // If subtotal is not provided, use get the current subtotal
142 }
143
144 if( !is_numeric($total_paid) ) {
145 $total_paid = $order->get_total(); // If total_paid is not provided, use get the current total
146 }
147
148 // Set custom item totals (without tax)
149 $item->set_subtotal( $subtotal );
150 $item->set_total( $subtotal );
151
152 // --- Add/Update line item meta ---
153 // Pass associative array: ['_internal_note' => 'x', 'room_type' => 'Deluxe']
154 if ( ! empty( $item_meta ) && is_array( $item_meta ) ) {
155 foreach ( $item_meta as $key => $value ) {
156 // update_meta_data prevents duplicate keys; use add_meta_data for duplicates
157 $item->update_meta_data( $key, $value );
158 }
159 }
160
161 // Save the line item with meta and totals
162 $item->save();
163 }
164
165 // 8. Set the order total
166 if ( !is_numeric($total_paid) ) {
167 $total_paid = $order->get_total(); // If total_paid is not provided, use get the current total
168 }
169
170 $order->set_total( $total_paid ); // without tax
171
172 if (!empty($status) && $status !== $order->get_status()) {
173 $order->update_status( $status, 'Order updated programmatically.' );
174 }
175
176 // 9. Add custom order meta (loop through meta_data array)
177 if ( ! empty($meta_data) && is_array($meta_data) ) {
178 foreach ($meta_data as $key => $value) {
179 $order->update_meta_data($key, $value);
180 }
181 }
182
183 // Save the order
184 $order->save();
185
186 return true; // Order updated successfully
187
188 }
189
190 function create_order_after_save_booking_post($booking_id, $booking, $update){
191
192
193 if( (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || $booking->post_type !== 'eshb_booking' ) return;
194
195 static $processing = false;
196
197 if ( $processing ) {
198 return;
199 }
200
201 if ( $update !== true) {
202 return;
203 }
204
205 if ( ! isset( $_POST['nonce'] ) ||
206 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action') ) ) {
207 $new_status = $booking->post_status;
208 }else{
209 $new_status = !empty($_POST['post_status']) ? sanitize_text_field( wp_unslash( $_POST['post_status'] ) ) : 'not found';
210 }
211
212 $processing = true;
213 $order_id = get_post_meta($booking_id, '_order_post_created', true);
214
215 $booking_status = $booking->post_status;
216
217
218 // create woocommerce order if post status is
219 $allowed_statuses = array_keys(ESHB_Helper::eshb_get_booking_statuses());
220 if( !in_array($booking_status, $allowed_statuses) ) {
221 return;
222 }
223
224 $eshb_settings = get_option('eshb_settings');
225 $booking_type = isset($eshb_settings['booking-type']) ? $eshb_settings['booking-type'] : '';
226
227 $room_visibility = in_array('rooms', $eshb_settings['booking-form-fields']) ? true : false;
228 $visible_fields = $eshb_settings['booking-form-fields'] ?? [];
229
230 $thumbnail_id = get_post_meta( $booking_id, '_thumbnail_id', true );
231 $address = get_post_meta( $booking_id, 'eshb_booking_customer_details_metaboxes', true);
232
233 $eshb_booking_metaboxes = get_post_meta( $booking_id, 'eshb_booking_metaboxes', true);
234 $accomodation_id = !empty($eshb_booking_metaboxes['booking_accomodation_id']) ? $eshb_booking_metaboxes['booking_accomodation_id'] : '';
235 $room_quantity = !empty($eshb_booking_metaboxes['room_quantity']) ? $eshb_booking_metaboxes['room_quantity'] : 1;
236 $extra_bed_quantity = !empty($eshb_booking_metaboxes['extra_bed_quantity']) ? $eshb_booking_metaboxes['extra_bed_quantity'] : 0;
237 $adult_quantity = !empty($eshb_booking_metaboxes['adult_quantity']) ? $eshb_booking_metaboxes['adult_quantity'] : 1;
238 $children_quantity = !empty($eshb_booking_metaboxes['children_quantity']) ? $eshb_booking_metaboxes['children_quantity'] : 1;
239 $start_date = !empty($eshb_booking_metaboxes['start_date']) ? $eshb_booking_metaboxes['start_date'] : '';
240 $end_date = !empty($eshb_booking_metaboxes['start_date']) ? $eshb_booking_metaboxes['end_date'] : '';
241 $dates = !empty($eshb_booking_metaboxes['dates']) ? $eshb_booking_metaboxes['dates'] : '';
242 $details_html = !empty($eshb_booking_metaboxes['details_html']) ? $eshb_booking_metaboxes['details_html'] : '';
243 $extra_services = !empty($eshb_booking_metaboxes['extra_services']) ? $eshb_booking_metaboxes['extra_services'] : '';
244 $subtotal_price = !empty($eshb_booking_metaboxes['subtotal_price']) ? $eshb_booking_metaboxes['subtotal_price'] : 0;
245 $base_price = !empty($eshb_booking_metaboxes['base_price']) ? $eshb_booking_metaboxes['base_price'] : 0;
246 $total_price = !empty($eshb_booking_metaboxes['total_price']) ? $eshb_booking_metaboxes['total_price'] : 0;
247 $extra_services_charge = !empty($eshb_booking_metaboxes['extra_service_price']) ? $eshb_booking_metaboxes['extra_service_price'] : 0;
248 $extra_bed_price = !empty($eshb_booking_metaboxes['extra_bed_price']) ? $eshb_booking_metaboxes['extra_bed_price'] : 0;
249 $total_paid = !empty($eshb_booking_metaboxes['total_paid']) ? $eshb_booking_metaboxes['total_paid'] : 0;
250 $new_due = (float) $total_price - (float) $total_paid;
251 $extra_services_html = $this->format_extra_services($extra_services, $room_visibility);
252 $details_html = $this->format_details($eshb_booking_metaboxes, $visible_fields);
253
254 if(!empty($accomodation_id)){
255 $meta_data = [
256 'Accomodation ID' => $accomodation_id,
257 'Total Price' => $total_price,
258 'Subtotal Price' => $subtotal_price,
259 'Base Price' => $base_price,
260 'Extra Services Charge' => $extra_services_charge,
261 'Extra Bed Price' => $extra_bed_price,
262 'Rooms' => $room_quantity,
263 'Extra Bed' => $extra_bed_quantity,
264 'Adults' => $adult_quantity,
265 'Children' => $children_quantity,
266 'Start Date' => $start_date,
267 'End Date' => $end_date,
268 'Date' => $dates,
269 'Details' => $details_html,
270 'Extra Services IDs' => $extra_services,
271 'Extra Services' => $extra_services_html,
272 ];
273
274 $eshb_booking_metaboxes['extra_services_html'] = $extra_services_html;
275
276 // update woocommerce order if it exists
277 if(!empty($order_id)) {
278
279
280 $is_done_initial_update = get_post_meta($booking_id, 'is_done_initial_update', true);
281
282
283 if($is_done_initial_update == 'yes') {
284
285 // booking status change
286 if($new_due > 0 && $total_paid > 0){
287 $booking_status = 'deposit-payment';
288 }
289
290 if($new_due > 0){
291 update_post_meta($order_id, 'eshb_booking_due_amount', $new_due);
292 }
293
294 if($new_due < 1){
295
296 if (!empty($eshb_settings['booking-auto-approval']) && $eshb_settings['booking-auto-approval'] == true) {
297 $booking_status = 'completed';
298 }else{
299 $booking_status = 'processing';
300 }
301 delete_post_meta( $order_id, 'eshb_booking_due_amount');
302 }
303
304 if(in_array($new_status, ['processing', 'on-hold', 'cancelled', 'failed', 'refunded', 'trash'])){
305 $booking_status = $new_status;
306 }
307
308
309 if ($booking_type == 'woocommerce' && class_exists( 'woocommerce' )) {
310 $product_id = get_post_meta($accomodation_id, '_woocommerce_product_id', true);
311 $this->update_woocommerce_order($order_id, $subtotal_price, $total_paid, $booking_status, $product_id, $address, $meta_data);
312
313 // assign accomodation_id to woocommerce product
314 update_post_meta($product_id, '_accomodation_id', $accomodation_id);
315 }
316 }
317
318 update_post_meta($booking_id, 'is_done_initial_update', 'yes');
319
320 $processing = false;
321 return;
322 }else{
323
324 if ($booking_type == 'woocommerce' && class_exists( 'woocommerce' )) {
325
326 $product_id = ESHB_Helper::get_or_create_woocommerce_product($accomodation_id, $thumbnail_id);
327
328 // assign product_id to booking post
329 update_post_meta($booking_id, '_woocommerce_product_id', $product_id);
330
331 // create a woocommerce order
332 $order_id = $this->create_woocommerce_order($product_id, $subtotal_price, '', $address, $booking_status, $meta_data);
333
334
335 // update due
336 if($new_due > 0) {
337 update_post_meta($order_id, 'eshb_booking_due_amount', $new_due);
338 }
339
340 // assign accomodation_id to woocommerce product
341 update_post_meta($product_id, '_accomodation_id', $accomodation_id);
342 update_post_meta($order_id, '_booking_post_created', $booking_id);
343 update_post_meta($booking_id, '_order_post_created', $order_id);
344
345 do_action( 'after_created_manual_booking', ['booking_id' => $booking_id, 'order_id' => $order_id, 'due' => $new_due] );
346
347
348
349 $processing = false;
350 return;
351 }
352 }
353 }
354 }
355
356 function eshb_update_booking_title_on_save( $post_id, $post, $update ) {
357
358 // Skip autosave/revision
359 if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
360 return;
361 }
362
363 // Run only on update (not insert)
364 if ( !$update ) {
365 return;
366 }
367
368 // Skip if deleting, trashing, or being moved to trash
369 if ( in_array( $post->post_status, [ 'trash', 'auto-draft' ], true ) ) {
370 return;
371 }
372
373 // Re-entrancy guard
374 static $running = false;
375 if ( $running ) return;
376 $running = true;
377
378 if ( ! isset( $_POST['nonce'] ) ||
379 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), ESHB_Helper::generate_secure_nonce_action('eshb_global_nonce_action') ) ) {
380 $eshb_booking_metaboxes = get_post_meta( $post_id, 'eshb_booking_metaboxes', true );
381 }else{
382 $eshb_booking_metaboxes = !empty($_POST['eshb_booking_metaboxes']) ? map_deep( wp_unslash( $_POST['eshb_booking_metaboxes']), 'sanitize_text_field' ) : $eshb_booking_metaboxes;
383 }
384
385
386 $accommodation_id = is_array( $eshb_booking_metaboxes ) && ! empty( $eshb_booking_metaboxes['booking_accomodation_id'] ) ? (int) $eshb_booking_metaboxes['booking_accomodation_id'] : 0;
387 $accommodation_title = $accommodation_id ? get_the_title( $accommodation_id ) : '';
388 $new_title = 'Booking #' . $post_id . ( $accommodation_title ? ' for: ' . $accommodation_title : '' );
389
390 // update title if its not same to old title
391 if ( get_post_field( 'post_title', $post_id ) !== $new_title ) {
392 // Recursion is prevented by the static $running guard above; no
393 // need to remove/re-add the hook here.
394 wp_update_post( [
395 'ID' => $post_id,
396 'post_title' => $new_title,
397 ] );
398 }
399
400 // Prevent duplicate execution
401 set_transient( 'eshb_manual_booking_done_' . $post_id, true, 10 ); // expires
402 $running = false;
403 }
404
405 /**
406 * Build extra services titles.
407 */
408 private function format_extra_services($extra_services, $room_visibility) {
409 if (empty($extra_services) || !is_array($extra_services)) return '';
410
411 $titles = [];
412 foreach ($extra_services as $service) {
413 $service_id = $service['id'];
414 $qty = (int) ($service['quantity'] ?? 0);
415 $title = get_the_title($service_id);
416
417 if ($qty > 0) {
418 $meta = get_post_meta($service_id, 'eshb_service_metaboxes', true);
419 $charge_type = $meta['service_charge_type'] ?? '';
420 if ($room_visibility || $charge_type !== 'room') {
421 $title .= " For {$qty} " . ucfirst(strtolower($charge_type));
422 }
423 }
424 $titles[] = $title;
425 }
426 return implode(', ', $titles);
427 }
428
429 /**
430 * Build booking details string.
431 */
432 private function format_details($data, $visible_fields) {
433 $map = [
434 'rooms' => ['label' => 'Room', 'qty' => $data['room_quantity']],
435 'extra_beds' => ['label' => 'Extra Bed','qty' => $data['extra_bed_quantity']],
436 'adults' => ['label' => 'Adult', 'qty' => $data['adult_quantity']],
437 'childrens' => ['label' => 'Children', 'qty' => $data['children_quantity']],
438 ];
439
440 $details = [];
441 foreach ($map as $key => $info) {
442 if (in_array($key, $visible_fields) && $info['qty'] > 0) {
443 $details[] = "{$info['label']}: {$info['qty']}";
444 }
445 }
446 return implode(', ', $details);
447 }
448
449
450 }
451 if(is_admin()) {
452 new ESHB_Admin_Booking();
453 }