- PDF generation with WeasyPrint: deviz and factura templates (A4, branding)
- GET /orders/{id}/pdf/deviz returns PDF with order lines and totals
- Client portal (public, no auth): GET /p/{token}, POST /p/{token}/accept|reject
- SMS service (SMSAPI.ro) - skips in dev when no token configured
- Invoice service: create from validated order, auto-number (F-YYYY-NNNN)
- GET /invoices/{id}/pdf returns factura PDF
- Order status_client field for client accept/reject tracking
- Alembic migration for status_client
- 19 passing tests (auth + sync + orders + pdf + portal + invoices)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
31 lines
908 B
Python
31 lines
908 B
Python
from pathlib import Path
|
|
|
|
from jinja2 import Environment, FileSystemLoader
|
|
from weasyprint import HTML
|
|
|
|
TEMPLATES = Path(__file__).parent / "templates"
|
|
|
|
|
|
def generate_deviz(order: dict, lines: list, tenant: dict) -> bytes:
|
|
env = Environment(loader=FileSystemLoader(str(TEMPLATES)))
|
|
html = env.get_template("deviz.html").render(
|
|
order=order,
|
|
tenant=tenant,
|
|
manopera=[l for l in lines if l.get("tip") == "manopera"],
|
|
materiale=[l for l in lines if l.get("tip") == "material"],
|
|
)
|
|
return HTML(string=html).write_pdf()
|
|
|
|
|
|
def generate_factura(
|
|
invoice: dict, order: dict, lines: list, tenant: dict
|
|
) -> bytes:
|
|
env = Environment(loader=FileSystemLoader(str(TEMPLATES)))
|
|
html = env.get_template("factura.html").render(
|
|
invoice=invoice,
|
|
order=order,
|
|
tenant=tenant,
|
|
lines=lines,
|
|
)
|
|
return HTML(string=html).write_pdf()
|