🏨 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>
436 lines
13 KiB
PHP
436 lines
13 KiB
PHP
<?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');
|
|
}
|
|
} |