436 lines
13 KiB
PHP
Raw Normal View History

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
<?php
/**
* Eagle Booking Advanced Pricing - Database Management
*
* @package EB_Advanced_Pricing
* @since 1.0.0
*/
defined('ABSPATH') || exit;
class EB_AP_Database {
private static $instance = null;
public static function instance() {
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action('init', array($this, 'check_database_version'));
}
/**
* Check database version and update if needed
*/
public function check_database_version() {
$current_version = get_option('eb_ap_db_version', '0.0.0');
$plugin_version = EB_AP_VERSION;
if (version_compare($current_version, $plugin_version, '<')) {
$this->update_database($current_version, $plugin_version);
}
}
/**
* Update database schema
*
* @param string $from_version
* @param string $to_version
*/
private function update_database($from_version, $to_version) {
global $wpdb;
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
// Create or update tables
$this->create_rates_table();
$this->create_availability_table();
$this->create_deals_table();
$this->create_restrictions_table();
// Run version-specific updates
if (version_compare($from_version, '1.0.0', '<')) {
$this->upgrade_to_1_0_0();
}
// Update database version
update_option('eb_ap_db_version', $to_version);
eb_ap_log("Database updated from version {$from_version} to {$to_version}");
}
/**
* Create rates table
*/
private function create_rates_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE " . EB_AP_TABLE_RATES . " (
id int(11) NOT NULL AUTO_INCREMENT,
room_id int(11) NOT NULL,
rate_date date NOT NULL,
base_rate decimal(10,2) NOT NULL DEFAULT 0.00,
adult_rate decimal(10,2) NOT NULL DEFAULT 0.00,
child_rate decimal(10,2) NOT NULL DEFAULT 0.00,
min_guests int(11) NOT NULL DEFAULT 1,
max_guests int(11) NOT NULL DEFAULT 10,
min_stay int(11) NOT NULL DEFAULT 1,
max_stay int(11) NOT NULL DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY room_date (room_id, rate_date),
KEY room_id (room_id),
KEY rate_date (rate_date)
) $charset_collate;";
dbDelta($sql);
}
/**
* Create availability table
*/
private function create_availability_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE " . EB_AP_TABLE_AVAILABILITY . " (
id int(11) NOT NULL AUTO_INCREMENT,
room_id int(11) NOT NULL,
availability_date date NOT NULL,
available_rooms int(11) NOT NULL DEFAULT 0,
stop_sell tinyint(1) NOT NULL DEFAULT 0,
closed_to_arrival tinyint(1) NOT NULL DEFAULT 0,
closed_to_departure tinyint(1) NOT NULL DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY room_date (room_id, availability_date),
KEY room_id (room_id),
KEY availability_date (availability_date)
) $charset_collate;";
dbDelta($sql);
}
/**
* Create deals table
*/
private function create_deals_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE " . EB_AP_TABLE_DEALS . " (
id int(11) NOT NULL AUTO_INCREMENT,
room_id int(11) NOT NULL,
deal_type varchar(50) NOT NULL,
deal_name varchar(255) NOT NULL,
discount_type varchar(20) NOT NULL,
discount_value decimal(10,2) NOT NULL,
date_from date NOT NULL,
date_to date NOT NULL,
min_stay int(11) NOT NULL DEFAULT 1,
max_stay int(11) NOT NULL DEFAULT 0,
advance_booking_days int(11) NOT NULL DEFAULT 0,
is_active tinyint(1) NOT NULL DEFAULT 1,
priority int(11) NOT NULL DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY room_id (room_id),
KEY deal_type (deal_type),
KEY date_from (date_from),
KEY date_to (date_to),
KEY is_active (is_active)
) $charset_collate;";
dbDelta($sql);
}
/**
* Create restrictions table
*/
private function create_restrictions_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE " . EB_AP_TABLE_RESTRICTIONS . " (
id int(11) NOT NULL AUTO_INCREMENT,
room_id int(11) NOT NULL,
restriction_date date NOT NULL,
restriction_type varchar(50) NOT NULL,
restriction_value text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY room_id (room_id),
KEY restriction_date (restriction_date),
KEY restriction_type (restriction_type)
) $charset_collate;";
dbDelta($sql);
}
/**
* Upgrade to version 1.0.0
*/
private function upgrade_to_1_0_0() {
// Initial setup - migrate existing Eagle Booking data if needed
$this->migrate_existing_data();
}
/**
* Migrate existing Eagle Booking data
*/
private function migrate_existing_data() {
// Get all rooms
$rooms = get_posts(array(
'post_type' => 'eagle_rooms',
'posts_per_page' => -1,
'post_status' => 'publish'
));
foreach ($rooms as $room) {
$this->migrate_room_data($room->ID);
}
eb_ap_log('Migrated existing Eagle Booking data for ' . count($rooms) . ' rooms');
}
/**
* Migrate data for a specific room
*
* @param int $room_id
*/
private function migrate_room_data($room_id) {
// Get existing room data
$base_price = get_post_meta($room_id, 'eagle_booking_mtb_room_price', true);
$quantity = get_post_meta($room_id, 'eagle_booking_mtb_room_quantity', true);
$min_guests = get_post_meta($room_id, 'eagle_booking_mtb_room_min_guests', true);
$max_guests = get_post_meta($room_id, 'eagle_booking_mtb_room_max_guests', true);
// Set default values if empty
$base_price = $base_price ? floatval($base_price) : 0;
$quantity = $quantity ? intval($quantity) : 1;
$min_guests = $min_guests ? intval($min_guests) : 1;
$max_guests = $max_guests ? intval($max_guests) : 10;
// Create default availability for the next 365 days
$start_date = new DateTime();
$end_date = new DateTime();
$end_date->add(new DateInterval('P365D'));
$period = new DatePeriod($start_date, new DateInterval('P1D'), $end_date);
foreach ($period as $date) {
$date_str = $date->format('Y-m-d');
// Set default rates
$rates = array(
'base_rate' => $base_price,
'adult_rate' => $base_price,
'child_rate' => $base_price * 0.5, // 50% for children
'min_guests' => $min_guests,
'max_guests' => $max_guests,
'min_stay' => 1,
'max_stay' => 0
);
// Set default availability
$availability = array(
'available_rooms' => $quantity,
'stop_sell' => 0,
'closed_to_arrival' => 0,
'closed_to_departure' => 0
);
// Only insert if not already exists
if (!$this->rate_exists($room_id, $date_str)) {
EB_AP_Rates::instance()->update_rates($room_id, $date_str, $rates);
}
if (!$this->availability_exists($room_id, $date_str)) {
EB_AP_Availability::instance()->update_availability($room_id, $date_str, $availability);
}
}
}
/**
* Check if rate exists for room and date
*
* @param int $room_id
* @param string $date
* @return bool
*/
private function rate_exists($room_id, $date) {
global $wpdb;
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM " . EB_AP_TABLE_RATES . " WHERE room_id = %d AND rate_date = %s",
$room_id,
$date
));
return $count > 0;
}
/**
* Check if availability exists for room and date
*
* @param int $room_id
* @param string $date
* @return bool
*/
private function availability_exists($room_id, $date) {
global $wpdb;
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM " . EB_AP_TABLE_AVAILABILITY . " WHERE room_id = %d AND availability_date = %s",
$room_id,
$date
));
return $count > 0;
}
/**
* Clean up old data
*
* @param int $days_old
*/
public function cleanup_old_data($days_old = 365) {
global $wpdb;
$cutoff_date = date('Y-m-d', strtotime("-{$days_old} days"));
// Clean old rates
$wpdb->query($wpdb->prepare(
"DELETE FROM " . EB_AP_TABLE_RATES . " WHERE rate_date < %s",
$cutoff_date
));
// Clean old availability
$wpdb->query($wpdb->prepare(
"DELETE FROM " . EB_AP_TABLE_AVAILABILITY . " WHERE availability_date < %s",
$cutoff_date
));
// Clean expired deals
$wpdb->query($wpdb->prepare(
"DELETE FROM " . EB_AP_TABLE_DEALS . " WHERE date_to < %s",
$cutoff_date
));
eb_ap_log("Cleaned up data older than {$days_old} days");
}
/**
* Backup tables
*
* @return array
*/
public function backup_tables() {
global $wpdb;
$tables = array(
EB_AP_TABLE_RATES,
EB_AP_TABLE_AVAILABILITY,
EB_AP_TABLE_DEALS,
EB_AP_TABLE_RESTRICTIONS
);
$backup_data = array();
foreach ($tables as $table) {
$data = $wpdb->get_results("SELECT * FROM {$table}", ARRAY_A);
$backup_data[basename($table)] = $data;
}
return $backup_data;
}
/**
* Get database statistics
*
* @return array
*/
public function get_statistics() {
global $wpdb;
$stats = array();
// Rates statistics
$stats['rates'] = $wpdb->get_row(
"SELECT COUNT(*) as total,
MIN(rate_date) as earliest_date,
MAX(rate_date) as latest_date,
AVG(base_rate) as avg_rate
FROM " . EB_AP_TABLE_RATES,
ARRAY_A
);
// Availability statistics
$stats['availability'] = $wpdb->get_row(
"SELECT COUNT(*) as total,
SUM(available_rooms) as total_rooms,
SUM(stop_sell) as stop_sell_days,
SUM(closed_to_arrival) as cta_days,
SUM(closed_to_departure) as ctd_days
FROM " . EB_AP_TABLE_AVAILABILITY,
ARRAY_A
);
// Deals statistics
$stats['deals'] = $wpdb->get_row(
"SELECT COUNT(*) as total,
SUM(is_active) as active_deals,
AVG(discount_value) as avg_discount
FROM " . EB_AP_TABLE_DEALS,
ARRAY_A
);
return $stats;
}
/**
* Drop all tables (for uninstall)
*/
public function drop_tables() {
global $wpdb;
$tables = array(
EB_AP_TABLE_RATES,
EB_AP_TABLE_AVAILABILITY,
EB_AP_TABLE_DEALS,
EB_AP_TABLE_RESTRICTIONS
);
foreach ($tables as $table) {
$wpdb->query("DROP TABLE IF EXISTS {$table}");
}
// Delete options
delete_option('eb_ap_db_version');
delete_option('eb_ap_activated');
// Delete all plugin options
$options = $wpdb->get_results(
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE 'eb_ap_%'"
);
foreach ($options as $option) {
delete_option($option->option_name);
}
eb_ap_log('All Eagle Booking Advanced Pricing data removed');
}
}