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:
@@ -244,6 +244,81 @@ function exportWaterDebtorsPDF() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filtros para deudores de conceptos -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="bi bi-funnel"></i> Filtros</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="GET" class="row g-3">
|
||||
<input type="hidden" name="page" value="reportes">
|
||||
<input type="hidden" name="type" value="concept-debtors">
|
||||
|
||||
<div class="col-md-5">
|
||||
<label class="form-label">Casas</label>
|
||||
<div class="border rounded p-2" style="max-height: 200px; overflow-y: auto;">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="filter_houses[]" value="all" class="form-check-input house-checkbox" id="house-all" checked>
|
||||
<label class="form-check-label fw-bold" for="house-all">Todas las casas</label>
|
||||
</div>
|
||||
<hr class="my-2">
|
||||
<?php
|
||||
$houses = House::getAccessible();
|
||||
foreach ($houses as $house):
|
||||
$checked = (!isset($_GET['filter_houses']) || in_array('all', $_GET['filter_houses'] ?? []) || in_array($house['id'], $_GET['filter_houses'] ?? [])) ? 'checked' : '';
|
||||
?>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="filter_houses[]" value="<?= $house['id'] ?>" class="form-check-input house-checkbox house-individual" id="house-<?= $house['id'] ?>" <?= $checked ?>>
|
||||
<label class="form-check-label" for="house-<?= $house['id'] ?>">
|
||||
<?= htmlspecialchars($house['number']) ?> - <?= htmlspecialchars($house['owner_name'] ?? 'Sin propietario') ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<label class="form-label">Conceptos</label>
|
||||
<div class="border rounded p-2" style="max-height: 200px; overflow-y: auto;">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="filter_concepts[]" value="all" class="form-check-input concept-checkbox" id="concept-all" checked>
|
||||
<label class="form-check-label fw-bold" for="concept-all">Todos los conceptos</label>
|
||||
</div>
|
||||
<hr class="my-2">
|
||||
<?php
|
||||
require_once __DIR__ . '/../../models/CollectionConcept.php';
|
||||
$concepts = CollectionConcept::all(true);
|
||||
foreach ($concepts as $concept):
|
||||
$checked = (!isset($_GET['filter_concepts']) || in_array('all', $_GET['filter_concepts'] ?? []) || in_array($concept['id'], $_GET['filter_concepts'] ?? [])) ? 'checked' : '';
|
||||
?>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" name="filter_concepts[]" value="<?= $concept['id'] ?>" class="form-check-input concept-checkbox concept-individual" id="concept-<?= $concept['id'] ?>" <?= $checked ?>>
|
||||
<label class="form-check-label" for="concept-<?= $concept['id'] ?>">
|
||||
<?= htmlspecialchars($concept['name']) ?> ($<?= number_format($concept['amount_per_house'], 2) ?>)
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<div class="d-grid gap-2 w-100">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-search"></i> Aplicar Filtros
|
||||
</button>
|
||||
<a href="?page=reportes&type=concept-debtors" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-x-circle"></i> Limpiar
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php foreach ($conceptDebtors['debtors'] as $concept): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
@@ -306,8 +381,77 @@ function exportWaterDebtorsPDF() {
|
||||
|
||||
<script>
|
||||
function exportConceptDebtorsPDF() {
|
||||
window.open('/dashboard.php?page=reportes_actions&action=export_pdf_report&type=concept-debtors', '_blank');
|
||||
const houseCheckboxes = document.querySelectorAll('input[name="filter_houses[]"]:checked');
|
||||
const conceptCheckboxes = document.querySelectorAll('input[name="filter_concepts[]"]:checked');
|
||||
|
||||
let url = '/dashboard.php?page=reportes_actions&action=export_pdf_report&type=concept-debtors';
|
||||
|
||||
// Agregar casas seleccionadas
|
||||
const selectedHouses = Array.from(houseCheckboxes).map(cb => cb.value);
|
||||
if (selectedHouses.length > 0) {
|
||||
selectedHouses.forEach(house => {
|
||||
url += '&filter_houses[]=' + encodeURIComponent(house);
|
||||
});
|
||||
}
|
||||
|
||||
// Agregar conceptos seleccionados
|
||||
const selectedConcepts = Array.from(conceptCheckboxes).map(cb => cb.value);
|
||||
if (selectedConcepts.length > 0) {
|
||||
selectedConcepts.forEach(concept => {
|
||||
url += '&filter_concepts[]=' + encodeURIComponent(concept);
|
||||
});
|
||||
}
|
||||
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
// Lógica para checkboxes de casas
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const houseAllCheckbox = document.getElementById('house-all');
|
||||
const houseIndividualCheckboxes = document.querySelectorAll('.house-individual');
|
||||
|
||||
if (houseAllCheckbox) {
|
||||
houseAllCheckbox.addEventListener('change', function() {
|
||||
const isChecked = this.checked;
|
||||
houseIndividualCheckboxes.forEach(cb => {
|
||||
cb.checked = isChecked;
|
||||
});
|
||||
});
|
||||
|
||||
houseIndividualCheckboxes.forEach(cb => {
|
||||
cb.addEventListener('change', function() {
|
||||
const allChecked = Array.from(houseIndividualCheckboxes).every(cb => cb.checked);
|
||||
const someChecked = Array.from(houseIndividualCheckboxes).some(cb => cb.checked);
|
||||
|
||||
houseAllCheckbox.checked = allChecked;
|
||||
houseAllCheckbox.indeterminate = someChecked && !allChecked;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Lógica para checkboxes de conceptos
|
||||
const conceptAllCheckbox = document.getElementById('concept-all');
|
||||
const conceptIndividualCheckboxes = document.querySelectorAll('.concept-individual');
|
||||
|
||||
if (conceptAllCheckbox) {
|
||||
conceptAllCheckbox.addEventListener('change', function() {
|
||||
const isChecked = this.checked;
|
||||
conceptIndividualCheckboxes.forEach(cb => {
|
||||
cb.checked = isChecked;
|
||||
});
|
||||
});
|
||||
|
||||
conceptIndividualCheckboxes.forEach(cb => {
|
||||
cb.addEventListener('change', function() {
|
||||
const allChecked = Array.from(conceptIndividualCheckboxes).every(cb => cb.checked);
|
||||
const someChecked = Array.from(conceptIndividualCheckboxes).some(cb => cb.checked);
|
||||
|
||||
conceptAllCheckbox.checked = allChecked;
|
||||
conceptAllCheckbox.indeterminate = someChecked && !allChecked;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php elseif ($reportType == 'concepts'): ?>
|
||||
|
||||
Reference in New Issue
Block a user