Files
TimeTracker/docs/REPORTLAB_MIGRATION_SUMMARY.md
T
Dries Peeters 4eeaa2a842 feat: Migrate PDF templates to ReportLab JSON format
- Add ReportLab template renderer with JSON-based template system
- Implement template schema validation and helper functions
- Add database migration for template_json columns
- Update visual editor to generate ReportLab JSON alongside HTML/CSS
- Maintain backward compatibility with legacy templates
- Add comprehensive migration documentation

BREAKING CHANGE: Existing PDF templates need to be saved again through
the visual editor to generate the new template_json format. Templates
will continue to work using the legacy fallback generator until saved.
2026-01-09 11:43:42 +01:00

6.8 KiB

ReportLab PDF Generation Migration - Summary

Overview

The PDF generation system has been successfully migrated from WeasyPrint to ReportLab. This migration provides better reliability, fewer system dependencies, and more precise control over PDF generation.

Migration Date

Completed: January 2025

Key Changes

1. Template Format

  • Old: HTML/CSS templates (WeasyPrint)
  • New: JSON-based templates (ReportLab)
  • Compatibility: Both formats are supported during transition period

2. Database Schema

  • Added template_json column to invoice_pdf_templates table
  • Added template_json column to quote_pdf_templates table
  • Migration script: migrations/versions/106_add_reportlab_template_json.py

3. Visual Editor

  • Updated generateCode() function to generate ReportLab JSON alongside legacy HTML/CSS
  • Templates saved from visual editor include both formats for backward compatibility
  • Preview still uses HTML/CSS for browser rendering

4. PDF Generators

  • InvoicePDFGenerator: Now uses ReportLab when template_json exists
  • QuotePDFGenerator: Now uses ReportLab when template_json exists
  • Fallback to legacy ReportLab generator if no template JSON is found
  • Automatic fallback on errors ensures PDFs are always generated

5. New Components

ReportLab Template Schema (app/utils/pdf_template_schema.py)

  • Defines JSON structure for ReportLab templates
  • Validation functions for template integrity
  • Page size and element type enums
  • Helper functions for dimensions and defaults

ReportLab Template Renderer (app/utils/pdf_generator_reportlab.py)

  • ReportLabTemplateRenderer class
  • Handles absolute positioning via canvas drawing
  • Supports all element types: text, images, rectangles, circles, lines, tables
  • Template variable processing (Jinja2-style)
  • Page numbering support

Features

Supported Element Types

  • Text: Font family, size, color, alignment, opacity
  • Images: Base64 data URIs or file paths, sizing, opacity
  • Rectangles: Fill, stroke, dimensions
  • Circles: Fill, stroke, radius
  • Lines: Stroke color, width
  • Tables: Dynamic data binding, column alignment, styling

Page Sizes

  • A4, A5, A3
  • Letter, Legal
  • Tabloid
  • Custom dimensions (via JSON)

Template Variables

  • Jinja2-style template processing
  • Data binding for invoices/quotes
  • Row templates for table data
  • Helper functions (format_money, format_date, etc.)

Backward Compatibility

The migration maintains full backward compatibility:

  1. Existing Templates: Continue to work using legacy ReportLab fallback generator
  2. New Templates: Use ReportLab JSON format for better control
  3. Preview System: Still uses HTML/CSS for browser-based preview
  4. API: No changes required for existing integrations

File Structure

app/
├── utils/
│   ├── pdf_generator.py              # Main generator (updated)
│   ├── pdf_generator_reportlab.py    # NEW: ReportLab renderer
│   ├── pdf_generator_fallback.py     # Legacy fallback (still used)
│   └── pdf_template_schema.py        # NEW: Schema definition
├── models/
│   ├── invoice_pdf_template.py       # Updated with template_json
│   └── quote.py                      # Updated with template_json
└── routes/
    └── admin.py                      # Updated save/reset routes

templates/admin/
├── pdf_layout.html                   # Updated generateCode()
└── quote_pdf_layout.html             # Updated generateCode()

migrations/versions/
└── 106_add_reportlab_template_json.py # Database migration

Usage

Creating a New Template

  1. Use the visual editor at /admin/pdf-layout or /admin/quote-pdf-layout
  2. Design your template using the Konva.js canvas
  3. Click "Save Design"
  4. The system automatically generates both:
    • ReportLab JSON (for PDF generation)
    • HTML/CSS (for preview)

Template JSON Structure

{
  "page": {
    "size": "A4",
    "margin": {
      "top": 20,
      "right": 20,
      "bottom": 20,
      "left": 20
    }
  },
  "elements": [
    {
      "type": "text",
      "x": 40,
      "y": 40,
      "text": "{{ invoice.invoice_number }}",
      "width": 400,
      "style": {
        "font": "Helvetica-Bold",
        "size": 16,
        "color": "#000000",
        "align": "left"
      }
    },
    {
      "type": "table",
      "x": 40,
      "y": 200,
      "width": 515,
      "columns": [...],
      "data": "{{ invoice.items }}",
      "row_template": {...}
    }
  ]
}

Testing

Manual Testing

  1. Create a new invoice/quote template in the visual editor
  2. Save the template
  3. Export a PDF - verify it matches the preview
  4. Test all page sizes (A4, A5, Letter, etc.)
  5. Test tables with multiple rows
  6. Verify template variables are processed correctly

Automated Testing

  • Migration includes validation for template JSON
  • Schema validation prevents invalid templates
  • Error handling ensures fallback on failures

Performance

  • ReportLab: Faster than WeasyPrint (no HTML parsing)
  • Memory: Lower memory usage (programmatic generation vs HTML rendering)
  • Dependencies: Fewer system dependencies required
  • Reliability: More consistent across platforms

Troubleshooting

Template Not Rendering

  1. Check if template_json exists in database
  2. Verify JSON is valid (use validation function)
  3. Check error logs for specific issues
  4. System falls back to legacy generator automatically

Elements Not Positioning Correctly

  • Coordinates are in points (1 point = 1/72 inch)
  • Y-coordinate is from top of page
  • Check margins are accounted for in positioning

Tables Not Showing Data

  • Verify data source path (e.g., {{ invoice.items }})
  • Check row_template structure matches columns
  • Ensure data is available in context

Future Improvements

  1. Template Converter: Utility to convert existing HTML/CSS templates to JSON
  2. WeasyPrint Removal: Optional cleanup to remove unused WeasyPrint dependencies
  3. Enhanced Elements: Additional element types (curved lines, polygons, etc.)
  4. Template Library: Pre-built templates for common layouts

Migration Notes

  • WeasyPrint imports remain in codebase for backward compatibility but are not used
  • Legacy HTML/CSS templates continue to work via fallback generator
  • New templates should use JSON format for best results
  • Preview system uses HTML/CSS regardless of template format (browser compatibility)

Support

For issues or questions:

  1. Check error logs for specific errors
  2. Verify template JSON structure using schema validation
  3. Test with fallback generator if ReportLab template fails
  4. Review this document for common issues

Credits

Migration completed as part of improving PDF generation reliability and reducing system dependencies.