Files
HotelRaxa/wp-content/plugins/eagle-booking-tourist-tax/eagle-booking-tourist-tax.php
Hotel Raxa Dev 8bd12173b5 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 14:44:06 +02:00

578 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Plugin Name: Eagle Booking Tourist Tax
* Plugin URI: https://hotelraxa.com
* Description: Adds tourist tax calculation (€2.20 per person per day) to Eagle Booking system
* Version: 1.0.0
* Author: Hotel Raxa Dev Team
* Author URI: https://hotelraxa.com
* Text Domain: eb-tourist-tax
* Domain Path: /languages
* Requires at least: 5.0
* Requires PHP: 7.4
*
* 🤖 Generated with Claude Code (https://claude.ai/code)
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
// Define plugin constants
define('EB_TOURIST_TAX_VERSION', '1.0.0');
define('EB_TOURIST_TAX_URL', plugin_dir_url(__FILE__));
define('EB_TOURIST_TAX_PATH', plugin_dir_path(__FILE__));
/**
* Main Tourist Tax Plugin Class
*/
class EB_Tourist_Tax {
/**
* Tourist tax rate per person per day in EUR
*/
const TAX_RATE = 2.20;
/**
* Initialize the plugin
*/
public function __construct() {
add_action('init', array($this, 'init'));
add_action('plugins_loaded', array($this, 'load_textdomain'));
}
/**
* Initialize plugin functionality
*/
public function init() {
// Check if Eagle Booking is active
if (!class_exists('EB_CORE')) {
add_action('admin_notices', array($this, 'eagle_booking_required_notice'));
return;
}
// Initialize hooks
$this->init_hooks();
}
/**
* Initialize WordPress hooks
*/
private function init_hooks() {
// Add tourist tax to booking calculations
add_filter('eb_booking_total_price', array($this, 'add_tourist_tax_to_total'), 10, 2);
// Add tourist tax display to booking forms
add_action('eb_booking_form_after_price', array($this, 'display_tourist_tax_info'));
// Add tourist tax to checkout summary
add_action('eb_checkout_summary_after_taxes', array($this, 'display_tourist_tax_line'));
// Add tourist tax to booking confirmation
add_action('eb_booking_confirmation_details', array($this, 'display_tourist_tax_confirmation'));
// Save tourist tax data with booking
add_action('eb_booking_created', array($this, 'save_tourist_tax_data'), 10, 2);
// Add admin settings
add_action('admin_menu', array($this, 'add_admin_menu'));
// Enqueue scripts and styles
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
/**
* Calculate tourist tax for booking
*
* @param int $guests Number of guests
* @param int $nights Number of nights
* @return float Tourist tax amount
*/
public function calculate_tourist_tax($guests, $nights) {
// Apply tourist tax only to adults (children usually exempted)
$adults = max(1, $guests); // At least 1 adult
// Calculate: €2.20 × adults × nights
$tax_amount = self::TAX_RATE * $adults * $nights;
return round($tax_amount, 2);
}
/**
* Add tourist tax to booking total price
*
* @param float $total_price Current total price
* @param array $booking_data Booking information
* @return float Modified total price
*/
public function add_tourist_tax_to_total($total_price, $booking_data) {
if (!isset($booking_data['guests']) || !isset($booking_data['nights'])) {
return $total_price;
}
$tourist_tax = $this->calculate_tourist_tax(
$booking_data['guests'],
$booking_data['nights']
);
return $total_price + $tourist_tax;
}
/**
* Display tourist tax information on booking forms
*/
public function display_tourist_tax_info() {
?>
<div class="eb-tourist-tax-info">
<div class="eb-tax-notice">
<i class="fa fa-info-circle"></i>
<span class="eb-tax-text">
<?php
printf(
__('Tourist tax: €%.2f per person per day (will be added to final price)', 'eb-tourist-tax'),
self::TAX_RATE
);
?>
</span>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Update tourist tax calculation when guests or dates change
function updateTouristTax() {
var guests = parseInt($('#eb_guests, .eb-guests-input').val()) || 1;
var checkIn = $('#eb_checkin, .eb-checkin-input').val();
var checkOut = $('#eb_checkout, .eb-checkout-input').val();
if (checkIn && checkOut) {
var nights = calculateNights(checkIn, checkOut);
var touristTax = <?php echo self::TAX_RATE; ?> * guests * nights;
// Update or create tourist tax display
var $display = $('.eb-tourist-tax-amount');
if ($display.length === 0) {
$('.eb-tourist-tax-info').append('<div class="eb-tourist-tax-amount"></div>');
$display = $('.eb-tourist-tax-amount');
}
$display.html('<strong><?php _e("Tourist Tax:", "eb-tourist-tax"); ?> €' + touristTax.toFixed(2) + '</strong>');
}
}
function calculateNights(checkIn, checkOut) {
var date1 = new Date(checkIn);
var date2 = new Date(checkOut);
var timeDiff = date2.getTime() - date1.getTime();
return Math.ceil(timeDiff / (1000 * 3600 * 24));
}
// Bind to form changes
$(document).on('change', '#eb_guests, .eb-guests-input, #eb_checkin, .eb-checkin-input, #eb_checkout, .eb-checkout-input', updateTouristTax);
// Initial calculation
updateTouristTax();
});
</script>
<?php
}
/**
* Display tourist tax line in checkout summary
*/
public function display_tourist_tax_line() {
// Get current booking data from session or form
$booking_data = $this->get_current_booking_data();
if (!$booking_data) {
return;
}
$tourist_tax = $this->calculate_tourist_tax(
$booking_data['guests'],
$booking_data['nights']
);
if ($tourist_tax > 0) {
?>
<tr class="eb-tourist-tax-row">
<td class="eb-summary-label">
<?php _e('Tourist Tax', 'eb-tourist-tax'); ?>
<small>(<?php printf(__('€%.2f × %d guests × %d nights', 'eb-tourist-tax'), self::TAX_RATE, $booking_data['guests'], $booking_data['nights']); ?>)</small>
</td>
<td class="eb-summary-amount">
€<?php echo number_format($tourist_tax, 2); ?>
</td>
</tr>
<?php
}
}
/**
* Display tourist tax in booking confirmation
*/
public function display_tourist_tax_confirmation() {
global $eb_booking_id;
if (!$eb_booking_id) {
return;
}
$tourist_tax = get_post_meta($eb_booking_id, '_eb_tourist_tax_amount', true);
if ($tourist_tax && $tourist_tax > 0) {
?>
<div class="eb-confirmation-tourist-tax">
<h4><?php _e('Tourist Tax', 'eb-tourist-tax'); ?></h4>
<p>
<strong>€<?php echo number_format($tourist_tax, 2); ?></strong>
<br>
<small><?php _e('Tourist tax is included in your total booking amount.', 'eb-tourist-tax'); ?></small>
</p>
</div>
<?php
}
}
/**
* Save tourist tax data with booking
*
* @param int $booking_id Booking ID
* @param array $booking_data Booking information
*/
public function save_tourist_tax_data($booking_id, $booking_data) {
if (!isset($booking_data['guests']) || !isset($booking_data['nights'])) {
return;
}
$tourist_tax = $this->calculate_tourist_tax(
$booking_data['guests'],
$booking_data['nights']
);
// Save tourist tax data
update_post_meta($booking_id, '_eb_tourist_tax_amount', $tourist_tax);
update_post_meta($booking_id, '_eb_tourist_tax_rate', self::TAX_RATE);
update_post_meta($booking_id, '_eb_tourist_tax_guests', $booking_data['guests']);
update_post_meta($booking_id, '_eb_tourist_tax_nights', $booking_data['nights']);
}
/**
* Get current booking data from various sources
*
* @return array|false Booking data or false if not available
*/
private function get_current_booking_data() {
// Try to get from POST data (during checkout)
if (isset($_POST['eb_guests']) && isset($_POST['eb_checkin']) && isset($_POST['eb_checkout'])) {
$checkin = sanitize_text_field($_POST['eb_checkin']);
$checkout = sanitize_text_field($_POST['eb_checkout']);
$guests = intval($_POST['eb_guests']);
$checkin_date = new DateTime($checkin);
$checkout_date = new DateTime($checkout);
$nights = $checkout_date->diff($checkin_date)->days;
return array(
'guests' => $guests,
'nights' => $nights
);
}
// Try to get from session
if (isset($_SESSION['eb_booking_data'])) {
return $_SESSION['eb_booking_data'];
}
return false;
}
/**
* Add admin menu for tourist tax settings
*/
public function add_admin_menu() {
if (!class_exists('EB_CORE')) {
return;
}
add_submenu_page(
'eb_bookings',
__('Tourist Tax', 'eb-tourist-tax'),
__('Tourist Tax', 'eb-tourist-tax'),
'manage_options',
'eb-tourist-tax',
array($this, 'admin_page')
);
}
/**
* Render admin page
*/
public function admin_page() {
// Get tourist tax statistics
$stats = $this->get_tourist_tax_stats();
?>
<div class="wrap">
<h1><?php _e('Tourist Tax Management', 'eb-tourist-tax'); ?></h1>
<div class="eb-admin-content">
<div class="eb-admin-section">
<h2><?php _e('Current Configuration', 'eb-tourist-tax'); ?></h2>
<table class="form-table">
<tr>
<th scope="row"><?php _e('Tax Rate', 'eb-tourist-tax'); ?></th>
<td>
<strong>€<?php echo number_format(self::TAX_RATE, 2); ?></strong>
<?php _e('per person per day', 'eb-tourist-tax'); ?>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Application', 'eb-tourist-tax'); ?></th>
<td><?php _e('Applied to all adult guests for each night of stay', 'eb-tourist-tax'); ?></td>
</tr>
<tr>
<th scope="row"><?php _e('Status', 'eb-tourist-tax'); ?></th>
<td><span class="eb-status-active"><?php _e('Active', 'eb-tourist-tax'); ?></span></td>
</tr>
</table>
</div>
<div class="eb-admin-section">
<h2><?php _e('Statistics', 'eb-tourist-tax'); ?></h2>
<div class="eb-stats-grid">
<div class="eb-stat-box">
<h3><?php echo $stats['total_bookings']; ?></h3>
<p><?php _e('Bookings with Tourist Tax', 'eb-tourist-tax'); ?></p>
</div>
<div class="eb-stat-box">
<h3>€<?php echo number_format($stats['total_tax_collected'], 2); ?></h3>
<p><?php _e('Total Tourist Tax Collected', 'eb-tourist-tax'); ?></p>
</div>
<div class="eb-stat-box">
<h3>€<?php echo number_format($stats['average_tax_per_booking'], 2); ?></h3>
<p><?php _e('Average Tax per Booking', 'eb-tourist-tax'); ?></p>
</div>
</div>
</div>
<div class="eb-admin-section">
<h2><?php _e('Recent Bookings with Tourist Tax', 'eb-tourist-tax'); ?></h2>
<?php $this->display_recent_bookings_table(); ?>
</div>
</div>
</div>
<style>
.eb-admin-section {
background: #fff;
padding: 20px;
margin: 20px 0;
border: 1px solid #ccd0d4;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.eb-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-top: 15px;
}
.eb-stat-box {
background: #f8f9fa;
padding: 20px;
text-align: center;
border-radius: 5px;
border: 1px solid #e1e5e9;
}
.eb-stat-box h3 {
margin: 0 0 10px;
font-size: 2em;
color: #2271b1;
}
.eb-stat-box p {
margin: 0;
color: #666;
}
.eb-status-active {
color: #00a32a;
font-weight: bold;
}
</style>
<?php
}
/**
* Get tourist tax statistics
*
* @return array Statistics data
*/
private function get_tourist_tax_stats() {
global $wpdb;
// Get bookings with tourist tax
$bookings = $wpdb->get_results(
"SELECT pm.meta_value as tax_amount
FROM {$wpdb->postmeta} pm
WHERE pm.meta_key = '_eb_tourist_tax_amount'
AND pm.meta_value > 0"
);
$total_bookings = count($bookings);
$total_tax_collected = array_sum(array_column($bookings, 'tax_amount'));
$average_tax_per_booking = $total_bookings > 0 ? $total_tax_collected / $total_bookings : 0;
return array(
'total_bookings' => $total_bookings,
'total_tax_collected' => $total_tax_collected,
'average_tax_per_booking' => $average_tax_per_booking
);
}
/**
* Display recent bookings table
*/
private function display_recent_bookings_table() {
global $wpdb;
// Get recent bookings with tourist tax
$bookings = $wpdb->get_results(
"SELECT p.ID, p.post_title, p.post_date,
pm1.meta_value as tax_amount,
pm2.meta_value as guests,
pm3.meta_value as nights
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm1 ON p.ID = pm1.post_id AND pm1.meta_key = '_eb_tourist_tax_amount'
LEFT JOIN {$wpdb->postmeta} pm2 ON p.ID = pm2.post_id AND pm2.meta_key = '_eb_tourist_tax_guests'
LEFT JOIN {$wpdb->postmeta} pm3 ON p.ID = pm3.post_id AND pm3.meta_key = '_eb_tourist_tax_nights'
WHERE p.post_type = 'eagle_booking'
AND pm1.meta_value > 0
ORDER BY p.post_date DESC
LIMIT 10"
);
if (empty($bookings)) {
echo '<p>' . __('No bookings with tourist tax found.', 'eb-tourist-tax') . '</p>';
return;
}
?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php _e('Booking ID', 'eb-tourist-tax'); ?></th>
<th><?php _e('Date', 'eb-tourist-tax'); ?></th>
<th><?php _e('Guests', 'eb-tourist-tax'); ?></th>
<th><?php _e('Nights', 'eb-tourist-tax'); ?></th>
<th><?php _e('Tourist Tax', 'eb-tourist-tax'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($bookings as $booking): ?>
<tr>
<td>
<a href="<?php echo admin_url('post.php?post=' . $booking->ID . '&action=edit'); ?>">
#<?php echo $booking->ID; ?>
</a>
</td>
<td><?php echo date_i18n(get_option('date_format'), strtotime($booking->post_date)); ?></td>
<td><?php echo $booking->guests; ?></td>
<td><?php echo $booking->nights; ?></td>
<td><strong>€<?php echo number_format($booking->tax_amount, 2); ?></strong></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php
}
/**
* Enqueue frontend scripts and styles
*/
public function enqueue_frontend_scripts() {
if (!is_page() && !is_single()) {
return;
}
wp_enqueue_style(
'eb-tourist-tax-frontend',
EB_TOURIST_TAX_URL . 'assets/css/frontend.css',
array(),
EB_TOURIST_TAX_VERSION
);
}
/**
* Enqueue admin scripts and styles
*/
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'eb-tourist-tax') === false) {
return;
}
wp_enqueue_style(
'eb-tourist-tax-admin',
EB_TOURIST_TAX_URL . 'assets/css/admin.css',
array(),
EB_TOURIST_TAX_VERSION
);
}
/**
* Load plugin text domain
*/
public function load_textdomain() {
load_plugin_textdomain(
'eb-tourist-tax',
false,
dirname(plugin_basename(__FILE__)) . '/languages'
);
}
/**
* Display admin notice if Eagle Booking is not active
*/
public function eagle_booking_required_notice() {
?>
<div class="notice notice-error">
<p>
<strong><?php _e('Eagle Booking Tourist Tax', 'eb-tourist-tax'); ?></strong>
<?php _e('requires Eagle Booking plugin to be installed and activated.', 'eb-tourist-tax'); ?>
</p>
</div>
<?php
}
}
// Initialize the plugin
new EB_Tourist_Tax();
/**
* Plugin activation hook
*/
register_activation_hook(__FILE__, function() {
// Set default options
add_option('eb_tourist_tax_rate', 2.20);
add_option('eb_tourist_tax_enabled', 'yes');
// Clear any caches
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
});
/**
* Plugin deactivation hook
*/
register_deactivation_hook(__FILE__, function() {
// Clear any caches
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
});