Autosave: 20260203-070225
This commit is contained in:
parent
a059de67e8
commit
9a3241c3ec
65
agregar_producto.php
Normal file
65
agregar_producto.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
$pageTitle = "Agregar Nuevo Producto";
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$nombre_producto = filter_input(INPUT_POST, 'nombre_producto', FILTER_SANITIZE_STRING);
|
||||
|
||||
if ($nombre_producto) {
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8", DB_USER, DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// Insertar el nuevo producto
|
||||
$stmt = $pdo->prepare("INSERT INTO products (nombre) VALUES (:nombre)");
|
||||
$stmt->execute(['nombre' => $nombre_producto]);
|
||||
|
||||
$message = "¡Producto '" . htmlspecialchars($nombre_producto) . "' agregado correctamente!";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error = "Error al agregar el producto: " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$error = "Por favor, ingrese el nombre del producto.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mx-auto">
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<?php echo $message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($error); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-plus"></i> Agregar Nuevo Producto al Catálogo
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="agregar_producto.php" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="nombre_producto" class="form-label">Nombre del Producto</label>
|
||||
<input type="text" class="form-control" id="nombre_producto" name="nombre_producto" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100"> <i class="fa fa-plus-circle"></i> Guardar Producto</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
248
cobertura.php
248
cobertura.php
@ -1,212 +1,98 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
require_once 'db/config.php';
|
||||
$pageTitle = "Cobertura";
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Fetch all items from the new 'cobertura' table
|
||||
$db = db();
|
||||
$stmt = $db->query("SELECT id, titulo, texto FROM cobertura ORDER BY id ASC");
|
||||
$coberturas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM cobertura ORDER BY id DESC");
|
||||
$coberturas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
echo "<div class='alert alert-danger'>Error al conectar con la base de datos: " . $e->getMessage() . "</div>";
|
||||
die();
|
||||
}
|
||||
|
||||
$cobertura_banner = 'assets/uploads/cobertura_banner.jpg';
|
||||
?>
|
||||
|
||||
<style>
|
||||
@keyframes saved {
|
||||
0% { background-color: #ffffff; }
|
||||
30% { background-color: #d4edda; }
|
||||
100% { background-color: #ffffff; }
|
||||
}
|
||||
.saved-animation {
|
||||
animation: saved 1.5s ease-in-out;
|
||||
}
|
||||
[contenteditable="true"]:focus {
|
||||
outline: 2px solid #007bff;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.action-controls .btn {
|
||||
padding: 0.2rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
</style>
|
||||
<div class="container-fluid mt-4">
|
||||
<h1>Gestión de Cobertura</h1>
|
||||
|
||||
<div class="container-fluid">
|
||||
<h1 class="mt-4">Textos de Cobertura</h1>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo $_SESSION['message']; unset($_SESSION['message']); ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Banner de la Página de Cobertura
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_SESSION['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo $_SESSION['error']; unset($_SESSION['error']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<?php
|
||||
$banner_path = 'assets/uploads/cobertura_banner.jpg';
|
||||
if (file_exists($banner_path)) {
|
||||
echo '<img src="' . $banner_path . '?t=' . time() . '" alt="Banner de Cobertura" class="img-fluid rounded">';
|
||||
} else {
|
||||
echo '<p>No hay imagen de cabecera todavía.</p>';
|
||||
}
|
||||
?>
|
||||
<?php if (file_exists($cobertura_banner)): ?>
|
||||
<p><strong>Banner Actual:</strong></p>
|
||||
<img src="<?php echo $cobertura_banner; ?>?v=<?php echo time(); ?>" alt="Banner Cobertura" class="img-fluid mb-3" style="max-width: 400px;">
|
||||
<?php else: ?>
|
||||
<p class="text-muted">No hay un banner de cobertura actualmente.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="save_cobertura_banner.php" method="post" enctype="multipart/form-data" class="mt-3">
|
||||
<div class="form-group">
|
||||
<label for="cobertura_banner_input">Cambiar/Subir Banner (se recomienda formato JPG, 1200x400px)</label>
|
||||
<input type="file" name="cobertura_banner" id="cobertura_banner_input" class="form-control" accept=".jpg,.jpeg">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-2">Guardar Banner</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
Coberturas Guardadas
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Zonas de Cobertura
|
||||
<a href="add_cobertura.php" class="btn btn-success">Agregar Nueva Zona</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Productos</th>
|
||||
<th>Cobertura</th>
|
||||
<th><!-- Columna para botón de guardar en nuevas filas --></th>
|
||||
<th style="width: 150px;">Imagen</th>
|
||||
<th>Título</th>
|
||||
<th>Descripción</th>
|
||||
<th style="width: 100px;">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($coberturas as $item): ?>
|
||||
<tr data-id="<?php echo $item['id']; ?>">
|
||||
<td contenteditable="true" class="editable-cell" data-field="titulo" style="font-weight: bold;"><?php echo htmlspecialchars($item['titulo']); ?></td>
|
||||
<td contenteditable="true" class="editable-cell" data-field="texto" style="font-weight: bold;"><?php echo htmlspecialchars($item['texto']); ?></td>
|
||||
<td><!-- Celda vacía para alinear con la cabecera --></td>
|
||||
<?php if (empty($coberturas)): ?>
|
||||
<tr>
|
||||
<td colspan="4" class="text-center">No hay zonas de cobertura definidas.</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<?php foreach ($coberturas as $row): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$image_path = 'assets/uploads/cobertura_images/' . $row['imagen'];
|
||||
if (file_exists($image_path) && !empty($row['imagen'])):
|
||||
?>
|
||||
<img src="<?php echo $image_path; ?>?v=<?php echo time();?>" alt="Imagen de cobertura" class="img-fluid">
|
||||
<?php else: ?>
|
||||
<span class="text-muted">Sin imagen</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($row['titulo']); ?></td>
|
||||
<td><?php echo nl2br(htmlspecialchars($row['descripcion'])); ?></td>
|
||||
<td>
|
||||
<a href="delete_cobertura.php?id=<?php echo $row['id']; ?>" class="btn btn-danger btn-sm" onclick="return confirm('¿Estás seguro de que quieres eliminar esta zona de cobertura?');">
|
||||
<i class="fas fa-trash"></i> Eliminar
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($_SESSION['user_role'] !== 'Asesor'): ?>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-primary" id="addRowBtn">Agregar Fila</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tableBody = document.querySelector('.table-bordered tbody');
|
||||
|
||||
// --- INLINE EDITING ---
|
||||
tableBody.addEventListener('blur', function(e) {
|
||||
if (e.target.classList.contains('editable-cell')) {
|
||||
const cell = e.target;
|
||||
const id = cell.closest('tr').dataset.id;
|
||||
if (!id) return; // No guardar celdas de filas nuevas que aún no se han creado en DB
|
||||
|
||||
const field = cell.dataset.field;
|
||||
const value = cell.innerText;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('id', id);
|
||||
formData.append('field', field);
|
||||
formData.append('value', value);
|
||||
|
||||
fetch('save_cobertura.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
if (data.deleted) {
|
||||
// Si la fila fue eliminada en el servidor, la quitamos de la vista
|
||||
cell.closest('tr').remove();
|
||||
} else {
|
||||
cell.classList.add('saved-animation');
|
||||
setTimeout(() => cell.classList.remove('saved-animation'), 1500);
|
||||
}
|
||||
} else {
|
||||
alert('Error al guardar: ' + (data.error || 'Error desconocido'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Ocurrió un error de red.');
|
||||
});
|
||||
}
|
||||
}, true); // Use capturing to get the blur event
|
||||
|
||||
// --- ADD NEW ROW ---
|
||||
document.getElementById('addRowBtn').addEventListener('click', function() {
|
||||
const newRow = document.createElement('tr');
|
||||
newRow.innerHTML = `
|
||||
<td contenteditable="true" class="new-cobertura-titulo" placeholder="Nuevo Producto"></td>
|
||||
<td contenteditable="true" class="new-cobertura-texto" placeholder="Nueva Cobertura"></td>
|
||||
<td>
|
||||
<button class="btn btn-success btn-sm save-new-row">Guardar</button>
|
||||
</td>
|
||||
`;
|
||||
tableBody.appendChild(newRow);
|
||||
newRow.querySelector('.new-cobertura-titulo').focus();
|
||||
});
|
||||
|
||||
// --- SAVE NEW ROW ---
|
||||
tableBody.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('save-new-row')) {
|
||||
const saveButton = e.target;
|
||||
const newRow = saveButton.closest('tr');
|
||||
const titulo = newRow.querySelector('.new-cobertura-titulo').innerText.trim();
|
||||
const texto = newRow.querySelector('.new-cobertura-texto').innerText.trim();
|
||||
|
||||
if (!titulo && !texto) {
|
||||
// Si ambos están vacíos, simplemente quita la fila nueva sin guardar
|
||||
newRow.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!titulo) {
|
||||
alert('Por favor, introduce un título.');
|
||||
return;
|
||||
}
|
||||
|
||||
saveButton.disabled = true;
|
||||
saveButton.innerText = 'Guardando...';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('titulo', titulo);
|
||||
formData.append('texto', texto);
|
||||
|
||||
fetch('add_cobertura.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error al guardar: ' + (data.error || 'Error desconocido'));
|
||||
saveButton.disabled = false;
|
||||
saveButton.innerText = 'Guardar';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Ocurrió un error de red.');
|
||||
saveButton.disabled = false;
|
||||
saveButton.innerText = 'Guardar';
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
require_once 'layout_footer.php';
|
||||
?>
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
|
||||
@ -1,208 +1,52 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
require_once 'db/config.php';
|
||||
$pageTitle = "Cobertura Xpress";
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$pdo = db();
|
||||
$cobertura_xpress_banner = 'assets/uploads/cobertura_xpress_banner.jpg';
|
||||
|
||||
// Fetch all items from the 'cobertura_xpress' table
|
||||
$db = db();
|
||||
$stmt = $db->query("SELECT id, titulo, texto FROM cobertura_xpress ORDER BY id ASC");
|
||||
$coberturas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<style>
|
||||
@keyframes saved {
|
||||
0% { background-color: #ffffff; }
|
||||
30% { background-color: #d4edda; }
|
||||
100% { background-color: #ffffff; }
|
||||
}
|
||||
.saved-animation {
|
||||
animation: saved 1.5s ease-in-out;
|
||||
}
|
||||
[contenteditable="true"]:focus {
|
||||
outline: 2px solid #007bff;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.action-controls .btn {
|
||||
padding: 0.2rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
</style>
|
||||
<div class="container-fluid mt-4">
|
||||
<h1>Gestión de Cobertura Xpress</h1>
|
||||
|
||||
<div class="container-fluid">
|
||||
<h1 class="mt-4">Textos de Cobertura Xpress</h1>
|
||||
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo $_SESSION['message']; unset($_SESSION['message']); ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Banner de la Página de Cobertura Xpress
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_SESSION['error'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo $_SESSION['error']; unset($_SESSION['error']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<?php
|
||||
$banner_path = 'assets/uploads/cobertura_xpress_banner.jpg';
|
||||
if (file_exists($banner_path)) {
|
||||
echo '<img src="' . $banner_path . '?t=' . time() . '" alt="Banner de Cobertura Xpress" class="img-fluid rounded">';
|
||||
} else {
|
||||
echo '<p>No hay imagen de cabecera todavía.</p>';
|
||||
}
|
||||
?>
|
||||
<?php if (file_exists($cobertura_xpress_banner)): ?>
|
||||
<p><strong>Banner Actual:</strong></p>
|
||||
<img src="<?php echo $cobertura_xpress_banner; ?>?v=<?php echo time(); ?>" alt="Banner Cobertura Xpress" class="img-fluid mb-3" style="max-width: 400px;">
|
||||
<?php else: ?>
|
||||
<p class="text-muted">No hay un banner de Cobertura Xpress actualmente.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="save_cobertura_xpress_banner.php" method="post" enctype="multipart/form-data" class="mt-3">
|
||||
<div class="form-group">
|
||||
<label for="cobertura_xpress_banner_input">Cambiar/Subir Banner (se recomienda formato JPG, 1200x400px)</label>
|
||||
<input type="file" name="cobertura_xpress_banner" id="cobertura_xpress_banner_input" class="form-control" accept=".jpg,.jpeg">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-2">Guardar Banner</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
Coberturas Xpress Guardadas
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Zonas de Cobertura Xpress
|
||||
<a href="add_cobertura_xpress.php" class="btn btn-success">Agregar Nueva Zona Xpress</a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ciudad</th>
|
||||
<th>Cobertura</th>
|
||||
<th><!-- Columna para botón de guardar en nuevas filas --></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($coberturas as $item): ?>
|
||||
<tr data-id="<?php echo $item['id']; ?>">
|
||||
<td contenteditable="true" class="editable-cell" data-field="titulo" style="font-weight: bold;"><?php echo htmlspecialchars($item['titulo']); ?></td>
|
||||
<td contenteditable="true" class="editable-cell" data-field="texto" style="font-weight: bold;"><?php echo htmlspecialchars($item['texto']); ?></td>
|
||||
<td><!-- Celda vacía para alinear con la cabecera --></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="text-muted">La configuración para las zonas de cobertura Xpress estará disponible aquí.</p>
|
||||
<!-- Aquí iría la tabla y lógica para mostrar las zonas de Cobertura Xpress -->
|
||||
</div>
|
||||
<?php if ($_SESSION['user_role'] !== 'Asesor'): ?>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-primary" id="addRowBtn">Agregar Fila</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tableBody = document.querySelector('.table-bordered tbody');
|
||||
|
||||
// --- INLINE EDITING ---
|
||||
tableBody.addEventListener('blur', function(e) {
|
||||
if (e.target.classList.contains('editable-cell')) {
|
||||
const cell = e.target;
|
||||
const id = cell.closest('tr').dataset.id;
|
||||
if (!id) return; // No guardar celdas de filas nuevas que aún no se han creado en DB
|
||||
|
||||
const field = cell.dataset.field;
|
||||
const value = cell.innerText;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('id', id);
|
||||
formData.append('field', field);
|
||||
formData.append('value', value);
|
||||
|
||||
fetch('save_cobertura_xpress.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
if (data.deleted) {
|
||||
// Si la fila fue eliminada en el servidor, la quitamos de la vista
|
||||
cell.closest('tr').remove();
|
||||
} else {
|
||||
cell.classList.add('saved-animation');
|
||||
setTimeout(() => cell.classList.remove('saved-animation'), 1500);
|
||||
}
|
||||
} else {
|
||||
alert('Error al guardar: ' + (data.error || 'Error desconocido'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Ocurrió un error de red.');
|
||||
});
|
||||
}
|
||||
}, true); // Use capturing to get the blur event
|
||||
|
||||
// --- ADD NEW ROW ---
|
||||
document.getElementById('addRowBtn').addEventListener('click', function() {
|
||||
const newRow = document.createElement('tr');
|
||||
newRow.innerHTML = `
|
||||
<td contenteditable="true" class="new-cobertura-titulo" placeholder="Nueva Ciudad"></td>
|
||||
<td contenteditable="true" class="new-cobertura-texto" placeholder="Nueva Cobertura"></td>
|
||||
<td>
|
||||
<button class="btn btn-success btn-sm save-new-row">Guardar</button>
|
||||
</td>
|
||||
`;
|
||||
tableBody.appendChild(newRow);
|
||||
newRow.querySelector('.new-cobertura-titulo').focus();
|
||||
});
|
||||
|
||||
// --- SAVE NEW ROW ---
|
||||
tableBody.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('save-new-row')) {
|
||||
const saveButton = e.target;
|
||||
const newRow = saveButton.closest('tr');
|
||||
const titulo = newRow.querySelector('.new-cobertura-titulo').innerText.trim();
|
||||
const texto = newRow.querySelector('.new-cobertura-texto').innerText.trim();
|
||||
|
||||
if (!titulo && !texto) {
|
||||
// Si ambos están vacíos, simplemente quita la fila nueva sin guardar
|
||||
newRow.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!titulo) {
|
||||
alert('Por favor, introduce un título.');
|
||||
return;
|
||||
}
|
||||
|
||||
saveButton.disabled = true;
|
||||
saveButton.innerText = 'Guardando...';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('titulo', titulo);
|
||||
formData.append('texto', texto);
|
||||
|
||||
fetch('add_cobertura_xpress.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error al guardar: ' + (data.error || 'Error desconocido'));
|
||||
saveButton.disabled = false;
|
||||
saveButton.innerText = 'Guardar';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Ocurrió un error de red.');
|
||||
saveButton.disabled = false;
|
||||
saveButton.innerText = 'Guardar';
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
require_once 'layout_footer.php';
|
||||
?>
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
10
db/migrations/050_create_stock_sedes_table.sql
Normal file
10
db/migrations/050_create_stock_sedes_table.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS stock_sedes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
product_id INT NOT NULL,
|
||||
sede_id INT NOT NULL,
|
||||
quantity INT NOT NULL DEFAULT 0,
|
||||
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (sede_id) REFERENCES sedes(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY `product_sede` (`product_id`, `sede_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@ -74,43 +74,49 @@ $navItems = [
|
||||
'text' => 'Agregar Pedido',
|
||||
'roles' => ['Administrador', 'admin', 'Asesor', 'Control Logistico']
|
||||
],
|
||||
'productos' => [
|
||||
'url' => 'productos.php',
|
||||
'icon' => 'fa-box',
|
||||
'text' => 'Gestionar Productos',
|
||||
'roles' => ['Administrador', 'admin']
|
||||
],
|
||||
'panel_inventario' => [
|
||||
'icon' => 'fa-warehouse',
|
||||
'text' => 'Panel de Inventario',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico'],
|
||||
'submenu' => [
|
||||
'dashboard' => [
|
||||
'url' => 'panel_inventario.php?seccion=dashboard',
|
||||
'icon' => 'fa-tachometer-alt',
|
||||
'text' => 'Dashboard',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'entrada' => [
|
||||
'url' => 'panel_inventario.php?seccion=entrada',
|
||||
'icon' => 'fa-arrow-circle-down',
|
||||
'text' => 'Registro de Entrada',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'salida' => [
|
||||
'url' => 'panel_inventario.php?seccion=salida',
|
||||
'icon' => 'fa-arrow-circle-up',
|
||||
'text' => 'Registro de Salida',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'registro_producto' => [
|
||||
'url' => 'panel_inventario.php?seccion=registro_producto',
|
||||
'icon' => 'fa-plus-circle',
|
||||
'text' => 'Registro de Producto',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
'inventario_group' => [
|
||||
'icon' => 'fa-warehouse',
|
||||
'text' => 'Inventario',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico'],
|
||||
'submenu' => [
|
||||
'panel_inventario' => [
|
||||
'url' => 'panel_inventario.php',
|
||||
'icon' => 'fa-warehouse',
|
||||
'text' => 'Inventario General',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'registro_entrada' => [
|
||||
'url' => 'registro_entrada.php',
|
||||
'icon' => 'fa-arrow-circle-down',
|
||||
'text' => 'Registro de Entrada',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'registro_salida' => [
|
||||
'url' => 'registro_salida.php',
|
||||
'icon' => 'fa-arrow-circle-up',
|
||||
'text' => 'Registro de Salida',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'sede' => [
|
||||
'url' => 'sedes.php',
|
||||
'icon' => 'fa-building',
|
||||
'text' => 'Sede',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'resumen_stock' => [
|
||||
'url' => '#',
|
||||
'icon' => 'fa-chart-bar',
|
||||
'text' => 'Resumen de stock',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'agregar_producto' => [
|
||||
'url' => 'agregar_producto.php',
|
||||
'icon' => 'fa-plus',
|
||||
'text' => 'Agregar Producto',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'finanzas_group' => [
|
||||
'icon' => 'fa-dollar-sign',
|
||||
'text' => 'Finanzas',
|
||||
@ -142,12 +148,6 @@ $navItems = [
|
||||
],
|
||||
]
|
||||
],
|
||||
'info_producto' => [
|
||||
'url' => 'info_producto.php',
|
||||
'icon' => 'fa-info-circle',
|
||||
'text' => 'Info Producto',
|
||||
'roles' => ['Administrador', 'admin', 'Control Logistico']
|
||||
],
|
||||
'pedidos_duplicados' => [
|
||||
'url' => 'pedidos_duplicados.php',
|
||||
'icon' => 'fa-copy',
|
||||
@ -165,12 +165,6 @@ $navItems = [
|
||||
'icon' => 'fa-users',
|
||||
'text' => 'Gestionar Usuarios',
|
||||
'roles' => ['Administrador', 'admin']
|
||||
],
|
||||
'configuracion' => [
|
||||
'url' => 'configuracion.php',
|
||||
'icon' => 'fa-cog',
|
||||
'text' => 'Configuración',
|
||||
'roles' => ['Administrador', 'admin']
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@ -6,116 +6,62 @@ if (!isset($_SESSION['user_id'])) {
|
||||
}
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
$pdo = db();
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM products ORDER BY order_position ASC");
|
||||
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} 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.
|
||||
die();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<h1>Panel de Inventario</h1>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs" id="inventoryTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link active" id="general-tab" data-bs-toggle="tab" href="#general" role="tab" aria-controls="general" aria-selected="true">Inventario General</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" id="cobertura-tab" data-bs-toggle="tab" href="#cobertura" role="tab" aria-controls="cobertura" aria-selected="false">Cobertura</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" id="cobertura-xpress-tab" data-bs-toggle="tab" href="#cobertura-xpress" role="tab" aria-controls="cobertura-xpress" aria-selected="false">Cobertura Xpress</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="inventoryTabsContent">
|
||||
<div class="tab-pane fade show active" id="inventario" role="tabpanel" aria-labelledby="inventario-tab">
|
||||
<?php
|
||||
// Obtener productos
|
||||
$stmt = $pdo->query("SELECT * FROM products ORDER BY order_position ASC");
|
||||
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2 class="m-0">Inventario General</h2>
|
||||
<a href="edit_product.php" class="btn btn-primary">Añadir Producto</a>
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nombre</th>
|
||||
<th>SKU</th>
|
||||
<th>Precio</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="thead-dark">
|
||||
<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>
|
||||
<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>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="cobertura" class="tab-pane fade">
|
||||
<?php
|
||||
// Restaurando la pestaña Cobertura
|
||||
$cobertura_banner = 'assets/uploads/cobertura_banner.jpg';
|
||||
if (file_exists($cobertura_banner)) {
|
||||
echo "<img src='{$cobertura_banner}?v=" . time() . "' alt='Banner Cobertura' class='img-fluid mb-3'>";
|
||||
}
|
||||
?>
|
||||
<form action="save_cobertura_banner.php" method="post" enctype="multipart/form-data" class="mb-3">
|
||||
<div class="form-group">
|
||||
<label for="cobertura_banner_input">Cambiar Banner de Cobertura (JPG)</label>
|
||||
<input type="file" name="cobertura_banner" id="cobertura_banner_input" class="form-control" accept=".jpg">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Subir Banner</button>
|
||||
</form>
|
||||
|
||||
<a href="add_cobertura.php" class="btn btn-success mb-3">Agregar Nueva Cobertura</a>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Imagen</th>
|
||||
<th>Título</th>
|
||||
<th>Descripción</th>
|
||||
<th>Acciones</th>
|
||||
<th>ID</th>
|
||||
<th>Nombre</th>
|
||||
<th>SKU</th>
|
||||
<th>Precio</th>
|
||||
<th class="text-center">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$stmt = $pdo->query("SELECT * FROM cobertura ORDER BY id DESC");
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo "<tr>";
|
||||
$image_path = 'assets/uploads/cobertura_images/' . $row['imagen'];
|
||||
if (file_exists($image_path)) {
|
||||
echo "<td><img src='{$image_path}?v=".time()."' alt='Imagen de cobertura' style='width: 100px;'></td>";
|
||||
} else {
|
||||
echo "<td><span class='text-danger'>Imagen no encontrada</span></td>";
|
||||
}
|
||||
echo "<td>" . htmlspecialchars($row['titulo']) . "</td>";
|
||||
echo "<td>" . htmlspecialchars($row['descripcion']) . "</td>";
|
||||
echo "<td>";
|
||||
echo "<a href='delete_cobertura.php?id=" . $row['id'] . "' class='btn btn-danger btn-sm' onclick='return confirm("¿Estás seguro de que quieres eliminar esta cobertura?");'>Eliminar</a>";
|
||||
echo "</td>";
|
||||
echo "</tr>";
|
||||
}
|
||||
?>
|
||||
<?php if (empty($products)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">No hay productos en el inventario. <a href="edit_product.php">Agrega el primero</a>.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<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>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="cobertura-xpress" role="tabpanel" aria-labelledby="cobertura-xpress-tab">
|
||||
<p class="mt-3">Aquí irá la configuración de cobertura xpress.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
require_once 'layout_footer.php';
|
||||
?>
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
121
registro_entrada.php
Normal file
121
registro_entrada.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
$pageTitle = "Agregar Producto al Inventario";
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// Lógica para manejar el envío del formulario
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$product_id = filter_input(INPUT_POST, 'product_id', FILTER_VALIDATE_INT);
|
||||
$sede_id = filter_input(INPUT_POST, 'sede_id', FILTER_VALIDATE_INT);
|
||||
$quantity = filter_input(INPUT_POST, 'quantity', FILTER_VALIDATE_INT);
|
||||
|
||||
if ($product_id && $sede_id && $quantity) {
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8", DB_USER, DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// Verificar si ya existe un registro para este producto en esta sede
|
||||
$stmt = $pdo->prepare("SELECT * FROM stock_sedes WHERE product_id = :product_id AND sede_id = :sede_id");
|
||||
$stmt->execute(['product_id' => $product_id, 'sede_id' => $sede_id]);
|
||||
$existing_stock = $stmt->fetch();
|
||||
|
||||
if ($existing_stock) {
|
||||
// Si existe, actualizar la cantidad
|
||||
$new_quantity = $existing_stock['quantity'] + $quantity;
|
||||
$update_stmt = $pdo->prepare("UPDATE stock_sedes SET quantity = :quantity WHERE id = :id");
|
||||
$update_stmt->execute(['quantity' => $new_quantity, 'id' => $existing_stock['id']]);
|
||||
} else {
|
||||
// Si no existe, insertar un nuevo registro
|
||||
$insert_stmt = $pdo->prepare("INSERT INTO stock_sedes (product_id, sede_id, quantity) VALUES (:product_id, :sede_id, :quantity)");
|
||||
$insert_stmt->execute(['product_id' => $product_id, 'sede_id' => $sede_id, 'quantity' => $quantity]);
|
||||
}
|
||||
|
||||
$message = "¡Inventario actualizado correctamente!";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error = "Error al actualizar el inventario: " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$error = "Por favor, complete todos los campos del formulario.";
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener productos y sedes de la base de datos para los dropdowns
|
||||
$products = [];
|
||||
$sedes = [];
|
||||
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8", DB_USER, DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$products_stmt = $pdo->query("SELECT id, nombre FROM products ORDER BY nombre ASC");
|
||||
$products = $products_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$sedes_stmt = $pdo->query("SELECT id, nombre FROM sedes ORDER BY nombre ASC");
|
||||
$sedes = $sedes_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error = "Error al cargar datos: " . $e->getMessage();
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mx-auto">
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($error); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-plus"></i> Registro de Entrada de Producto
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="registro_entrada.php" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="producto" class="form-label">Producto</label>
|
||||
<select class="form-select" id="producto" name="product_id" required>
|
||||
<option value="">Seleccione un producto</option>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<option value="<?php echo htmlspecialchars($product['id']); ?>">
|
||||
<?php echo htmlspecialchars($product['nombre']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cantidad" class="form-label">Cantidad</label>
|
||||
<input type="number" class="form-control" id="cantidad" name="quantity" min="1" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="sede" class="form-label">Sede de Destino</label>
|
||||
<select class="form-select" id="sede" name="sede_id" required>
|
||||
<option value="">Seleccione una sede</option>
|
||||
<?php foreach ($sedes as $sede): ?>
|
||||
<option value="<?php echo htmlspecialchars($sede['id']); ?>">
|
||||
<?php echo htmlspecialchars($sede['nombre']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100"> <i class="fa fa-plus-circle"></i> Agregar al Inventario</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
123
registro_salida.php
Normal file
123
registro_salida.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
$pageTitle = "Registro de Salida de Producto";
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// Lógica para manejar el envío del formulario
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$product_id = filter_input(INPUT_POST, 'product_id', FILTER_VALIDATE_INT);
|
||||
$sede_id = filter_input(INPUT_POST, 'sede_id', FILTER_VALIDATE_INT);
|
||||
$quantity = filter_input(INPUT_POST, 'quantity', FILTER_VALIDATE_INT);
|
||||
|
||||
if ($product_id && $sede_id && $quantity) {
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8", DB_USER, DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// Verificar si ya existe un registro para este producto en esta sede
|
||||
$stmt = $pdo->prepare("SELECT * FROM stock_sedes WHERE product_id = :product_id AND sede_id = :sede_id");
|
||||
$stmt->execute(['product_id' => $product_id, 'sede_id' => $sede_id]);
|
||||
$existing_stock = $stmt->fetch();
|
||||
|
||||
if ($existing_stock) {
|
||||
// Si existe, actualizar la cantidad
|
||||
$new_quantity = $existing_stock['quantity'] - $quantity;
|
||||
if ($new_quantity < 0) {
|
||||
$error = "No hay suficiente stock para registrar la salida.";
|
||||
} else {
|
||||
$update_stmt = $pdo->prepare("UPDATE stock_sedes SET quantity = :quantity WHERE id = :id");
|
||||
$update_stmt->execute(['quantity' => $new_quantity, 'id' => $existing_stock['id']]);
|
||||
$message = "¡Inventario actualizado correctamente!";
|
||||
}
|
||||
} else {
|
||||
// Si no existe, no se puede dar salida
|
||||
$error = "No hay stock registrado para este producto en la sede seleccionada.";
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error = "Error al actualizar el inventario: " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$error = "Por favor, complete todos los campos del formulario.";
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener productos y sedes de la base de datos para los dropdowns
|
||||
$products = [];
|
||||
$sedes = [];
|
||||
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8", DB_USER, DB_PASS);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$products_stmt = $pdo->query("SELECT id, nombre FROM products ORDER BY nombre ASC");
|
||||
$products = $products_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$sedes_stmt = $pdo->query("SELECT id, nombre FROM sedes ORDER BY nombre ASC");
|
||||
$sedes = $sedes_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$error = "Error al cargar datos: " . $e->getMessage();
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mx-auto">
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($error); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fa fa-minus"></i> Registro de Salida de Producto
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="registro_salida.php" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="producto" class="form-label">Producto</label>
|
||||
<select class="form-select" id="producto" name="product_id" required>
|
||||
<option value="">Seleccione un producto</option>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<option value="<?php echo htmlspecialchars($product['id']); ?>">
|
||||
<?php echo htmlspecialchars($product['nombre']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cantidad" class="form-label">Cantidad a Retirar</label>
|
||||
<input type="number" class="form-control" id="cantidad" name="quantity" min="1" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="sede" class="form-label">Sede de Origen</label>
|
||||
<select class="form-select" id="sede" name="sede_id" required>
|
||||
<option value="">Seleccione una sede</option>
|
||||
<?php foreach ($sedes as $sede): ?>
|
||||
<option value="<?php echo htmlspecialchars($sede['id']); ?>">
|
||||
<?php echo htmlspecialchars($sede['nombre']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100"> <i class="fa fa-minus-circle"></i> Registrar Salida</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once 'layout_footer.php'; ?>
|
||||
111
sedes.php
Normal file
111
sedes.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
require_once 'layout_header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// Handle form submission for adding a new sede
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['nombre_sede'])) {
|
||||
$nombre_sede = trim($_POST['nombre_sede']);
|
||||
|
||||
if (!empty($nombre_sede)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
// Check if sede already exists
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM sedes WHERE nombre = ?");
|
||||
$stmt->execute([$nombre_sede]);
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
$error = "La sede '" . htmlspecialchars($nombre_sede) . "' ya existe.";
|
||||
} else {
|
||||
// Insert new sede
|
||||
$stmt = $pdo->prepare("INSERT INTO sedes (nombre) VALUES (?)");
|
||||
if ($stmt->execute([$nombre_sede])) {
|
||||
$message = "Sede '" . htmlspecialchars($nombre_sede) . "' agregada correctamente.";
|
||||
} else {
|
||||
$error = "Error al agregar la sede.";
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Do not show detailed SQL errors to the user
|
||||
error_log("Database Error: " . $e->getMessage());
|
||||
$error = "Error de base de datos al intentar agregar la sede.";
|
||||
}
|
||||
} else {
|
||||
$error = "El nombre de la sede no puede estar vacío.";
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch all existing sedes
|
||||
$sedes = [];
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT id, nombre FROM sedes ORDER BY nombre ASC");
|
||||
$sedes = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database Error: " . $e->getMessage());
|
||||
$error .= " Error al cargar la lista de sedes.";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 offset-lg-2">
|
||||
|
||||
<h2 class="mb-4 text-center">Gestionar Sedes</h2>
|
||||
<p class="text-center">Aquí puedes agregar nuevas sedes para la gestión de inventario.</p>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success"><?php echo $message; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Add Sede Form -->
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Agregar Nueva Sede</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="sedes.php" method="post">
|
||||
<div class="form-group">
|
||||
<label for="nombre_sede">Nombre de la Sede</label>
|
||||
<input type="text" class="form-control" id="nombre_sede" name="nombre_sede" placeholder="Ej: Almacén Principal" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3">
|
||||
<i class="fas fa-plus-circle"></i> Agregar Sede
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List of Sedes -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Sedes Existentes</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (count($sedes) > 0): ?>
|
||||
<ul class="list-group">
|
||||
<?php foreach ($sedes as $sede): ?>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<?php echo htmlspecialchars($sede['nombre']); ?>
|
||||
<!-- Optional: Add delete/edit buttons here in the future -->
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php else: ?>
|
||||
<p class="text-muted">No hay sedes registradas. ¡Agrega la primera!</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
require_once 'layout_footer.php';
|
||||
?>
|
||||
Loading…
x
Reference in New Issue
Block a user