PROJECT_002 / CASO TÉCNICO

INVENTARIO Y VENTAS

TECH_
ONLINE

Sistema Java de productos y ventas donde el stock se protege tanto desde la lógica HTTP como desde MySQL mediante objetos SQL.

JAVAMYSQLRESTSQL

01 / RETO

LÓGICA REAL.
NO SOLO UNA INTERFAZ.

01

VENTAS

Registrar una venta únicamente con cantidades válidas.

02

STOCK

Impedir ventas superiores a las unidades disponibles.

03

REPOSICIÓN

Aumentar stock mediante una operación específica.

04

CONSULTA

Exponer productos y operaciones mediante handlers HTTP.

02 / ARQUITECTURA

DE LA INTERFAZ
A LA LÓGICA Y LOS DATOS.

↓↓↓↓

Selecciona un nodo para revisar su responsabilidad.

03 / EVIDENCIA DEL PROYECTO

QUÉ HAY
REALMENTE IMPLEMENTADO.

TRIGGER

tg_control_stock

BEFORE INSERT en ventas; consulta stock, lanza SQLSTATE 45000 o descuenta unidades.

VIEW

v_stock_bajo

Vista SQL dedicada a productos con disponibilidad baja.

FUNCTION

fn_valor_stock

Función SQL para calcular valor de stock.

PROCEDURE

pr_reabastecer_producto

Procedimiento SQL para reponer unidades.

API

VentasHandler

POST con validación de cantidad, producto y tratamiento diferenciado de errores SQL.

04 / IMPLEMENTACIÓN Y DECISIONES

DECISIONES EN CÓDIGO
RESPALDADAS POR EL PROYECTO.

Fragmentos seleccionados directamente de los archivos que componen el proyecto adjuntado.

JAVAVentasHandler
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 obtenerEnteroJson

Valida método, JSON, cantidad y producto; traduce errores de negocio/base de datos a respuestas HTTP.

SQLtg_control_stock
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

TECH_ONLINE

JAVA × MYSQL × REST × SQL