Overview
The order processing system in Mis Compras handles the conversion of shopping cart items into database orders with full transaction tracking. Orders are stored with customer information, product details, quantities, and pricing.
Key Features
Order Creation Convert cart items into database orders
Order Details Track individual products within each order
Transaction Records Timestamped order history for auditing
User Association Link orders to customer accounts
Database Schema
Orders Table
The main orders table stores order headers:
CREATE TABLE ` pedidos ` (
`id_pedido` int NOT NULL AUTO_INCREMENT,
`id_usuario` int DEFAULT NULL ,
`total` decimal ( 10 , 2 ) NOT NULL ,
`direccion` varchar ( 255 ) DEFAULT NULL ,
`fecha_pedido` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ( `id_pedido` ),
FOREIGN KEY ( `id_usuario` ) REFERENCES `usuarios` ( `id_usuario` )
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
Order Details Table
The details table stores line items for each order:
CREATE TABLE ` detalle_pedido ` (
`id_detalle` int NOT NULL AUTO_INCREMENT,
`id_pedido` int NOT NULL ,
`id_producto` int NOT NULL ,
`cantidad` int DEFAULT '1' ,
`precio` decimal ( 10 , 2 ) NOT NULL ,
PRIMARY KEY ( `id_detalle` ),
FOREIGN KEY ( `id_pedido` ) REFERENCES `pedidos` ( `id_pedido` )
ON DELETE CASCADE ON UPDATE CASCADE ,
FOREIGN KEY ( `id_producto` ) REFERENCES `productos` ( `id_producto` )
ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
The precio field in detalle_pedido stores the price at the time of purchase, preserving historical pricing even if product prices change later.
Checkout Process
Order Creation Flow
Receive cart data
Client sends cart items, total, and user info as JSON
Validate input
Server validates structure and required fields
Create order record
Insert main order into pedidos table
Insert order details
Loop through items and insert into detalle_pedido
Return success
Send confirmation back to client
Backend Implementation
The checkout endpoint (php/checkout.php) processes orders:
<? php
error_reporting ( E_ALL );
ini_set ( 'display_errors' , 1 );
header ( 'Content-Type: application/json' );
header ( "Access-Control-Allow-Origin: *" );
header ( "Access-Control-Allow-Methods: POST, OPTIONS" );
header ( "Access-Control-Allow-Headers: Content-Type" );
include '../conexion.php' ;
// Read JSON body
$input = file_get_contents ( "php://input" );
$data = json_decode ( $input , true );
// Validate structure
if ( empty ( $data ) || ! isset ( $data [ 'items' ]) || ! is_array ( $data [ 'items' ])) {
echo json_encode ([ 'success' => false , 'message' => 'Estructura JSON inválida' ]);
exit ;
}
// Extract data
$id_usuario = isset ( $data [ 'usuario_id' ]) ? intval ( $data [ 'usuario_id' ]) : null ;
$total = isset ( $data [ 'total' ]) ? floatval ( $data [ 'total' ]) : 0 ;
$items = $data [ 'items' ];
// Insert order
$stmt = $conn -> prepare ( " INSERT INTO pedidos (id_usuario, total) VALUES (?, ?)" );
$stmt -> bind_param ( "id" , $id_usuario , $total );
if ( ! $stmt -> execute ()) {
echo json_encode ([
'success' => false ,
'message' => 'Error al registrar pedido: ' . $stmt -> error
]);
exit ;
}
$id_pedido = $stmt -> insert_id ;
// Insert order details
$stmt = $conn -> prepare (
" INSERT INTO detalle_pedido (id_pedido, id_producto, cantidad, precio) VALUES (?, ?, ?, ?)"
);
foreach ( $items as $item ) {
$id_producto = intval ( $item [ 'id' ]);
$cantidad = intval ( $item [ 'cantidad' ]);
$precio = floatval ( $item [ 'precio' ]);
$stmt -> bind_param ( "iiid" , $id_pedido , $id_producto , $cantidad , $precio );
if ( ! $stmt -> execute ()) {
echo json_encode ([
'success' => false ,
'message' => 'Error al registrar compra: ' . $stmt -> error
]);
exit ;
}
}
// Success response
echo json_encode ([
'success' => true ,
'message' => 'Compra registrada correctamente.' ,
'redirect' => 'gracias.html'
]);
$conn -> close ();
?>
Checkout Request
The client sends cart data as JSON:
POST /php/checkout.php
Content-Type: application/json
{
"usuario_id" : 17 ,
"total" : "2599.98" ,
"direccion" : "123 Main St, City, State 12345" ,
"items" : [
{
"id" : "1" ,
"nombre" : "iPhone 15 Pro" ,
"precio" : 999.99 ,
"cantidad" : 2 ,
"subtotal" : 1999.98 ,
"imagen" : "iphone15.jpg"
},
{
"id" : "3" ,
"nombre" : "iPad" ,
"precio" : 599.99 ,
"cantidad" : 1 ,
"subtotal" : 599.99 ,
"imagen" : "ipad.jpg"
}
]
}
Success Response
{
"success" : true ,
"message" : "Compra registrada correctamente." ,
"redirect" : "gracias.html"
}
Error Response
{
"success" : false ,
"message" : "Error al registrar pedido: Connection timeout"
}
Data Validation
The checkout endpoint validates:
JSON structure
Ensure valid JSON with required fields
Items array
Verify items array exists and is not empty
Data types
Cast user ID, product IDs, quantities to integers
Price format
Convert prices to float values
Validation Example
// Structure validation
if ( empty ( $data ) || ! isset ( $data [ 'items' ]) || ! is_array ( $data [ 'items' ])) {
echo json_encode ([ 'success' => false , 'message' => 'Estructura JSON inválida' ]);
exit ;
}
// Type casting for safety
$id_usuario = isset ( $data [ 'usuario_id' ]) ? intval ( $data [ 'usuario_id' ]) : null ;
$total = isset ( $data [ 'total' ]) ? floatval ( $data [ 'total' ]) : 0 ;
$id_producto = intval ( $item [ 'id' ]);
$cantidad = intval ( $item [ 'cantidad' ]);
$precio = floatval ( $item [ 'precio' ]);
Always validate and sanitize input data on the server side, even if client-side validation is in place.
Order Data Model
Order Record
Each order in the pedidos table represents a complete purchase:
[
'id_pedido' => 24 ,
'id_usuario' => 17 ,
'total' => 2599.98 ,
'direccion' => '123 Main St, City, State 12345' ,
'fecha_pedido' => '2025-11-20 01:35:21'
]
Order Detail Records
Each product in the order has a detail record:
[
'id_detalle' => 21 ,
'id_pedido' => 24 ,
'id_producto' => 1 ,
'cantidad' => 2 ,
'precio' => 999.99
]
Transaction Management
Database Transactions
For production systems, wrap order creation in a transaction:
// Start transaction
$conn -> begin_transaction ();
try {
// Insert order
$stmt = $conn -> prepare ( " INSERT INTO pedidos (id_usuario, total) VALUES (?, ?)" );
$stmt -> bind_param ( "id" , $id_usuario , $total );
$stmt -> execute ();
$id_pedido = $stmt -> insert_id ;
// Insert order details
$stmt = $conn -> prepare (
" INSERT INTO detalle_pedido (id_pedido, id_producto, cantidad, precio) VALUES (?, ?, ?, ?)"
);
foreach ( $items as $item ) {
$id_producto = intval ( $item [ 'id' ]);
$cantidad = intval ( $item [ 'cantidad' ]);
$precio = floatval ( $item [ 'precio' ]);
$stmt -> bind_param ( "iiid" , $id_pedido , $id_producto , $cantidad , $precio );
$stmt -> execute ();
}
// Commit transaction
$conn -> commit ();
echo json_encode ([ 'success' => true ]);
} catch ( Exception $e ) {
// Rollback on error
$conn -> rollback ();
echo json_encode ([ 'success' => false , 'message' => $e -> getMessage ()]);
}
Transactions ensure that either the complete order is created (header + all details) or nothing is saved, maintaining database consistency.
Guest Checkout
Handling Anonymous Orders
The system allows guest checkout where id_usuario can be NULL:
$id_usuario = isset ( $data [ 'usuario_id' ]) ? intval ( $data [ 'usuario_id' ]) : null ;
// This will insert NULL if user is not logged in
$stmt -> bind_param ( "id" , $id_usuario , $total );
Database Constraint
FOREIGN KEY ( `id_usuario` ) REFERENCES `usuarios` ( `id_usuario` )
ON DELETE SET NULL ON UPDATE CASCADE
This constraint allows:
Orders without users (guest checkout)
Orders to persist if user account is deleted (set to NULL)
Order History
Querying User Orders
Retrieve all orders for a specific user:
<? php
$id_usuario = $_GET [ 'id' ] ?? null ;
if ( ! $id_usuario ) {
echo json_encode ([ 'success' => false , 'message' => 'User ID required' ]);
exit ;
}
$sql = " SELECT p . id_pedido , p . total , p . fecha_pedido , p . direccion
FROM pedidos p
WHERE p . id_usuario = ?
ORDER BY p . fecha_pedido DESC " ;
$stmt = $conn -> prepare ( $sql );
$stmt -> bind_param ( "i" , $id_usuario );
$stmt -> execute ();
$result = $stmt -> get_result ();
$orders = [];
while ( $row = $result -> fetch_assoc ()) {
$orders [] = $row ;
}
echo json_encode ([ 'success' => true , 'orders' => $orders ]);
?>
Getting Order Details
Retrieve all products in a specific order:
<? php
$id_pedido = $_GET [ 'id' ] ?? null ;
$sql = " SELECT
dp . id_detalle ,
dp . cantidad ,
dp . precio ,
p . nombre ,
p . imagen
FROM detalle_pedido dp
INNER JOIN productos p ON dp . id_producto = p . id_producto
WHERE dp . id_pedido = ?" ;
$stmt = $conn -> prepare ( $sql );
$stmt -> bind_param ( "i" , $id_pedido );
$stmt -> execute ();
$result = $stmt -> get_result ();
$items = [];
while ( $row = $result -> fetch_assoc ()) {
$items [] = $row ;
}
echo json_encode ([ 'success' => true , 'items' => $items ]);
?>
Complete Order View
Join Query for Full Order
Get complete order information with all products:
SELECT
p . id_pedido ,
p . total ,
p . fecha_pedido ,
p . direccion ,
u . nombre as cliente_nombre,
u . email as cliente_email,
dp . cantidad ,
dp . precio as precio_unitario,
( dp . cantidad * dp . precio ) as subtotal,
prod . nombre as producto_nombre,
prod . imagen as producto_imagen
FROM pedidos p
LEFT JOIN usuarios u ON p . id_usuario = u . id_usuario
INNER JOIN detalle_pedido dp ON p . id_pedido = dp . id_pedido
INNER JOIN productos prod ON dp . id_producto = prod . id_producto
WHERE p . id_pedido = ?
ORDER BY dp . id_detalle ;
Error Handling
Common Error Scenarios
Cause: Malformed JSON or missing required fieldsResponse: {
"success" : false ,
"message" : "Estructura JSON inválida"
}
Database Connection Error
Cause: Cannot connect to MySQL databaseResponse: {
"success" : false ,
"message" : "Error al registrar pedido: Connection refused"
}
Cause: Items array is emptyHandled client-side: if ( ! cart . length ) {
alert ( 'Tu carrito está vacío.' );
return ;
}
Cause: Product ID doesn’t exist in databaseResponse: {
"success" : false ,
"message" : "Error al registrar compra: Foreign key constraint fails"
}
Debugging
Debug Logging
The checkout script includes debug logging:
// Log raw input for debugging
$input = file_get_contents ( "php://input" );
file_put_contents ( "debug_input.txt" , $input );
$data = json_decode ( $input , true );
This creates a debug_input.txt file with the raw POST body, useful for troubleshooting.
Checking for Errors
error_reporting ( E_ALL );
ini_set ( 'display_errors' , 1 );
Disable display_errors in production environments. Log errors to files instead of displaying them to users.
Post-Checkout Flow
Client-Side Success Handling
After successful checkout:
Clear cart
Remove all items from localStorage
Show confirmation
Display success modal to user
Redirect
Navigate to thank you page after 3 seconds
if ( data . success ) {
// Clear cart
this . clear ();
// Show success modal
const modal = document . createElement ( 'div' );
modal . innerHTML = `
<div style="...">
<h2>¡Compra realizada con éxito!</h2>
<p>Tu pedido ha sido registrado correctamente.</p>
</div>` ;
document . body . appendChild ( modal );
// Redirect
setTimeout (() => {
window . location . href = 'gracias.html' ;
}, 3000 );
}
Sample Database Records
Example Order
-- pedidos table
INSERT INTO pedidos (id_pedido, id_usuario, total, direccion, fecha_pedido)
VALUES ( 24 , 17 , 999 . 99 , NULL , '2025-11-20 01:35:21' );
-- detalle_pedido table
INSERT INTO detalle_pedido (id_detalle, id_pedido, id_producto, cantidad, precio)
VALUES ( 21 , 24 , 1 , 1 , 999 . 99 );
This represents:
Order #24
Customer ID 17
Total $999.99
1 iPhone 15 Pro at $999.99
API Reference
POST /php/checkout.php
Process cart items and create an order.
Content-Type: application/json
Request Body:
{
"usuario_id" : 17 , // integer or null for guest
"total" : "2599.98" , // string or number
"direccion" : "..." , // string or null
"items" : [ // array (required)
{
"id" : "1" , // product ID (string or number)
"cantidad" : 2 , // integer
"precio" : 999.99 , // number
"nombre" : "..." , // string (not stored)
"subtotal" : 1999.98 , // number (not stored)
"imagen" : "..." // string (not stored)
}
]
}
Success Response (200):
{
"success" : true ,
"message" : "Compra registrada correctamente." ,
"redirect" : "gracias.html"
}
Error Response (200):
{
"success" : false ,
"message" : "Error al registrar pedido: ..."
}
Best Practices
Use Transactions Wrap order creation in database transactions for consistency
Preserve Prices Store product prices in order details, not just product IDs
Validate Input Always validate and sanitize all input data
Log Errors Log errors to files for debugging, don’t expose to users
Next Steps
Shopping Cart Learn how the cart feeds data to checkout
User Authentication Understand user session management