from datetime import datetime from pathlib import Path from typing import List from weasyprint import HTML from app.core.config import settings from app.core.logging import app_logger from app.models.invoice import Invoice, InvoiceItem from app.models.client import Client from app.models.user import User def generate_invoice_pdf( invoice: Invoice, items: List[InvoiceItem], client: Client, user: User, ) -> Path: """ Generate a PDF for an invoice and save it to the storage directory """ try: # Create a unique filename timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"invoice_{invoice.id}_{timestamp}.pdf" file_path = settings.INVOICE_STORAGE_DIR / filename # Make sure the directory exists settings.INVOICE_STORAGE_DIR.mkdir(parents=True, exist_ok=True) # Generate HTML content for the invoice html_content = _generate_invoice_html(invoice, items, client, user) # Convert HTML to PDF HTML(string=html_content).write_pdf(file_path) app_logger.info(f"Generated PDF invoice: {file_path}") return file_path except Exception as e: app_logger.error(f"Error generating PDF invoice: {str(e)}") raise def _generate_invoice_html( invoice: Invoice, items: List[InvoiceItem], client: Client, user: User, ) -> str: """ Generate HTML content for an invoice """ # Calculate totals subtotal = sum(item.unit_price * item.quantity for item in items) total = subtotal # Add tax calculations if needed # Format dates issued_date = invoice.issued_date.strftime("%Y-%m-%d") if invoice.issued_date else "" due_date = invoice.due_date.strftime("%Y-%m-%d") if invoice.due_date else "" # Basic HTML template for the invoice return f"""
Description | Quantity | Unit Price | Amount |
---|---|---|---|
{item.description} | {item.quantity} | ${item.unit_price:.2f} | ${item.quantity * item.unit_price:.2f} |