mcpField
F
frappe-syntax-print

frappe-syntax-print

github.com/impertio-studio文档处理198108 次安装30 周前更新
代码仓库

关于 frappe-syntax-print

面向 Frappe 开发者,提供 v14、v15、v16 打印格式、信头和 PDF 生成的参考。涵盖 Jinja、报表 JS 模板及 v15+ 的 Print Designer,并说明 PDF 引擎与版本差异。

主要功能

  1. 01标准、Jinja 和报表 JS 打印格式
  2. 02Print Designer 的版本与引擎说明
  3. 03信头及页眉页脚配置
  4. 04PDF 生成 API 与下载端点
  5. 05分页、打印 CSS 和模板过滤器

适用场景

  1. 01为单据创建自定义打印格式
  2. 02为报表配置 JS 打印模板
  3. 03生成带信头的 PDF
  4. 04调整打印布局和分页

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/impertio-studio/frappe_claude_skill_package --skill frappe-syntax-print

安装后在 Claude Code 中输入/frappe-syntax-print确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
anti-patterns.md
jinja-print-formats.md
pdf-api.md

详细介绍

Frappe 打印格式与 PDF 生成

关于 Frappe v14/v15/v16 中打印格式、Letter Head 和 PDF 生成的确定性参考。


何时使用此技能

使用场景:

  • 创建或修改打印格式(Jinja 或 JS)
  • 以编程方式生成 PDF(get_pdf、下载端点)
  • 为打印输出配置 Letter Head(页眉/页脚)
  • 使用 Print Designer(v15+)
  • 实现分页、打印 CSS 或横向布局
  • 构建报表打印格式({%= %} 语法)

请勿用于:

  • 通用 Jinja 模板语法(电子邮件、门户)——请参阅 frappe-syntax-jinja
  • 客户端脚本 UI 逻辑——请参阅 frappe-syntax-clientscripts
  • Web 视图或门户页面——请参阅 frappe-syntax-jinja

决策树:选择哪种打印格式类型?

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.

打印格式类型

类型引擎版本使用场景
标准根据 DocType 字段布局自动生成v14+无需自定义
Jinja服务端 Jinja2(wkhtmltopdf)v14+完全控制布局
JS 模板客户端微模板v14+仅用于报表打印格式
Print DesignerWeasyPrint / Chromev15+可视化拖放构建器
标准打印格式

始终为默认格式。Frappe 根据 DocType 字段自动生成布局。无需编写代码。通过 Print Settings 和字段的 print_hide 属性进行控制。

Jinja 打印格式

在 Print Format 文档上设置 custom_format = 1。使用完整的 Jinja2 进行服务端渲染。

每个 Jinja 打印格式中可用的上下文变量:

变量类型内容
docDocument正在打印的文档
metaMetaDocType 元数据
layoutlist字段布局分区
letter_headstr渲染后的 Letter Head HTML
footerstr渲染后的页脚 HTML
print_settingsdictPrint Settings 配置
frappemodule完整的 frappe 模块访问权限

示例 — 最简 Jinja 打印格式:

<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 模板(报表打印格式)

仅用于 Query Reports 和 Script Reports。使用 {%= %} 微模板语法,而非 Jinja。

// 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>
{% } %}

**关键:**绝不要混用 Jinja {{ }} 和 JS {%= %} 语法。它们是完全独立的模板引擎。

Print Designer(仅 v15+)
  • 独立应用:bench get-app print_designer
  • 使用 WeasyPrint(而非 wkhtmltopdf)
  • 在浏览器中使用可视化拖放构建器
  • 绝不要尝试在 v14 上使用 Print Designer——该版本中不存在此功能

Letter Head

Letter Head 为所有打印格式提供统一的页眉/页脚。

配置
字段用途
source"Image" 或 "HTML"
content页眉 HTML(使用 doc 上下文进行 Jinja 渲染)
footer页脚 HTML(使用 Jinja 渲染,仅限 PDF)
image页眉图像(当 source = "Image" 时)
align图像对齐方式:Left、Center、Right

重要:footer 字段仅在 PDF 输出中显示,不会显示在浏览器打印预览中。

Jinja 模板中的 Letter Head
# 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
)
动态 Letter Head 内容

Letter Head 的 content 和 footer 字段支持使用 doc 上下文进行 Jinja 渲染:


<div style="text-align: right;">
  <strong>{{ doc.company }}</strong><br>
  Date: {{ doc.posting_date | global_date_format }}
</div>

PDF 生成 API

完整 API 参考请参阅 references/pdf-api.md。

快速参考
# 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)
下载端点
# 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 引擎选择(v15+)
引擎使用场景配置
wkhtmltopdfv14 上的默认引擎,v15+ 上的备用引擎默认
Chromev15+ 且已安装 Chromium在 Print Format 上设置 pdf_generator = "chrome"
WeasyPrint仅限 Print Designer 格式Print Designer 自动使用

在 v14 上始终使用 wkhtmltopdf。在 v15+ 上,Chrome 对 CSS3 的支持更好。


分页与打印 CSS

分页类

<div class="page-break"></div>


<div style="page-break-after: always;"></div>


<div style="page-break-before: always;"></div>
打印 CSS 类(Frappe 内置)
类效果
.print-format容器:最大宽度 8.3in,最小高度 11.69in(A4 纵向)
.print-format.landscape宽度 11.69in(A4 横向)
.page-breakpage-break-after: always
.print-heading打印标题样式
.hidden-pdf仅在 PDF 输出中隐藏
.visible-pdf仅在 PDF 输出中显示
PDF 页眉/页脚 HTML
# In hooks.py — inject header/footer into every PDF
pdf_header_html = "myapp.utils.get_pdf_header"
pdf_body_html = "myapp.utils.get_pdf_body"
pdf_footer_html = "myapp.utils.get_pdf_footer"

<div id="header-html">
  <span class="page"></span> of <span class="topage"></span>
</div>

<div id="footer-html">
  <p style="text-align: center; font-size: 9px;">
    Printed on {{ frappe.utils.nowdate() }}
  </p>
</div>
打印 CSS 最佳实践
/* ALWAYS use relative units for print widths */
@media print {
  .print-format {
    max-width: 100%;
    margin: 0;
    padding: 15mm;
  }

  /* Prevent table rows from splitting across pages */
  tr {
    page-break-inside: avoid;
  }

  /* Constrain images */
  img {
    max-width: 100%;
    height: auto;
  }
}

自定义应用打印格式

随应用发布打印格式
myapp/
└── mymodule/
    └── print_format/
        └── my_custom_format/
            ├── my_custom_format.json   # Print Format doc
            └── my_custom_format.html   # Jinja template

在 JSON 文件中,务必设置:

{
  "doctype": "Print Format",
  "name": "My Custom Format",
  "doc_type": "Sales Invoice",
  "module": "My Module",
  "standard": "Yes",
  "custom_format": 1,
  "print_format_type": "Jinja"
}

对于随应用发布的打印格式,务必设置 standard = "Yes" 和 module。这样可确保系统将其识别为应用的一部分,而非站点级自定义项。


打印格式的 Jinja 过滤器

过滤器用途示例
global_date_format按系统设置格式化日期{{ doc.posting_date | global_date_format }}
json序列化为 JSON 字符串{{ doc.items | json }}
len获取长度{{ doc.items | len }}
int转换为整数{{ value | int }}
flt转换为浮点数{{ value | flt }}
markdown将 Markdown 渲染为 HTML{{ doc.description | markdown }}
abs绝对值{{ value | abs }}
注册自定义 Jinja 过滤器/方法
# In hooks.py
jinja = {
    "methods": [
        "myapp.utils.jinja.my_custom_method"
    ],
    "filters": [
        "myapp.utils.jinja.my_custom_filter"
    ]
}
# myapp/utils/jinja.py
def my_custom_method(value):
    """Available as {{ my_custom_method(doc.field) }} in templates."""
    return value.upper()

def my_custom_filter(value, arg=None):
    """Available as {{ doc.field | my_custom_filter }} in templates."""
    return f"[{value}]"

版本兼容性矩阵

功能v14v15v16
Jinja 打印格式是是是
JS 报表模板是是是
标准打印格式是是是
信笺抬头(图像/HTML)是是是
wkhtmltopdf默认回退回退
Chrome PDF 引擎否是是
WeasyPrint否是是
Print Designer 应用否是是
pdf_header_html hook是是是
download_multi_pdf是是是

常见反模式

请参阅 references/anti-patterns.md,查看完整列表及修复方法。

  1. 绝不在报表打印格式中使用 {{ }} —— 它们使用 {%= %}(JS 微模板)
  2. 绝不在模板的 {% for %} 循环中调用 frappe.get_doc() —— 这会导致 N+1 查询
  3. 绝不在 Jinja 模板中放置复杂的业务逻辑 —— 将其移至 Python 并传入结果
  4. 绝不在 CSS 中硬编码页面尺寸 —— 使用 .print-format 类或相对单位
  5. 绝不在以编程方式生成 PDF 时忽略 no_letterhead 参数
  6. 绝不在 v14 上使用 Print Designer —— 它需要 v15 或更高版本
  7. 绝不在打印模板中嵌入大型 base64 图像 —— 使用 URL 并设置 max-width: 100%

参考文件

  • Jinja 打印格式 —— Jinja 语法、变量、过滤器、宏
  • PDF API —— get_pdf()、下载端点、分页符、钩子
  • 反模式 —— 常见打印格式错误及修复方法

评论

支持 Markdown