From 53b632c07cea3340b7bf5f67f8d9359d31e007cc Mon Sep 17 00:00:00 2001 From: Renato Date: Sun, 15 Feb 2026 22:48:48 +0100 Subject: [PATCH] =?UTF-8?q?Agrega=20verificaci=C3=B3n=20de=20stock=20para?= =?UTF-8?q?=20ventas=20de=20kits=20m=C3=BAltiples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Nueva tool verificar_stock_kit() para calcular cuántos kits se pueden armar - Nueva función db_verificar_stock_kit() que verifica stock de todos los productos - Calcula kits_posibles basado en el producto con menor stock relativo - Actualiza skill armar_kits.md con proceso de verificación obligatoria - Ahora advierte antes de vender: 'Solo podés armar X kits, pediste Y' - Prevents ventas parciales no deseadas de kits --- pymesbot/backend/main.py | 126 ++++++++++++++++++++++++++++++++++ pymesbot/skills/armar_kits.md | 28 ++++++++ 2 files changed, 154 insertions(+) diff --git a/pymesbot/backend/main.py b/pymesbot/backend/main.py index e2a447d..8157b9a 100644 --- a/pymesbot/backend/main.py +++ b/pymesbot/backend/main.py @@ -329,6 +329,89 @@ def db_confirmar_venta_kit(items: list) -> dict: } +def db_verificar_stock_kit(items: list, cantidad_kits: int) -> dict: + """Verifica si hay stock suficiente para armar N kits completos""" + conn = sqlite3.connect(DB_PATH) + conn.row_factory = sqlite3.Row + cursor = conn.cursor() + + productos_info = [] + kits_posibles = float("inf") + faltantes = [] + + for item in items: + producto_nombre = item.get("producto_nombre", "") + cantidad_por_kit = item.get("cantidad", 1) + + query_normalized = normalize_text(producto_nombre.lower()) + search_term = f"%{query_normalized}%" + + cursor.execute( + """ + SELECT nombre, stock FROM productos + WHERE activo = 1 AND ( + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(LOWER(nombre), 'á', 'a'), 'é', 'e'), 'í', 'i'), 'ó', 'o'), 'ú', 'u') LIKE ? + ) + LIMIT 1 + """, + (search_term,), + ) + + producto = cursor.fetchone() + + if not producto: + faltantes.append(f"Producto no encontrado: {producto_nombre}") + continue + + stock_disponible = producto["stock"] + kits_con_este_producto = stock_disponible // cantidad_por_kit + + productos_info.append( + { + "nombre": producto["nombre"], + "stock": stock_disponible, + "cantidad_por_kit": cantidad_por_kit, + "kits_posibles": kits_con_este_producto, + } + ) + + # El límite es el producto con menos kits posibles + if kits_con_este_producto < kits_posibles: + kits_posibles = kits_con_este_producto + + conn.close() + + # Si no hay productos válidos + if not productos_info: + return { + "puede_vender": False, + "kits_solicitados": cantidad_kits, + "kits_posibles": 0, + "mensaje": "No se encontraron los productos del kit", + "detalles": faltantes, + } + + # Si puede vender todos los kits solicitados + if kits_posibles >= cantidad_kits: + return { + "puede_vender": True, + "kits_solicitados": cantidad_kits, + "kits_posibles": cantidad_kits, + "mensaje": f"✅ Stock suficiente para {cantidad_kits} kits", + "productos": productos_info, + } + + # Si no alcanza el stock + return { + "puede_vender": False, + "kits_solicitados": cantidad_kits, + "kits_posibles": kits_posibles, + "mensaje": f"⚠️ Solo podés armar {kits_posibles} kits completos (pediste {cantidad_kits})", + "productos": productos_info, + "sugerencia": f"Con el stock actual solo alcanza para {kits_posibles} kits. ¿Vendés {kits_posibles} o preferís ver otros productos?", + } + + async def chat_with_ai(message: str, session_id: str = "pymesbot") -> Optional[str]: """Send message to Anthropic API with tools""" @@ -402,6 +485,38 @@ async def chat_with_ai(message: str, session_id: str = "pymesbot") -> Optional[s "required": ["items"], }, }, + { + "name": "verificar_stock_kit", + "description": "Verifica si hay stock suficiente para armar N kits completos ANTES de vender. Usar SIEMPRE cuando el usuario quiera vender múltiples kits para calcular cuántos se pueden armar con el stock actual.", + "input_schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "description": "Lista de productos que componen un kit", + "items": { + "type": "object", + "properties": { + "producto_nombre": { + "type": "string", + "description": "Nombre del producto", + }, + "cantidad": { + "type": "integer", + "description": "Cantidad que lleva el kit de este producto", + }, + }, + "required": ["producto_nombre", "cantidad"], + }, + }, + "cantidad_kits": { + "type": "integer", + "description": "Cantidad de kits que quiere vender", + }, + }, + "required": ["items", "cantidad_kits"], + }, + }, ] messages = [{"role": "user", "content": message}] @@ -497,6 +612,17 @@ async def chat_with_ai(message: str, session_id: str = "pymesbot") -> Optional[s "content": json.dumps(resultado), } ) + elif tool_name == "verificar_stock_kit": + items = tool_input.get("items", []) + cantidad_kits = tool_input.get("cantidad_kits", 1) + resultado = db_verificar_stock_kit(items, cantidad_kits) + tool_results.append( + { + "type": "tool_result", + "tool_use_id": tool_call.get("id"), + "content": json.dumps(resultado), + } + ) # Agregar el tool use y los resultados a los mensajes messages.append({"role": "assistant", "content": json.dumps(content)}) diff --git a/pymesbot/skills/armar_kits.md b/pymesbot/skills/armar_kits.md index 1e5568a..e6110a5 100644 --- a/pymesbot/skills/armar_kits.md +++ b/pymesbot/skills/armar_kits.md @@ -37,11 +37,39 @@ Formato de presentación: ## Venta de Kits +### VERIFICACIÓN CRÍTICA - Antes de Vender Múltiples Kits + +**SIEMPRE** verificar stock antes de confirmar venta de múltiples kits. + +**Proceso:** +1. Usar `verificar_stock_kit` con: + - `items`: Lista de productos del kit + - `cantidad_kits`: Cuántos kits quiere vender +2. Si `puede_vender: true` → Proceder con `confirmar_venta_kit` +3. Si `puede_vender: false` → Informar límite y preguntar si vende esa cantidad + +**Ejemplo:** +Usuario: "Se vendieron 10 kits" +Bot: [USAR verificar_stock_kit(items=[...], cantidad_kits=10)] + +Si alcanza: +"✅ Tenés stock para 10 kits. ¿Confirmamos la venta?" + +Si no alcanza (solo hay para 7): +"⚠️ Solo podés armar 7 kits completos con el stock actual. +¿Vendemos 7 kits o preferís ver otros productos?" + ### Confirmación de Venta de Kit Cuando el usuario diga "se vendió el kit", "concretamos", "dale, lo lleva", etc: +**Si es UN solo kit:** **Acción:** Usar `confirmar_venta_kit` con TODOS los productos del kit. +**Si son MÚLTIPLES kits:** +**Acción:** +1. PRIMERO `verificar_stock_kit` para verificar cuántos se pueden armar +2. LUEGO `confirmar_venta_kit` SOLO si hay stock suficiente + **Ejemplo:** Usuario: "Se vendió el kit de 15mil" Bot: [USAR confirmar_venta_kit con items=[