/** * Sales Bot - Camera Capture for Ticket Processing */ let cameraStream = null; async function abrirCamara() { const modal = document.getElementById('camera-modal'); const video = document.getElementById('camera-video'); if (!modal || !video) { console.error('Camera elements not found'); return; } try { // Request camera access cameraStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment', // Use back camera on mobile width: { ideal: 1920 }, height: { ideal: 1080 } }, audio: false }); video.srcObject = cameraStream; modal.classList.add('active'); } catch (error) { console.error('Error accessing camera:', error); if (error.name === 'NotAllowedError') { alert('Permiso de camara denegado. Por favor, permite el acceso a la camara en la configuracion del navegador.'); } else if (error.name === 'NotFoundError') { alert('No se encontro una camara en este dispositivo.'); } else { alert('Error al acceder a la camara: ' + error.message); } } } function cerrarCamara() { const modal = document.getElementById('camera-modal'); const video = document.getElementById('camera-video'); if (cameraStream) { cameraStream.getTracks().forEach(track => track.stop()); cameraStream = null; } if (video) { video.srcObject = null; } if (modal) { modal.classList.remove('active'); } } async function capturarFoto() { const video = document.getElementById('camera-video'); const canvas = document.getElementById('camera-canvas'); if (!video || !canvas) { console.error('Video or canvas not found'); return; } // Set canvas size to video size canvas.width = video.videoWidth; canvas.height = video.videoHeight; // Draw video frame to canvas const ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0); // Get base64 image const imageData = canvas.toDataURL('image/jpeg', 0.9); // Close camera cerrarCamara(); // Show loading if (window.Utils) { window.Utils.showNotification('Procesando imagen...', 'info'); } try { // Send to server for OCR processing const response = await fetch('/api/capture/ticket', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image: imageData }) }); const result = await response.json(); if (result.success) { if (window.Utils) { window.Utils.showNotification('Ticket procesado correctamente', 'success'); } // Show detected data mostrarResultadoOCR(result); } else { if (window.Utils) { window.Utils.showNotification('Error procesando ticket: ' + (result.error || 'Error desconocido'), 'error'); } } } catch (error) { console.error('Error sending image:', error); if (window.Utils) { window.Utils.showNotification('Error enviando imagen al servidor', 'error'); } } } function mostrarResultadoOCR(result) { // Create modal to show OCR results const modal = document.createElement('div'); modal.className = 'camera-modal active'; modal.style.cssText = 'display: flex; align-items: center; justify-content: center;'; const monto = result.monto ? window.Utils.formatMoney(result.monto) : 'No detectado'; const productos = result.productos || []; const tubos = productos.filter(p => p.nombre && p.nombre.toLowerCase().includes('tinte') ).length; modal.innerHTML = `

Resultado del Ticket

${monto}
${tubos}
${productos.length > 0 ? `
` : ''}
`; document.body.appendChild(modal); } async function confirmarVenta(monto, tubos) { // This would integrate with the main sales flow // For now, just show a notification if (window.Utils) { window.Utils.showNotification(`Venta de ${window.Utils.formatMoney(monto)} lista para confirmar`, 'info'); } // Here you could redirect to Mattermost or show a form // to complete the sale registration } // File input fallback for devices without camera API function createFileInput() { const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; input.capture = 'environment'; input.style.display = 'none'; input.addEventListener('change', async (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = async (event) => { const imageData = event.target.result; if (window.Utils) { window.Utils.showNotification('Procesando imagen...', 'info'); } try { const response = await fetch('/api/capture/ticket', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image: imageData }) }); const result = await response.json(); if (result.success) { mostrarResultadoOCR(result); } else { if (window.Utils) { window.Utils.showNotification('Error procesando imagen', 'error'); } } } catch (error) { console.error('Error:', error); } }; reader.readAsDataURL(file); }); return input; } // Export functions window.abrirCamara = abrirCamara; window.cerrarCamara = cerrarCamara; window.capturarFoto = capturarFoto;