Skill125 repo starsupdated 2mo ago
frappe-syntax-print
>
Install in Claude Code
Copygit clone --depth 1 https://github.com/Impertio-Studio/Frappe_Claude_Skill_Package /tmp/frappe-syntax-print && cp -r /tmp/frappe-syntax-print/skills/source/syntax/frappe-syntax-print ~/.claude/skills/frappe-syntax-printThen start a new Claude Code session; the skill loads automatically.
Definition
SKILL.md
# Frappe Print Formats & PDF Generation
> Deterministic reference for print formats, Letter Head, and PDF generation in Frappe v14/v15/v16.
---
## When to Use This Skill
USE when:
- Creating or modifying Print Formats (Jinja or JS)
- Generating PDFs programmatically (`get_pdf`, download endpoints)
- Configuring Letter Head (header/footer) for print output
- Working with Print Designer (v15+)
- Implementing page breaks, print CSS, or landscape layouts
- Building Report Print Formats ({%= %} syntax)
DO NOT USE for:
- General Jinja template syntax (emails, portals) -- see `frappe-syntax-jinja`
- Client Script UI logic -- see `frappe-syntax-clientscripts`
- Web views or portal pages -- see `frappe-syntax-jinja`
---
## Decision Tree: Which Print Format Type?
```
Need a printable/PDF document?
├─ YES → Is it a Query/Script Report?
│ ├─ YES → Use JS Template ({%= %} microtemplate)
│ │ Set print_format_for = "Report"
│ └─ NO → Need visual drag-and-drop editor?
│ ├─ YES → On v15+?
│ │ ├─ YES → Use Print Designer (WeasyPrint)
│ │ └─ NO → NOT available on v14. Use Jinja.
│ └─ NO → Need full layout control?
│ ├─ YES → Use Jinja Print Format (custom_format=1)
│ └─ NO → Use Standard Print Format (auto layout)
└─ NO → This skill does not apply.
```
---
## Print Format Types
| Type | Engine | Version | When to Use |
|------|--------|---------|-------------|
| Standard | Auto from DocType field layout | v14+ | No customization needed |
| Jinja | Server-side Jinja2 (wkhtmltopdf) | v14+ | Full layout control |
| JS Template | Client-side microtemplate | v14+ | Report print formats only |
| Print Designer | WeasyPrint / Chrome | v15+ | Visual drag-and-drop builder |
### Standard Print Format
ALWAYS the default. Frappe auto-generates layout from DocType fields. No code needed. Controlled via Print Settings and field `print_hide` property.
### Jinja Print Format
Set `custom_format = 1` on the Print Format document. Full Jinja2 with server-side rendering.
**Context variables available in every Jinja Print Format:**
| Variable | Type | Content |
|----------|------|---------|
| `doc` | Document | The document being printed |
| `meta` | Meta | DocType metadata |
| `layout` | list | Field layout sections |
| `letter_head` | str | Rendered Letter Head HTML |
| `footer` | str | Rendered footer HTML |
| `print_settings` | dict | Print Settings configuration |
| `frappe` | module | Full frappe module access |
**Example — Minimal Jinja Print Format:**
```html
<h1>{{ doc.name }}</h1>
<p>Customer: {{ doc.customer_name }}</p>
<p>Date: {{ doc.posting_date | global_date_format }}</p>
<table class="table table-bordered">
<thead>
<tr><th>Item</th><th>Qty</th><th>Rate</th><th>Amount</th></tr>
</thead>
<tbody>
{% for row in doc.items %}
<tr>
<td>{{ row.item_name }}</td>
<td>{{ row.qty }}</td>
<td>{{ frappe.utils.fmt_money(row.rate, currency=doc.currency) }}</td>
<td>{{ frappe.utils.fmt_money(row.amount, currency=doc.currency) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<p><strong>Grand Total:</strong> {{ frappe.utils.fmt_money(doc.grand_total, currency=doc.currency) }}</p>
```
### JS Template (Report Print Formats)
ONLY for Query Reports and Script Reports. Uses `{%= %}` microtemplate syntax, NOT Jinja.
```javascript
// In report's .js file
{%= row.item_name %}
{% if (row.qty > 10) { %}
<strong>Bulk order</strong>
{% } %}
{% for (var i = 0; i < rows.length; i++) { %}
<tr>
<td>{%= rows[i].item_name %}</td>
<td>{%= rows[i].qty %}</td>
</tr>
{% } %}
```
**CRITICAL:** NEVER mix Jinja `{{ }}` and JS `{%= %}` syntax. They are completely separate template engines.
### Print Designer (v15+ Only)
- Separate app: `bench get-app print_designer`
- Uses WeasyPrint (not wkhtmltopdf)
- Visual drag-and-drop builder in the browser
- NEVER attempt to use Print Designer on v14 -- it does not exist
---
## Letter Head
Letter Head provides consistent header/footer across all print formats.
### Configuration
| Field | Purpose |
|-------|---------|
| `source` | `"Image"` or `"HTML"` |
| `content` | Header HTML (Jinja-rendered with `doc` context) |
| `footer` | Footer HTML (Jinja-rendered, **PDF only**) |
| `image` | Header image (when source = "Image") |
| `align` | Image alignment: Left, Center, Right |
**IMPORTANT:** The `footer` field only displays in PDF output, never in browser print preview.
### Letter Head in Jinja Templates
```python
# Server-side: render Letter Head programmatically
from frappe.utils.print_format import render_letterhead_for_print
letterhead_html = render_letterhead_for_print(
letter_head_name="My Company",
doc=doc
)
```
### Dynamic Letter Head Content
Letter Head `content` and `footer` fields support Jinja with `doc` context:
```html
<!-- In Letter Head content field -->
<div style="text-align: right;">
<strong>{{ doc.company }}</strong><br>
Date: {{ doc.posting_date | global_date_format }}
</div>
```
---
## PDF Generation API
> See `references/pdf-api.md` for complete API reference.
### Quick Reference
```python
# Generate PDF bytes from HTML
from frappe.utils.pdf import get_pdf
pdf_bytes = get_pdf(html_string, options=None)
# Generate PDF from a specific document + print format
from frappe.utils.print_format import download_pdf
download_pdf(doctype, name, format=None, doc=None, no_letterhead=0)
```
### Download Endpoints
```
# Single document PDF
GET /api/method/frappe.utils.print_format.download_pdf
?doctype=Sales Invoice
&name=SINV-00001
&format=My Print Format
&no_letterhead=0
# Multiple documents in one PDF
GET /api/method/frappe.utils.print_format.download_multi_pdf
?doctype=Sales Invoice
&name=["SINV-00001","SINV-00002"]
&format=My Print Format
```
### PDF Engine Selection (v15+)
| Engine | When |