Autosave: 20260212-165014
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 55 KiB |
BIN
assets/uploads/vouchers/698e00626c968-98.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
assets/uploads/vouchers/698e00b6286ef-5818.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
assets/uploads/vouchers/698e011a74324-306.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
assets/uploads/vouchers/698e039ab31d0-951.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
assets/uploads/vouchers/698e0443145c1-910.png
Normal file
|
After Width: | Height: | Size: 247 KiB |
3
db/migrations/063_add_label_code_to_products.sql
Normal file
@ -0,0 +1,3 @@
|
||||
ALTER TABLE `products`
|
||||
ADD COLUMN `codigo_base` VARCHAR(20) DEFAULT NULL,
|
||||
ADD COLUMN `contador_etiquetas` INT DEFAULT 0;
|
||||
@ -71,6 +71,12 @@ include 'layout_header.php';
|
||||
<input type="text" class="form-control" id="nombre" name="nombre" value="<?php echo htmlspecialchars($product['nombre']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="codigo_base">Prefijo para Etiquetas (Opcional)</label>
|
||||
<input type="text" class="form-control" id="codigo_base" name="codigo_base" value="<?php echo htmlspecialchars($product['codigo_base'] ?? ''); ?>">
|
||||
<small class="form-text text-muted">Ej: "AFS" para Anillo Feng Shui. Si lo dejas vacío, se usarán las iniciales del nombre.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="provincia_id">Provincia (Opcional)</label>
|
||||
<select class="form-control" id="provincia_id" name="provincia_id">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
$pageTitle = "Generador de Etiquetas";
|
||||
include 'layout_header.php';
|
||||
include 'db/config.php';
|
||||
require_once 'includes/barcode_generator.php'; // Added this line
|
||||
|
||||
|
||||
// Fetch products for the dropdown
|
||||
$products = [];
|
||||
@ -15,51 +15,50 @@ try {
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
$generated_codes = []; // Initialize array to hold codes for display
|
||||
$generated_codes = [];
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$producto_id = $_POST['producto_id'] ?? null;
|
||||
$cantidad = isset($_POST['cantidad']) ? (int)$_POST['cantidad'] : 0;
|
||||
|
||||
if ($producto_id && $cantidad > 0 && $cantidad <= 1000) {
|
||||
// Find product name to generate initials
|
||||
$product_name = '';
|
||||
foreach ($products as $p) {
|
||||
if ($p['id'] == $producto_id) {
|
||||
$product_name = $p['nombre'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$initials = '';
|
||||
if (!empty($product_name)) {
|
||||
$words = preg_split('/\s+/', trim($product_name));
|
||||
foreach ($words as $w) {
|
||||
if (isset($w[0])) {
|
||||
$initials .= strtoupper($w[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$db = db();
|
||||
try {
|
||||
$db->beginTransaction();
|
||||
|
||||
// Prepare statement for insertion
|
||||
$stmt = $db->prepare("INSERT INTO unidades_inventario (codigo_unico, producto_id) VALUES (?, ?)");
|
||||
|
||||
for ($i = 0; $i < $cantidad; $i++) {
|
||||
// Generate a unique code with product initials
|
||||
$unique_part = strtoupper(uniqid());
|
||||
$unique_code = ($initials ? $initials . '-' : '') . $producto_id . '-' . $unique_part;
|
||||
// 1. Lock the product row and get current counter and code base
|
||||
$stmt = $db->prepare("SELECT codigo_base, contador_etiquetas FROM products WHERE id = ? FOR UPDATE");
|
||||
$stmt->execute([$producto_id]);
|
||||
$product_data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$product_data) {
|
||||
throw new Exception("Producto no encontrado.");
|
||||
}
|
||||
|
||||
$codigo_base = $product_data['codigo_base'];
|
||||
$contador_actual = (int)$product_data['contador_etiquetas'];
|
||||
|
||||
// Prepare statement for insertion into unidades_inventario
|
||||
$insert_stmt = $db->prepare("INSERT INTO unidades_inventario (codigo_unico, producto_id) VALUES (?, ?)");
|
||||
|
||||
// 2. Generate new codes
|
||||
for ($i = 1; $i <= $cantidad; $i++) {
|
||||
$nuevo_contador = $contador_actual + $i;
|
||||
$numero_formateado = str_pad($nuevo_contador, 4, '0', STR_PAD_LEFT);
|
||||
$unique_code = $codigo_base . '-' . $numero_formateado;
|
||||
|
||||
$stmt->execute([$unique_code, $producto_id]);
|
||||
$insert_stmt->execute([$unique_code, $producto_id]);
|
||||
$generated_codes[] = $unique_code;
|
||||
}
|
||||
|
||||
// 3. Update the counter in the products table
|
||||
$nuevo_total_contador = $contador_actual + $cantidad;
|
||||
$update_stmt = $db->prepare("UPDATE products SET contador_etiquetas = ? WHERE id = ?");
|
||||
$update_stmt->execute([$nuevo_total_contador, $producto_id]);
|
||||
|
||||
$db->commit();
|
||||
$_SESSION['success_message'] = 'Se generaron ' . count($generated_codes) . ' códigos exitosamente.';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
$_SESSION['error_message'] = 'Error al generar los códigos: ' . $e->getMessage();
|
||||
}
|
||||
@ -113,7 +112,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
<?php
|
||||
if (!empty($generated_codes)) {
|
||||
$generator = new BarcodeGenerator();
|
||||
?>
|
||||
<div class="card mt-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
@ -133,13 +131,7 @@ if (!empty($generated_codes)) {
|
||||
<?php foreach ($generated_codes as $code): ?>
|
||||
<div class="col-lg-4 col-md-6 text-center mb-4">
|
||||
<div class="barcode-container" style="min-height: 70px;">
|
||||
<?php
|
||||
try {
|
||||
echo $generator->getBarcode($code);
|
||||
} catch (Exception $e) {
|
||||
echo '<div class="alert alert-danger">Error al generar código de barras.</div>';
|
||||
}
|
||||
?>
|
||||
<img src="https://barcode.tec-it.com/barcode.ashx?data=<?php echo urlencode($code); ?>&code=Code128" alt="Barcode for <?php echo htmlspecialchars($code); ?>" style="max-height: 50px;">
|
||||
</div>
|
||||
<code><?php echo htmlspecialchars($code); ?></code>
|
||||
</div>
|
||||
@ -149,4 +141,4 @@ if (!empty($generated_codes)) {
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php include 'layout_footer.php'; ?>
|
||||
<?php include 'layout_footer.php'; ?>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
require_once 'includes/barcode_generator.php';
|
||||
|
||||
|
||||
$codes = $_POST['codes'] ?? [];
|
||||
|
||||
@ -8,7 +8,7 @@ if (empty($codes)) {
|
||||
// For now, we'll just show a blank page if no codes are provided.
|
||||
}
|
||||
|
||||
$generator = new BarcodeGenerator();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
@ -80,13 +80,7 @@ $generator = new BarcodeGenerator();
|
||||
<?php foreach ($codes as $code): ?>
|
||||
<div class="label">
|
||||
<div class="barcode-svg">
|
||||
<?php
|
||||
try {
|
||||
echo $generator->getBarcode($code, 2, 50);
|
||||
} catch (Exception $e) {
|
||||
echo '<div class="alert alert-danger p-1">Error</div>';
|
||||
}
|
||||
?>
|
||||
<img src="https://barcode.tec-it.com/barcode.ashx?data=<?php echo urlencode($code); ?>&code=Code128" alt="Barcode for <?php echo htmlspecialchars($code); ?>" style="max-height: 50px;">
|
||||
</div>
|
||||
<div class="code-text">
|
||||
<code><?php echo htmlspecialchars($code); ?></code>
|
||||
|
||||
@ -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 FROM products ORDER BY nombre");
|
||||
$products_stmt = $pdo->query("SELECT id, nombre, sku 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");
|
||||
@ -37,6 +37,7 @@ try {
|
||||
foreach ($products as $product) {
|
||||
$inventario[$product['id']] = [
|
||||
'nombre' => $product['nombre'],
|
||||
'sku' => $product['sku'],
|
||||
'total' => 0,
|
||||
'sedes' => array_fill_keys(array_column($sedes, 'id'), 0)
|
||||
];
|
||||
@ -180,6 +181,7 @@ try {
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>Producto</th>
|
||||
<th>SKU</th>
|
||||
<th class="text-center">Stock Total</th>
|
||||
<?php foreach ($sedes as $sede): ?>
|
||||
<th class="text-center"><?php echo htmlspecialchars($sede['nombre']); ?></th>
|
||||
@ -188,11 +190,12 @@ try {
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($inventario)): ?>
|
||||
<tr><td colspan="<?php echo count($sedes) + 2; ?>" class="text-center">No hay productos.</td></tr>
|
||||
<tr><td colspan="<?php echo count($sedes) + 3; ?>" class="text-center">No hay productos.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($inventario as $datos_producto): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($datos_producto['nombre']); ?></td>
|
||||
<td><?php echo htmlspecialchars($datos_producto['sku']); ?></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>
|
||||
|
||||
@ -2,10 +2,23 @@
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Función para generar el código base a partir de las iniciales
|
||||
function generar_codigo_base($nombre) {
|
||||
$palabras = explode(' ', trim($nombre));
|
||||
$iniciales = '';
|
||||
foreach ($palabras as $palabra) {
|
||||
if (!empty($palabra)) {
|
||||
$iniciales .= strtoupper($palabra[0]);
|
||||
}
|
||||
}
|
||||
return $iniciales;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Recoger todos los datos del formulario
|
||||
$id = $_POST['id'] ?? null;
|
||||
$nombre = $_POST['nombre'] ?? '';
|
||||
$codigo_base = $_POST['codigo_base'] ?? '';
|
||||
$sku = !empty($_POST['sku']) ? $_POST['sku'] : null;
|
||||
$costo = !empty($_POST['costo']) ? (float)$_POST['costo'] : 0.00;
|
||||
$precio_venta = !empty($_POST['precio_venta']) ? (float)$_POST['precio_venta'] : 0.00;
|
||||
@ -14,20 +27,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
$show_on_panel = isset($_POST['show_on_panel']) ? 1 : 0;
|
||||
|
||||
// Generar código base si está vacío
|
||||
if (empty($codigo_base)) {
|
||||
$codigo_base = generar_codigo_base($nombre);
|
||||
}
|
||||
|
||||
$db = db();
|
||||
|
||||
if (!empty($id)) {
|
||||
// Actualizar producto existente
|
||||
$sql = "UPDATE products SET nombre = ?, sku = ?, costo = ?, precio_venta = ?, description = ?, provincia_id = ?, show_on_panel = ? WHERE id = ?";
|
||||
$sql = "UPDATE products SET nombre = ?, sku = ?, 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, $id]);
|
||||
$stmt->execute([$nombre, $sku, $costo, $precio_venta, $description, $provincia_id, $show_on_panel, $codigo_base, $id]);
|
||||
$_SESSION['success_message'] = "Producto actualizado exitosamente.";
|
||||
} else {
|
||||
// Crear nuevo producto
|
||||
// No se insertan columnas generadas como ganancia_unidad, ingreso_total, ganancia_total
|
||||
$sql = "INSERT INTO products (nombre, sku, costo, precio_venta, description, provincia_id, show_on_panel, unidades_vendidas) VALUES (?, ?, ?, ?, ?, ?, ?, 0)";
|
||||
$sql = "INSERT INTO products (nombre, sku, 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]);
|
||||
$stmt->execute([$nombre, $sku, $costo, $precio_venta, $description, $provincia_id, $show_on_panel, $codigo_base]);
|
||||
$_SESSION['success_message'] = "Producto creado exitosamente.";
|
||||
}
|
||||
|
||||
|
||||