feat: Agregar filtros avanzados a reporte de Deudores de Conceptos

- Filtros por casas: selección múltiple con opción 'Todas las casas'
- Filtros por conceptos: selección múltiple con opción 'Todos los conceptos'
- Estado inicial: todos los filtros marcados por defecto (muestra toda la info)
- Exportación PDF: incluye solo datos filtrados según selección
- JavaScript interactivo: lógica de checkboxes con estados intermedios
- Modelo actualizado: método getConceptDebtorsFiltered para filtrado avanzado
- Interfaz intuitiva: scrollable containers para listas largas
- Preserva permisos: respeta restricciones de acceso por casas
This commit is contained in:
2026-01-05 16:12:24 -06:00
parent 5d5f81c325
commit 535f7c5963
13 changed files with 1944 additions and 3 deletions

View File

@@ -482,4 +482,100 @@ class Report {
'total_due' => $grandTotal
];
}
public static function getConceptDebtorsFiltered($houseIds, $conceptIds = null) {
$db = Database::getInstance();
$whereConditions = [];
$params = [];
// Base conditions
$whereConditions[] = "h.status = 'activa'";
$whereConditions[] = "(cc.amount_per_house - COALESCE(cp.amount, 0)) > 0";
// House filter
if (!empty($houseIds)) {
$placeholders = str_repeat('?,', count($houseIds) - 1) . '?';
$whereConditions[] = "h.id IN ({$placeholders})";
$params = array_merge($params, $houseIds);
}
// Concept filter
if (!empty($conceptIds)) {
$placeholders = str_repeat('?,', count($conceptIds) - 1) . '?';
$whereConditions[] = "cc.id IN ({$placeholders})";
$params = array_merge($params, $conceptIds);
}
$whereClause = implode(' AND ', $whereConditions);
$query = "
SELECT
h.number as house_number,
h.owner_name,
cc.name as concept_name,
cc.id as concept_id,
cc.amount_per_house,
COALESCE(cp.amount, 0) as paid_amount,
(cc.amount_per_house - COALESCE(cp.amount, 0)) as debt_amount,
cc.concept_date,
cp.payment_date
FROM houses h
CROSS JOIN finance_collection_concepts cc
LEFT JOIN finance_collection_payments cp ON cp.house_id = h.id AND cp.concept_id = cc.id
WHERE {$whereClause}
ORDER BY cc.name, h.number, cc.concept_date DESC
";
$results = $db->fetchAll($query, $params);
// Group by concept like the original method
$debtors = [];
$grandTotal = 0;
$groupedResults = [];
foreach ($results as $row) {
$key = $row['concept_name'];
if (!isset($groupedResults[$key])) {
$groupedResults[$key] = [
'concept_name' => $row['concept_name'],
'concept_id' => $row['concept_id'],
'amount_per_house' => $row['amount_per_house'],
'house_debtors' => []
];
}
$groupedResults[$key]['house_debtors'][] = [
'house_number' => $row['house_number'],
'owner_name' => $row['owner_name'],
'expected' => $row['amount_per_house'],
'paid' => $row['paid_amount'],
'due' => $row['debt_amount']
];
}
// Calculate totals for each concept
foreach ($groupedResults as $concept) {
$totalExpected = count($concept['house_debtors']) * $concept['amount_per_house'];
$totalCollected = array_sum(array_column($concept['house_debtors'], 'paid'));
$conceptTotalDue = $totalExpected - $totalCollected;
if ($conceptTotalDue > 0) {
$debtors[] = [
'concept_name' => $concept['concept_name'],
'concept_id' => $concept['concept_id'],
'amount_per_house' => $concept['amount_per_house'],
'total_expected' => $totalExpected,
'total_collected' => $totalCollected,
'total_due' => $conceptTotalDue,
'house_debtors' => $concept['house_debtors']
];
$grandTotal += $conceptTotalDue;
}
}
return [
'debtors' => $debtors,
'total_due' => $grandTotal
];
}
}