Autosave: 20260203-220138
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 257 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 62 KiB |
@ -1,150 +1,74 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
$pageTitle = "Configuración del Kanban";
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
$db = db();
|
||||
|
||||
// Fetch banner text for the form
|
||||
$stmt_banner = $db->prepare('SELECT valor FROM configuracion WHERE clave = ?');
|
||||
$stmt_banner->execute(['banner_text']);
|
||||
$banner_text = $stmt_banner->fetchColumn();
|
||||
// Asegurarse de que el usuario sea administrador
|
||||
if ($_SESSION['user_role'] !== 'Administrador' && $_SESSION['user_role'] !== 'admin') {
|
||||
echo "<div class='alert alert-danger'>Acceso denegado.</div>";
|
||||
require_once 'layout_footer.php';
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch kanban columns
|
||||
$kanban_columns = $db->query("SELECT id, nombre FROM kanban_columns ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$conn = db();
|
||||
|
||||
include 'layout_header.php';
|
||||
// Obtener la configuración actual
|
||||
$query = "SELECT * FROM configuracion WHERE id = 1";
|
||||
$result = $conn->query($query);
|
||||
$config = $result->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Columnas disponibles
|
||||
$available_columns = [
|
||||
'new' => 'Nuevos',
|
||||
'reagendado' => 'Reagendado',
|
||||
'no_contactado' => 'No Contactado',
|
||||
'contactado' => 'Contactado',
|
||||
'agendado' => 'Agendado',
|
||||
'en_ruta' => 'En Ruta',
|
||||
'entregado' => 'Entregado',
|
||||
'no_entregado' => 'No Entregado',
|
||||
'reprogramado' => 'Reprogramado'
|
||||
];
|
||||
|
||||
$visible_columns = $config ? json_decode($config['kanban_columns'], true) : [];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$new_visible_columns = $_POST['columns'] ?? [];
|
||||
$json_columns = json_encode($new_visible_columns);
|
||||
|
||||
$update_query = "UPDATE configuracion SET kanban_columns = :kanban_columns WHERE id = 1";
|
||||
$stmt = $conn->prepare($update_query);
|
||||
$stmt->bindParam(':kanban_columns', $json_columns);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo "<div class='alert alert-success'>Configuración guardada correctamente.</div>";
|
||||
$visible_columns = $new_visible_columns;
|
||||
} else {
|
||||
echo "<div class='alert alert-danger'>Error al guardar la configuración.</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<?php if (isset($_SESSION['success_message'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo $_SESSION['success_message']; unset($_SESSION['success_message']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_SESSION['error_message'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo $_SESSION['error_message']; unset($_SESSION['error_message']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<h2>Configuración de Columnas del Kanban</h2>
|
||||
<p>Selecciona las columnas que deseas que sean visibles en el tablero Kanban.</p>
|
||||
|
||||
<h1 class="mb-4">Configuración General</h1>
|
||||
|
||||
<!-- Banner Text Management -->
|
||||
<div class="card mb-5">
|
||||
<div class="card-header">
|
||||
<h2>Editar Banner del Kanban</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="save_banner_text.php" method="post">
|
||||
<div class="form-group">
|
||||
<label for="banner_text">Texto del banner</label>
|
||||
<textarea name="banner_text" id="banner_text" class="form-control" rows="2"><?php echo htmlspecialchars($banner_text ?? ''); ?></textarea>
|
||||
<small class="form-text text-muted">Este texto aparecerá en un banner deslizante en la parte superior del tablero Kanban.</small>
|
||||
<form method="POST">
|
||||
<div class="row">
|
||||
<?php foreach ($available_columns as $key => $name): ?>
|
||||
<div class="col-md-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="columns[]" value="<?php echo $key; ?>" id="col_<?php echo $key; ?>" <?php echo in_array($key, $visible_columns) ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="col_<?php echo $key; ?>">
|
||||
<?php echo htmlspecialchars($name); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Guardar Banner</button>
|
||||
</form>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cobertura Banner Management -->
|
||||
<div class="card mb-5">
|
||||
<div class="card-header">
|
||||
<h2>Editar Imagen de Cobertura</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center mb-3">
|
||||
<p>Imagen actual:</p>
|
||||
<?php
|
||||
$banner_image = 'assets/uploads/cobertura_banner.jpg';
|
||||
if (file_exists($banner_image)):
|
||||
?>
|
||||
<img src="<?php echo $banner_image; ?>?t=<?php echo time(); ?>" alt="Banner de Cobertura" class="img-fluid rounded" style="max-height: 200px;">
|
||||
<?php else: ?>
|
||||
<p>No hay ninguna imagen de cobertura cargada.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<form action="save_cobertura_banner.php" method="post" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="banner_image">Subir o reemplazar imagen</label>
|
||||
<input type="file" class="form-control-file" id="banner_image" name="banner_image" accept="image/jpeg,image/png,image/gif,image/webp" required>
|
||||
<small class="form-text text-muted">La imagen se guardará como .jpg y se mostrará en la sección de Cobertura.</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Guardar Imagen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cobertura Xpress Banner Management -->
|
||||
<div class="card mb-5">
|
||||
<div class="card-header">
|
||||
<h2>Editar Imagen de Cobertura Xpress</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center mb-3">
|
||||
<p>Imagen actual:</p>
|
||||
<?php
|
||||
$banner_image_xpress = 'assets/uploads/cobertura_xpress_banner.jpg';
|
||||
if (file_exists($banner_image_xpress)):
|
||||
?>
|
||||
<img src="<?php echo $banner_image_xpress; ?>?t=<?php echo time(); ?>" alt="Banner de Cobertura Xpress" class="img-fluid rounded" style="max-height: 200px;">
|
||||
<?php else: ?>
|
||||
<p>No hay ninguna imagen de Cobertura Xpress cargada.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<form action="save_cobertura_xpress_banner.php" method="post" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="banner_image_xpress">Subir o reemplazar imagen</label>
|
||||
<input type="file" class="form-control-file" id="banner_image_xpress" name="banner_image_xpress" accept="image/jpeg,image/png,image/gif,image/webp" required>
|
||||
<small class="form-text text-muted">Esta imagen se mostrará en la sección de Cobertura Xpress.</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Guardar Imagen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column Management -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2>Configuración de Columnas Kanban</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nombre de la Columna</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($kanban_columns as $column): ?>
|
||||
<tr>
|
||||
<form action="edit_column.php" method="post">
|
||||
<td><?php echo htmlspecialchars($column['id']); ?></td>
|
||||
<td>
|
||||
<input type="text" name="nombre" class="form-control" value="<?php echo htmlspecialchars($column['nombre']); ?>">
|
||||
<input type="hidden" name="id" value="<?php echo $column['id']; ?>">
|
||||
</td>
|
||||
<td>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Guardar</button>
|
||||
<a href="delete_column.php?id=<?php echo $column['id']; ?>" class="btn btn-danger btn-sm" onclick="return confirm('¿Estás seguro?')">Eliminar</a>
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<form action="add_column.php" method="post" class="form-inline mt-3">
|
||||
<div class="form-group">
|
||||
<input type="text" name="nombre" class="form-control" placeholder="Nueva Columna" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success ml-2">Agregar Columna</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3">Guardar Configuración</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include 'layout_footer.php'; ?>
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
1
db/migrations/053_add_c_pedidos_to_flujo_caja.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `flujo_caja` ADD `c_pedidos` VARCHAR(255) NULL AFTER `fecha`;
|
||||
@ -9,12 +9,21 @@ $start_date = "$year-$month-01";
|
||||
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
|
||||
$end_date = "$year-$month-$days_in_month";
|
||||
|
||||
$columns = [
|
||||
// Columns from DB that are editable
|
||||
$db_columns = [
|
||||
'bcp_yape', 'b_nacion', 'interbank', 'bbva', 'otros_ingresos',
|
||||
'tu1', 'tu2', 'tu3', 'fl1', 'fl2', 'fl3',
|
||||
'rc_envio', 'rc_contraent', 'sc'
|
||||
'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 {
|
||||
@ -33,26 +42,39 @@ try {
|
||||
$all_days_data = [];
|
||||
for ($day = 1; $day <= $days_in_month; $day++) {
|
||||
$date = date('Y-m-d', strtotime("$year-$month-$day"));
|
||||
$all_days_data[$date] = isset($flujo_data[$date]) ? $flujo_data[$date] : array_fill_keys($columns, '0.00');
|
||||
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($columns, 0);
|
||||
$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 $day_data) {
|
||||
$ingresos_dia = (float)$day_data['bcp_yape'] + (float)$day_data['b_nacion'] + (float)$day_data['interbank'] + (float)$day_data['bbva'] + (float)$day_data['otros_ingresos'] + (float)$day_data['rc_envio'] + (float)$day_data['rc_contraent'];
|
||||
$inversion_dia = (float)$day_data['tu1'] + (float)$day_data['tu2'] + (float)$day_data['tu3'] + (float)$day_data['fl1'] + (float)$day_data['fl2'] + (float)$day_data['fl3'];
|
||||
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 ($columns as $col) {
|
||||
$totals[$col] += (float)$day_data[$col];
|
||||
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);
|
||||
|
||||
?>
|
||||
|
||||
@ -108,14 +130,15 @@ foreach ($all_days_data as $day_data) {
|
||||
<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;">Sc</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>
|
||||
@ -135,24 +158,32 @@ foreach ($all_days_data as $day_data) {
|
||||
<?php foreach ($all_days_data as $date => $day_data): ?>
|
||||
<tr data-date="<?php echo $date; ?>">
|
||||
<td><?php echo $date; ?></td>
|
||||
<?php foreach ($columns as $col): ?>
|
||||
<td contenteditable="true" data-column="<?php echo $col; ?>"><?php echo htmlspecialchars(number_format((float)$day_data[$col], 2, '.', '')); ?></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>
|
||||
<?php foreach ($columns as $col): ?>
|
||||
<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>
|
||||
@ -169,7 +200,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return parseFloat(cell.textContent.replace(/,/g, '')) || 0;
|
||||
};
|
||||
|
||||
const ingresos = getVal('bcp_yape') + getVal('b_nacion') + getVal('interbank') + getVal('bbva') + getVal('otros_ingresos') + getVal('rc_envio') + getVal('rc_contraent');
|
||||
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;
|
||||
|
||||
@ -180,16 +217,20 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
function updateGrandTotals() {
|
||||
const grandTotals = {
|
||||
<?php foreach ($columns as $col) echo "'$col': 0,"; ?>
|
||||
<?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 ($columns as $col): ?>
|
||||
<?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;
|
||||
@ -198,7 +239,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
for (const key in grandTotals) {
|
||||
const th = table.querySelector(`tfoot [data-total-column="${key}"]`);
|
||||
if (th) {
|
||||
th.textContent = grandTotals[key].toFixed(2);
|
||||
if (key === 'c_pedidos') {
|
||||
th.textContent = grandTotals[key];
|
||||
} else {
|
||||
th.textContent = grandTotals[key].toFixed(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,12 +267,23 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const row = cell.closest('tr');
|
||||
const date = row.dataset.date;
|
||||
const column = cell.dataset.column;
|
||||
let value = parseFloat(cell.textContent.replace(/,/g, ''));
|
||||
let value;
|
||||
|
||||
if (column === 'c_pedidos') {
|
||||
value = parseInt(cell.textContent.replace(/,/g, ''));
|
||||
} else {
|
||||
value = parseFloat(cell.textContent.replace(/,/g, ''));
|
||||
}
|
||||
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
cell.textContent = value.toFixed(2);
|
||||
|
||||
if (column === 'c_pedidos') {
|
||||
cell.textContent = value;
|
||||
} else {
|
||||
cell.textContent = value.toFixed(2);
|
||||
}
|
||||
|
||||
fetch('save_flujo_caja.php', {
|
||||
method: 'POST',
|
||||
@ -258,4 +314,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
<?php
|
||||
require_once 'layout_footer.php';
|
||||
?>
|
||||
?>
|
||||
|
||||
307
kanban.php
@ -1,223 +1,146 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'layout_header.php';
|
||||
|
||||
if (!isset($_SESSION['username'])) {
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$username = $_SESSION['username'];
|
||||
$role = $_SESSION['role'];
|
||||
|
||||
// Conectar a la base de datos
|
||||
$pdo = db();
|
||||
|
||||
// Fetch banner text
|
||||
$stmt_banner = $pdo->prepare('SELECT valor FROM configuracion WHERE clave = ?');
|
||||
$stmt_banner->execute(['banner_text']);
|
||||
$banner_text = $stmt_banner->fetchColumn();
|
||||
if (empty($banner_text)) {
|
||||
$banner_text = '¡Define tu frase motivacional en la sección de Información de Producto!';
|
||||
}
|
||||
// Obtener la configuración de las columnas del Kanban
|
||||
$stmt = $pdo->query("SELECT kanban_columns FROM configuracion WHERE id = 1");
|
||||
$config = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch Kanban columns
|
||||
$stmt_columns = $pdo->query('SELECT id, nombre FROM kanban_columns ORDER BY orden ASC');
|
||||
$columns = $stmt_columns->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// If no columns exist, create default ones
|
||||
if (empty($columns)) {
|
||||
$default_columns = ['Backlog', 'En Proceso', 'Hecho'];
|
||||
$stmt_insert = $pdo->prepare('INSERT INTO kanban_columns (nombre, orden) VALUES (?, ?)');
|
||||
foreach ($default_columns as $index => $name) {
|
||||
$stmt_insert->execute([$name, $index + 1]);
|
||||
$columns_to_display = [];
|
||||
if ($config && !empty($config['kanban_columns'])) {
|
||||
$column_ids = json_decode($config['kanban_columns'], true);
|
||||
if (!empty($column_ids)) {
|
||||
$placeholders = implode(',', array_fill(0, count($column_ids), '?'));
|
||||
$stmt = $pdo->prepare("SELECT id, nombre FROM kanban_columns WHERE id IN ($placeholders)");
|
||||
$stmt->execute($column_ids);
|
||||
$columns_to_display = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
// Re-fetch columns
|
||||
$stmt_columns = $pdo->query('SELECT id, nombre FROM kanban_columns ORDER BY orden ASC');
|
||||
$columns = $stmt_columns->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
// Fetch info cards and group them by column
|
||||
$stmt_cards = $pdo->query('
|
||||
SELECT
|
||||
ip.id,
|
||||
ip.texto_informativo,
|
||||
ip.imagen_url,
|
||||
ip.column_id,
|
||||
p.nombre as producto_nombre
|
||||
FROM
|
||||
info_productos ip
|
||||
LEFT JOIN
|
||||
products p ON ip.producto_id = p.id
|
||||
ORDER BY
|
||||
ip.id ASC
|
||||
');
|
||||
$cards = $stmt_cards->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
|
||||
|
||||
$cards_by_column = [];
|
||||
foreach ($cards as $card) {
|
||||
$column_id = $card['column_id'] ?: 'unassigned';
|
||||
$cards_by_column[$column_id][] = $card;
|
||||
if (empty($columns_to_display)) {
|
||||
$stmt = $pdo->query("SELECT id, nombre FROM kanban_columns");
|
||||
$columns_to_display = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
// Obtener todos los productos de información
|
||||
$stmt = $pdo->query("SELECT ip.*, p.nombre as producto_nombre FROM info_productos ip LEFT JOIN products p ON ip.product_id = p.id");
|
||||
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$pageTitle = "Kanban de Productos";
|
||||
$pageDescription = "Tablero Kanban para visualizar la información de los productos.";
|
||||
|
||||
include 'layout_header.php';
|
||||
?>
|
||||
|
||||
<style>
|
||||
@keyframes marquee {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
.motivational-banner {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
color: #333;
|
||||
padding: 15px 0;
|
||||
margin: 0 auto 20px auto;
|
||||
border-radius: 8px;
|
||||
max-width: 80%;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.motivational-banner p {
|
||||
display: inline-block;
|
||||
padding-left: 100%;
|
||||
animation: marquee 15s linear infinite;
|
||||
margin: 0;
|
||||
}
|
||||
.kanban-board {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding: 20px 10px;
|
||||
background: linear-gradient(to right, #e8f5e9, #c8e6c9);
|
||||
border-radius: 8px;
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
.kanban-column {
|
||||
flex: 1 0 300px;
|
||||
margin: 0 10px;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(5px);
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100%;
|
||||
}
|
||||
.kanban-cards-container {
|
||||
overflow-y: auto;
|
||||
flex-grow: 1;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.kanban-column-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.kanban-column-header h5 {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
.kanban-card {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 0 rgba(9,30,66,.25);
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.kanban-card img {
|
||||
max-width: 100%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="motivational-banner">
|
||||
<p><?php echo htmlspecialchars($banner_text); ?></p>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h2>Tablero Kanban</h2>
|
||||
<p>Visualiza el flujo de trabajo de la información de tus productos.</p>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1><?php echo $pageTitle; ?></h1>
|
||||
</div>
|
||||
<p><?php echo $pageDescription; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kanban-board">
|
||||
<?php foreach ($columns as $column) : ?>
|
||||
<div class="kanban-column" data-column-id="<?= $column['id'] ?>">
|
||||
<div class="kanban-column-header">
|
||||
<h5><?= htmlspecialchars($column['nombre']) ?></h5>
|
||||
</div>
|
||||
<div class="kanban-cards-container">
|
||||
<?php if (isset($cards_by_column[$column['id']])) : ?>
|
||||
<?php foreach ($cards_by_column[$column['id']] as $card) : ?>
|
||||
<div class="kanban-card" data-card-id="<?= $card['id'] ?>">
|
||||
<?php if (!empty($card['imagen_url'])) : ?>
|
||||
<img src="<?= htmlspecialchars($card['imagen_url']) ?>" class="card-img-top" alt="Imagen del producto">
|
||||
<?php endif; ?>
|
||||
<div class="card-body" style="padding: 10px 0 0 0;">
|
||||
<?php if (!empty($card['producto_nombre'])) : ?>
|
||||
<h6 class="card-title" style="margin-bottom: 5px; font-weight: bold;"><?= htmlspecialchars($card['producto_nombre']) ?></h6>
|
||||
<?php endif; ?>
|
||||
<p class="card-text" id="texto-info-<?= $card['id'] ?>" style="font-size: 0.9rem;"><?= nl2br(htmlspecialchars($card['texto_informativo'])) ?></p>
|
||||
<button class="btn btn-sm btn-outline-secondary mt-2" onclick="copiarTexto(this, 'texto-info-<?= $card['id'] ?>')">
|
||||
<i class="fas fa-copy"></i> Copiar Texto
|
||||
</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="kanban-board-container">
|
||||
<div class="kanban-board">
|
||||
<?php foreach ($columns_to_display as $column): ?>
|
||||
<div class="kanban-column" data-column-id="<?php echo $column['nombre']; ?>">
|
||||
<div class="kanban-column-header">
|
||||
<h5><?php echo htmlspecialchars($column['nombre']); ?></h5>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<!-- Unassigned column -->
|
||||
<div class="kanban-column" data-column-id="unassigned">
|
||||
<div class="kanban-column-header">
|
||||
<h5>Sin Asignar</h5>
|
||||
</div>
|
||||
<div class="kanban-cards-container">
|
||||
<?php if (isset($cards_by_column['unassigned'])) : ?>
|
||||
<?php foreach ($cards_by_column['unassigned'] as $card) : ?>
|
||||
<div class="kanban-card" data-card-id="<?= $card['id'] ?>">
|
||||
<?php if (!empty($card['imagen_url'])) : ?>
|
||||
<img src="<?= htmlspecialchars($card['imagen_url']) ?>" class="card-img-top" alt="Imagen del producto">
|
||||
<?php endif; ?>
|
||||
<div class="card-body" style="padding: 10px 0 0 0;">
|
||||
<?php if (!empty($card['producto_nombre'])) : ?>
|
||||
<h6 class="card-title" style="margin-bottom: 5px; font-weight: bold;"><?= htmlspecialchars($card['producto_nombre']) ?></h6>
|
||||
<?php endif; ?>
|
||||
<p class="card-text" id="texto-info-<?= $card['id'] ?>" style="font-size: 0.9rem;"><?= nl2br(htmlspecialchars($card['texto_informativo'])) ?></p>
|
||||
<button class="btn btn-sm btn-outline-secondary mt-2" onclick="copiarTexto(this, 'texto-info-<?= $card['id'] ?>')">
|
||||
<i class="fas fa-copy"></i> Copiar Texto
|
||||
</button>
|
||||
<div class="kanban-column-body">
|
||||
<?php foreach ($items as $item): ?>
|
||||
<?php if ($item['estado_kanban'] == $column['nombre']): ?>
|
||||
<div class="kanban-card" data-item-id="<?php echo $item['id']; ?>">
|
||||
<div class="card-body">
|
||||
<?php if (!empty($item['imagen'])): ?>
|
||||
<img src="assets/uploads/info_images/<?php echo htmlspecialchars($item['imagen']); ?>" class="card-img-top mb-2" alt="Imagen del producto">
|
||||
<?php endif; ?>
|
||||
<h6 class="card-title"><?php echo htmlspecialchars($item['titulo']); ?></h6>
|
||||
<p class="card-text small"><?php echo htmlspecialchars($item['producto_nombre']); ?></p>
|
||||
<button class="btn btn-sm btn-secondary" onclick="copiarTexto(this)">Copiar Texto</button>
|
||||
<div class="texto-a-copiar" style="display:none;"><?php echo htmlspecialchars($item['texto']); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.kanban-board-container {
|
||||
overflow-x: auto;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.kanban-board {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
min-width: max-content;
|
||||
}
|
||||
.kanban-column {
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
background-color: #f4f5f7;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.kanban-column-header {
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.kanban-column-body {
|
||||
padding: 10px;
|
||||
min-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.kanban-card {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
cursor: grab;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function copiarTexto(button, elementId) {
|
||||
const textToCopy = document.getElementById(elementId).innerText;
|
||||
navigator.clipboard.writeText(textToCopy).then(() => {
|
||||
const originalIcon = 'fas fa-copy';
|
||||
const originalText = ' Copiar Texto';
|
||||
|
||||
button.querySelector('i').className = 'fas fa-check';
|
||||
button.lastChild.nodeValue = ' ¡Copiado!';
|
||||
|
||||
setTimeout(() => {
|
||||
button.querySelector('i').className = originalIcon;
|
||||
button.lastChild.nodeValue = originalText;
|
||||
}, 2000);
|
||||
}).catch(err => {
|
||||
console.error('Error al copiar texto: ', err);
|
||||
alert('Error al copiar texto.');
|
||||
});
|
||||
function copiarTexto(button) {
|
||||
var cardBody = button.closest('.card-body');
|
||||
var texto = cardBody.querySelector('.texto-a-copiar').innerText;
|
||||
|
||||
var tempInput = document.createElement('textarea');
|
||||
tempInput.style.position = 'absolute';
|
||||
tempInput.style.left = '-9999px';
|
||||
tempInput.value = texto;
|
||||
document.body.appendChild(tempInput);
|
||||
tempInput.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(tempInput);
|
||||
|
||||
button.innerText = 'Copiado!';
|
||||
setTimeout(function() {
|
||||
button.innerText = 'Copiar Texto';
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
<?php include 'layout_footer.php'; ?>
|
||||
|
||||
@ -165,6 +165,12 @@ $navItems = [
|
||||
'icon' => 'fa-users',
|
||||
'text' => 'Gestionar Usuarios',
|
||||
'roles' => ['Administrador', 'admin']
|
||||
],
|
||||
'configuracion' => [
|
||||
'url' => 'configuracion.php',
|
||||
'icon' => 'fa-cog',
|
||||
'text' => 'Configuración',
|
||||
'roles' => ['Administrador', 'admin']
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@ -10,9 +10,9 @@ if ($data) {
|
||||
|
||||
// Column name validation to prevent SQL injection
|
||||
$allowed_columns = [
|
||||
'bcp_yape', 'b_nacion', 'interbank', 'bbva', 'otros_ingresos',
|
||||
'c_pedidos', 'bcp_yape', 'b_nacion', 'interbank', 'bbva', 'otros_ingresos',
|
||||
'tu1', 'tu2', 'tu3', 'fl1', 'fl2', 'fl3',
|
||||
'rc_envio', 'rc_contraent', 'sc', 'total_inversion_publicitaria'
|
||||
'rc_contraent', 'sc', 'total_inversion_publicitaria'
|
||||
];
|
||||
|
||||
if (in_array($columna, $allowed_columns)) {
|
||||
|
||||