34786-vm/reporte_de_pagos.php
2025-12-12 16:33:10 +00:00

256 lines
11 KiB
PHP

<?php
require_once 'includes/header.php';
// Restringir acceso solo a administradores
if (isset($_SESSION['user_rol']) && $_SESSION['user_rol'] === 'Encargado de Stock') {
header('Location: /index.php?error=unauthorized');
exit;
}
require_once 'db/config.php';
// Get current month and year, or from query string
$month = isset($_GET['month']) ? (int)$_GET['month'] : date('m');
$year = isset($_GET['year']) ? (int)$_GET['year'] : date('Y');
// Handle month overflow/underflow
if ($month > 12) {
$month = 1;
$year++;
} elseif ($month < 1) {
$month = 12;
$year--;
}
$liquidacion_id = (int)($year . str_pad($month, 2, '0', STR_PAD_LEFT));
// Get city and sales data
$db = db();
$cities_stmt = $db->query("SELECT id, nombre FROM ciudades ORDER BY orden ASC");
$cities = $cities_stmt->fetchAll(PDO::FETCH_ASSOC);
// Get payment statuses for each city and day
$estados_stmt = $db->prepare("SELECT ciudad_id, fecha, estado FROM liquidaciones_ciudades_estados WHERE liquidacion_id = :liquidacion_id");
$estados_stmt->execute(['liquidacion_id' => $liquidacion_id]);
$estados_raw = $estados_stmt->fetchAll(PDO::FETCH_ASSOC);
$estados = [];
foreach ($estados_raw as $row) {
$estados[$row['ciudad_id']][$row['fecha']] = $row['estado'];
}
$sales_stmt = $db->prepare("
SELECT
DAY(m.fecha) as dia,
m.ciudad_origen_id,
SUM(m.precio_liquidacion) as monto_total
FROM movimientos m
WHERE m.tipo = 'Salida'
AND MONTH(m.fecha) = :month
AND YEAR(m.fecha) = :year
GROUP BY DAY(m.fecha), m.ciudad_origen_id
");
$sales_stmt->execute(['month' => $month, 'year' => $year]);
$sales_data = $sales_stmt->fetchAll(PDO::FETCH_ASSOC);
// Organize sales data in a structured way: [day][city_id] => amount
$sales_by_day_city = [];
foreach ($sales_data as $sale) {
$sales_by_day_city[$sale['dia']][$sale['ciudad_origen_id']] = $sale['monto_total'];
}
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$month_name = DateTime::createFromFormat('!m', $month)->format('F');
?>
<div class="container-fluid">
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Validaciones De Pagos</h1>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Resumen de Ventas por Ciudad</h6>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center mb-3">
<a href="?month=<?php echo $month - 1; ?>&year=<?php echo $year; ?>" class="btn btn-secondary btn-sm mr-2">&lt; Mes Anterior</a>
<h4 class="mb-0"><?php echo ucfirst($month_name) . ' ' . $year; ?></h4>
<a href="?month=<?php echo $month + 1; ?>&year=<?php echo $year; ?>" class="btn btn-secondary btn-sm ml-2">Mes Siguiente &gt;</a>
</div>
<style>
#dataTable td,
#dataTable th {
padding-top: 0.2rem;
padding-bottom: 0.2rem;
vertical-align: middle;
}
#dataTable .form-control-sm {
padding-top: 0.1rem;
padding-bottom: 0.1rem;
height: auto;
}
.table-responsive {
max-height: 70vh; /* Ajusta la altura máxima según necesites */
overflow-y: auto;
}
#dataTable thead th {
position: sticky;
background-color: #343a40 !important;
color: #fff !important;
z-index: 1;
}
#dataTable thead tr:first-child th {
top: 0;
z-index: 2; /* Prioridad para la fila superior */
}
#dataTable thead tr:nth-child(2) th {
top: 38px; /* Ajusta si es necesario a la altura de la primera fila */
}
</style>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="dataTable" width="100%" cellspacing="0">
<thead class="thead-dark">
<tr>
<th rowspan="2" class="align-middle text-center">Día</th>
<?php foreach ($cities as $city) : ?>
<th colspan="2" class="text-center"><?php echo htmlspecialchars($city['nombre']); ?></th>
<?php endforeach; ?>
<th rowspan="2" class="text-center table-primary align-middle">Total Diario</th>
</tr>
<tr>
<?php foreach ($cities as $city) : ?>
<th class="text-center">Recaudo</th>
<th class="text-center">Estado</th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php
$grand_total = 0;
$city_totals = array_fill_keys(array_column($cities, 'id'), 0);
for ($day = 1; $day <= $days_in_month; $day++) :
$daily_total = 0;
$current_date = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-' . str_pad($day, 2, '0', STR_PAD_LEFT);
?>
<tr>
<td class="text-center align-middle"><?php echo htmlspecialchars(date('d-m-Y', strtotime($current_date))); ?></td>
<?php foreach ($cities as $city) :
$amount = $sales_by_day_city[$day][$city['id']] ?? 0;
$daily_total += $amount;
$city_totals[$city['id']] += $amount;
?>
<td class="text-right align-middle">
<?php echo $amount > 0 ? number_format($amount, 2) : '-'; ?>
</td>
<?php
$estado_actual = $estados[$city['id']][$current_date] ?? 'Pendiente';
?>
<td>
<select class="form-control form-control-sm estado-pago"
data-ciudad-id="<?php echo $city['id']; ?>"
data-liquidacion-id="<?php echo $liquidacion_id; ?>"
data-fecha="<?php echo $current_date; ?>">
<option value="Pendiente" <?php echo $estado_actual === 'Pendiente' ? 'selected' : ''; ?>>Pendiente</option>
<option value="Pagado" <?php echo $estado_actual === 'Pagado' ? 'selected' : ''; ?>>Pagado</option>
</select>
</td>
<?php endforeach; ?>
<td class="text-right font-weight-bold table-primary align-middle">
<?php echo number_format($daily_total, 2); ?>
</td>
</tr>
<?php
$grand_total += $daily_total;
endfor;
?>
</tbody>
<tfoot class="thead-dark">
<tr>
<th>Total por Ciudad</th>
<?php foreach ($cities as $city) : ?>
<th class="text-right">
<?php echo number_format($city_totals[$city['id']], 2); ?>
</th>
<th></th>
<?php endforeach; ?>
<th class="text-right table-success font-weight-bolder">
<?php echo number_format($grand_total, 2); ?>
</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const selects = document.querySelectorAll('.estado-pago');
function setSelectStyle(select, estado) {
const td = select.parentElement;
if (estado === 'Pagado') {
td.classList.add('bg-success');
select.classList.add('bg-success', 'text-white');
select.classList.remove('bg-light');
} else {
td.classList.remove('bg-success');
select.classList.remove('bg-success', 'text-white');
select.classList.add('bg-light');
}
}
selects.forEach(select => {
// Set initial style based on the loaded value
setSelectStyle(select, select.value);
select.addEventListener('change', function() {
const ciudadId = this.dataset.ciudadId;
const liquidacionId = this.dataset.liquidacionId;
const fecha = this.dataset.fecha;
const estado = this.value;
const originalState = estado === 'Pagado' ? 'Pendiente' : 'Pagado';
// Optimistically update UI
setSelectStyle(this, estado);
fetch('handle_pago_ciudad.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
liquidacion_id: liquidacionId,
ciudad_id: ciudadId,
fecha: fecha,
estado: estado
})
})
.then(response => response.json())
.then(data => {
if (!data.success) {
alert('Error al actualizar el estado: ' + data.message);
// Revert UI on error
this.value = originalState;
setSelectStyle(this, originalState);
}
})
.catch(error => {
console.error('Error en la petición:', error);
alert('Ocurrió un error de red. Inténtalo de nuevo.');
// Revert UI on error
this.value = originalState;
setSelectStyle(this, originalState);
});
});
});
});
</script>
<?php require_once 'includes/footer.php'; ?>