mcpField
F
frappe-impl-customapp

frappe-impl-customapp

github.com/impertio-studio开发198114 次安装30 周前更新
代码仓库

关于 frappe-impl-customapp

面向 Frappe 开发者的自定义应用实施指南,覆盖从创建应用到测试和发布的流程。强调先判断是否确实需要自定义应用,并提供 v14、v15、v16 的相关做法。

主要功能

  1. 01评估是否需要自定义应用
  2. 02创建应用并配置模块
  3. 03实现钩子、补丁与 Fixtures
  4. 04迁移、测试和发布应用
  5. 05参考 v14 至 v16 差异

适用场景

  1. 01从头搭建 Frappe 自定义应用
  2. 02为 DocType 添加模块与控制器
  3. 03迁移数据并管理应用配置
  4. 04测试并将应用安装到其他站点

安装

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

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

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

包含的文件

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

references/
anti-patterns.md
decision-tree.md
examples.md
workflows.md

详细介绍

Frappe 自定义应用 - 实施

从头构建自定义 Frappe 应用的工作流。关于准确语法,请参阅 frappe-syntax-customapp。

版本:兼容 v14/v15/v16


主要决策:你需要自定义应用吗?

WHAT CHANGES DO YOU NEED?
|
+-- Add fields to existing DocType?
|   +-- NO APP NEEDED: Custom Field + Property Setter
|
+-- Simple automation/validation (<50 lines)?
|   +-- NO APP NEEDED: Server Script or Client Script
|
+-- Complex business logic, new DocTypes, or Python code?
|   +-- YES: Create custom app
|
+-- Integration with external system (needs imports)?
|   +-- YES: Custom app REQUIRED (Server Scripts block imports)
|
+-- Custom reports with complex queries?
|   +-- Script Report (no app) vs Query Report (app optional)

规则:始终从最简单的解决方案开始。Server Scripts + Custom Fields 无需自定义应用即可满足 70% 的需求。


步骤 1:创建应用结构

cd ~/frappe-bench
bench new-app my_app
# Prompts: Title, Description, Publisher, Email, License

务必立即验证:

# my_app/my_app/__init__.py MUST have:
__version__ = "0.0.1"

步骤 2:配置 pyproject.toml(v15+)

[build-system]
requires = ["flit_core >=3.4,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "my_app"
authors = [{ name = "Your Company", email = "[email protected]" }]
description = "Your app description"
requires-python = ">=3.10"
readme = "README.md"
dynamic = ["version"]
dependencies = [
    "requests>=2.28.0"   # Only PyPI packages here
]

[tool.bench.frappe-dependencies]
frappe = ">=15.0.0,<16.0.0"
# erpnext = ">=15.0.0,<16.0.0"  # Only if needed

规则:绝不要将 frappe 或 erpnext 放入 [project].dependencies——它们不在 PyPI 上。


步骤 3:配置 hooks.py

app_name = "my_app"
app_title = "My App"
app_publisher = "Your Company"
app_description = "Description"
app_email = "[email protected]"
app_license = "MIT"

required_apps = ["frappe"]  # Or ["frappe", "erpnext"]

fixtures = []  # Configured later

规则:务必声明所有依赖项的 required_apps。


步骤 4:定义模块

# my_app/my_app/modules.txt
My App
应用规模模块策略
1-5 个 DocType使用一个以应用名称命名的模块
6-15 个 DocType按功能领域划分为 2-4 个模块
15 个以上 DocType按业务领域划分模块

规则:每个 DocType 必须且只能属于一个模块。modules.txt 中的模块名称映射到目录:My Custom App --> my_custom_app/。

添加模块
mkdir -p my_app/my_app/new_module/doctype
touch my_app/my_app/new_module/__init__.py
# Add "New Module" to modules.txt
bench --site mysite migrate

步骤 5:安装并创建 DocType

# Install app on site
bench --site mysite install-app my_app

# Create DocType (via UI recommended, or CLI)
bench --site mysite new-doctype "My Document" --module "My App"

这会创建:

my_app/my_app/doctype/my_document/
+-- my_document.json    # DocType definition
+-- my_document.py      # Controller
+-- my_document.js      # Client script
+-- test_my_document.py # Tests

步骤 6:添加钩子

doc_events(v14/v15/v16)
doc_events = {
    "Sales Invoice": {
        "validate": "my_app.events.sales_invoice.validate",
        "on_submit": "my_app.events.sales_invoice.on_submit"
    }
}
extend_doctype_class(仅限 v16——首选)
extend_doctype_class = {
    "Sales Invoice": "my_app.overrides.sales_invoice.CustomSalesInvoice"
}

规则:在 v16 中重写生命周期方法时,务必调用 super().method()。

Scheduler Events
scheduler_events = {
    "daily": ["my_app.tasks.daily_cleanup"],
    "cron": {"0 9 * * 1-5": ["my_app.tasks.morning_report"]}
}

完整模式请参阅 frappe-impl-hooks 和 frappe-impl-scheduler。


步骤 7:添加补丁

创建补丁文件
mkdir -p my_app/my_app/patches/v1_0
touch my_app/my_app/patches/__init__.py
touch my_app/my_app/patches/v1_0/__init__.py
# my_app/my_app/patches/v1_0/populate_defaults.py
import frappe

def execute():
    if not frappe.db.has_column("My DocType", "target_field"):
        return  # Skip if not applicable

    batch_size = 1000
    offset = 0
    while True:
        records = frappe.get_all("My DocType",
            limit_page_length=batch_size, limit_start=offset)
        if not records:
            break
        for r in records:
            frappe.db.set_value("My DocType", r.name,
                "target_field", "default", update_modified=False)
        frappe.db.commit()
        offset += batch_size
在 patches.txt 中注册
[pre_model_sync]
# Patches that run BEFORE schema changes (backup data from deleted fields)

[post_model_sync]
# Patches that run AFTER schema changes (populate new fields)
my_app.patches.v1_0.populate_defaults

规则:

  • 务必检查是否需要运行补丁(守卫子句)
  • 处理 1000 条以上记录时,务必分批处理
  • 每批处理后务必提交
  • 绝不要在生产环境运行未经测试的补丁

步骤 8:管理 Fixtures

在 hooks.py 中配置
fixtures = [
    {"dt": "Custom Field", "filters": [["module", "=", "My App"]]},
    {"dt": "Property Setter", "filters": [["module", "=", "My App"]]},
    {"dt": "Role", "filters": [["name", "in", ["My App User", "My App Manager"]]]},
    {"dt": "Workflow", "filters": [["document_type", "=", "My DocType"]]},
    "My Category",  # All records of your own config DocType
]
导出并验证
bench --site mysite export-fixtures --app my_app
ls my_app/my_app/fixtures/
# custom_field.json, property_setter.json, etc.

规则:

  • 务必只筛选与你的应用自定义项相关的 Fixtures
  • 绝不要包含事务数据(发票、订单)
  • 对于共享 DocType(Custom Field、Workflow),绝不要在未设置筛选条件的情况下导出
  • Fixtures 会在 bench migrate 期间自动导入

步骤 9:开发工作流

必备命令
# After schema changes (DocType fields, hooks.py, patches)
bench --site mysite migrate

# After JS/CSS changes
bench build --app my_app

# After Python changes (controllers, events)
bench --site mysite clear-cache

# Full restart (production)
bench restart

# Watch mode (development)
bench watch  # Auto-rebuilds on file changes
开发周期
1. Edit code/DocType
2. bench --site mysite migrate (if schema changed)
3. bench build --app my_app (if JS/CSS changed)
4. bench --site mysite clear-cache (if Python changed)
5. Test in browser
6. Repeat

步骤 10:测试应用

# Run all tests
bench --site mysite run-tests --app my_app

# Run specific test
bench --site mysite run-tests --module my_app.my_module.doctype.my_doctype.test_my_doctype

# Run with verbose output
bench --site mysite run-tests --app my_app -v

有关编写测试用例,请参阅 frappe-testing-unit。


步骤 11:打包以供分发

通过 Git(标准方法)
cd apps/my_app
git init && git add . && git commit -m "Initial commit"
git remote add origin https://github.com/org/my_app.git
git push -u origin main
在另一个站点上安装
# On target bench
bench get-app https://github.com/org/my_app.git
bench --site target-site install-app my_app
bench --site target-site migrate
版本管理
# my_app/my_app/__init__.py
__version__ = "1.0.0"  # Semantic versioning: MAJOR.MINOR.PATCH
变更类型版本递增类型示例
破坏性变更MAJOR1.x -> 2.0.0
新功能MINOR1.1.x -> 1.2.0
Bug 修复PATCH1.2.0 -> 1.2.1

步骤 12:应用依赖项

Frappe/ERPNext 依赖项
# hooks.py
required_apps = ["frappe", "erpnext"]  # Install order matters
# pyproject.toml
[tool.bench.frappe-dependencies]
frappe = ">=15.0.0,<16.0.0"
erpnext = ">=15.0.0,<16.0.0"
Python 包依赖项
[project]
dependencies = ["requests>=2.28.0", "pandas>=1.5.0"]

规则:绝不要在应用之间创建循环依赖。


特定版本的注意事项

方面v14v15v16
构建配置setup.pypyproject.tomlpyproject.toml
DocType 扩展doc_eventsdoc_events首选 extend_doctype_class
Python 最低版本3.103.103.11
补丁格式INI sectionsINI sectionsINI sections
需要了解的 v16 破坏性变更
  • extend_doctype_class 钩子:通过 mixin 实现更简洁的扩展
  • 数据脱敏:字段级隐私配置
  • UUID 命名:新增命名规则选项
  • Chrome PDF:wkhtmltopdf 已弃用

关键规则摘要

务必遵守
  1. 从 bench new-app 开始——绝不要手动创建结构
  2. 在 __init__.py 中定义 __version__
  3. 在 pyproject.toml 中使用 dynamic = ["version"]
  4. 在生产环境使用前,先在数据库副本上测试补丁
  5. 仅筛选与你的应用自定义项相关的 Fixtures
  6. 为补丁进行版本管理(v1_0、v2_0 目录)
  7. 在全新站点上测试安装
切勿
  1. 将 frappe/erpnext 放入 [project].dependencies
  2. 在 fixtures 中包含事务数据
  3. 硬编码特定站点的值(使用设置 DocType)
  4. 在大型补丁中跳过 frappe.db.commit()
  5. 未备份就删除字段
  6. 直接修改 ERPNext 核心文件

参考文件

文件内容
workflows.md8 个分步实施指南
decision-tree.md完整的决策流程图
examples.md5 个完整可运行的应用示例
anti-patterns.md常见错误及规避方法

另请参阅

  • frappe-syntax-customapp - 精确语法参考
  • frappe-syntax-hooks - Hooks 配置语法
  • frappe-impl-hooks - Hook 实现模式
  • frappe-core-database - 补丁的数据库操作
  • frappe-impl-scheduler - 定时任务实现
  • frappe-ops-bench - Bench 命令参考
  • frappe-ops-app-lifecycle - 应用版本管理与发布管理
  • frappe-testing-unit - 为应用编写测试
  • frappe-testing-cicd - 应用测试的 CI/CD 流水线

评论

支持 Markdown