db = Database::getConnection(); } // OBTENER BALANCE ANUAL public function obtenerBalanceAnual($anio) { $sql = "WITH meses AS ( SELECT generate_series(1,12) AS mes ), -- INGRESOS DE VENTAS ingresos_ventas AS ( SELECT mes, SUM(total) AS total FROM ( SELECT EXTRACT(MONTH FROM v.fecha)::int AS mes, SUM(v.total) AS total FROM ventas v WHERE EXTRACT(YEAR FROM v.fecha)::int = :anio GROUP BY mes ) sub GROUP BY mes ), -- INGRESOS DE SERVICIOS ingresos_servicios AS ( SELECT mes, SUM(total) AS total FROM ( SELECT EXTRACT(MONTH FROM s.fecha_terminado)::int AS mes, SUM(s.total) AS total FROM servicios s WHERE EXTRACT(YEAR FROM s.fecha_terminado)::int = :anio GROUP BY mes ) sub GROUP BY mes ), -- COSTOS DE PEDIDOS costos_pedidos AS ( SELECT mes, SUM(total) AS total FROM ( SELECT EXTRACT(MONTH FROM p.fecha)::int AS mes, SUM(p.total) AS total FROM pedidos p WHERE EXTRACT(YEAR FROM p.fecha)::int = :anio GROUP BY mes ) sub GROUP BY mes ) -- SUMAS Y CALCULO DE UTILIDAD SELECT m.mes, COALESCE(SUM(iv.total),0) AS ventas, COALESCE(SUM(isv.total),0) AS servicios, COALESCE(SUM(cp.total),0) AS costos, COALESCE(SUM(iv.total),0) + COALESCE(SUM(isv.total),0) - COALESCE(SUM(cp.total),0) AS utilidad FROM meses m LEFT JOIN ingresos_ventas iv ON (iv.mes = m.mes) LEFT JOIN ingresos_servicios isv ON (isv.mes = m.mes) LEFT JOIN costos_pedidos cp ON (cp.mes = m.mes) GROUP BY m.mes ORDER BY m.mes"; try { $stmt = $this->db->prepare($sql); $stmt->bindValue(':anio', $anio, PDO::PARAM_INT); $stmt->execute(); $resultados = $stmt->fetchAll(PDO::FETCH_ASSOC); $meses = []; $ventas = []; $servicios = []; $costos = []; $utilidades = []; $totalVentas = 0; $totalServicios = 0; $totalCostos = 0; $totalUtilidad = 0; $mejorMes = ''; $maxUtilidad = null; // Calculo de totales foreach ($resultados as $row) { $meses[] = (int) $row['mes']; $ventas[] = (float) $row['ventas']; $servicios[] = (float) $row['servicios']; $costos[] = (float) $row['costos']; $utilidades[] = (float) $row['utilidad']; $totalVentas += $row['ventas']; $totalServicios += $row['servicios']; $totalCostos += $row['costos']; $totalUtilidad += $row['utilidad']; if ($maxUtilidad === null || $row['utilidad'] > $maxUtilidad) { $maxUtilidad = $row['utilidad']; $mejorMes = $row['mes']; } } // Mapeo de nombres de mes $nombresMeses = [ 1=>'Enero',2=>'Febrero',3=>'Marzo',4=>'Abril', 5=>'Mayo',6=>'Junio',7=>'Julio',8=>'Agosto', 9=>'Septiembre',10=>'Octubre',11=>'Noviembre',12=>'Diciembre' ]; $mejorMesNombre = $nombresMeses[$mejorMes] ?? ''; // Retorno de array completo return [ 'meses' => $meses, 'ventas' => $ventas, 'servicios' => $servicios, 'costos' => $costos, 'utilidad' => $utilidades, 'kpis' => [ 'totalIngresos' => $totalVentas + $totalServicios, 'totalCostos' => $totalCostos, 'resultado' => $totalUtilidad, 'mejorMes' => $mejorMesNombre ] ]; } catch (PDOException $e) { // Log interno error_log($e->getMessage()); return []; } } // OBTENER MONTOS A COBRAR public function obtenerACobrar($anio) { $sql = "WITH meses AS ( SELECT generate_series(1,12) AS mes ), -- SERVICIOS PENDIENTES servicios_pendientes AS ( SELECT EXTRACT(MONTH FROM s.fecha_registro)::int AS mes, SUM(s.total) AS total FROM servicios s WHERE s.estado = 'pendiente - enviado' AND EXTRACT(YEAR FROM s.fecha_registro)::int = :anio GROUP BY mes ) -- RESULTADO FINAL SELECT m.mes, COALESCE(sp.total,0) AS servicios FROM meses m LEFT JOIN servicios_pendientes sp ON (sp.mes = m.mes) ORDER BY m.mes"; try { $stmt = $this->db->prepare($sql); $stmt->bindValue(':anio', $anio, PDO::PARAM_INT); $stmt->execute(); $resultados = $stmt->fetchAll(PDO::FETCH_ASSOC); $meses = $totales = []; foreach ($resultados as $row) { $meses[] = (int) $row['mes']; $totales[] = (float) $row['servicios']; } return [ 'meses' => $meses, 'totales' => $totales, 'kpis' => [ 'totalACobrar' => array_sum($totales) ] ]; } catch (PDOException $e) { // Log interno error_log($e->getMessage()); return []; } } }