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

345 lines
15 KiB
PHP

<?php
require_once 'includes/header.php';
if (isset($_SESSION['user_rol']) && $_SESSION['user_rol'] === 'Encargado de Stock') {
header('Location: /index.php?error=unauthorized');
exit;
}
require_once 'db/config.php';
$db = db();
// Lógica para obtener el mes y año seleccionados
$selected_month = isset($_GET['month']) ? (int)$_GET['month'] : date('m');
$selected_year = isset($_GET['year']) ? (int)$_GET['year'] : date('Y');
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $selected_month, $selected_year);
$start_date = "$selected_year-$selected_month-01";
$end_date = "$selected_year-$selected_month-$days_in_month";
// --- Obtener Recaudos Contraentrega ---
$stmt_recaudos = $db->prepare(
"SELECT DATE(fecha) as fecha_recaudo, SUM(precio_liquidacion) as total_recaudado
FROM movimientos
WHERE tipo = 'salida' AND fecha BETWEEN ? AND ?
GROUP BY DATE(fecha)"
);
$stmt_recaudos->execute([$start_date, $end_date]);
$recaudos_por_fecha = $stmt_recaudos->fetchAll(PDO::FETCH_KEY_PAIR);
// --- Obtener datos del flujo de caja para el mes ---
$stmt_flujo = $db->prepare("SELECT * FROM flujo_de_caja WHERE YEAR(fecha) = ? AND MONTH(fecha) = ? ORDER BY fecha ASC");
$stmt_flujo->execute([$selected_year, $selected_month]);
$flujo_data = $stmt_flujo->fetchAll(PDO::FETCH_ASSOC);
$data_por_dia = [];
foreach ($flujo_data as $row) {
$data_por_dia[$row['fecha']] = $row;
}
$dias_del_mes = [];
for ($day = 1; $day <= $days_in_month; $day++) {
$fecha_str = sprintf("%s-%s-%02d", $selected_year, str_pad($selected_month, 2, '0', STR_PAD_LEFT), $day);
$default_row = [
'bcp_yape' => 0, 'banco_nacion' => 0, 'interbank' => 0, 'bbva' => 0, 'otros_ingresos' => 0, 'rc_envio' => 0,
'tu_1' => 0, 'tu_2' => 0, 'tu_3' => 0, 'fl_1' => 0, 'fl_2' => 0, 'fl_3' => 0
];
$dia_data = $data_por_dia[$fecha_str] ?? $default_row;
// RC ENVIO es la suma de los otros ingresos
$rc_envio_dia =
(float)($dia_data['bcp_yape'] ?? 0) + (float)($dia_data['banco_nacion'] ?? 0) +
(float)($dia_data['interbank'] ?? 0) + (float)($dia_data['bbva'] ?? 0) +
(float)($dia_data['otros_ingresos'] ?? 0);
$dia_data['rc_envio'] = $rc_envio_dia;
$recaudo_contraentrega = $recaudos_por_fecha[$fecha_str] ?? 0;
$total_ingresos_dia = $rc_envio_dia + (float)$recaudo_contraentrega;
$total_egresos_dia =
(float)($dia_data['tu_1'] ?? 0) + (float)($dia_data['tu_2'] ?? 0) +
(float)($dia_data['tu_3'] ?? 0) + (float)($dia_data['fl_1'] ?? 0) +
(float)($dia_data['fl_2'] ?? 0) + (float)($dia_data['fl_3'] ?? 0);
// El "Recaudo final" es la diferencia del día
$recaudo_final_dia = $total_ingresos_dia - $total_egresos_dia;
$dias_del_mes[] = [
'fecha' => $fecha_str,
'data' => $dia_data,
'recaudo_contraentrega' => $recaudo_contraentrega,
'total_ingresos' => $total_ingresos_dia,
'total_egresos' => $total_egresos_dia,
'recaudo_final' => $recaudo_final_dia
];
}
?>
<style>
.table-responsive { max-height: 80vh; overflow-y: auto; }
.table th, .table td { white-space: nowrap; padding: 0.5rem; vertical-align: middle; }
.editable { cursor: pointer; background-color: #f9f9f9; }
.editable:hover { background-color: #e9ecef; }
.ingreso { background-color: #d4edda; }
.egreso { background-color: #f8d7da; }
.total-ingreso, .total-egreso, .saldo { font-weight: bold; }
/* Estilos para el encabezado anclado */
thead.table-dark th {
position: sticky;
top: 0;
z-index: 1;
background-color: #343a40 !important; /* Fondo oscuro */
color: #fff !important; /* Texto blanco */
}
tfoot { position: sticky; bottom: 0; background-color: #fff; z-index: 10; }
</style>
<div class="container-fluid mt-4">
<h2>Flujo de Caja</h2>
<form method="get" class="row g-3 align-items-center mb-3">
<div class="col-auto"><label for="month" class="col-form-label">Mes</label></div>
<div class="col-auto">
<select name="month" id="month" class="form-select">
<?php for ($i = 1; $i <= 12; $i++): ?>
<option value="<?= $i ?>" <?= $i == $selected_month ? 'selected' : '' ?>><?= ucfirst(strftime('%B', mktime(0, 0, 0, $i, 1))) ?></option>
<?php endfor; ?>
</select>
</div>
<div class="col-auto"><label for="year" class="col-form-label">Año</label></div>
<div class="col-auto">
<select name="year" id="year" class="form-select">
<?php for ($y = date('Y'); $y >= 2020; $y--): ?>
<option value="<?= $y ?>" <?= $y == $selected_year ? 'selected' : '' ?>><?= $y ?></option>
<?php endfor; ?>
</select>
</div>
<div class="col-auto"><button type="submit" class="btn btn-primary">Ver</button></div>
</form>
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<thead class="table-dark">
<tr>
<th rowspan="2" style="text-align:center; vertical-align: middle;">Fecha</th>
<th colspan="5">Ingresos</th>
<th colspan="6">Inversion publicitaria</th>
<th rowspan="2" class="ingreso" style="text-align:center; vertical-align: middle;">RC ENVIO</th>
<th rowspan="2" class="ingreso" style="text-align:center; vertical-align: middle;">RC CONTRAENT</th>
<th rowspan="2" style="text-align:center; vertical-align: middle;">Total Ingresos</th>
<th rowspan="2" style="text-align:center; vertical-align: middle;">Total Inversion Publicitaria</th>
<th rowspan="2" style="text-align:center; vertical-align: middle;">Recaudo final</th>
</tr>
<tr>
<!-- Ingresos -->
<th class="ingreso">BCP/YAPE</th>
<th class="ingreso">B. NACION</th>
<th class="ingreso">INTERBANK</th>
<th class="ingreso">BBVA</th>
<th class="ingreso">Otros Ingresos</th>
<!-- Egresos -->
<th class="egreso">TU 1</th>
<th class="egreso">TU 2</th>
<th class="egreso">TU 3</th>
<th class="egreso">FL1</th>
<th class="egreso">FL2</th>
<th class="egreso">FL3</th>
</tr>
</thead>
<tbody>
<?php foreach ($dias_del_mes as $dia): ?>
<tr data-fecha="<?= $dia['fecha'] ?>">
<td><?= date("d/m/Y", strtotime($dia['fecha'])) ?></td>
<!-- Ingresos -->
<td class="editable ingreso" data-field="bcp_yape"><?= number_format($dia['data']['bcp_yape'] ?? 0, 2) ?></td>
<td class="editable ingreso" data-field="banco_nacion"><?= number_format($dia['data']['banco_nacion'] ?? 0, 2) ?></td>
<td class="editable ingreso" data-field="interbank"><?= number_format($dia['data']['interbank'] ?? 0, 2) ?></td>
<td class="editable ingreso" data-field="bbva"><?= number_format($dia['data']['bbva'] ?? 0, 2) ?></td>
<td class="editable ingreso" data-field="otros_ingresos"><?= number_format($dia['data']['otros_ingresos'] ?? 0, 2) ?></td>
<!-- Egresos -->
<td class="editable egreso" data-field="tu_1"><?= number_format($dia['data']['tu_1'] ?? 0, 2) ?></td>
<td class="editable egreso" data-field="tu_2"><?= number_format($dia['data']['tu_2'] ?? 0, 2) ?></td>
<td class="editable egreso" data-field="tu_3"><?= number_format($dia['data']['tu_3'] ?? 0, 2) ?></td>
<td class="editable egreso" data-field="fl_1"><?= number_format($dia['data']['fl_1'] ?? 0, 2) ?></td>
<td class="editable egreso" data-field="fl_2"><?= number_format($dia['data']['fl_2'] ?? 0, 2) ?></td>
<td class="editable egreso" data-field="fl_3"><?= number_format($dia['data']['fl_3'] ?? 0, 2) ?></td>
<!-- RC (ya no es editable) -->
<td class="ingreso" data-field="rc_envio"><?= number_format($dia['data']['rc_envio'] ?? 0, 2) ?></td>
<td class="ingreso" data-field="rc_contraent"><?= number_format($dia['recaudo_contraentrega'], 2) ?></td>
<!-- Totales -->
<td class="total-ingreso" data-field="total_ingresos"><?= number_format($dia['total_ingresos'], 2) ?></td>
<td class="total-egreso" data-field="total_egresos"><?= number_format($dia['total_egresos'], 2) ?></td>
<td class="saldo" data-field="recaudo_final"><?= number_format($dia['recaudo_final'], 2) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr class="table-dark" style="font-weight: bold;">
<td>TOTALES</td>
<td data-total="bcp_yape">0.00</td>
<td data-total="banco_nacion">0.00</td>
<td data-total="interbank">0.00</td>
<td data-total="bbva">0.00</td>
<td data-total="otros_ingresos">0.00</td>
<td data-total="tu_1">0.00</td>
<td data-total="tu_2">0.00</td>
<td data-total="tu_3">0.00</td>
<td data-total="fl_1">0.00</td>
<td data-total="fl_2">0.00</td>
<td data-total="fl_3">0.00</td>
<td data-total="rc_envio">0.00</td>
<td data-total="rc_contraent">0.00</td>
<td data-total="total_ingresos">0.00</td>
<td data-total="total_egresos">0.00</td>
<td data-total="recaudo_final">0.00</td>
</tr>
</tfoot>
</table>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const table = document.querySelector('.table');
table.addEventListener('dblclick', function (e) {
if (e.target.classList.contains('editable')) {
makeCellEditable(e.target);
}
});
function makeCellEditable(cell) {
const originalValue = parseFloat(cell.textContent.trim().replace(/,/g, '')) || 0;
if (cell.querySelector('input')) return;
const input = document.createElement('input');
input.type = 'number';
input.step = '0.01';
input.value = originalValue.toFixed(2);
input.className = 'form-control';
cell.innerHTML = '';
cell.appendChild(input);
input.focus();
input.select();
const onFinish = () => {
const newValue = parseFloat(input.value) || 0;
cell.textContent = newValue.toFixed(2);
saveData(cell, newValue, originalValue);
};
input.addEventListener('blur', onFinish, { once: true });
input.addEventListener('keydown', e => {
if (e.key === 'Enter') input.blur();
if (e.key === 'Escape') {
cell.textContent = originalValue.toFixed(2);
input.removeEventListener('blur', onFinish);
}
});
}
function saveData(cell, value, originalValue) {
const row = cell.closest('tr');
updateUI(row); // Optimistic UI update
const formData = new FormData();
formData.append('fecha', row.dataset.fecha);
formData.append('field', cell.dataset.field);
formData.append('value', value);
fetch('handle_editar_flujo_de_caja.php', { method: 'POST', body: formData })
.then(res => res.json())
.then(data => {
if (!data.success) {
console.error('Error al guardar:', data.message);
cell.textContent = originalValue.toFixed(2);
updateUI(row); // Revert on failure
}
})
.catch(error => {
console.error('Error de red:', error);
cell.textContent = originalValue.toFixed(2);
updateUI(row); // Revert on failure
});
}
function getCellValue(row, field) {
const cell = row.querySelector(`[data-field="${field}"]`);
return cell ? parseFloat(cell.textContent.replace(/,/g, '')) : 0;
}
function setCellValue(row, field, value) {
const cell = row.querySelector(`[data-field="${field}"]`);
if (cell) cell.textContent = value.toFixed(2);
}
function recalculateRow(row) {
// Calcular rc_envio a partir de sus componentes
const rc_envio_calc =
getCellValue(row, 'bcp_yape') + getCellValue(row, 'banco_nacion') +
getCellValue(row, 'interbank') + getCellValue(row, 'bbva') +
getCellValue(row, 'otros_ingresos');
setCellValue(row, 'rc_envio', rc_envio_calc);
const ingresos = rc_envio_calc + getCellValue(row, 'rc_contraent');
const egresos =
getCellValue(row, 'tu_1') + getCellValue(row, 'tu_2') +
getCellValue(row, 'tu_3') + getCellValue(row, 'fl_1') +
getCellValue(row, 'fl_2') + getCellValue(row, 'fl_3');
const recaudoFinal = ingresos - egresos;
setCellValue(row, 'total_ingresos', ingresos);
setCellValue(row, 'total_egresos', egresos);
setCellValue(row, 'recaudo_final', recaudoFinal);
}
function updateUI(row) {
recalculateRow(row);
updateFooterTotals();
}
function updateFooterTotals() {
const footer = document.querySelector('tfoot tr');
const totals = {};
footer.querySelectorAll('[data-total]').forEach(cell => {
totals[cell.dataset.total] = 0;
});
document.querySelectorAll('tbody tr').forEach(row => {
for (const key in totals) {
totals[key] += getCellValue(row, key);
}
});
// Recalcular totales derivados que no son una suma directa de columnas
totals['rc_envio'] = totals['bcp_yape'] + totals['banco_nacion'] + totals['interbank'] + totals['bbva'] + totals['otros_ingresos'];
totals['total_ingresos'] = totals['rc_envio'] + totals['rc_contraent'];
totals['total_egresos'] = totals['tu_1'] + totals['tu_2'] + totals['tu_3'] + totals['fl_1'] + totals['fl_2'] + totals['fl_3'];
totals['recaudo_final'] = totals['total_ingresos'] - totals['total_egresos'];
for (const key in totals) {
const cell = footer.querySelector(`[data-total="${key}"]`);
if(cell) cell.textContent = totals[key].toFixed(2);
}
}
// Initial calculation on load
document.querySelectorAll('tbody tr').forEach(row => recalculateRow(row));
updateFooterTotals();
});
</script>
<?php require_once 'includes/footer.php'; ?>