diff --git a/src/components/POS/UnitEquivalenceSelector.vue b/src/components/POS/UnitEquivalenceSelector.vue index c8b9970..87290fb 100644 --- a/src/components/POS/UnitEquivalenceSelector.vue +++ b/src/components/POS/UnitEquivalenceSelector.vue @@ -60,6 +60,7 @@ const confirmSelection = () => { unit_of_measure_id: selectedOption.value.unit_of_measure_id, unit_price: selectedOption.value.unit_price, unit_name: selectedOption.value.unit_of_measure_id ? selectedOption.value.unit_name : null, + conversion_factor: selectedOption.value.conversion_factor }); selectedOption.value = null; }; diff --git a/src/pages/POS/Point.vue b/src/pages/POS/Point.vue index 64bb01f..c9579d7 100644 --- a/src/pages/POS/Point.vue +++ b/src/pages/POS/Point.vue @@ -209,7 +209,7 @@ const addToCart = async (product) => { // Si el producto ya está en el carrito (sin seriales), solo incrementar sin abrir selectores const existingItem = cart.items.find(i => i.item_key === 'p:' + product.id); if (existingItem && !existingItem.track_serials) { - if (existingItem.quantity < product.stock) { + if (existingItem.quantity < existingItem.max_stock) { existingItem.quantity++; window.Notify.success(`${product.name} agregado al carrito`); } else { @@ -536,12 +536,21 @@ const handleConfirmSale = async (paymentData) => { }; }); + const unitMap = {}; + cart.items.filter(i => !i.is_bundle && i.unit_of_measure_id).forEach(item => { + unitMap[item.inventory_id] = { + unit_name: item.unit_name, + quantity: item.quantity + }; + }); + // Generar ticket PDF con descarga automática e impresión await ticketService.generateSaleTicket(response, { businessName: 'HIKVISION DISTRIBUIDOR', autoDownload: true, autoPrint: false, - bundleMap + bundleMap, + unitMap }); window.Notify.success('Ticket generado e impreso correctamente'); diff --git a/src/services/ticketService.js b/src/services/ticketService.js index b1bb620..ee4ed9a 100644 --- a/src/services/ticketService.js +++ b/src/services/ticketService.js @@ -80,7 +80,8 @@ const ticketService = { businessName = 'HIKVISION DISTRIBUIDOR', autoDownload = true, autoPrint = false, - bundleMap = {} + bundleMap = {}, + unitMap = {} } = options; // Detectar ubicación del usuario @@ -322,14 +323,24 @@ const ticketService = { } // Cantidad y Precio - const quantity = item.quantity || 1; + const unitInfo = unitMap[item.inventory_id]; + const displayQty = unitInfo?.quantity + ?? ((item.unit_of_measure_id && item.unit_quantity) + ? parseFloat(item.unit_quantity) + : (item.quantity || 1)); + const unitAbbr = unitInfo?.unit_name + || (item.unit_of_measure_id + ? (item.unit_of_measure?.abbreviation || item.unit_of_measure?.name || '') + : ''); + const qtyText = unitAbbr ? `${displayQty} ${unitAbbr}` : String(displayQty); + const unitPrice = formatMoney(item.unit_price); doc.setFontSize(8); doc.setFont('helvetica', 'normal'); doc.setTextColor(...blackColor); - doc.text(String(quantity), 52, yPosition, { align: 'center' }); + doc.text(qtyText, 52, yPosition, { align: 'center' }); doc.text(`$${unitPrice}`, rightMargin, yPosition, { align: 'right' }); yPosition += 4; diff --git a/src/stores/cart.js b/src/stores/cart.js index b66b8fe..8419df1 100644 --- a/src/stores/cart.js +++ b/src/stores/cart.js @@ -68,6 +68,9 @@ const useCart = defineStore('cart', { ? parseFloat(config.unit_price) : parseFloat(product.price?.retail_price || 0); + const conversionFactor = parseFloat(config?.conversion_factor || 1); + const maxStock = conversionFactor !== 1 ? Math.floor(product.stock / conversionFactor) : product.stock; + // Agregar nuevo item this.items.push({ item_key: key, @@ -79,7 +82,7 @@ const useCart = defineStore('cart', { quantity: 1, unit_price: unitPrice, tax_rate: parseFloat(product.price?.tax || 16), - max_stock: product.stock, + max_stock: maxStock, // Campos para seriales track_serials: product.track_serials || false, serial_numbers: config?.serialNumbers || [],