VENTAS
Registrar una venta únicamente con cantidades válidas.
← PROYECTOSPROJECT_002 / CASO TÉCNICO
INVENTARIO Y VENTAS
Sistema Java de productos y ventas donde el stock se protege tanto desde la lógica HTTP como desde MySQL mediante objetos SQL.
01 / RETO
Registrar una venta únicamente con cantidades válidas.
Impedir ventas superiores a las unidades disponibles.
Aumentar stock mediante una operación específica.
Exponer productos y operaciones mediante handlers HTTP.
02 / ARQUITECTURA
Selecciona un nodo para revisar su responsabilidad.
03 / EVIDENCIA DEL PROYECTO
BEFORE INSERT en ventas; consulta stock, lanza SQLSTATE 45000 o descuenta unidades.
Vista SQL dedicada a productos con disponibilidad baja.
Función SQL para calcular valor de stock.
Procedimiento SQL para reponer unidades.
POST con validación de cantidad, producto y tratamiento diferenciado de errores SQL.
04 / IMPLEMENTACIÓN Y DECISIONES
Fragmentos seleccionados directamente de los archivos que componen el proyecto adjuntado.
public void handle(HttpExchange exchange)throws IOException {
if (!exchange.getRequestMethod().equalsIgnoreCase("POST")) {
enviarRespuesta(exchange,405,
"{\"error\":\"Método no permitido\"}");
return;
}
try {
String cuerpo = new String(exchange.getRequestBody().readAllBytes(),StandardCharsets.UTF_8);
int productoId = obtenerEnteroJson(cuerpo,"productoId");
int cantidad = obtenerEnteroJson(cuerpo,"cantidad");
if (cantidad <= 0) {
enviarRespuesta(exchange,400,
"{\"error\":\"La cantidad debe ser positiva\"}");
return;
}
Producto producto = TechOnlineNegocio.buscarProducto(productoId);
if (producto == null) {
enviarRespuesta(exchange,404,
"{\"error\":\"Producto no encontrado\"}");
return;
}
TechOnlineNegocio.realizarVenta(productoId,cantidad);
enviarRespuesta(exchange,201,
"{\"mensaje\":\"Venta realizada correctamente\"}");
} catch (IllegalArgumentException e) {
enviarRespuesta(exchange,400,
"{\"error\":\""+ escaparJson(e.getMessage())+ "\"}");
} catch (SQLException e) {
if ("45000".equals(e.getSQLState())) {
enviarRespuesta(exchange,409,
"{\"error\":\""+ escaparJson(e.getMessage())+ "\"}");
} else {
enviarRespuesta(exchange,500,
"{\"error\":\"Error interno de base de datos\"}");
}
}
}
private int obtenerEnteroJsonValida método, JSON, cantidad y producto; traduce errores de negocio/base de datos a respuestas HTTP.
DELIMITER //
CREATE TRIGGER tg_control_stock
BEFORE INSERT ON ventas
FOR EACH ROW
BEGIN
DECLARE v_stock INT;
SELECT p.stock
INTO v_stock
FROM productos p
WHERE p.id = NEW.producto_id;
IF NEW.cantidad > v_stock THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Stock insuficiente';
ELSE
UPDATE productos
SET stock = stock - NEW.cantidad
WHERE id = NEW.producto_id;
END IF;
END //
DELIMITER ;
SELECT p.id, p.nombre, p.stock
FROM productos p;
DELIMITER ;
INSERT INTO ventas (producto_id, cantidad)
VALUES (13,10);
DELIMITER ;
SELECT
v.id,
p.nombre AS producto,
v.cantidad,
v.fecha
FROM ventas v
JOIN productos p
ON p.id = v.producto_id;
SELECT
v.id,
p.nombre AS producto,
CONCAT(FORMAT(p.precio, 2), ' €') AS precio_unitario,
v.cantidad,
CONCAT(FORMAT(p.precio * v.cantidad, 2), ' €') AS total,
v.fecha
FROM ventas v
JOIN productos p
ON p.id = v.producto_id;La base de datos actúa como última barrera de integridad: rechaza una venta sin stock o descuenta las unidades.
PROJECT_002 / CIERRE
JAVA × MYSQL × REST × SQL