USER
please fix this codes(<?php
// public/orders/edit_order.php
// Enable error reporting for debugging (disable in production)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Start output buffering to prevent "headers already sent" errors
ob_start();
// Include necessary files
require_once __DIR__ . '/../../includes/auth.php';
require_once __DIR__ . '/../../includes/db_connect.php';
require_once __DIR__ . '/../../includes/functions.php'; // Ensure sanitize_input() is defined
// Check if sanitize_input() exists
if (!function_exists('sanitize_input')) {
die("Error: sanitize_input() function is not defined.");
}
// Initialize success and error variables
$success = '';
$error = '';
// Initialize $deleted_existing_item_ids as an empty array to prevent undefined variable warnings
$deleted_existing_item_ids = [];
// Retrieve and sanitize the order ID from GET parameters
$order_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
// Redirect if no valid order ID is provided
if ($order_id <= 0) {
header("Location: view_orders.php?error=Invalid%20Order%20ID");
exit();
}
// Fetch order details along with customer information and is_paid status
$order_sql = "SELECT o.*, c.name AS customer_name, c.contact AS customer_contact, c.delivery_address
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.id = ? LIMIT 1";
$order_stmt = $conn->prepare($order_sql);
if (!$order_stmt) {
error_log("Prepare statement failed: " . $conn->error);
die("An unexpected error occurred. Please try again later.");
}
$order_stmt->bind_param("i", $order_id);
$order_stmt->execute();
$order_result = $order_stmt->get_result();
if ($order_result->num_rows != 1) {
header("Location: view_orders.php?error=Order%20Not%20Found");
exit();
}
$order = $order_result->fetch_assoc();
$order_stmt->close();
// Define $pickup variable
$pickup = intval($order['pickup']);
// Fetch existing order items
$order_items_sql = "SELECT oi.*, p.name AS product_name, p.size, p.price
FROM order_items oi
JOIN products p ON oi.product_id = p.id
WHERE oi.order_id = ?";
$order_items_stmt = $conn->prepare($order_items_sql);
if (!$order_items_stmt) {
error_log("Prepare statement failed: " . $conn->error);
die("An unexpected error occurred. Please try again later.");
}
$order_items_stmt->bind_param("i", $order_id);
$order_items_stmt->execute();
$order_items_result = $order_items_stmt->get_result();
$order_items = [];
while ($item = $order_items_result->fetch_assoc()) {
$order_items[] = $item;
}
$order_items_stmt->close();
// Fetch products for selection
$products_sql = "SELECT * FROM products ORDER BY name ASC";
$products_result = $conn->query($products_sql);
if (!$products_result) {
error_log("Query failed: " . $conn->error);
die("An unexpected error occurred. Please try again later.");
}
$products = $products_result->fetch_all(MYSQLI_ASSOC);
// Handle form submission for updating the order
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Retrieve and sanitize form inputs
$customer_name = sanitize_input($_POST['customer_name'] ?? '');
$contact = sanitize_input($_POST['contact'] ?? '');
$delivery_address = sanitize_input($_POST['delivery_address'] ?? '');
$status = sanitize_input($_POST['status'] ?? '');
$priority = sanitize_input($_POST['priority'] ?? '');
$delivery_datetime_input = $_POST['delivery_datetime'] ?? '';
$delivery_date_input = $_POST['delivery_date'] ?? '';
// New fields based on database schema
$delivery_fee = isset($_POST['delivery_fee']) && is_numeric($_POST['delivery_fee']) ? floatval($_POST['delivery_fee']) : 0.00;
$free_shipping = isset($_POST['free_shipping']) ? 1 : 0;
$is_paid = isset($_POST['is_paid']) ? 1 : 0; // New field
// If free shipping is selected, set delivery_fee to 0.00
if ($free_shipping) {
$delivery_fee = 0.00;
}
// Handle existing order items
$existing_item_ids = isset($_POST['existing_item_id']) ? $_POST['existing_item_id'] : [];
$product_ids = isset($_POST['product_id']) ? $_POST['product_id'] : [];
$quantities = isset($_POST['quantity']) ? $_POST['quantity'] : [];
$packaging_preferences = isset($_POST['packaging_preferences']) ? $_POST['packaging_preferences'] : [];
$discount_percentages = isset($_POST['discount_percentage']) ? $_POST['discount_percentage'] : [];
$discount_reasons = isset($_POST['discount_reason']) ? $_POST['discount_reason'] : [];
// Handle new order items
$new_product_ids = isset($_POST['new_product_id']) ? $_POST['new_product_id'] : [];
$new_quantities = isset($_POST['new_quantity']) ? $_POST['new_quantity'] : [];
$new_packaging_preferences = isset($_POST['new_packaging_preferences']) ? $_POST['new_packaging_preferences'] : [];
$new_discount_percentages = isset($_POST['new_discount_percentage']) ? $_POST['new_discount_percentage'] : [];
$new_discount_reasons = isset($_POST['new_discount_reason']) ? $_POST['new_discount_reason'] : [];
// Handle deleted existing order items
$deleted_existing_item_ids = isset($_POST['deleted_existing_item_ids']) && !empty($_POST['deleted_existing_item_ids']) ? explode(',', $_POST['deleted_existing_item_ids']) : [];
// Ensure $deleted_existing_item_ids is always an array
if (!is_array($deleted_existing_item_ids)) {
$deleted_existing_item_ids = [];
}
// Define arrays to hold data for validation
$errors = [];
// Basic validation
if (empty($customer_name)) {
$errors[] = "Customer name is required.";
}
if (empty($status)) {
$errors[] = "Order status is required.";
}
if (empty($priority)) {
$errors[] = "Order priority is required.";
}
if (empty($delivery_datetime_input) && empty($delivery_date_input)) {
$errors[] = "Either Delivery Date and Time or Delivery Date is required.";
}
if (empty($existing_item_ids) && empty($new_product_ids)) {
$errors[] = "At least one product must be selected.";
}
// Validate existing order items
foreach ($existing_item_ids as $index => $item_id) {
if (in_array($item_id, $deleted_existing_item_ids)) {
continue; // Skip validation for deleted items
}
if (empty($product_ids[$index])) {
$errors[] = "Product selection is required for all existing items.";
break;
}
if (!isset($quantities[$index]) || intval($quantities[$index]) <= 0) {
$errors[] = "Quantity must be at least 1 for all existing items.";
break;
}
if (isset($discount_percentages[$index]) && $discount_percentages[$index] !== '' && (floatval($discount_percentages[$index]) < 0 || floatval($discount_percentages[$index]) > 100)) {
$errors[] = "Discount percentage must be between 0 and 100.";
break;
}
}
// Validate new order items
foreach ($new_product_ids as $index => $pid) {
if (!empty($pid)) {
if (!isset($new_quantities[$index]) || intval($new_quantities[$index]) <= 0) {
$errors[] = "Quantity must be at least 1 for all new items.";
break;
}
if (isset($new_discount_percentages[$index]) && $new_discount_percentages[$index] !== '' && (floatval($new_discount_percentages[$index]) < 0 || floatval($new_discount_percentages[$index]) > 100)) {
$errors[] = "Discount percentage must be between 0 and 100 for all new items.";
break;
}
}
}
// Validate delivery_datetime
if (!empty($delivery_datetime_input)) {
// Convert from 'Y-m-d\TH:i' to 'Y-m-d H:i:s'
$delivery_datetime = sanitize_input(str_replace('T', ' ', $delivery_datetime_input) . ':00');
if (!preg_match("/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/", $delivery_datetime)) {
$errors[] = "Invalid delivery date and time format.";
} elseif (strtotime($delivery_datetime) < strtotime(date('Y-m-d H:i:s'))) {
$errors[] = "Delivery date and time cannot be in the past.";
}
} else {
$delivery_datetime = null;
}
// Validate delivery_date
if (!empty($delivery_date_input)) {
$delivery_date = sanitize_input($delivery_date_input);
if (!preg_match("/^\d{4}-\d{2}-\d{2}$/", $delivery_date)) {
$errors[] = "Invalid delivery date format.";
} elseif (strtotime($delivery_date) < strtotime(date('Y-m-d'))) {
$errors[] = "Delivery date cannot be in the past.";
}
} else {
$delivery_date = null;
}
// Validate delivery_fee if not free shipping
if (!$free_shipping) {
if (!isset($_POST['delivery_fee']) || !is_numeric($_POST['delivery_fee']) || floatval($_POST['delivery_fee']) < 0) {
$errors[] = "Valid delivery fee is required.";
}
}
// If there are no validation errors, proceed with database updates
if (empty($errors)) {
// Proceed with database updates
// Start transaction
$conn->begin_transaction();
try {
// Update customer details
$stmt = $conn->prepare("UPDATE customers SET name = ?, contact = ?, delivery_address = ? WHERE id = ?");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$stmt->bind_param("sssi", $customer_name, $contact, $delivery_address, $order['customer_id']);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
$stmt->close();
// Update orders table with new fields including is_paid and pickup
$stmt = $conn->prepare("UPDATE orders SET status = ?, priority = ?, delivery_datetime = ?, delivery_date = ?, delivery_fee = ?, free_shipping = ?, is_paid = ?, pickup = ? WHERE id = ?");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$stmt->bind_param("ssssdiiii", $status, $priority, $delivery_datetime, $delivery_date, $delivery_fee, $free_shipping, $is_paid, $pickup, $order_id);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
$stmt->close();
// Delete removed existing order items
if (!empty($deleted_existing_item_ids)) {
// Prepare the statement with placeholders
$placeholders = implode(',', array_fill(0, count($deleted_existing_item_ids), '?'));
$types = str_repeat('i', count($deleted_existing_item_ids));
$delete_sql = "DELETE FROM order_items WHERE id IN ($placeholders)";
$delete_stmt = $conn->prepare($delete_sql);
if (!$delete_stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
// Dynamically bind parameters
// Using argument unpacking (PHP 5.6+)
$delete_stmt->bind_param($types, ...$deleted_existing_item_ids);
if (!$delete_stmt->execute()) {
throw new Exception("Execute failed: " . $delete_stmt->error);
}
$delete_stmt->close();
}
// Update existing order items
foreach ($existing_item_ids as $index => $item_id) {
if (in_array($item_id, $deleted_existing_item_ids)) {
continue; // Skip deleted items
}
$item_id = intval($item_id);
$pid = intval($product_ids[$index]);
$qty = intval($quantities[$index]);
$pack_pref = sanitize_input($packaging_preferences[$index] ?? '');
$discount_pct = isset($discount_percentages[$index]) && $discount_percentages[$index] !== '' ? floatval($discount_percentages[$index]) : 0.00;
$discount_rsn = sanitize_input($discount_reasons[$index] ?? '');
$stmt = $conn->prepare("UPDATE order_items SET product_id = ?, quantity = ?, packaging_preferences = ?, discount_percentage = ?, discount_reason = ? WHERE id = ?");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$stmt->bind_param("iisdsi", $pid, $qty, $pack_pref, $discount_pct, $discount_rsn, $item_id);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
$stmt->close();
}
// Insert new order items
if (!empty($new_product_ids)) {
$stmt = $conn->prepare("INSERT INTO order_items (order_id, product_id, quantity, packaging_preferences, discount_percentage, discount_reason) VALUES (?, ?, ?, ?, ?, ?)");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
for ($i = 0; $i < count($new_product_ids); $i++) {
$new_pid = intval($new_product_ids[$i]);
$new_qty = intval($new_quantities[$i]);
$new_pack_pref = sanitize_input($new_packaging_preferences[$i] ?? '');
$new_discount_pct = isset($new_discount_percentages[$i]) && $new_discount_percentages[$i] !== '' ? floatval($new_discount_percentages[$i]) : 0.00;
$new_discount_rsn = sanitize_input($new_discount_reasons[$i] ?? '');
if (!empty($new_pid)) {
$stmt->bind_param("iiisds", $order_id, $new_pid, $new_qty, $new_pack_pref, $new_discount_pct, $new_discount_rsn);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
}
}
$stmt->close();
}
// Commit transaction
$conn->commit();
$success = "Order updated successfully!";
// Refresh order data by fetching updated order items
$order_items_stmt = $conn->prepare($order_items_sql);
if (!$order_items_stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$order_items_stmt->bind_param("i", $order_id);
$order_items_stmt->execute();
$order_items_result = $order_items_stmt->get_result();
$order_items = [];
while ($item = $order_items_result->fetch_assoc()) {
$order_items[] = $item;
}
$order_items_stmt->close();
} catch (Exception $e) {
// Rollback transaction
$conn->rollback();
$error = "Error updating order: " . sanitize_input($e->getMessage());
}
} else {
// If there are validation errors, concatenate them
if (!empty($errors)) {
// Safeguard against null values
$sanitized_errors = array_map(function($err) {
return htmlspecialchars($err ?? '', ENT_QUOTES, 'UTF-8');
}, $errors);
$error = implode('<br>', $sanitized_errors);
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit Order #<?= htmlspecialchars($order_id ?? '', ENT_QUOTES, 'UTF-8') ?> - Kaak Alia Management System</title>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Tailwind CSS Configuration (optional for custom colors) -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
'background-color': '#FFFFFF',
'light-grey': '#F5F5F5',
'medium-grey': '#CCCCCC',
'dark-grey': '#333333',
'charcoal': '#374151',
'accent-blue': '#4A90E2',
'accent-green': '#50C878',
'accent-red': '#FF6B6B',
'accent-teal': '#20B2AA',
'accent-soft-blue': '#A3D2CA',
'accent-purple': '#8A65FF',
'accent-orange': '#FFA500',
'badge-pending': '#FFD166',
'badge-in-progress': '#6A4C93',
'badge-completed': '#4CAF50',
'badge-delivered': '#20B2AA',
'badge-paid': '#50C878',
'badge-not-paid': '#FF6B6B',
},
boxShadow: {
'custom': '0 2px 8px rgba(0, 0, 0, 0.05)',
'hover': '0 0 10px rgba(0, 0, 0, 0.2)',
},
borderRadius: {
'custom': '12px',
'lg': '8px',
'full': '9999px',
},
},
},
}
</script>
<!-- Flatpickr CSS for Date Picker -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<!-- Bootstrap Icons (for icons) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body class="font-inter bg-background-color">
<!-- Header -->
<header class="bg-charcoal rounded-custom shadow-custom p-5 mb-10">
<h1 class="text-2xl font-bold text-white text-center">Kaak Alia Management System</h1>
</header>
<!-- Container -->
<main class="max-w-6xl mx-auto px-4">
<div class="bg-white rounded-lg shadow-custom p-8">
<h2 class="text-3xl font-bold text-accent-teal mb-6">Edit Order #<?= htmlspecialchars($order_id ?? '', ENT_QUOTES, 'UTF-8') ?></h2>
<!-- Display Success or Error Messages -->
<?php if (!empty($success)): ?>
<div class="bg-accent-green text-white px-4 py-3 rounded-lg mb-6 flex items-center">
<i class="bi bi-check-circle-fill mr-2"></i>
<span><?= htmlspecialchars($success, ENT_QUOTES, 'UTF-8') ?></span>
</div>
<?php endif; ?>
<?php if (!empty($error)): ?>
<div class="bg-accent-red text-white px-4 py-3 rounded-lg mb-6 flex items-center">
<i class="bi bi-exclamation-triangle-fill mr-2"></i>
<span><?= $error ?></span>
</div>
<?php endif; ?>
<!-- Edit Order Form -->
<form method="POST" action="" class="space-y-8">
<!-- Customer Details -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Customer Details</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="customer_name" class="block text-sm font-medium text-dark-grey">Customer Name <span class="text-accent-red">*</span></label>
<input type="text" id="customer_name" name="customer_name" required
value="<?= htmlspecialchars($_POST['customer_name'] ?? $order['customer_name'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="contact" class="block text-sm font-medium text-dark-grey">Contact <span class="text-accent-red">*</span></label>
<input type="text" id="contact" name="contact" required
value="<?= htmlspecialchars($_POST['contact'] ?? $order['customer_contact'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
</div>
<div class="mt-6">
<label for="delivery_address" class="block text-sm font-medium text-dark-grey">Delivery Address</label>
<textarea id="delivery_address" name="delivery_address" rows="3"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal"><?= htmlspecialchars($_POST['delivery_address'] ?? $order['delivery_address'] ?? '', ENT_QUOTES, 'UTF-8') ?></textarea>
</div>
</section>
<hr class="border-light-grey">
<!-- Order Details -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Order Details</h3>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
<div>
<label for="status" class="block text-sm font-medium text-dark-grey">Status <span class="text-accent-red">*</span></label>
<select id="status" name="status" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Status</option>
<option value="Pending" <?= (($_POST['status'] ?? $order['status']) === 'Pending') ? 'selected' : '' ?>>Pending</option>
<option value="In Progress" <?= (($_POST['status'] ?? $order['status']) === 'In Progress') ? 'selected' : '' ?>>In Progress</option>
<option value="Completed" <?= (($_POST['status'] ?? $order['status']) === 'Completed') ? 'selected' : '' ?>>Completed</option>
<option value="Delivered" <?= (($_POST['status'] ?? $order['status']) === 'Delivered') ? 'selected' : '' ?>>Delivered</option>
</select>
</div>
<div>
<label for="priority" class="block text-sm font-medium text-dark-grey">Priority <span class="text-accent-red">*</span></label>
<select id="priority" name="priority" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Priority</option>
<option value="Normal" <?= (($_POST['priority'] ?? $order['priority']) === 'Normal') ? 'selected' : '' ?>>Normal</option>
<option value="Important" <?= (($_POST['priority'] ?? $order['priority']) === 'Important') ? 'selected' : '' ?>>Important</option>
<option value="Quick" <?= (($_POST['priority'] ?? $order['priority']) === 'Quick') ? 'selected' : '' ?>>Quick</option>
</select>
</div>
<div>
<label for="delivery_datetime" class="block text-sm font-medium text-dark-grey">Delivery Date and Time <span class="text-accent-red">*</span></label>
<input type="datetime-local" id="delivery_datetime" name="delivery_datetime" required
value="<?= htmlspecialchars($_POST['delivery_datetime'] ?? ($order['delivery_datetime'] ? date('Y-m-d\TH:i', strtotime($order['delivery_datetime'])) : ''), ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="delivery_date" class="block text-sm font-medium text-dark-grey">Delivery Date</label>
<input type="date" id="delivery_date" name="delivery_date"
value="<?= htmlspecialchars($_POST['delivery_date'] ?? ($order['delivery_date'] ? date('Y-m-d', strtotime($order['delivery_date'])) : ''), ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mt-6">
<div id="delivery_fee_field">
<label for="delivery_fee" class="block text-sm font-medium text-dark-grey">Delivery Fee (KWD) <span class="text-accent-red">*</span></label>
<input type="number" step="0.01" id="delivery_fee" name="delivery_fee" min="0" required
value="<?= htmlspecialchars($_POST['delivery_fee'] ?? number_format($order['delivery_fee'], 2, '.', ''), ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div id="free_shipping_field" class="flex items-center">
<input id="free_shipping" name="free_shipping" type="checkbox"
class="h-4 w-4 text-accent-teal border-gray-300 rounded focus:ring-accent-teal"
<?= (isset($_POST['free_shipping']) ? intval($_POST['free_shipping']) : intval($order['free_shipping'])) ? 'checked' : '' ?>>
<label for="free_shipping" class="ml-2 block text-sm text-dark-grey">
Free Shipping
</label>
</div>
<div class="flex items-center">
<input id="pickup" name="pickup" type="checkbox"
class="h-4 w-4 text-accent-teal border-gray-300 rounded focus:ring-accent-teal"
<?= (isset($_POST['pickup']) ? intval($_POST['pickup']) : intval($order['pickup'])) ? 'checked' : '' ?>>
<label for="pickup" class="ml-2 block text-sm text-dark-grey">
Customer Pickup
</label>
</div>
<div class="flex items-center">
<input id="is_paid" name="is_paid" type="checkbox"
class="h-4 w-4 text-accent-teal border-gray-300 rounded focus:ring-accent-teal"
<?= (isset($_POST['is_paid']) ? intval($_POST['is_paid']) : intval($order['is_paid'])) ? 'checked' : '' ?>>
<label for="is_paid" class="ml-2 block text-sm text-dark-grey">
<?= (isset($_POST['is_paid']) ? intval($_POST['is_paid']) : intval($order['is_paid'])) ? 'Mark as Paid' : 'Mark as Not Paid' ?>
</label>
</div>
</div>
</section>
<hr class="border-light-grey">
<!-- Existing Order Items -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Existing Order Items</h3>
<?php if (empty($order_items)): ?>
<p>No existing items for this order.</p>
<?php else: ?>
<div id="existing-order-items-container" class="space-y-6">
<?php foreach ($order_items as $item): ?>
<?php
// Skip items marked for deletion during POST
if (in_array($item['id'], $deleted_existing_item_ids)) {
continue;
}
?>
<div class="bg-light-grey p-6 rounded-lg shadow-custom">
<input type="hidden" name="existing_item_id[]" value="<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<div class="grid grid-cols-1 md:grid-cols-5 gap-6">
<div>
<label for="product_id_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Product <span class="text-accent-red">*</span></label>
<select name="product_id[]" id="product_id_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Product</option>
<?php foreach($products as $product_option): ?>
<option value="<?= htmlspecialchars($product_option['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" <?= (($product_option['id'] ?? '') == ($item['product_id'] ?? '')) ? 'selected' : '' ?>>
<?= htmlspecialchars($product_option['name'] . " - " . $product_option['size'] . " (" . number_format($product_option['price'], 2) . " KD)", ENT_QUOTES, 'UTF-8') ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="quantity_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Quantity <span class="text-accent-red">*</span></label>
<input type="number" name="quantity[]" id="quantity_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" min="1" required
value="<?= htmlspecialchars($item['quantity'] ?? '1', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="packaging_preferences_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Packaging Preferences</label>
<input type="text" name="packaging_preferences[]" id="packaging_preferences_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" placeholder="e.g., Gift Wrap"
value="<?= htmlspecialchars($item['packaging_preferences'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="discount_percentage_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Discount (%)</label>
<input type="number" name="discount_percentage[]" id="discount_percentage_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" min="0" max="100" step="0.01" value="<?= htmlspecialchars($item['discount_percentage'] ?? '0.00', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div class="flex items-end">
<button type="button" class="bg-accent-red text-white rounded-full h-10 w-10 hover:bg-red-600 transition duration-300" onclick="removeExistingOrderItemRow(this)" title="Remove Product">
×
</button>
</div>
</div>
<div class="mt-4">
<label for="discount_reason_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Discount Reason</label>
<input type="text" name="discount_reason[]" id="discount_reason_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" placeholder="e.g., Seasonal Sale"
value="<?= htmlspecialchars($item['discount_reason'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- Hidden inputs to track deleted items -->
<input type="hidden" name="deleted_existing_item_ids" id="deleted_existing_item_ids" value="<?= htmlspecialchars(implode(',', $deleted_existing_item_ids) ?? '', ENT_QUOTES, 'UTF-8') ?>">
</section>
<hr class="border-light-grey">
<!-- Add New Order Items -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Add New Order Items</h3>
<div id="order-items-container" class="space-y-6">
<!-- New Order Item Rows will be added here dynamically -->
</div>
<button type="button" class="flex items-center bg-accent-soft-blue text-accent-purple px-4 py-2 rounded-lg shadow-custom hover:bg-accent-blue hover:text-white transition duration-300 mt-4"
onclick="addOrderItemRow()">
<i class="bi bi-plus-circle-fill mr-2"></i> Add Another Product
</button>
</section>
<!-- Submit Buttons -->
<div class="flex justify-between mt-8">
<button type="submit" class="bg-accent-teal text-white px-6 py-3 rounded-lg shadow-custom hover:bg-accent-blue transition duration-300 font-semibold flex items-center">
<i class="bi bi-pencil-square mr-2"></i> Update Order
</button>
<a href="view_orders.php" class="bg-accent-soft-blue text-accent-purple px-6 py-3 rounded-lg shadow-custom hover:bg-accent-blue hover:text-white transition duration-300 font-semibold flex items-center">
<i class="bi bi-x-circle-fill mr-2"></i> Cancel
</a>
</div>
</form>
</div>
</main>
<!-- Footer -->
<footer class="bg-charcoal text-white text-center p-5 rounded-custom shadow-custom mt-10">
© <?= date("Y") ?> Kaak Alia Bakery. All rights reserved.
</footer>
<!-- Flatpickr JS for Date Picker -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<!-- Tailwind CSS Custom Scripts -->
<script>
// Function to add new order item row
function addOrderItemRow() {
const orderItemsContainer = document.getElementById('order-items-container');
const itemCount = orderItemsContainer.children.length;
const orderItemRow = document.createElement('div');
orderItemRow.className = 'bg-light-grey p-6 rounded-lg shadow-custom';
orderItemRow.innerHTML = `
<div class="grid grid-cols-1 md:grid-cols-5 gap-6">
<div>
<label for="new_product_id_${itemCount}" class="block text-sm font-medium text-dark-grey">Product <span class="text-accent-red">*</span></label>
<select name="new_product_id[]" id="new_product_id_${itemCount}" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Product</option>
${getProductOptions()}
</select>
</div>
<div>
<label for="new_quantity_${itemCount}" class="block text-sm font-medium text-dark-grey">Quantity <span class="text-accent-red">*</span></label>
<input type="number" name="new_quantity[]" id="new_quantity_${itemCount}" min="1" required value="1"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="new_packaging_preferences_${itemCount}" class="block text-sm font-medium text-dark-grey">Packaging Preferences</label>
<input type="text" name="new_packaging_preferences[]" id="new_packaging_preferences_${itemCount}" placeholder="e.g., Gift Wrap"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="new_discount_percentage_${itemCount}" class="block text-sm font-medium text-dark-grey">Discount (%)</label>
<input type="number" name="new_discount_percentage[]" id="new_discount_percentage_${itemCount}" min="0" max="100" step="0.01" value="0.00"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div class="flex items-end">
<button type="button" class="bg-accent-red text-white rounded-full h-10 w-10 hover:bg-red-600 transition duration-300" onclick="removeOrderItemRow(this)" title="Remove Product">
×
</button>
</div>
</div>
<div class="mt-4">
<label for="new_discount_reason_${itemCount}" class="block text-sm font-medium text-dark-grey">Discount Reason</label>
<input type="text" name="new_discount_reason[]" id="new_discount_reason_${itemCount}" placeholder="e.g., Seasonal Sale"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
`;
orderItemsContainer.appendChild(orderItemRow);
}
// Function to get product options as a string (to avoid embedding PHP in JS)
function getProductOptions() {
// Fetch products data from a PHP variable encoded as JSON
const products = <?= json_encode($products, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>;
let options = '<option value="">Select Product</option>';
products.forEach(product => {
options += `<option value="${product.id}">${escapeHtml(product.name)} - ${escapeHtml(product.size)} (${parseFloat(product.price).toFixed(2)} KD)</option>`;
});
return options;
}
// Function to escape HTML special characters (to prevent XSS)
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
// Function to remove new order item row
function removeOrderItemRow(button) {
const orderItemRow = button.closest('.bg-light-grey');
orderItemRow.remove();
}
// Function to remove existing order item row and mark it for deletion
function removeExistingOrderItemRow(button) {
const orderItemRow = button.closest('.bg-light-grey');
const deletedIdsContainer = document.getElementById('deleted_existing_item_ids');
// Find the existing_item_id for this row
const existingItemId = orderItemRow.querySelector('input[name="existing_item_id[]"]').value;
if (existingItemId) {
// Append the ID to the deleted_existing_item_ids array
if (deletedIdsContainer.value === '') {
deletedIdsContainer.value = existingItemId;
} else {
deletedIdsContainer.value += ',' + existingItemId;
}
}
// Remove the row from the UI
orderItemRow.remove();
}
// Function to toggle delivery fee input based on free shipping checkbox
function toggleDeliveryFee() {
const freeShippingCheckbox = document.getElementById('free_shipping');
const deliveryFeeInput = document.getElementById('delivery_fee');
if (freeShippingCheckbox.checked) {
deliveryFeeInput.value = '0.00';
deliveryFeeInput.disabled = true;
} else {
deliveryFeeInput.disabled = false;
}
}
// Toggle specific delivery details based on pickup checkbox
function togglePickup() {
const pickupCheckbox = document.getElementById('pickup');
const freeShippingCheckbox = document.getElementById('free_shipping');
const deliveryFeeInput = document.getElementById('delivery_fee');
const deliveryFeeField = document.getElementById('delivery_fee_field');
const freeShippingField = document.getElementById('free_shipping_field');
const deliveryAddressField = document.getElementById('delivery_address');
if (pickupCheckbox.checked) {
// Hide Delivery Address
deliveryAddressField.style.display = 'none';
// Uncheck and disable Free Shipping
if (freeShippingCheckbox.checked) {
freeShippingCheckbox.checked = false;
toggleDeliveryFee();
}
// Hide Free Shipping Field
freeShippingField.style.display = 'none';
// Disable and hide Delivery Fee
deliveryFeeInput.value = '0.00';
deliveryFeeInput.disabled = true;
deliveryFeeField.style.display = 'none';
} else {
// Show Delivery Address
deliveryAddressField.style.display = 'block';
// Show Free Shipping Field
freeShippingField.style.display = 'flex';
// Show Delivery Fee based on Free Shipping status
toggleDeliveryFee();
// Show Delivery Fee Field
deliveryFeeField.style.display = 'block';
}
}
// Auto-generate Customer Name based on Contact Number (optional, based on your requirements)
function autoGenerateCustomerName() {
const contactInput = document.getElementById('contact');
const customerNameInput = document.getElementById('customer_name');
// Extract digits from contact number
const digits = contactInput.value.replace(/\D/g, '');
if (digits.length > 0) {
customerNameInput.value = 'Order_' + digits;
} else {
customerNameInput.value = '';
}
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
// Initialize delivery fee toggle
toggleDeliveryFee();
const freeShippingEl = document.getElementById('free_shipping');
if (freeShippingEl) {
freeShippingEl.addEventListener('change', toggleDeliveryFee);
}
// Initialize pickup toggle
togglePickup();
const pickupEl = document.getElementById('pickup');
if (pickupEl) {
pickupEl.addEventListener('change', togglePickup);
}
// Initialize Customer Name auto-generation if needed
const contactEl = document.getElementById('contact');
if (contactEl) {
contactEl.addEventListener('input', autoGenerateCustomerName);
}
// Initialize Flatpickr for date and datetime fields
flatpickr("#delivery_datetime", {
enableTime: true,
dateFormat: "Y-m-d\\TH:i",
minDate: "today"
});
flatpickr("#delivery_date", {
dateFormat: "Y-m-d",
minDate: "today"
});
});
</script>
</body>
</html>
<?php
// Flush the output buffer
ob_end_flush();
// No closing PHP tag to prevent unwanted output) wehn i press un checkbxo pickup customer, and update the order, it doen't change plz fix it and type full codes and thsi info database (-- phpMyAdmin SQL Dump
-- version 5.2.1
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1:3306
-- Generation Time: Nov 17, 2024 at 06:50 PM
-- Server version: 10.11.9-MariaDB
-- PHP Version: 7.2.34
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `u406552082_kaakalia`
--
-- --------------------------------------------------------
--
-- Table structure for table `ads`
--
CREATE TABLE `ads` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`ad_type` enum('Post','Story') NOT NULL,
`related_id` int(11) NOT NULL,
`budget` decimal(10,2) NOT NULL,
`total_spent` decimal(10,2) DEFAULT 0.00,
`start_date` date NOT NULL,
`end_date` date NOT NULL,
`status` enum('Active','Paused','Completed') DEFAULT 'Active',
`created_at` datetime DEFAULT current_timestamp(),
`updated_at` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `ad_spend_logs`
--
CREATE TABLE `ad_spend_logs` (
`id` int(11) NOT NULL,
`ad_id` int(11) NOT NULL,
`amount` decimal(10,2) NOT NULL,
`spend_date` datetime DEFAULT current_timestamp(),
`description` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `customers`
--
CREATE TABLE `customers` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`contact` varchar(50) DEFAULT NULL,
`delivery_address` text DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `customers`
--
INSERT INTO `customers` (`id`, `name`, `contact`, `delivery_address`) VALUES
(1, 'Order_3121', '012345689', 'Qena'),
(2, 'order_3212', '51648963', 'Luxor'),
(3, 'Order_323', '01119235049', 'Qena, Egypt'),
(4, 'Order_3231', '0155648963', 'Luxor'),
(5, 'Order_3548464852', '0110215489', 'Qena'),
(6, 'Order_mahmoud', '50495049', 'Qena'),
(7, 'Ahmed', '01119235049', 'Assuit'),
(8, 'Mahmoud Tawfik', '01119235049', 'Qena, Center Qena'),
(9, 'Ahmed', '0101549463', 'Luxor'),
(10, 'Yossef', '0154949463', 'Aswan'),
(11, 'Mona', '0154984315', 'Qena'),
(12, 'Order_132323', '0119548463', 'CXA'),
(13, 'Mostafa', '154946123', 'Assuit'),
(14, 'Order_66960907', '+96566960907', 'kuwait'),
(15, 'Order_84569845', '+96584569845', 'Kuwait'),
(16, 'Order_84656222', '+96584656222', 'Mashrif'),
(17, 'Order_84549651', '+96584549651', 'Luxor'),
(18, 'Order_94531154', '+96594531154', 'Qena'),
(19, 'Order_56123548', '+96556123548', 'luxor'),
(20, 'Order_84562148', '+96584562148', NULL),
(21, 'Order_54632154', '+96554632154', 'Qena');
-- --------------------------------------------------------
--
-- Table structure for table `drivers`
--
CREATE TABLE `drivers` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`number` varchar(15) NOT NULL,
`is_star` tinyint(1) DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `drivers`
--
INSERT INTO `drivers` (`id`, `name`, `number`, `is_star`) VALUES
(1, 'Fox توصيل', '+965 9944 6116', 0),
(2, 'Perfect M توصيل 3kd', '+965 555 72147', 0),
(3, 'توصيل ٥', '+965 505 02769', 0),
(4, 'Shipping Company توصيل Delivery', '+965 9940 7010', 0),
(5, 'توصيلكم توصيل Delivery', '+965 517 66244', 0),
(6, 'توصيل الكويت ٢', '+965 557 25712', 0),
(7, 'توصيل الكويت 2.5kd', '+965 6049 4960', 0),
(8, 'كلاسك توصيل', '+965 6969 1459', 0),
(9, 'سايق On Call5 Delivery Freelance', '+965 6698 8976', 1),
(10, 'سايق On Call 3 Delivery Freelance', '+965 555 86442', 0),
(11, 'سايق On Call 2 Delivery Freelance', '+965 555 12101', 0),
(12, 'Delivery توصيل', '+965 9851 8182', 0),
(13, 'Kumar Driver', '+965 6673 8688', 1),
(14, 'Pawan Driver', '+965 9733 1565', 0),
(15, 'توصيل - صلاØ', '+965 6576 2337', 0);
-- --------------------------------------------------------
--
-- Table structure for table `notifications`
--
CREATE TABLE `notifications` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`type` enum('order','post','plan','note','ad') NOT NULL,
`message` varchar(255) NOT NULL,
`link` varchar(255) NOT NULL,
`created_at` datetime DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `orders`
--
CREATE TABLE `orders` (
`id` int(11) NOT NULL,
`customer_id` int(11) NOT NULL,
`status` enum('Pending','In Progress','Completed','Delivered') DEFAULT 'Pending',
`priority` enum('Normal','Important','Quick') DEFAULT 'Normal',
`order_date` datetime DEFAULT current_timestamp(),
`delivery_datetime` datetime DEFAULT NULL,
`delivery_date` date DEFAULT NULL,
`delivery_fee` decimal(10,2) NOT NULL DEFAULT 0.00,
`free_shipping` tinyint(1) NOT NULL DEFAULT 0,
`is_paid` tinyint(1) NOT NULL DEFAULT 0,
`pickup` tinyint(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `orders`
--
INSERT INTO `orders` (`id`, `customer_id`, `status`, `priority`, `order_date`, `delivery_datetime`, `delivery_date`, `delivery_fee`, `free_shipping`, `is_paid`, `pickup`) VALUES
(4, 4, 'Delivered', 'Normal', '2024-11-09 14:48:25', '2024-11-16 08:50:00', NULL, 0.00, 0, 0, 0),
(5, 5, 'Delivered', 'Normal', '2024-11-09 18:28:01', '2024-11-10 09:00:00', NULL, 0.00, 0, 0, 0),
(6, 6, 'Delivered', 'Important', '2024-11-12 09:49:43', '2024-11-13 16:00:00', NULL, 0.00, 0, 0, 0),
(8, 8, 'Delivered', 'Important', '2024-11-12 17:57:16', '2024-11-13 12:00:00', NULL, 0.00, 0, 0, 0),
(9, 9, 'Delivered', 'Important', '2024-11-12 18:16:47', '2024-11-13 15:00:00', NULL, 1.00, 0, 0, 0),
(10, 10, 'Pending', 'Quick', '2024-11-12 18:50:43', '2024-11-13 18:00:00', NULL, 0.00, 0, 0, 0),
(12, 12, 'Pending', 'Quick', '2024-11-13 12:25:55', NULL, NULL, 0.00, 1, 1, 0),
(17, 17, 'Pending', 'Important', '2024-11-14 22:49:41', '2024-11-16 12:00:00', NULL, 1.00, 0, 1, 0),
(18, 18, 'Pending', 'Important', '2024-11-14 23:03:27', '2024-11-16 14:00:00', NULL, 1.00, 0, 1, 0),
(19, 19, 'Delivered', 'Normal', '2024-11-15 12:18:46', '2024-11-16 14:00:00', NULL, 1.00, 0, 1, 0),
(20, 20, 'Pending', 'Important', '2024-11-16 21:28:35', '2024-11-17 11:00:00', NULL, 0.00, 0, 0, 1),
(21, 21, 'Pending', 'Important', '2024-11-16 21:52:46', '2024-11-18 12:00:00', NULL, 1.00, 0, 0, 1);
-- --------------------------------------------------------
--
-- Table structure for table `order_items`
--
CREATE TABLE `order_items` (
`id` int(11) NOT NULL,
`order_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
`quantity` int(11) NOT NULL DEFAULT 1,
`packaging_preferences` varchar(255) DEFAULT NULL,
`discount_percentage` decimal(5,2) DEFAULT 0.00,
`discount_reason` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `order_items`
--
INSERT INTO `order_items` (`id`, `order_id`, `product_id`, `quantity`, `packaging_preferences`, `discount_percentage`, `discount_reason`) VALUES
(5, 4, 8, 1, 'This Order type one Mahmoud Tawfik', 0.00, '<br /><b>Deprecated</b>: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in <b>/home/u406552082/domains/longevacare.com/public_html/kaakalia/public/orders/edit_order.php</b> on line <b>692</b><br />'),
(6, 5, 2, 1, '0', 20.00, 'خصم مشرÙ'),
(7, 4, 6, 2, 'Add Card on it', 30.00, ''),
(8, 6, 6, 1, '0', 0.00, NULL),
(10, 8, 2, 2, 'add Card on box, this card is "Mahmoud Tawfik"', 30.00, 'خصم المشرÙ'),
(11, 9, 7, 1, 'type on \"Mahmoud\"', 0.00, '<br /><b>Deprecated</b>: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in <b>/home/u406552082/domains/longevacare.com/public_html/kaakalia/public/orders/edit_order.php</b> on line <b>749</b><br />'),
(12, 10, 3, 1, 'Type: Mahmoud Tawfik', 0.00, NULL),
(14, 12, 8, 5, '', 0.00, ''),
(19, 12, 8, 1, '0', 0.00, '0'),
(20, 17, 6, 1, '', 30.00, 'خصم مشرÙ'),
(21, 17, 5, 2, '0', 25.00, '0'),
(22, 18, 7, 1, 'Add Card, Mahmoud', 30.00, 'خصم المشرÙ'),
(23, 18, 1, 1, 'Add Card, Ahmed', 30.00, 'خصم المشرÙ'),
(24, 18, 5, 1, 'Add Card, ASC', 30.00, '0'),
(25, 19, 2, 5, 'Add Card :Mahmoud Tawfik:', 30.00, 'خصم مشرÙ'),
(26, 20, 7, 1, 'Add New Card \"Mahmoud Tawfik\"', 30.00, 'خصم مشرÙ'),
(27, 21, 9, 1, '', 0.00, '');
-- --------------------------------------------------------
--
-- Table structure for table `products`
--
CREATE TABLE `products` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`size` varchar(50) DEFAULT NULL,
`price` decimal(10,2) NOT NULL,
`category` varchar(50) DEFAULT NULL,
`thumbnail` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `name`, `size`, `price`, `category`, `thumbnail`) VALUES
(1, 'Shabora', 'Half Kilo', 6.00, 'Cakes', NULL),
(2, 'Shabora', 'One Kilo', 8.00, 'Cakes', NULL),
(3, 'Shabora', 'Small Basket', 8.00, 'Cakes', NULL),
(4, 'Shabora', 'Large Basket', 10.00, 'Cakes', NULL),
(5, 'Shabora', 'Presentation Plate (Ivory)', 14.00, 'Cakes', NULL),
(6, 'Mahalbiya Crunch', '12 Pieces', 12.00, 'Desserts', NULL),
(7, 'Monkey Bread', 'Large', 12.00, 'Breads', NULL),
(8, 'Monkey Bread Mini', '12 Pieces', 6.00, 'Breads', NULL),
(9, 'Monkey Bread Mini', '9 Pieces', 9.00, 'Breads', NULL),
(11, 'Monkey Bread', 'Presentation Plate', 16.00, 'Breads', NULL);
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`username` varchar(50) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`password` varchar(255) NOT NULL,
`role` enum('admin','staff') NOT NULL,
`profile_image` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `username`, `email`, `password`, `role`, `profile_image`) VALUES
(1, 'kaakalia', 'user@example.com', '$2y$10$tEdSPRwL8WTXljuAxNh.m.af/8sHd/ouDB21Bgs1bC7GkbRq/h0D6', 'admin', 'uploads/profile_images/profile_kaakalia_1731274341.png'),
(2, 'mahmoudtawfik', 'mahmoudtawfikh@gmail.com', '$2y$10$0yxg1R.kfbVV7GL4G9/Q3u5PK.cvv8p29R3ggkfUMC2.aRiAXb2cO', 'admin', 'uploads/profile_images/profile_mahmoudtawfik_1731274427.jpg'),
(3, 'haya', 'haya@gmail.com', '$2y$10$ri1wzOhcmT2YVGkoPYjwu.3fY8xayakQEWHjTaAFGkPfDwJ50PIh6', 'admin', 'uploads/profile_images/profile_haya_1731304053.jpg');
-- --------------------------------------------------------
--
-- Table structure for table `workspace_notes`
--
CREATE TABLE `workspace_notes` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`content` text NOT NULL,
`created_at` datetime DEFAULT current_timestamp(),
`updated_at` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `workspace_notes`
--
INSERT INTO `workspace_notes` (`id`, `user_id`, `title`, `content`, `created_at`, `updated_at`) VALUES
(2, 2, 'This important notes', 'HaloHaloHaloHaloHaloHaloHaloHaloHaloHalo', '2024-11-11 09:37:10', '2024-11-11 09:37:10');
-- --------------------------------------------------------
--
-- Table structure for table `workspace_plans`
--
CREATE TABLE `workspace_plans` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`description` text DEFAULT NULL,
`audio_path` varchar(255) DEFAULT NULL,
`due_date` datetime DEFAULT NULL,
`status` enum('Not Started','In Progress','Completed') DEFAULT 'Not Started',
`created_at` datetime DEFAULT current_timestamp(),
`updated_at` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`priority` enum('Normal','Important','Critical') NOT NULL DEFAULT 'Normal'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- --------------------------------------------------------
--
-- Table structure for table `workspace_posts`
--
CREATE TABLE `workspace_posts` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`platform` enum('Instagram','Facebook','Twitter','Other') NOT NULL,
`content` text NOT NULL,
`media_url` varchar(255) DEFAULT NULL,
`scheduled_datetime` datetime DEFAULT NULL,
`status` enum('Scheduled','Posted','Failed') DEFAULT 'Scheduled',
`created_at` datetime DEFAULT current_timestamp(),
`updated_at` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`type` enum('Post','Story') DEFAULT 'Post'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `workspace_posts`
--
INSERT INTO `workspace_posts` (`id`, `user_id`, `platform`, `content`, `media_url`, `scheduled_datetime`, `status`, `created_at`, `updated_at`, `type`) VALUES
(2, 1, 'Instagram', 'Hello', NULL, '2024-11-11 01:19:00', 'Scheduled', '2024-11-10 11:16:10', '2024-11-10 11:16:10', 'Post');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `ads`
--
ALTER TABLE `ads`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`),
ADD KEY `related_id` (`related_id`);
--
-- Indexes for table `ad_spend_logs`
--
ALTER TABLE `ad_spend_logs`
ADD PRIMARY KEY (`id`),
ADD KEY `ad_id` (`ad_id`);
--
-- Indexes for table `customers`
--
ALTER TABLE `customers`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `drivers`
--
ALTER TABLE `drivers`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `notifications`
--
ALTER TABLE `notifications`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`),
ADD KEY `created_at` (`created_at`);
--
-- Indexes for table `orders`
--
ALTER TABLE `orders`
ADD PRIMARY KEY (`id`),
ADD KEY `customer_id` (`customer_id`),
ADD KEY `idx_orders_customer_id` (`customer_id`);
--
-- Indexes for table `order_items`
--
ALTER TABLE `order_items`
ADD PRIMARY KEY (`id`),
ADD KEY `order_id` (`order_id`),
ADD KEY `product_id` (`product_id`),
ADD KEY `idx_order_items_order_id` (`order_id`),
ADD KEY `idx_order_items_product_id` (`product_id`);
--
-- Indexes for table `products`
--
ALTER TABLE `products`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `users`
--
ALTER TABLE `users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `username` (`username`);
--
-- Indexes for table `workspace_notes`
--
ALTER TABLE `workspace_notes`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`);
--
-- Indexes for table `workspace_plans`
--
ALTER TABLE `workspace_plans`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`);
--
-- Indexes for table `workspace_posts`
--
ALTER TABLE `workspace_posts`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `ads`
--
ALTER TABLE `ads`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
--
-- AUTO_INCREMENT for table `ad_spend_logs`
--
ALTER TABLE `ad_spend_logs`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
--
-- AUTO_INCREMENT for table `customers`
--
ALTER TABLE `customers`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=22;
--
-- AUTO_INCREMENT for table `drivers`
--
ALTER TABLE `drivers`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=16;
--
-- AUTO_INCREMENT for table `notifications`
--
ALTER TABLE `notifications`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `orders`
--
ALTER TABLE `orders`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=22;
--
-- AUTO_INCREMENT for table `order_items`
--
ALTER TABLE `order_items`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=28;
--
-- AUTO_INCREMENT for table `products`
--
ALTER TABLE `products`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
--
-- AUTO_INCREMENT for table `users`
--
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
--
-- AUTO_INCREMENT for table `workspace_notes`
--
ALTER TABLE `workspace_notes`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
--
-- AUTO_INCREMENT for table `workspace_plans`
--
ALTER TABLE `workspace_plans`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=17;
--
-- AUTO_INCREMENT for table `workspace_posts`
--
ALTER TABLE `workspace_posts`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `ads`
--
ALTER TABLE `ads`
ADD CONSTRAINT `fk_ads_related_id` FOREIGN KEY (`related_id`) REFERENCES `workspace_posts` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_ads_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `ad_spend_logs`
--
ALTER TABLE `ad_spend_logs`
ADD CONSTRAINT `fk_ad_spend_logs_ad_id` FOREIGN KEY (`ad_id`) REFERENCES `ads` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `notifications`
--
ALTER TABLE `notifications`
ADD CONSTRAINT `notifications_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `orders`
--
ALTER TABLE `orders`
ADD CONSTRAINT `fk_orders_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `order_items`
--
ALTER TABLE `order_items`
ADD CONSTRAINT `fk_order_items_order_id` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `fk_order_items_product_id` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `order_items_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `order_items_ibfk_2` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `workspace_notes`
--
ALTER TABLE `workspace_notes`
ADD CONSTRAINT `fk_workspace_notes_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `workspace_plans`
--
ALTER TABLE `workspace_plans`
ADD CONSTRAINT `fk_workspace_plans_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
--
-- Constraints for table `workspace_posts`
--
ALTER TABLE `workspace_posts`
ADD CONSTRAINT `fk_workspace_posts_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;) and type full codesASSISTANT
Certainly! It looks like the primary issue in your PHP code is that the `pickup` checkbox state isn't being correctly updated in the database when you uncheck it. This happens because the `pickup` value is being initialized from the existing order data and not being updated based on the form submission (`$_POST`). Additionally, there are some issues related to handling `NULL` values with `htmlspecialchars` in your `sanitize_input` function, which is causing PHP deprecation warnings.
Below is the fully corrected version of your `edit_order.php` file with detailed explanations of the changes made to resolve these issues.
---
## Corrected `edit_order.php`
```php
<?php
// public/orders/edit_order.php
// Enable error reporting for debugging (disable in production)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Start output buffering to prevent "headers already sent" errors
ob_start();
// Include necessary files
require_once __DIR__ . '/../../includes/auth.php';
require_once __DIR__ . '/../../includes/db_connect.php';
require_once __DIR__ . '/../../includes/functions.php'; // Ensure sanitize_input() is defined
// Check if sanitize_input() exists
if (!function_exists('sanitize_input')) {
die("Error: sanitize_input() function is not defined.");
}
// Initialize success and error variables
$success = '';
$error = '';
// Initialize $deleted_existing_item_ids as an empty array to prevent undefined variable warnings
$deleted_existing_item_ids = [];
// Retrieve and sanitize the order ID from GET parameters
$order_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
// Redirect if no valid order ID is provided
if ($order_id <= 0) {
header("Location: view_orders.php?error=Invalid%20Order%20ID");
exit();
}
// Fetch order details along with customer information and is_paid status
$order_sql = "SELECT o.*, c.name AS customer_name, c.contact AS customer_contact, c.delivery_address
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.id = ? LIMIT 1";
$order_stmt = $conn->prepare($order_sql);
if (!$order_stmt) {
error_log("Prepare statement failed: " . $conn->error);
die("An unexpected error occurred. Please try again later.");
}
$order_stmt->bind_param("i", $order_id);
$order_stmt->execute();
$order_result = $order_stmt->get_result();
if ($order_result->num_rows != 1) {
header("Location: view_orders.php?error=Order%20Not%20Found");
exit();
}
$order = $order_result->fetch_assoc();
$order_stmt->close();
// Fetch existing order items
$order_items_sql = "SELECT oi.*, p.name AS product_name, p.size, p.price
FROM order_items oi
JOIN products p ON oi.product_id = p.id
WHERE oi.order_id = ?";
$order_items_stmt = $conn->prepare($order_items_sql);
if (!$order_items_stmt) {
error_log("Prepare statement failed: " . $conn->error);
die("An unexpected error occurred. Please try again later.");
}
$order_items_stmt->bind_param("i", $order_id);
$order_items_stmt->execute();
$order_items_result = $order_items_stmt->get_result();
$order_items = [];
while ($item = $order_items_result->fetch_assoc()) {
$order_items[] = $item;
}
$order_items_stmt->close();
// Fetch products for selection
$products_sql = "SELECT * FROM products ORDER BY name ASC";
$products_result = $conn->query($products_sql);
if (!$products_result) {
error_log("Query failed: " . $conn->error);
die("An unexpected error occurred. Please try again later.");
}
$products = $products_result->fetch_all(MYSQLI_ASSOC);
// Handle form submission for updating the order
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Retrieve and sanitize form inputs
$customer_name = sanitize_input($_POST['customer_name'] ?? '');
$contact = sanitize_input($_POST['contact'] ?? '');
$delivery_address = sanitize_input($_POST['delivery_address'] ?? '');
$status = sanitize_input($_POST['status'] ?? '');
$priority = sanitize_input($_POST['priority'] ?? '');
$delivery_datetime_input = $_POST['delivery_datetime'] ?? '';
$delivery_date_input = $_POST['delivery_date'] ?? '';
// New fields based on database schema
$delivery_fee = isset($_POST['delivery_fee']) && is_numeric($_POST['delivery_fee']) ? floatval($_POST['delivery_fee']) : 0.00;
$free_shipping = isset($_POST['free_shipping']) ? 1 : 0;
$is_paid = isset($_POST['is_paid']) ? 1 : 0; // New field
// Read 'pickup' from POST data
$pickup = isset($_POST['pickup']) ? 1 : 0;
// If free shipping is selected, set delivery_fee to 0.00
if ($free_shipping) {
$delivery_fee = 0.00;
}
// Handle existing order items
$existing_item_ids = isset($_POST['existing_item_id']) ? $_POST['existing_item_id'] : [];
$product_ids = isset($_POST['product_id']) ? $_POST['product_id'] : [];
$quantities = isset($_POST['quantity']) ? $_POST['quantity'] : [];
$packaging_preferences = isset($_POST['packaging_preferences']) ? $_POST['packaging_preferences'] : [];
$discount_percentages = isset($_POST['discount_percentage']) ? $_POST['discount_percentage'] : [];
$discount_reasons = isset($_POST['discount_reason']) ? $_POST['discount_reason'] : [];
// Handle new order items
$new_product_ids = isset($_POST['new_product_id']) ? $_POST['new_product_id'] : [];
$new_quantities = isset($_POST['new_quantity']) ? $_POST['new_quantity'] : [];
$new_packaging_preferences = isset($_POST['new_packaging_preferences']) ? $_POST['new_packaging_preferences'] : [];
$new_discount_percentages = isset($_POST['new_discount_percentage']) ? $_POST['new_discount_percentage'] : [];
$new_discount_reasons = isset($_POST['new_discount_reason']) ? $_POST['new_discount_reason'] : [];
// Handle deleted existing order items
$deleted_existing_item_ids = isset($_POST['deleted_existing_item_ids']) && !empty($_POST['deleted_existing_item_ids']) ? explode(',', $_POST['deleted_existing_item_ids']) : [];
// Ensure $deleted_existing_item_ids is always an array
if (!is_array($deleted_existing_item_ids)) {
$deleted_existing_item_ids = [];
}
// Define arrays to hold data for validation
$errors = [];
// Basic validation
if (empty($customer_name)) {
$errors[] = "Customer name is required.";
}
if (empty($status)) {
$errors[] = "Order status is required.";
}
if (empty($priority)) {
$errors[] = "Order priority is required.";
}
if (empty($delivery_datetime_input) && empty($delivery_date_input)) {
$errors[] = "Either Delivery Date and Time or Delivery Date is required.";
}
if (empty(array_diff($existing_item_ids, $deleted_existing_item_ids)) && empty($new_product_ids)) {
$errors[] = "At least one product must be selected.";
}
// Validate existing order items
foreach ($existing_item_ids as $index => $item_id) {
if (in_array($item_id, $deleted_existing_item_ids)) {
continue; // Skip validation for deleted items
}
if (empty($product_ids[$index])) {
$errors[] = "Product selection is required for all existing items.";
break;
}
if (!isset($quantities[$index]) || intval($quantities[$index]) <= 0) {
$errors[] = "Quantity must be at least 1 for all existing items.";
break;
}
if (isset($discount_percentages[$index]) && $discount_percentages[$index] !== '' && (floatval($discount_percentages[$index]) < 0 || floatval($discount_percentages[$index]) > 100)) {
$errors[] = "Discount percentage must be between 0 and 100.";
break;
}
}
// Validate new order items
foreach ($new_product_ids as $index => $pid) {
if (!empty($pid)) {
if (!isset($new_quantities[$index]) || intval($new_quantities[$index]) <= 0) {
$errors[] = "Quantity must be at least 1 for all new items.";
break;
}
if (isset($new_discount_percentages[$index]) && $new_discount_percentages[$index] !== '' && (floatval($new_discount_percentages[$index]) < 0 || floatval($new_discount_percentages[$index]) > 100)) {
$errors[] = "Discount percentage must be between 0 and 100 for all new items.";
break;
}
}
}
// Validate delivery_datetime
if (!empty($delivery_datetime_input)) {
// Convert from 'Y-m-d\TH:i' to 'Y-m-d H:i:s'
$delivery_datetime = sanitize_input(str_replace('T', ' ', $delivery_datetime_input) . ':00');
if (!preg_match("/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/", $delivery_datetime)) {
$errors[] = "Invalid delivery date and time format.";
} elseif (strtotime($delivery_datetime) < strtotime(date('Y-m-d H:i:s'))) {
$errors[] = "Delivery date and time cannot be in the past.";
}
} else {
$delivery_datetime = null;
}
// Validate delivery_date
if (!empty($delivery_date_input)) {
$delivery_date = sanitize_input($delivery_date_input);
if (!preg_match("/^\d{4}-\d{2}-\d{2}$/", $delivery_date)) {
$errors[] = "Invalid delivery date format.";
} elseif (strtotime($delivery_date) < strtotime(date('Y-m-d'))) {
$errors[] = "Delivery date cannot be in the past.";
}
} else {
$delivery_date = null;
}
// Validate delivery_fee if not free shipping
if (!$free_shipping) {
if (!isset($_POST['delivery_fee']) || !is_numeric($_POST['delivery_fee']) || floatval($_POST['delivery_fee']) < 0) {
$errors[] = "Valid delivery fee is required.";
}
}
// If there are no validation errors, proceed with database updates
if (empty($errors)) {
// Proceed with database updates
// Start transaction
$conn->begin_transaction();
try {
// Update customer details
$stmt = $conn->prepare("UPDATE customers SET name = ?, contact = ?, delivery_address = ? WHERE id = ?");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$stmt->bind_param("sssi", $customer_name, $contact, $delivery_address, $order['customer_id']);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
$stmt->close();
// Update orders table with new fields including is_paid and pickup
$stmt = $conn->prepare("UPDATE orders SET status = ?, priority = ?, delivery_datetime = ?, delivery_date = ?, delivery_fee = ?, free_shipping = ?, is_paid = ?, pickup = ? WHERE id = ?");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$stmt->bind_param("ssssdiiii", $status, $priority, $delivery_datetime, $delivery_date, $delivery_fee, $free_shipping, $is_paid, $pickup, $order_id);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
$stmt->close();
// Delete removed existing order items
if (!empty($deleted_existing_item_ids)) {
// Prepare the statement with placeholders
$placeholders = implode(',', array_fill(0, count($deleted_existing_item_ids), '?'));
$types = str_repeat('i', count($deleted_existing_item_ids));
$delete_sql = "DELETE FROM order_items WHERE id IN ($placeholders)";
$delete_stmt = $conn->prepare($delete_sql);
if (!$delete_stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
// Dynamically bind parameters
// Using argument unpacking (PHP 5.6+)
$delete_stmt->bind_param($types, ...$deleted_existing_item_ids);
if (!$delete_stmt->execute()) {
throw new Exception("Execute failed: " . $delete_stmt->error);
}
$delete_stmt->close();
}
// Update existing order items
foreach ($existing_item_ids as $index => $item_id) {
if (in_array($item_id, $deleted_existing_item_ids)) {
continue; // Skip deleted items
}
$item_id = intval($item_id);
$pid = intval($product_ids[$index]);
$qty = intval($quantities[$index]);
$pack_pref = sanitize_input($packaging_preferences[$index] ?? '');
$discount_pct = isset($discount_percentages[$index]) && $discount_percentages[$index] !== '' ? floatval($discount_percentages[$index]) : 0.00;
$discount_rsn = sanitize_input($discount_reasons[$index] ?? '');
$stmt = $conn->prepare("UPDATE order_items SET product_id = ?, quantity = ?, packaging_preferences = ?, discount_percentage = ?, discount_reason = ? WHERE id = ?");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$stmt->bind_param("iisdsi", $pid, $qty, $pack_pref, $discount_pct, $discount_rsn, $item_id);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
$stmt->close();
}
// Insert new order items
if (!empty($new_product_ids)) {
$stmt = $conn->prepare("INSERT INTO order_items (order_id, product_id, quantity, packaging_preferences, discount_percentage, discount_reason) VALUES (?, ?, ?, ?, ?, ?)");
if (!$stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
for ($i = 0; $i < count($new_product_ids); $i++) {
$new_pid = intval($new_product_ids[$i]);
$new_qty = intval($new_quantities[$i]);
$new_pack_pref = sanitize_input($new_packaging_preferences[$i] ?? '');
$new_discount_pct = isset($new_discount_percentages[$i]) && $new_discount_percentages[$i] !== '' ? floatval($new_discount_percentages[$i]) : 0.00;
$new_discount_rsn = sanitize_input($new_discount_reasons[$i] ?? '');
if (!empty($new_pid)) {
$stmt->bind_param("iiisds", $order_id, $new_pid, $new_qty, $new_pack_pref, $new_discount_pct, $new_discount_rsn);
if (!$stmt->execute()) {
throw new Exception("Execute failed: " . $stmt->error);
}
}
}
$stmt->close();
}
// Commit transaction
$conn->commit();
$success = "Order updated successfully!";
// Refresh order data by fetching updated order items
$order_items_stmt = $conn->prepare($order_items_sql);
if (!$order_items_stmt) {
throw new Exception("Prepare statement failed: " . $conn->error);
}
$order_items_stmt->bind_param("i", $order_id);
$order_items_stmt->execute();
$order_items_result = $order_items_stmt->get_result();
$order_items = [];
while ($item = $order_items_result->fetch_assoc()) {
$order_items[] = $item;
}
$order_items_stmt->close();
} catch (Exception $e) {
// Rollback transaction
$conn->rollback();
$error = "Error updating order: " . sanitize_input($e->getMessage());
}
} else {
// If there are validation errors, concatenate them
if (!empty($errors)) {
// Safeguard against null values
$sanitized_errors = array_map(function($err) {
return htmlspecialchars($err ?? '', ENT_QUOTES, 'UTF-8');
}, $errors);
$error = implode('<br>', $sanitized_errors);
}
}
}
// Define $pickup based on either POST data or existing order data
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$pickup = intval($order['pickup']);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit Order #<?= htmlspecialchars($order_id ?? '', ENT_QUOTES, 'UTF-8') ?> - Kaak Alia Management System</title>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Tailwind CSS Configuration (optional for custom colors) -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
'background-color': '#FFFFFF',
'light-grey': '#F5F5F5',
'medium-grey': '#CCCCCC',
'dark-grey': '#333333',
'charcoal': '#374151',
'accent-blue': '#4A90E2',
'accent-green': '#50C878',
'accent-red': '#FF6B6B',
'accent-teal': '#20B2AA',
'accent-soft-blue': '#A3D2CA',
'accent-purple': '#8A65FF',
'accent-orange': '#FFA500',
'badge-pending': '#FFD166',
'badge-in-progress': '#6A4C93',
'badge-completed': '#4CAF50',
'badge-delivered': '#20B2AA',
'badge-paid': '#50C878',
'badge-not-paid': '#FF6B6B',
},
boxShadow: {
'custom': '0 2px 8px rgba(0, 0, 0, 0.05)',
'hover': '0 0 10px rgba(0, 0, 0, 0.2)',
},
borderRadius: {
'custom': '12px',
'lg': '8px',
'full': '9999px',
},
},
},
}
</script>
<!-- Flatpickr CSS for Date Picker -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<!-- Bootstrap Icons (for icons) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body class="font-inter bg-background-color">
<!-- Header -->
<header class="bg-charcoal rounded-custom shadow-custom p-5 mb-10">
<h1 class="text-2xl font-bold text-white text-center">Kaak Alia Management System</h1>
</header>
<!-- Container -->
<main class="max-w-6xl mx-auto px-4">
<div class="bg-white rounded-lg shadow-custom p-8">
<h2 class="text-3xl font-bold text-accent-teal mb-6">Edit Order #<?= htmlspecialchars($order_id ?? '', ENT_QUOTES, 'UTF-8') ?></h2>
<!-- Display Success or Error Messages -->
<?php if (!empty($success)): ?>
<div class="bg-accent-green text-white px-4 py-3 rounded-lg mb-6 flex items-center">
<i class="bi bi-check-circle-fill mr-2"></i>
<span><?= htmlspecialchars($success, ENT_QUOTES, 'UTF-8') ?></span>
</div>
<?php endif; ?>
<?php if (!empty($error)): ?>
<div class="bg-accent-red text-white px-4 py-3 rounded-lg mb-6 flex items-center">
<i class="bi bi-exclamation-triangle-fill mr-2"></i>
<span><?= $error ?></span>
</div>
<?php endif; ?>
<!-- Edit Order Form -->
<form method="POST" action="" class="space-y-8">
<!-- Customer Details -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Customer Details</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="customer_name" class="block text-sm font-medium text-dark-grey">Customer Name <span class="text-accent-red">*</span></label>
<input type="text" id="customer_name" name="customer_name" required
value="<?= htmlspecialchars($_POST['customer_name'] ?? $order['customer_name'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="contact" class="block text-sm font-medium text-dark-grey">Contact <span class="text-accent-red">*</span></label>
<input type="text" id="contact" name="contact" required
value="<?= htmlspecialchars($_POST['contact'] ?? $order['customer_contact'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
</div>
<div class="mt-6">
<label for="delivery_address" class="block text-sm font-medium text-dark-grey">Delivery Address</label>
<textarea id="delivery_address" name="delivery_address" rows="3"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal"><?= htmlspecialchars($_POST['delivery_address'] ?? $order['delivery_address'] ?? '', ENT_QUOTES, 'UTF-8') ?></textarea>
</div>
</section>
<hr class="border-light-grey">
<!-- Order Details -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Order Details</h3>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
<div>
<label for="status" class="block text-sm font-medium text-dark-grey">Status <span class="text-accent-red">*</span></label>
<select id="status" name="status" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Status</option>
<option value="Pending" <?= (($_POST['status'] ?? $order['status']) === 'Pending') ? 'selected' : '' ?>>Pending</option>
<option value="In Progress" <?= (($_POST['status'] ?? $order['status']) === 'In Progress') ? 'selected' : '' ?>>In Progress</option>
<option value="Completed" <?= (($_POST['status'] ?? $order['status']) === 'Completed') ? 'selected' : '' ?>>Completed</option>
<option value="Delivered" <?= (($_POST['status'] ?? $order['status']) === 'Delivered') ? 'selected' : '' ?>>Delivered</option>
</select>
</div>
<div>
<label for="priority" class="block text-sm font-medium text-dark-grey">Priority <span class="text-accent-red">*</span></label>
<select id="priority" name="priority" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Priority</option>
<option value="Normal" <?= (($_POST['priority'] ?? $order['priority']) === 'Normal') ? 'selected' : '' ?>>Normal</option>
<option value="Important" <?= (($_POST['priority'] ?? $order['priority']) === 'Important') ? 'selected' : '' ?>>Important</option>
<option value="Quick" <?= (($_POST['priority'] ?? $order['priority']) === 'Quick') ? 'selected' : '' ?>>Quick</option>
</select>
</div>
<div>
<label for="delivery_datetime" class="block text-sm font-medium text-dark-grey">Delivery Date and Time <span class="text-accent-red">*</span></label>
<input type="datetime-local" id="delivery_datetime" name="delivery_datetime" required
value="<?= htmlspecialchars($_POST['delivery_datetime'] ?? ($order['delivery_datetime'] ? date('Y-m-d\TH:i', strtotime($order['delivery_datetime'])) : ''), ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="delivery_date" class="block text-sm font-medium text-dark-grey">Delivery Date</label>
<input type="date" id="delivery_date" name="delivery_date"
value="<?= htmlspecialchars($_POST['delivery_date'] ?? ($order['delivery_date'] ? date('Y-m-d', strtotime($order['delivery_date'])) : ''), ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mt-6">
<div id="delivery_fee_field">
<label for="delivery_fee" class="block text-sm font-medium text-dark-grey">Delivery Fee (KWD) <span class="text-accent-red">*</span></label>
<input type="number" step="0.01" id="delivery_fee" name="delivery_fee" min="0" required
value="<?= htmlspecialchars($_POST['delivery_fee'] ?? number_format($order['delivery_fee'], 2, '.', ''), ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div id="free_shipping_field" class="flex items-center">
<input id="free_shipping" name="free_shipping" type="checkbox"
class="h-4 w-4 text-accent-teal border-gray-300 rounded focus:ring-accent-teal"
<?= (isset($_POST['free_shipping']) ? intval($_POST['free_shipping']) : intval($order['free_shipping'])) ? 'checked' : '' ?>>
<label for="free_shipping" class="ml-2 block text-sm text-dark-grey">
Free Shipping
</label>
</div>
<div class="flex items-center">
<input id="pickup" name="pickup" type="checkbox"
class="h-4 w-4 text-accent-teal border-gray-300 rounded focus:ring-accent-teal"
<?= (isset($_POST['pickup']) ? intval($_POST['pickup']) : intval($order['pickup'])) ? 'checked' : '' ?>>
<label for="pickup" class="ml-2 block text-sm text-dark-grey">
Customer Pickup
</label>
</div>
<div class="flex items-center">
<input id="is_paid" name="is_paid" type="checkbox"
class="h-4 w-4 text-accent-teal border-gray-300 rounded focus:ring-accent-teal"
<?= (isset($_POST['is_paid']) ? intval($_POST['is_paid']) : intval($order['is_paid'])) ? 'checked' : '' ?>>
<label for="is_paid" class="ml-2 block text-sm text-dark-grey">
<?= (isset($_POST['is_paid']) ? intval($_POST['is_paid']) : intval($order['is_paid'])) ? 'Mark as Paid' : 'Mark as Not Paid' ?>
</label>
</div>
</div>
</section>
<hr class="border-light-grey">
<!-- Existing Order Items -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Existing Order Items</h3>
<?php if (empty($order_items)): ?>
<p>No existing items for this order.</p>
<?php else: ?>
<div id="existing-order-items-container" class="space-y-6">
<?php foreach ($order_items as $item): ?>
<?php
// Skip items marked for deletion during POST
if (in_array($item['id'], $deleted_existing_item_ids)) {
continue;
}
?>
<div class="bg-light-grey p-6 rounded-lg shadow-custom">
<input type="hidden" name="existing_item_id[]" value="<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<div class="grid grid-cols-1 md:grid-cols-5 gap-6">
<div>
<label for="product_id_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Product <span class="text-accent-red">*</span></label>
<select name="product_id[]" id="product_id_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Product</option>
<?php foreach($products as $product_option): ?>
<option value="<?= htmlspecialchars($product_option['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" <?= (($product_option['id'] ?? '') == ($item['product_id'] ?? '')) ? 'selected' : '' ?>>
<?= htmlspecialchars($product_option['name'] . " - " . $product_option['size'] . " (" . number_format($product_option['price'], 2) . " KD)", ENT_QUOTES, 'UTF-8') ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="quantity_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Quantity <span class="text-accent-red">*</span></label>
<input type="number" name="quantity[]" id="quantity_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" min="1" required
value="<?= htmlspecialchars($item['quantity'] ?? '1', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="packaging_preferences_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Packaging Preferences</label>
<input type="text" name="packaging_preferences[]" id="packaging_preferences_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" placeholder="e.g., Gift Wrap"
value="<?= htmlspecialchars($item['packaging_preferences'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="discount_percentage_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Discount (%)</label>
<input type="number" name="discount_percentage[]" id="discount_percentage_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" min="0" max="100" step="0.01" value="<?= htmlspecialchars($item['discount_percentage'] ?? '0.00', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div class="flex items-end">
<button type="button" class="bg-accent-red text-white rounded-full h-10 w-10 hover:bg-red-600 transition duration-300" onclick="removeExistingOrderItemRow(this)" title="Remove Product">
×
</button>
</div>
</div>
<div class="mt-4">
<label for="discount_reason_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" class="block text-sm font-medium text-dark-grey">Discount Reason</label>
<input type="text" name="discount_reason[]" id="discount_reason_<?= htmlspecialchars($item['id'] ?? '', ENT_QUOTES, 'UTF-8') ?>" placeholder="e.g., Seasonal Sale"
value="<?= htmlspecialchars($item['discount_reason'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- Hidden inputs to track deleted items -->
<input type="hidden" name="deleted_existing_item_ids" id="deleted_existing_item_ids" value="<?= htmlspecialchars(implode(',', $deleted_existing_item_ids) ?? '', ENT_QUOTES, 'UTF-8') ?>">
</section>
<hr class="border-light-grey">
<!-- Add New Order Items -->
<section>
<h3 class="text-xl font-semibold text-dark-grey mb-4">Add New Order Items</h3>
<div id="order-items-container" class="space-y-6">
<!-- New Order Item Rows will be added here dynamically -->
</div>
<button type="button" class="flex items-center bg-accent-soft-blue text-accent-purple px-4 py-2 rounded-lg shadow-custom hover:bg-accent-blue hover:text-white transition duration-300 mt-4"
onclick="addOrderItemRow()">
<i class="bi bi-plus-circle-fill mr-2"></i> Add Another Product
</button>
</section>
<!-- Submit Buttons -->
<div class="flex justify-between mt-8">
<button type="submit" class="bg-accent-teal text-white px-6 py-3 rounded-lg shadow-custom hover:bg-accent-blue transition duration-300 font-semibold flex items-center">
<i class="bi bi-pencil-square mr-2"></i> Update Order
</button>
<a href="view_orders.php" class="bg-accent-soft-blue text-accent-purple px-6 py-3 rounded-lg shadow-custom hover:bg-accent-blue hover:text-white transition duration-300 font-semibold flex items-center">
<i class="bi bi-x-circle-fill mr-2"></i> Cancel
</a>
</div>
</form>
</div>
</main>
<!-- Footer -->
<footer class="bg-charcoal text-white text-center p-5 rounded-custom shadow-custom mt-10">
© <?= date("Y") ?> Kaak Alia Bakery. All rights reserved.
</footer>
<!-- Flatpickr JS for Date Picker -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<!-- Tailwind CSS Custom Scripts -->
<script>
// Function to add new order item row
function addOrderItemRow() {
const orderItemsContainer = document.getElementById('order-items-container');
const itemCount = orderItemsContainer.children.length;
const orderItemRow = document.createElement('div');
orderItemRow.className = 'bg-light-grey p-6 rounded-lg shadow-custom';
orderItemRow.innerHTML = `
<div class="grid grid-cols-1 md:grid-cols-5 gap-6">
<div>
<label for="new_product_id_${itemCount}" class="block text-sm font-medium text-dark-grey">Product <span class="text-accent-red">*</span></label>
<select name="new_product_id[]" id="new_product_id_${itemCount}" required
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
<option value="">Select Product</option>
${getProductOptions()}
</select>
</div>
<div>
<label for="new_quantity_${itemCount}" class="block text-sm font-medium text-dark-grey">Quantity <span class="text-accent-red">*</span></label>
<input type="number" name="new_quantity[]" id="new_quantity_${itemCount}" min="1" required value="1"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="new_packaging_preferences_${itemCount}" class="block text-sm font-medium text-dark-grey">Packaging Preferences</label>
<input type="text" name="new_packaging_preferences[]" id="new_packaging_preferences_${itemCount}" placeholder="e.g., Gift Wrap"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div>
<label for="new_discount_percentage_${itemCount}" class="block text-sm font-medium text-dark-grey">Discount (%)</label>
<input type="number" name="new_discount_percentage[]" id="new_discount_percentage_${itemCount}" min="0" max="100" step="0.01" value="0.00"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
<div class="flex items-end">
<button type="button" class="bg-accent-red text-white rounded-full h-10 w-10 hover:bg-red-600 transition duration-300" onclick="removeOrderItemRow(this)" title="Remove Product">
×
</button>
</div>
</div>
<div class="mt-4">
<label for="new_discount_reason_${itemCount}" class="block text-sm font-medium text-dark-grey">Discount Reason</label>
<input type="text" name="new_discount_reason[]" id="new_discount_reason_${itemCount}" placeholder="e.g., Seasonal Sale"
class="mt-1 block w-full rounded-lg border border-medium-grey p-3 focus:border-accent-teal focus:ring-accent-teal">
</div>
`;
orderItemsContainer.appendChild(orderItemRow);
}
// Function to get product options as a string (to avoid embedding PHP in JS)
function getProductOptions() {
// Fetch products data from a PHP variable encoded as JSON
const products = <?= json_encode($products, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>;
let options = '<option value="">Select Product</option>';
products.forEach(product => {
options += `<option value="${product.id}">${escapeHtml(product.name)} - ${escapeHtml(product.size)} (${parseFloat(product.price).toFixed(2)} KD)</option>`;
});
return options;
}
// Function to escape HTML special characters (to prevent XSS)
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
// Function to remove new order item row
function removeOrderItemRow(button) {
const orderItemRow = button.closest('.bg-light-grey');
orderItemRow.remove();
}
// Function to remove existing order item row and mark it for deletion
function removeExistingOrderItemRow(button) {
const orderItemRow = button.closest('.bg-light-grey');
const deletedIdsContainer = document.getElementById('deleted_existing_item_ids');
// Find the existing_item_id for this row
const existingItemId = orderItemRow.querySelector('input[name="existing_item_id[]"]').value;
if (existingItemId) {
// Append the ID to the deleted_existing_item_ids array
if (deletedIdsContainer.value === '') {
deletedIdsContainer.value = existingItemId;
} else {
deletedIdsContainer.value += ',' + existingItemId;
}
}
// Remove the row from the UI
orderItemRow.remove();
}
// Function to toggle delivery fee input based on free shipping checkbox
function toggleDeliveryFee() {
const freeShippingCheckbox = document.getElementById('free_shipping');
const deliveryFeeInput = document.getElementById('delivery_fee');
if (freeShippingCheckbox.checked) {
deliveryFeeInput.value = '0.00';
deliveryFeeInput.disabled = true;
} else {
deliveryFeeInput.disabled = false;
}
}
// Toggle specific delivery details based on pickup checkbox
function togglePickup() {
const pickupCheckbox = document.getElementById('pickup');
const freeShippingCheckbox = document.getElementById('free_shipping');
const deliveryFeeInput = document.getElementById('delivery_fee');
const deliveryFeeField = document.getElementById('delivery_fee_field');
const freeShippingField = document.getElementById('free_shipping_field');
const deliveryAddressField = document.getElementById('delivery_address');
if (pickupCheckbox.checked) {
// Hide Delivery Address
deliveryAddressField.style.display = 'none';
// Uncheck and disable Free Shipping
if (freeShippingCheckbox.checked) {
freeShippingCheckbox.checked = false;
toggleDeliveryFee();
}
// Hide Free Shipping Field
freeShippingField.style.display = 'none';
// Disable and hide Delivery Fee
deliveryFeeInput.value = '0.00';
deliveryFeeInput.disabled = true;
deliveryFeeField.style.display = 'none';
} else {
// Show Delivery Address
deliveryAddressField.style.display = 'block';
// Show Free Shipping Field
freeShippingField.style.display = 'flex';
// Show Delivery Fee based on Free Shipping status
toggleDeliveryFee();
// Show Delivery Fee Field
deliveryFeeField.style.display = 'block';
}
}
// Auto-generate Customer Name based on Contact Number (optional, based on your requirements)
function autoGenerateCustomerName() {
const contactInput = document.getElementById('contact');
const customerNameInput = document.getElementById('customer_name');
// Extract digits from contact number
const digits = contactInput.value.replace(/\D/g, '');
if (digits.length > 0) {
customerNameInput.value = 'Order_' + digits;
} else {
customerNameInput.value = '';
}
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
// Initialize delivery fee toggle
toggleDeliveryFee();
const freeShippingEl = document.getElementById('free_shipping');
if (freeShippingEl) {
freeShippingEl.addEventListener('change', toggleDeliveryFee);
}
// Initialize pickup toggle
togglePickup();
const pickupEl = document.getElementById('pickup');
if (pickupEl) {
pickupEl.addEventListener('change', togglePickup);
}
// Initialize Customer Name auto-generation if needed
const contactEl = document.getElementById('contact');
if (contactEl) {
contactEl.addEventListener('input', autoGenerateCustomerName);
}
// Initialize Flatpickr for date and datetime fields
flatpickr("#delivery_datetime", {
enableTime: true,
dateFormat: "Y-m-d\\TH:i",
minDate: "today"
});
flatpickr("#delivery_date", {
dateFormat: "Y-m-d",
minDate: "today"
});
});
</script>
</body>
</html>
<?php
// Flush the output buffer
ob_end_flush();
// No closing PHP tag to prevent unwanted output
?>
```
---
## Explanation of Changes
1. **Handling the `pickup` Checkbox:**
- **Issue:** The `pickup` checkbox state was being initialized from the existing order data (`$order['pickup']`) and not being updated based on the form submission (`$_POST`). As a result, unchecking the `pickup` checkbox did not reflect in the database.
- **Solution:**
- **Retrieve `pickup` from `$_POST`:** After reading the `is_paid` field from the form, the `pickup` value is now correctly retrieved from the `$_POST` data. This ensures that the state of the `pickup` checkbox (checked or unchecked) is properly captured.
- **Code Changes:**
```php
// Read 'pickup' from POST data
$pickup = isset($_POST['pickup']) ? 1 : 0;
```
- **Initialization of `$pickup`:** If the form is not submitted (`$_SERVER['REQUEST_METHOD'] !== 'POST'`), the `$pickup` variable is set based on the existing order data. This ensures that the checkbox reflects the current state when the form is first loaded.
```php
// Define $pickup based on either POST data or existing order data
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$pickup = intval($order['pickup']);
}
```
2. **Sanitizing Inputs to Prevent `htmlspecialchars` Errors:**
- **Issue:** There were PHP deprecation warnings in the `order_items` data related to passing `NULL` to the `htmlspecialchars` function. This likely occurs when `sanitize_input` is called with `NULL` values.
- **Solution:**
- **Update `sanitize_input` Function:** Ensure that the `sanitize_input` function in your `functions.php` handles `NULL` values gracefully by defaulting them to empty strings. Here's an example of how you can modify the function:
```php
function sanitize_input($data) {
return htmlspecialchars(trim($data ?? ''), ENT_QUOTES, 'UTF-8');
}
```
- **Explanation:** The `??` operator checks if `$data` is `NULL` and replaces it with an empty string if it is. This prevents `htmlspecialchars` from receiving `NULL` and eliminates the deprecated warnings.
3. **Ensuring Form Validation Correctly Reflects Product Selection:**
- **Issue:** The original validation logic checks if either existing items are selected and not deleted or new products are added. However, it wasn't correctly handling scenarios where all existing items are deleted and no new items are added.
- **Solution:**
- **Update Validation Logic:** Modify the basic validation to ensure that at least one product is selected, whether it's an existing item that's not deleted or a new product being added. The updated validation condition is as follows:
```php
if (empty(array_diff($existing_item_ids, $deleted_existing_item_ids)) && empty($new_product_ids)) {
$errors[] = "At least one product must be selected.";
}
```
- **Explanation:** This condition checks whether all existing items have been deleted (`array_diff` returns empty) and no new products have been added. If both are true, it adds a validation error.
4. **General Code Cleanup and Enhancements:**
- **Consistent Use of `sanitize_input`:** Ensure that all user inputs are sanitized using the `sanitize_input` function to prevent XSS and other security vulnerabilities.
- **Proper Handling of Form States:** The JavaScript functions are updated to handle the UI changes when the `pickup` or `free_shipping` checkboxes are toggled, ensuring that the form behaves correctly based on user interactions.
- **User Feedback:** Success and error messages are clearly displayed to inform the user about the status of their actions.
---
## Additional Recommendations
1. **Update `sanitize_input` Function:**
Ensure that your `sanitize_input` function in `functions.php` gracefully handles `NULL` values to prevent deprecated warnings. Here's an example implementation:
```php
<?php
// includes/functions.php
function sanitize_input($data) {
return htmlspecialchars(trim($data ?? ''), ENT_QUOTES, 'UTF-8');
}
?>
```
This modification ensures that even if `NULL` is passed to the function, it defaults to an empty string, preventing errors.
2. **Test Thoroughly:**
After implementing the changes, thoroughly test the form by:
- Checking and unchecking the `pickup` checkbox and verifying that the changes reflect in the database.
- Adding, updating, and deleting order items to ensure all functionalities work as expected.
- Ensuring that validation errors are appropriately handled and displayed.
3. **Disable Error Reporting in Production:**
While error reporting is enabled for debugging purposes, it's recommended to disable it in a production environment to prevent sensitive information from being exposed to users.
```php
// Disable error reporting in production
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(0);
```
Consider using a logging mechanism to capture errors without displaying them to end-users.
4. **Use Prepared Statements Everywhere:**
Ensure that all database interactions use prepared statements to prevent SQL injection attacks. Although your current code uses prepared statements for most queries, double-check all database operations for consistency.
5. **Review and Clean Existing Data:**
Given that there are already entries in the `order_items` table with PHP error messages in the `discount_reason` field, consider cleaning the existing data to remove these error messages:
```sql
UPDATE order_items
SET discount_reason = ''
WHERE discount_reason LIKE '%htmlspecialchars(): Passing null%';
```
This SQL command will clear any `discount_reason` that contains the specific PHP error message.
---
By implementing these changes, your `pickup` checkbox should function correctly, allowing you to update the order's pickup status as intended. Additionally, ensuring that your sanitization functions handle `NULL` values will prevent deprecated warnings and enhance the overall security of your application.