Autosave: 20260523-234035
This commit is contained in:
parent
7b765bd9d0
commit
f587c9e57c
BIN
assets/uploads/vouchers/6a1225e5ee363-144.png
Normal file
BIN
assets/uploads/vouchers/6a1225e5ee363-144.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 257 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 304 KiB |
BIN
assets/uploads/vouchers/6a122fa11cf0c-7075.png
Normal file
BIN
assets/uploads/vouchers/6a122fa11cf0c-7075.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 364 KiB |
BIN
assets/uploads/vouchers/6a1233751865f-038.png
Normal file
BIN
assets/uploads/vouchers/6a1233751865f-038.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 317 KiB |
17
db/migrations/070_add_pendiente_to_estado_enum.sql
Normal file
17
db/migrations/070_add_pendiente_to_estado_enum.sql
Normal file
@ -0,0 +1,17 @@
|
||||
-- Add PENDIENTE as a valid route status for contraentrega pedidos.
|
||||
ALTER TABLE pedidos MODIFY COLUMN estado ENUM(
|
||||
'ROTULADO 📦',
|
||||
'EN TRANSITO 🚛',
|
||||
'EN DESTINO 🏬',
|
||||
'COMPLETADO ✅',
|
||||
'Gestion',
|
||||
'RUTA_CONTRAENTREGA',
|
||||
'ENTREGA EXITOSA',
|
||||
'RETORNADO',
|
||||
'Duplicados',
|
||||
'NO CONTESTO, DEVOLVER LLAMADA',
|
||||
'CANCELADO',
|
||||
'REPROGRAMADO',
|
||||
'NO CONTESTO, VOLVER A LLAMAR',
|
||||
'PENDIENTE'
|
||||
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 'ROTULADO 📦';
|
||||
3
db/migrations/072_add_ean_to_products.sql
Normal file
3
db/migrations/072_add_ean_to_products.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- Add EAN code column to products for admin-maintained barcode/catalog codes.
|
||||
ALTER TABLE products
|
||||
ADD COLUMN IF NOT EXISTS ean VARCHAR(32) NULL AFTER sku;
|
||||
173
download_ruta_contraentrega.php
Normal file
173
download_ruta_contraentrega.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
use Shuchkin\SimpleXLSXGen;
|
||||
|
||||
function splitProvinciaDistrito(?string $value): array
|
||||
{
|
||||
$value = trim((string)$value);
|
||||
if ($value === '') {
|
||||
return ['', ''];
|
||||
}
|
||||
|
||||
$clean = preg_replace('/\s+/', ' ', $value);
|
||||
$parts = preg_split('/\s*[\/\-,|]\s*/', $clean, 2);
|
||||
|
||||
if (is_array($parts) && count($parts) === 2) {
|
||||
return [trim($parts[0]), trim($parts[1])];
|
||||
}
|
||||
|
||||
return [$clean, ''];
|
||||
}
|
||||
|
||||
function extractProductNames(array $pedido): array
|
||||
{
|
||||
$names = [];
|
||||
$notas = (string)($pedido['notas'] ?? '');
|
||||
|
||||
if (preg_match('/Detalle de productos:\s*(.+)$/mi', $notas, $match)) {
|
||||
$items = explode(',', $match[1]);
|
||||
foreach ($items as $item) {
|
||||
$name = preg_replace('/\s*\(x\d+\)\s*$/i', '', trim($item));
|
||||
if ($name !== '') {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($names) && !empty($pedido['producto'])) {
|
||||
foreach (explode(',', (string)$pedido['producto']) as $item) {
|
||||
$name = trim($item);
|
||||
if ($name !== '') {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($names));
|
||||
}
|
||||
|
||||
function getEansForProducts(PDO $pdo, array $productNames): string
|
||||
{
|
||||
if (empty($productNames)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($productNames), '?'));
|
||||
$stmt = $pdo->prepare("SELECT nombre, ean FROM products WHERE nombre IN ($placeholders)");
|
||||
$stmt->execute($productNames);
|
||||
|
||||
$map = [];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$ean = trim((string)($row['ean'] ?? ''));
|
||||
if ($ean !== '') {
|
||||
$map[$row['nombre']] = $ean;
|
||||
}
|
||||
}
|
||||
|
||||
$eans = [];
|
||||
foreach ($productNames as $name) {
|
||||
if (!empty($map[$name])) {
|
||||
$eans[] = $map[$name];
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' | ', array_values(array_unique($eans)));
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$user_role = $_SESSION['user_role'] ?? 'Asesor';
|
||||
|
||||
$selected_month = $_GET['mes'] ?? '';
|
||||
$selected_year = $_GET['año'] ?? '';
|
||||
$search_query = trim($_GET['q'] ?? '');
|
||||
|
||||
$sql = "SELECT p.* FROM pedidos p WHERE p.estado IN ('RUTA_CONTRAENTREGA', 'PENDIENTE', 'NO CONTESTO, VOLVER A LLAMAR', 'NO CONTESTO, DEVOLVER LLAMADA', 'CANCELADO', 'REPROGRAMADO', 'ENTREGA EXITOSA', 'RETORNADO')";
|
||||
$params = [];
|
||||
|
||||
if ($user_role === 'Asesor') {
|
||||
$sql .= " AND p.asesor_id = ?";
|
||||
$params[] = $user_id;
|
||||
}
|
||||
|
||||
if ($search_query !== '') {
|
||||
$sql .= " AND (p.nombre_completo LIKE ? OR p.dni_cliente LIKE ? OR p.celular LIKE ?)";
|
||||
$params[] = "%$search_query%";
|
||||
$params[] = "%$search_query%";
|
||||
$params[] = "%$search_query%";
|
||||
}
|
||||
|
||||
if ($selected_month !== '') {
|
||||
$sql .= " AND MONTH(p.created_at) = ?";
|
||||
$params[] = $selected_month;
|
||||
}
|
||||
|
||||
if ($selected_year !== '') {
|
||||
$sql .= " AND YEAR(p.created_at) = ?";
|
||||
$params[] = $selected_year;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY p.created_at DESC";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$pedidos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$rows = [];
|
||||
$rows[] = [
|
||||
'Nombre y apellido',
|
||||
'Celular',
|
||||
'Pais',
|
||||
'Departamento',
|
||||
'Provincia',
|
||||
'Distrito',
|
||||
'Direccion',
|
||||
'Referencia',
|
||||
'Coordenadas',
|
||||
'Codigo EAN',
|
||||
'Cantidad',
|
||||
'Precio',
|
||||
'Total'
|
||||
];
|
||||
|
||||
foreach ($pedidos as $pedido) {
|
||||
[$provincia, $distrito] = splitProvinciaDistrito($pedido['codigo_rastreo'] ?? '');
|
||||
$cantidad = (int)($pedido['cantidad'] ?? 0);
|
||||
$total = (float)($pedido['monto_total'] ?? 0);
|
||||
$precio = $cantidad > 0 ? round($total / $cantidad, 2) : 0;
|
||||
$ean = getEansForProducts($pdo, extractProductNames($pedido));
|
||||
|
||||
$rows[] = [
|
||||
(string)($pedido['nombre_completo'] ?? ''),
|
||||
(string)($pedido['celular'] ?? ''),
|
||||
'Perú',
|
||||
(string)($pedido['sede_envio'] ?? ''),
|
||||
$provincia,
|
||||
$distrito,
|
||||
(string)($pedido['direccion_exacta'] ?? ''),
|
||||
(string)($pedido['referencia_domicilio'] ?? ''),
|
||||
(string)($pedido['coordenadas'] ?? ''),
|
||||
(string)$ean,
|
||||
$cantidad,
|
||||
$precio,
|
||||
$total
|
||||
];
|
||||
}
|
||||
|
||||
$filename = 'ruta_contraentrega_' . date('Y-m-d_H-i') . '.xlsx';
|
||||
SimpleXLSXGen::fromArray($rows, 'Ruta Contraentrega')->downloadAs($filename);
|
||||
exit;
|
||||
} catch (Throwable $e) {
|
||||
error_log('Error exportando Ruta Contraentrega: ' . $e->getMessage());
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
echo 'Error al generar el Excel de Ruta Contraentrega.';
|
||||
}
|
||||
@ -94,6 +94,11 @@ include 'layout_header.php';
|
||||
<input type="text" class="form-control" id="sku" name="sku" value="<?php echo htmlspecialchars($product['sku'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ean">EAN</label>
|
||||
<input type="text" class="form-control" id="ean" name="ean" maxlength="32" inputmode="numeric" value="<?php echo htmlspecialchars($product['ean'] ?? ''); ?>" placeholder="Código EAN del producto">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="costo">Costo</label>
|
||||
<input type="number" step="0.01" class="form-control" id="costo" name="costo" value="<?php echo htmlspecialchars($product['costo'] ?? '0.00'); ?>">
|
||||
|
||||
72
includes/contraentrega_cobertura.php
Normal file
72
includes/contraentrega_cobertura.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('contraentregaProvinciasPorDepartamento')) {
|
||||
function contraentregaProvinciasPorDepartamento(): array
|
||||
{
|
||||
return [
|
||||
'Ancash' => ['Carhuaz', 'Huaraz', 'Huaylas', 'Santa', 'Yungay'],
|
||||
'Apurimac' => ['Abancay'],
|
||||
'Arequipa' => ['Arequipa'],
|
||||
'Ayacucho' => ['Huamanga'],
|
||||
'Cajamarca' => ['Cajamarca'],
|
||||
'Cusco' => ['Cusco'],
|
||||
'Huanuco' => ['Huanuco'],
|
||||
'Ica' => ['Ica'],
|
||||
'Junin' => ['Chupaca', 'Huancayo'],
|
||||
'La Libertad' => ['Trujillo'],
|
||||
'Lambayeque' => ['Ferreñafe', 'Chiclayo', 'Lambayeque'],
|
||||
'Lima' => ['Callao', 'Lima'],
|
||||
'Loreto' => ['Maynas'],
|
||||
'Madre de Dios' => ['Tambopata'],
|
||||
'Moquegua' => ['Ilo', 'Mariscal Nieto'],
|
||||
'Piura' => ['Paita', 'Piura', 'Sullana', 'Talara'],
|
||||
'Puno' => ['Puno', 'San Roman'],
|
||||
'San Martin' => ['Lamas', 'San Martin'],
|
||||
'Tacna' => ['Tacna'],
|
||||
'Ucayali' => ['Coronel Portillo'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('contraentregaDistritosPorProvincia')) {
|
||||
function contraentregaDistritosPorProvincia(): array
|
||||
{
|
||||
return [
|
||||
'Abancay' => ['Abancay'],
|
||||
'Arequipa' => ['Alto Selva Alegre', 'Arequipa', 'Cayma', 'Cerro Colorado', 'Characato', 'Jacobo Hunter', 'Jose Luis Bustamante y Rivero', 'Mariano Melgar', 'Miraflores', 'Paucarpata', 'Sabandia', 'Sachaca', 'Socabaya', 'Tiabaya', 'Yanahuara'],
|
||||
'Cajamarca' => ['Los Baqos del Inca', 'Cajamarca'],
|
||||
'Callao' => ['Bellavista', 'Callao', 'Carmen de la Legua Reynoso', 'La Perla', 'La Punta', 'Ventanilla'],
|
||||
'Carhuaz' => ['Carhuaz'],
|
||||
'Chupaca' => ['Chongos Bajo', 'Chupaca', 'Huamancaca Chico', 'Tres de Diciembre'],
|
||||
'Cusco' => ['Cusco', 'San Jeronimo', 'San Sebastian', 'Santiago', 'Saylla', 'Wanchaq'],
|
||||
'Huamanga' => ['Ayacucho', 'Jesús Nazareno', 'San Juan Bautista'],
|
||||
'Huancayo' => ['Chilca', 'El Tambo', 'Hualhuas', 'Huancan', 'Huancayo', 'Huayucachi', 'Pariahuanca', 'Pilcomayo', 'Pucara', 'Quilcas', 'San Agustin', 'San Jeronimo de Tunan', 'Sapallanga', 'Sicaya', 'Viques'],
|
||||
'Huanuco' => ['Amarilis', 'Huanuco', 'Pillcomarca'],
|
||||
'Huaraz' => ['Huaraz', 'Independencia'],
|
||||
'Huaylas' => ['Caraz', 'Huaylas'],
|
||||
'Ilo' => ['El Algarrobal', 'Ilo', 'Pacocha'],
|
||||
'Lima' => ['Ancon', 'Ate', 'Barranco', 'Breña', 'Carabayllo', 'Cercado de Lima', 'Chaclacayo', 'Chorrillos', 'Cieneguilla', 'Comas', 'El Agustino', 'Independencia', 'Jesus Maria', 'La Molina', 'La Victoria', 'Lince', 'Los Olivos', 'Lurigancho - Chosica', 'Lurin', 'Magdalena del Mar', 'Miraflores', 'Pachacamac', 'Pueblo Libre', 'Puente Piedra', 'Punta Hermosa', 'Punta Negra', 'Rimac', 'San Borja', 'San Isidro', 'San Juan de Lurigancho', 'San Juan de Miraflores', 'San Luis', 'San Martin de Porres', 'San Miguel', 'Santa Anita', 'Santa Maria del Mar', 'Santa Rosa', 'Santiago de Surco', 'Surquillo', 'Villa El Salvador', 'Villa Maria del Triunfo'],
|
||||
'Mariscal Nieto' => ['Carumas', 'Cuchumbaya', 'Moquegua', 'Samegua', 'San Cristobal', 'Torata'],
|
||||
'Paita' => ['Amotape', 'Arenal', 'Colan', 'La Huaca', 'Paita', 'Tamarindo', 'Vichayal'],
|
||||
'Piura' => ['26 de Octubre', 'Castilla', 'Catacaos', 'Piura'],
|
||||
'Santa' => ['Chimbote', 'Coishco', 'Nuevo Chimbote'],
|
||||
'Sullana' => ['Sullana'],
|
||||
'Talara' => ['Pariñas'],
|
||||
'Trujillo' => ['El Porvenir', 'Florencia de Mora', 'Huanchaco', 'La Esperanza', 'Laredo', 'Moche', 'Salaverry', 'Trujillo', 'Victor Larco Herrera'],
|
||||
'Yungay' => ['Yungay'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('splitProvinciaDistritoContraentrega')) {
|
||||
function splitProvinciaDistritoContraentrega(?string $value): array
|
||||
{
|
||||
$value = trim((string)$value);
|
||||
if ($value === '') {
|
||||
return ['', ''];
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s*(?:\/|-|,|\|)\s*/', $value, 2);
|
||||
return [trim($parts[0] ?? ''), trim($parts[1] ?? '')];
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@ try {
|
||||
$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, sku FROM products ORDER BY nombre");
|
||||
$products_stmt = $pdo->query("SELECT id, nombre, sku, ean FROM products ORDER BY nombre");
|
||||
$products = $products_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$stock_stmt = $pdo->query("SELECT product_id AS producto_id, sede_id, quantity FROM stock_sedes");
|
||||
@ -38,6 +38,7 @@ try {
|
||||
$inventario[$product['id']] = [
|
||||
'nombre' => $product['nombre'],
|
||||
'sku' => $product['sku'],
|
||||
'ean' => $product['ean'] ?? '',
|
||||
'total' => 0,
|
||||
'sedes' => array_fill_keys(array_column($sedes, 'id'), 0)
|
||||
];
|
||||
@ -146,6 +147,29 @@ try {
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
<style>
|
||||
.editable-ean {
|
||||
min-width: 140px;
|
||||
cursor: pointer;
|
||||
background: #fffdf5;
|
||||
}
|
||||
.editable-ean:hover {
|
||||
background: #fff3cd;
|
||||
box-shadow: inset 0 0 0 1px #f0c36d;
|
||||
}
|
||||
.ean-input {
|
||||
width: 100%;
|
||||
min-width: 130px;
|
||||
border: 1px solid #f0c36d;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.ean-saving {
|
||||
opacity: .65;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1>Dashboard de Inventario</h1>
|
||||
@ -211,6 +235,7 @@ try {
|
||||
<tr>
|
||||
<th>Producto</th>
|
||||
<th>SKU</th>
|
||||
<th>EAN</th>
|
||||
<th class="text-center">Stock Total</th>
|
||||
<?php foreach ($sedes as $sede): ?>
|
||||
<th class="text-center"><?php echo htmlspecialchars($sede['nombre']); ?></th>
|
||||
@ -219,12 +244,13 @@ try {
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($inventario)): ?>
|
||||
<tr><td colspan="<?php echo count($sedes) + 3; ?>" class="text-center">No hay productos.</td></tr>
|
||||
<tr><td colspan="<?php echo count($sedes) + 4; ?>" class="text-center">No hay productos.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($inventario as $product_id => $datos_producto): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($datos_producto['nombre']); ?></td>
|
||||
<td><?php echo htmlspecialchars($datos_producto['sku']); ?></td>
|
||||
<td><?php echo htmlspecialchars($datos_producto['sku'] ?? ''); ?></td>
|
||||
<td class="editable-ean" data-product-id="<?php echo (int)$product_id; ?>" title="Doble clic para editar EAN"><?php echo htmlspecialchars($datos_producto['ean'] ?? ''); ?></td>
|
||||
<td class="text-center fw-bold"><?php echo $datos_producto['total']; ?></td>
|
||||
<?php foreach ($datos_producto['sedes'] as $sede_id => $cantidad): ?>
|
||||
<td class="text-center">
|
||||
@ -386,6 +412,62 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
$(document).on('dblclick', '.editable-ean', function () {
|
||||
const cell = $(this);
|
||||
if (cell.find('input').length) return;
|
||||
|
||||
const originalValue = cell.text().trim();
|
||||
const input = $('<input type="text" class="ean-input" maxlength="32" inputmode="numeric">').val(originalValue);
|
||||
cell.empty().append(input);
|
||||
input.trigger('focus').trigger('select');
|
||||
|
||||
function finish(save) {
|
||||
const newValue = input.val().trim();
|
||||
if (!save || newValue === originalValue) {
|
||||
cell.text(originalValue);
|
||||
return;
|
||||
}
|
||||
|
||||
cell.addClass('ean-saving');
|
||||
$.ajax({
|
||||
url: 'update_product_ean.php',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
product_id: cell.data('product-id'),
|
||||
ean: newValue
|
||||
}
|
||||
}).done(function (response) {
|
||||
if (response && response.success) {
|
||||
cell.text(response.ean || '');
|
||||
} else {
|
||||
alert('Error: ' + ((response && response.message) ? response.message : 'No se pudo guardar el EAN.'));
|
||||
cell.text(originalValue);
|
||||
}
|
||||
}).fail(function () {
|
||||
alert('Error: No se pudo conectar para guardar el EAN.');
|
||||
cell.text(originalValue);
|
||||
}).always(function () {
|
||||
cell.removeClass('ean-saving');
|
||||
});
|
||||
}
|
||||
|
||||
input.on('keydown', function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
finish(true);
|
||||
}
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
finish(false);
|
||||
}
|
||||
});
|
||||
input.on('blur', function () {
|
||||
finish(true);
|
||||
});
|
||||
});
|
||||
|
||||
$('.ver-codigos').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id'])) {
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
require_once 'includes/contraentrega_cobertura.php';
|
||||
$pdo = db();
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
@ -30,6 +31,11 @@ $pedido = [
|
||||
'asesor_id' => $user_id, // Default to current user
|
||||
'notas' => '',
|
||||
];
|
||||
|
||||
$provinciasPorDepartamentoContraentrega = contraentregaProvinciasPorDepartamento();
|
||||
$distritosPorProvinciaContraentrega = contraentregaDistritosPorProvincia();
|
||||
$departamentosContraentrega = array_keys($provinciasPorDepartamentoContraentrega);
|
||||
|
||||
$page_title = 'Agregar Pedido Contraentrega';
|
||||
|
||||
if (isset($_GET['id'])) {
|
||||
@ -101,6 +107,9 @@ if (empty($display_products)) {
|
||||
$display_products[] = ['nombre' => '', 'cantidad' => 1];
|
||||
}
|
||||
|
||||
[$provinciaContraentrega, $distritoContraentrega] = splitProvinciaDistritoContraentrega($pedido['codigo_rastreo'] ?? '');
|
||||
$departamentoSeleccionado = trim((string)($pedido['sede_envio'] ?? ''));
|
||||
|
||||
?>
|
||||
<?php
|
||||
$pageTitle = 'Agregar Pedidos Contraentrega';
|
||||
@ -166,17 +175,45 @@ include 'layout_header.php';
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="sede_envio" class="form-label">Ciudad</label>
|
||||
<input type="text" class="form-control" id="sede_envio" name="sede_envio" value="<?php echo htmlspecialchars($pedido['sede_envio']); ?>" required>
|
||||
<label for="sede_envio" class="form-label">Departamento</label>
|
||||
<select class="form-select" id="sede_envio" name="sede_envio" required>
|
||||
<option value="">Seleccione departamento</option>
|
||||
<?php foreach ($departamentosContraentrega as $departamento): ?>
|
||||
<option value="<?php echo htmlspecialchars($departamento); ?>" <?php echo ($departamentoSeleccionado === $departamento) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($departamento); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="codigo_rastreo" class="form-label">Provincia/Distrito</label>
|
||||
<input type="text" class="form-control" id="codigo_rastreo" name="codigo_rastreo" value="<?php echo htmlspecialchars($pedido['codigo_rastreo']); ?>">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="provincia" class="form-label">Provincia</label>
|
||||
<select class="form-select" id="provincia" name="provincia" required>
|
||||
<option value="">Seleccione provincia</option>
|
||||
<?php foreach (($provinciasPorDepartamentoContraentrega[$departamentoSeleccionado] ?? []) as $provinciaOpcion): ?>
|
||||
<option value="<?php echo htmlspecialchars($provinciaOpcion); ?>" <?php echo ($provinciaContraentrega === $provinciaOpcion) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($provinciaOpcion); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
<?php if ($provinciaContraentrega !== '' && !in_array($provinciaContraentrega, $provinciasPorDepartamentoContraentrega[$departamentoSeleccionado] ?? [], true)): ?>
|
||||
<option value="<?php echo htmlspecialchars($provinciaContraentrega); ?>" selected>
|
||||
<?php echo htmlspecialchars($provinciaContraentrega); ?>
|
||||
</option>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="distrito_select" class="form-label">Distrito</label>
|
||||
<select class="form-select" id="distrito_select">
|
||||
<option value="">Seleccione primero provincia</option>
|
||||
</select>
|
||||
<input type="text" class="form-control mt-2 d-none" id="distrito_manual" placeholder="Escriba el distrito si aún no está en cobertura">
|
||||
<input type="hidden" id="distrito" name="distrito" value="<?php echo htmlspecialchars($distritoContraentrega); ?>" required>
|
||||
<div class="form-text">Si una provincia aún no tiene cobertura cargada, podrás escribir el distrito manualmente.</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="direccion_exacta" class="form-label">Direccion exacta</label>
|
||||
<input type="text" class="form-control" id="direccion_exacta" name="direccion_exacta" value="<?php echo htmlspecialchars($pedido['direccion_exacta'] ?? ''); ?>" required>
|
||||
</div>
|
||||
@ -306,6 +343,120 @@ include 'layout_header.php';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const provinciasPorDepartamento = <?php echo json_encode($provinciasPorDepartamentoContraentrega, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
const distritosPorProvincia = <?php echo json_encode($distritosPorProvinciaContraentrega, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
const departamentoSelect = document.getElementById('sede_envio');
|
||||
const provinciaSelect = document.getElementById('provincia');
|
||||
const distritoSelect = document.getElementById('distrito_select');
|
||||
const distritoManualInput = document.getElementById('distrito_manual');
|
||||
const distritoHiddenInput = document.getElementById('distrito');
|
||||
const provinciaSeleccionada = <?php echo json_encode($provinciaContraentrega, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
const distritoSeleccionado = <?php echo json_encode($distritoContraentrega, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
|
||||
function syncDistrito(value) {
|
||||
distritoHiddenInput.value = value || '';
|
||||
}
|
||||
|
||||
function renderDistritos(useInitialSelection = false) {
|
||||
const provincia = provinciaSelect.value;
|
||||
const distritos = distritosPorProvincia[provincia] || [];
|
||||
const targetValue = useInitialSelection ? distritoSeleccionado : '';
|
||||
|
||||
distritoSelect.innerHTML = '';
|
||||
|
||||
if (distritos.length > 0) {
|
||||
const emptyOption = document.createElement('option');
|
||||
emptyOption.value = '';
|
||||
emptyOption.textContent = 'Seleccione distrito';
|
||||
distritoSelect.appendChild(emptyOption);
|
||||
|
||||
distritos.forEach(function(distrito) {
|
||||
const option = document.createElement('option');
|
||||
option.value = distrito;
|
||||
option.textContent = distrito;
|
||||
if (distrito === targetValue) {
|
||||
option.selected = true;
|
||||
}
|
||||
distritoSelect.appendChild(option);
|
||||
});
|
||||
|
||||
if (targetValue && !distritos.includes(targetValue)) {
|
||||
const legacyOption = document.createElement('option');
|
||||
legacyOption.value = targetValue;
|
||||
legacyOption.textContent = targetValue;
|
||||
legacyOption.selected = true;
|
||||
distritoSelect.appendChild(legacyOption);
|
||||
}
|
||||
|
||||
distritoSelect.disabled = false;
|
||||
distritoSelect.classList.remove('d-none');
|
||||
distritoManualInput.classList.add('d-none');
|
||||
distritoManualInput.value = '';
|
||||
syncDistrito(distritoSelect.value);
|
||||
} else {
|
||||
distritoSelect.disabled = true;
|
||||
distritoSelect.classList.add('d-none');
|
||||
distritoManualInput.classList.remove('d-none');
|
||||
distritoManualInput.value = targetValue;
|
||||
syncDistrito(distritoManualInput.value);
|
||||
}
|
||||
}
|
||||
|
||||
function renderProvincias(useInitialSelection = false) {
|
||||
const departamento = departamentoSelect.value;
|
||||
const provincias = provinciasPorDepartamento[departamento] || [];
|
||||
const targetValue = useInitialSelection ? provinciaSeleccionada : '';
|
||||
|
||||
provinciaSelect.innerHTML = '';
|
||||
const emptyOption = document.createElement('option');
|
||||
emptyOption.value = '';
|
||||
emptyOption.textContent = provincias.length ? 'Seleccione provincia' : 'Seleccione primero departamento';
|
||||
provinciaSelect.appendChild(emptyOption);
|
||||
|
||||
provincias.forEach(function(provincia) {
|
||||
const option = document.createElement('option');
|
||||
option.value = provincia;
|
||||
option.textContent = provincia;
|
||||
if (provincia === targetValue) {
|
||||
option.selected = true;
|
||||
}
|
||||
provinciaSelect.appendChild(option);
|
||||
});
|
||||
|
||||
if (targetValue && !provincias.includes(targetValue)) {
|
||||
const legacyOption = document.createElement('option');
|
||||
legacyOption.value = targetValue;
|
||||
legacyOption.textContent = targetValue;
|
||||
legacyOption.selected = true;
|
||||
provinciaSelect.appendChild(legacyOption);
|
||||
}
|
||||
|
||||
provinciaSelect.disabled = provincias.length === 0;
|
||||
renderDistritos(useInitialSelection);
|
||||
}
|
||||
|
||||
departamentoSelect.addEventListener('change', function() {
|
||||
renderProvincias(false);
|
||||
});
|
||||
|
||||
provinciaSelect.addEventListener('change', function() {
|
||||
renderDistritos(false);
|
||||
});
|
||||
|
||||
distritoSelect.addEventListener('change', function() {
|
||||
syncDistrito(distritoSelect.value);
|
||||
});
|
||||
|
||||
distritoManualInput.addEventListener('input', function() {
|
||||
syncDistrito(distritoManualInput.value);
|
||||
});
|
||||
|
||||
renderProvincias(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const numeroOperacionInput = document.getElementById('numero_operacion');
|
||||
|
||||
@ -54,6 +54,7 @@ $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<th>Código de Barras</th>
|
||||
<th>Nombre</th>
|
||||
<th>SKU</th>
|
||||
<th>EAN</th>
|
||||
<th>Costo</th>
|
||||
<th>Precio Venta</th>
|
||||
<th>Unidades Vendidas</th>
|
||||
@ -76,7 +77,8 @@ $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($product['nombre']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['sku']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['sku'] ?? ''); ?></td>
|
||||
<td class="editable-ean" data-product-id="<?php echo (int)$product['id']; ?>" title="Doble clic para editar EAN"><?php echo htmlspecialchars($product['ean'] ?? ''); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['costo']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['precio_venta']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['unidades_vendidas']); ?></td>
|
||||
@ -133,4 +135,84 @@ $(function () {
|
||||
"autoWidth": false,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
<style>
|
||||
.editable-ean {
|
||||
min-width: 140px;
|
||||
cursor: pointer;
|
||||
background: #fffdf5;
|
||||
}
|
||||
.editable-ean:hover {
|
||||
background: #fff3cd;
|
||||
box-shadow: inset 0 0 0 1px #f0c36d;
|
||||
}
|
||||
.ean-input {
|
||||
width: 100%;
|
||||
min-width: 130px;
|
||||
border: 1px solid #f0c36d;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.ean-saving {
|
||||
opacity: .65;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
$(document).on('dblclick', '.editable-ean', function () {
|
||||
const cell = $(this);
|
||||
if (cell.find('input').length) return;
|
||||
|
||||
const originalValue = cell.text().trim();
|
||||
const input = $('<input type="text" class="ean-input" maxlength="32" inputmode="numeric">').val(originalValue);
|
||||
cell.empty().append(input);
|
||||
input.trigger('focus').trigger('select');
|
||||
|
||||
function finish(save) {
|
||||
const newValue = input.val().trim();
|
||||
if (!save || newValue === originalValue) {
|
||||
cell.text(originalValue);
|
||||
return;
|
||||
}
|
||||
|
||||
cell.addClass('ean-saving');
|
||||
$.ajax({
|
||||
url: 'update_product_ean.php',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
product_id: cell.data('product-id'),
|
||||
ean: newValue
|
||||
}
|
||||
}).done(function (response) {
|
||||
if (response && response.success) {
|
||||
cell.text(response.ean || '');
|
||||
} else {
|
||||
alert('Error: ' + ((response && response.message) ? response.message : 'No se pudo guardar el EAN.'));
|
||||
cell.text(originalValue);
|
||||
}
|
||||
}).fail(function () {
|
||||
alert('Error: No se pudo conectar para guardar el EAN.');
|
||||
cell.text(originalValue);
|
||||
}).always(function () {
|
||||
cell.removeClass('ean-saving');
|
||||
});
|
||||
}
|
||||
|
||||
input.on('keydown', function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
finish(true);
|
||||
}
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
finish(false);
|
||||
}
|
||||
});
|
||||
input.on('blur', function () {
|
||||
finish(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -145,6 +145,22 @@ $months = [
|
||||
7 => 'Julio', 8 => 'Agosto', 9 => 'Septiembre', 10 => 'Octubre', 11 => 'Noviembre', 12 => 'Diciembre'
|
||||
];
|
||||
|
||||
function splitProvinciaDistrito($value) {
|
||||
$value = trim((string)($value ?? ''));
|
||||
if ($value === '') {
|
||||
return ['N/A', 'N/A'];
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s*(?:\/|\||,|-)\s*/', $value, 2);
|
||||
$provincia = trim($parts[0] ?? '');
|
||||
$distrito = trim($parts[1] ?? '');
|
||||
|
||||
return [
|
||||
$provincia !== '' ? $provincia : 'N/A',
|
||||
$distrito !== '' ? $distrito : 'N/A',
|
||||
];
|
||||
}
|
||||
|
||||
?>
|
||||
<?php
|
||||
$pageTitle = "Ruta Contraentrega";
|
||||
@ -164,7 +180,7 @@ include 'layout_header.php';
|
||||
<style>
|
||||
/* Ajustes puntuales para Ruta Contraentrega: opciones largas sin invadir columnas vecinas */
|
||||
#pedidos-table {
|
||||
min-width: 1750px;
|
||||
min-width: 1850px;
|
||||
}
|
||||
#pedidos-table th:nth-child(3),
|
||||
#pedidos-table td:nth-child(3) {
|
||||
@ -224,6 +240,19 @@ include 'layout_header.php';
|
||||
<div class="col-auto mt-4">
|
||||
<button type="submit" class="btn btn-info">Filtrar</button>
|
||||
<a href="ruta_contraentrega.php" class="btn btn-secondary">Limpiar</a>
|
||||
<?php
|
||||
$excelParams = array_filter([
|
||||
'q' => $search_query,
|
||||
'mes' => $selected_month,
|
||||
'año' => $selected_year,
|
||||
], static function ($value) {
|
||||
return $value !== '' && $value !== null;
|
||||
});
|
||||
$excelUrl = 'download_ruta_contraentrega.php' . (!empty($excelParams) ? '?' . http_build_query($excelParams) : '');
|
||||
?>
|
||||
<a href="<?php echo htmlspecialchars($excelUrl); ?>" class="btn btn-success">
|
||||
<i class="fas fa-file-excel me-1"></i> Descargar Excel
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -244,8 +273,9 @@ include 'layout_header.php';
|
||||
<th style="width: 120px;">Celular</th>
|
||||
<th style="width: 250px;">Dirección</th>
|
||||
<th style="width: 200px;">Referencia</th>
|
||||
<th style="width: 120px;">Ciudad</th>
|
||||
<th style="width: 150px;">Provincia/Distrito</th>
|
||||
<th style="width: 140px;">Departamento</th>
|
||||
<th style="width: 140px;">Provincia</th>
|
||||
<th style="width: 140px;">Distrito</th>
|
||||
<th style="width: 150px;">Coordenadas</th>
|
||||
<th style="width: 200px;">Producto</th>
|
||||
<th style="width: 80px;">Cant.</th>
|
||||
@ -313,8 +343,10 @@ include 'layout_header.php';
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($pedido['direccion_exacta'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($pedido['referencia_domicilio'] ?? 'N/A'); ?></td>
|
||||
<?php [$provinciaPedido, $distritoPedido] = splitProvinciaDistrito($pedido['codigo_rastreo'] ?? ''); ?>
|
||||
<td><?php echo htmlspecialchars($pedido['sede_envio'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($pedido['codigo_rastreo'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($provinciaPedido); ?></td>
|
||||
<td><?php echo htmlspecialchars($distritoPedido); ?></td>
|
||||
<td><?php echo htmlspecialchars($pedido['coordenadas'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($pedido['producto']); ?></td>
|
||||
<td><?php echo htmlspecialchars($pedido['cantidad']); ?></td>
|
||||
|
||||
@ -10,6 +10,7 @@ if (!isset($_SESSION['user_id'])) {
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
require_once __DIR__ . '/includes/contraentrega_cobertura.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$pdo = db();
|
||||
@ -20,8 +21,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$nombre_completo = trim($_POST['nombre_completo'] ?? '');
|
||||
$celular = trim($_POST['celular'] ?? '');
|
||||
$agencia = trim($_POST['agencia'] ?? 'CONTRAENTREGA');
|
||||
$provinciasPorDepartamentoContraentrega = contraentregaProvinciasPorDepartamento();
|
||||
$distritosPorProvinciaContraentrega = contraentregaDistritosPorProvincia();
|
||||
$departamentosContraentrega = array_keys($provinciasPorDepartamentoContraentrega);
|
||||
$sede_envio = trim($_POST['sede_envio'] ?? '');
|
||||
$provincia = trim($_POST['provincia'] ?? '');
|
||||
$distrito = trim($_POST['distrito'] ?? '');
|
||||
$codigo_rastreo = trim($_POST['codigo_rastreo'] ?? '');
|
||||
if ($provincia !== '' || $distrito !== '') {
|
||||
$codigo_rastreo = trim($provincia . ' / ' . $distrito, ' /');
|
||||
}
|
||||
$codigo_tracking = trim($_POST['codigo_tracking'] ?? '');
|
||||
$direccion_exacta = trim($_POST['direccion_exacta'] ?? '');
|
||||
$referencia_domicilio = trim($_POST['referencia_domicilio'] ?? '');
|
||||
@ -76,9 +85,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!empty($productos_detalle)) {
|
||||
$notas .= "\n\n" . $notas_adicionales;
|
||||
}
|
||||
|
||||
if (!in_array($sede_envio, $departamentosContraentrega, true)) {
|
||||
$error_message = urlencode('Seleccione un departamento válido para el pedido contra entrega.');
|
||||
$id_param = $id ? '&id=' . $id : '';
|
||||
header('Location: pedidos_contraentrega.php?error=' . $error_message . $id_param);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($provincia !== '' && !in_array($provincia, $provinciasPorDepartamentoContraentrega[$sede_envio] ?? [], true)) {
|
||||
$error_message = urlencode('Seleccione una provincia válida para el departamento elegido.');
|
||||
$id_param = $id ? '&id=' . $id : '';
|
||||
header('Location: pedidos_contraentrega.php?error=' . $error_message . $id_param);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($distrito !== '' && isset($distritosPorProvinciaContraentrega[$provincia]) && !in_array($distrito, $distritosPorProvinciaContraentrega[$provincia], true)) {
|
||||
$error_message = urlencode('Seleccione un distrito válido para la provincia elegida.');
|
||||
$id_param = $id ? '&id=' . $id : '';
|
||||
header('Location: pedidos_contraentrega.php?error=' . $error_message . $id_param);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($nombre_completo) || empty($celular) || empty($sede_envio) || empty($producto) || $cantidad === false || $monto_total === false || empty($coordenadas)) {
|
||||
$error_message = urlencode('Por favor, complete todos los campos obligatorios, incluyendo las coordenadas.');
|
||||
if (empty($nombre_completo) || empty($celular) || empty($sede_envio) || empty($provincia) || empty($distrito) || empty($producto) || $cantidad === false || $monto_total === false || empty($coordenadas)) {
|
||||
$error_message = urlencode('Por favor, complete todos los campos obligatorios: departamento, provincia, distrito y coordenadas.');
|
||||
$id_param = $id ? '&id=' . $id : '';
|
||||
header('Location: pedidos_contraentrega.php?error=' . $error_message . $id_param);
|
||||
exit;
|
||||
|
||||
@ -26,6 +26,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$nombre = $_POST['nombre'] ?? '';
|
||||
$codigo_base = $_POST['codigo_base'] ?? '';
|
||||
$sku = !empty($_POST['sku']) ? $_POST['sku'] : null;
|
||||
$ean = isset($_POST['ean']) ? preg_replace('/\s+/', '', trim($_POST['ean'])) : '';
|
||||
$ean = $ean !== '' ? $ean : null;
|
||||
if ($ean !== null && !preg_match('/^[0-9]{1,32}$/', $ean)) {
|
||||
$_SESSION['error_message'] = 'El EAN solo debe contener números.';
|
||||
header('Location: ' . (!empty($id) ? 'edit_product.php?id=' . urlencode($id) : 'edit_product.php'));
|
||||
exit;
|
||||
}
|
||||
$costo = !empty($_POST['costo']) ? (float)$_POST['costo'] : 0.00;
|
||||
$precio_venta = !empty($_POST['precio_venta']) ? (float)$_POST['precio_venta'] : 0.00;
|
||||
$description = $_POST['description'] ?? '';
|
||||
@ -42,15 +49,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
if (!empty($id)) {
|
||||
// Actualizar producto existente
|
||||
$sql = "UPDATE products SET nombre = ?, sku = ?, costo = ?, precio_venta = ?, description = ?, provincia_id = ?, show_on_panel = ?, codigo_base = ? WHERE id = ?";
|
||||
$sql = "UPDATE products SET nombre = ?, sku = ?, ean = ?, costo = ?, precio_venta = ?, description = ?, provincia_id = ?, show_on_panel = ?, codigo_base = ? WHERE id = ?";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute([$nombre, $sku, $costo, $precio_venta, $description, $provincia_id, $show_on_panel, $codigo_base, $id]);
|
||||
$stmt->execute([$nombre, $sku, $ean, $costo, $precio_venta, $description, $provincia_id, $show_on_panel, $codigo_base, $id]);
|
||||
$_SESSION['success_message'] = "Producto actualizado exitosamente.";
|
||||
} else {
|
||||
// Crear nuevo producto
|
||||
$sql = "INSERT INTO products (nombre, sku, costo, precio_venta, description, provincia_id, show_on_panel, codigo_base, unidades_vendidas) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)";
|
||||
$sql = "INSERT INTO products (nombre, sku, ean, costo, precio_venta, description, provincia_id, show_on_panel, codigo_base, unidades_vendidas) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0)";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute([$nombre, $sku, $costo, $precio_venta, $description, $provincia_id, $show_on_panel, $codigo_base]);
|
||||
$stmt->execute([$nombre, $sku, $ean, $costo, $precio_venta, $description, $provincia_id, $show_on_panel, $codigo_base]);
|
||||
$_SESSION['success_message'] = "Producto creado exitosamente.";
|
||||
}
|
||||
|
||||
|
||||
43
update_product_ean.php
Normal file
43
update_product_ean.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
try {
|
||||
$role = $_SESSION['user_role'] ?? ($_SESSION['role'] ?? '');
|
||||
if (!isset($_SESSION['user_id']) || !in_array($role, ['Administrador', 'admin', 'Control Logistico', 'Logistica'], true)) {
|
||||
throw new Exception('No autorizado.');
|
||||
}
|
||||
|
||||
$productId = isset($_POST['product_id']) ? (int)$_POST['product_id'] : 0;
|
||||
$ean = isset($_POST['ean']) ? preg_replace('/\s+/', '', trim($_POST['ean'])) : '';
|
||||
|
||||
if ($productId <= 0) {
|
||||
throw new Exception('Producto inválido.');
|
||||
}
|
||||
|
||||
if ($ean !== '' && !preg_match('/^[0-9]{1,32}$/', $ean)) {
|
||||
throw new Exception('El EAN solo debe contener números.');
|
||||
}
|
||||
|
||||
$eanToSave = $ean !== '' ? $ean : null;
|
||||
$stmt = db()->prepare('UPDATE products SET ean = :ean WHERE id = :id');
|
||||
$stmt->bindValue(':ean', $eanToSave, $eanToSave === null ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||
$stmt->bindValue(':id', $productId, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
|
||||
if ($stmt->rowCount() === 0) {
|
||||
$check = db()->prepare('SELECT id FROM products WHERE id = :id');
|
||||
$check->bindValue(':id', $productId, PDO::PARAM_INT);
|
||||
$check->execute();
|
||||
if (!$check->fetchColumn()) {
|
||||
throw new Exception('Producto no encontrado.');
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true, 'ean' => $eanToSave ?? '']);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user