feat: add agents/app

This commit is contained in:
2025-03-24 20:33:04 -05:00
parent cb63404b50
commit b6b94ac2b5
37 changed files with 3396 additions and 1 deletions

View File

@@ -0,0 +1,476 @@
import sqlite3
import uuid
import os
import re
from datetime import datetime
from typing import List, Dict, Optional, Tuple
from contextlib import contextmanager
# Construir la ruta de la base de datos de manera más robusta
current_dir = os.path.dirname(os.path.abspath(__file__))
app_dir = os.path.abspath(os.path.join(current_dir, "..", "..", ".."))
DATABASE_PATH = os.path.join(app_dir, "data", "orders.db")
# Estados válidos para órdenes
ORDER_STATES = ['in_cart', 'confirmed', 'processing', 'ready', 'delivering', 'delivered', 'cancelled']
DELIVERY_STATES = ['pending', 'assigned', 'in_transit', 'delivered', 'failed']
def validate_phone(phone: str) -> bool:
"""Valida el formato del número de teléfono"""
phone_pattern = re.compile(r'^\+?1?\d{9,15}$')
return bool(phone_pattern.match(phone))
def init_database():
"""Inicializa la base de datos de pedidos"""
os.makedirs(os.path.dirname(DATABASE_PATH), exist_ok=True)
conn = sqlite3.connect(DATABASE_PATH)
cursor = conn.cursor()
# Crear tabla de carritos/pedidos con nuevos campos
cursor.execute("""
CREATE TABLE IF NOT EXISTS orders (
order_id TEXT PRIMARY KEY,
phone TEXT NOT NULL,
status TEXT NOT NULL,
total REAL DEFAULT 0,
delivery_address TEXT,
delivery_status TEXT,
payment_method TEXT,
discount_applied REAL DEFAULT 0,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Crear tabla de items del pedido con unidad de medida
cursor.execute("""
CREATE TABLE IF NOT EXISTS order_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id TEXT NOT NULL,
product_id TEXT NOT NULL,
quantity INTEGER NOT NULL,
price REAL NOT NULL,
unit TEXT NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders (order_id),
UNIQUE(order_id, product_id)
)
""")
conn.commit()
conn.close()
@contextmanager
def get_db_connection():
"""Contexto para manejar la conexión a la base de datos"""
conn = sqlite3.connect(DATABASE_PATH)
conn.row_factory = sqlite3.Row
try:
yield conn
finally:
conn.close()
class OrderManager:
@staticmethod
def get_active_cart(phone: str) -> Optional[str]:
"""Obtiene el carrito activo de un cliente o crea uno nuevo"""
if not validate_phone(phone):
raise ValueError("Número de teléfono inválido")
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"""
SELECT order_id FROM orders
WHERE phone = ? AND status = 'in_cart'
ORDER BY created_at DESC LIMIT 1
""",
(phone,),
)
result = cursor.fetchone()
if result:
return result["order_id"]
order_id = str(uuid.uuid4())
cursor.execute(
"""
INSERT INTO orders (order_id, phone, status)
VALUES (?, ?, 'in_cart')
""",
(order_id, phone),
)
conn.commit()
return order_id
@staticmethod
def add_to_cart(phone: str, product_id: str, quantity: int, price: float, unit: str) -> bool:
"""Añade un producto al carrito del cliente"""
try:
order_id = OrderManager.get_active_cart(phone)
with get_db_connection() as conn:
cursor = conn.cursor()
# Verificar si el producto ya está en el carrito
cursor.execute(
"""
SELECT quantity FROM order_items
WHERE order_id = ? AND product_id = ?
""",
(order_id, product_id),
)
existing_item = cursor.fetchone()
if existing_item:
# Actualizar cantidad si ya existe
cursor.execute(
"""
UPDATE order_items
SET quantity = quantity + ?,
price = ?
WHERE order_id = ? AND product_id = ?
""",
(quantity, price, order_id, product_id),
)
else:
# Insertar nuevo item
cursor.execute(
"""
INSERT INTO order_items (order_id, product_id, quantity, price, unit)
VALUES (?, ?, ?, ?, ?)
""",
(order_id, product_id, quantity, price, unit),
)
# Actualizar total del carrito
cursor.execute(
"""
UPDATE orders
SET total = (
SELECT SUM(quantity * price)
FROM order_items
WHERE order_id = ?
)
WHERE order_id = ?
""",
(order_id, order_id),
)
conn.commit()
return True
except Exception as e:
print(f"Error adding to cart: {e}")
return False
@staticmethod
def remove_from_cart(phone: str, product_id: str) -> bool:
"""Elimina un producto del carrito"""
try:
order_id = OrderManager.get_active_cart(phone)
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"""
DELETE FROM order_items
WHERE order_id = ? AND product_id = ?
""",
(order_id, product_id),
)
# Actualizar total
cursor.execute(
"""
UPDATE orders
SET total = (
SELECT SUM(quantity * price)
FROM order_items
WHERE order_id = ?
)
WHERE order_id = ?
""",
(order_id, order_id),
)
conn.commit()
return True
except Exception as e:
print(f"Error removing from cart: {e}")
return False
@staticmethod
def get_cart_items(phone: str) -> List[Dict]:
"""Obtiene los items en el carrito del cliente"""
order_id = OrderManager.get_active_cart(phone)
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"""
SELECT * FROM order_items
WHERE order_id = ?
""",
(order_id,),
)
return [dict(row) for row in cursor.fetchall()]
@staticmethod
def confirm_order(phone: str, delivery_address: Optional[str] = None,
payment_method: Optional[str] = None, notes: Optional[str] = None) -> Tuple[bool, str]:
"""Confirma un pedido y lo marca como confirmado"""
try:
order_id = OrderManager.get_active_cart(phone)
with get_db_connection() as conn:
cursor = conn.cursor()
# Verificar que hay items en el carrito
cursor.execute("SELECT COUNT(*) FROM order_items WHERE order_id = ?", (order_id,))
if cursor.fetchone()[0] == 0:
return False, "El carrito está vacío"
# Actualizar estado de la orden
cursor.execute(
"""
UPDATE orders
SET status = 'confirmed',
delivery_address = ?,
payment_method = ?,
notes = ?,
delivery_status = 'pending',
updated_at = CURRENT_TIMESTAMP
WHERE order_id = ?
""",
(delivery_address, payment_method, notes, order_id),
)
conn.commit()
return True, order_id
except Exception as e:
print(f"Error confirming order: {e}")
return False, str(e)
@staticmethod
def get_order_history(phone: str) -> List[Dict]:
"""Obtiene el historial de pedidos del cliente"""
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"""
SELECT o.*,
COUNT(oi.id) as item_count,
GROUP_CONCAT(oi.quantity || 'x ' || oi.product_id) as items
FROM orders o
LEFT JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.phone = ? AND o.status != 'in_cart'
GROUP BY o.order_id
ORDER BY o.created_at DESC
""",
(phone,),
)
return [dict(row) for row in cursor.fetchall()]
@staticmethod
def update_delivery_status(order_id: str, status: str) -> bool:
"""Actualiza el estado de entrega de una orden"""
if status not in DELIVERY_STATES:
raise ValueError(f"Estado de entrega inválido. Debe ser uno de: {', '.join(DELIVERY_STATES)}")
try:
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"""
UPDATE orders
SET delivery_status = ?,
updated_at = CURRENT_TIMESTAMP
WHERE order_id = ?
""",
(status, order_id),
)
conn.commit()
return True
except Exception as e:
print(f"Error updating delivery status: {e}")
return False
@staticmethod
def apply_discount(order_id: str, discount_amount: float) -> bool:
"""Aplica un descuento al total de la orden"""
try:
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"""
UPDATE orders
SET discount_applied = ?,
total = (SELECT SUM(quantity * price) FROM order_items WHERE order_id = ?) - ?,
updated_at = CURRENT_TIMESTAMP
WHERE order_id = ?
""",
(discount_amount, order_id, discount_amount, order_id),
)
conn.commit()
return True
except Exception as e:
print(f"Error applying discount: {e}")
return False
@staticmethod
def get_order_details(order_id: str) -> Optional[Dict]:
"""Obtiene los detalles completos de una orden"""
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM orders WHERE order_id = ?", (order_id,))
order = cursor.fetchone()
if not order:
return None
cursor.execute("SELECT * FROM order_items WHERE order_id = ?", (order_id,))
items = cursor.fetchall()
order_dict = dict(order)
order_dict['items'] = [dict(item) for item in items]
return order_dict
@staticmethod
def merge_orders(phone: str, order_ids: List[str], new_address: Optional[str] = None) -> Tuple[bool, str]:
"""Crea un nuevo pedido combinando los productos de varios pedidos"""
try:
with get_db_connection() as conn:
cursor = conn.cursor()
# Verificar que todos los pedidos existen y son del mismo cliente
for order_id in order_ids:
cursor.execute(
"SELECT phone, status FROM orders WHERE order_id = ?",
(order_id,)
)
order = cursor.fetchone()
if not order or order[0] != phone:
return False, f"El pedido {order_id} no existe o no pertenece a este cliente"
if order[1] not in ['in_cart', 'confirmed']:
return False, f"El pedido {order_id} no se puede modificar en su estado actual"
# Crear nuevo pedido
new_order_id = str(uuid.uuid4())
cursor.execute(
"""
INSERT INTO orders (order_id, phone, status, delivery_address)
VALUES (?, ?, 'confirmed', ?)
""",
(new_order_id, phone, new_address)
)
# Copiar items de los pedidos originales
for order_id in order_ids:
cursor.execute(
"""
INSERT INTO order_items (order_id, product_id, quantity, price, unit)
SELECT ?, product_id, quantity, price, unit
FROM order_items WHERE order_id = ?
""",
(new_order_id, order_id)
)
# Actualizar total
cursor.execute(
"""
UPDATE orders
SET total = (
SELECT SUM(quantity * price)
FROM order_items
WHERE order_id = ?
)
WHERE order_id = ?
""",
(new_order_id, new_order_id)
)
conn.commit()
return True, new_order_id
except Exception as e:
print(f"Error merging orders: {e}")
return False, "Error al combinar los pedidos"
@staticmethod
def delete_order(phone: str, order_id: str) -> bool:
"""Elimina un pedido si está en estado permitido"""
try:
with get_db_connection() as conn:
cursor = conn.cursor()
# Verificar propiedad y estado del pedido
cursor.execute(
"SELECT status FROM orders WHERE order_id = ? AND phone = ?",
(order_id, phone)
)
order = cursor.fetchone()
if not order:
return False
if order[0] not in ['in_cart', 'confirmed']:
return False
# Eliminar items y pedido
cursor.execute("DELETE FROM order_items WHERE order_id = ?", (order_id,))
cursor.execute("DELETE FROM orders WHERE order_id = ?", (order_id,))
conn.commit()
return True
except Exception as e:
print(f"Error deleting order: {e}")
return False
@staticmethod
def modify_order_items(phone: str, order_id: str, items: List[Dict]) -> bool:
"""Modifica los items de un pedido existente"""
try:
with get_db_connection() as conn:
cursor = conn.cursor()
# Verificar propiedad y estado del pedido
cursor.execute(
"SELECT status FROM orders WHERE order_id = ? AND phone = ?",
(order_id, phone)
)
order = cursor.fetchone()
if not order or order[0] not in ['in_cart', 'confirmed']:
return False
# Eliminar items actuales
cursor.execute("DELETE FROM order_items WHERE order_id = ?", (order_id,))
# Insertar nuevos items
for item in items:
cursor.execute(
"""
INSERT INTO order_items (order_id, product_id, quantity, price, unit)
VALUES (?, ?, ?, ?, ?)
""",
(order_id, item['product_id'], item['quantity'], item['price'], item['unit'])
)
# Actualizar total
cursor.execute(
"""
UPDATE orders
SET total = (
SELECT SUM(quantity * price)
FROM order_items
WHERE order_id = ?
)
WHERE order_id = ?
""",
(order_id, order_id)
)
conn.commit()
return True
except Exception as e:
print(f"Error modifying order: {e}")
return False
# Inicializar la base de datos al importar el módulo
init_database()

View File

@@ -0,0 +1,370 @@
from langchain_core.tools import tool
from typing import Optional, List
from .db_manager import OrderManager
@tool
def add_to_cart(phone: str, product_id: str, quantity: int) -> str:
"""
Añade un producto al carrito del cliente.
Args:
phone: Número de teléfono del cliente
product_id: ID o nombre del producto
quantity: Cantidad a añadir
"""
# Primero intentar obtener el producto por ID o nombre
product = CatalogManager.get_product(product_id)
if not product:
# Si no se encuentra, intentar buscar por nombre exacto
product = CatalogManager.get_product_by_name(product_id)
if not product:
return f"❌ No se encontró el producto '{product_id}' en el catálogo. Por favor, verifica el nombre o ID del producto."
if product["stock"] < quantity:
return f"❌ Stock insuficiente. Solo hay {product['stock']} {product['unidad']} disponibles de {product['producto']}."
# Añadir al carrito
success = OrderManager.add_to_cart(
phone,
str(product["id"]),
quantity,
product["precio"],
product["unidad"]
)
if success:
remaining_stock = product["stock"] - quantity
response = f"✅ Se añadieron {quantity} {product['unidad']} de {product['producto']} al carrito."
# Advertencia de stock bajo
if remaining_stock < 10:
response += f"\n⚠️ Aviso: Solo quedan {remaining_stock} {product['unidad']} en stock."
# Sugerir productos relacionados
related_products = CatalogManager.search_products(product["categoria"])
if len(related_products) > 1:
response += "\n\n📦 También podría interesarte:"
for related in related_products[:3]:
if related["id"] != product["id"] and related["stock"] > 0:
response += f"\n- {related['producto']} ({related['unidad']} a ${related['precio']:,})"
return response
else:
return "❌ Hubo un error al añadir el producto al carrito. Por favor, intenta de nuevo."
@tool
def remove_from_cart(phone: str, product_id: str) -> str:
"""
Elimina un producto del carrito del cliente.
Args:
phone: Número de teléfono del cliente
product_id: ID o nombre del producto a eliminar
"""
product = CatalogManager.get_product(product_id)
if not product:
product = CatalogManager.get_product_by_name(product_id)
if not product:
return f"❌ No se encontró el producto '{product_id}' en el catálogo."
success = OrderManager.remove_from_cart(phone, str(product["id"]))
if success:
return f"✅ Se eliminó {product['producto']} del carrito."
else:
return "❌ No se pudo eliminar el producto del carrito. ¿Está seguro que el producto está en su carrito?"
@tool
def view_cart(phone: str) -> str:
"""
Muestra los productos en el carrito del cliente.
Args:
phone: Número de teléfono del cliente
"""
items = OrderManager.get_cart_items(phone)
if not items:
return "El carrito está vacío."
result = "🛒 Productos en el carrito:\n\n"
total = 0
for item in items:
product = CatalogManager.get_product(item["product_id"])
if product:
subtotal = item["quantity"] * item["price"]
total += subtotal
result += f"- {product['producto']}\n"
result += f" Cantidad: {item['quantity']} {item['unit']}\n"
result += f" Precio unitario: ${item['price']:,}\n"
result += f" Subtotal: ${subtotal:,}\n\n"
result += f"Total del carrito: ${total:,}"
return result
@tool
def confirm_order(phone: str, delivery_address: Optional[str] = None,
payment_method: Optional[str] = None, notes: Optional[str] = None) -> str:
"""
Confirma el pedido actual del cliente.
Args:
phone: Número de teléfono del cliente
delivery_address: Dirección de entrega (opcional)
payment_method: Método de pago (opcional)
notes: Notas adicionales para el pedido (opcional)
"""
success, result = OrderManager.confirm_order(
phone, delivery_address, payment_method, notes
)
if success:
order_details = OrderManager.get_order_details(result)
response = "✅ ¡Pedido confirmado exitosamente!\n\n"
response += "📋 Resumen del pedido:\n"
# Detalles de entrega
if delivery_address:
response += f"📍 Dirección de entrega: {delivery_address}\n"
if payment_method:
response += f"💳 Método de pago: {payment_method}\n"
if notes:
response += f"📝 Notas: {notes}\n"
response += "\nProductos:\n"
for item in order_details['items']:
product = CatalogManager.get_product(item['product_id'])
response += f"- {item['quantity']} {item['unit']} de {product['producto']} a ${item['price']:,} c/u\n"
response += f"\n💰 Total: ${order_details['total']:,}"
if delivery_address:
response += "\n\n🚚 El pedido será preparado y enviado a la dirección proporcionada."
response += "\nRecibirás actualizaciones sobre el estado de tu pedido."
else:
response += "\n\n🏪 El pedido estará listo para retirar en tienda."
return response
else:
return f"❌ Error al confirmar el pedido: {result}"
@tool
def view_order_history(phone: str) -> str:
"""
Muestra el historial de órdenes del cliente.
Args:
phone: Número de teléfono del cliente
"""
orders = OrderManager.get_order_history(phone)
if not orders:
return "No hay pedidos registrados para este número."
result = "📚 Historial de pedidos:\n\n"
for order in orders:
result += f"🔸 Pedido #{order['order_id'][:8]}\n"
result += f" Fecha: {order['created_at']}\n"
result += f" Estado: {order['status']}\n"
if order['delivery_status']:
result += f" Estado de entrega: {order['delivery_status']}\n"
result += f" Total: ${order['total']:,}\n"
if order['delivery_address']:
result += f" Dirección: {order['delivery_address']}\n"
if order['notes']:
result += f" Notas: {order['notes']}\n"
result += "\n"
return result
@tool
def update_delivery_status(phone: str, order_id: str, status: str) -> str:
"""
Actualiza el estado de entrega de una orden.
Args:
phone: Número de teléfono del cliente
order_id: ID de la orden
status: Nuevo estado de entrega
"""
success = OrderManager.update_delivery_status(order_id, status)
if success:
return f"✅ Estado de entrega actualizado a: {status}"
return "❌ Error al actualizar el estado de entrega"
@tool
def apply_discount(phone: str, discount_amount: float) -> str:
"""
Aplica un descuento al carrito actual.
Args:
phone: Número de teléfono del cliente
discount_amount: Cantidad del descuento
"""
order_id = OrderManager.get_active_cart(phone)
success = OrderManager.apply_discount(order_id, discount_amount)
if success:
return f"✅ Descuento de ${discount_amount:,} aplicado al carrito"
return "❌ Error al aplicar el descuento"
@tool
def get_order_status(phone: str, order_id: str) -> str:
"""
Obtiene el estado actual de una orden específica.
Args:
phone: Número de teléfono del cliente
order_id: ID de la orden
"""
order = OrderManager.get_order_details(order_id)
if not order:
return f"No se encontró la orden con ID {order_id}"
result = f"📦 Estado del pedido #{order_id[:8]}:\n"
result += f"Estado: {order['status']}\n"
if order['delivery_status']:
result += f"Estado de entrega: {order['delivery_status']}\n"
result += f"Total: ${order['total']:,}\n"
if order['delivery_address']:
result += f"Dirección de entrega: {order['delivery_address']}\n"
return result
@tool
def merge_orders(phone: str, order_ids: List[str], delivery_address: Optional[str] = None) -> str:
"""
Combina varios pedidos en uno nuevo.
Args:
phone: Número de teléfono del cliente
order_ids: Lista de IDs de pedidos a combinar
delivery_address: Nueva dirección de entrega (opcional)
"""
success, result = OrderManager.merge_orders(phone, order_ids, delivery_address)
if success:
order_details = OrderManager.get_order_details(result)
response = "✅ ¡Pedidos combinados exitosamente!\n\n"
response += "📋 Resumen del nuevo pedido:\n"
if delivery_address:
response += f"📍 Dirección de entrega: {delivery_address}\n"
response += "\nProductos:\n"
for item in order_details['items']:
product = CatalogManager.get_product(item['product_id'])
response += f"- {item['quantity']} {item['unit']} de {product['producto']} a ${item['price']:,} c/u\n"
response += f"\n💰 Total: ${order_details['total']:,}"
return response
else:
return f"❌ Error: {result}"
@tool
def delete_order(phone: str, order_id: str) -> str:
"""
Elimina un pedido si está en estado permitido.
Args:
phone: Número de teléfono del cliente
order_id: ID del pedido a eliminar
"""
success = OrderManager.delete_order(phone, order_id)
if success:
return f"✅ El pedido #{order_id[:8]} ha sido eliminado exitosamente."
else:
return "❌ No se pudo eliminar el pedido. Solo se pueden eliminar pedidos en estado 'en carrito' o 'confirmado'."
@tool
def modify_order(phone: str, order_id: str, modifications: str) -> str:
"""
Modifica los productos de un pedido existente.
Args:
phone: Número de teléfono del cliente
order_id: ID del pedido a modificar
modifications: Descripción de las modificaciones (ej: "agregar 2 kg de arroz, quitar café")
"""
# Obtener detalles actuales del pedido
current_order = OrderManager.get_order_details(order_id)
if not current_order:
return f"❌ No se encontró el pedido #{order_id[:8]}"
# Procesar las modificaciones (esto es un ejemplo simplificado)
try:
# Aquí iría la lógica para interpretar las modificaciones
# Por ahora solo mostraremos un mensaje informativo
return (
"Para modificar el pedido, por favor especifica exactamente qué cambios deseas hacer:\n"
"- Para agregar productos: 'agregar X unidades de [producto]'\n"
"- Para quitar productos: 'quitar [producto]'\n"
"- Para cambiar cantidades: 'cambiar [producto] a X unidades'\n"
"\nPedido actual:\n" +
"\n".join(f"- {item['quantity']} {item['unit']} de {CatalogManager.get_product(item['product_id'])['producto']}"
for item in current_order['items'])
)
except Exception as e:
return f"❌ Error al modificar el pedido: {str(e)}"
@tool
def get_order_products(phone: str, order_id: str) -> str:
"""
Obtiene la lista detallada de productos en un pedido.
Args:
phone: Número de teléfono del cliente
order_id: ID del pedido
"""
# Limpiar el ID del pedido (remover # si existe)
clean_order_id = order_id.strip().replace('#', '')
order = OrderManager.get_order_details(clean_order_id)
if not order:
return f"❌ No se encontró el pedido #{clean_order_id[:8]}"
if order['phone'] != phone:
return "❌ Este pedido no pertenece a este cliente"
if not order.get('items'):
return f" El pedido #{clean_order_id[:8]} no tiene productos registrados"
result = f"📦 Productos en el pedido #{clean_order_id[:8]}:\n\n"
total = 0
for item in order['items']:
product = CatalogManager.get_product(item['product_id'])
if product:
subtotal = item['quantity'] * item['price']
total += subtotal
result += f"- {item['quantity']} {item['unit']} de {product['producto']}\n"
result += f" 💵 Precio unitario: ${item['price']:,}\n"
result += f" 💰 Subtotal: ${subtotal:,}\n\n"
else:
result += f"- {item['quantity']} {item['unit']} de producto no encontrado (ID: {item['product_id']})\n"
result += f"💰 Total del pedido: ${order['total']:,}\n"
if order.get('discount_applied', 0) > 0:
result += f"🏷️ Descuento aplicado: ${order['discount_applied']:,}\n"
if order.get('delivery_address'):
result += f"📍 Dirección de entrega: {order['delivery_address']}\n"
if order.get('delivery_status'):
result += f"🚚 Estado de entrega: {order['delivery_status']}\n"
return result
# Lista de todas las herramientas disponibles
tools = [
add_to_cart,
remove_from_cart,
view_cart,
confirm_order,
view_order_history,
update_delivery_status,
apply_discount,
get_order_status,
merge_orders,
delete_order,
modify_order,
get_order_products,
]

View File

@@ -0,0 +1,243 @@
from langchain_core.tools import tool
from typing import Optional, List
import requests
import json
url = "http://192.168.0.25:8000"
key = "9a9ffc430146447d81e6698240199a4be2b0e774cb18474999d0f60e33b5b1eb1cfff9d9141346a98844879b5a9e787489c891ddc8fb45cc903b7244cab64fb1"
db = "tryton"
application_name = "sale_don_confiao"
url_don_confiao = "{}/{}/{}".format(url, db, application_name)
url_order = "{}/{}/{}".format(url, db, "sale_order")
#@tool
def create_party(
party_full_name: str,
contact_method_type: str,
contact_method_value: str,
):
"""
Crea un nuevo cliente (party) en el sistema.
Args:
party_full_name (str): Nombre completo del cliente.
contact_method_type (str): Tipo de método de contacto (ej. 'email', 'phone').
contact_method_value (str): Valor del método de contacto (ej. dirección de email o número de teléfono).
Returns:
requests.Response: La respuesta del servidor que contiene la información del cliente creado.
"""
url = "http://192.168.0.25:8000"
key = "9a9ffc430146447d81e6698240199a4be2b0e774cb18474999d0f60e33b5b1eb1cfff9d9141346a98844879b5a9e787489c891ddc8fb45cc903b7244cab64fb1"
db = "tryton"
application_name = "sale_don_confiao"
url_don_confiao = "{}/{}/{}".format(url, db, application_name)
url_order = "{}/{}/{}".format(url, db, "sale_order")
url_order = url_order.replace("sale_order", "sale_don_confiao")
data = {
"name": party_full_name,
"contact_mechanisms": [
["create", [{"type": contact_method_type, "value": contact_method_value}]]
],
}
response = requests.post(
url_order + "/parties",
headers={"Authorization": f"bearer {key}"},
data=json.dumps(data),
)
return json.loads(response.text)
@tool
def create_sale_order(
party: int, pickup_location: str = "on_site", lines: Optional[List] = None
) -> int:
"""
Crea una nueva orden de venta en el sistema.
Args:
party (int): El ID del cliente.
pickup_location (str, optional): Ubicación de recogida. Valores posibles:
- "on_site": Recoger en el local
- "at_home": Entrega a domicilio
Por defecto es "on_site".
lines (List, optional): Lista de líneas de la orden. Por defecto es None.
Cada línea debe ser una lista con el formato: ["create", [{"product": str, "unit": str, "quantity": str, "unitprice": str}]]
Donde:
- product (str): ID del producto
- unit (str): ID de la unidad de medida
- quantity (str): Cantidad del producto
- unitprice (str): Precio unitario del producto
Ejemplo:
lines=[["create", [{
"product": "1",
"unit": "1",
"quantity": "5",
"unitprice": "10"
}]]]
Returns:
int: El ID de la orden creada
"""
data = {
"party": party,
"pickup_location": pickup_location,
}
if lines:
data["lines"] = lines
response = requests.post(
url_order + "/order",
headers={
"Authorization": f"bearer {key}",
},
data=json.dumps(data),
)
# Extraer y retornar directamente el ID de la orden
return json.loads(json.loads(response.text)[0]).get("id")
@tool
def search_sale_order(order_id: int):
"""
Busca una orden de venta específica en el sistema.
Args:
order_id (int): El ID de la orden de venta a buscar.
Returns:
requests.Response: La respuesta del servidor que contiene:
- party (int): ID del cliente
- id (int): ID de la orden
- lines (List): Lista de líneas de la orden
Ejemplo de respuesta:
[{"party": 2573, "id": 22, "lines": []}]
"""
response_sale = requests.get(
url_order + f"/order/{order_id}",
headers={
"Authorization": f"bearer {key}",
},
)
return response_sale
@tool
def add_lines_to_order(
order_id: int, product: str, unit: str, quantity: str, unitprice: str
):
"""
Agrega una línea de producto a una orden existente.
Args:
order_id (int): ID de la orden a la que se agregará la línea.
product (str): ID del producto a agregar.
unit (str): ID de la unidad de medida del producto.
quantity (str): Cantidad del producto a agregar.
unitprice (str): Precio unitario del producto.
Returns:
requests.Response: La respuesta del servidor que contiene:
- order_lines (List[int]): Lista de IDs de las líneas creadas
- status (str): Estado de la operación ('success' si fue exitosa)
- message (str): Mensaje descriptivo del resultado
Ejemplo de respuesta:
{"order_lines": [1], "status": "success", "message": "Order lines created successfully"}
"""
data = {
"order": order_id,
"product": product,
"unit": unit,
"quantity": quantity,
"unitprice": unitprice,
}
response = requests.post(
url_order + f"/{order_id}/order_line",
headers={
"Authorization": f"bearer {key}",
},
data=json.dumps(data),
)
return response
@tool
def search_associate_party_to_contact_mechanism(contact_mechanism: str):
"""
Busca un cliente en el sistema por un metodo de contacto que pueda ser un numero de celular o un correo electronico.
Args:
contact_mechanism (str): El número de contacto del cliente.
Returns:
requests.Response: La respuesta del servidor que contiene:
- id (int): ID de la asociación en la base de datos
- associate_party (int): ID del cliente asociado (Party)
- status (str): Estado de la operación ('success' si fue exitosa)
- type (str): Tipo de contacto asociado
- message (str): Mensaje descriptivo del resultado
Ejemplo de respuesta:
{"id": 1, "associate_party": 1, "status": "success", "type": "phone", "message": "Associate Party found"}
"""
response = requests.get(
url_order + f"/associate_party/{contact_mechanism}",
headers={
"Authorization": f"bearer {key}",
},
)
return response
tools = [
create_party,
create_sale_order,
search_sale_order,
add_lines_to_order,
search_associate_party_to_contact_mechanism,
]
# if __name__ == "__main__":
# # Crear una orden de venta
# party = 2573
# pickup_location = "at_home"
# order_id = create_sale_order(party=party, pickup_location=pickup_location)
# print(f"\nOrden creada con ID: {order_id}")
# # Agregar líneas a la orden
# product = "1"
# unit = "1"
# quantity = "3"
# unitprice = "15"
# add_line_response = add_lines_to_order(order_id, product, unit, quantity, unitprice)
# print(f"\nRespuesta al agregar línea: {add_line_response.text}")
# # Verificar la orden actualizada
# updated_order = search_sale_order(order_id)
# print(f"\nOrden actualizada: {updated_order.text}")
# # Agregar otra línea a la orden
# product = "2"
# unit = "1"
# quantity = "3"
# unitprice = "15"
# add_line_response = add_lines_to_order(order_id, product, unit, quantity, unitprice)
# print(f"\nRespuesta al agregar línea: {add_line_response.text}")
# # Verificar la orden actualizada
# updated_order = search_sale_order(order_id)
# print(f"\nOrden actualizada: {updated_order.text}")