Carpeta models
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../database/database.php';
|
||||
|
||||
class pedidoModel {
|
||||
|
||||
private PDO $db;
|
||||
private ?string $error = null;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getConnection();
|
||||
}
|
||||
|
||||
// MÉTODO PARA OBTENER ERRORES E INFORMARLOS A TRAVÉZ DEL CONTROLLER
|
||||
|
||||
public function getError(): ?string {
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
// GUARDAR PEDIDO (retorna false o el ID del pedido generado)
|
||||
|
||||
public function guardarPedido(array $productosFinales, array $proveedor, array $vendedor, float $total): int|false {
|
||||
|
||||
// Validaciones (ya verifica el controller también)
|
||||
|
||||
if (empty($productosFinales)) {
|
||||
$this->error = 'El pedido no tiene productos.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($proveedor['id'])) {
|
||||
$this->error = 'Proveedor inválido.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($vendedor['id'])) {
|
||||
$this->error = 'No se pudo vincular al usuario.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($total <= 0) {
|
||||
$this->error = 'Total de pedido inválido.';
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($productosFinales as $p) {
|
||||
if (empty($p['id_producto']) || empty($p['cantidad']) || empty($p['costo']) || empty($p['precio'])) {
|
||||
$this->error = 'Producto inválido en el pedido.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($p['cantidad'] <= 0 || $p['costo'] < 0) {
|
||||
$this->error = 'Cantidad o costo inválido.';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->db->beginTransaction();
|
||||
|
||||
// 1. INSERT PEDIDO
|
||||
|
||||
$sqlPedido = "
|
||||
INSERT INTO pedidos (total, id_proveedor, id_usuario)
|
||||
VALUES (:total, :id_proveedor, :id_usuario)
|
||||
RETURNING id
|
||||
";
|
||||
|
||||
$stmtPedido = $this->db->prepare($sqlPedido);
|
||||
|
||||
$stmtPedido->execute([
|
||||
':total' => $total,
|
||||
':id_proveedor' => $proveedor['id'],
|
||||
':id_usuario' => $vendedor['id']
|
||||
]);
|
||||
|
||||
$idPedido = $stmtPedido->fetchColumn();
|
||||
|
||||
if (!$idPedido) {
|
||||
$this->error = 'No se pudo crear el pedido.';
|
||||
$this->db->rollBack();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. INSERT DETALLE (LOOP)
|
||||
|
||||
$sqlDetalle = "
|
||||
INSERT INTO pedido_detalle
|
||||
(precio_unitario, cantidad, subtotal, id_pedido, id_producto)
|
||||
VALUES
|
||||
(:precio_unitario, :cantidad, :subtotal, :id_pedido, :id_producto)
|
||||
";
|
||||
|
||||
$stmtDetalle = $this->db->prepare($sqlDetalle);
|
||||
|
||||
foreach ($productosFinales as $p) {
|
||||
|
||||
$subtotal = $p['costo'] * $p['cantidad'];
|
||||
|
||||
if (!$stmtDetalle->execute([
|
||||
':precio_unitario' => $p['costo'],
|
||||
':cantidad' => $p['cantidad'],
|
||||
':subtotal' => $subtotal,
|
||||
':id_pedido' => $idPedido,
|
||||
':id_producto' => $p['id_producto'],
|
||||
])
|
||||
) {
|
||||
$this->error = 'Error al guardar el detalle del pedido.';
|
||||
$this->db->rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. ACTUALIZAR DATOS DE PRODUCTO
|
||||
|
||||
$sqlStock = "
|
||||
UPDATE productos
|
||||
SET
|
||||
stock = COALESCE(stock, 0) + :cantidad,
|
||||
precio = :precio
|
||||
WHERE id = :id_producto
|
||||
";
|
||||
|
||||
$stmtStock = $this->db->prepare($sqlStock);
|
||||
|
||||
foreach ($productosFinales as $p) {
|
||||
|
||||
if (!$stmtStock->execute([
|
||||
':cantidad' => $p['cantidad'],
|
||||
':precio' => $p['precio'],
|
||||
':id_producto' => $p['id_producto'],
|
||||
])
|
||||
) {
|
||||
$this->error = 'Error al actualizar el producto.';
|
||||
$this->db->rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. COMMIT
|
||||
|
||||
$this->db->commit();
|
||||
return $idPedido;
|
||||
|
||||
} catch (Throwable $e) {
|
||||
$this->db->rollBack();
|
||||
|
||||
// Log interno
|
||||
|
||||
error_log($e->getMessage());
|
||||
|
||||
$this->error = 'Error interno al guardar el pedido.';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// LISTAR PEDIDOS
|
||||
|
||||
public function listarPedidos(int $anio): ?array {
|
||||
|
||||
$sql = "SELECT p.id, p.fecha, p.total, pe.razon_social, u.nombre AS vendedor_nombre, u.apellido AS vendedor_apellido FROM pedidos AS p
|
||||
INNER JOIN proveedores AS pe ON (p.id_proveedor = pe.id)
|
||||
INNER JOIN usuarios AS u ON (p.id_usuario = u.id)
|
||||
WHERE EXTRACT(YEAR FROM p.fecha) = :anio
|
||||
ORDER BY p.id ASC";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
|
||||
$stmt->execute([':anio' => $anio]);
|
||||
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
// OBTENER DETALLE DE PEDIDO
|
||||
|
||||
public function getDetallePedido(int $idPedido): ?array {
|
||||
|
||||
$sql = "SELECT p.id AS id_producto, p.marca, p.modelo, pd.precio_unitario, pd.cantidad, pd.subtotal FROM pedido_detalle AS pd
|
||||
INNER JOIN productos AS p ON (pd.id_producto = p.id)
|
||||
WHERE (pd.id_pedido = :id_pedido)
|
||||
ORDER BY p.id ASC";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
|
||||
$stmt->execute([':id_pedido' => $idPedido]);
|
||||
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
// OBTENER PREVIEW DE CODIGO DE REMITO (no se utiliza más)
|
||||
|
||||
/*
|
||||
|
||||
public function getNumeroRemitoPreview(): int {
|
||||
|
||||
$sql = "SELECT nextval('remito_preview_seq')";
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->execute();
|
||||
|
||||
return (int) $stmt->fetchColumn();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// OBTENER COSTO DE PRODUCTO
|
||||
|
||||
public function obtenerCosto(int $idProducto): ?float {
|
||||
|
||||
$sql = "SELECT pd.precio_unitario FROM pedido_detalle AS pd
|
||||
INNER JOIN productos AS p ON (pd.id_producto = p.id)
|
||||
WHERE (p.id = :idProducto)
|
||||
AND pd.id_pedido = (
|
||||
SELECT MAX(pd2.id_pedido)
|
||||
FROM pedido_detalle AS pd2
|
||||
WHERE pd2.id_producto = :idProducto2
|
||||
)";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
|
||||
$stmt->execute([
|
||||
':idProducto' => $idProducto,
|
||||
':idProducto2' => $idProducto
|
||||
]);
|
||||
|
||||
$resultado = $stmt->fetchColumn();
|
||||
|
||||
return $resultado !== false ? (float) $resultado : null;
|
||||
}
|
||||
|
||||
// OBTENER COSTOS DE PRODUCTOS EN BASE A UNA CATEGORIA
|
||||
|
||||
public function obtenerCostosPorCategoria(int $idCategoria): array {
|
||||
|
||||
// Uso de LATERAL en LEFT JOIN -> permite traer el costo mas reciente (actúa como un foreach, ejecutando la subconsulta por cada producto)
|
||||
|
||||
$sql = "SELECT
|
||||
p.id AS id_producto, pd.precio_unitario AS costo FROM productos AS p
|
||||
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT pd.precio_unitario FROM pedido_detalle AS pd
|
||||
INNER JOIN pedidos AS pe ON (pe.id = pd.id_pedido)
|
||||
WHERE (pd.id_producto = p.id)
|
||||
ORDER BY pe.fecha DESC, pd.id DESC LIMIT 1
|
||||
) pd ON true
|
||||
|
||||
WHERE (p.id_categoria = :idCategoria)";
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
|
||||
$stmt->execute([':idCategoria' => $idCategoria]);
|
||||
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user