Automated Action b51b13eb3e Create backend scaffold for freelancer invoicing API
- Set up FastAPI application with CORS support
- Configure SQLite database connection
- Create database models for users, clients, invoices, and line items
- Set up Alembic for database migrations
- Implement JWT-based authentication system
- Create basic CRUD endpoints for users, clients, and invoices
- Add PDF generation functionality
- Implement activity logging
- Update README with project information
2025-05-26 18:21:20 +00:00

93 lines
2.9 KiB
Python

from pathlib import Path
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from app.models.invoice import Invoice
from app.models.client import Client
from datetime import datetime
PDF_DIR = Path("/app") / "storage" / "pdfs"
PDF_DIR.mkdir(parents=True, exist_ok=True)
def generate_invoice_pdf(invoice: Invoice, client: Client) -> str:
"""
Generate a PDF for an invoice and return the path to the PDF file.
"""
# Create a unique filename for the PDF
filename = f"invoice_{invoice.invoice_number}_{datetime.now().strftime('%Y%m%d%H%M%S')}.pdf"
pdf_path = PDF_DIR / filename
# Create a PDF using ReportLab
c = canvas.Canvas(str(pdf_path), pagesize=letter)
# Add invoice information to the PDF
c.setFont("Helvetica-Bold", 18)
c.drawString(50, 750, f"Invoice #{invoice.invoice_number}")
c.setFont("Helvetica", 12)
c.drawString(50, 730, f"Status: {invoice.status}")
c.drawString(50, 715, f"Issued Date: {invoice.issued_date}")
c.drawString(50, 700, f"Due Date: {invoice.due_date}")
# Add client information
c.setFont("Helvetica-Bold", 14)
c.drawString(50, 670, "Client Information")
c.setFont("Helvetica", 12)
c.drawString(50, 655, f"Name: {client.name}")
c.drawString(50, 640, f"Email: {client.email}")
if client.company:
c.drawString(50, 625, f"Company: {client.company}")
if client.address:
c.drawString(50, 610, f"Address: {client.address}")
if client.phone:
c.drawString(50, 595, f"Phone: {client.phone}")
# Add invoice items
c.setFont("Helvetica-Bold", 14)
c.drawString(50, 560, "Invoice Items")
c.setFont("Helvetica", 12)
y = 540
c.drawString(50, y, "Description")
c.drawString(300, y, "Quantity")
c.drawString(370, y, "Unit Price")
c.drawString(450, y, "Total")
y -= 20
total = 0
for item in invoice.items:
item_total = item.quantity * item.unit_price
total += item_total
c.drawString(50, y, item.description)
c.drawString(300, y, str(item.quantity))
c.drawString(370, y, f"${item.unit_price:.2f}")
c.drawString(450, y, f"${item_total:.2f}")
y -= 15
# Add a page break if needed
if y < 50:
c.showPage()
c.setFont("Helvetica-Bold", 14)
c.drawString(50, 750, "Invoice Items (continued)")
c.setFont("Helvetica", 12)
y = 730
# Add total
c.setFont("Helvetica-Bold", 14)
c.drawString(370, y - 20, "Total:")
c.drawString(450, y - 20, f"${total:.2f}")
# Add footer with notes
if invoice.notes:
c.setFont("Helvetica-Bold", 12)
c.drawString(50, 50, "Notes:")
c.setFont("Helvetica", 10)
c.drawString(50, 35, invoice.notes)
c.save()
return str(pdf_path)