-- =====================================================================
-- DB_VENTAS V2.0 - BASE DE DATOS MEJORADA
-- Compatible con MySQL 8.0+ / MariaDB 10.5+
-- Incluye estructura, restricciones, triggers, procedimientos,
-- vistas y datos semilla.
-- =====================================================================

DROP DATABASE IF EXISTS db_ventas_v2;
CREATE DATABASE db_ventas_v2
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;
USE db_ventas_v2;


-- =====================================================================
-- MÓDULO 1: CONFIGURACIÓN / EMPRESA
-- =====================================================================
CREATE TABLE empresa (
    id_empresa INT AUTO_INCREMENT PRIMARY KEY,
    ruc VARCHAR(11) NOT NULL,
    razon_social VARCHAR(150) NOT NULL,
    nombre_comercial VARCHAR(150),
    direccion VARCHAR(200),
    telefono VARCHAR(20),
    email VARCHAR(100),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    fecha_registro DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_actualizacion DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_empresa_ruc (ruc),
    CONSTRAINT chk_empresa_ruc CHECK (ruc REGEXP '^[0-9]{11}$')
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 2: SEGURIDAD
-- =====================================================================
CREATE TABLE roles (
    id_rol INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL,
    descripcion VARCHAR(150),
    es_sistema TINYINT(1) NOT NULL DEFAULT 0,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    fecha_registro DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_roles_nombre (nombre),
    CONSTRAINT chk_roles_es_sistema CHECK (es_sistema IN (0,1))
) ENGINE=InnoDB;

CREATE TABLE usuarios (
    id_usuario INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL,
    imagen VARCHAR(255) NOT NULL DEFAULT 'uploads/usuarios/usuario_default.png',
    password_hash VARCHAR(255) NOT NULL,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    fecha_registro DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_actualizacion DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_usuarios_email (email)
) ENGINE=InnoDB;

CREATE TABLE usuario_roles (
    id_usuario_rol INT AUTO_INCREMENT PRIMARY KEY,
    id_usuario INT NOT NULL,
    id_rol INT NOT NULL,
    fecha_asignacion DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_usuario_roles_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_usuario_roles_rol FOREIGN KEY (id_rol)
        REFERENCES roles(id_rol) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_usuario_roles (id_usuario, id_rol),
    KEY idx_usuario_roles_usuario (id_usuario),
    KEY idx_usuario_roles_rol (id_rol)
) ENGINE=InnoDB;

CREATE TABLE modulos (
    id_modulo INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(80) NOT NULL,
    ruta VARCHAR(100) NOT NULL,
    icono VARCHAR(60) NULL,
    orden_menu INT NOT NULL DEFAULT 0,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    UNIQUE KEY uk_modulos_nombre (nombre),
    UNIQUE KEY uk_modulos_ruta (ruta),
    CONSTRAINT chk_modulos_orden CHECK (orden_menu >= 0)
) ENGINE=InnoDB;

CREATE TABLE permisos (
    id_permiso INT AUTO_INCREMENT PRIMARY KEY,
    id_modulo INT NOT NULL,
    nombre VARCHAR(50) NOT NULL,
    descripcion VARCHAR(150),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    CONSTRAINT fk_permisos_modulos FOREIGN KEY (id_modulo)
        REFERENCES modulos(id_modulo) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_permisos_modulo_nombre (id_modulo, nombre),
    KEY idx_permisos_modulo (id_modulo)
) ENGINE=InnoDB;

CREATE TABLE rol_permisos (
    id_rol_permiso INT AUTO_INCREMENT PRIMARY KEY,
    id_rol INT NOT NULL,
    id_permiso INT NOT NULL,
    fecha_asignacion DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_rol_permisos_rol FOREIGN KEY (id_rol)
        REFERENCES roles(id_rol) ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_rol_permisos_permiso FOREIGN KEY (id_permiso)
        REFERENCES permisos(id_permiso) ON UPDATE CASCADE ON DELETE CASCADE,
    UNIQUE KEY uk_rol_permisos (id_rol, id_permiso),
    KEY idx_rol_permisos_rol (id_rol),
    KEY idx_rol_permisos_permiso (id_permiso)
) ENGINE=InnoDB;

CREATE TABLE sesiones (
    id_sesion BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_usuario INT NOT NULL,
    token_hash CHAR(64) NOT NULL,
    ip VARCHAR(45),
    navegador VARCHAR(255),
    fecha_inicio DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_ultima_actividad DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_fin DATETIME NULL,
    estado ENUM('ACTIVA','CERRADA','EXPIRADA') NOT NULL DEFAULT 'ACTIVA',
    CONSTRAINT fk_sesiones_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE CASCADE,
    UNIQUE KEY uk_sesiones_token_hash (token_hash),
    KEY idx_sesiones_usuario_estado (id_usuario, estado),
    KEY idx_sesiones_actividad (fecha_ultima_actividad)
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 3: CLIENTES
-- =====================================================================
CREATE TABLE clientes (
    id_cliente INT AUTO_INCREMENT PRIMARY KEY,
    tipo_documento ENUM('DNI','RUC','CE') NOT NULL,
    numero_documento VARCHAR(20) NOT NULL,
    nombre VARCHAR(150) NOT NULL,
    direccion VARCHAR(200),
    telefono VARCHAR(20),
    email VARCHAR(100),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    fecha_registro DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_actualizacion DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_clientes_documento (tipo_documento, numero_documento),
    KEY idx_clientes_nombre (nombre),
    CONSTRAINT chk_clientes_documento CHECK (
        (tipo_documento = 'DNI' AND numero_documento REGEXP '^[0-9]{8}$') OR
        (tipo_documento = 'RUC' AND numero_documento REGEXP '^[0-9]{11}$') OR
        (tipo_documento = 'CE' AND CHAR_LENGTH(numero_documento) BETWEEN 8 AND 20)
    )
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 4: PROVEEDORES
-- =====================================================================
CREATE TABLE proveedores (
    id_proveedor INT AUTO_INCREMENT PRIMARY KEY,
    ruc VARCHAR(11) NOT NULL,
    razon_social VARCHAR(150) NOT NULL,
    telefono VARCHAR(20),
    email VARCHAR(100),
    direccion VARCHAR(200),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    fecha_registro DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_actualizacion DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_proveedores_ruc (ruc),
    KEY idx_proveedores_razon_social (razon_social),
    CONSTRAINT chk_proveedores_ruc CHECK (ruc REGEXP '^[0-9]{11}$')
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 5: CATÁLOGO / PRODUCTOS
-- =====================================================================
CREATE TABLE categorias (
    id_categoria INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    descripcion VARCHAR(200),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    UNIQUE KEY uk_categorias_nombre (nombre)
) ENGINE=InnoDB;

CREATE TABLE marcas (
    id_marca INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    descripcion VARCHAR(200),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    UNIQUE KEY uk_marcas_nombre (nombre)
) ENGINE=InnoDB;

CREATE TABLE productos (
    id_producto INT AUTO_INCREMENT PRIMARY KEY,
    id_categoria INT NOT NULL,
    id_marca INT NOT NULL,
    codigo VARCHAR(30) NOT NULL,
    nombre VARCHAR(120) NOT NULL,
    descripcion TEXT,
    imagen VARCHAR(255) NOT NULL DEFAULT 'uploads/productos/producto_default.png',
    precio_compra DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    precio_venta DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    stock_minimo INT NOT NULL DEFAULT 0,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    fecha_registro DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_actualizacion DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_productos_categoria FOREIGN KEY (id_categoria)
        REFERENCES categorias(id_categoria) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_productos_marca FOREIGN KEY (id_marca)
        REFERENCES marcas(id_marca) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_productos_codigo (codigo),
    KEY idx_productos_nombre (nombre),
    KEY idx_productos_categoria (id_categoria),
    KEY idx_productos_marca (id_marca),
    CONSTRAINT chk_productos_precio_compra CHECK (precio_compra >= 0),
    CONSTRAINT chk_productos_precio_venta CHECK (precio_venta >= 0),
    CONSTRAINT chk_productos_stock_minimo CHECK (stock_minimo >= 0)
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 6: COMPROBANTES Y MÉTODOS DE PAGO
-- =====================================================================
CREATE TABLE tipos_comprobante (
    id_tipo_comprobante INT AUTO_INCREMENT PRIMARY KEY,
    codigo VARCHAR(20) NOT NULL,
    nombre VARCHAR(80) NOT NULL,
    tipo ENUM('VENTA','COMPRA') NOT NULL,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    UNIQUE KEY uk_tipos_comprobante_codigo (codigo),
    UNIQUE KEY uk_tipos_comprobante_nombre_tipo (nombre, tipo)
) ENGINE=InnoDB;

CREATE TABLE series_comprobantes (
    id_serie INT AUTO_INCREMENT PRIMARY KEY,
    id_tipo_comprobante INT NOT NULL,
    serie VARCHAR(10) NOT NULL,
    numero_actual BIGINT NOT NULL DEFAULT 0,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    CONSTRAINT fk_series_tipo_comprobante FOREIGN KEY (id_tipo_comprobante)
        REFERENCES tipos_comprobante(id_tipo_comprobante) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_series_tipo_serie (id_tipo_comprobante, serie),
    KEY idx_series_tipo_comprobante (id_tipo_comprobante),
    CONSTRAINT chk_series_numero_actual CHECK (numero_actual >= 0)
) ENGINE=InnoDB;

CREATE TABLE metodos_pago (
    id_metodo_pago INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL,
    descripcion VARCHAR(150),
    requiere_referencia TINYINT(1) NOT NULL DEFAULT 0,
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    UNIQUE KEY uk_metodos_pago_nombre (nombre),
    CONSTRAINT chk_metodos_referencia CHECK (requiere_referencia IN (0,1))
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 7: INVENTARIO
-- =====================================================================
CREATE TABLE almacenes (
    id_almacen INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    direccion VARCHAR(200),
    estado ENUM('ACTIVO','INACTIVO') NOT NULL DEFAULT 'ACTIVO',
    UNIQUE KEY uk_almacenes_nombre (nombre)
) ENGINE=InnoDB;

CREATE TABLE stock_almacen (
    id_stock INT AUTO_INCREMENT PRIMARY KEY,
    id_almacen INT NOT NULL,
    id_producto INT NOT NULL,
    stock_actual INT NOT NULL DEFAULT 0,
    fecha_actualizacion DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_stock_almacen_almacen FOREIGN KEY (id_almacen)
        REFERENCES almacenes(id_almacen) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_stock_almacen_producto FOREIGN KEY (id_producto)
        REFERENCES productos(id_producto) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_stock_almacen_producto (id_almacen, id_producto),
    KEY idx_stock_producto (id_producto),
    CONSTRAINT chk_stock_actual CHECK (stock_actual >= 0)
) ENGINE=InnoDB;

CREATE TABLE movimientos_stock (
    id_movimiento_stock BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_producto INT NOT NULL,
    id_almacen INT NOT NULL,
    id_almacen_destino INT NULL,
    id_usuario INT NOT NULL,
    tipo_movimiento ENUM('ENTRADA','SALIDA','AJUSTE','TRASLADO') NOT NULL,
    cantidad INT NOT NULL,
    motivo VARCHAR(150) NOT NULL,
    referencia_tipo ENUM('COMPRA','VENTA','AJUSTE','TRASLADO','ANULACION','INICIAL','OTRO') NOT NULL DEFAULT 'OTRO',
    referencia_id BIGINT NULL,
    referencia VARCHAR(100),
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_mov_stock_producto FOREIGN KEY (id_producto)
        REFERENCES productos(id_producto) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_mov_stock_almacen FOREIGN KEY (id_almacen)
        REFERENCES almacenes(id_almacen) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_mov_stock_almacen_destino FOREIGN KEY (id_almacen_destino)
        REFERENCES almacenes(id_almacen) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_mov_stock_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE RESTRICT,
    KEY idx_mov_stock_producto_fecha (id_producto, fecha),
    KEY idx_mov_stock_almacen_fecha (id_almacen, fecha),
    KEY idx_mov_stock_referencia (referencia_tipo, referencia_id),
    CONSTRAINT chk_mov_stock_cantidad CHECK (cantidad > 0),
    CONSTRAINT chk_mov_stock_traslado CHECK (
        (tipo_movimiento <> 'TRASLADO' AND id_almacen_destino IS NULL) OR
        (tipo_movimiento = 'TRASLADO' AND id_almacen_destino IS NOT NULL AND id_almacen_destino <> id_almacen)
    )
) ENGINE=InnoDB;

CREATE TABLE kardex (
    id_kardex BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_producto INT NOT NULL,
    id_almacen INT NOT NULL,
    id_usuario INT NULL,
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    tipo_movimiento ENUM('ENTRADA','SALIDA','AJUSTE','TRASLADO') NOT NULL,
    referencia_tipo ENUM('COMPRA','VENTA','AJUSTE','TRASLADO','ANULACION','INICIAL','OTRO') NOT NULL DEFAULT 'OTRO',
    referencia_id BIGINT NULL,
    cantidad INT NOT NULL,
    costo_unitario DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    stock_anterior INT NOT NULL,
    stock_actual INT NOT NULL,
    saldo_valorizado DECIMAL(14,2) NOT NULL DEFAULT 0.00,
    observacion VARCHAR(200),
    CONSTRAINT fk_kardex_producto FOREIGN KEY (id_producto)
        REFERENCES productos(id_producto) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_kardex_almacen FOREIGN KEY (id_almacen)
        REFERENCES almacenes(id_almacen) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_kardex_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE SET NULL,
    KEY idx_kardex_producto_almacen_fecha (id_producto, id_almacen, fecha),
    KEY idx_kardex_referencia (referencia_tipo, referencia_id),
    CONSTRAINT chk_kardex_cantidad CHECK (cantidad > 0),
    CONSTRAINT chk_kardex_costo_unitario CHECK (costo_unitario >= 0),
    CONSTRAINT chk_kardex_stock_anterior CHECK (stock_anterior >= 0),
    CONSTRAINT chk_kardex_stock_actual CHECK (stock_actual >= 0),
    CONSTRAINT chk_kardex_saldo_valorizado CHECK (saldo_valorizado >= 0)
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 8: COMPRAS
-- =====================================================================
CREATE TABLE compras (
    id_compra BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_proveedor INT NOT NULL,
    id_usuario INT NOT NULL,
    id_almacen INT NOT NULL,
    id_tipo_comprobante INT NOT NULL,
    serie VARCHAR(10) NOT NULL,
    numero VARCHAR(20) NOT NULL,
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    subtotal DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    igv DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    total DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    estado ENUM('REGISTRADA','ANULADA') NOT NULL DEFAULT 'REGISTRADA',
    fecha_anulacion DATETIME NULL,
    motivo_anulacion VARCHAR(200) NULL,
    CONSTRAINT fk_compras_proveedor FOREIGN KEY (id_proveedor)
        REFERENCES proveedores(id_proveedor) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_compras_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_compras_almacen FOREIGN KEY (id_almacen)
        REFERENCES almacenes(id_almacen) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_compras_tipo_comprobante FOREIGN KEY (id_tipo_comprobante)
        REFERENCES tipos_comprobante(id_tipo_comprobante) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_compras_comprobante (id_tipo_comprobante, serie, numero),
    KEY idx_compras_fecha (fecha),
    KEY idx_compras_proveedor (id_proveedor),
    KEY idx_compras_almacen (id_almacen),
    CONSTRAINT chk_compras_subtotal CHECK (subtotal >= 0),
    CONSTRAINT chk_compras_igv CHECK (igv >= 0),
    CONSTRAINT chk_compras_total CHECK (total >= 0),
    CONSTRAINT chk_compras_total_calculado CHECK (ABS(total - (subtotal + igv)) < 0.01)
) ENGINE=InnoDB;

CREATE TABLE detalle_compras (
    id_detalle_compra BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_compra BIGINT NOT NULL,
    id_producto INT NOT NULL,
    cantidad INT NOT NULL,
    costo_unitario DECIMAL(12,2) NOT NULL,
    subtotal DECIMAL(12,2) NOT NULL,
    CONSTRAINT fk_detalle_compras_compra FOREIGN KEY (id_compra)
        REFERENCES compras(id_compra) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_detalle_compras_producto FOREIGN KEY (id_producto)
        REFERENCES productos(id_producto) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_detalle_compras_producto (id_compra, id_producto),
    KEY idx_det_compras_producto (id_producto),
    CONSTRAINT chk_det_compras_cantidad CHECK (cantidad > 0),
    CONSTRAINT chk_det_compras_costo CHECK (costo_unitario >= 0),
    CONSTRAINT chk_det_compras_subtotal CHECK (ABS(subtotal - (cantidad * costo_unitario)) < 0.01)
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 9: VENTAS
-- =====================================================================
CREATE TABLE ventas (
    id_venta BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_cliente INT NOT NULL,
    id_usuario INT NOT NULL,
    id_almacen INT NOT NULL,
    id_tipo_comprobante INT NOT NULL,
    serie VARCHAR(10) NOT NULL,
    numero VARCHAR(20) NOT NULL,
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    subtotal DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    igv DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    total DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    estado ENUM('EMITIDA','ANULADA') NOT NULL DEFAULT 'EMITIDA',
    estado_pago ENUM('PENDIENTE','PARCIAL','PAGADO') NOT NULL DEFAULT 'PENDIENTE',
    fecha_anulacion DATETIME NULL,
    motivo_anulacion VARCHAR(200) NULL,
    CONSTRAINT fk_ventas_cliente FOREIGN KEY (id_cliente)
        REFERENCES clientes(id_cliente) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_ventas_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_ventas_almacen FOREIGN KEY (id_almacen)
        REFERENCES almacenes(id_almacen) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_ventas_tipo_comprobante FOREIGN KEY (id_tipo_comprobante)
        REFERENCES tipos_comprobante(id_tipo_comprobante) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_ventas_comprobante (id_tipo_comprobante, serie, numero),
    KEY idx_ventas_fecha (fecha),
    KEY idx_ventas_cliente (id_cliente),
    KEY idx_ventas_almacen (id_almacen),
    KEY idx_ventas_estado_pago (estado_pago),
    CONSTRAINT chk_ventas_subtotal CHECK (subtotal >= 0),
    CONSTRAINT chk_ventas_igv CHECK (igv >= 0),
    CONSTRAINT chk_ventas_total CHECK (total >= 0),
    CONSTRAINT chk_ventas_total_calculado CHECK (ABS(total - (subtotal + igv)) < 0.01)
) ENGINE=InnoDB;

CREATE TABLE detalle_ventas (
    id_detalle_venta BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_venta BIGINT NOT NULL,
    id_producto INT NOT NULL,
    cantidad INT NOT NULL,
    costo_unitario DECIMAL(12,2) NOT NULL,
    precio_unitario DECIMAL(12,2) NOT NULL,
    subtotal DECIMAL(12,2) NOT NULL,
    CONSTRAINT fk_detalle_ventas_venta FOREIGN KEY (id_venta)
        REFERENCES ventas(id_venta) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_detalle_ventas_producto FOREIGN KEY (id_producto)
        REFERENCES productos(id_producto) ON UPDATE CASCADE ON DELETE RESTRICT,
    UNIQUE KEY uk_detalle_ventas_producto (id_venta, id_producto),
    KEY idx_det_ventas_producto (id_producto),
    CONSTRAINT chk_det_ventas_cantidad CHECK (cantidad > 0),
    CONSTRAINT chk_det_ventas_costo CHECK (costo_unitario >= 0),
    CONSTRAINT chk_det_ventas_precio CHECK (precio_unitario >= 0),
    CONSTRAINT chk_det_ventas_subtotal CHECK (ABS(subtotal - (cantidad * precio_unitario)) < 0.01)
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 10: CAJA Y PAGOS
-- =====================================================================
CREATE TABLE cajas (
    id_caja INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(100) NOT NULL,
    descripcion VARCHAR(150),
    estado ENUM('ACTIVA','INACTIVA') NOT NULL DEFAULT 'ACTIVA',
    UNIQUE KEY uk_cajas_nombre (nombre)
) ENGINE=InnoDB;

CREATE TABLE cierres_caja (
    id_cierre_caja BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_caja INT NOT NULL,
    id_usuario_apertura INT NOT NULL,
    id_usuario_cierre INT NULL,
    fecha_apertura DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    fecha_cierre DATETIME NULL,
    saldo_inicial DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    total_ingresos DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    total_egresos DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    saldo_sistema DECIMAL(12,2) NOT NULL DEFAULT 0.00,
    saldo_fisico DECIMAL(12,2) NULL,
    diferencia DECIMAL(12,2) NULL,
    estado ENUM('ABIERTA','CERRADA') NOT NULL DEFAULT 'ABIERTA',
    observacion VARCHAR(200),
    CONSTRAINT fk_cierres_caja_caja FOREIGN KEY (id_caja)
        REFERENCES cajas(id_caja) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_cierres_caja_usuario_apertura FOREIGN KEY (id_usuario_apertura)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_cierres_caja_usuario_cierre FOREIGN KEY (id_usuario_cierre)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE SET NULL,
    KEY idx_cierres_caja_estado (id_caja, estado),
    KEY idx_cierres_fecha_apertura (fecha_apertura),
    CONSTRAINT chk_cierres_saldo_inicial CHECK (saldo_inicial >= 0),
    CONSTRAINT chk_cierres_total_ingresos CHECK (total_ingresos >= 0),
    CONSTRAINT chk_cierres_total_egresos CHECK (total_egresos >= 0),
    CONSTRAINT chk_cierres_saldo_sistema CHECK (saldo_sistema >= 0)
) ENGINE=InnoDB;

CREATE TABLE pagos (
    id_pago BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_venta BIGINT NOT NULL,
    id_metodo_pago INT NOT NULL,
    id_usuario INT NOT NULL,
    id_cierre_caja BIGINT NULL,
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    monto DECIMAL(12,2) NOT NULL,
    referencia VARCHAR(100),
    observacion VARCHAR(200),
    estado ENUM('REGISTRADO','ANULADO') NOT NULL DEFAULT 'REGISTRADO',
    fecha_anulacion DATETIME NULL,
    CONSTRAINT fk_pagos_venta FOREIGN KEY (id_venta)
        REFERENCES ventas(id_venta) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_pagos_metodo_pago FOREIGN KEY (id_metodo_pago)
        REFERENCES metodos_pago(id_metodo_pago) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_pagos_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_pagos_cierre FOREIGN KEY (id_cierre_caja)
        REFERENCES cierres_caja(id_cierre_caja) ON UPDATE CASCADE ON DELETE RESTRICT,
    KEY idx_pagos_venta_estado (id_venta, estado),
    KEY idx_pagos_fecha (fecha),
    KEY idx_pagos_cierre (id_cierre_caja),
    CONSTRAINT chk_pagos_monto CHECK (monto > 0)
) ENGINE=InnoDB;

CREATE TABLE movimientos_caja (
    id_movimiento_caja BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_cierre_caja BIGINT NOT NULL,
    id_caja INT NOT NULL,
    id_usuario INT NOT NULL,
    id_pago BIGINT NULL,
    tipo_movimiento ENUM('APERTURA','INGRESO','EGRESO','CIERRE','ANULACION') NOT NULL,
    monto DECIMAL(12,2) NOT NULL,
    descripcion VARCHAR(200),
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_mov_caja_cierre FOREIGN KEY (id_cierre_caja)
        REFERENCES cierres_caja(id_cierre_caja) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_mov_caja_caja FOREIGN KEY (id_caja)
        REFERENCES cajas(id_caja) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_mov_caja_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE RESTRICT,
    CONSTRAINT fk_mov_caja_pago FOREIGN KEY (id_pago)
        REFERENCES pagos(id_pago) ON UPDATE CASCADE ON DELETE SET NULL,
    KEY idx_mov_caja_cierre_fecha (id_cierre_caja, fecha),
    KEY idx_mov_caja_pago (id_pago),
    CONSTRAINT chk_mov_caja_monto CHECK (monto >= 0)
) ENGINE=InnoDB;

-- =====================================================================
-- MÓDULO 11: AUDITORÍA
-- =====================================================================
CREATE TABLE auditoria (
    id_auditoria BIGINT AUTO_INCREMENT PRIMARY KEY,
    id_usuario INT NULL,
    tabla_afectada VARCHAR(80) NOT NULL,
    registro_id BIGINT NULL,
    accion ENUM('INSERT','UPDATE','DELETE','ANULAR','LOGIN','LOGOUT') NOT NULL,
    valores_anteriores JSON NULL,
    valores_nuevos JSON NULL,
    descripcion TEXT,
    ip VARCHAR(45) NULL,
    fecha DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_auditoria_usuario FOREIGN KEY (id_usuario)
        REFERENCES usuarios(id_usuario) ON UPDATE CASCADE ON DELETE SET NULL,
    KEY idx_auditoria_tabla_registro (tabla_afectada, registro_id),
    KEY idx_auditoria_usuario_fecha (id_usuario, fecha),
    KEY idx_auditoria_fecha (fecha)
) ENGINE=InnoDB;


-- =====================================================================
-- TRIGGERS Y REGLAS DE NEGOCIO
-- =====================================================================
DELIMITER $$

CREATE TRIGGER trg_roles_bu_proteger
BEFORE UPDATE ON roles
FOR EACH ROW
BEGIN
    IF OLD.es_sistema = 1 AND (NEW.nombre <> OLD.nombre OR NEW.es_sistema = 0) THEN
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'No se puede cambiar el nombre ni desproteger un rol del sistema';
    END IF;
END$$

CREATE TRIGGER trg_roles_bd_proteger
BEFORE DELETE ON roles
FOR EACH ROW
BEGIN
    IF OLD.es_sistema = 1 THEN
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'No se puede eliminar un rol protegido del sistema';
    END IF;
END$$

CREATE TRIGGER trg_cierres_caja_bi_unica_abierta
BEFORE INSERT ON cierres_caja
FOR EACH ROW
BEGIN
    IF NEW.estado = 'ABIERTA' AND EXISTS (
        SELECT 1 FROM cierres_caja
        WHERE id_caja = NEW.id_caja AND estado = 'ABIERTA'
    ) THEN
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'La caja ya tiene una apertura activa';
    END IF;
END$$

CREATE TRIGGER trg_detalle_compras_bi
BEFORE INSERT ON detalle_compras
FOR EACH ROW
BEGIN
    DECLARE v_estado VARCHAR(20);
    SELECT estado INTO v_estado FROM compras WHERE id_compra = NEW.id_compra;
    IF v_estado IS NULL THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La compra no existe';
    END IF;
    IF v_estado <> 'REGISTRADA' THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'No se puede agregar detalle a una compra anulada';
    END IF;
    SET NEW.subtotal = ROUND(NEW.cantidad * NEW.costo_unitario, 2);
END$$

CREATE TRIGGER trg_detalle_compras_ai
AFTER INSERT ON detalle_compras
FOR EACH ROW
BEGIN
    DECLARE v_id_almacen INT;
    DECLARE v_id_usuario INT;
    DECLARE v_stock_anterior INT DEFAULT 0;
    DECLARE v_stock_actual INT DEFAULT 0;

    SELECT id_almacen, id_usuario
      INTO v_id_almacen, v_id_usuario
      FROM compras
     WHERE id_compra = NEW.id_compra;

    INSERT INTO stock_almacen (id_almacen, id_producto, stock_actual)
    VALUES (v_id_almacen, NEW.id_producto, 0)
    ON DUPLICATE KEY UPDATE stock_actual = stock_actual;

    SELECT stock_actual INTO v_stock_anterior
      FROM stock_almacen
     WHERE id_almacen = v_id_almacen AND id_producto = NEW.id_producto
     FOR UPDATE;

    UPDATE stock_almacen
       SET stock_actual = stock_actual + NEW.cantidad
     WHERE id_almacen = v_id_almacen AND id_producto = NEW.id_producto;

    SET v_stock_actual = v_stock_anterior + NEW.cantidad;

    INSERT INTO movimientos_stock
    (id_producto, id_almacen, id_usuario, tipo_movimiento, cantidad, motivo,
     referencia_tipo, referencia_id, referencia)
    VALUES
    (NEW.id_producto, v_id_almacen, v_id_usuario, 'ENTRADA', NEW.cantidad,
     'Compra registrada', 'COMPRA', NEW.id_compra, CONCAT('COMPRA-', NEW.id_compra));

    INSERT INTO kardex
    (id_producto, id_almacen, id_usuario, tipo_movimiento, referencia_tipo,
     referencia_id, cantidad, costo_unitario, stock_anterior, stock_actual,
     saldo_valorizado, observacion)
    VALUES
    (NEW.id_producto, v_id_almacen, v_id_usuario, 'ENTRADA', 'COMPRA',
     NEW.id_compra, NEW.cantidad, NEW.costo_unitario, v_stock_anterior,
     v_stock_actual, ROUND(v_stock_actual * NEW.costo_unitario, 2),
     'Entrada automática por compra');

    UPDATE productos
       SET precio_compra = NEW.costo_unitario
     WHERE id_producto = NEW.id_producto;
END$$

CREATE TRIGGER trg_detalle_compras_bu_bloquear
BEFORE UPDATE ON detalle_compras
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se permite editar un detalle de compra; anule y registre nuevamente';
END$$

CREATE TRIGGER trg_detalle_compras_bd_bloquear
BEFORE DELETE ON detalle_compras
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se permite eliminar un detalle de compra; utilice la anulación';
END$$

CREATE TRIGGER trg_detalle_ventas_bi
BEFORE INSERT ON detalle_ventas
FOR EACH ROW
BEGIN
    DECLARE v_id_almacen INT;
    DECLARE v_estado VARCHAR(20);
    DECLARE v_stock_actual INT DEFAULT 0;
    DECLARE v_costo DECIMAL(12,2) DEFAULT 0.00;

    SELECT id_almacen, estado INTO v_id_almacen, v_estado
      FROM ventas WHERE id_venta = NEW.id_venta;

    IF v_estado IS NULL THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La venta no existe';
    END IF;
    IF v_estado <> 'EMITIDA' THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'No se puede agregar detalle a una venta anulada';
    END IF;

    SELECT precio_compra INTO v_costo
      FROM productos WHERE id_producto = NEW.id_producto;

    SELECT COALESCE(MAX(stock_actual), 0) INTO v_stock_actual
      FROM stock_almacen
     WHERE id_almacen = v_id_almacen AND id_producto = NEW.id_producto;

    IF v_stock_actual < NEW.cantidad THEN
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'Stock insuficiente para realizar la venta';
    END IF;

    SET NEW.costo_unitario = v_costo;
    SET NEW.subtotal = ROUND(NEW.cantidad * NEW.precio_unitario, 2);
END$$

CREATE TRIGGER trg_detalle_ventas_ai
AFTER INSERT ON detalle_ventas
FOR EACH ROW
BEGIN
    DECLARE v_id_almacen INT;
    DECLARE v_id_usuario INT;
    DECLARE v_stock_anterior INT DEFAULT 0;
    DECLARE v_stock_actual INT DEFAULT 0;

    SELECT id_almacen, id_usuario
      INTO v_id_almacen, v_id_usuario
      FROM ventas WHERE id_venta = NEW.id_venta;

    SELECT stock_actual INTO v_stock_anterior
      FROM stock_almacen
     WHERE id_almacen = v_id_almacen AND id_producto = NEW.id_producto
     FOR UPDATE;

    IF v_stock_anterior < NEW.cantidad THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Stock insuficiente para realizar la venta';
    END IF;

    UPDATE stock_almacen
       SET stock_actual = stock_actual - NEW.cantidad
     WHERE id_almacen = v_id_almacen AND id_producto = NEW.id_producto;

    SET v_stock_actual = v_stock_anterior - NEW.cantidad;

    INSERT INTO movimientos_stock
    (id_producto, id_almacen, id_usuario, tipo_movimiento, cantidad, motivo,
     referencia_tipo, referencia_id, referencia)
    VALUES
    (NEW.id_producto, v_id_almacen, v_id_usuario, 'SALIDA', NEW.cantidad,
     'Venta registrada', 'VENTA', NEW.id_venta, CONCAT('VENTA-', NEW.id_venta));

    INSERT INTO kardex
    (id_producto, id_almacen, id_usuario, tipo_movimiento, referencia_tipo,
     referencia_id, cantidad, costo_unitario, stock_anterior, stock_actual,
     saldo_valorizado, observacion)
    VALUES
    (NEW.id_producto, v_id_almacen, v_id_usuario, 'SALIDA', 'VENTA',
     NEW.id_venta, NEW.cantidad, NEW.costo_unitario, v_stock_anterior,
     v_stock_actual, ROUND(v_stock_actual * NEW.costo_unitario, 2),
     'Salida automática por venta');
END$$

CREATE TRIGGER trg_detalle_ventas_bu_bloquear
BEFORE UPDATE ON detalle_ventas
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se permite editar un detalle de venta; anule y registre nuevamente';
END$$

CREATE TRIGGER trg_detalle_ventas_bd_bloquear
BEFORE DELETE ON detalle_ventas
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se permite eliminar un detalle de venta; utilice la anulación';
END$$

CREATE TRIGGER trg_pagos_bi_validar
BEFORE INSERT ON pagos
FOR EACH ROW
BEGIN
    DECLARE v_total DECIMAL(12,2);
    DECLARE v_pagado DECIMAL(12,2);
    DECLARE v_estado_venta VARCHAR(20);
    DECLARE v_requiere_ref TINYINT;

    SELECT total, estado INTO v_total, v_estado_venta
      FROM ventas WHERE id_venta = NEW.id_venta;

    IF v_estado_venta IS NULL OR v_estado_venta <> 'EMITIDA' THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'No se puede pagar una venta inexistente o anulada';
    END IF;

    SELECT requiere_referencia INTO v_requiere_ref
      FROM metodos_pago WHERE id_metodo_pago = NEW.id_metodo_pago;

    IF v_requiere_ref = 1 AND (NEW.referencia IS NULL OR TRIM(NEW.referencia) = '') THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'El método de pago requiere una referencia';
    END IF;

    SELECT COALESCE(SUM(monto), 0) INTO v_pagado
      FROM pagos WHERE id_venta = NEW.id_venta AND estado = 'REGISTRADO';

    IF v_pagado + NEW.monto > v_total + 0.009 THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'El pago excede el saldo pendiente de la venta';
    END IF;
END$$

CREATE TRIGGER trg_pagos_ai_estado
AFTER INSERT ON pagos
FOR EACH ROW
BEGIN
    DECLARE v_total DECIMAL(12,2);
    DECLARE v_pagado DECIMAL(12,2);

    SELECT total INTO v_total FROM ventas WHERE id_venta = NEW.id_venta;
    SELECT COALESCE(SUM(monto), 0) INTO v_pagado
      FROM pagos WHERE id_venta = NEW.id_venta AND estado = 'REGISTRADO';

    UPDATE ventas
       SET estado_pago = CASE
           WHEN v_pagado <= 0 THEN 'PENDIENTE'
           WHEN v_pagado + 0.009 >= v_total THEN 'PAGADO'
           ELSE 'PARCIAL'
       END
     WHERE id_venta = NEW.id_venta;
END$$

CREATE TRIGGER trg_pagos_au_estado
AFTER UPDATE ON pagos
FOR EACH ROW
BEGIN
    DECLARE v_total DECIMAL(12,2);
    DECLARE v_pagado DECIMAL(12,2);

    SELECT total INTO v_total FROM ventas WHERE id_venta = NEW.id_venta;
    SELECT COALESCE(SUM(monto), 0) INTO v_pagado
      FROM pagos WHERE id_venta = NEW.id_venta AND estado = 'REGISTRADO';

    UPDATE ventas
       SET estado_pago = CASE
           WHEN v_pagado <= 0 THEN 'PENDIENTE'
           WHEN v_pagado + 0.009 >= v_total THEN 'PAGADO'
           ELSE 'PARCIAL'
       END
     WHERE id_venta = NEW.id_venta;
END$$

-- =====================================================================
-- PROCEDIMIENTOS CONTROLADOS
-- =====================================================================
CREATE PROCEDURE sp_anular_venta(
    IN p_id_venta BIGINT,
    IN p_id_usuario INT,
    IN p_motivo VARCHAR(200)
)
BEGIN
    DECLARE v_estado VARCHAR(20);
    DECLARE v_id_almacen INT;
    DECLARE v_producto INT;
    DECLARE v_cantidad INT;
    DECLARE v_costo DECIMAL(12,2);
    DECLARE v_stock_anterior INT;
    DECLARE v_stock_actual INT;
    DECLARE done INT DEFAULT 0;

    DECLARE cur CURSOR FOR
        SELECT id_producto, cantidad, costo_unitario
          FROM detalle_ventas WHERE id_venta = p_id_venta;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        RESIGNAL;
    END;

    START TRANSACTION;

    SELECT estado, id_almacen INTO v_estado, v_id_almacen
      FROM ventas WHERE id_venta = p_id_venta FOR UPDATE;

    IF v_estado IS NULL THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La venta no existe';
    END IF;
    IF v_estado = 'ANULADA' THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La venta ya está anulada';
    END IF;
    IF EXISTS (SELECT 1 FROM pagos WHERE id_venta = p_id_venta AND estado = 'REGISTRADO') THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Anule primero los pagos registrados de la venta';
    END IF;

    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO v_producto, v_cantidad, v_costo;
        IF done = 1 THEN LEAVE read_loop; END IF;

        SELECT stock_actual INTO v_stock_anterior
          FROM stock_almacen
         WHERE id_almacen = v_id_almacen AND id_producto = v_producto
         FOR UPDATE;

        UPDATE stock_almacen
           SET stock_actual = stock_actual + v_cantidad
         WHERE id_almacen = v_id_almacen AND id_producto = v_producto;

        SET v_stock_actual = v_stock_anterior + v_cantidad;

        INSERT INTO movimientos_stock
        (id_producto, id_almacen, id_usuario, tipo_movimiento, cantidad, motivo,
         referencia_tipo, referencia_id, referencia)
        VALUES
        (v_producto, v_id_almacen, p_id_usuario, 'ENTRADA', v_cantidad,
         'Anulación de venta', 'ANULACION', p_id_venta,
         CONCAT('ANULA-VENTA-', p_id_venta));

        INSERT INTO kardex
        (id_producto, id_almacen, id_usuario, tipo_movimiento, referencia_tipo,
         referencia_id, cantidad, costo_unitario, stock_anterior, stock_actual,
         saldo_valorizado, observacion)
        VALUES
        (v_producto, v_id_almacen, p_id_usuario, 'ENTRADA', 'ANULACION',
         p_id_venta, v_cantidad, v_costo, v_stock_anterior, v_stock_actual,
         ROUND(v_stock_actual * v_costo, 2), 'Reversión por anulación de venta');
    END LOOP;
    CLOSE cur;

    UPDATE ventas
       SET estado = 'ANULADA', estado_pago = 'PENDIENTE',
           fecha_anulacion = NOW(), motivo_anulacion = p_motivo
     WHERE id_venta = p_id_venta;

    INSERT INTO auditoria
    (id_usuario, tabla_afectada, registro_id, accion, descripcion)
    VALUES
    (p_id_usuario, 'ventas', p_id_venta, 'ANULAR', p_motivo);

    COMMIT;
END$$

CREATE PROCEDURE sp_anular_compra(
    IN p_id_compra BIGINT,
    IN p_id_usuario INT,
    IN p_motivo VARCHAR(200)
)
BEGIN
    DECLARE v_estado VARCHAR(20);
    DECLARE v_id_almacen INT;
    DECLARE v_producto INT;
    DECLARE v_cantidad INT;
    DECLARE v_costo DECIMAL(12,2);
    DECLARE v_stock_anterior INT;
    DECLARE v_stock_actual INT;
    DECLARE done INT DEFAULT 0;

    DECLARE cur CURSOR FOR
        SELECT id_producto, cantidad, costo_unitario
          FROM detalle_compras WHERE id_compra = p_id_compra;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        RESIGNAL;
    END;

    START TRANSACTION;

    SELECT estado, id_almacen INTO v_estado, v_id_almacen
      FROM compras WHERE id_compra = p_id_compra FOR UPDATE;

    IF v_estado IS NULL THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La compra no existe';
    END IF;
    IF v_estado = 'ANULADA' THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La compra ya está anulada';
    END IF;

    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO v_producto, v_cantidad, v_costo;
        IF done = 1 THEN LEAVE read_loop; END IF;

        SELECT stock_actual INTO v_stock_anterior
          FROM stock_almacen
         WHERE id_almacen = v_id_almacen AND id_producto = v_producto
         FOR UPDATE;

        IF v_stock_anterior < v_cantidad THEN
            SIGNAL SQLSTATE '45000'
                SET MESSAGE_TEXT = 'No se puede anular la compra: parte del stock ya fue utilizado';
        END IF;

        UPDATE stock_almacen
           SET stock_actual = stock_actual - v_cantidad
         WHERE id_almacen = v_id_almacen AND id_producto = v_producto;

        SET v_stock_actual = v_stock_anterior - v_cantidad;

        INSERT INTO movimientos_stock
        (id_producto, id_almacen, id_usuario, tipo_movimiento, cantidad, motivo,
         referencia_tipo, referencia_id, referencia)
        VALUES
        (v_producto, v_id_almacen, p_id_usuario, 'SALIDA', v_cantidad,
         'Anulación de compra', 'ANULACION', p_id_compra,
         CONCAT('ANULA-COMPRA-', p_id_compra));

        INSERT INTO kardex
        (id_producto, id_almacen, id_usuario, tipo_movimiento, referencia_tipo,
         referencia_id, cantidad, costo_unitario, stock_anterior, stock_actual,
         saldo_valorizado, observacion)
        VALUES
        (v_producto, v_id_almacen, p_id_usuario, 'SALIDA', 'ANULACION',
         p_id_compra, v_cantidad, v_costo, v_stock_anterior, v_stock_actual,
         ROUND(v_stock_actual * v_costo, 2), 'Reversión por anulación de compra');
    END LOOP;
    CLOSE cur;

    UPDATE compras
       SET estado = 'ANULADA', fecha_anulacion = NOW(), motivo_anulacion = p_motivo
     WHERE id_compra = p_id_compra;

    INSERT INTO auditoria
    (id_usuario, tabla_afectada, registro_id, accion, descripcion)
    VALUES
    (p_id_usuario, 'compras', p_id_compra, 'ANULAR', p_motivo);

    COMMIT;
END$$

CREATE PROCEDURE sp_trasladar_stock(
    IN p_id_producto INT,
    IN p_id_almacen_origen INT,
    IN p_id_almacen_destino INT,
    IN p_cantidad INT,
    IN p_id_usuario INT,
    IN p_observacion VARCHAR(200)
)
BEGIN
    DECLARE v_stock_origen INT;
    DECLARE v_stock_destino INT;
    DECLARE v_costo DECIMAL(12,2);
    DECLARE v_ref BIGINT;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        RESIGNAL;
    END;

    IF p_id_almacen_origen = p_id_almacen_destino THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Los almacenes de origen y destino deben ser diferentes';
    END IF;
    IF p_cantidad <= 0 THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La cantidad debe ser mayor que cero';
    END IF;

    START TRANSACTION;

    SELECT precio_compra INTO v_costo FROM productos WHERE id_producto = p_id_producto;

    SELECT stock_actual INTO v_stock_origen
      FROM stock_almacen
     WHERE id_almacen = p_id_almacen_origen AND id_producto = p_id_producto
     FOR UPDATE;

    IF v_stock_origen < p_cantidad THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Stock insuficiente en el almacén de origen';
    END IF;

    INSERT INTO stock_almacen (id_almacen, id_producto, stock_actual)
    VALUES (p_id_almacen_destino, p_id_producto, 0)
    ON DUPLICATE KEY UPDATE stock_actual = stock_actual;

    SELECT stock_actual INTO v_stock_destino
      FROM stock_almacen
     WHERE id_almacen = p_id_almacen_destino AND id_producto = p_id_producto
     FOR UPDATE;

    SET v_ref = UNIX_TIMESTAMP(NOW(6));

    UPDATE stock_almacen SET stock_actual = stock_actual - p_cantidad
     WHERE id_almacen = p_id_almacen_origen AND id_producto = p_id_producto;
    UPDATE stock_almacen SET stock_actual = stock_actual + p_cantidad
     WHERE id_almacen = p_id_almacen_destino AND id_producto = p_id_producto;

    INSERT INTO movimientos_stock
    (id_producto, id_almacen, id_almacen_destino, id_usuario, tipo_movimiento,
     cantidad, motivo, referencia_tipo, referencia_id, referencia)
    VALUES
    (p_id_producto, p_id_almacen_origen, p_id_almacen_destino, p_id_usuario,
     'TRASLADO', p_cantidad, COALESCE(p_observacion,'Traslado entre almacenes'),
     'TRASLADO', v_ref, CONCAT('TRASLADO-', v_ref));

    INSERT INTO kardex
    (id_producto, id_almacen, id_usuario, tipo_movimiento, referencia_tipo,
     referencia_id, cantidad, costo_unitario, stock_anterior, stock_actual,
     saldo_valorizado, observacion)
    VALUES
    (p_id_producto, p_id_almacen_origen, p_id_usuario, 'TRASLADO', 'TRASLADO',
     v_ref, p_cantidad, v_costo, v_stock_origen, v_stock_origen - p_cantidad,
     ROUND((v_stock_origen - p_cantidad) * v_costo,2), 'Salida por traslado'),
    (p_id_producto, p_id_almacen_destino, p_id_usuario, 'TRASLADO', 'TRASLADO',
     v_ref, p_cantidad, v_costo, v_stock_destino, v_stock_destino + p_cantidad,
     ROUND((v_stock_destino + p_cantidad) * v_costo,2), 'Entrada por traslado');

    COMMIT;
END$$

DELIMITER ;

-- =====================================================================
-- VISTAS DE CONSULTA
-- =====================================================================
CREATE OR REPLACE VIEW vw_usuarios_roles AS
SELECT
    u.id_usuario,
    u.nombre AS usuario,
    u.email,
    u.estado AS estado_usuario,
    GROUP_CONCAT(r.nombre ORDER BY r.nombre SEPARATOR ', ') AS roles
FROM usuarios u
LEFT JOIN usuario_roles ur ON ur.id_usuario = u.id_usuario
LEFT JOIN roles r ON r.id_rol = ur.id_rol
GROUP BY u.id_usuario, u.nombre, u.email, u.estado;

CREATE OR REPLACE VIEW vw_stock_actual AS
SELECT
    sa.id_almacen,
    a.nombre AS almacen,
    p.id_producto,
    p.codigo,
    p.nombre AS producto,
    c.nombre AS categoria,
    m.nombre AS marca,
    sa.stock_actual,
    p.stock_minimo,
    CASE WHEN sa.stock_actual <= p.stock_minimo THEN 'STOCK BAJO' ELSE 'STOCK NORMAL' END AS estado_stock,
    p.precio_compra,
    ROUND(sa.stock_actual * p.precio_compra, 2) AS valor_stock
FROM stock_almacen sa
INNER JOIN almacenes a ON a.id_almacen = sa.id_almacen
INNER JOIN productos p ON p.id_producto = sa.id_producto
INNER JOIN categorias c ON c.id_categoria = p.id_categoria
INNER JOIN marcas m ON m.id_marca = p.id_marca;

CREATE OR REPLACE VIEW vw_ventas_detalladas AS
SELECT
    v.id_venta,
    CONCAT(v.serie, '-', v.numero) AS comprobante,
    v.fecha,
    c.nombre AS cliente,
    u.nombre AS vendedor,
    a.nombre AS almacen,
    p.codigo,
    p.nombre AS producto,
    dv.cantidad,
    dv.costo_unitario,
    dv.precio_unitario,
    dv.subtotal,
    ROUND((dv.precio_unitario - dv.costo_unitario) * dv.cantidad, 2) AS utilidad_bruta,
    v.igv,
    v.total,
    v.estado,
    v.estado_pago
FROM ventas v
INNER JOIN clientes c ON c.id_cliente = v.id_cliente
INNER JOIN usuarios u ON u.id_usuario = v.id_usuario
INNER JOIN almacenes a ON a.id_almacen = v.id_almacen
INNER JOIN detalle_ventas dv ON dv.id_venta = v.id_venta
INNER JOIN productos p ON p.id_producto = dv.id_producto;

CREATE OR REPLACE VIEW vw_saldos_ventas AS
SELECT
    v.id_venta,
    CONCAT(v.serie, '-', v.numero) AS comprobante,
    v.fecha,
    c.nombre AS cliente,
    v.total,
    COALESCE(SUM(CASE WHEN p.estado = 'REGISTRADO' THEN p.monto ELSE 0 END), 0) AS total_pagado,
    ROUND(v.total - COALESCE(SUM(CASE WHEN p.estado = 'REGISTRADO' THEN p.monto ELSE 0 END), 0), 2) AS saldo_pendiente,
    v.estado_pago,
    v.estado
FROM ventas v
INNER JOIN clientes c ON c.id_cliente = v.id_cliente
LEFT JOIN pagos p ON p.id_venta = v.id_venta
GROUP BY v.id_venta, v.serie, v.numero, v.fecha, c.nombre, v.total, v.estado_pago, v.estado;

-- =====================================================================
-- DATOS SEMILLA
-- Contraseña para los usuarios demo: password
-- =====================================================================
INSERT INTO empresa
(ruc, razon_social, nombre_comercial, direccion, telefono, email)
VALUES
('20600000099', 'Sistema Ventas Demo SAC', 'Ventas Demo',
 'Av. Principal 123 - Lima', '999888777', 'contacto@ventasdemo.com');

INSERT INTO roles (nombre, descripcion, es_sistema) VALUES
('ADMINISTRADOR', 'Acceso total al sistema', 1),
('VENDEDOR', 'Gestiona clientes, ventas y pagos', 1),
('ALMACENERO', 'Gestiona productos, compras e inventario', 1),
('CAJERO', 'Gestiona caja y pagos', 1);

INSERT INTO usuarios (nombre, email, imagen, password_hash) VALUES
('Administrador General', 'admin@sistema.com', 'uploads/usuarios/admin.png',
 '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi'),
('Vendedor Principal', 'vendedor@sistema.com', 'uploads/usuarios/vendedor.png',
 '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi'),
('Almacenero Principal', 'almacen@sistema.com', 'uploads/usuarios/almacenero.png',
 '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi'),
('Cajero Principal', 'caja@sistema.com', 'uploads/usuarios/cajero.png',
 '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi');

INSERT INTO usuario_roles (id_usuario, id_rol) VALUES
(1,1),(2,2),(3,3),(4,4);

INSERT INTO modulos (nombre, ruta, icono, orden_menu) VALUES
('Empresa', '/empresa', 'bi-building', 1),
('Usuarios', '/usuarios', 'bi-people', 2),
('Roles', '/roles', 'bi-shield-lock', 3),
('Clientes', '/clientes', 'bi-person-vcard', 4),
('Proveedores', '/proveedores', 'bi-truck', 5),
('Categorías', '/categorias', 'bi-tags', 6),
('Marcas', '/marcas', 'bi-bookmark', 7),
('Productos', '/productos', 'bi-box-seam', 8),
('Almacenes', '/almacenes', 'bi-buildings', 9),
('Inventario', '/inventario', 'bi-boxes', 10),
('Kardex', '/kardex', 'bi-journal-text', 11),
('Compras', '/compras', 'bi-cart-plus', 12),
('Ventas', '/ventas', 'bi-cart-check', 13),
('Pagos', '/pagos', 'bi-cash-coin', 14),
('Caja', '/caja', 'bi-safe', 15),
('Reportes', '/reportes', 'bi-bar-chart', 16),
('Auditoría', '/auditoria', 'bi-clipboard-data', 17);

INSERT INTO permisos (id_modulo, nombre, descripcion)
SELECT id_modulo, 'ver', CONCAT('Ver ', nombre) FROM modulos;
INSERT INTO permisos (id_modulo, nombre, descripcion)
SELECT id_modulo, 'crear', CONCAT('Crear ', nombre)
FROM modulos WHERE nombre NOT IN ('Reportes','Auditoría','Kardex');
INSERT INTO permisos (id_modulo, nombre, descripcion)
SELECT id_modulo, 'editar', CONCAT('Editar ', nombre)
FROM modulos WHERE nombre NOT IN ('Reportes','Auditoría','Kardex');
INSERT INTO permisos (id_modulo, nombre, descripcion)
SELECT id_modulo, 'anular', CONCAT('Anular ', nombre)
FROM modulos WHERE nombre IN ('Compras','Ventas','Pagos');
INSERT INTO permisos (id_modulo, nombre, descripcion)
SELECT id_modulo, 'eliminar', CONCAT('Eliminar ', nombre)
FROM modulos WHERE nombre IN ('Clientes','Proveedores','Categorías','Marcas','Productos','Usuarios','Roles');

INSERT INTO rol_permisos (id_rol, id_permiso)
SELECT 1, id_permiso FROM permisos;
INSERT INTO rol_permisos (id_rol, id_permiso)
SELECT 2, p.id_permiso FROM permisos p
INNER JOIN modulos m ON m.id_modulo = p.id_modulo
WHERE m.nombre IN ('Clientes','Productos','Ventas','Pagos','Reportes');
INSERT INTO rol_permisos (id_rol, id_permiso)
SELECT 3, p.id_permiso FROM permisos p
INNER JOIN modulos m ON m.id_modulo = p.id_modulo
WHERE m.nombre IN ('Proveedores','Categorías','Marcas','Productos','Almacenes','Inventario','Kardex','Compras','Reportes');
INSERT INTO rol_permisos (id_rol, id_permiso)
SELECT 4, p.id_permiso FROM permisos p
INNER JOIN modulos m ON m.id_modulo = p.id_modulo
WHERE m.nombre IN ('Pagos','Caja','Reportes');

INSERT INTO clientes
(tipo_documento, numero_documento, nombre, direccion, telefono, email) VALUES
('DNI','12345678','Juan Pérez','Av. Principal 123','999111222','juan@gmail.com'),
('RUC','20123456789','Empresa Demo SAC','Av. Comercial 456','987654321','empresa@gmail.com'),
('CE','CE12345678','Carlos Ramírez','Jr. Las Flores 321','988111333','carlos@gmail.com');

INSERT INTO proveedores (ruc, razon_social, telefono, email, direccion) VALUES
('20600000001','Proveedor Tecnológico SAC','999888777','proveedor1@gmail.com','Av. Industrial 100'),
('20600000002','Distribuidora Digital EIRL','988777666','proveedor2@gmail.com','Jr. Comercio 200');

INSERT INTO categorias (nombre, descripcion) VALUES
('Computadoras','Laptops y computadoras de escritorio'),
('Periféricos','Mouse, teclado y audífonos'),
('Componentes','Memorias, discos y partes internas'),
('Accesorios','Cables, adaptadores y otros');

INSERT INTO marcas (nombre, descripcion) VALUES
('HP','Marca de computadoras'),
('Lenovo','Marca de laptops'),
('Logitech','Marca de periféricos'),
('Kingston','Marca de memorias y almacenamiento');

INSERT INTO productos
(id_categoria,id_marca,codigo,nombre,descripcion,imagen,precio_compra,precio_venta,stock_minimo) VALUES
(1,1,'PROD001','Laptop HP Core i5','Laptop para oficina y estudio','uploads/productos/laptop_hp_core_i5.png',2000.00,2500.00,2),
(2,3,'PROD002','Mouse Logitech','Mouse inalámbrico','uploads/productos/mouse_logitech.png',40.00,65.00,5),
(2,3,'PROD003','Teclado Logitech','Teclado USB','uploads/productos/teclado_logitech.png',55.00,85.00,5),
(3,4,'PROD004','SSD Kingston 1TB','Disco sólido SSD 1TB','uploads/productos/ssd_kingston_1tb.png',250.00,350.00,3);

INSERT INTO tipos_comprobante (codigo,nombre,tipo) VALUES
('BV','BOLETA DE VENTA','VENTA'),
('FV','FACTURA DE VENTA','VENTA'),
('TC','TICKET DE VENTA','VENTA'),
('FC','FACTURA DE COMPRA','COMPRA');

INSERT INTO series_comprobantes (id_tipo_comprobante,serie,numero_actual) VALUES
(1,'B001',1),(2,'F001',1),(3,'T001',1),(4,'C001',1);

INSERT INTO metodos_pago (nombre,descripcion,requiere_referencia) VALUES
('EFECTIVO','Pago en efectivo',0),
('YAPE','Pago mediante Yape',1),
('TRANSFERENCIA','Pago por transferencia bancaria',1),
('TARJETA','Pago con tarjeta',1);

INSERT INTO almacenes (nombre,direccion) VALUES
('Almacén Principal','Av. Principal 123'),
('Tienda Central','Av. Comercial 456');

INSERT INTO stock_almacen (id_almacen,id_producto,stock_actual) VALUES
(1,1,10),(1,2,30),(1,3,20),(1,4,15),
(2,1,3),(2,2,10),(2,3,8),(2,4,5);

INSERT INTO movimientos_stock
(id_producto,id_almacen,id_usuario,tipo_movimiento,cantidad,motivo,referencia_tipo,referencia) VALUES
(1,1,3,'AJUSTE',10,'Stock inicial','INICIAL','INICIAL'),
(2,1,3,'AJUSTE',30,'Stock inicial','INICIAL','INICIAL'),
(3,1,3,'AJUSTE',20,'Stock inicial','INICIAL','INICIAL'),
(4,1,3,'AJUSTE',15,'Stock inicial','INICIAL','INICIAL'),
(1,2,3,'AJUSTE',3,'Stock inicial','INICIAL','INICIAL'),
(2,2,3,'AJUSTE',10,'Stock inicial','INICIAL','INICIAL'),
(3,2,3,'AJUSTE',8,'Stock inicial','INICIAL','INICIAL'),
(4,2,3,'AJUSTE',5,'Stock inicial','INICIAL','INICIAL');

INSERT INTO kardex
(id_producto,id_almacen,id_usuario,tipo_movimiento,referencia_tipo,cantidad,costo_unitario,stock_anterior,stock_actual,saldo_valorizado,observacion) VALUES
(1,1,3,'AJUSTE','INICIAL',10,2000.00,0,10,20000.00,'Stock inicial'),
(2,1,3,'AJUSTE','INICIAL',30,40.00,0,30,1200.00,'Stock inicial'),
(3,1,3,'AJUSTE','INICIAL',20,55.00,0,20,1100.00,'Stock inicial'),
(4,1,3,'AJUSTE','INICIAL',15,250.00,0,15,3750.00,'Stock inicial'),
(1,2,3,'AJUSTE','INICIAL',3,2000.00,0,3,6000.00,'Stock inicial'),
(2,2,3,'AJUSTE','INICIAL',10,40.00,0,10,400.00,'Stock inicial'),
(3,2,3,'AJUSTE','INICIAL',8,55.00,0,8,440.00,'Stock inicial'),
(4,2,3,'AJUSTE','INICIAL',5,250.00,0,5,1250.00,'Stock inicial');

-- Compra de ejemplo: los triggers incrementan stock y registran kardex.
INSERT INTO compras
(id_proveedor,id_usuario,id_almacen,id_tipo_comprobante,serie,numero,subtotal,igv,total) VALUES
(1,3,1,4,'C001','000001',2200.00,396.00,2596.00);
INSERT INTO detalle_compras
(id_compra,id_producto,cantidad,costo_unitario,subtotal) VALUES
(1,1,1,2000.00,2000.00),
(1,2,5,40.00,200.00);

-- Venta de ejemplo: costo histórico se captura automáticamente.
INSERT INTO ventas
(id_cliente,id_usuario,id_almacen,id_tipo_comprobante,serie,numero,subtotal,igv,total) VALUES
(1,2,1,1,'B001','000001',2500.00,450.00,2950.00);
INSERT INTO detalle_ventas
(id_venta,id_producto,cantidad,costo_unitario,precio_unitario,subtotal) VALUES
(1,1,1,0.00,2500.00,2500.00);

INSERT INTO cajas (nombre,descripcion) VALUES
('Caja Principal','Caja de ventas principal'),
('Caja Secundaria','Caja auxiliar');

INSERT INTO cierres_caja
(id_caja,id_usuario_apertura,saldo_inicial,estado,observacion) VALUES
(1,4,500.00,'ABIERTA','Apertura de caja de demostración');

INSERT INTO movimientos_caja
(id_cierre_caja,id_caja,id_usuario,tipo_movimiento,monto,descripcion) VALUES
(1,1,4,'APERTURA',500.00,'Apertura de caja');

INSERT INTO pagos
(id_venta,id_metodo_pago,id_usuario,id_cierre_caja,monto,referencia,observacion) VALUES
(1,1,4,1,2950.00,'PAGO-VENTA-1','Pago total en efectivo');

INSERT INTO movimientos_caja
(id_cierre_caja,id_caja,id_usuario,id_pago,tipo_movimiento,monto,descripcion) VALUES
(1,1,4,1,'INGRESO',2950.00,'Ingreso por venta B001-000001');

UPDATE cierres_caja
SET total_ingresos = 2950.00,
    total_egresos = 0.00,
    saldo_sistema = 3450.00
WHERE id_cierre_caja = 1;

INSERT INTO sesiones
(id_usuario,token_hash,ip,navegador) VALUES
(1,SHA2('TOKEN_ADMIN_DEMO_001',256),'127.0.0.1','Google Chrome');

INSERT INTO auditoria
(id_usuario,tabla_afectada,registro_id,accion,descripcion) VALUES
(1,'usuarios',1,'LOGIN','Inicio de sesión del administrador'),
(3,'compras',1,'INSERT','Registro de compra inicial'),
(2,'ventas',1,'INSERT','Registro de venta inicial'),
(4,'pagos',1,'INSERT','Registro de pago inicial');

-- =====================================================================
-- CONSULTAS DE VALIDACIÓN RÁPIDA
-- =====================================================================
-- SELECT * FROM vw_usuarios_roles;
-- SELECT * FROM vw_stock_actual ORDER BY almacen, producto;
-- SELECT * FROM vw_ventas_detalladas;
-- SELECT * FROM vw_saldos_ventas;
-- SELECT COUNT(*) AS tablas FROM information_schema.tables WHERE table_schema='db_ventas_v2';
-- SHOW TRIGGERS FROM db_ventas_v2;
-- SHOW PROCEDURE STATUS WHERE Db='db_ventas_v2';

-- FIN DEL SCRIPT
