testing_multi_agent / src /tools /invoice.py
adilpanwar's picture
Upload 16 files
927c050 verified
Raw
History Blame Contribute Delete
6.45 kB
"""Invoice information tools for the multi-agent system."""
import logging
from langchain_core.tools import tool
from src.db.database import run_query_safe
logger = logging.getLogger(__name__)
def _safe_int(value: str, label: str = "value") -> int:
try:
return int(value)
except (ValueError, TypeError):
raise ValueError(f"Invalid {label}: '{value}'. Please provide a numeric value.")
@tool
def get_invoices_by_customer_sorted_by_date(customer_id: str) -> str:
"""
Look up all invoices for a customer using their ID.
Returns invoices sorted by date (most recent first).
"""
logger.info(f"TOOL_CALL: get_invoices_by_customer_sorted_by_date | customer_id={customer_id}")
try:
result = run_query_safe(
"""
SELECT InvoiceId, CustomerId, InvoiceDate, BillingAddress, BillingCity,
BillingState, BillingCountry, BillingPostalCode, Total
FROM Invoice
WHERE CustomerId = :customer_id
ORDER BY InvoiceDate DESC;
""",
{"customer_id": _safe_int(customer_id, "customer ID")},
)
logger.info(f"TOOL_RESULT: get_invoices_by_customer_sorted_by_date | result_length={len(result)}")
if result == "[]":
return f"No invoices found for customer {customer_id}."
return result
except Exception as e:
logger.error(f"Error in get_invoices_by_customer_sorted_by_date: {e}")
return f"Error retrieving invoices for customer {customer_id}. Please try again."
@tool
def get_invoice_line_items_sorted_by_price(customer_id: str) -> str:
"""
Look up all purchased line items for a customer, sorted by unit price (highest first).
Each row is a single purchased track (NOT a full invoice). An invoice with 5 tracks
will appear as 5 separate rows, each showing the track name, unit price, and quantity.
"""
logger.info(f"TOOL_CALL: get_invoice_line_items_sorted_by_price | customer_id={customer_id}")
try:
result = run_query_safe(
"""
SELECT Invoice.InvoiceId, Invoice.InvoiceDate, Invoice.Total AS InvoiceTotal,
Track.Name AS TrackName, InvoiceLine.UnitPrice, InvoiceLine.Quantity
FROM Invoice
JOIN InvoiceLine ON Invoice.InvoiceId = InvoiceLine.InvoiceId
JOIN Track ON InvoiceLine.TrackId = Track.TrackId
WHERE Invoice.CustomerId = :customer_id
ORDER BY InvoiceLine.UnitPrice DESC;
""",
{"customer_id": _safe_int(customer_id, "customer ID")},
)
logger.info(f"TOOL_RESULT: get_invoice_line_items_sorted_by_price | result_length={len(result)}")
if result == "[]":
return f"No purchase records found for customer {customer_id}."
return result
except Exception as e:
logger.error(f"Error in get_invoice_line_items_sorted_by_price: {e}")
return f"Error retrieving purchase records for customer {customer_id}. Please try again."
@tool
def get_employee_by_invoice_and_customer(invoice_id: str, customer_id: str) -> str:
"""
Find the employee (support rep) associated with a specific invoice and customer.
Returns employee full name, title, and email.
"""
logger.info(f"TOOL_CALL: get_employee_by_invoice_and_customer | invoice_id={invoice_id}, customer_id={customer_id}")
try:
result = run_query_safe(
"""
SELECT Employee.FirstName, Employee.LastName, Employee.Title, Employee.Email
FROM Employee
JOIN Customer ON Customer.SupportRepId = Employee.EmployeeId
JOIN Invoice ON Invoice.CustomerId = Customer.CustomerId
WHERE Invoice.InvoiceId = :invoice_id AND Invoice.CustomerId = :customer_id;
""",
{"invoice_id": _safe_int(invoice_id, "invoice ID"), "customer_id": _safe_int(customer_id, "customer ID")},
)
logger.info(f"TOOL_RESULT: get_employee_by_invoice_and_customer | result_length={len(result)}")
if result == "[]":
return f"No employee found for invoice ID {invoice_id} and customer ID {customer_id}."
return result
except Exception as e:
logger.error(f"Error in get_employee_by_invoice_and_customer: {e}")
return f"Error finding employee for invoice {invoice_id}. Please try again."
@tool
def get_invoice_line_items(invoice_id: str, customer_id: str) -> str:
"""
Get the detailed line items (tracks purchased) for a specific invoice.
Returns full track details for each purchased item.
"""
logger.info(f"TOOL_CALL: get_invoice_line_items | invoice_id={invoice_id}, customer_id={customer_id}")
try:
result = run_query_safe(
"""
SELECT Track.TrackId,
Track.Name AS TrackName,
Artist.Name AS ArtistName,
Album.Title AS AlbumTitle,
Genre.Name AS GenreName,
Track.Composer,
Track.Milliseconds,
ROUND(Track.Milliseconds / 60000.0, 1) AS DurationMinutes,
InvoiceLine.UnitPrice,
InvoiceLine.Quantity
FROM InvoiceLine
JOIN Invoice ON InvoiceLine.InvoiceId = Invoice.InvoiceId
JOIN Track ON InvoiceLine.TrackId = Track.TrackId
LEFT JOIN Album ON Track.AlbumId = Album.AlbumId
LEFT JOIN Artist ON Album.ArtistId = Artist.ArtistId
LEFT JOIN Genre ON Track.GenreId = Genre.GenreId
WHERE Invoice.InvoiceId = :invoice_id AND Invoice.CustomerId = :customer_id
ORDER BY Track.Name;
""",
{"invoice_id": _safe_int(invoice_id, "invoice ID"), "customer_id": _safe_int(customer_id, "customer ID")},
)
logger.info(f"TOOL_RESULT: get_invoice_line_items | result_length={len(result)}")
if result == "[]":
return f"No line items found for invoice {invoice_id} (customer {customer_id})."
return result
except Exception as e:
logger.error(f"Error in get_invoice_line_items: {e}")
return f"Error retrieving line items for invoice {invoice_id}. Please try again."
invoice_tools = [
get_invoices_by_customer_sorted_by_date,
get_invoice_line_items_sorted_by_price,
get_employee_by_invoice_and_customer,
get_invoice_line_items,
]