import logging import re from datetime import datetime from utils import extraer_monto, extraer_cliente, formatear_moneda, extraer_tubos from ocr_processor import OCRProcessor import os logger = logging.getLogger(__name__) def handle_venta_message(data, mattermost, nocodb): """ Maneja mensajes de venta en Mattermost NUEVO: Sistema de comisiones por tubos vendidos """ try: user_name = data.get('user_name') text = data.get('text', '').strip() channel_name = data.get('channel_name') post_id = data.get('post_id') file_ids = data.get('file_ids', '') if file_ids and isinstance(file_ids, str): file_ids = [f.strip() for f in file_ids.split(',') if f.strip()] elif not file_ids: file_ids = [] logger.info(f"Procesando venta de {user_name}: {text}, archivos: {file_ids}") # Extraer información del texto monto = extraer_monto(text) cliente = extraer_cliente(text) tubos_manual = extraer_tubos(text) # NUEVO: tubos manuales # Procesar imágenes adjuntas imagen_url = None ocr_info = "" productos_ocr = [] if file_ids: logger.info(f"Procesando {len(file_ids)} archivos adjuntos") file_id = file_ids[0] imagen_data = mattermost.get_file(file_id) file_info = mattermost.get_file_info(file_id) if file_info and imagen_data: filename = file_info.get('name', 'ticket.jpg') file_size = file_info.get('size', 0) bot_token = os.getenv('MATTERMOST_BOT_TOKEN') mattermost_url = os.getenv('MATTERMOST_URL') imagen_url = f"{mattermost_url}/api/v4/files/{file_id}?access_token={bot_token}" logger.info(f"Archivo adjunto: {filename}, tamaño: {file_size} bytes") # Procesar con OCR try: ocr = OCRProcessor() resultado_ocr = ocr.procesar_ticket(imagen_data) if resultado_ocr: monto_ocr = resultado_ocr.get('monto_detectado') fecha_ocr = resultado_ocr.get('fecha_detectada') productos_ocr = resultado_ocr.get('productos', []) if not monto and monto_ocr: monto = monto_ocr logger.info(f"Usando monto detectado por OCR: ${monto}") ocr_info += f"\n💡 Monto detectado: ${monto:,.2f}" elif monto and monto_ocr: es_valido, mensaje = ocr.validar_monto_con_ocr(monto, monto_ocr, tolerancia=0.05) ocr_info += f"\n{mensaje}" if not es_valido: logger.warning(mensaje) if fecha_ocr: ocr_info += f"\n📅 Fecha: {fecha_ocr}" if productos_ocr: # NUEVO: Contar tubos de tinte tubos_tinte = sum( p['cantidad'] for p in productos_ocr if 'tinte' in p['marca'].lower() or 'tinte' in p['producto'].lower() or 'cromatique' in p['marca'].lower() ) ocr_info += f"\n🧪 Tubos de tinte: {tubos_tinte}" ocr_info += f"\n📦 Total productos: {len(productos_ocr)}" logger.info(f"Tubos de tinte detectados: {tubos_tinte}") except Exception as ocr_error: logger.error(f"Error en OCR: {str(ocr_error)}") ocr_info = "\n⚠️ No se pudo leer el ticket" productos_ocr = [] logger.info(f"URL de imagen: {imagen_url}") if not monto: mensaje = ( f"@{user_name} Necesito el monto de la venta.\n" "**Formatos válidos:**\n" "• `venta @monto 1500 @cliente Juan Pérez`\n" "• `vendí $1500 a Juan Pérez`\n" "• Adjunta foto del ticket" ) mattermost.post_message_webhook(mensaje, username='Sales Bot', icon_emoji=':moneybag:') return {'text': mensaje} if not cliente: cliente = "Cliente sin nombre" # Verificar/crear vendedor vendedor = nocodb.get_vendedor(user_name) if not vendedor: user_info = mattermost.get_user_by_username(user_name) email = user_info.get('email', f"{user_name}@consultoria-as.com") if user_info else f"{user_name}@consultoria-as.com" nombre = user_info.get('first_name', user_name) if user_info else user_name vendedor = nocodb.crear_vendedor( username=user_name, nombre_completo=nombre, email=email, meta_diaria_tubos=3 # NUEVO: Meta de 3 tubos diarios ) if vendedor: mensaje_bienvenida = ( f"👋 ¡Bienvenido @{user_name}!\n" f"**Sistema de comisiones:**\n" f"• Meta diaria: {nocodb.META_DIARIA_TUBOS} tubos de tinte\n" f"• Comisión: ${nocodb.COMISION_POR_TUBO:.0f} por tubo después del {nocodb.META_DIARIA_TUBOS}º\n" f"¡Empieza a registrar tus ventas!" ) mattermost.post_message_webhook(mensaje_bienvenida, username='Sales Bot', icon_emoji=':wave:') # Registrar venta venta = nocodb.registrar_venta( vendedor_username=user_name, monto=monto, cliente=cliente, descripcion=text, mensaje_id=post_id, canal=channel_name, imagen_url=imagen_url ) if venta: venta_id = venta.get('Id') # Guardar productos detectados por OCR if productos_ocr: productos_guardados = nocodb.guardar_productos_venta(venta_id, productos_ocr) if productos_guardados: logger.info(f"Guardados {len(productos_guardados)} productos para venta {venta_id}") # NUEVO: Guardar tubos manuales si se especificaron elif tubos_manual and tubos_manual > 0: productos_manuales = [{ 'producto': 'Tinte (registro manual)', 'marca': 'Manual', 'cantidad': tubos_manual, 'precio_unitario': monto / tubos_manual if tubos_manual > 0 else 0, 'importe': monto }] productos_guardados = nocodb.guardar_productos_venta(venta_id, productos_manuales) if productos_guardados: logger.info(f"Guardados {tubos_manual} tubos manuales para venta {venta_id}") # NUEVO: Actualizar tabla de metas try: nocodb.actualizar_meta_vendedor(user_name) logger.info(f"Metas actualizadas para {user_name}") except Exception as meta_error: logger.error(f"Error actualizando metas: {str(meta_error)}") # Reacción de éxito if post_id: mattermost.add_reaction(post_id, 'white_check_mark') # NUEVO: Obtener estadísticas del día stats_dia = nocodb.get_estadisticas_vendedor_dia(user_name) # Construir mensaje mensaje_confirmacion = ( f"✅ **Venta registrada**\n\n" f"**Vendedor:** @{user_name}\n" f"**Monto:** {formatear_moneda(monto)}\n" f"**Cliente:** {cliente}\n" ) if imagen_url: mensaje_confirmacion += f"📸 **Ticket:** Guardado{ocr_info}\n" # NUEVO: Mostrar estadísticas de tubos y comisiones if stats_dia: tubos_hoy = stats_dia.get('tubos_vendidos', 0) comision_hoy = stats_dia.get('comision', 0) meta = stats_dia.get('meta_diaria', 3) tubos_comisionables = stats_dia.get('tubos_comisionables', 0) # Determinar emoji según progreso if tubos_hoy >= meta * 2: emoji = '🔥' mensaje_extra = '¡Increíble día!' elif tubos_hoy >= meta: emoji = '⭐' mensaje_extra = '¡Meta cumplida!' elif tubos_hoy >= meta - 1: emoji = '💪' mensaje_extra = '¡Casi llegas!' else: emoji = '📊' mensaje_extra = '¡Sigue así!' mensaje_confirmacion += ( f"\n**Resumen del día:** {emoji}\n" f"• Tubos vendidos hoy: {tubos_hoy} 🧪\n" f"• Meta diaria: {meta} tubos\n" ) if tubos_hoy > meta: mensaje_confirmacion += ( f"• Tubos con comisión: {tubos_comisionables}\n" f"• Comisión ganada hoy: {formatear_moneda(comision_hoy)} 💰\n" ) else: faltan = meta - tubos_hoy mensaje_confirmacion += f"• Faltan {faltan} tubos para comisión\n" mensaje_confirmacion += f"• {mensaje_extra}" # Enviar confirmación mattermost.post_message_webhook( mensaje_confirmacion, username='Sales Bot', icon_emoji=':moneybag:' ) return {'text': mensaje_confirmacion} else: mensaje_error = f"❌ Error al registrar la venta. Intenta de nuevo." mattermost.post_message_webhook(mensaje_error, username='Sales Bot', icon_emoji=':x:') return {'text': mensaje_error} except Exception as e: logger.error(f"Error en handle_venta_message: {str(e)}", exc_info=True) mensaje_error = f"❌ Error: {str(e)}" return {'text': mensaje_error} def generar_reporte_diario(mattermost, nocodb): """ Genera reporte diario de ventas y comisiones NUEVO: Muestra tubos vendidos y comisiones ganadas """ try: import os hoy = datetime.now().strftime('%Y-%m-%d') mes_actual = datetime.now().strftime('%Y-%m') # Obtener todas las ventas del día ventas_hoy = nocodb.get_ventas_dia() # Agrupar por vendedor vendedores_hoy = {} for venta in ventas_hoy: vendedor = venta.get('vendedor_username') if vendedor not in vendedores_hoy: vendedores_hoy[vendedor] = [] vendedores_hoy[vendedor].append(venta) # Calcular estadísticas por vendedor stats_vendedores = [] for vendedor in vendedores_hoy.keys(): stats = nocodb.get_estadisticas_vendedor_dia(vendedor, hoy) if stats: stats_vendedores.append(stats) # Ordenar por tubos vendidos stats_vendedores.sort(key=lambda x: x.get('tubos_vendidos', 0), reverse=True) # Calcular totales total_tubos_dia = sum(s.get('tubos_vendidos', 0) for s in stats_vendedores) total_comisiones = sum(s.get('comision', 0) for s in stats_vendedores) total_monto = sum(s.get('monto_total_dia', 0) for s in stats_vendedores) # Construir mensaje mensaje = ( f"📊 **Reporte Diario - {datetime.now().strftime('%d/%m/%Y')}**\n\n" f"**Resumen del día:**\n" f"• Tubos vendidos: {total_tubos_dia} 🧪\n" f"• Comisiones pagadas: {formatear_moneda(total_comisiones)} 💰\n" f"• Monto total: {formatear_moneda(total_monto)}\n" f"• Ventas: {len(ventas_hoy)}\n\n" ) if stats_vendedores: mensaje += "**Top Vendedores del Día:**\n" for i, stats in enumerate(stats_vendedores[:5], 1): vendedor = stats.get('vendedor') tubos = stats.get('tubos_vendidos', 0) comision = stats.get('comision', 0) emoji = '🥇' if i == 1 else '🥈' if i == 2 else '🥉' if i == 3 else '🏅' if comision > 0: mensaje += f"{emoji} @{vendedor} - {tubos} tubos ({formatear_moneda(comision)} comisión)\n" else: mensaje += f"{emoji} @{vendedor} - {tubos} tubos\n" # Obtener canal de reportes team_name = os.getenv('MATTERMOST_TEAM_NAME') channel_reportes = os.getenv('MATTERMOST_CHANNEL_REPORTES') canal = mattermost.get_channel_by_name(team_name, channel_reportes) if canal: mattermost.post_message(canal['id'], mensaje) logger.info("Reporte diario generado") return {'status': 'success', 'message': 'Reporte generado'} else: logger.warning(f"Canal {channel_reportes} no encontrado") return {'status': 'error', 'message': 'Canal no encontrado'} except Exception as e: logger.error(f"Error generando reporte diario: {str(e)}", exc_info=True) return {'status': 'error', 'message': str(e)} def comando_estadisticas(user_name, mattermost, nocodb): """ Muestra estadísticas personales del vendedor Comando: /stats o /estadisticas """ try: # Estadísticas del día stats_hoy = nocodb.get_estadisticas_vendedor_dia(user_name) # Estadísticas del mes stats_mes = nocodb.get_estadisticas_vendedor_mes(user_name) if not stats_hoy and not stats_mes: mensaje = f"@{user_name} Aún no tienes ventas registradas." return mensaje mensaje = f"📈 **Estadísticas de @{user_name}**\n\n" # Hoy if stats_hoy: mensaje += ( f"**Hoy ({datetime.now().strftime('%d/%m')})**\n" f"• Tubos: {stats_hoy.get('tubos_vendidos', 0)} 🧪\n" f"• Comisión: {formatear_moneda(stats_hoy.get('comision', 0))}\n" f"• Monto: {formatear_moneda(stats_hoy.get('monto_total_dia', 0))}\n" f"• Ventas: {stats_hoy.get('cantidad_ventas', 0)}\n\n" ) # Mes if stats_mes: mensaje += ( f"**Este mes**\n" f"• Tubos totales: {stats_mes.get('tubos_totales', 0)} 🧪\n" f"• Comisión total: {formatear_moneda(stats_mes.get('comision_total', 0))} 💰\n" f"• Monto total: {formatear_moneda(stats_mes.get('monto_total', 0))}\n" f"• Ventas: {stats_mes.get('cantidad_ventas', 0)}\n" f"• Días activos: {stats_mes.get('dias_activos', 0)}\n" f"• Días con meta: {stats_mes.get('dias_meta_cumplida', 0)}\n" f"• Promedio/día: {stats_mes.get('promedio_tubos_dia', 0):.1f} tubos\n" ) mattermost.post_message_webhook(mensaje, username='Sales Bot', icon_emoji=':bar_chart:') return mensaje except Exception as e: logger.error(f"Error en comando_estadisticas: {str(e)}", exc_info=True) return f"❌ Error obteniendo estadísticas"