feat: add agents/app
This commit is contained in:
35
agents/app/langgraph_tools/tools/catalog/catalog_class.py
Normal file
35
agents/app/langgraph_tools/tools/catalog/catalog_class.py
Normal file
@@ -0,0 +1,35 @@
|
||||
class CatalogTools:
|
||||
def list_products(self):
|
||||
"""
|
||||
Lista todos los productos disponibles en el catálogo con su disponibilidad
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
def search_products(self):
|
||||
"""
|
||||
Busca productos en el catálogo que coincidan con la consulta
|
||||
"""
|
||||
pass
|
||||
|
||||
def check_price(self):
|
||||
"""
|
||||
Verifica el precio de un producto específico
|
||||
"""
|
||||
pass
|
||||
|
||||
def check_availability(self):
|
||||
"""
|
||||
Verifica la disponibilidad de un producto espécifico
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_product_details(self):
|
||||
"""
|
||||
Obtiene detalles completos de un producto
|
||||
"""
|
||||
pass
|
||||
|
||||
def list_tools(self):
|
||||
"""Retorna los metodos de esta clase en una lista"""
|
||||
pass
|
||||
190
agents/app/langgraph_tools/tools/catalog/catalog_tools.py
Normal file
190
agents/app/langgraph_tools/tools/catalog/catalog_tools.py
Normal file
@@ -0,0 +1,190 @@
|
||||
from langchain_core.tools import tool
|
||||
from typing import List, Dict, Optional
|
||||
from app.seller.catalog_tools import CatalogTrytonTools
|
||||
import json
|
||||
import requests
|
||||
|
||||
|
||||
url = "http://192.168.0.25:8000"
|
||||
key = "9a9ffc430146447d81e6698240199a4be2b0e774cb18474999d0f60e33b5b1eb1cfff9d9141346a98844879b5a9e787489c891ddc8fb45cc903b7244cab64fb1"
|
||||
db = "tryton"
|
||||
application_name = "sale_don_confiao"
|
||||
|
||||
|
||||
catalog = CatalogTrytonTools(url, application_name, key, db)
|
||||
|
||||
|
||||
@tool
|
||||
def list_products() -> str:
|
||||
"""
|
||||
Lista todos los productos disponibles en el catálogo con su disponibilidad
|
||||
"""
|
||||
response = catalog.list_products()
|
||||
|
||||
products: str = ""
|
||||
|
||||
for product in response:
|
||||
id = product["id"]
|
||||
name = product["name"]
|
||||
id_unit_measurement = product["default_uom."]["id"]
|
||||
products += f"- id: {id} - Nombre: {name} - ID Unidad de Medida: {id_unit_measurement} \n"
|
||||
|
||||
return products
|
||||
|
||||
|
||||
@tool
|
||||
def search_products(product_name: str) -> str:
|
||||
"""
|
||||
Busca productos en el catálogo que coincidan con el nombre del producto proporcionado.
|
||||
|
||||
Parámetros:
|
||||
- product_name (str): El nombre del producto a buscar.
|
||||
|
||||
Devuelve:
|
||||
- str: Una cadena de texto que lista los IDs, nombres y precios de los productos encontrados,
|
||||
formateada con cada producto en una línea separada.
|
||||
"""
|
||||
|
||||
response = catalog.search_products(product_name)
|
||||
precios: str = ""
|
||||
|
||||
for product in response:
|
||||
id = product["id"]
|
||||
name = product["name"]
|
||||
precio = product["template."]["list_price"]["decimal"]
|
||||
id_unit_measurement = product["default_uom."]["id"]
|
||||
|
||||
precios += f"- id: {id} - Nombre: {name}: ${precio} - ID Unidad de Medida: {id_unit_measurement}\n"
|
||||
|
||||
|
||||
return precios
|
||||
|
||||
|
||||
@tool
|
||||
def check_price(product_name: str) -> str:
|
||||
"""
|
||||
Verifica el precio de un producto específico
|
||||
"""
|
||||
response = catalog.search_products(product_name)
|
||||
precios: str = ""
|
||||
|
||||
for product in response:
|
||||
id = product["id"]
|
||||
name = product["name"]
|
||||
precio = product["template."]["list_price"]["decimal"]
|
||||
id_unit_measurement = product["default_uom."]["id"]
|
||||
|
||||
precios += f"- id: {id} - Nombre: {name}: ${precio} - ID Unidad de Medida: {id_unit_measurement}\n"
|
||||
|
||||
return precios
|
||||
|
||||
|
||||
|
||||
@tool
|
||||
def check_availability(product_name: str) -> str:
|
||||
"""
|
||||
Verifica la disponibilidad de un producto específico
|
||||
"""
|
||||
response = catalog.search_products("Papa")
|
||||
disponibilidad: str = ""
|
||||
|
||||
for product in response:
|
||||
id = product["id"]
|
||||
name = product["name"]
|
||||
stock = product["quantity"]
|
||||
id_unit_measurement = product["default_uom."]["id"]
|
||||
|
||||
disponibilidad += f"- id: {id} - Nombre: {name} - Stock: {stock} - ID Unidad de Medida: {id_unit_measurement}\n"
|
||||
|
||||
return disponibilidad
|
||||
|
||||
|
||||
|
||||
@tool
|
||||
def get_product_details(product_name: str) -> str:
|
||||
"""
|
||||
Obtiene los detalles completos de un producto
|
||||
"""
|
||||
products = CatalogManager.search_products(product_name)
|
||||
if products:
|
||||
product = products[0] # Tomar el primer producto que coincida
|
||||
stock_status = "En stock" if product["stock"] > 0 else "Agotado"
|
||||
return f"""
|
||||
Detalles del producto:
|
||||
- Producto: {product['producto']}
|
||||
- Categoría: {product['categoria']}
|
||||
- Unidad de medida: {product['unidad']}
|
||||
- id unidad de medida: {product["default_uom."]["id"]}
|
||||
- Precio: ${product['precio']:,}
|
||||
- Estado: {stock_status} ({product['stock']} unidades)
|
||||
"""
|
||||
return f"No se encontró el producto '{product_name}' en nuestro catálogo."
|
||||
|
||||
|
||||
@tool
|
||||
def list_category_products(category_name: str) -> str:
|
||||
"""
|
||||
Lista todos los productos de una categoría específica
|
||||
"""
|
||||
products = CatalogManager.search_products(category_name)
|
||||
if not products:
|
||||
return f"No se encontraron productos en la categoría '{category_name}'."
|
||||
|
||||
result = f"Productos en la categoría {category_name}:\n"
|
||||
for product in products:
|
||||
if product["categoria"] == category_name:
|
||||
stock_status = " Disponible" if product["stock"] > 0 else " Agotado"
|
||||
result += f"- {product['producto']} | {product['unidad']} | ${product['precio']:,} | {stock_status}\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@tool
|
||||
def get_low_stock_products(threshold: int = 10) -> str:
|
||||
"""
|
||||
Lista productos con stock bajo (por defecto, menos de 10 unidades)
|
||||
"""
|
||||
products = CatalogManager.list_all_products()
|
||||
low_stock = [p for p in products if p["stock"] <= threshold]
|
||||
|
||||
if not low_stock:
|
||||
return f"No hay productos con stock menor a {threshold} unidades."
|
||||
|
||||
result = f"Productos con stock bajo (menos de {threshold} unidades):\n"
|
||||
for product in low_stock:
|
||||
result += f"- {product['producto']}: {product['stock']} {product['unidad']}(s) restantes\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@tool
|
||||
def get_products_by_price_range(min_price: float, max_price: float) -> str:
|
||||
"""
|
||||
Busca productos dentro de un rango de precios específico
|
||||
"""
|
||||
products = CatalogManager.list_all_products()
|
||||
filtered_products = [p for p in products if min_price <= p["precio"] <= max_price]
|
||||
|
||||
if not filtered_products:
|
||||
return f"No se encontraron productos entre ${min_price:,} y ${max_price:,}."
|
||||
|
||||
result = f"Productos entre ${min_price:,} y ${max_price:,}:\n"
|
||||
for product in filtered_products:
|
||||
result += (
|
||||
f"- {product['producto']} | {product['unidad']} | ${product['precio']:,}\n"
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Lista de todas las herramientas disponibles
|
||||
tools = [
|
||||
list_products,
|
||||
search_products,
|
||||
check_price,
|
||||
check_availability,
|
||||
# get_product_details,
|
||||
# list_category_products,
|
||||
# get_low_stock_products,
|
||||
# get_products_by_price_range,
|
||||
]
|
||||
66
agents/app/langgraph_tools/tools/general_info.py
Normal file
66
agents/app/langgraph_tools/tools/general_info.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import yaml
|
||||
from langchain_core.tools import tool
|
||||
from datetime import datetime
|
||||
import pytz
|
||||
import os
|
||||
|
||||
# Obtener la ruta del directorio actual
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
yaml_path = os.path.join(current_dir, "store_info.yaml")
|
||||
|
||||
with open(yaml_path, "r") as f:
|
||||
STORE_INFO = yaml.safe_load(f)
|
||||
|
||||
|
||||
@tool
|
||||
def get_store_hours() -> str:
|
||||
"""Obtiene el horario de la tienda"""
|
||||
return STORE_INFO["store"]["hours"]
|
||||
|
||||
|
||||
@tool
|
||||
def get_store_location() -> str:
|
||||
"""Obtiene la ubicación de la tienda"""
|
||||
return STORE_INFO["store"]["location"]
|
||||
|
||||
|
||||
@tool
|
||||
def get_contact_info() -> dict:
|
||||
"""Obtiene la información de contacto"""
|
||||
return STORE_INFO["store"]["contact"]
|
||||
|
||||
|
||||
@tool
|
||||
def get_about_info() -> str:
|
||||
"""Obtiene el about de la tienda"""
|
||||
return STORE_INFO["store"]["about"]
|
||||
|
||||
|
||||
@tool
|
||||
def get_link_page() -> str:
|
||||
"""Obtiene la pagina web de la tienda"""
|
||||
return STORE_INFO["store"]["page"]
|
||||
|
||||
|
||||
def get_time():
|
||||
"""
|
||||
Retorna la hora actual en Bogotá, Colombia.
|
||||
"""
|
||||
# Definir la zona horaria de Bogotá
|
||||
bogota_tz = pytz.timezone("America/Bogota")
|
||||
|
||||
# Obtener la hora actual en Bogotá
|
||||
hora_actual = datetime.now(bogota_tz)
|
||||
|
||||
# Formatear la hora en un formato legible
|
||||
return hora_actual.strftime("%H:%M:%S")
|
||||
|
||||
|
||||
tools = [
|
||||
get_store_hours,
|
||||
get_store_location,
|
||||
get_contact_info,
|
||||
get_about_info,
|
||||
get_link_page,
|
||||
get_time,
|
||||
]
|
||||
476
agents/app/langgraph_tools/tools/orders/db_manager.py
Normal file
476
agents/app/langgraph_tools/tools/orders/db_manager.py
Normal 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()
|
||||
370
agents/app/langgraph_tools/tools/orders/order_tools.py
Normal file
370
agents/app/langgraph_tools/tools/orders/order_tools.py
Normal 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,
|
||||
]
|
||||
243
agents/app/langgraph_tools/tools/orders/order_tools_2.py
Normal file
243
agents/app/langgraph_tools/tools/orders/order_tools_2.py
Normal 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}")
|
||||
20
agents/app/langgraph_tools/tools/store_info.yaml
Normal file
20
agents/app/langgraph_tools/tools/store_info.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
store:
|
||||
hours: "Lunes a Viernes: 8:00 AM - 8:00 PM | Sábados: 9:00 AM - 6:00 PM | Domingos y Festivos: 10:00 AM - 4:00 PM"
|
||||
location: "Carrera 53 #42-81, 2do piso, Diagonal al Parque del Periodista, Medellín, (Col)"
|
||||
contact:
|
||||
phone: "+57 302 356 77 97"
|
||||
whatsapp: "+57 302 356 77 97"
|
||||
email: "info@recreo.red"
|
||||
|
||||
about: |
|
||||
Acerca de Nosotros
|
||||
La Corporación Centro Taller Recreo le apuesta a la Economía Solidaria como una herramienta
|
||||
para establecer relaciones fundadas en el compartir, la colectividad y el consumo responsable
|
||||
con la colectividad y el medio ambiente; para trascender el competir, el individualismo y el
|
||||
consumismo. De esta manera, buscamos promover valores solidarios como la responsabilidad, el
|
||||
respeto, la ayuda mutua, la confianza y la equidad.
|
||||
|
||||
Una de nuestras acciones más importantes es la consolidación del Circuito Cooperativo Tienda
|
||||
La Ilusión, CIRCOOTIL. Por medio del Circuito se tejen puentes campo-ciudad aunando esfuerzos
|
||||
de productores campesinos, tenderos y consumidores concientes.
|
||||
page: "https://recreo.red/"
|
||||
Reference in New Issue
Block a user