listarProductos(); // Saneamiento de datos para enviar a la view foreach ($productos as $i => $p) { if (($p['precio'] === null) || ($p['precio'] == 0)) { $productos[$i]['precio'] = '-'; } else { $productos[$i]['precio'] = '$ ' . number_format($p['precio'], 2, '.', ','); } if ($p['stock'] === null || $p['stock'] === 0) { $productos[$i]['stock'] = '-'; } $productos[$i]['descuento_total'] = number_format($p['descuento_total'], 2, '.', '') . ' %'; } ob_start(); require __DIR__ . '/../views/productos/listaProductosView.php'; return ob_get_clean(); // LISTAR PRODUCTOS INACTIVOS case 'productos_inactivos': // Utilizamos el modelo para obtener la lista completa de productos $productos = $productomodel->listarProductosInactivos(); ob_start(); require __DIR__ . '/../views/productos/listaProductosInactivosView.php'; return ob_get_clean(); // CREAR PRODUCTO case 'crear_producto': // Mostramos la vista con los datos correspondientes if ($_SERVER['REQUEST_METHOD'] === 'GET') { $categorias = $productomodel->listarCategorias(); $tipos = $productomodel->listarTipos(); ob_start(); require __DIR__ . '/../views/productos/crearProductoView.php'; return ob_get_clean(); } // En caso de modificación de datos if ($_SERVER['REQUEST_METHOD'] === 'POST') { $marca = trim($_POST['marca'] ?? ''); $modelo = trim($_POST['modelo'] ?? ''); $id_categoria = trim($_POST['categoria'] ?? ''); $id_tipo = trim($_POST['tipo'] ?? ''); // Normalización de datos $descuentoRaw = trim($_POST['descuento'] ?? ''); $descuento = $descuentoRaw === '' ? null : $descuentoRaw; $errores = []; // Validaciones if ($marca === '') { $errores[] = "La marca no puede estar vacía."; } else if (!preg_match("/^[A-Za-zÁÉÍÓÚÑáéíóúñ0-9]+(?: [A-Za-zÁÉÍÓÚÑáéíóúñ0-9]+)*$/", $marca)) { $errores[] = "La marca solo puede contener letras, números y espacios."; } else if (strlen($marca) < 2) { $errores[] = "La marca debe tener al menos 2 caracteres."; } else if (strlen($marca) > 50) { $errores[] = "La marca no puede superar los 50 caracteres."; } if ($modelo === '') { $errores[] = "El modelo no puede estar vacío."; } else if (!preg_match("/^[A-Za-zÁÉÍÓÚÑáéíóúñ0-9.\-]+(?: [A-Za-zÁÉÍÓÚÑáéíóúñ0-9.\-]+)*$/", $modelo)) { $errores[] = "El modelo solo puede contener letras, números, espacios, guiones y puntos"; } else if (strlen($modelo) < 2) { $errores[] = "El modelo debe tener al menos 2 caracteres."; } else if (strlen($modelo) > 50) { $errores[] = "El modelo no puede superar los 50 caracteres."; } if ($descuento !== null) { if (!preg_match("/^\d{1,3}(\.\d{1,2})?$/", $descuento)) { $errores[] = "El descuento debe ser un número válido con hasta 2 decimales."; } else if ((float)$descuento <= 0 || (float)$descuento > 100) { $errores[] = "El descuento debe estar entre 0 a 100."; } } if ($id_categoria === '') { $errores[] = "Debe seleccionar una categoría."; } else if (!filter_var($id_categoria, FILTER_VALIDATE_INT) || $id_categoria <= 0) { $errores[] = "La categoría seleccionada no es válida."; } else if (!$productomodel->existeCategoria($id_categoria)) { $errores[] = "La categoría ingresada no existe."; } if ($id_tipo === '') { $errores[] = "Debe seleccionar un tipo."; } else if (!filter_var($id_tipo, FILTER_VALIDATE_INT) || $id_tipo <= 0) { $errores[] = "El tipo seleccionado no es válido."; } else if (!$productomodel->existeTipo($id_tipo)) { $errores[] = "El tipo ingresado no existe."; } if (($id_tipo === 2) && ($descuento !== null)) { $errores[] = "No se permite descuento si el tipo de producto es Servicio."; } if (!empty($errores)) { $_SESSION['flash_error'] = implode('
', $errores); header("Location: index.php?opt=crear_producto"); exit; } // Utilizamos el método del modelo para crear el producto if ($productomodel->crearProducto([ 'marca' => $marca, 'modelo' => $modelo, 'precio' => null, 'stock' => null, 'descuento' => $descuento !== null ? (float)$descuento : null, 'id_categoria' => $id_categoria, 'id_tipo' => $id_tipo ])) { $_SESSION['flash_success'] = "Producto creado correctamente."; } else { $_SESSION['flash_error'] = "No se pudo crear el producto."; } header("Location: index.php?opt=productos"); exit; } // EDITAR PRODUCTO case 'editar_producto': $idEditar = (int) ($_GET['id'] ?? 0); if ($idEditar <= 0) { header("Location: index.php?opt=productos"); exit; } // Busco el producto en la base de datos mediante el modelo $producto = $productomodel->obtenerPorId($idEditar); if (!$producto) { $_SESSION['flash_error'] = "No se encontró el producto."; header("Location: index.php?opt=productos"); exit; }; // (Para indicar que aún no existen pedidos que incluyan dicho producto (no existe ID de pedido)) if ($producto['id_pedido'] === null) { $producto['id_pedido'] = 'Aún no existe pedido que incluya este producto'; } // Si el descuento es null lo seteamos en 0 if ($producto['descuento'] === null) { $producto['descuento'] = 0; } // Mostrar datos de producto if ($_SERVER['REQUEST_METHOD'] === 'GET') { $categorias = $productomodel->listarCategorias(); $tipos = $productomodel->listarTipos(); ob_start(); require __DIR__ . '/../views/productos/editarProductoView.php'; return ob_get_clean(); } // Caso en donde se modifican los datos if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Normalización de datos $descuentoRaw = trim($_POST['descuento'] ?? ''); $descuento = $descuentoRaw === '' ? null : $descuentoRaw; $errores = []; // Validaciones if ($descuento !== null) { if (!preg_match("/^\d{1,3}(\.\d{1,2})?$/", $descuento)) { $errores[] = "El descuento debe ser un número válido con hasta 2 decimales."; } else if ((float)$descuento < 0 || (float)$descuento > 100) { $errores[] = "El descuento debe estar entre 0 a 100."; } } if (!empty($errores)) { $_SESSION['flash_error'] = implode('
', $errores); header("Location: index.php?opt=editar_producto&id=" . $idEditar); exit; } // Recalculoamos precio (en caso de que se modifique descuento) require_once __DIR__ . '/../models/pedidoModel.php'; $pedidomodel = new pedidoModel(); $costoUnitario = $pedidomodel->obtenerCosto($_GET['id']); $categoria = $productomodel->obtenerPorIdCategoria($producto['id_categoria']); // Antes de guardar los datos verificamos que la suma del descuento no sea mayor a 100 if (($categoria['porcentaje_ganancia'] + $descuento) > 100) { $_SESSION['flash_error'] = "La suma entre el descuento ingresado y el descuento de la categoria supera el 100%. Verifique."; header("Location:index.php?opt=editar_producto&id=$idEditar"); exit; } // Creamos el array con los datos correspondientes $guardarData = [ 'precio' => $costoUnitario !== null ? (100 + $categoria['porcentaje_ganancia']) * $costoUnitario / 100 : null, 'descuento' => $descuento !== null ? (float) $descuento : null, 'id_categoria' => $producto['id_categoria'] ]; // Utilizamos la función del modelo para actualizar el producto if ($productomodel->actualizarProducto($_GET['id'], $guardarData)) { $_SESSION['flash_success'] = "Datos actualizados correctamente."; } else { $_SESSION['flash_error'] = "No se pudo actualizar los datos."; } header("Location: index.php?opt=productos"); exit; } // CAMBIAR ESTADO DEL PRODUCTO (ACTIVO / INACTIVO) case 'cambiar_estado': $idProducto = (int) ($_POST['id'] ?? 0); $nuevoEstado = isset($_POST['estado']) ? (bool) $_POST['estado'] : null; if ($idProducto <= 0 || !is_bool($nuevoEstado)) { header("Location: index.php?opt=productos"); exit; }; $productomodel->actualizarEstado($idProducto, $nuevoEstado); $_SESSION['flash_success'] = "Estado actualizado correctamente."; header("Location: index.php?opt=productos"); exit; // LISTAR LAS CATEGORIAS DE PRODUCTOS case 'categorias': $categorias = $productomodel->listarCategorias(); foreach ($categorias as $i => $c) { if (($categorias)[$i]['porcentaje_ganancia'] === null) { $c['porcentaje_ganancia'] = 0; } if (($categorias)[$i]['descuento'] === null) { $c['descuento'] = 0; } $categorias[$i]['porcentaje_ganancia'] = number_format($c['porcentaje_ganancia'], 2, '.', '') . ' %'; $categorias[$i]['descuento'] = number_format($c['descuento'], 2, '.', '') . ' %'; } ob_start(); require __DIR__ . '/../views/productos/listaCategoriasView.php'; return ob_get_clean(); // CREAR NUEVA CATEGORIA DE PRODUCTOS case 'crear_categoria': if ($_SERVER['REQUEST_METHOD'] === 'GET') { ob_start(); require __DIR__ . '/../views/productos/crearCategoriaView.php'; return ob_get_clean(); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $nombre = trim($_POST['nombre'] ?? ''); // Normalización $porcentaje_gananciaRaw = trim($_POST['porcentaje_ganancia'] ?? ''); $porcentaje_ganancia = $porcentaje_gananciaRaw === '' ? null : $porcentaje_gananciaRaw; $descuentoRaw = trim($_POST['descuento'] ?? ''); $descuento = $descuentoRaw === '' ? null : $descuentoRaw; $errores = []; // Validaciones if ($nombre === '') { $errores[] = "El nombre no puede estar vacío."; } else if (!preg_match("/^[A-Za-zÁÉÍÓÚÑáéíóúñ0-9]+(?: [A-Za-zÁÉÍÓÚÑáéíóúñ0-9]+)*$/", $nombre)) { $errores[] = "El nombre solo puede contener letras, números y espacios."; } else if (strlen($nombre) < 2) { $errores[] = "El nombre debe tener al menos 2 caracteres."; } else if (strlen($nombre) > 50) { $errores[] = "El nombre no puede superar los 50 caracteres."; } if ($porcentaje_ganancia !== null) { if (!preg_match("/^\d{1,3}(\.\d{1,2})?$/", $porcentaje_ganancia)) { $errores[] = "La ganancia debe ser un número válido con hasta 2 decimales."; } else if ((float)$porcentaje_ganancia <= 0 || (float)$porcentaje_ganancia > 100) { $errores[] = "La ganancia debe estar entre 0 a 100."; } } if ($descuento !== null) { if (!preg_match("/^\d{1,3}(\.\d{1,2})?$/", $descuento)) { $errores[] = "El descuento debe ser un número válido con hasta 2 decimales."; } else if ((float)$descuento < 0 || (float)$descuento > 100) { $errores[] = "El descuento debe estar entre 0 a 100."; } } if (!empty($errores)) { $_SESSION['flash_error'] = implode('
', $errores); header("Location: index.php?opt=crear_categoria"); exit; } if ($productomodel->crearCategoria([ 'nombre' => $nombre, 'porcentaje_ganancia' => $porcentaje_ganancia !== null ? (float) $porcentaje_ganancia : null, 'descuento' => $descuento !== null ? (float) $descuento : null ])) { $_SESSION['flash_success'] = "Categoría creada correctamente."; } else { $_SESSION['flash_error'] = "No se pudo crear la categoría."; } header("Location: index.php?opt=categorias"); exit; } // EDITAR CATEGORIA case 'editar_categoria': $idEditar = (int) ($_GET['id'] ?? 0); if ($idEditar <= 0) { header("Location: index.php?opt=categorias"); exit; } // Busco la categoría en la base de datos mediante el modelo $categorias = $productomodel->obtenerPorIdCategoria($idEditar); if (!$categorias) { header("Location: index.php?opt=categorias"); exit; }; // Si el descuento o el porcentaje_ganancia es null lo seteamos en 0 if ($categorias['porcentaje_ganancia'] === null) { $categorias['porcentaje_ganancia'] = 0; } if ($categorias['descuento'] === null) { $categorias['descuento'] = 0; } // Mostrar datos de producto if ($_SERVER['REQUEST_METHOD'] === 'GET') { ob_start(); require __DIR__ . '/../views/productos/editarCategoriaView.php'; return ob_get_clean(); } // Caso en donde se modifican los datos if ($_SERVER['REQUEST_METHOD'] === 'POST') { $nombre = trim($_POST['nombre'] ?? ''); // Normalización $porcentaje_gananciaRaw = trim($_POST['porcentaje_ganancia'] ?? ''); $porcentaje_ganancia = $porcentaje_gananciaRaw === '' ? null : $porcentaje_gananciaRaw; $descuentoRaw = trim($_POST['descuento'] ?? ''); $descuento = $descuentoRaw === '' ? null : $descuentoRaw; $errores = []; // Validaciones if ($nombre === '') { $errores[] = "El nombre no puede estar vacío."; } else if (!preg_match("/^[A-Za-zÁÉÍÓÚÑáéíóúñ0-9]+(?: [A-Za-zÁÉÍÓÚÑáéíóúñ0-9]+)*$/", $nombre)) { $errores[] = "El nombre solo puede contener letras, números y espacios."; } else if (strlen($nombre) < 2) { $errores[] = "El nombre debe tener al menos 2 caracteres."; } else if (strlen($nombre) > 50) { $errores[] = "El nombre no puede superar los 50 caracteres."; } if ($porcentaje_ganancia !== null) { if (!preg_match("/^\d{1,3}(\.\d{1,2})?$/", $porcentaje_ganancia)) { $errores[] = "La ganancia debe ser un número válido con hasta 2 decimales."; } else if ((float)$porcentaje_ganancia <= 0 || (float)$porcentaje_ganancia > 100) { $errores[] = "La ganancia debe estar entre 0 a 100."; } } if ($descuento !== null) { if (!preg_match("/^\d{1,3}(\.\d{1,2})?$/", $descuento)) { $errores[] = "El descuento debe ser un número válido con hasta 2 decimales."; } else if ((float)$descuento < 0 || (float)$descuento > 100) { $errores[] = "El descuento debe estar entre 0 a 100."; } } if (!empty($errores)) { $_SESSION['flash_error'] = implode('
', $errores); header("Location: index.php?opt=editar_categoria&id=" . $idEditar); exit; } // Verificamos que la suma entre los descuentos no supere el 100% require_once __DIR__ . '/../models/productoModel.php'; $productomodel = new productoModel(); $productosDescuentos = $productomodel->obtenerDescuento($idEditar); foreach ($productosDescuentos as $i => $p) { if (($productosDescuentos[$i]['descuento'] + $descuento) > 100) { $_SESSION['flash_error'] = "Existe al menos un producto que supera el 100% de sumatoria en el descuento. Verifique."; header("Location:index.php?opt=editar_categoria&id=$idEditar"); exit; } } $guardarData = [ 'nombre' => $nombre, 'porcentaje_ganancia' => $porcentaje_ganancia !== null ? (float) $porcentaje_ganancia : null, 'descuento' => $descuento !== null ? (float) $descuento : null ]; // Obtenemos productos con sus respectivos costos para recalcular el precio de venta require_once __DIR__ . '/../models/pedidoModel.php'; $pedidomodel = new pedidoModel(); $costosProductos = $pedidomodel->obtenerCostosPorCategoria($idEditar); if ($productomodel->actualizarPreciosPorCategoria($idEditar, $guardarData, $costosProductos)) { $_SESSION['flash_success'] = "Datos actualizados correctamente."; } else { $_SESSION['flash_error'] = "No se pudo actualizar la categoría."; } header("Location: index.php?opt=categorias"); exit; } // DEFAULT (404) default: ob_start(); require __DIR__ . '/../views/404View.php'; return ob_get_clean(); }