318 lines
13 KiB
PHP
318 lines
13 KiB
PHP
<?php
|
|
require_once 'layout_header.php';
|
|
require_once 'db/config.php';
|
|
|
|
$month = isset($_GET['month']) ? $_GET['month'] : date('m');
|
|
$year = isset($_GET['year']) ? $_GET['year'] : date('Y');
|
|
|
|
$start_date = "$year-$month-01";
|
|
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
|
|
$end_date = "$year-$month-$days_in_month";
|
|
|
|
// Columns from DB that are editable
|
|
$db_columns = [
|
|
'bcp_yape', 'b_nacion', 'interbank', 'bbva', 'otros_ingresos',
|
|
'tu1', 'tu2', 'tu3', 'fl1', 'fl2', 'fl3',
|
|
'rc_contraent', 'sc', 'c_pedidos'
|
|
];
|
|
|
|
// Columns to display in the table body in order
|
|
$display_columns = [
|
|
'bcp_yape', 'b_nacion', 'interbank', 'bbva', 'otros_ingresos',
|
|
'tu1', 'tu2', 'tu3', 'fl1', 'fl2', 'fl3',
|
|
'rc_envio', 'rc_contraent'
|
|
];
|
|
|
|
|
|
// Fetch data from DB
|
|
$flujo_data = [];
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare("SELECT * FROM flujo_caja WHERE fecha BETWEEN ? AND ?");
|
|
$stmt->execute([$start_date, $end_date]);
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($rows as $row) {
|
|
$flujo_data[$row['fecha']] = $row;
|
|
}
|
|
} catch (PDOException $e) {
|
|
// Handle error
|
|
}
|
|
|
|
// Prepare data for the entire month
|
|
$all_days_data = [];
|
|
for ($day = 1; $day <= $days_in_month; $day++) {
|
|
$date = date('Y-m-d', strtotime("$year-$month-$day"));
|
|
if (isset($flujo_data[$date])) {
|
|
$all_days_data[$date] = $flujo_data[$date];
|
|
} else {
|
|
// Initialize with 0.00 for all expected columns
|
|
$all_days_data[$date] = array_fill_keys($db_columns, '0.00');
|
|
}
|
|
}
|
|
|
|
// Calculate totals
|
|
$totals = array_fill_keys($display_columns, 0);
|
|
$totals['sc'] = 0;
|
|
$totals['c_pedidos'] = 0;
|
|
$totals['total_ingresos'] = 0;
|
|
$totals['total_inversion'] = 0;
|
|
$totals['recaudo_final'] = 0;
|
|
|
|
foreach ($all_days_data as $date => &$day_data) {
|
|
$rc_envio_dia = (float)($day_data['bcp_yape'] ?? 0) + (float)($day_data['b_nacion'] ?? 0) + (float)($day_data['interbank'] ?? 0) + (float)($day_data['bbva'] ?? 0) + (float)($day_data['otros_ingresos'] ?? 0);
|
|
$day_data['rc_envio'] = $rc_envio_dia;
|
|
|
|
$ingresos_dia = $rc_envio_dia + (float)($day_data['rc_contraent'] ?? 0);
|
|
$inversion_dia = (float)($day_data['tu1'] ?? 0) + (float)($day_data['tu2'] ?? 0) + (float)($day_data['tu3'] ?? 0) + (float)($day_data['fl1'] ?? 0) + (float)($day_data['fl2'] ?? 0) + (float)($day_data['fl3'] ?? 0);
|
|
|
|
foreach ($display_columns as $col) {
|
|
$totals[$col] += (float)($day_data[$col] ?? 0);
|
|
}
|
|
$totals['sc'] += (float)($day_data['sc'] ?? 0);
|
|
$totals['c_pedidos'] += (int)($day_data['c_pedidos'] ?? 0);
|
|
$totals['total_ingresos'] += $ingresos_dia;
|
|
$totals['total_inversion'] += $inversion_dia;
|
|
$totals['recaudo_final'] += ($ingresos_dia - $inversion_dia);
|
|
}
|
|
unset($day_data);
|
|
|
|
?>
|
|
|
|
<style>
|
|
.table thead th {
|
|
background-color: #337ab7;
|
|
color: #ffffff;
|
|
font-weight: 600;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
}
|
|
.table tfoot th {
|
|
position: sticky;
|
|
bottom: 0;
|
|
background-color: #e9ecef;
|
|
z-index: 10;
|
|
font-weight: 700;
|
|
}
|
|
.table td[contenteditable="true"]:focus {
|
|
background-color: #fff3cd;
|
|
}
|
|
</style>
|
|
|
|
<div class="container-fluid mt-4">
|
|
<h2>Flujo de Caja</h2>
|
|
<p>Registro y control de los movimientos de ingresos y gastos.</p>
|
|
|
|
<form method="GET" action="flujo_de_caja.php" class="form-inline mb-4">
|
|
<div class="form-group mr-2">
|
|
<label for="month" class="mr-2">Mes:</label>
|
|
<select name="month" id="month" class="form-control">
|
|
<?php for ($m = 1; $m <= 12; $m++): ?>
|
|
<option value="<?php echo str_pad($m, 2, '0', STR_PAD_LEFT); ?>" <?php echo $m == $month ? 'selected' : ''; ?>>
|
|
<?php echo DateTime::createFromFormat('!m', $m)->format('F'); ?>
|
|
</option>
|
|
<?php endfor; ?>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mr-2">
|
|
<label for="year" class="mr-2">Año:</label>
|
|
<select name="year" id="year" class="form-control">
|
|
<?php for ($y = date('Y'); $y >= date('Y') - 5; $y--): ?>
|
|
<option value="<?php echo $y; ?>" <?php echo $y == $year ? 'selected' : ''; ?>><?php echo $y; ?></option>
|
|
<?php endfor; ?>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Filtrar</button>
|
|
</form>
|
|
|
|
<div class="table-responsive" style="max-height: 70vh; overflow-y: auto;">
|
|
<table class="table table-bordered table-striped table-hover" style="width: 100%;">
|
|
<thead>
|
|
<tr>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">Fecha</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">C.pedidos</th>
|
|
<th colspan="5" style="text-align: center;">Ingresos</th>
|
|
<th colspan="6" style="text-align: center;">Inversion Publicitaria</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">RC ENVIO</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">RC CONTRAENT</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">Total Ingresos</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">Total Inversion Publicitaria</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">Recaudo final</th>
|
|
<th rowspan="2" style="vertical-align: middle; text-align: center;">Sc</th>
|
|
</tr>
|
|
<tr>
|
|
<th>BCP/YAPE</th>
|
|
<th>B. NACION</th>
|
|
<th>INTERBANK</th>
|
|
<th>BBVA</th>
|
|
<th>Otros Ingresos</th>
|
|
<th>TU 1</th>
|
|
<th>TU 2</th>
|
|
<th>TU 3</th>
|
|
<th>FL1</th>
|
|
<th>FL2</th>
|
|
<th>FL3</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($all_days_data as $date => $day_data): ?>
|
|
<tr data-date="<?php echo $date; ?>">
|
|
<td><?php echo $date; ?></td>
|
|
<td contenteditable="true" data-column="c_pedidos"><?php echo htmlspecialchars(number_format((int)($day_data['c_pedidos'] ?? 0), 0, '', '')); ?></td>
|
|
<?php foreach ($display_columns as $col): ?>
|
|
<?php if ($col === 'rc_envio'): ?>
|
|
<td data-column="rc_envio"><?php echo htmlspecialchars(number_format((float)($day_data[$col] ?? 0), 2, '.', '')); ?></td>
|
|
<?php else: ?>
|
|
<td contenteditable="true" data-column="<?php echo $col; ?>"><?php echo htmlspecialchars(number_format((float)($day_data[$col] ?? 0), 2, '.', '')); ?></td>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
<td class="total-ingresos">0.00</td>
|
|
<td class="total-inversion">0.00</td>
|
|
<td class="recaudo-final">0.00</td>
|
|
<td contenteditable="true" data-column="sc"><?php echo htmlspecialchars(number_format((float)($day_data['sc'] ?? 0), 2, '.', '')); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<th>TOTAL</th>
|
|
<th data-total-column="c_pedidos"><?php echo number_format($totals['c_pedidos'], 0); ?></th>
|
|
<?php foreach ($display_columns as $col): ?>
|
|
<th data-total-column="<?php echo $col; ?>"><?php echo number_format($totals[$col], 2); ?></th>
|
|
<?php endforeach; ?>
|
|
<th data-total-column="total-ingresos"><?php echo number_format($totals['total_ingresos'], 2); ?></th>
|
|
<th data-total-column="total-inversion"><?php echo number_format($totals['total_inversion'], 2); ?></th>
|
|
<th data-total-column="recaudo-final"><?php echo number_format($totals['recaudo_final'], 2); ?></th>
|
|
<th data-total-column="sc"><?php echo number_format($totals['sc'], 2); ?></th>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const table = document.querySelector('.table');
|
|
|
|
function updateTotals(row) {
|
|
const getVal = (selector) => {
|
|
const cell = row.querySelector(`[data-column="${selector}"]`);
|
|
return parseFloat(cell.textContent.replace(/,/g, '')) || 0;
|
|
};
|
|
|
|
const rcEnvio = getVal('bcp_yape') + getVal('b_nacion') + getVal('interbank') + getVal('bbva') + getVal('otros_ingresos');
|
|
const rcEnvioCell = row.querySelector('[data-column="rc_envio"]');
|
|
if (rcEnvioCell) {
|
|
rcEnvioCell.textContent = rcEnvio.toFixed(2);
|
|
}
|
|
|
|
const ingresos = rcEnvio + getVal('rc_contraent');
|
|
const totalInversion = getVal('tu1') + getVal('tu2') + getVal('tu3') + getVal('fl1') + getVal('fl2') + getVal('fl3');
|
|
const recaudoFinal = ingresos - totalInversion;
|
|
|
|
row.querySelector('.total-ingresos').textContent = ingresos.toFixed(2);
|
|
row.querySelector('.total-inversion').textContent = totalInversion.toFixed(2);
|
|
row.querySelector('.recaudo-final').textContent = recaudoFinal.toFixed(2);
|
|
}
|
|
|
|
function updateGrandTotals() {
|
|
const grandTotals = {
|
|
<?php foreach ($display_columns as $col) echo "'$col': 0,"; ?>
|
|
'c_pedidos': 0,
|
|
'sc': 0,
|
|
'total-ingresos': 0,
|
|
'total-inversion': 0,
|
|
'recaudo-final': 0
|
|
};
|
|
|
|
table.querySelectorAll('tbody tr').forEach(row => {
|
|
<?php foreach ($display_columns as $col): ?>
|
|
grandTotals['<?php echo $col; ?>'] += parseFloat(row.querySelector(`[data-column="<?php echo $col; ?>"]`).textContent.replace(/,/g, '')) || 0;
|
|
<?php endforeach; ?>
|
|
grandTotals['c_pedidos'] += parseInt(row.querySelector(`[data-column="c_pedidos"]`).textContent.replace(/,/g, '')) || 0;
|
|
grandTotals['sc'] += parseFloat(row.querySelector(`[data-column="sc"]`).textContent.replace(/,/g, '')) || 0;
|
|
grandTotals['total-ingresos'] += parseFloat(row.querySelector('.total-ingresos').textContent.replace(/,/g, '')) || 0;
|
|
grandTotals['total-inversion'] += parseFloat(row.querySelector('.total-inversion').textContent.replace(/,/g, '')) || 0;
|
|
grandTotals['recaudo-final'] += parseFloat(row.querySelector('.recaudo-final').textContent.replace(/,/g, '')) || 0;
|
|
});
|
|
|
|
for (const key in grandTotals) {
|
|
const th = table.querySelector(`tfoot [data-total-column="${key}"]`);
|
|
if (th) {
|
|
if (key === 'c_pedidos') {
|
|
th.textContent = grandTotals[key];
|
|
} else {
|
|
th.textContent = grandTotals[key].toFixed(2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
table.querySelectorAll('tbody tr').forEach(updateTotals);
|
|
updateGrandTotals();
|
|
|
|
table.addEventListener('focus', function(e) {
|
|
if (e.target.hasAttribute('contenteditable')) {
|
|
const range = document.createRange();
|
|
range.selectNodeContents(e.target);
|
|
const sel = window.getSelection();
|
|
sel.removeAllRanges();
|
|
sel.addRange(range);
|
|
}
|
|
}, true);
|
|
|
|
table.addEventListener('blur', function(e) {
|
|
if (e.target.hasAttribute('contenteditable')) {
|
|
const cell = e.target;
|
|
const row = cell.closest('tr');
|
|
const date = row.dataset.date;
|
|
const column = cell.dataset.column;
|
|
let value;
|
|
|
|
if (column === 'c_pedidos') {
|
|
value = parseInt(cell.textContent.replace(/,/g, ''));
|
|
} else {
|
|
value = parseFloat(cell.textContent.replace(/,/g, ''));
|
|
}
|
|
|
|
if (isNaN(value)) {
|
|
value = 0;
|
|
}
|
|
|
|
if (column === 'c_pedidos') {
|
|
cell.textContent = value;
|
|
} else {
|
|
cell.textContent = value.toFixed(2);
|
|
}
|
|
|
|
fetch('save_flujo_caja.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ fecha: date, columna: column, valor: value })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
updateTotals(row);
|
|
updateGrandTotals(); // Update grand totals after successful save
|
|
} else {
|
|
console.error('Error saving data:', data.message);
|
|
}
|
|
})
|
|
.catch(error => console.error('Fetch error:', error));
|
|
}
|
|
}, true);
|
|
|
|
table.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter' && e.target.hasAttribute('contenteditable')) {
|
|
e.preventDefault();
|
|
e.target.blur();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<?php
|
|
require_once 'layout_footer.php';
|
|
?>
|