724 lines
26 KiB
PHP
724 lines
26 KiB
PHP
<?php
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class ON_Booking_Ajax
|
|
{
|
|
|
|
public function __construct()
|
|
{
|
|
add_action('wp_ajax_on_get_slots', array($this, 'get_slots'));
|
|
add_action('wp_ajax_nopriv_on_get_slots', array($this, 'get_slots'));
|
|
|
|
add_action('wp_ajax_on_submit_booking', array($this, 'submit_booking'));
|
|
add_action('wp_ajax_nopriv_on_submit_booking', array($this, 'submit_booking'));
|
|
|
|
add_action('wp_ajax_on_get_admin_bookings', array($this, 'get_admin_bookings'));
|
|
|
|
add_action('wp_ajax_on_get_booking_details', array($this, 'get_booking_details'));
|
|
|
|
// New Actions
|
|
add_action('wp_ajax_on_delete_booking', array($this, 'delete_booking'));
|
|
add_action('wp_ajax_on_update_booking_date', array($this, 'update_booking_date'));
|
|
add_action('wp_ajax_on_update_booking_status', array($this, 'update_booking_status'));
|
|
add_action('wp_ajax_on_update_booking_notes', array($this, 'update_booking_notes'));
|
|
|
|
// Tracking
|
|
add_action('wp_ajax_on_check_tracking_status', array($this, 'check_tracking_status'));
|
|
add_action('wp_ajax_nopriv_on_check_tracking_status', array($this, 'check_tracking_status'));
|
|
|
|
// Service Management
|
|
add_action('wp_ajax_on_create_service', array($this, 'create_service'));
|
|
add_action('wp_ajax_on_update_service', array($this, 'update_service'));
|
|
add_action('wp_ajax_on_delete_service', array($this, 'delete_service'));
|
|
add_action('wp_ajax_on_toggle_service_status', array($this, 'toggle_service_status'));
|
|
add_action('wp_ajax_on_get_services', array($this, 'get_services'));
|
|
add_action('wp_ajax_nopriv_on_get_services', array($this, 'get_services'));
|
|
|
|
// Service-based slot availability
|
|
add_action('wp_ajax_on_get_slots_for_service', array($this, 'get_slots_for_service'));
|
|
add_action('wp_ajax_nopriv_on_get_slots_for_service', array($this, 'get_slots_for_service'));
|
|
|
|
// Test Email
|
|
add_action('wp_ajax_on_send_test_email', array($this, 'send_test_email'));
|
|
}
|
|
|
|
public function get_slots()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$date_str = isset($_POST['date']) ? sanitize_text_field($_POST['date']) : ''; // YYYY-MM-DD
|
|
if (!$date_str) {
|
|
wp_send_json_error(array('message' => 'Ungültiges Datum'));
|
|
}
|
|
|
|
// 1. Check blocked days
|
|
$day_of_week = date('w', strtotime($date_str)); // 0=Sun, 6=Sat
|
|
$blocked_days = get_option('on_booking_days_blocked', array());
|
|
if (!is_array($blocked_days))
|
|
$blocked_days = array();
|
|
|
|
if (in_array($day_of_week, $blocked_days)) {
|
|
wp_send_json_success(array('slots' => array())); // No slots on blocked days
|
|
return;
|
|
}
|
|
|
|
// 2. Generate Slots
|
|
$start_time = get_option('on_booking_time_start', '08:00');
|
|
$end_time = get_option('on_booking_time_end', '17:00');
|
|
$interval = (int) get_option('on_booking_time_interval', '60');
|
|
if ($interval < 15)
|
|
$interval = 60;
|
|
|
|
$slots = array();
|
|
$current = strtotime($date_str . ' ' . $start_time);
|
|
$end = strtotime($date_str . ' ' . $end_time);
|
|
|
|
$now = current_time('timestamp');
|
|
|
|
// 3. Get existing bookings
|
|
$args = array(
|
|
'post_type' => 'on_booking',
|
|
'meta_query' => array(
|
|
array(
|
|
'key' => 'on_booking_date',
|
|
'value' => $date_str,
|
|
),
|
|
),
|
|
'posts_per_page' => -1,
|
|
'fields' => 'ids',
|
|
);
|
|
$existing_bookings_query = new WP_Query($args);
|
|
$booked_times = array();
|
|
|
|
if ($existing_bookings_query->have_posts()) {
|
|
foreach ($existing_bookings_query->posts as $post_id) {
|
|
$time = get_post_meta($post_id, 'on_booking_time', true);
|
|
if ($time) {
|
|
$booked_times[] = $time;
|
|
}
|
|
}
|
|
}
|
|
|
|
while ($current < $end) {
|
|
$time_label = date('H:i', $current);
|
|
|
|
// Check past time if today
|
|
if ($current < $now) {
|
|
$available = false;
|
|
} else {
|
|
$available = !in_array($time_label, $booked_times);
|
|
}
|
|
|
|
$slots[] = array(
|
|
'time' => $time_label,
|
|
'available' => $available,
|
|
);
|
|
|
|
$current = strtotime('+' . $interval . ' minutes', $current);
|
|
}
|
|
|
|
wp_send_json_success(array('slots' => $slots));
|
|
}
|
|
|
|
public function submit_booking()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
// Detect simple mode
|
|
$is_simple_mode = !empty($_POST['simple_mode']);
|
|
|
|
// Sanitization - common fields
|
|
$name = sanitize_text_field($_POST['user_name']);
|
|
$phone = sanitize_text_field($_POST['user_phone']);
|
|
$email = sanitize_email($_POST['user_email']);
|
|
$brand = isset($_POST['brand']) ? sanitize_text_field($_POST['brand']) : '';
|
|
$year = isset($_POST['year']) ? sanitize_text_field($_POST['year']) : '';
|
|
|
|
if (!$name || !$email) {
|
|
wp_send_json_error(array('message' => 'Bitte alle Pflichtfelder ausfüllen.'));
|
|
}
|
|
|
|
$service_id = 0; // Default for simple mode
|
|
$other_desc = ''; // Default for simple mode
|
|
$customer_request = ''; // Default for normal mode
|
|
|
|
if ($is_simple_mode) {
|
|
// Simple mode: no service/date/time required
|
|
$customer_request = sanitize_textarea_field($_POST['customer_request']);
|
|
if (!$customer_request) {
|
|
wp_send_json_error(array('message' => 'Bitte beschreibe, was gemacht werden soll.'));
|
|
}
|
|
|
|
$date = date('Y-m-d');
|
|
$time = date('H:i');
|
|
$service_name = 'Offene Anfrage';
|
|
$service_duration = 0;
|
|
|
|
$post_title = sprintf('Anfrage - %s (%s)', $date, $name);
|
|
$content = "Kundenwunsch: $customer_request\n";
|
|
if ($brand) {
|
|
$content .= "Fahrzeug: $brand";
|
|
if ($year)
|
|
$content .= " ($year)";
|
|
$content .= "\n";
|
|
}
|
|
$content .= "\nKontakt:\nName: $name\nTel: $phone\nEmail: $email";
|
|
} else {
|
|
// Normal mode: full booking flow
|
|
$date = sanitize_text_field($_POST['selected_date']);
|
|
$time = sanitize_text_field($_POST['selected_time']);
|
|
$service_id = isset($_POST['service_id']) ? intval($_POST['service_id']) : 0;
|
|
$service_duration = isset($_POST['service_duration']) ? intval($_POST['service_duration']) : 30;
|
|
$other_desc = isset($_POST['other_service_desc']) ? sanitize_textarea_field($_POST['other_service_desc']) : '';
|
|
|
|
if (!$date || !$time || !$service_id) {
|
|
wp_send_json_error(array('message' => 'Bitte alle Pflichtfelder ausfüllen.'));
|
|
}
|
|
|
|
$service = ON_Service_Manager::get_service($service_id);
|
|
$service_name = $service ? $service['name'] : 'Unbekannt';
|
|
|
|
$post_title = sprintf('%s - %s (%s)', $date, $time, $name);
|
|
$content = "Fahrzeug: $brand ($year)\nService: $service_name\n";
|
|
if ($other_desc) {
|
|
$content .= "Beschreibung: $other_desc\n";
|
|
}
|
|
$content .= "\nKontakt:\nName: $name\nTel: $phone\nEmail: $email";
|
|
}
|
|
|
|
$post_data = array(
|
|
'post_title' => $post_title,
|
|
'post_content' => $content,
|
|
'post_status' => 'publish',
|
|
'post_type' => 'on_booking',
|
|
);
|
|
|
|
$post_id = wp_insert_post($post_data);
|
|
|
|
if (is_wp_error($post_id)) {
|
|
wp_send_json_error(array('message' => 'Fehler beim Speichern.'));
|
|
}
|
|
|
|
// Save Meta
|
|
update_post_meta($post_id, 'on_booking_date', $date);
|
|
update_post_meta($post_id, 'on_booking_time', $time);
|
|
update_post_meta($post_id, 'on_booking_email', $email);
|
|
update_post_meta($post_id, 'on_booking_service_name', $service_name);
|
|
update_post_meta($post_id, 'on_booking_service_duration', $service_duration);
|
|
update_post_meta($post_id, 'on_booking_phone', $phone);
|
|
update_post_meta($post_id, 'on_booking_brand', $brand);
|
|
if ($service_id) { // Only save service_id if it's a normal booking
|
|
update_post_meta($post_id, 'on_booking_service_id', $service_id);
|
|
}
|
|
if (!empty($customer_request)) {
|
|
update_post_meta($post_id, 'on_booking_customer_request', $customer_request);
|
|
}
|
|
|
|
|
|
// Generate Tracking ID
|
|
$tracking_id = strtoupper(substr(md5(uniqid($post_id, true)), 0, 8));
|
|
update_post_meta($post_id, 'on_booking_tracking_id', $tracking_id);
|
|
// Set default status if not set
|
|
update_post_meta($post_id, 'on_booking_status', 'waiting');
|
|
|
|
// Send Email Confirmation FIRST (before file upload to avoid timeout issues)
|
|
ON_Email_Manager::queue_booking_confirmation($post_id);
|
|
|
|
// Handle File Upload (after customer email, so it always fires)
|
|
$upload_warning = '';
|
|
$attachment_file_path = '';
|
|
if (!empty($_FILES['vehicle_doc']['name'])) {
|
|
// Check file size (max 10MB)
|
|
$max_size = 10 * 1024 * 1024; // 10MB
|
|
if ($_FILES['vehicle_doc']['size'] > $max_size) {
|
|
$upload_warning = 'Das Bild ist zu groß (max. 10 MB). Die Buchung wurde trotzdem gespeichert.';
|
|
} elseif ($_FILES['vehicle_doc']['error'] !== UPLOAD_ERR_OK) {
|
|
$upload_warning = 'Fehler beim Hochladen des Bildes. Die Buchung wurde trotzdem gespeichert.';
|
|
} else {
|
|
require_once(ABSPATH . 'wp-admin/includes/image.php');
|
|
require_once(ABSPATH . 'wp-admin/includes/file.php');
|
|
require_once(ABSPATH . 'wp-admin/includes/media.php');
|
|
|
|
$attachment_id = media_handle_upload('vehicle_doc', $post_id);
|
|
if (is_wp_error($attachment_id)) {
|
|
$upload_warning = 'Das Bild konnte nicht gespeichert werden. Die Buchung wurde trotzdem erstellt.';
|
|
} else {
|
|
$attachment_file_path = get_attached_file($attachment_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Send admin notification (after upload, so attachment can be included)
|
|
try {
|
|
ON_Email_Manager::send_admin_notification(
|
|
$post_id,
|
|
$name,
|
|
$email,
|
|
$date,
|
|
$time,
|
|
$service_name,
|
|
$tracking_id,
|
|
$attachment_file_path
|
|
);
|
|
} catch (\Exception $e) {
|
|
// Don't crash the booking if admin email fails
|
|
error_log('ON Booking: Admin notification failed - ' . $e->getMessage());
|
|
}
|
|
|
|
$response = array(
|
|
'message' => 'Buchung erfolgreich! Wir melden uns.',
|
|
'tracking_id' => $tracking_id
|
|
);
|
|
if ($upload_warning) {
|
|
$response['upload_warning'] = $upload_warning;
|
|
}
|
|
|
|
wp_send_json_success($response);
|
|
}
|
|
public function get_admin_bookings()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$args = array(
|
|
'post_type' => 'on_booking',
|
|
'posts_per_page' => -1,
|
|
'post_status' => array('publish', 'pending', 'future', 'draft', 'private'),
|
|
);
|
|
|
|
$query = new WP_Query($args);
|
|
$events = array();
|
|
|
|
foreach ($query->posts as $post) {
|
|
$date = get_post_meta($post->ID, 'on_booking_date', true); // YYYY-MM-DD
|
|
$time = get_post_meta($post->ID, 'on_booking_time', true); // HH:MM
|
|
|
|
if ($date && $time) {
|
|
$start_dt = $date . 'T' . $time . ':00';
|
|
$end_dt = date('Y-m-d\TH:i:s', strtotime($start_dt) + 3600); // 1hr default length for visual
|
|
|
|
$events[] = array(
|
|
'id' => $post->ID,
|
|
'title' => $post->post_title,
|
|
'start' => $start_dt,
|
|
'end' => $end_dt,
|
|
'backgroundColor' => '#0061ff',
|
|
'borderColor' => '#0061ff',
|
|
);
|
|
}
|
|
}
|
|
|
|
wp_send_json($events);
|
|
}
|
|
|
|
public function get_booking_details()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
|
|
$post = get_post($post_id);
|
|
|
|
if (!$post || $post->post_type !== 'on_booking') {
|
|
wp_send_json_error(array('message' => 'Buchung nicht gefunden.'));
|
|
}
|
|
|
|
$content = wpautop($post->post_content);
|
|
|
|
// Check for attachments
|
|
$attachments = get_children(array(
|
|
'post_parent' => $post->ID,
|
|
'post_type' => 'attachment',
|
|
));
|
|
|
|
if ($attachments) {
|
|
$content .= '<hr><strong>Angehängte Dateien:</strong><br>';
|
|
foreach ($attachments as $att) {
|
|
$url = wp_get_attachment_url($att->ID);
|
|
$content .= '<a href="' . $url . '" target="_blank" style="color:#0061ff;">' . basename($url) . '</a><br>';
|
|
}
|
|
}
|
|
|
|
// Tracking ID
|
|
$tracking_id = get_post_meta($post->ID, 'on_booking_tracking_id', true);
|
|
if ($tracking_id) {
|
|
$content .= '<hr><strong>Auftragsnummer:</strong> <span style="font-family:monospace; background:#eee; padding:2px 5px;">' . esc_html($tracking_id) . '</span><br>';
|
|
}
|
|
|
|
// Return meta for edit functionality
|
|
$date = get_post_meta($post->ID, 'on_booking_date', true);
|
|
$time = get_post_meta($post->ID, 'on_booking_time', true);
|
|
$notes = get_post_meta($post->ID, 'on_booking_notes', true);
|
|
|
|
wp_send_json_success(array(
|
|
'id' => $post->ID,
|
|
'title' => $post->post_title,
|
|
'content' => $content,
|
|
'date' => $date,
|
|
'time' => $time,
|
|
'notes' => $notes
|
|
));
|
|
}
|
|
|
|
public function delete_booking()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
|
|
|
|
if (!$post_id || get_post_type($post_id) !== 'on_booking') {
|
|
wp_send_json_error(array('message' => 'Ungültige Buchungs-ID.'));
|
|
}
|
|
|
|
$deleted = wp_trash_post($post_id); // Move to trash
|
|
|
|
if ($deleted) {
|
|
wp_send_json_success(array('message' => 'Buchung gelöscht.'));
|
|
} else {
|
|
wp_send_json_error(array('message' => 'Fehler beim Löschen.'));
|
|
}
|
|
}
|
|
|
|
public function update_booking_date()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
|
|
$new_date = isset($_POST['new_date']) ? sanitize_text_field($_POST['new_date']) : '';
|
|
$new_time = isset($_POST['new_time']) ? sanitize_text_field($_POST['new_time']) : '';
|
|
|
|
if (!$post_id || !$new_date) {
|
|
wp_send_json_error(array('message' => 'Fehlende Daten.'));
|
|
}
|
|
|
|
// Update Meta
|
|
update_post_meta($post_id, 'on_booking_date', $new_date);
|
|
if ($new_time) {
|
|
update_post_meta($post_id, 'on_booking_time', $new_time);
|
|
}
|
|
|
|
// Ideally update post title also to reflect new time?
|
|
// Let's do it if we have both
|
|
if ($new_time) {
|
|
// Fetch post to get original name part
|
|
$post = get_post($post_id);
|
|
// Try to preserve name? Format is "YYYY-MM-DD - HH:MM (Name)"
|
|
// Regex or just overwrite? Let's just update date/time in title if format matches or just leave title alone as it's secondary.
|
|
// But for clarity in list view, updating is good.
|
|
// Simplistic approach: just update title with new timestamp + existing name extracted?
|
|
// Too complex to parse reliably. Let's just update meta. User can see new time in calendar.
|
|
}
|
|
|
|
wp_send_json_success(array('message' => 'Buchung verschoben.'));
|
|
}
|
|
|
|
public function update_booking_status()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
|
|
$status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : '';
|
|
|
|
if (!$post_id || !$status) {
|
|
wp_send_json_error(array('message' => 'Fehlerhafte Daten.'));
|
|
}
|
|
|
|
update_post_meta($post_id, 'on_booking_status', $status);
|
|
update_post_meta($post_id, 'on_booking_status', $status);
|
|
wp_send_json_success(array('message' => 'Status aktualisiert.'));
|
|
}
|
|
|
|
public function update_booking_notes()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
|
|
// Allow safe HTML tags for formatting (bold, italic, lists, paragraphs, line breaks)
|
|
$notes = isset($_POST['notes']) ? wp_kses_post($_POST['notes']) : '';
|
|
|
|
if (!$post_id) {
|
|
wp_send_json_error(array('message' => 'Fehlerhafte ID.'));
|
|
}
|
|
|
|
update_post_meta($post_id, 'on_booking_notes', $notes);
|
|
wp_send_json_success(array('message' => 'Notizen gespeichert.'));
|
|
}
|
|
|
|
public function check_tracking_status()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$tracking_id = isset($_POST['tracking_id']) ? sanitize_text_field($_POST['tracking_id']) : '';
|
|
|
|
if (!$tracking_id) {
|
|
wp_send_json_error(array('message' => 'Bitte ID eingeben.'));
|
|
}
|
|
|
|
$args = array(
|
|
'post_type' => 'on_booking',
|
|
'meta_key' => 'on_booking_tracking_id',
|
|
'meta_value' => $tracking_id,
|
|
'posts_per_page' => 1,
|
|
'post_status' => array('publish', 'pending', 'future', 'private')
|
|
);
|
|
|
|
$query = new WP_Query($args);
|
|
|
|
if ($query->have_posts()) {
|
|
$query->the_post();
|
|
$post_id = get_the_ID();
|
|
|
|
$status = get_post_meta($post_id, 'on_booking_status', true);
|
|
$date = get_post_meta($post_id, 'on_booking_date', true);
|
|
$time = get_post_meta($post_id, 'on_booking_time', true);
|
|
$notes = get_post_meta($post_id, 'on_booking_notes', true);
|
|
|
|
// Labels
|
|
$status_labels = array(
|
|
'waiting' => 'Warten',
|
|
'in_progress' => 'In Bearbeitung',
|
|
'done' => 'Abholbereit'
|
|
);
|
|
$status_text = isset($status_labels[$status]) ? $status_labels[$status] : ucfirst($status);
|
|
|
|
wp_send_json_success(array(
|
|
'status' => $status_text,
|
|
'date' => $date,
|
|
'time' => $time,
|
|
'notes' => wpautop($notes) // Convert line breaks to <p> and <br> tags
|
|
));
|
|
} else {
|
|
wp_send_json_error(array('message' => 'Diese Nummer wurde nicht gefunden.'));
|
|
}
|
|
}
|
|
|
|
// =====================
|
|
// SERVICE MANAGEMENT
|
|
// =====================
|
|
|
|
public function get_services()
|
|
{
|
|
$services = ON_Service_Manager::get_active_services();
|
|
wp_send_json_success(array('services' => $services));
|
|
}
|
|
|
|
public function create_service()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : '';
|
|
$duration = isset($_POST['duration']) ? intval($_POST['duration']) : 30;
|
|
|
|
if (empty($name)) {
|
|
wp_send_json_error(array('message' => 'Service Name ist erforderlich.'));
|
|
}
|
|
|
|
// Get max order for sorting
|
|
$services = ON_Service_Manager::get_all_services();
|
|
$max_order = 0;
|
|
foreach ($services as $s) {
|
|
$order = get_post_meta($s['id'], 'service_order', true);
|
|
if ($order > $max_order) {
|
|
$max_order = $order;
|
|
}
|
|
}
|
|
|
|
$post_id = wp_insert_post(array(
|
|
'post_type' => 'on_service',
|
|
'post_title' => $name,
|
|
'post_status' => 'publish',
|
|
));
|
|
|
|
if (is_wp_error($post_id)) {
|
|
wp_send_json_error(array('message' => 'Fehler beim Erstellen des Services.'));
|
|
}
|
|
|
|
update_post_meta($post_id, 'service_duration', $duration);
|
|
update_post_meta($post_id, 'service_active', 1);
|
|
update_post_meta($post_id, 'service_order', $max_order + 1);
|
|
|
|
wp_send_json_success(array('message' => 'Service erstellt.', 'id' => $post_id));
|
|
}
|
|
|
|
public function update_service()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$service_id = isset($_POST['service_id']) ? intval($_POST['service_id']) : 0;
|
|
$name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : '';
|
|
$duration = isset($_POST['duration']) ? intval($_POST['duration']) : 30;
|
|
|
|
if (!$service_id || empty($name)) {
|
|
wp_send_json_error(array('message' => 'Ungültige Daten.'));
|
|
}
|
|
|
|
wp_update_post(array(
|
|
'ID' => $service_id,
|
|
'post_title' => $name,
|
|
));
|
|
|
|
update_post_meta($service_id, 'service_duration', $duration);
|
|
|
|
wp_send_json_success(array('message' => 'Service aktualisiert.'));
|
|
}
|
|
|
|
public function delete_service()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$service_id = isset($_POST['service_id']) ? intval($_POST['service_id']) : 0;
|
|
|
|
if (!$service_id) {
|
|
wp_send_json_error(array('message' => 'Ungültige ID.'));
|
|
}
|
|
|
|
$deleted = wp_delete_post($service_id, true);
|
|
|
|
if ($deleted) {
|
|
wp_send_json_success(array('message' => 'Service gelöscht.'));
|
|
} else {
|
|
wp_send_json_error(array('message' => 'Fehler beim Löschen.'));
|
|
}
|
|
}
|
|
|
|
public function toggle_service_status()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$service_id = isset($_POST['service_id']) ? intval($_POST['service_id']) : 0;
|
|
|
|
if (!$service_id) {
|
|
wp_send_json_error(array('message' => 'Ungültige ID.'));
|
|
}
|
|
|
|
$current_status = get_post_meta($service_id, 'service_active', true);
|
|
$new_status = $current_status == 1 ? 0 : 1;
|
|
|
|
update_post_meta($service_id, 'service_active', $new_status);
|
|
|
|
wp_send_json_success(array('message' => 'Status aktualisiert.', 'active' => $new_status));
|
|
}
|
|
|
|
public function get_slots_for_service()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
$service_id = isset($_POST['service_id']) ? intval($_POST['service_id']) : 0;
|
|
$date = isset($_POST['date']) ? sanitize_text_field($_POST['date']) : '';
|
|
|
|
if (!$service_id || empty($date)) {
|
|
wp_send_json_error(array('message' => 'Ungültige Daten.'));
|
|
}
|
|
|
|
// Get service duration
|
|
$service = ON_Service_Manager::get_service($service_id);
|
|
if (!$service) {
|
|
wp_send_json_error(array('message' => 'Service nicht gefunden.'));
|
|
}
|
|
|
|
$duration = $service['duration'];
|
|
|
|
// Get time settings
|
|
$start_time = get_option('on_booking_start_time', '08:00');
|
|
$end_time = get_option('on_booking_end_time', '17:00');
|
|
|
|
// Generate all possible slots based on service duration
|
|
$slots = array();
|
|
$start_minutes = $this->time_to_minutes($start_time);
|
|
$end_minutes = $this->time_to_minutes($end_time);
|
|
|
|
$current = $start_minutes;
|
|
while ($current + $duration <= $end_minutes) {
|
|
$slots[] = $this->minutes_to_time($current);
|
|
$current += $duration;
|
|
}
|
|
|
|
// Get existing bookings for this date
|
|
$existing_bookings = new WP_Query(array(
|
|
'post_type' => 'on_booking',
|
|
'posts_per_page' => -1,
|
|
'post_status' => 'publish',
|
|
'meta_query' => array(
|
|
array(
|
|
'key' => 'on_booking_date',
|
|
'value' => $date,
|
|
'compare' => '='
|
|
)
|
|
)
|
|
));
|
|
|
|
$booked_ranges = array();
|
|
if ($existing_bookings->have_posts()) {
|
|
while ($existing_bookings->have_posts()) {
|
|
$existing_bookings->the_post();
|
|
$booking_time = get_post_meta(get_the_ID(), 'on_booking_time', true);
|
|
$booking_duration = get_post_meta(get_the_ID(), 'on_booking_service_duration', true);
|
|
if (!$booking_duration) {
|
|
$booking_duration = 30; // Default fallback
|
|
}
|
|
|
|
$booking_start = $this->time_to_minutes($booking_time);
|
|
$booking_end = $booking_start + intval($booking_duration);
|
|
|
|
$booked_ranges[] = array('start' => $booking_start, 'end' => $booking_end);
|
|
}
|
|
wp_reset_postdata();
|
|
}
|
|
|
|
// Filter available slots (check for overlap)
|
|
$available_slots = array();
|
|
foreach ($slots as $slot) {
|
|
$slot_start = $this->time_to_minutes($slot);
|
|
$slot_end = $slot_start + $duration;
|
|
|
|
$is_available = true;
|
|
foreach ($booked_ranges as $booked) {
|
|
// Check overlap: new_start < existing_end AND new_end > existing_start
|
|
if ($slot_start < $booked['end'] && $slot_end > $booked['start']) {
|
|
$is_available = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($is_available) {
|
|
$available_slots[] = $slot;
|
|
}
|
|
}
|
|
|
|
wp_send_json_success(array('slots' => $available_slots, 'duration' => $duration));
|
|
}
|
|
|
|
private function time_to_minutes($time)
|
|
{
|
|
$parts = explode(':', $time);
|
|
return intval($parts[0]) * 60 + intval($parts[1]);
|
|
}
|
|
|
|
private function minutes_to_time($minutes)
|
|
{
|
|
$hours = floor($minutes / 60);
|
|
$mins = $minutes % 60;
|
|
return sprintf('%02d:%02d', $hours, $mins);
|
|
}
|
|
|
|
public function send_test_email()
|
|
{
|
|
check_ajax_referer('on_booking_nonce', 'nonce');
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error(array('message' => 'Keine Berechtigung.'));
|
|
}
|
|
|
|
$email = isset($_POST['test_email']) ? sanitize_email($_POST['test_email']) : '';
|
|
|
|
if (!$email || !is_email($email)) {
|
|
wp_send_json_error(array('message' => 'Bitte eine gültige E-Mail eingeben.'));
|
|
}
|
|
|
|
$result = ON_Email_Manager::send_test_email($email);
|
|
|
|
if ($result === true) {
|
|
wp_send_json_success(array('message' => 'Test E-Mail wurde gesendet.'));
|
|
} else {
|
|
// Result contains error message string
|
|
wp_send_json_error(array('message' => $result));
|
|
}
|
|
}
|
|
}
|