Files
2026-08-04 19:24:03 -03:00

490 lines
14 KiB
PHP

<?php
require_once __DIR__ . '/../database/database.php';
class productoModel {
private PDO $db;
public function __construct() {
$this->db = Database::getConnection();
}
// LISTAR PRODUCTOS
public function listarProductos(): array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, p.stock, (COALESCE(p.descuento, 0) + COALESCE(c.descuento, 0)) AS descuento_total, c.nombre AS categoria, t.nombre AS tipo
FROM productos AS p
INNER JOIN categorias AS c ON (p.id_categoria = c.id)
INNER JOIN tipos AS t ON (p.id_tipo = t.id)
WHERE (p.estado IS TRUE)
ORDER BY p.id ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// LISTAR PRODUCTOS INACTIVOS
public function listarProductosInactivos(): array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, c.nombre AS categoria, t.nombre AS tipo
FROM productos AS p
INNER JOIN categorias AS c ON (p.id_categoria = c.id)
INNER JOIN tipos AS t ON (p.id_tipo = t.id)
WHERE (p.estado IS FALSE)
ORDER BY p.id ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// LISTAR PRODUCTOS PARA VENTA
public function listarProductosVenta(): array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, CAST(p.precio - ((COALESCE(p.descuento, 0) + COALESCE(c.descuento, 0)) * p.precio / 100) AS DECIMAL(10,2)) AS precio_final, p.stock,
(COALESCE(p.descuento, 0) + COALESCE(c.descuento, 0)) AS descuento_total
FROM productos AS p
INNER JOIN categorias AS c ON (p.id_categoria = c.id)
INNER JOIN tipos AS t ON (p.id_tipo = t.id)
WHERE (p.estado IS TRUE) AND (p.id_tipo = 1) AND (p.precio IS NOT NULL) AND (p.stock <> 0)
ORDER BY p.id ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// LISTAR PORDUCTOS PARA PEDIDO
public function listarProductosPedido(): array {
$sql = "SELECT p.id, p.marca, p.modelo, p.stock FROM productos AS p
INNER JOIN tipos AS t ON (p.id_tipo = t.id)
WHERE (p.estado IS TRUE)
ORDER BY p.id ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// LISTAR INSUMOS PARA SERVICIO
public function listarInsumosServicio(): array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, p.stock
FROM productos AS p
INNER JOIN categorias AS c ON (p.id_categoria = c.id)
INNER JOIN tipos AS t ON (p.id_tipo = t.id)
WHERE (p.estado IS TRUE) AND (p.id_tipo = 2) AND (p.precio IS NOT NULL) AND (p.stock <> 0)
ORDER BY p.id ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// CREAR PRODUCTO
public function crearProducto(array $data): bool {
$sql = "INSERT INTO productos (marca, modelo, precio, stock, descuento, estado, id_categoria, id_tipo)
VALUES (:marca, :modelo, :precio, :stock, :descuento, :estado, :id_categoria, :id_tipo)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([
':marca' => $data['marca'],
':modelo' => $data['modelo'],
':precio' => $data['precio'],
':stock' => $data['stock'],
':descuento' => $data['descuento'],
':estado' => 1, // Cuando un producto se crea, automáticamente se setea el estado en true, es decir está activo
':id_categoria' => $data['id_categoria'],
':id_tipo' => $data['id_tipo']
]);
}
// OBTENER PRODUCTO MEDIANTE ID
public function obtenerPorId(int $id): ?array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, p.stock, p.descuento, p.id_categoria, p.id_tipo, pd.id_pedido AS id_pedido FROM productos AS p
LEFT JOIN pedido_detalle AS pd ON (p.id = pd.id_producto)
WHERE p.id = :id
ORDER BY pd.id_pedido DESC LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
$producto = $stmt->fetch(PDO::FETCH_ASSOC);
return $producto ?: null;
}
// OBTENER PRODUCTO POR ID PARA CAJA
public function obtenerPorIdParaCaja(int $id): ?array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, COALESCE(p.descuento, 0) AS descuento_producto, COALESCE(c.descuento, 0) AS descuento_categoria, p.stock
FROM productos AS p
LEFT JOIN categorias AS c ON (c.id = p.id_categoria)
WHERE (p.id = :id) AND (p.estado IS TRUE) AND (p.id_tipo = 1) LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
// OBTENER PRODUCTOS DE PEDIDO POR ID PARA CAJA
public function obtenerPorIdParaCajaPedido(int $id): ?array {
$sql = "SELECT p.id, p.marca, p.modelo, p.stock, COALESCE(c.porcentaje_ganancia, 0) AS porcentaje_ganancia
FROM productos AS p
LEFT JOIN categorias AS c ON (c.id = p.id_categoria)
WHERE (p.id = :id) AND (p.estado IS TRUE) LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
// OBTENER INSUMO DE SERVICIO POR ID PARA CAJA
public function obtenerPorIdParaCajaServicio(int $id): ?array {
$sql = "SELECT p.id, p.marca, p.modelo, p.precio, p.stock
FROM productos AS p
LEFT JOIN categorias AS c ON (c.id = p.id_categoria)
WHERE (p.id = :id) AND (p.estado IS TRUE) AND (p.id_tipo = 2) LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
// EDITAR PRODUCTO
public function actualizarProducto(int $id, array $data): bool {
if (empty($data)) {
return false;
}
$campos = [];
$params = [];
foreach ($data as $campo => $valor) {
$campos[] = "$campo = :$campo";
$params[":$campo"] = $valor;
}
$params[':id'] = $id;
$sql = "UPDATE productos SET " . implode(', ', $campos) . " WHERE id = :id";
$stmt = $this->db->prepare($sql);
return $stmt->execute($params);
}
// ACTUALIZAR ESTADO (ACTIVO / INACTIVO)
public function actualizarEstado(int $idProducto, bool $nuevoEstado): bool {
try {
$this->db->beginTransaction();
// Actualizamaos datos del producto
$sql1 = "UPDATE productos
SET estado = :estado,
precio = NULL,
stock = NULL,
descuento = NULL
WHERE id = :id";
$stmt1 = $this->db->prepare($sql1);
$stmt1->bindValue(':estado', $nuevoEstado, PDO::PARAM_BOOL);
$stmt1->bindValue(':id', $idProducto, PDO::PARAM_INT);
$stmt1->execute();
// Actualizamos los stock y cantidades de pedido_detalle
$sql2 = "UPDATE pedido_detalle
SET cantidad_vendida = cantidad
WHERE id_producto = :id";
$stmt2 = $this->db->prepare($sql2);
$stmt2->bindValue(':id', $idProducto, PDO::PARAM_INT);
$stmt2->execute();
$this->db->commit();
return true;
} catch (Exception $e) {
$this->db->rollBack();
// Log interno
error_log($e->getMessage());
return false;
}
}
// LISTAR CATEGORIAS
public function listarCategorias(): array {
$sql = "SELECT id, nombre, porcentaje_ganancia, descuento FROM categorias ORDER BY nombre ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// VERIFICAR SI EXISTE UNA CATEGORIA
public function existeCategoria(int $id): bool {
$sql = "SELECT 1 FROM categorias WHERE id = :id LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
return (bool) $stmt->fetchColumn();
}
// OBTENER CATEGORIA POR ID
public function obtenerPorIdCategoria(int $id): ?array {
$sql = "SELECT id, nombre, porcentaje_ganancia, descuento FROM categorias WHERE id = :id";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
$categoria = $stmt->fetch(PDO::FETCH_ASSOC);
return $categoria ?: null;
}
// CREAR CATEGORIA
public function crearCategoria(array $data): bool {
$sql = "INSERT INTO categorias (nombre, porcentaje_ganancia, descuento) VALUES (:nombre, :porcentaje_ganancia, :descuento)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([
':nombre' => $data['nombre'],
':porcentaje_ganancia' => $data['porcentaje_ganancia'],
':descuento' => $data['descuento']
]);
}
// EDITAR CATEGORIA
public function actualizarCategoria(int $id, array $data): bool {
if (empty($data)) {
return false;
}
$campos = [];
$params = [];
foreach ($data as $campo => $valor) {
$campos[] = "$campo = :$campo";
$params[":$campo"] = $valor;
}
$params[':id'] = $id;
$sql = "UPDATE categorias SET " . implode(', ', $campos) . " WHERE id = :id";
$stmt = $this->db->prepare($sql);
return $stmt->execute($params);
}
// ACTUALIZAR PRECIOS DE PRODUCTOS AL EDITAR LA CATEGORIA
public function actualizarPreciosPorCategoria(int $idCategoria, array $data, array $costosProductos): bool {
try {
$this->db->beginTransaction();
// Actualizamos la categoría
$ok = $this->actualizarCategoria($idCategoria, $data);
if (!$ok) {
$this->db->rollBack();
return false;
}
// Obtenemos el nuevo porcentaje de ganancia
$stmt = $this->db->prepare("
SELECT porcentaje_ganancia
FROM categorias
WHERE id = :id
");
$stmt->execute([':id' => $idCategoria]);
$categoria = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$categoria) {
$this->db->rollBack();
return false;
}
$porcentaje_ganancia = (float) $categoria['porcentaje_ganancia'];
$stmt = $this->db->prepare("
UPDATE productos
SET precio = :precio
WHERE (id = :id) AND (id_categoria = :idCategoria)
");
foreach ($costosProductos as $c) {
// Validaciones defensivas
if (empty($c['id_producto']) || $c['costo'] === null) {
continue;
}
$costo = (float) $c['costo'];
// Fórmula correcta
$nuevoPrecio = (100 + $porcentaje_ganancia) * $costo / 100;
$stmt->execute([
':precio' => $nuevoPrecio,
':id' => $c['id_producto'],
':idCategoria' => $idCategoria
]);
}
$this->db->commit();
return true;
} catch (Exception $e) {
$this->db->rollBack();
// Log interno
error_log($e->getMessage());
return false;
}
}
// LISTAR TIPOS DE PRODUCTOS
public function listarTipos(): array {
$sql = "SELECT id, nombre FROM tipos ORDER BY id ASC";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// VERIFICAR SI EXISTE EL TIPO DE PRODUCTO
public function existeTipo(int $id): bool {
$sql = "SELECT 1 FROM tipos WHERE id = :id LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([':id' => $id]);
return (bool) $stmt->fetchColumn();
}
// OBTENER TIPO POR ID
public function obtenerPorIdTipo(int $tipo): ?array {
$sql = "SELECT id, nombre FROM tipos WHERE id = :id";
$stmt = $this->db->prepare($sql);
$tipo = $stmt->execute();
return $tipo ?: null;
}
// OBTENER DESCUENTOS DE PRODUCTOS EN BASE A UNA CATEGORIA
public function obtenerDescuento(int $idCategoria): ?array {
$sql = "SELECT productos.id, productos.descuento FROM productos
INNER JOIN categorias ON (categorias.id = productos.id_categoria)
WHERE (categorias.id = :idCategoria)";
$stmt = $this->db->prepare($sql);
$stmt->execute([':idCategoria' => $idCategoria]);
$resultado = $stmt->fetchAll(PDO::FETCH_ASSOC);
return !empty($resultado) ? $resultado : null;
}
// BÚSQUEDA EN INPUT DE DESCRIPCIÓN DEL EQUIPO (MÓDULO SERVICIOS)
public function busquedaParaServicio(): array {
$sql = "SELECT marca, modelo FROM productos WHERE (id_tipo = 1)";
$stmt = $this->db->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}