Autosave: 20260203-072219
This commit is contained in:
parent
9a3241c3ec
commit
e2dbd8b86f
@ -9,6 +9,13 @@ $start_date = "$year-$month-01";
|
||||
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
|
||||
$end_date = "$year-$month-$days_in_month";
|
||||
|
||||
$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();
|
||||
@ -22,22 +29,51 @@ try {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
$columns = [
|
||||
'bcp_yape', 'b_nacion', 'interbank', 'bbva', 'otros_ingresos',
|
||||
'tu1', 'tu2', 'tu3', 'fl1', 'fl2', 'fl3',
|
||||
'rc_envio', 'rc_contraent'
|
||||
];
|
||||
// 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"));
|
||||
$all_days_data[$date] = isset($flujo_data[$date]) ? $flujo_data[$date] : array_fill_keys($columns, '0.00');
|
||||
}
|
||||
|
||||
// Calculate totals
|
||||
$totals = array_fill_keys($columns, 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 ($columns as $col) {
|
||||
$totals[$col] += (float)$day_data[$col];
|
||||
}
|
||||
$totals['total_ingresos'] += $ingresos_dia;
|
||||
$totals['total_inversion'] += $inversion_dia;
|
||||
$totals['recaudo_final'] += ($ingresos_dia - $inversion_dia);
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<style>
|
||||
.table thead th {
|
||||
background-color: #e9ecef; /* Un gris claro y profesional */
|
||||
background-color: #e9ecef;
|
||||
color: #495057;
|
||||
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; /* Un amarillo suave para resaltar la celda activa */
|
||||
background-color: #fff3cd;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -67,7 +103,7 @@ $columns = [
|
||||
<button type="submit" class="btn btn-primary">Filtrar</button>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive">
|
||||
<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>
|
||||
@ -95,21 +131,29 @@ $columns = [
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php for ($day = 1; $day <= $days_in_month; $day++):
|
||||
$date = date('Y-m-d', strtotime("$year-$month-$day"));
|
||||
$day_data = isset($flujo_data[$date]) ? $flujo_data[$date] : array_fill_keys($columns, '0.00');
|
||||
?>
|
||||
<?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($day_data[$col]); ?></td>
|
||||
<td contenteditable="true" data-column="<?php echo $col; ?>"><?php echo htmlspecialchars(number_format((float)$day_data[$col], 2, '.', '')); ?></td>
|
||||
<?php endforeach; ?>
|
||||
<td class="total-ingresos">0.00</td>
|
||||
<td class="total-inversion">0.00</td>
|
||||
<td class="recaudo-final">0.00</td>
|
||||
</tr>
|
||||
<?php endfor; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>TOTAL</th>
|
||||
<?php foreach ($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>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -118,17 +162,14 @@ $columns = [
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const table = document.querySelector('.table');
|
||||
|
||||
// Function to update totals for a specific row
|
||||
function updateTotals(row) {
|
||||
const getVal = (selector) => {
|
||||
const cell = row.querySelector(`[data-column="${selector}"]`);
|
||||
return parseFloat(cell.textContent) || 0;
|
||||
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 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);
|
||||
@ -136,10 +177,34 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
row.querySelector('.recaudo-final').textContent = recaudoFinal.toFixed(2);
|
||||
}
|
||||
|
||||
// Initial calculation for all rows
|
||||
table.querySelectorAll('tbody tr').forEach(updateTotals);
|
||||
function updateGrandTotals() {
|
||||
const grandTotals = {
|
||||
<?php foreach ($columns as $col) echo "'$col': 0,"; ?>
|
||||
'total-ingresos': 0,
|
||||
'total-inversion': 0,
|
||||
'recaudo-final': 0
|
||||
};
|
||||
|
||||
table.querySelectorAll('tbody tr').forEach(row => {
|
||||
<?php foreach ($columns as $col): ?>
|
||||
grandTotals['<?php echo $col; ?>'] += parseFloat(row.querySelector(`[data-column="<?php echo $col; ?>"]`).textContent.replace(/,/g, '')) || 0;
|
||||
<?php endforeach; ?>
|
||||
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) {
|
||||
th.textContent = grandTotals[key].toFixed(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.querySelectorAll('tbody tr').forEach(updateTotals);
|
||||
updateGrandTotals();
|
||||
|
||||
// Event listener for cell focus to select all content
|
||||
table.addEventListener('focus', function(e) {
|
||||
if (e.target.hasAttribute('contenteditable')) {
|
||||
const range = document.createRange();
|
||||
@ -148,50 +213,43 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}
|
||||
}, true); // Use capturing for focus
|
||||
}, true);
|
||||
|
||||
// Event listener for cell edits
|
||||
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 = parseFloat(cell.textContent);
|
||||
let value = parseFloat(cell.textContent.replace(/,/g, ''));
|
||||
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
cell.textContent = '0.00';
|
||||
}
|
||||
cell.textContent = value.toFixed(2);
|
||||
|
||||
// Save data to server
|
||||
fetch('save_flujo_caja.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ fecha: date, columna: column, valor: value })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
if (data.success) {
|
||||
updateTotals(row);
|
||||
updateGrandTotals(); // Update grand totals after successful save
|
||||
} else {
|
||||
console.error('Error saving data:', data.message);
|
||||
// Optional: Add user feedback for save failure
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Fetch error:', error));
|
||||
|
||||
// Update totals for the edited row
|
||||
updateTotals(row);
|
||||
}
|
||||
}, true); // Use capturing to ensure blur event is handled properly
|
||||
}, true);
|
||||
|
||||
// Event listener for Enter key to save and not expand
|
||||
table.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter' && e.target.hasAttribute('contenteditable')) {
|
||||
e.preventDefault(); // Prevent new line
|
||||
e.target.blur(); // Trigger blur to save
|
||||
e.preventDefault();
|
||||
e.target.blur();
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -199,4 +257,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
<?php
|
||||
require_once 'layout_footer.php';
|
||||
?>
|
||||
?>
|
||||
@ -76,7 +76,7 @@ $navItems = [
|
||||
],
|
||||
'inventario_group' => [
|
||||
'icon' => 'fa-warehouse',
|
||||
'text' => 'Inventario',
|
||||
'text' => 'Inventario General',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico'],
|
||||
'submenu' => [
|
||||
'panel_inventario' => [
|
||||
|
||||
@ -9,51 +9,160 @@ require_once 'db/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM products ORDER BY order_position ASC");
|
||||
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 1. Datos para las tarjetas de resumen
|
||||
$total_productos = $pdo->query("SELECT COUNT(*) FROM products")->fetchColumn();
|
||||
$total_sedes = $pdo->query("SELECT COUNT(*) FROM sedes")->fetchColumn();
|
||||
$total_stock = $pdo->query("SELECT SUM(quantity) FROM stock_sedes")->fetchColumn();
|
||||
|
||||
// 2. Datos para la tabla de inventario
|
||||
$sedes_stmt = $pdo->query("SELECT id, nombre FROM sedes ORDER BY nombre");
|
||||
$sedes = $sedes_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$products_stmt = $pdo->query("SELECT id, nombre FROM products ORDER BY nombre");
|
||||
$products = $products_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$stock_stmt = $pdo->query("SELECT product_id, sede_id, quantity FROM stock_sedes");
|
||||
$stock_data = $stock_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Procesar datos para la tabla
|
||||
$inventario = [];
|
||||
foreach ($products as $product) {
|
||||
$inventario[$product['id']] = [
|
||||
'nombre' => $product['nombre'],
|
||||
'total' => 0,
|
||||
'sedes' => array_fill_keys(array_column($sedes, 'id'), 0)
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($stock_data as $stock_item) {
|
||||
if (isset($inventario[$stock_item['product_id']])) {
|
||||
$inventario[$stock_item['product_id']]['sedes'][$stock_item['sede_id']] = $stock_item['quantity'];
|
||||
$inventario[$stock_item['product_id']]['total'] += $stock_item['quantity'];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Datos para el gráfico circular (Distribución por Sede)
|
||||
$stock_por_sede_stmt = $pdo->query("
|
||||
SELECT s.nombre, SUM(ss.quantity) as total_stock
|
||||
FROM sedes s
|
||||
JOIN stock_sedes ss ON s.id = ss.sede_id
|
||||
GROUP BY s.nombre
|
||||
HAVING total_stock > 0
|
||||
ORDER BY s.nombre
|
||||
");
|
||||
$stock_por_sede = $stock_por_sede_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$sede_chart_labels = json_encode(array_column($stock_por_sede, 'nombre'));
|
||||
$sede_chart_data = json_encode(array_column($stock_por_sede, 'total_stock'));
|
||||
|
||||
// 4. Datos para el gráfico de barras (Stock por Producto)
|
||||
$stock_por_producto_stmt = $pdo->query("
|
||||
SELECT p.nombre, SUM(ss.quantity) as total_stock
|
||||
FROM products p
|
||||
JOIN stock_sedes ss ON p.id = ss.product_id
|
||||
GROUP BY p.nombre
|
||||
HAVING total_stock > 0
|
||||
ORDER BY total_stock DESC
|
||||
LIMIT 15
|
||||
");
|
||||
$stock_por_producto = $stock_por_producto_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$producto_chart_labels = json_encode(array_column($stock_por_producto, 'nombre'));
|
||||
$producto_chart_data = json_encode(array_column($stock_por_producto, 'total_stock'));
|
||||
|
||||
|
||||
} catch (PDOException $e) {
|
||||
echo "<div class='alert alert-danger'>Error al conectar con la base de datos: " . $e->getMessage() . "</div>";
|
||||
// Consider logging the error and showing a more user-friendly message
|
||||
// For now, we stop execution if the database connection fails.
|
||||
echo "<div class='alert alert-danger'>Error al conectar o consultar la base de datos: " . $e->getMessage() . "</div>";
|
||||
require_once 'layout_footer.php';
|
||||
die();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1 class="m-0">Inventario General</h1>
|
||||
<a href="edit_product.php" class="btn btn-primary">Añadir Producto</a>
|
||||
<h1 class="mb-4">Dashboard de Inventario</h1>
|
||||
|
||||
<!-- Tarjetas de Resumen -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card text-white bg-primary mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Total de Productos</h5>
|
||||
<p class="card-text fs-4"><?php echo $total_productos; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card text-white bg-success mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Sedes Activas</h5>
|
||||
<p class="card-text fs-4"><?php echo $total_sedes; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card text-white bg-info mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Unidades Totales en Stock</h5>
|
||||
<p class="card-text fs-4"><?php echo $total_stock ?: 0; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección de Gráficos -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="m-0">Distribución por Sede</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="distribucionSedeChart" style="max-height: 300px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="m-0">Top 15 Productos con Más Stock</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="stockProductoChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Tabla de Inventario Detallado -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="m-0">Inventario por Sede</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="thead-dark">
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nombre</th>
|
||||
<th>SKU</th>
|
||||
<th>Precio</th>
|
||||
<th class="text-center">Acciones</th>
|
||||
<th>Producto</th>
|
||||
<th class="text-center">Stock Total</th>
|
||||
<?php foreach ($sedes as $sede): ?>
|
||||
<th class="text-center"><?php echo htmlspecialchars($sede['nombre']); ?></th>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($products)): ?>
|
||||
<?php if (empty($inventario)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">No hay productos en el inventario. <a href="edit_product.php">Agrega el primero</a>.</td>
|
||||
<td colspan="<?php echo count($sedes) + 2; ?>" class="text-center">No hay productos para mostrar.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<?php foreach ($inventario as $datos_producto): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($product['id']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['nombre']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['sku']); ?></td>
|
||||
<td>S/ <?php echo htmlspecialchars(number_format($product['precio'], 2)); ?></td>
|
||||
<td class="text-center">
|
||||
<a href="edit_product.php?id=<?php echo $product['id']; ?>" class="btn btn-sm btn-warning">Editar</a>
|
||||
<a href="delete_product.php?id=<?php echo $product['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('¿Estás seguro de que quieres eliminar este producto?');">Eliminar</a>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($datos_producto['nombre']); ?></td>
|
||||
<td class="text-center fw-bold"><?php echo $datos_producto['total']; ?></td>
|
||||
<?php foreach ($datos_producto['sedes'] as $cantidad): ?>
|
||||
<td class="text-center"><?php echo $cantidad; ?></td>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
@ -64,4 +173,88 @@ try {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Incluir Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// --- Gráfico 1: Distribución por Sede (Circular) ---
|
||||
const sedeLabels = <?php echo $sede_chart_labels; ?>;
|
||||
const sedeData = <?php echo $sede_chart_data; ?>;
|
||||
|
||||
if (sedeLabels.length > 0) {
|
||||
const defaultColors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'];
|
||||
const alidrvColor = '#28a745'; // Verde
|
||||
|
||||
const backgroundColors = sedeLabels.map((label, index) => {
|
||||
if (label.toLowerCase() === 'alidrv') {
|
||||
return alidrvColor;
|
||||
}
|
||||
return defaultColors[index % defaultColors.length];
|
||||
});
|
||||
|
||||
const ctxSede = document.getElementById('distribucionSedeChart').getContext('2d');
|
||||
new Chart(ctxSede, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: sedeLabels,
|
||||
datasets: [{
|
||||
label: 'Stock',
|
||||
data: sedeData,
|
||||
backgroundColor: backgroundColors,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- Gráfico 2: Stock por Producto (Barras) ---
|
||||
const productoLabels = <?php echo $producto_chart_labels; ?>;
|
||||
const productoData = <?php echo $producto_chart_data; ?>;
|
||||
|
||||
if (productoLabels.length > 0) {
|
||||
const ctxProducto = document.getElementById('stockProductoChart').getContext('2d');
|
||||
new Chart(ctxProducto, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: productoLabels,
|
||||
datasets: [{
|
||||
label: 'Cantidad en Stock',
|
||||
data: productoData,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.6)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y', // Hace que el gráfico sea horizontal
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Stock por Producto'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user