Hotel Raxa Dev 5b1e2453c7 Hotel Raxa - Advanced Booking System Implementation
🏨 Hotel Booking Enhancements:
- Implemented Eagle Booking Advanced Pricing add-on
- Added Booking.com-style rate management system
- Created professional calendar interface for pricing
- Integrated deals and discounts functionality

💰 Advanced Pricing Features:
- Dynamic pricing models (per room, per person, per adult)
- Base rates, adult rates, and child rates management
- Length of stay discounts and early bird deals
- Mobile rates and secret deals implementation
- Seasonal promotions and flash sales

📅 Availability Management:
- Real-time availability tracking
- Stop sell and restriction controls
- Closed to arrival/departure functionality
- Minimum/maximum stay requirements
- Automatic sold-out management

💳 Payment Integration:
- Maintained Redsys payment gateway integration
- Seamless integration with existing Eagle Booking
- No modifications to core Eagle Booking plugin

🛠️ Technical Implementation:
- Custom database tables for advanced pricing
- WordPress hooks and filters integration
- AJAX-powered admin interface
- Data migration from existing Eagle Booking
- Professional calendar view for revenue management

📊 Admin Interface:
- Booking.com-style management dashboard
- Visual rate and availability calendar
- Bulk operations for date ranges
- Statistics and analytics dashboard
- Modal dialogs for quick editing

🔧 Code Quality:
- WordPress coding standards compliance
- Secure database operations with prepared statements
- Proper input validation and sanitization
- Error handling and logging
- Responsive admin interface

🤖 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-11 07:43:22 +02:00

553 lines
22 KiB
PHP

<?php
/* --------------------------------------------------------------------------
* @ EB Admin
* @ Taxes & Fees [Admin]
* @ Since 1.3.3
* @ Author: Eagle Themes
* @ Developer: Jomin Muskaj
---------------------------------------------------------------------------*/
// Exit if accessed directly
defined('ABSPATH') || exit;
class EB_ADMIN_TAXES_FEES {
public function __construct() {
// Actions
add_action( 'admin_menu', array( $this, 'add_admin_sub_page' ) );
add_action( 'wp_ajax_admin_create_entry', array( $this, 'create') );
add_action( 'wp_ajax_admin_update_entry', array( $this, 'update') );
add_action( 'wp_ajax_admin_delete_entry', array( $this, 'delete') );
}
/**
* Create the submenu
*/
public function add_admin_sub_page(){
$current_page = add_submenu_page(
'eb_bookings',
__('Taxes & Fees', 'eagle-booking'),
__('Taxes & Fees', 'eagle-booking'),
'edit_pages',
'eb_taxes_and_fees',
array( $this, 'render' )
);
// Load the JS only on this page
add_action( 'load-' . $current_page, array( $this, 'load_admin_js') );
}
/**
* Load Admin JS
*/
public function load_admin_js(){
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts') );
}
/**
* Enqueue the required scripts
*/
public function enqueue_scripts() {
wp_enqueue_script( 'eb-admin-taxes-fees', EB_URL .'assets/js/admin/taxesfees.js', array( 'jquery' ), EB_VERSION, true );
wp_localize_script( 'eb-admin-taxes-fees', 'taxes_fees', array(
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('nonce')
));
}
/**
* Create Entry [AJAX Request]
*/
public function create() {
if( isset( $_POST['entry_title'] ) ) {
$entry_cat = sanitize_text_field( $_POST['entry_cat'] );
$entry_nonce = sanitize_text_field( $_POST['entry_nonce'] );
$entry_title = sanitize_text_field( $_POST['entry_title'] );
$entry_type = sanitize_text_field( $_POST['entry_type'] );
$entry_amount = sanitize_text_field( $_POST['entry_amount'] );
$entry_global = sanitize_text_field( $_POST['entry_global'] );
$entry_services = sanitize_text_field( $_POST['entry_services'] );
// $entry_fees = sanitize_text_field( $_POST['entry_fees'] );
// Check nonce
if ( !wp_verify_nonce($entry_nonce, 'nonce') ) {
$return_data['status'] = 'failed';
$return_data['mssg'] = __('Invalid Nonce', 'eagle-booking');
// If everything is ok let's proceed to the deletion
} else {
// Current Entries
$current_entries = get_option( $entry_cat );
if ( empty( $current_entries ) ) {
// Set first id to 1
$entry_id = "1";
} else {
// Get the last entry
$last_array = end( $current_entries );
// Get the id of the latest entry
$last_id = $last_array['id'];
// Get the last id + 1
$entry_id = ++$last_id;
}
// New Entry Fields (based on cat)
if ( $entry_cat === 'eb_taxes' ){
$new_entries = array(
'id' => $entry_id,
'title' => $entry_title,
'amount' => $entry_amount,
'global' => $entry_global,
'services' => $entry_services,
// 'fees' => $entry_fees
);
} else {
$new_entries = array(
'id' => $entry_id,
'title' => $entry_title,
'type' => $entry_type,
'amount' => $entry_amount,
'global' => $entry_global
);
}
// First time (doesn't exist yet)
if ( empty( $current_entries) ){
update_option( $entry_cat, array( $new_entries ) );
} else {
$merged_options = array_merge ( $current_entries , array ( $new_entries ) );
//Update Option
update_option( $entry_cat, $merged_options );
}
$return_data['status'] = 'success';
$return_data['mssg'] = __('New Entry Added Successfully', 'eagle-booking');
}
} else {
$return_data['status'] = 'failed';
$return_data['mssg'] = __('No ID', 'eagle-booking');
}
// Return all data to json
wp_send_json($return_data);
wp_die();
}
/**
* Update Entry [AJAX Request]
*/
public function update() {
// Check if Ajax response and get Ajax variables
if (! empty($_POST['entry_id'])) {
$entry_nonce = sanitize_text_field( $_POST['entry_nonce'] );
$entry_cat = sanitize_text_field( $_POST['entry_cat'] );
$entry_id = sanitize_text_field( $_POST['entry_id'] );
$entry_title = sanitize_text_field( $_POST['entry_title'] );
$entry_type = sanitize_text_field( $_POST['entry_type'] );
$entry_amount = sanitize_text_field( $_POST['entry_amount'] );
$entry_global = sanitize_text_field( $_POST['entry_global'] );
$entry_services = sanitize_text_field( $_POST['entry_services'] );
// $entry_fees = sanitize_text_field( $_POST['entry_fees'] );
// Check nonce
if ( !wp_verify_nonce($entry_nonce, 'nonce') ) {
$return_data['status'] = 'failed';
$return_data['mssg'] = __('Invalid Nonce', 'eagle-booking');
// // If everything is ok let's proceed to the deletion
} else {
// Existing Entries
$data = get_option($entry_cat);
// Loop the array to find the specific entry
foreach( $data as $key => $row ) {
if( $row['id'] == $entry_id ) {
// Update Entry Fields based on cat
if ( $entry_cat === 'eb_taxes' ){
// Set new values
$data[$key]['id'] = $entry_id;
$data[$key]['title'] = $entry_title;
$data[$key]['amount'] = $entry_amount;
$data[$key]['global'] = $entry_global;
$data[$key]['services'] = $entry_services;
// $data[$key]['fees'] = $entry_fees;
// break the loop
break;
} else {
// Set new values
$data[$key]['id'] = $entry_id;
$data[$key]['title'] = $entry_title;
$data[$key]['type'] = $entry_type;
$data[$key]['amount'] = $entry_amount;
$data[$key]['global'] = $entry_global;
// break the loop
break;
}
}
}
update_option($entry_cat, $data);
$return_data['status'] = 'success';
$return_data['mssg'] = __('Entry Updated Successfully ', 'eagle-booking');
}
} else {
$return_data['status'] = 'failed';
$return_data['mssg'] = __('No ID', 'eagle-booking');
}
// Return all data to json
wp_send_json($return_data);
wp_die();
}
/**
* Delete Entry [AJAX Request]f
*/
public function delete() {
// Check if Ajax response and get Ajax variables
if (! empty($_POST['id'])) {
$entry_nonce = sanitize_text_field( $_POST['nonce'] );
$entry_cat = sanitize_text_field( $_POST['cat'] );
$entry_id = sanitize_text_field( $_POST['id'] );
// Check nonce
if ( !wp_verify_nonce($entry_nonce, 'nonce') ) {
$return_data['status'] = 'failed';
$return_data['mssg'] = __('Invalid Nonce', 'eagle-booking');
// If everything is ok let's proceed to the deletion
} else {
// Existing Entries (tax or fee)
$data = get_option($entry_cat);
// Loop the array to find the specific entry
foreach( $data as $key => $row ) {
if( $row['id'] == $entry_id ){
// Dlete the array
unset( $data[$key] );
// Stop the loop
break;
}
}
update_option($entry_cat, $data);
$return_data['status'] = 'success';
$return_data['mssg'] = __('Entry Deleted Successfully ', 'eagle-booking');
}
} else {
$return_data['status'] = 'failed';
$return_data['mssg'] = __('No ID', 'eagle-booking');
}
// Return all data to json
wp_send_json($return_data);
wp_die();
}
/**
* On Load Retrive Entries
*/
public function entries( $cat = '' ) {
// Get Entries
if( $cat === 'fees' ) {
$entry_cat = 'eb_fees';
} else {
$entry_cat = 'eb_taxes';
}
$entries = get_option($entry_cat);
// echo '<pre>'; print_r($entries); echo '</pre>';
$html = '';
if ( $entries ) {
foreach( $entries as $key => $item ) {
$entry_id = !empty( $item["id"] ) ? $item["id"] : '';
$entry_title = !empty( $item["title"] ) ? $item["title"] : '';
$entry_type = !empty( $item["type"] ) ? $item["type"] : '';
$entry_amount = !empty( $item["amount"] ) ? $item["amount"] : '';
$entry_global = !empty( $item["global"] ) ? $item["global"] : '';
$entry_services = !empty( $item["services"] ) ? $item["services"] : '';
// $entry_fees = !empty( $item["fees"] ) ? $item["fees"] : '';
if ( $entry_global == true ) {
$entry_global = 'Yes';
} else {
$entry_global = 'No';
}
if ( $entry_services == true ) {
$entry_services = 'Yes';
} else {
$entry_services = 'No';
}
// if ( $entry_fees == true ) {
// $entry_fees = 'Yes';
// } else {
// $entry_fees = 'No';
// }
$html .= "<tr class='eb-entry-line' data-entry-id='$entry_id' data-cat='$entry_cat'>";
$html .= "<td class='eb-entry-title'>$entry_title</td>";
if ( $entry_cat === 'eb_fees' ) $html .= "<td class='eb-entry-type'>".str_replace('_', ' ', $entry_type)."</td>";
$html .= "<td class='eb-entry-amount'>$entry_amount</td>";
$html .= "<td class='eb-entry-global'>$entry_global</td>";
if ( $entry_cat === 'eb_taxes' ) $html .= "<td class='eb-entry-services'>$entry_services</td>";
// if ( $entry_cat === 'eb_taxes' ) $html .= "<td class='eb-entry-fees'>$entry_fees</td>";
$html .= "<td class='eb-action-buttons'>";
$html .= "<span class='eb-edit-action eb-edit-entry' data-entry-id='$entry_id' data-cat='$entry_cat'><i class='far fa-edit'></i></span>";
$html .= "<span class='eb-delete-action eb-delete-entry' data-entry-id='$entry_id' data-cat='$entry_cat'><i class='far fa-trash-alt'></i></span>";
$html .= "</td>";
$html .= "</tr>";
}
} else {
$html .= "<tr class='eb-$entry_cat-no-entry'><td colspan='5' style='text-align: center'>". __('No entries have been created yet', 'eagle-booking' )."</td></tr>";
}
return $html;
}
/**
* Render Output
*/
public function render() {
?>
<div class="eb-admin eb-wrapper">
<div class="eb-admin-dashboard">
<?php
/**
* Include the EB admin header
*
* @since 1.3.2
*/
include EB_PATH.''."core/admin/bookings/elements/admin-header.php";
?>
<div class="eb-admin-title">
<h1 class="wp-heading-inline"><?php echo __('Taxes & Fees', 'eagle-booking') ?></h1>
</div>
<div class="eb-admin-dashboard-inner">
<form method="POST" action="">
<!-- Taxes -->
<div class="eb-admin-list-group eb-admin-taxes-fees" data-cat="eb_taxes">
<h3 style="display: inline-block; margin-right: 20px; margin-bottom: 40px"><?php echo __('Taxes', 'eagle-booking') ?></h3> <button class="eb-admin-btn eb-new-entry" data-cat="eb_taxes"><i class="fas fa-plus"></i></button>
<table class="widefat striped">
<thead>
<tr>
<th class="row-title" width="30%"><?php echo __('Title', 'eagle-booking') ?></th>
<th class="row-title" width="15%"><span data-eb-tooltip="Enter a tax rate (percentage)"><?php echo __('Rate %', 'eagle-booking') ?></span></th>
<th class="row-title" width="15%"><span data-eb-tooltip="Choose if you want to apply this taX globally on all rooms or if you want to assign it under each room's price tab"><?php echo __('Global', 'eagle-booking') ?></span></th>
<th class="row-title" width="15%"><span data-eb-tooltip="Choose if you want to apply this tax on additional services price"><?php echo __('Additional Services', 'eagle-booking') ?></span></th>
<!-- <th class="row-title" width="15%"><span data-eb-tooltip="Choose if you want to apply this tax on fees price"><?php echo __('Fees', 'eagle-booking') ?></span></th> -->
<th class="row-title" width="10%"><?php echo __('Actions', 'eagle-booking') ?></th>
</tr>
</thead>
<tbody>
<?php
/**
* Print Existing Entries
*/
echo $this->entries('taxes');
?>
<tr class="eb-new-eb_taxes-line " style="display: none;">
<td>
<input id="eb_entry_title" class="" type="text" placeholder="<?php echo __('Title', 'eagle-booking') ?>">
<input id="eb_entry_cat" value="eb_taxes" type="hidden">
</td>
<td>
<input type="text" id="eb_entry_amount" laceholder="<?php echo __('Amount', 'eagle-booking') ?>">
</td>
<td>
<label class="switch">
<input type="checkbox" id="eb_entry_global">
<span class="slider round"></span>
</label>
</td>
<td>
<label class="switch">
<input type="checkbox" id="eb_entry_services">
<span class="slider round"></span>
</label>
</td>
<!-- <td>
<label class="switch">
<input type="checkbox" id="eb_entry_fees">
<span class="slider round"></span>
</label>
</td> -->
<td class="eb-action-buttons">
<span class='eb-edit-action eb-create-entry'><i class='fas fa-check'></i></span>
<span class='eb-delete-action eb-cancel-entry' data-booking-id='2'><i class='fas fa-times'></i></span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Fees -->
<div class="eb-admin-list-group eb-admin-taxes-fees" data-cat="eb_fees" style="margin-top: 40px;">
<h3 style="display: inline-block; margin-right: 20px; margin-bottom: 40px"><?php echo __('Fees', 'eagle-booking') ?></h3> <button class="eb-admin-btn eb-new-entry" data-cat="eb_fees"><i class="fas fa-plus"></i></button>
<table class="widefat striped">
<thead>
<tr>
<th class="row-title" width="30%"><?php echo __('Title', 'eagle-booking') ?></th>
<th class="row-title" width="20%"><?php echo __('Type', 'eagle-booking') ?></th>
<th class="row-title" width="20%"><span data-eb-tooltip="Enter a fee amount (fixed)"><?php echo __('Amount', 'eagle-booking') ?></span></th>
<th class="row-title" width="20%"><span data-eb-tooltip="Choose if you want to apply this fee globally on all rooms or if you want to assign it under each room's price tab"><?php echo __('Global', 'eagle-booking') ?></span></th>
<th class="row-title" width="10%"><?php echo __('Actions', 'eagle-booking') ?></th>
</tr>
</thead>
<tbody>
<?php
/**
* Print Existing Entries
*/
echo $this->entries('fees');
?>
<tr class="eb-new-eb_fees-line" style="display: none;">
<td>
<input id="eb_entry_title" value="" class="" type="text" placeholder="<?php echo __('Title', 'eagle-booking') ?>">
<input id="eb_entry_cat" value="eb_fees" type="hidden">
</td>
<td>
<select id="eb_entry_type">
<option value="per_booking" selected="selected"><?php echo __('Per Booking ', 'eagle-booking') ?></option>
<option value="per_booking_nights"><?php echo __('Per Booking Nights', 'eagle-booking') ?></option>
<option value="per_guests"><?php echo __('Per Guests', 'eagle-booking') ?></option>
<option value="per_booking_nights_guests"><?php echo __('Per Booking Nights x Guests', 'eagle-booking') ?></option>
</select>
</td>
<td>
<input type="text" id="eb_entry_amount" value="" placeholder="<?php echo __('Amount', 'eagle-booking') ?>">
</td>
<td>
<label class="switch">
<input type="checkbox" id="eb_entry_global">
<span class="slider round"></span>
</label>
</td>
<td class="eb-action-buttons">
<span class='eb-edit-action eb-create-entry'><i class='fas fa-check'></i></span>
<span class='eb-delete-action eb-cancel-entry' data-booking-id='2'><i class='fas fa-times'></i></span>
</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
</div>
</div>
<?php
}
}
new EB_ADMIN_TAXES_FEES();