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.
<?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/`.
$(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.
<?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();
}
?>