erpnext-syntax-jinja

安装

npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-syntax-jinja

ERPNext Jinja Templates Syntax Skill Correct Jinja syntax for Print Formats, Email Templates, and Portal Pages in ERPNext/Frappe v14/v15/v16. When to Use This Skill USE this skill when: Creating or modifying Print Formats Developing Email Templates Building Portal Pages (www/*.html) Adding custom Jinja filters/methods via hooks DO NOT USE for: Report Print Formats (they use JavaScript templating, not Jinja) Client Scripts (use erpnext-syntax-clientscripts) Server Scripts (use erpnext-syntax-serverscripts) Context Objects per Template Type Print Formats Object Description doc The document being printed frappe Frappe module with utility methods _() Translation function Email Templates Object Description doc The linked document frappe Frappe module (limited) Portal Pages Object Description frappe.session.user Current user frappe.form_dict Query parameters frappe.lang Current language Custom context Via Python controller See : references/context-objects.md for complete details. Essential Methods Formatting (ALWAYS use) {# RECOMMENDED for fields in print formats #} {{ doc.get_formatted("posting_date") }} {{ doc.get_formatted("grand_total") }} {# For child table rows - pass parent doc #} {% for row in doc.items %} {{ row.get_formatted("rate", doc) }} {{ row.get_formatted("amount", doc) }} {% endfor %} {# General formatting #} {{ frappe.format(value, {'fieldtype': 'Currency'}) }} {{ frappe.format_date(doc.posting_date) }} Document Retrieval {# Full document #} {% set customer = frappe.get_doc("Customer", doc.customer) %} {# Specific field value (more efficient) #} {% set abbr = frappe.db.get_value("Company", doc.company, "abbr") %} {# List of records #} {% set tasks = frappe.get_all('Task', filters={'status': 'Open'}, fields=['title', 'due_date']) %} Translation (REQUIRED for user-facing strings)

{{ _("Invoice") }}

{{ _("Total: {0}").format(doc.grand_total) }}

See : references/methods-reference.md for all methods. Control Structures Conditionals {% if doc.status == "Paid" %} {{ ("Paid") }} {% elif doc.status == "Overdue" %} {{ ("Overdue") }} {% else %} {{ doc.status }} {% endif %} Loops

{{ loop.index }} {{ item.item_name }} {{ item.get_formatted("amount", doc) }}

{% else %}

{{ _("No items") }}

{% endfor %} Loop Variables Variable Description loop.index 1-indexed position loop.first True on first loop.last True on last loop.length Total items Variables {% set total = 0 %} {% set customer_name = doc.customer_name | default('Unknown') %} Filters Commonly Used Filter Example default {{ value | default('N/A') }} length {{ items | length }} join {{ names | join(', ') }} truncate {{ text | truncate(100) }} safe {{ html | safe }} (trusted content only!) See : references/filters-reference.md for all filters. Print Format Template

<style> .header { background: #f5f5f5; padding: 15px; } .table { width: 100%; border-collapse: collapse; } .table th, .table td { border: 1px solid #ddd; padding: 8px; } .text-right { text-align: right; } </style>

{{ doc.select_print_heading or _("Invoice") }}

{{ doc.name }}

{{ _("Date") }}: {{ doc.get_formatted("posting_date") }}

{% for row in doc.items %} {% endfor %}
{{ _("Item") }} {{ _("Qty") }} {{ _("Amount") }}
{{ row.item_name }} {{ row.qty }} {{ row.get_formatted("amount", doc) }}

{{ _("Grand Total") }}: {{ doc.get_formatted("grand_total") }}

Email Template

{{ _("Dear") }} {{ doc.customer_name }},

{{ _("Invoice") }} {{ doc.name }} {{ _("for") }} {{ doc.get_formatted("grand_total") }} {{ _("is due.") }}

{{ _("Due Date") }}: {{ frappe.format_date(doc.due_date) }}

{% if doc.items %}

    {% for item in doc.items %}
  • {{ item.item_name }} - {{ item.qty }} x {{ item.get_formatted("rate", doc) }}
  • {% endfor %}

{% endif %}

{{ _("Best regards") }},
{{ frappe.db.get_value("Company", doc.company, "company_name") }}

Portal Page with Controller www/projects/index.html {% extends "templates/web.html" %} {% block title %}{{ _("Projects") }}{% endblock %}

{{ _("Projects") }}

{% if frappe.session.user != 'Guest' %}

{{ _("Welcome") }}, {{ frappe.get_fullname() }}

{% endif %}

{{ project.title }}

{{ project.description | truncate(150) }}

{% else %}

{{ _("No projects found.") }}

{% endfor %}
{% endblock %}
www/projects/index.py
import
frappe
def
get_context
(
context
)
:
context
.
title
=
"Projects"
context
.
projects
=
frappe
.
get_all
(
"Project"
,
filters
=
{
"is_public"
:
1
}
,
fields
=
[
"name"
,
"title"
,
"description"
]
,
order_by
=
"creation desc"
)
return
context
Custom Filters/Methods via jenv Hook
hooks.py
jenv
=
{
"methods"
:
[
"myapp.jinja.methods"
]
,
"filters"
:
[
"myapp.jinja.filters"
]
}
myapp/jinja/methods.py
import
frappe
def
get_company_logo
(
company
)
:
"""Get company logo URL"""
return
frappe
.
db
.
get_value
(
"Company"
,
company
,
"company_logo"
)
or
""
Usage
Critical Rules
✅ ALWAYS
Use
_()
for all user-facing strings
Use
get_formatted()
for currency/date fields
Use default values:
{{ value | default('') }}
Child table rows:
row.get_formatted("field", doc)
❌ NEVER
Execute queries in loops (N+1 problem)
Use
| safe
for user input (XSS risk)
Heavy calculations in templates (do in Python)
Jinja syntax in Report Print Formats (they use JS)
Report Print Formats (NOT Jinja!)
WARNING
Report Print Formats for Query/Script Reports use JavaScript templating. Aspect Jinja (Print Formats) JS (Report Print Formats) Output {{ }} {%= %} Code {% %} {% %} Language Python JavaScript

{% for(var i=0; i < data.length; i++) { %}

< td > {%= data[i].name %}

{% } %} Version Compatibility Feature v14 v15 Basic Jinja API ✅ ✅ get_formatted() ✅ ✅ jenv hook ✅ ✅ Portal pages ✅ ✅ frappe.utils.format_date with format ✅ ✅+ V16: Chrome PDF Rendering Version 16 introduced Chrome-based PDF rendering replacing wkhtmltopdf. Key Differences Aspect v14/v15 (wkhtmltopdf) v16 (Chrome) CSS Support Limited CSS3 Full modern CSS Flexbox/Grid Partial Full support Page breaks page-break- break- preferred Fonts System fonts Web fonts supported Performance Faster Slightly slower CSS Updates for V16 / v14/v15 / .page-break { page-break-before : always ; } / v16 - both work, but break- is preferred */ .page-break { break-before : page ; } Configuration (V16)

In site_config.json

{ "pdf_engine" : "chrome" ,

or "wkhtmltopdf" for legacy

"chrome_path" : "/usr/bin/chromium" } Print Format Compatibility Most print formats work unchanged. Update if using: Complex CSS layouts (flexbox/grid now fully supported) Custom fonts (web fonts now work) Advanced page break control Reference Files File Contents references/context-objects.md Available objects per template type references/methods-reference.md All frappe.* methods references/filters-reference.md Standard and custom filters references/examples.md Complete working examples references/anti-patterns.md Mistakes to avoid See Also erpnext-syntax-hooks - For jenv configuration in hooks.py erpnext-impl-jinja - For implementation patterns erpnext-errors-jinja - For error handling

返回排行榜