Module 5: Order Management & Point of Sale (POS)

Let's start selling! In this module, we'll build the interactive POS interface for taking customer orders.

Bringing It All Together

This module is where our front-end and back-end skills truly merge. We will build a dynamic Point of Sale (POS) system that allows staff to select products, add them to a cart, and submit an order—all without page reloads. This requires a combination of PHP for fetching data, JavaScript for handling user interactions, and a robust PHP script on the back end to process the final order.

We will also build a page to view the history of all completed orders, a crucial feature for any business.

Step 1: The POS Interface (The "Front End")

First, we need to create the user interface. Create a file named `pos.php` in the `admin/` directory. This page will have two main sections: a grid displaying all available products and a "cart" area on the side to show the current order.

admin/pos.php
<?php
session_start();
require_once '../includes/db.php';

// Fetch all available products
$products = $conn->query("SELECT * FROM products WHERE stock > 0 ORDER BY name ASC");
?>
<!-- Basic HTML Structure -->
<div class="pos-container">
    <div class="product-grid">
        <?php while($product = $products->fetch_assoc()): ?>
            <div class="product-card" data-id="<?php echo $product['id']; ?>" data-name="<?php echo htmlspecialchars($product['name']); ?>" data-price="<?php echo $product['price']; ?>">
                <img src="../<?php echo $product['image_url']; ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">
                <h5><?php echo htmlspecialchars($product['name']); ?></h5>
                <p>$<?php echo $product['price']; ?></p>
            </div>
        <?php endwhile; ?>
    </div>
    <div class="order-summary">
        <h3>Current Order</h3>
        <ul id="cart-items"></ul>
        <h4>Total: $<span id="cart-total">0.00</span></h4>
        <input type="text" id="customer-name" placeholder="Customer Name">
        <button id="submit-order">Place Order</button>
    </div>
</div>

<!-- Include jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Custom JS for POS functionality -->
<script src="../assets/js/pos.js"></script>
                            

Step 2: The JavaScript for Interactivity

Now for the magic. We'll use jQuery to handle clicks on products, add them to a cart object, and update the display. Create a file named `pos.js` inside `assets/js/`.

assets/js/pos.js
$(document).ready(function() {
    let cart = {};

    // Add item to cart when a product card is clicked
    $('.product-card').on('click', function() {
        const id = $(this).data('id');
        const name = $(this).data('name');
        const price = parseFloat($(this).data('price'));

        if (cart[id]) {
            cart[id].quantity++;
        } else {
            cart[id] = { name: name, price: price, quantity: 1 };
        }
        updateCartDisplay();
    });

    // Function to update the cart display and total
    function updateCartDisplay() {
        $('#cart-items').empty();
        let total = 0;
        for (const id in cart) {
            const item = cart[id];
            total += item.price * item.quantity;
            $('#cart-items').append(`<li>${item.name} x${item.quantity} - $${(item.price * item.quantity).toFixed(2)}</li>`);
        }
        $('#cart-total').text(total.toFixed(2));
    }

    // Submit order via AJAX
    $('#submit-order').on('click', function() {
        const customerName = $('#customer-name').val();
        if (!customerName || Object.keys(cart).length === 0) {
            alert('Please add items to the cart and enter a customer name.');
            return;
        }

        $.ajax({
            url: 'process_order.php',
            method: 'POST',
            data: {
                customer_name: customerName,
                cart: JSON.stringify(cart)
            },
            success: function(response) {
                alert('Order placed successfully!');
                cart = {};
                $('#customer-name').val('');
                updateCartDisplay();
            },
            error: function() {
                alert('Error processing order.');
            }
        });
    });
});
                            

Step 3: Processing the Order (The "Back End")

The JavaScript sends the cart data to this PHP script. This is a critical process, so we use a **database transaction**. A transaction ensures that all SQL queries must succeed; if any one of them fails, all previous changes are rolled back. This prevents partial orders or incorrect stock levels.

Create `process_order.php` in the `admin/` folder.

admin/process_order.php
<?php
require_once '../includes/db.php';

$customer_name = $_POST['customer_name'];
$cart = json_decode($_POST['cart'], true);
$total_amount = 0;

// Calculate total amount
foreach ($cart as $item) {
    $total_amount += $item['price'] * $item['quantity'];
}

// Start a transaction
$conn->begin_transaction();

try {
    // 1. Insert into the orders table
    $sql_order = "INSERT INTO orders (customer_name, total_amount, status) VALUES (?, ?, 'completed')";
    $stmt_order = $conn->prepare($sql_order);
    $stmt_order->bind_param("sd", $customer_name, $total_amount);
    $stmt_order->execute();
    $order_id = $stmt_order->insert_id; // Get the ID of the new order

    // 2. Insert into order_items and update product stock
    $sql_item = "INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)";
    $sql_update_stock = "UPDATE products SET stock = stock - ? WHERE id = ?";
    
    foreach ($cart as $id => $item) {
        // Insert order item
        $stmt_item = $conn->prepare($sql_item);
        $stmt_item->bind_param("iiid", $order_id, $id, $item['quantity'], $item['price']);
        $stmt_item->execute();

        // Update stock
        $stmt_update = $conn->prepare($sql_update_stock);
        $stmt_update->bind_param("ii", $item['quantity'], $id);
        $stmt_update->execute();
    }
    
    // If everything is successful, commit the transaction
    $conn->commit();
    echo "Success";

} catch (Exception $e) {
    // If any query fails, roll back the changes
    $conn->rollback();
    echo "Failed: " . $e->getMessage();
}
?>