浏览代码

implementing backorder functionality

Medowar 2 月之前
父节点
当前提交
9e9585aeab
共有 10 个文件被更改,包括 676 次插入135 次删除
  1. 195 0
      admin/backorders.php
  2. 8 3
      admin/index.php
  3. 5 0
      admin/reservations.php
  4. 6 0
      assets/css/style.css
  5. 2 2
      cart.php
  6. 83 26
      checkout.php
  7. 218 1
      includes/functions.php
  8. 2 4
      index.php
  9. 44 47
      product.php
  10. 113 52
      reservation.php

+ 195 - 0
admin/backorders.php

@@ -0,0 +1,195 @@
+<?php
+require_once __DIR__ . '/../config.php';
+require_once __DIR__ . '/../includes/functions.php';
+
+// Check admin login
+if (!isset($_SESSION['admin_logged_in']) || !$_SESSION['admin_logged_in']) {
+    header('Location: login.php');
+    exit;
+}
+
+$pageTitle = 'Nachbestellungen verwalten';
+
+// Handle availability notification
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['notify_available'])) {
+    $reservationId = sanitize($_POST['reservation_id']);
+    $result = markBackorderAvailable($reservationId);
+    $message = $result['success'] ? 'Kunde wurde über die Verfügbarkeit informiert.' : $result['message'];
+    $messageType = $result['success'] ? 'success' : 'error';
+}
+
+$reservations = getReservations();
+$filter = isset($_GET['filter']) ? sanitize($_GET['filter']) : 'pending';
+$searchCode = isset($_GET['code']) ? sanitize($_GET['code']) : '';
+
+// Filter backorders
+$reservations = array_filter($reservations, function($r) {
+    return isset($r['type']) && $r['type'] === 'backorder';
+});
+
+if ($searchCode) {
+    $reservations = array_filter($reservations, function($r) use ($searchCode) {
+        return stripos($r['code'], $searchCode) !== false || stripos($r['id'], $searchCode) !== false;
+    });
+} else {
+    switch ($filter) {
+        case 'notified':
+            $reservations = array_filter($reservations, function($r) {
+                return isset($r['backorder_status']) && $r['backorder_status'] === 'notified';
+            });
+            break;
+        case 'pending':
+            $reservations = array_filter($reservations, function($r) {
+                return !isset($r['backorder_status']) || $r['backorder_status'] !== 'notified';
+            });
+            break;
+    }
+}
+
+$reservations = array_reverse($reservations); // Newest first
+
+include __DIR__ . '/../includes/header.php';
+?>
+
+<div class="admin-header">
+    <h2>Nachbestellungen verwalten</h2>
+    <div>
+        <a href="index.php" class="btn btn-secondary">Zurück zum Dashboard</a>
+    </div>
+</div>
+
+<?php if (isset($message)): ?>
+    <div class="alert alert-<?php echo $messageType; ?>">
+        <?php echo htmlspecialchars($message); ?>
+    </div>
+<?php endif; ?>
+
+<div style="background: white; padding: 1.5rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 2rem;">
+    <form method="GET" style="display: flex; gap: 1rem; align-items: end; flex-wrap: wrap;">
+        <div style="flex: 1; min-width: 200px;">
+            <label for="code">Code/ID suchen:</label>
+            <input type="text" id="code" name="code" value="<?php echo htmlspecialchars($searchCode); ?>" placeholder="Abholcode oder Nachbestellungsnummer">
+        </div>
+        <div>
+            <label for="filter">Filter:</label>
+            <select id="filter" name="filter">
+                <option value="pending" <?php echo $filter === 'pending' ? 'selected' : ''; ?>>Offen</option>
+                <option value="notified" <?php echo $filter === 'notified' ? 'selected' : ''; ?>>Informiert</option>
+                <option value="all" <?php echo $filter === 'all' ? 'selected' : ''; ?>>Alle</option>
+            </select>
+        </div>
+        <div>
+            <button type="submit" class="btn">Filtern</button>
+            <a href="backorders.php" class="btn btn-secondary">Zurücksetzen</a>
+        </div>
+    </form>
+</div>
+
+<?php if (empty($reservations)): ?>
+    <div class="alert alert-info">
+        <p>Keine Nachbestellungen gefunden.</p>
+    </div>
+<?php else: ?>
+    <table>
+        <thead>
+            <tr>
+                <th>Code</th>
+                <th>Kunde</th>
+                <th>E-Mail</th>
+                <th>Artikel</th>
+                <th>Erstellt</th>
+                <th>Status</th>
+                <th>Aktionen</th>
+            </tr>
+        </thead>
+        <tbody>
+            <?php foreach ($reservations as $reservation): ?>
+                <tr>
+                    <td><strong><?php echo htmlspecialchars($reservation['code']); ?></strong></td>
+                    <td><?php echo htmlspecialchars($reservation['customer_name']); ?></td>
+                    <td><?php echo htmlspecialchars($reservation['customer_email']); ?></td>
+                    <td>
+                        <?php
+                        $itemCount = 0;
+                        foreach ($reservation['items'] as $item) {
+                            $itemCount += $item['quantity'];
+                        }
+                        echo $itemCount . ' Artikel';
+                        ?>
+                    </td>
+                    <td><?php echo formatDate($reservation['created']); ?></td>
+                    <td>
+                        <?php
+                        if (isset($reservation['backorder_status']) && $reservation['backorder_status'] === 'notified') {
+                            echo '<span style="color: #28a745;">Informiert</span>';
+                        } else {
+                            echo '<span style="color: #ffc107;">Offen</span>';
+                        }
+                        ?>
+                    </td>
+                    <td>
+                        <?php if ((!isset($reservation['backorder_status']) || $reservation['backorder_status'] !== 'notified') && canFulfillReservationItems($reservation['items'])): ?>
+                            <form method="POST" style="display: inline;" onsubmit="return confirm('Kunde über Verfügbarkeit informieren?');">
+                                <input type="hidden" name="reservation_id" value="<?php echo htmlspecialchars($reservation['id']); ?>">
+                                <button type="submit" name="notify_available" class="btn btn-small">Verfügbarkeit melden</button>
+                            </form>
+                        <?php endif; ?>
+                        <button onclick="showDetails('<?php echo htmlspecialchars($reservation['id']); ?>')" class="btn btn-secondary btn-small">Details</button>
+                    </td>
+                </tr>
+            <?php endforeach; ?>
+        </tbody>
+    </table>
+<?php endif; ?>
+
+<!-- Details Modal -->
+<div id="detailsModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
+    <div style="background: white; padding: 2rem; border-radius: 8px; max-width: 600px; max-height: 80vh; overflow-y: auto; position: relative;">
+        <button onclick="closeDetails()" style="position: absolute; top: 1rem; right: 1rem; background: #dc3545; color: white; border: none; border-radius: 4px; padding: 0.5rem 1rem; cursor: pointer;">Schließen</button>
+        <div id="detailsContent"></div>
+    </div>
+</div>
+
+<script>
+function showDetails(reservationId) {
+    const reservations = <?php echo json_encode(getReservations()); ?>;
+    const reservation = reservations.find(r => r.id === reservationId);
+    
+    if (!reservation) return;
+    
+    let itemsHtml = '<h3>Artikel:</h3><ul>';
+    reservation.items.forEach(item => {
+        const product = <?php echo json_encode(getProducts()); ?>.find(p => p.id == item.product_id);
+        if (product) {
+            let sizeInfo = '';
+            if (item.size && item.size !== '') {
+                sizeInfo = ` - Größe: ${item.size}`;
+            }
+            itemsHtml += `<li>${product.name}${sizeInfo} - Menge: ${item.quantity}</li>`;
+        }
+    });
+    itemsHtml += '</ul>';
+    
+    const statusText = reservation.backorder_status === 'notified' ? 'Informiert' : 'Offen';
+    const html = `
+        <h2>Nachbestellungsdetails</h2>
+        <p><strong>Nachbestellungsnummer:</strong> ${reservation.id}</p>
+        <p><strong>Abholcode:</strong> <strong style="font-size: 1.5rem; color: #c41e3a;">${reservation.code}</strong></p>
+        <p><strong>Kunde:</strong> ${reservation.customer_name}</p>
+        <p><strong>E-Mail:</strong> ${reservation.customer_email}</p>
+        <p><strong>Erstellt:</strong> ${reservation.created}</p>
+        <p><strong>Status:</strong> ${statusText}</p>
+        ${itemsHtml}
+        <p><strong>Hinweis:</strong> Lieferung erfolgt in Chargen.</p>
+    `;
+    
+    document.getElementById('detailsContent').innerHTML = html;
+    document.getElementById('detailsModal').style.display = 'flex';
+}
+
+function closeDetails() {
+    document.getElementById('detailsModal').style.display = 'none';
+}
+</script>
+
+<?php include __DIR__ . '/../includes/footer.php'; ?>

+ 8 - 3
admin/index.php

@@ -18,15 +18,19 @@ $reservations = getReservations();
 expireOldReservations();
 $reservations = getReservations(); // Refresh after expiry
 
+$regularReservations = array_filter($reservations, function($r) {
+    return !isset($r['type']) || $r['type'] !== 'backorder';
+});
+
 $totalProducts = count($products);
 $totalStock = 0;
 foreach ($products as $product) {
     $totalStock += getTotalStock($product);
 }
-$openReservations = count(array_filter($reservations, function($r) {
+$openReservations = count(array_filter($regularReservations, function($r) {
     return $r['status'] === 'open' && !$r['picked_up'];
 }));
-$pickedUpReservations = count(array_filter($reservations, function($r) {
+$pickedUpReservations = count(array_filter($regularReservations, function($r) {
     return $r['picked_up'];
 }));
 
@@ -38,6 +42,7 @@ include __DIR__ . '/../includes/header.php';
     <div>
         <a href="products.php" class="btn">Produkte verwalten</a>
         <a href="reservations.php" class="btn">Reservierungen</a>
+        <a href="backorders.php" class="btn">Nachbestellungen</a>
         <a href="login.php?logout=1" class="btn btn-secondary">Abmelden</a>
     </div>
 </div>
@@ -66,7 +71,7 @@ include __DIR__ . '/../includes/header.php';
 
 <h3 style="margin-top: 2rem;">Letzte Reservierungen</h3>
 <?php
-$recentReservations = array_slice(array_reverse($reservations), 0, 5);
+$recentReservations = array_slice(array_reverse($regularReservations), 0, 5);
 if (empty($recentReservations)):
 ?>
     <p>Keine Reservierungen vorhanden.</p>

+ 5 - 0
admin/reservations.php

@@ -25,6 +25,11 @@ $reservations = getReservations();
 $filter = isset($_GET['filter']) ? sanitize($_GET['filter']) : 'all';
 $searchCode = isset($_GET['code']) ? sanitize($_GET['code']) : '';
 
+// Exclude backorders
+$reservations = array_filter($reservations, function($r) {
+    return !isset($r['type']) || $r['type'] !== 'backorder';
+});
+
 // Filter reservations
 if ($searchCode) {
     $reservations = array_filter($reservations, function($r) use ($searchCode) {

+ 6 - 0
assets/css/style.css

@@ -252,6 +252,12 @@ table tr:hover {
     border: 1px solid #bee5eb;
 }
 
+.alert-warning {
+    background-color: #fff3cd;
+    color: #856404;
+    border: 1px solid #ffeeba;
+}
+
 /* Footer */
 footer {
     background-color: #333;

+ 2 - 2
cart.php

@@ -93,7 +93,7 @@ include __DIR__ . '/includes/header.php';
                     <p class="stock <?php echo $hasEnoughStock ? 'in-stock' : 'out-of-stock'; ?>">
                         Lagerbestand: <?php echo $itemStock; ?> Stück
                         <?php if (!$hasEnoughStock): ?>
-                            <br><strong style="color: #dc3545;">Nicht genügend Lagerbestand!</strong>
+                            <br><strong style="color: #dc3545;">Nachbestellung möglich</strong>
                         <?php endif; ?>
                     </p>
                 </div>
@@ -103,7 +103,7 @@ include __DIR__ . '/includes/header.php';
                         <input type="number" name="quantities[<?php echo $cartItem['cart_index']; ?>]" 
                                value="<?php echo $cartItem['quantity']; ?>" 
                                min="0" 
-                               max="<?php echo $itemStock; ?>"
+                               max="999"
                                class="quantity-input">
                     </label>
                     <form method="POST" style="display: inline;">

+ 83 - 26
checkout.php

@@ -12,8 +12,12 @@ if (empty($cart)) {
 
 // Validate cart items and stock
 $cartItems = [];
+$regularItems = [];
+$backorderItems = [];
 $errors = [];
 $total = 0;
+$regularTotal = 0;
+$backorderTotal = 0;
 
 foreach ($cart as $item) {
     $product = getProductById($item['product_id']);
@@ -23,19 +27,20 @@ foreach ($cart as $item) {
     }
     
     $size = isset($item['size']) ? $item['size'] : null;
-    if (!checkStock($item['product_id'], $item['quantity'], $size)) {
-        $sizeInfo = $size ? " (Größe: $size)" : '';
-        $errors[] = 'Nicht genügend Lagerbestand für: ' . $product['name'] . $sizeInfo;
-        continue;
-    }
-    
     $itemTotal = $product['price'] * $item['quantity'];
     $total += $itemTotal;
+    $isInStock = checkStock($item['product_id'], $item['quantity'], $size);
+    if ($isInStock) {
+        $regularTotal += $itemTotal;
+    } else {
+        $backorderTotal += $itemTotal;
+    }
     $cartItems[] = [
         'product' => $product,
         'quantity' => $item['quantity'],
         'total' => $itemTotal,
-        'size' => isset($item['size']) ? $item['size'] : null
+        'size' => isset($item['size']) ? $item['size'] : null,
+        'in_stock' => $isInStock
     ];
 }
 
@@ -54,7 +59,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_reservation'])
     
     if (empty($errors)) {
         // Create reservation
-        $items = [];
+        $regularItems = [];
+        $backorderItems = [];
         foreach ($cart as $cartItem) {
             $item = [
                 'product_id' => $cartItem['product_id'],
@@ -63,19 +69,40 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_reservation'])
             if (isset($cartItem['size']) && !empty($cartItem['size'])) {
                 $item['size'] = $cartItem['size'];
             }
-            $items[] = $item;
+            
+            $size = isset($cartItem['size']) ? $cartItem['size'] : null;
+            if (checkStock($cartItem['product_id'], $cartItem['quantity'], $size)) {
+                $regularItems[] = $item;
+            } else {
+                $backorderItems[] = $item;
+            }
+        }
+        
+        $regularResult = null;
+        $backorderResult = null;
+        
+        if (!empty($regularItems)) {
+            $regularResult = createReservation($customerName, $customerEmail, $regularItems);
+            if (!$regularResult['success']) {
+                $errors[] = $regularResult['message'];
+            }
         }
         
-        $result = createReservation($customerName, $customerEmail, $items);
+        if (empty($errors) && !empty($backorderItems)) {
+            $backorderResult = createBackorderReservation($customerName, $customerEmail, $backorderItems);
+        }
         
-        if ($result['success']) {
-            // Clear cart
+        if (empty($errors)) {
             $_SESSION['cart'] = [];
-            // Redirect to reservation confirmation
-            header('Location: reservation.php?code=' . urlencode($result['reservation']['code']));
+            $query = [];
+            if ($regularResult && $regularResult['success']) {
+                $query[] = 'code=' . urlencode($regularResult['reservation']['code']);
+            }
+            if ($backorderResult && $backorderResult['success']) {
+                $query[] = 'backorder_code=' . urlencode($backorderResult['reservation']['code']);
+            }
+            header('Location: reservation.php?' . implode('&', $query));
             exit;
-        } else {
-            $errors[] = $result['message'];
         }
     }
 }
@@ -98,18 +125,49 @@ include __DIR__ . '/includes/header.php';
 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin-top: 2rem;">
     <div>
         <h3>Ihre Bestellung</h3>
-        <?php foreach ($cartItems as $cartItem): ?>
-            <div style="background: white; padding: 1rem; margin-bottom: 1rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
-                <strong><?php echo htmlspecialchars($cartItem['product']['name']); ?></strong><br>
-                <?php if (isset($cartItem['size']) && !empty($cartItem['size'])): ?>
-                    Größe: <?php echo htmlspecialchars($cartItem['size']); ?><br>
+        
+        <?php if ($regularTotal > 0): ?>
+            <h4 style="margin-top: 1rem;">Sofort verfügbar</h4>
+            <?php foreach ($cartItems as $cartItem): ?>
+                <?php if ($cartItem['in_stock']): ?>
+                <div style="background: white; padding: 1rem; margin-bottom: 1rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
+                    <strong><?php echo htmlspecialchars($cartItem['product']['name']); ?></strong><br>
+                    <?php if (isset($cartItem['size']) && !empty($cartItem['size'])): ?>
+                        Größe: <?php echo htmlspecialchars($cartItem['size']); ?><br>
+                    <?php endif; ?>
+                    Menge: <?php echo $cartItem['quantity']; ?><br>
+                    Preis: <?php echo formatPrice($cartItem['total']); ?>
+                </div>
                 <?php endif; ?>
-                Menge: <?php echo $cartItem['quantity']; ?><br>
-                Preis: <?php echo formatPrice($cartItem['total']); ?>
+            <?php endforeach; ?>
+        <?php endif; ?>
+        
+        <?php if ($backorderTotal > 0): ?>
+            <h4 style="margin-top: 1.5rem;">Nachbestellung</h4>
+            <div class="alert alert-warning" style="margin-bottom: 1rem;">
+                <strong>Hinweis:</strong> Lieferzeiten sind nicht bekannt, da die Bestellung in Chargen erfolgt.
             </div>
-        <?php endforeach; ?>
+            <?php foreach ($cartItems as $cartItem): ?>
+                <?php if (!$cartItem['in_stock']): ?>
+                <div style="background: white; padding: 1rem; margin-bottom: 1rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
+                    <strong><?php echo htmlspecialchars($cartItem['product']['name']); ?></strong><br>
+                    <?php if (isset($cartItem['size']) && !empty($cartItem['size'])): ?>
+                        Größe: <?php echo htmlspecialchars($cartItem['size']); ?><br>
+                    <?php endif; ?>
+                    Menge: <?php echo $cartItem['quantity']; ?><br>
+                    Preis: <?php echo formatPrice($cartItem['total']); ?>
+                </div>
+                <?php endif; ?>
+            <?php endforeach; ?>
+        <?php endif; ?>
         
         <div style="background: white; padding: 1rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-top: 1rem;">
+            <?php if ($regularTotal > 0): ?>
+                <div>Summe sofort verfügbar: <strong><?php echo formatPrice($regularTotal); ?></strong></div>
+            <?php endif; ?>
+            <?php if ($backorderTotal > 0): ?>
+                <div>Summe Nachbestellung: <strong><?php echo formatPrice($backorderTotal); ?></strong></div>
+            <?php endif; ?>
             <strong style="font-size: 1.2rem;">Gesamtsumme: <?php echo formatPrice($total); ?></strong>
         </div>
     </div>
@@ -130,8 +188,7 @@ include __DIR__ . '/includes/header.php';
             </div>
             
             <div class="alert alert-info">
-                <strong>Hinweis:</strong> Nach der Reservierung erhalten Sie einen Abholcode, den Sie bei der Abholung vorzeigen müssen. 
-                Die Reservierung ist <?php echo RESERVATION_EXPIRY_DAYS; ?> Tage gültig.
+                <strong>Hinweis:</strong> Nach der Reservierung erhalten Sie einen Abholcode. Für Nachbestellungen informieren wir Sie, sobald die komplette Bestellung verfügbar ist.
             </div>
             
             <button type="submit" name="create_reservation" class="btn" style="width: 100%;">Reservierung abschließen</button>

+ 218 - 1
includes/functions.php

@@ -263,7 +263,8 @@ function createReservation($customerName, $customerEmail, $items) {
         'created' => $now->format('Y-m-d H:i:s'),
         'expires' => $expires->format('Y-m-d H:i:s'),
         'status' => 'open',
-        'picked_up' => false
+        'picked_up' => false,
+        'type' => 'regular'
     ];
     
     $reservations[] = $reservation;
@@ -275,6 +276,37 @@ function createReservation($customerName, $customerEmail, $items) {
     return ['success' => true, 'reservation' => $reservation];
 }
 
+/**
+ * Create new backorder reservation
+ */
+function createBackorderReservation($customerName, $customerEmail, $items) {
+    $reservations = getReservations();
+    
+    $now = new DateTime();
+    
+    $reservation = [
+        'id' => generateReservationId(),
+        'code' => generateReservationCode(),
+        'customer_name' => $customerName,
+        'customer_email' => $customerEmail,
+        'items' => $items,
+        'created' => $now->format('Y-m-d H:i:s'),
+        'expires' => '',
+        'status' => 'open',
+        'picked_up' => false,
+        'type' => 'backorder',
+        'backorder_status' => 'pending'
+    ];
+    
+    $reservations[] = $reservation;
+    saveReservations($reservations);
+    
+    // Send confirmation emails
+    sendBackorderEmails($reservation);
+    
+    return ['success' => true, 'reservation' => $reservation];
+}
+
 /**
  * Mark reservation as picked up
  */
@@ -300,6 +332,12 @@ function expireOldReservations() {
     
     foreach ($reservations as &$reservation) {
         if ($reservation['status'] === 'open' && !$reservation['picked_up']) {
+            if (isset($reservation['type']) && $reservation['type'] === 'backorder') {
+                continue;
+            }
+            if (empty($reservation['expires'])) {
+                continue;
+            }
             $expires = new DateTime($reservation['expires']);
             if ($now > $expires) {
                 $reservation['status'] = 'expired';
@@ -318,6 +356,52 @@ function expireOldReservations() {
     }
 }
 
+/**
+ * Check if all items are in stock
+ */
+function canFulfillReservationItems($items) {
+    foreach ($items as $item) {
+        $size = isset($item['size']) ? $item['size'] : null;
+        if (!checkStock($item['product_id'], $item['quantity'], $size)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * Mark backorder as available
+ */
+function markBackorderAvailable($reservationId) {
+    $reservations = getReservations();
+    foreach ($reservations as &$reservation) {
+        if ($reservation['id'] === $reservationId) {
+            if (!isset($reservation['type']) || $reservation['type'] !== 'backorder') {
+                return ['success' => false, 'message' => 'Diese Reservierung ist keine Nachbestellung.'];
+            }
+            if (isset($reservation['backorder_status']) && $reservation['backorder_status'] === 'notified') {
+                return ['success' => false, 'message' => 'Diese Nachbestellung wurde bereits informiert.'];
+            }
+            if (!canFulfillReservationItems($reservation['items'])) {
+                return ['success' => false, 'message' => 'Nicht alle Artikel sind verfügbar.'];
+            }
+            
+            foreach ($reservation['items'] as $item) {
+                $size = isset($item['size']) ? $item['size'] : null;
+                allocateStock($item['product_id'], $item['quantity'], $size);
+            }
+            
+            $reservation['backorder_status'] = 'notified';
+            saveReservations($reservations);
+            
+            sendBackorderAvailableEmail($reservation);
+            
+            return ['success' => true, 'reservation' => $reservation];
+        }
+    }
+    return ['success' => false, 'message' => 'Nachbestellung nicht gefunden.'];
+}
+
 /**
  * Sanitize input
  */
@@ -442,3 +526,136 @@ function sendReservationEmails($reservation) {
     
     sendEmail(ADMIN_EMAIL, $adminSubject, $adminMessage);
 }
+
+/**
+ * Send backorder confirmation emails
+ */
+function sendBackorderEmails($reservation) {
+    // Build items list
+    $itemsHtml = '<ul>';
+    foreach ($reservation['items'] as $item) {
+        $product = getProductById($item['product_id']);
+        if ($product) {
+            $sizeInfo = '';
+            if (isset($item['size']) && !empty($item['size'])) {
+                $sizeInfo = ' - Größe: ' . htmlspecialchars($item['size']);
+            }
+            $itemsHtml .= '<li>' . htmlspecialchars($product['name']) . $sizeInfo . ' - Menge: ' . $item['quantity'] . '</li>';
+        }
+    }
+    $itemsHtml .= '</ul>';
+    
+    // Customer email
+    $customerSubject = 'Nachbestellung bei ' . SITE_NAME;
+    $customerMessage = '
+    <html>
+    <head>
+        <meta charset="UTF-8">
+    </head>
+    <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
+        <h2 style="color: #c41e3a;">Nachbestellung bestätigt</h2>
+        <p>Sehr geehrte/r ' . htmlspecialchars($reservation['customer_name']) . ',</p>
+        <p>vielen Dank für Ihre Nachbestellung bei ' . SITE_NAME . '.</p>
+        
+        <div style="background: #fff3cd; border: 2px solid #ffc107; padding: 1.5rem; margin: 1.5rem 0; border-radius: 8px; text-align: center;">
+            <h3 style="margin-top: 0;">Ihr Abholcode:</h3>
+            <h2 style="font-size: 2rem; letter-spacing: 0.2rem; color: #856404; font-family: monospace;">' . htmlspecialchars($reservation['code']) . '</h2>
+        </div>
+        
+        <h3>Nachbestellungsdetails:</h3>
+        <p><strong>Nachbestellungsnummer:</strong> ' . htmlspecialchars($reservation['id']) . '</p>
+        <p><strong>Erstellt am:</strong> ' . formatDate($reservation['created']) . '</p>
+        
+        <h3>Nachbestellte Artikel:</h3>
+        ' . $itemsHtml . '
+        
+        <div style="background: #f8d7da; border: 2px solid #f5c6cb; padding: 1.5rem; margin: 1.5rem 0; border-radius: 8px;">
+            <strong>Hinweis:</strong> Die Lieferzeiten sind nicht bekannt, da die Bestellung in Chargen erfolgt.
+        </div>
+        
+        <p>Wir informieren Sie, sobald die komplette Nachbestellung verfügbar ist.</p>
+        
+        <p>Mit freundlichen Grüßen<br>' . SITE_NAME . '</p>
+    </body>
+    </html>';
+    
+    sendEmail($reservation['customer_email'], $customerSubject, $customerMessage);
+    
+    // Admin email
+    $adminSubject = 'Neue Nachbestellung: ' . $reservation['code'];
+    $adminMessage = '
+    <html>
+    <head>
+        <meta charset="UTF-8">
+    </head>
+    <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
+        <h2 style="color: #c41e3a;">Neue Nachbestellung</h2>
+        <p>Eine neue Nachbestellung wurde erstellt:</p>
+        
+        <div style="background: #d1ecf1; border: 2px solid #bee5eb; padding: 1.5rem; margin: 1.5rem 0; border-radius: 8px;">
+            <h3 style="margin-top: 0;">Abholcode:</h3>
+            <h2 style="font-size: 2rem; letter-spacing: 0.2rem; color: #0c5460; font-family: monospace;">' . htmlspecialchars($reservation['code']) . '</h2>
+        </div>
+        
+        <h3>Kundendaten:</h3>
+        <p><strong>Name:</strong> ' . htmlspecialchars($reservation['customer_name']) . '</p>
+        <p><strong>E-Mail:</strong> ' . htmlspecialchars($reservation['customer_email']) . '</p>
+        
+        <h3>Nachbestellungsdetails:</h3>
+        <p><strong>Nachbestellungsnummer:</strong> ' . htmlspecialchars($reservation['id']) . '</p>
+        <p><strong>Erstellt am:</strong> ' . formatDate($reservation['created']) . '</p>
+        
+        <h3>Nachbestellte Artikel:</h3>
+        ' . $itemsHtml . '
+        
+        <p><strong>Hinweis:</strong> Lieferzeiten sind nicht bekannt, Bestellung in Chargen.</p>
+    </body>
+    </html>';
+    
+    sendEmail(ADMIN_EMAIL, $adminSubject, $adminMessage);
+}
+
+/**
+ * Send backorder availability email
+ */
+function sendBackorderAvailableEmail($reservation) {
+    $itemsHtml = '<ul>';
+    foreach ($reservation['items'] as $item) {
+        $product = getProductById($item['product_id']);
+        if ($product) {
+            $sizeInfo = '';
+            if (isset($item['size']) && !empty($item['size'])) {
+                $sizeInfo = ' - Größe: ' . htmlspecialchars($item['size']);
+            }
+            $itemsHtml .= '<li>' . htmlspecialchars($product['name']) . $sizeInfo . ' - Menge: ' . $item['quantity'] . '</li>';
+        }
+    }
+    $itemsHtml .= '</ul>';
+    
+    $subject = 'Ihre Nachbestellung ist verfügbar';
+    $message = '
+    <html>
+    <head>
+        <meta charset="UTF-8">
+    </head>
+    <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
+        <h2 style="color: #28a745;">Nachbestellung verfügbar</h2>
+        <p>Sehr geehrte/r ' . htmlspecialchars($reservation['customer_name']) . ',</p>
+        <p>Ihre komplette Nachbestellung ist jetzt verfügbar.</p>
+        
+        <div style="background: #d4edda; border: 2px solid #c3e6cb; padding: 1.5rem; margin: 1.5rem 0; border-radius: 8px; text-align: center;">
+            <h3 style="margin-top: 0;">Ihr Abholcode:</h3>
+            <h2 style="font-size: 2rem; letter-spacing: 0.2rem; color: #155724; font-family: monospace;">' . htmlspecialchars($reservation['code']) . '</h2>
+        </div>
+        
+        <h3>Verfügbare Artikel:</h3>
+        ' . $itemsHtml . '
+        
+        <p>Bitte bringen Sie den Abholcode zur Abholung mit.</p>
+        
+        <p>Mit freundlichen Grüßen<br>' . SITE_NAME . '</p>
+    </body>
+    </html>';
+    
+    sendEmail($reservation['customer_email'], $subject, $message);
+}

+ 2 - 4
index.php

@@ -49,12 +49,10 @@ include __DIR__ . '/includes/header.php';
                         <?php if ($totalStock > 0): ?>
                             Verfügbar (<?php echo $totalStock; ?> Stück)
                         <?php else: ?>
-                            Ausverkauft
+                            Ausverkauft - Nachbestellung möglich
                         <?php endif; ?>
                     </div>
-                    <?php if ($totalStock > 0): ?>
-                        <a href="product.php?id=<?php echo $product['id']; ?>" class="btn" style="width: 100%; text-align: center; margin-top: 1rem;">Details ansehen</a>
-                    <?php endif; ?>
+                    <a href="product.php?id=<?php echo $product['id']; ?>" class="btn" style="width: 100%; text-align: center; margin-top: 1rem;">Details ansehen</a>
                 </div>
             </div>
         <?php endforeach; ?>

+ 44 - 47
product.php

@@ -22,9 +22,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_to_cart'])) {
         $error = 'Bitte wählen Sie eine Größe aus.';
     } elseif ($quantity < 1) {
         $error = 'Menge muss mindestens 1 sein.';
-    } elseif (!checkStock($productId, $quantity, $size)) {
-        $sizeInfo = $size ? " für Größe $size" : '';
-        $error = "Nicht genügend Lagerbestand verfügbar$sizeInfo.";
     } else {
         // Add to session cart
         if (!isset($_SESSION['cart'])) {
@@ -118,7 +115,7 @@ include __DIR__ . '/includes/header.php';
                     Verfügbar (<?php echo $totalStock; ?> Stück)
                 <?php endif; ?>
             <?php else: ?>
-                Ausverkauft
+                Ausverkauft - Nachbestellung möglich
             <?php endif; ?>
         </div>
         
@@ -127,53 +124,53 @@ include __DIR__ . '/includes/header.php';
             <p style="margin-top: 0.5rem; line-height: 1.8;"><?php echo nl2br(htmlspecialchars($product['description'])); ?></p>
         </div>
         
-        <?php if ($hasStock): ?>
-            <form method="POST" style="margin-top: 2rem;">
-                <?php if ($product['category'] === 'apparel' && !empty($product['sizes'])): ?>
-                    <div class="form-group">
-                        <label for="size">Größe *</label>
-                        <select id="size" name="size" required style="width: 100%;" onchange="updateMaxQuantity()">
-                            <option value="">Bitte wählen</option>
-                            <?php 
-                            $sizes = is_array($product['sizes']) ? $product['sizes'] : explode(',', $product['sizes']);
-                            $stockBySize = isset($product['stock_by_size']) && is_array($product['stock_by_size']) ? $product['stock_by_size'] : [];
-                            foreach ($sizes as $sizeOption): 
-                                $sizeOption = trim($sizeOption);
-                                $sizeStock = isset($stockBySize[$sizeOption]) ? (int)$stockBySize[$sizeOption] : 0;
-                            ?>
-                                <option value="<?php echo htmlspecialchars($sizeOption); ?>" data-stock="<?php echo $sizeStock; ?>" <?php echo $sizeStock <= 0 ? 'disabled' : ''; ?>>
-                                    <?php echo htmlspecialchars($sizeOption); ?><?php echo $sizeStock <= 0 ? ' (Ausverkauft)' : " ($sizeStock verfügbar)"; ?>
-                                </option>
-                            <?php endforeach; ?>
-                        </select>
-                    </div>
-                <?php endif; ?>
+        <form method="POST" style="margin-top: 2rem;">
+            <?php if ($product['category'] === 'apparel' && !empty($product['sizes'])): ?>
                 <div class="form-group">
-                    <label for="quantity">Menge:</label>
-                    <input type="number" id="quantity" name="quantity" value="1" min="1" max="<?php echo $totalStock; ?>" class="quantity-input" style="width: 100px;">
+                    <label for="size">Größe *</label>
+                    <select id="size" name="size" required style="width: 100%;" onchange="updateMaxQuantity()">
+                        <option value="">Bitte wählen</option>
+                        <?php 
+                        $sizes = is_array($product['sizes']) ? $product['sizes'] : explode(',', $product['sizes']);
+                        $stockBySize = isset($product['stock_by_size']) && is_array($product['stock_by_size']) ? $product['stock_by_size'] : [];
+                        foreach ($sizes as $sizeOption): 
+                            $sizeOption = trim($sizeOption);
+                            $sizeStock = isset($stockBySize[$sizeOption]) ? (int)$stockBySize[$sizeOption] : 0;
+                        ?>
+                            <option value="<?php echo htmlspecialchars($sizeOption); ?>" data-stock="<?php echo $sizeStock; ?>">
+                                <?php echo htmlspecialchars($sizeOption); ?><?php echo $sizeStock <= 0 ? ' (Ausverkauft - Nachbestellung möglich)' : " ($sizeStock verfügbar)"; ?>
+                            </option>
+                        <?php endforeach; ?>
+                    </select>
                 </div>
-                <button type="submit" name="add_to_cart" class="btn" style="width: 100%;">In den Warenkorb</button>
-            </form>
-            <?php if ($product['category'] === 'apparel' && !empty($product['sizes'])): ?>
-            <script>
-                function updateMaxQuantity() {
-                    const sizeSelect = document.getElementById('size');
-                    const quantityInput = document.getElementById('quantity');
-                    const selectedOption = sizeSelect.options[sizeSelect.selectedIndex];
-                    if (selectedOption && selectedOption.value) {
-                        const stock = parseInt(selectedOption.getAttribute('data-stock')) || 0;
-                        quantityInput.max = stock;
-                        if (parseInt(quantityInput.value) > stock) {
-                            quantityInput.value = stock > 0 ? stock : 1;
-                        }
-                    }
-                }
-            </script>
             <?php endif; ?>
-        <?php else: ?>
-            <div class="alert alert-error">
-                Dieses Produkt ist derzeit nicht verfügbar.
+            <div class="form-group">
+                <label for="quantity">Menge:</label>
+                <input type="number" id="quantity" name="quantity" value="1" min="1" max="<?php echo $hasStock ? $totalStock : 999; ?>" class="quantity-input" style="width: 100px;">
             </div>
+            <?php if (!$hasStock): ?>
+                <div class="alert alert-warning">
+                    <strong>Hinweis:</strong> Dieses Produkt wird nachbestellt. Lieferzeiten sind nicht bekannt.
+                </div>
+            <?php endif; ?>
+            <button type="submit" name="add_to_cart" class="btn" style="width: 100%;">In den Warenkorb</button>
+        </form>
+        <?php if ($product['category'] === 'apparel' && !empty($product['sizes'])): ?>
+        <script>
+            function updateMaxQuantity() {
+                const sizeSelect = document.getElementById('size');
+                const quantityInput = document.getElementById('quantity');
+                const selectedOption = sizeSelect.options[sizeSelect.selectedIndex];
+                if (selectedOption && selectedOption.value) {
+                    const stock = parseInt(selectedOption.getAttribute('data-stock')) || 0;
+                    const max = stock > 0 ? stock : 999;
+                    quantityInput.max = max;
+                    if (parseInt(quantityInput.value) > max) {
+                        quantityInput.value = 1;
+                    }
+                }
+            }
+        </script>
         <?php endif; ?>
         
         <div style="margin-top: 2rem;">

+ 113 - 52
reservation.php

@@ -5,28 +5,35 @@ require_once __DIR__ . '/includes/functions.php';
 $pageTitle = 'Reservierung bestätigt';
 
 $code = isset($_GET['code']) ? sanitize($_GET['code']) : '';
+$backorderCode = isset($_GET['backorder_code']) ? sanitize($_GET['backorder_code']) : '';
 $reservation = null;
+$backorderReservation = null;
 
 if ($code) {
     $reservation = getReservationByCode($code);
 }
+if ($backorderCode) {
+    $backorderReservation = getReservationByCode($backorderCode);
+}
 
-if (!$reservation) {
+if (!$reservation && !$backorderReservation) {
     header('Location: index.php');
     exit;
 }
 
-// Get product details for reservation items
-$items = [];
-foreach ($reservation['items'] as $item) {
-    $product = getProductById($item['product_id']);
-    if ($product) {
-        $items[] = [
-            'product' => $product,
-            'quantity' => $item['quantity'],
-            'size' => isset($item['size']) ? $item['size'] : null
-        ];
+function buildReservationItems($reservation) {
+    $items = [];
+    foreach ($reservation['items'] as $item) {
+        $product = getProductById($item['product_id']);
+        if ($product) {
+            $items[] = [
+                'product' => $product,
+                'quantity' => $item['quantity'],
+                'size' => isset($item['size']) ? $item['size'] : null
+            ];
+        }
     }
+    return $items;
 }
 
 include __DIR__ . '/includes/header.php';
@@ -48,54 +55,108 @@ include __DIR__ . '/includes/header.php';
 </style>
 
 
-<div class="alert alert-success">
-    <h2>Reservierung erfolgreich!</h2>
-    <p>Vielen Dank für Ihre Reservierung, <?php echo htmlspecialchars($reservation['customer_name']); ?>.</p>
-</div>
+<?php if ($reservation): ?>
+    <?php $items = buildReservationItems($reservation); ?>
+    <div class="alert alert-success">
+        <h2>Reservierung erfolgreich!</h2>
+        <p>Vielen Dank für Ihre Reservierung, <?php echo htmlspecialchars($reservation['customer_name']); ?>.</p>
+    </div>
 
-<div class="reservation-code">
-    <h3>Ihr Abholcode:</h3>
-    <h2><?php echo htmlspecialchars($reservation['code']); ?></h2>
-    <p>Bitte notieren Sie sich diesen Code und zeigen Sie ihn bei der Abholung vor.</p>
-</div>
+    <div class="reservation-code">
+        <h3>Ihr Abholcode:</h3>
+        <h2><?php echo htmlspecialchars($reservation['code']); ?></h2>
+        <p>Bitte notieren Sie sich diesen Code und zeigen Sie ihn bei der Abholung vor.</p>
+    </div>
 
-<div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 2rem 0;">
-    <h3>Reservierungsdetails</h3>
-    
-    <p><strong>Reservierungsnummer:</strong> <?php echo htmlspecialchars($reservation['id']); ?></p>
-    <p><strong>Name:</strong> <?php echo htmlspecialchars($reservation['customer_name']); ?></p>
-    <p><strong>E-Mail:</strong> <?php echo htmlspecialchars($reservation['customer_email']); ?></p>
-    <p><strong>Erstellt am:</strong> <?php echo formatDate($reservation['created']); ?></p>
-    <p><strong>Gültig bis:</strong> <?php echo formatDate($reservation['expires']); ?></p>
-    
-    <h4 style="margin-top: 1.5rem;">Reservierte Artikel:</h4>
-    <table style="margin-top: 1rem;">
-        <thead>
-            <tr>
-                <th>Produkt</th>
-                <?php if (array_filter($items, function($i) { return !empty($i['size']); })): ?>
-                    <th>Größe</th>
-                <?php endif; ?>
-                <th>Menge</th>
-            </tr>
-        </thead>
-        <tbody>
-            <?php foreach ($items as $item): ?>
+    <div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 2rem 0;">
+        <h3>Reservierungsdetails</h3>
+        
+        <p><strong>Reservierungsnummer:</strong> <?php echo htmlspecialchars($reservation['id']); ?></p>
+        <p><strong>Name:</strong> <?php echo htmlspecialchars($reservation['customer_name']); ?></p>
+        <p><strong>E-Mail:</strong> <?php echo htmlspecialchars($reservation['customer_email']); ?></p>
+        <p><strong>Erstellt am:</strong> <?php echo formatDate($reservation['created']); ?></p>
+        <p><strong>Gültig bis:</strong> <?php echo formatDate($reservation['expires']); ?></p>
+        
+        <h4 style="margin-top: 1.5rem;">Reservierte Artikel:</h4>
+        <table style="margin-top: 1rem;">
+            <thead>
                 <tr>
-                    <td><?php echo htmlspecialchars($item['product']['name']); ?></td>
+                    <th>Produkt</th>
                     <?php if (array_filter($items, function($i) { return !empty($i['size']); })): ?>
-                        <td><?php echo isset($item['size']) && !empty($item['size']) ? htmlspecialchars($item['size']) : '-'; ?></td>
+                        <th>Größe</th>
                     <?php endif; ?>
-                    <td><?php echo $item['quantity']; ?></td>
+                    <th>Menge</th>
                 </tr>
-            <?php endforeach; ?>
-        </tbody>
-    </table>
-</div>
+            </thead>
+            <tbody>
+                <?php foreach ($items as $item): ?>
+                    <tr>
+                        <td><?php echo htmlspecialchars($item['product']['name']); ?></td>
+                        <?php if (array_filter($items, function($i) { return !empty($i['size']); })): ?>
+                            <td><?php echo isset($item['size']) && !empty($item['size']) ? htmlspecialchars($item['size']) : '-'; ?></td>
+                        <?php endif; ?>
+                        <td><?php echo $item['quantity']; ?></td>
+                    </tr>
+                <?php endforeach; ?>
+            </tbody>
+        </table>
+    </div>
 
-<div class="alert alert-info">
-    <p><strong>Wichtig:</strong> Bitte bringen Sie diesen Abholcode zur Abholung mit. Die Reservierung ist bis zum <?php echo formatDate($reservation['expires']); ?> gültig.</p>
-</div>
+    <div class="alert alert-info">
+        <p><strong>Wichtig:</strong> Bitte bringen Sie diesen Abholcode zur Abholung mit. Die Reservierung ist bis zum <?php echo formatDate($reservation['expires']); ?> gültig.</p>
+    </div>
+<?php endif; ?>
+
+<?php if ($backorderReservation): ?>
+    <?php $backorderItems = buildReservationItems($backorderReservation); ?>
+    <div class="alert alert-warning" style="margin-top: 2rem;">
+        <h2>Nachbestellung bestätigt</h2>
+        <p>Vielen Dank für Ihre Nachbestellung, <?php echo htmlspecialchars($backorderReservation['customer_name']); ?>.</p>
+    </div>
+
+    <div class="reservation-code">
+        <h3>Ihr Abholcode:</h3>
+        <h2><?php echo htmlspecialchars($backorderReservation['code']); ?></h2>
+        <p>Bitte notieren Sie sich diesen Code. Wir informieren Sie, sobald die komplette Nachbestellung verfügbar ist.</p>
+    </div>
+
+    <div style="background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 2rem 0;">
+        <h3>Nachbestellungsdetails</h3>
+        
+        <p><strong>Nachbestellungsnummer:</strong> <?php echo htmlspecialchars($backorderReservation['id']); ?></p>
+        <p><strong>Name:</strong> <?php echo htmlspecialchars($backorderReservation['customer_name']); ?></p>
+        <p><strong>E-Mail:</strong> <?php echo htmlspecialchars($backorderReservation['customer_email']); ?></p>
+        <p><strong>Erstellt am:</strong> <?php echo formatDate($backorderReservation['created']); ?></p>
+        
+        <h4 style="margin-top: 1.5rem;">Nachbestellte Artikel:</h4>
+        <table style="margin-top: 1rem;">
+            <thead>
+                <tr>
+                    <th>Produkt</th>
+                    <?php if (array_filter($backorderItems, function($i) { return !empty($i['size']); })): ?>
+                        <th>Größe</th>
+                    <?php endif; ?>
+                    <th>Menge</th>
+                </tr>
+            </thead>
+            <tbody>
+                <?php foreach ($backorderItems as $item): ?>
+                    <tr>
+                        <td><?php echo htmlspecialchars($item['product']['name']); ?></td>
+                        <?php if (array_filter($backorderItems, function($i) { return !empty($i['size']); })): ?>
+                            <td><?php echo isset($item['size']) && !empty($item['size']) ? htmlspecialchars($item['size']) : '-'; ?></td>
+                        <?php endif; ?>
+                        <td><?php echo $item['quantity']; ?></td>
+                    </tr>
+                <?php endforeach; ?>
+            </tbody>
+        </table>
+    </div>
+
+    <div class="alert alert-warning">
+        <p><strong>Hinweis:</strong> Lieferzeiten sind nicht bekannt, da die Bestellung in Chargen erfolgt.</p>
+    </div>
+<?php endif; ?>
 
 <div style="text-align: center; margin-top: 2rem;">
     <button onclick="window.print()" class="btn">Reservierung drucken</button>