|
Server IP : 10.131.40.8 / Your IP : 216.73.216.37 Web Server : Apache System : Linux webd008.cluster131.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64 User : ludmqhh ( 137773) PHP Version : 8.4.10 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0705) : /home/ludmqhh/www/hotel-forum/wp-content/plugins/wp-hotelier/includes/ |
| [ Home ] | [ C0mmand ] | [ Upload File ] |
|---|
<?php
/**
* Helper class that calculates cart totals.
*
* @author Benito Lopez <hello@lopezb.com>
* @category Class
* @package Hotelier/Classes
* @version 2.6.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'HTL_Cart_Totals' ) ) :
/**
* HTL_Cart_Totals Class
*/
class HTL_Cart_Totals {
/**
* The arrival date of the guest.
*
* @var string
*/
public $checkin;
/**
* The departure date of the guest.
*
* @var string
*/
public $checkout;
/**
* Contains an array of cart items and the quantity.
* When we check if an item is available we use the ID
* of the room. Rates belong to the same room (ID) so we
* need to sum the quantity of each rate to check the
* availability.
*
* e.g. The stock of a room is 10 and the room has two
* rates ('rate one' and 'rate two'). If a guest selects
* 7 rooms of 'rate one', the stock available for the rate
* 'rate two' is 3, not 10.
*
* @var array
*/
public $cart_contents_quantity = array();
/**
* Contains an array of cart items.
*
* @var array
*/
public $cart_contents = array();
/**
* The total cost of the cart items.
*
* @var int
*/
public $cart_contents_total;
/**
* The required deposit.
*
* @var int
*/
public $required_deposit;
/**
* Total cart tax.
*
* @var int
*/
public $tax_total;
/**
* Total cart without tax.
*
* @var int
*/
public $subtotal;
/**
* Cart grand total.
*
* @var int
*/
public $total;
/**
* Cart discount.
*
* @var int
*/
public $discount_total;
/**
* Applied coupon.
*
* @var int
*/
public $coupon_id;
/**
* Get things going.
*/
public function __construct( $checkin, $checkout, $coupon_id = 0 ) {
$this->checkin = $checkin;
$this->checkout = $checkout;
$this->coupon_id = $coupon_id;
}
/**
* Add a room to the cart.
*
* @param integer $room_id contains the id of the room to add to the cart
* @param integer $quantity contains the quantity of the item to add
* @param integer $rate_id
* @param array $guests array of guests
* @param array $fees array of fees
* @param array $extras array of fees
* @param bool $force checks only if checkout > checkin
* @param array $exclude reservation IDs to exclude when checking the available rooms
* @return string $cart_item_key
*/
public function add_to_cart( $room_id = 0, $quantity = 1, $rate_id = 0, $guests = array(), $fees = false, $extras = false, $force = false, $exclude = array() ) {
// Wrap in try catch so plugins can throw an exception to prevent adding to cart
try {
$room_id = absint( $room_id );
$quantity = absint( $quantity );
$rate_id = absint( $rate_id );
if ( ! HTL_Formatting_Helper::is_valid_checkin_checkout( $this->checkin, $this->checkout, $force ) ) {
throw new Exception( esc_html__( 'Sorry, this room is not available on the given dates.', 'wp-hotelier' ) );
}
// Get the room
$_room = htl_get_room( $room_id );
if ( ! $_room->exists() ) {
// Oops, check failed so throw an error (this this room does not exists)
throw new Exception( esc_html__( 'Sorry, this room does not exists.', 'wp-hotelier' ) );
}
// Sanitity check
if ( $quantity <= 0 || ! $_room || 'publish' !== $_room->post->post_status ) {
throw new Exception();
}
// Check the real quantity (rates have the same ID and stock)
if ( isset( $this->cart_contents_quantity[ $_room->id ] ) ) {
$real_qty = $this->cart_contents_quantity[ $_room->id ] + $quantity;
} else {
$real_qty = $quantity;
}
// Check room is_available on the given dates
if ( ! $_room->is_available( $this->checkin, $this->checkout, $real_qty, $exclude, $force ) ) {
throw new Exception( esc_html__( 'Sorry, this room is not available on the given dates.', 'wp-hotelier' ) );
}
// If a $rate_id > 0 is passed, then this is (technically) a variable room
if ( $rate_id > 0 ) {
if ( ! $_room->is_variable_room() ) {
// Oops, check failed so throw an error (this is not a variable room)
throw new Exception( esc_html__( 'Sorry, this room does not exists.', 'wp-hotelier' ) );
}
// Check if the room has this rate and get it (we need the slug)
$rate_name = $_room->get_rate_name( $rate_id );
// Final check - Check if the rate exists in the room_rate taxonomy
// We need to make this check because the rate_name (term slug) is stored in a meta box (and we do not know if it still exists).
if ( $rate_name && $_room->rate_term_exists( $rate_name ) ) {
// Ok, we can load the variation
$_variation = $_room->get_room_variation( $rate_id );
// Deposit
$deposit = $_variation->get_deposit();
// Check if it is cancellable
$is_cancellable = $_variation->is_cancellable();
} else {
// Oops, check failed so throw an error (rate does not exist in the room_rate taxonomy)
throw new Exception( esc_html__( 'Sorry, this room does not exists.', 'wp-hotelier' ) );
}
} elseif ( $rate_id === 0 && $_room->is_variable_room() ) {
// Oops, check failed so throw an error (passed rate_id = 0 but this is a variable room)
throw new Exception( esc_html__( 'Sorry, this room does not exists.', 'wp-hotelier' ) );
} else {
// This is a standard room
$rate_name = false;
$_variation = false;
// Deposit
$deposit = $_room->get_deposit();
// Check if it is cancellable
$is_cancellable = $_room->is_cancellable();
}
// Fees
$fees = $fees && is_array( $fees ) ? $fees : array();
// Extras
$extras = $extras && is_array( $extras ) ? $extras : array();
// Generate an ID based on room ID and rate ID - this also avoid duplicates
$cart_item_key = htl_generate_item_key( $room_id, $rate_id );
// Hook to allow plugins to modify cart item
$this->cart_contents[ $cart_item_key ] = apply_filters( 'hotelier_add_cart_item', array(
'data' => $_room,
'room_id' => $_room->id,
'quantity' => $quantity,
'rate_id' => $rate_id,
'rate_name' => $rate_name,
'max_guests' => $_room->get_max_guests(),
'deposit' => $deposit,
'is_cancellable' => $is_cancellable,
'guests' => $guests,
'fees' => $fees,
'extras' => $extras,
) );
// Set the quantity
$this->cart_contents_quantity[ $_room->id ] = $real_qty;
return $cart_item_key;
} catch ( Exception $e ) {
if ( $e->getMessage() ) {
if ( function_exists( 'htl_add_notice' ) ) {
htl_add_notice( $e->getMessage(), 'error' );
} else {
// We are on admin. Return an array with the error message
return array(
'error' => true,
'message' => $e->getMessage()
);
}
}
return false;
}
}
/**
* Calculate totals for the items in the reservation.
*/
public function calculate_totals( $cart_contents = false) {
$this->cart_contents = $cart_contents ? $cart_contents : $this->cart_contents;
foreach ( $this->cart_contents as $cart_item_key => $values ) {
$_room = $values[ 'data' ];
$rate_id = $values[ 'rate_id' ];
$qty = $values[ 'quantity' ];
$room_type = 'standard';
// Price for variable room - We already know that if we pass a $rate_id is a variable room ( in $this->add_to_cart() )
if ( $rate_id ) {
$_variation = $_room->get_room_variation( $rate_id );
$line_price = $_variation->get_price( $this->checkin, $this->checkout );
$line_price_without_fees = $line_price;
$line_price = $this->calculate_fees( $line_price, $values[ 'fees' ], $_room );
$line_price_without_extras = $line_price;
$line_extras = $this->get_line_extras( $line_price, $values[ 'extras' ], $values, $_room );
$line_price = $this->calculate_extras( $line_price, $line_extras );
$line_deposit = $_variation->get_deposit();
$room_type = 'variation';
} else {
// Price for standard room
$line_price = $_room->get_price( $this->checkin, $this->checkout );
$line_price_without_fees = $line_price;
$line_price = $this->calculate_fees( $line_price, $values[ 'fees' ], $_room );
$line_price_without_extras = $line_price;
$line_extras = $this->get_line_extras( $line_price, $values[ 'extras' ], $values, $_room );
$line_price = $this->calculate_extras( $line_price, $line_extras );
$line_deposit = $_room->get_deposit();
}
if ( ! $line_price_without_fees ) {
// Remove room from reservation if has not price and throw an error
unset( $this->cart_contents[ $cart_item_key ] );
throw new Exception( esc_html__( 'Sorry, this room cannot be reserved.', 'wp-hotelier' ) );
}
// The total price of the room
$line_total = $line_price * $qty;
// The total required deposit of the room
$line_to_pay = ( ( $line_price * $line_deposit ) / 100 );
$line_to_pay = round( $line_to_pay ) * $qty;
// Hold room details so we can pass them to the filter
$room_data = $room_type == 'standard' ? $_room : $_variation;
// Allow plugins to filter the deposit
$line_to_pay = apply_filters( 'hotelier_line_to_pay', $line_to_pay, $line_price, $line_deposit, $qty, $room_type, $room_data );
// This is the total deposit required to confirm a reservation
// Deposits are per line (room)
$this->required_deposit += $line_to_pay;
// This is the total cost of the reservation (deposit included)
$this->cart_contents_total += $line_total;
// Set prices
$this->cart_contents[ $cart_item_key ][ 'price' ] = $line_price;
$this->cart_contents[ $cart_item_key ][ 'price_without_extras' ] = $line_price_without_extras;
$this->cart_contents[ $cart_item_key ][ 'total' ] = $line_total;
$this->cart_contents[ $cart_item_key ][ 'extras' ] = $line_extras ;
$this->cart_contents[ $cart_item_key ][ 'total_without_extras' ] = $line_price_without_extras * $qty;
}
// Subtotal
$this->subtotal = apply_filters( 'hotelier_calculated_subtotal', $this->cart_contents_total, $this );
// Calculate coupons
if ( htl_coupons_enabled() && $this->coupon_id > 0 ) {
$this->discount_total = htl_calculate_coupon( $this->cart_contents_total, $this->coupon_id );
if ( $this->discount_total > 0 ) {
$this->cart_contents_total = $this->discount_total > $this->cart_contents_total ? 0 : $this->cart_contents_total - $this->discount_total;
}
} else {
$this->discount_total = 0;
}
// Ensure deposit is never > cart totals
$this->required_deposit = $this->required_deposit > $this->cart_contents_total ? $this->cart_contents_total : $this->required_deposit;
// Calculate taxes
$this->tax_total = htl_is_tax_enabled() ? htl_calculate_tax( $this->cart_contents_total ) : 0;
// Taxes on deposits
if ( htl_is_deposit_tax_enabled() ) {
$this->required_deposit = $this->required_deposit + htl_calculate_tax( $this->required_deposit );
}
// Allow plugins to hook and alter totals before final total is calculated
do_action( 'hotelier_calculate_totals', $this );
$total = $this->cart_contents_total + htl_calculate_tax( $this->cart_contents_total );
$this->total = apply_filters( 'hotelier_calculated_total', $total, $this );
do_action( 'hotelier_after_calculate_totals' );
}
/**
* Calculate fees.
*/
public function calculate_fees( $line_price, $fees, $room, $rate_id = 0 ) {
foreach ( $fees as $key => $value ) {
$fee_to_add = htl_calculate_fee( $key, $value, $line_price, $this->checkin, $this->checkout, $room, $rate_id );
$line_price += $fee_to_add;
}
return $line_price;
}
/**
* Get line extras.
*/
public function get_line_extras( $line_price, $extras, $values, $room ) {
$line_extras = htl_get_room_extras( $line_price, $extras, $values, $room, $this->checkin, $this->checkout );
return $line_extras;
}
/**
* Calculate extras.
*/
public function calculate_extras( $line_price, $line_extras ) {
foreach ( $line_extras as $line_extra_id => $line_extra ) {
if ( isset( $line_extra['price'] ) ) {
$qty = isset( $line_extra['qty'] ) ? $line_extra['qty'] : 1;
$line_price += $line_extra['price'] * $qty;
}
}
return $line_price;
}
}
endif;
