- Crear nueva página /graficos con 4 tipos de gráficos interactivos - Agregar compatibilidad con tema oscuro en selectores - Implementar exportación a PDF profesional con encabezados - Agregar campo 'Monto Real del Recibo' a configuración mensual - Crear migración para nueva columna real_amount en monthly_bills - Mejorar filtros con botones interactivos en lugar de select múltiple - Agregar resumen ejecutivo con estadísticas detalladas - Optimizar espacio visual y responsividad de gráficos - Integrar Chart.js y jsPDF para funcionalidad avanzada - Corregir problemas de carga de datos y filtros dinámicos
116 lines
4.8 KiB
PHP
Executable File
116 lines
4.8 KiB
PHP
Executable File
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h2><i class="bi bi-gear"></i> Configuración Mensual</h2>
|
|
<p class="text-muted">Configurar montos esperados de agua por mes</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label for="yearSelect" class="form-label me-2">Año:</label>
|
|
<select id="yearSelect" class="form-select d-inline-block" style="width: auto;">
|
|
<?php for ($y = 2024; $y <= 2030; $y++): ?>
|
|
<option value="<?= $y ?>" <?= $y == $year ? 'selected' : '' ?>><?= $y ?></option>
|
|
<?php endfor; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<?php foreach ($months as $month):
|
|
$bill = $monthlyBills[$month] ?? null;
|
|
?>
|
|
<div class="col-md-4 mb-3">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h6 class="mb-0"><?= $month ?></h6>
|
|
<?php if ($bill): ?>
|
|
<span class="badge bg-success">$<?= number_format($bill['amount_per_house'], 2) ?>/casa</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-2">
|
|
<small class="text-muted">Monto Total del Mes</small>
|
|
<input type="number" step="0.01" class="form-control form-control-sm"
|
|
id="total_<?= $month ?>" value="<?= $bill['total_amount'] ?? '' ?>">
|
|
</div>
|
|
<div class="mb-2">
|
|
<small class="text-muted">Monto por Casa</small>
|
|
<input type="number" step="0.01" class="form-control form-control-sm"
|
|
id="per_house_<?= $month ?>" value="<?= $bill['amount_per_house'] ?? '' ?>">
|
|
</div>
|
|
<div class="mb-2">
|
|
<small class="text-muted">Monto Real del Recibo</small>
|
|
<input type="number" step="0.01" class="form-control form-control-sm"
|
|
id="real_<?= $month ?>" value="<?= $bill['real_amount'] ?? '' ?>">
|
|
</div>
|
|
<div class="mb-2">
|
|
<small class="text-muted">Fecha de Vencimiento</small>
|
|
<input type="date" class="form-control form-control-sm"
|
|
id="due_<?= $month ?>" value="<?= $bill['due_date'] ?? '' ?>">
|
|
</div>
|
|
<button onclick="saveMonth('<?= $month ?>')" class="btn btn-primary btn-sm w-100">
|
|
<i class="bi bi-save"></i> Guardar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<div class="card mt-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0"><i class="bi bi-info-circle"></i> Información</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="mb-2">El <strong>Monto por Casa</strong> se usa para determinar si un pago está completo, parcial o pendiente en la tabla de pagos.</p>
|
|
<p class="mb-0">Casas marcadas como "consumo_only" reciben un descuento de $100 (desde 2025)</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.getElementById('yearSelect').addEventListener('change', function() {
|
|
window.location.href = '/dashboard.php?page=configurar&year=' + this.value;
|
|
});
|
|
|
|
function saveMonth(month) {
|
|
const total = document.getElementById('total_' + month).value;
|
|
const perHouse = document.getElementById('per_house_' + month).value;
|
|
const realAmount = document.getElementById('real_' + month).value;
|
|
const dueDate = document.getElementById('due_' + month).value;
|
|
const year = <?= $year ?>;
|
|
|
|
if (total === '' || perHouse === '') {
|
|
Swal.fire('Error', 'Debe ingresar el monto total y el monto por casa', 'error');
|
|
return;
|
|
}
|
|
|
|
fetch('/dashboard.php?page=config_actions&action=save_monthly_bill', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
year: year,
|
|
month: month,
|
|
total_amount: parseFloat(total),
|
|
amount_per_house: parseFloat(perHouse),
|
|
real_amount: realAmount ? parseFloat(realAmount) : null,
|
|
due_date: dueDate || null
|
|
})
|
|
})
|
|
.then(r => {
|
|
console.log('Response status:', r.status);
|
|
return r.json();
|
|
})
|
|
.then(data => {
|
|
console.log('Response data:', data);
|
|
if (data.success) {
|
|
Swal.fire('Éxito', 'Configuración guardada', 'success').then(() => location.reload());
|
|
} else {
|
|
Swal.fire('Error', data.message, 'error');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
Swal.fire('Error', 'Error al guardar: ' + error.message, 'error');
|
|
});
|
|
}
|
|
</script>
|