trace / environments /trace_env /tools /report_tool.py
Ayush
Update
4156f51
Raw
History Blame Contribute Delete
3.59 kB
"""
environments/trace_env/tools/report_tool.py
Generates a DOCX report containing a table of financial transactions.
"""
import os
from docx import Document
from docx.shared import Inches, Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
def export_transactions_to_docx(transactions: list[dict], output_path: str = "financial_report.docx") -> str:
"""
Export a list of parsed transactions into a formatted DOCX table.
Args:
transactions: List of transaction dictionaries.
output_path: Path where the DOCX file will be saved.
Returns:
The absolute path to the generated DOCX file.
"""
doc = Document()
# Title
title = doc.add_heading("Financial Transactions Audit Report", 0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc.add_paragraph(f"Total Transactions: {len(transactions)}")
# Calculate total spend
import re
total_spend = 0.0
for t in transactions:
amount_str = re.sub(r'[^\d.]', '', t.get("total") or "")
amount = float(amount_str) if amount_str else 0.0
total_spend += amount
doc.add_paragraph(f"Total Spend: ₹{total_spend:,.2f}")
# Create Table
table = doc.add_table(rows=1, cols=7) # Increased to 7 columns
table.style = 'Table Grid'
# Set headers
hdr_cells = table.rows[0].cells
headers = ["Date", "Vendor", "Category", "Amount", "Method", "Source", "Notes"]
for i, header_text in enumerate(headers):
hdr_cells[i].text = header_text
for paragraph in hdr_cells[i].paragraphs:
for run in paragraph.runs:
run.font.bold = True
# Add rows
for t in transactions:
row_cells = table.add_row().cells
# Determine amount
amount_str = re.sub(r'[^\d.]', '', t.get("total") or "")
amount = float(amount_str) if amount_str else 0.0
# Build notes
details = []
if t.get("details"):
for k, v in t["details"].items():
if k == "sheet_notes": continue # handle separately
if isinstance(v, list):
details.append(f"{k}: {len(v)} items")
else:
details.append(f"{k}: {v}")
sheet_notes = t.get("notes") or t.get("details", {}).get("sheet_notes")
if sheet_notes and str(sheet_notes) not in details:
details.append(f"[Sheet] {sheet_notes}")
if not details:
subj = t.get("subject", "").strip()
if subj:
details.append(subj[:60])
notes_str = " | ".join(details)
source = t.get("_source", "gmail").capitalize()
if t.get("image_analyses") or t.get("doc_analyses"):
source += " (+AI)"
row_cells[0].text = t.get("date", "")
row_cells[1].text = t.get("vendor", "Unknown")
row_cells[2].text = t.get("category", "Unknown").capitalize()
row_cells[3].text = f"₹{amount:,.2f}" if amount > 0 else "-"
row_cells[4].text = t.get("payment_method", "Unknown")
row_cells[5].text = source
row_cells[6].text = notes_str
# Save the document with retry logic
abs_path = os.path.abspath(output_path)
try:
doc.save(abs_path)
except IOError:
# Fallback if file is open
import time
suffix = int(time.time())
alt_path = abs_path.replace(".docx", f"_{suffix}.docx")
doc.save(alt_path)
abs_path = alt_path
return abs_path