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:
@@ -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
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user