Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计通过

erpnext-impl-jinjaerpnext impl jinja 命令行

Agent Skill

erpnext-impl-jinja 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

1,137

周安装

46

GitHub Stars

87

下载量

357
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:erpnext-impl-jinja(erpnext impl jinja 命令行)
来源仓库:https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package
仓库路径:skills/erpnext-impl-jinja
安装命令:
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-impl-jinja
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

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

简介

指导 Jinja 模板在打印格式、邮件和门户页面的正确用法及上下文对象结构。

  • 适用于 Codex、Claude、Cursor、Gemini CLI 中设计美观且动态的内容展示。
  • 强调变量作用域和过滤器使用规范,避免模板注入或渲染错误。
  • 安装前应核对 ERPNext 版本支持的语法特性,确保跨版本兼容性。
  • erpnext-impl-jinja 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

ERPNext Jinja Templates - Implementation

This skill helps you determine HOW to implement Jinja templates. For exact syntax, see erpnext-syntax-jinja.

Version: v14/v15/v16 compatible (with V16-specific features noted)

Main Decision: What Are You Trying to Create?

┌─────────────────────────────────────────────────────────────────────────┐
│ WHAT DO YOU WANT TO CREATE?                                             │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ ► Printable document (invoice, PO, report)?                             │
│   ├── Standard DocType → Print Format (Jinja)                           │
│   └── Query/Script Report → Report Print Format (JavaScript!)           │
│                                                                         │
│ ► Automated email with dynamic content?                                 │
│   └── Email Template (Jinja)                                            │
│                                                                         │
│ ► Customer-facing web page?                                             │
│   └── Portal Page (www/*.html + *.py)                                   │
│                                                                         │
│ ► Reusable template functions/filters?                                  │
│   └── Custom jenv methods in hooks.py                                   │
│                                                                         │
│ ► Notification content?                                                 │
│   └── Notification Template (uses Jinja syntax)                         │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

⚠️ CRITICAL: Report Print Formats use JAVASCRIPT templating, NOT Jinja!
   - Jinja: {{ variable }}
   - JS Report: {%= variable %}

Decision Tree: Print Format Type

WHAT ARE YOU PRINTING?
│
├─► Standard DocType (Invoice, PO, Quotation)?
│   │
│   │ WHERE TO CREATE?
│   ├─► Quick/simple format → Print Format Builder (Setup > Print)
│   │   - Drag-drop interface
│   │   - Limited customization
│   │
│   └─► Complex layout needed → Custom HTML Print Format
│       - Full Jinja control
│       - Custom CSS styling
│       - Dynamic logic
│
├─► Query Report or Script Report?
│   └─► Report Print Format (JAVASCRIPT template!)
│       ⚠️ NOT Jinja! Uses {%= %} and {% %}
│
└─► Letter or standalone document?
    └─► Letter Head + Print Format combination

Decision Tree: Where to Store Template

IS THIS A ONE-OFF OR REUSABLE?
│
├─► Site-specific, managed via UI?
│   └─► Create via Setup > Print Format / Email Template
│       - Stored in database
│       - Easy to edit without code
│
├─► Part of your custom app?
│   │
│   │ WHAT TYPE?
│   ├─► Print Format → myapp/fixtures or db records
│   │
│   ├─► Portal Page → myapp/www/pagename/
│   │   - index.html (template)
│   │   - index.py (context)
│   │
│   └─► Custom methods/filters → myapp/jinja/
│       - Registered via hooks.py jenv
│
└─► Template for multiple sites?
    └─► Include in app, export as fixture

Implementation Workflow: Print Format

Step 1: Create via UI (Recommended Start)

Setup > Printing > Print Format > New
- DocType: Sales Invoice
- Module: Accounts
- Standard: No (Custom)
- Print Format Type: Jinja

Step 2: Basic Template Structure

{# ALWAYS include styles at top #}
<style>
    .print-format { font-family: Arial, sans-serif; }
    .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; }
    .footer { margin-top: 30px; border-top: 1px solid #ddd; }
</style>

{# Document header #}
<div class="header">
    <h1>{{ doc.select_print_heading or _("Invoice") }}</h1>
    <p><strong>{{ doc.name }}</strong></p>
    <p>{{ _("Date") }}: {{ doc.get_formatted("posting_date") }}</p>
</div>

{# Items table #}
<table class="table">
    <thead>
        <tr>
            <th>{{ _("Item") }}</th>
            <th class="text-right">{{ _("Qty") }}</th>
            <th class="text-right">{{ _("Amount") }}</th>
        </tr>
    </thead>
    <tbody>
        {% for row in doc.items %}
        <tr>
            <td>{{ row.item_name }}</td>
            <td class="text-right">{{ row.qty }}</td>
            <td class="text-right">{{ row.get_formatted("amount", doc) }}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

{# Totals #}
<div class="text-right">
    <p><strong>{{ _("Grand Total") }}:</strong> {{ doc.get_formatted("grand_total") }}</p>
</div>

Step 3: Test and Refine

1. Open a document (e.g., Sales Invoice)
2. Menu > Print > Select your format
3. Check layout, adjust CSS as needed
4. Test PDF generation

Implementation Workflow: Email Template

Step 1: Create via UI

Setup > Email > Email Template > New
- Name: Payment Reminder
- Subject: Invoice {{ doc.name }} - Payment Due
- DocType: Sales Invoice

Step 2: Template Content

<p>{{ _("Dear") }} {{ doc.customer_name }},</p>

<p>{{ _("This is a reminder that invoice") }} <strong>{{ doc.name }}</strong>
{{ _("for") }} {{ doc.get_formatted("grand_total") }} {{ _("is due.") }}</p>

<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
    <tr>
        <td style="padding: 8px; border: 1px solid #ddd;">
            <strong>{{ _("Due Date") }}</strong>
        </td>
        <td style="padding: 8px; border: 1px solid #ddd;">
            {{ frappe.format_date(doc.due_date) }}
        </td>
    </tr>
    <tr>
        <td style="padding: 8px; border: 1px solid #ddd;">
            <strong>{{ _("Outstanding") }}</strong>
        </td>
        <td style="padding: 8px; border: 1px solid #ddd;">
            {{ doc.get_formatted("outstanding_amount") }}
        </td>
    </tr>
</table>

{% if doc.items %}
<p><strong>{{ _("Items") }}:</strong></p>
<ul>
{% for item in doc.items %}
    <li>{{ item.item_name }} ({{ item.qty }})</li>
{% endfor %}
</ul>
{% endif %}

<p>{{ _("Best regards") }},<br>
{{ frappe.db.get_value("Company", doc.company, "company_name") }}</p>

Step 3: Use in Notifications or Code

# In Server Script or Controller
frappe.sendmail(
    recipients=[doc.email],
    subject=frappe.render_template(
        frappe.db.get_value("Email Template", "Payment Reminder", "subject"),
        {"doc": doc}
    ),
    message=frappe.get_template("Payment Reminder").render({"doc": doc})
)

Implementation Workflow: Portal Page

Step 1: Create Directory Structure

myapp/
└── www/
    └── projects/
        ├── index.html    # Jinja template
        └── index.py      # Python context

Step 2: Create Template (index.html)

{% extends "templates/web.html" %}

{% block title %}{{ _("Projects") }}{% endblock %}

{% block page_content %}
<div class="container">
    <h1>{{ title }}</h1>

    {% if frappe.session.user != 'Guest' %}
        <p>{{ _("Welcome") }}, {{ frappe.get_fullname() }}</p>
    {% endif %}

    <div class="row">
        {% for project in projects %}
        <div class="col-md-4">
            <div class="card">
                <h3>{{ project.title }}</h3>
                <p>{{ project.description | truncate(100) }}</p>
                <a href="/projects/{{ project.name }}">{{ _("View Details") }}</a>
            </div>
        </div>
        {% else %}
        <p>{{ _("No projects found.") }}</p>
        {% endfor %}
    </div>
</div>
{% endblock %}

Step 3: Create Context (index.py)

import frappe

def get_context(context):
    context.title = "Projects"
    context.no_cache = True  # Dynamic content

    # Fetch data
    context.projects = frappe.get_all(
        "Project",
        filters={"is_public": 1},
        fields=["name", "title", "description"],
        order_by="creation desc"
    )

    return context

Step 4: Test

Visit: https://yoursite.com/projects

Implementation Workflow: Custom Jinja Methods

Step 1: Register in hooks.py

# myapp/hooks.py
jenv = {
    "methods": ["myapp.jinja.methods"],
    "filters": ["myapp.jinja.filters"]
}

Step 2: Create Methods Module

# myapp/jinja/methods.py
import frappe

def get_company_logo(company):
    """Returns company logo URL - usable in any template"""
    return frappe.db.get_value("Company", company, "company_logo") or ""

def get_address_display(address_name):
    """Format address for display"""
    if not address_name:
        return ""
    return frappe.get_doc("Address", address_name).get_display()

def get_outstanding_amount(customer):
    """Get total outstanding for customer"""
    result = frappe.db.sql("""
        SELECT COALESCE(SUM(outstanding_amount), 0)
        FROM `tabSales Invoice`
        WHERE customer = %s AND docstatus = 1
    """, customer)
    return result[0][0] if result else 0

Step 3: Create Filters Module

# myapp/jinja/filters.py

def format_phone(value):
    """Format phone number: 1234567890 → (123) 456-7890"""
    if not value:
        return ""
    digits = ''.join(c for c in str(value) if c.isdigit())
    if len(digits) == 10:
        return f"({digits[:3]}) {digits[3:6]}-{digits[6:]}"
    return value

def currency_words(amount, currency="EUR"):
    """Convert number to words (simplified)"""
    return f"{currency} {amount:,.2f}"

Step 4: Use in Templates

{# Methods - called as functions #}
<img src="{{ get_company_logo(doc.company) }}" alt="Logo">
<p>{{ get_address_display(doc.customer_address) }}</p>
<p>Outstanding: {{ get_outstanding_amount(doc.customer) }}</p>

{# Filters - piped after values #}
<p>Phone: {{ doc.phone | format_phone }}</p>
<p>Amount: {{ doc.grand_total | currency_words }}</p>

Step 5: Deploy

bench --site sitename migrate

Quick Reference: Context Variables

Template TypeAvailable Objects
Print Formatdoc, frappe, _()
Email Templatedoc, frappe (limited)
Portal Pagefrappe.session, frappe.form_dict, custom context
Notificationdoc, frappe

Quick Reference: Essential Methods

NeedMethod
Format currency/datedoc.get_formatted("fieldname")
Format child rowrow.get_formatted("field", doc)
Translate string_("String")
Get linked docfrappe.get_doc("DocType", name)
Get single fieldfrappe.db.get_value("DT", name, "field")
Current datefrappe.utils.nowdate()
Format datefrappe.format_date(date)

Critical Rules

1. ALWAYS use get_formatted for display values

{# ❌ Raw database value #}
{{ doc.grand_total }}

{# ✅ Properly formatted with currency #}
{{ doc.get_formatted("grand_total") }}

2. ALWAYS pass parent doc for child table formatting

{% for row in doc.items %}
    {# ❌ Missing currency context #}
    {{ row.get_formatted("rate") }}

    {# ✅ Has currency context from parent #}
    {{ row.get_formatted("rate", doc) }}
{% endfor %}

3. ALWAYS use translation function for user text

{# ❌ Not translatable #}
<h1>Invoice</h1>

{# ✅ Translatable #}
<h1>{{ _("Invoice") }}</h1>

4. NEVER use Jinja in Report Print Formats

<!-- Query/Script Reports use JAVASCRIPT templating -->
{% for(var i=0; i<data.length; i++) { %}
<tr><td>{%= data[i].name %}</td></tr>
{% } %}

5. NEVER execute queries in loops

{# ❌ N+1 query problem #}
{% for item in doc.items %}
    {% set stock = frappe.db.get_value("Bin", ...) %}
{% endfor %}

{# ✅ Prefetch data in controller/context #}
{% for item in items_with_stock %}
    {{ item.stock_qty }}
{% endfor %}

Version Differences

FeatureV14V15V16
Jinja templates
get_formatted()
jenv hooks
wkhtmltopdf PDF⚠️
Chrome PDF
V16 Chrome PDF: See erpnext-syntax-jinja for details.

Reference Files

FileContents
decision-tree.mdComplete template type selection
workflows.mdStep-by-step implementation patterns
examples.mdComplete working examples
anti-patterns.mdCommon mistakes to avoid

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.64%
按下载量换算120

Claude

31.58%
按下载量换算113

Cursor

18.89%
按下载量换算67

Gemini CLI

9.25%
按下载量换算33

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills