256 lines
11 KiB
PHP
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">< 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 ></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'; ?>
|