erpnext-syntax-customapp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseERPNext Custom App Syntax Skill
ERPNext 自定义应用语法指南
Complete syntax for building Frappe custom apps in v14/v15, including build configuration, module organization, patches and fixtures.
构建Frappe自定义应用的完整语法(适用于v14/v15版本),包括构建配置、模块组织、补丁与数据Fixture。
When to Use This Skill
何时使用本指南
USE this skill when you:
- Create a new Frappe/ERPNext custom app
- Configure pyproject.toml or setup.py
- Organize modules within an app
- Write database migration patches
- Configure fixtures for data export/import
- Manage app dependencies
DO NOT USE for:
- DocType controllers (use erpnext-syntax-controllers)
- Client Scripts (use erpnext-syntax-clientscripts)
- Server Scripts (use erpnext-syntax-serverscripts)
- Hooks configuration (use erpnext-syntax-hooks)
在以下场景使用本指南:
- 创建新的Frappe/ERPNext自定义应用
- 配置pyproject.toml或setup.py
- 组织应用内的模块
- 编写数据库迁移补丁
- 配置数据导出/导入用的Fixture
- 管理应用依赖
请勿在以下场景使用:
- 文档类型控制器(请使用erpnext-syntax-controllers)
- 客户端脚本(请使用erpnext-syntax-clientscripts)
- 服务器脚本(请使用erpnext-syntax-serverscripts)
- Hooks配置(请使用erpnext-syntax-hooks)
App Structure Overview
应用结构概览
v15 (pyproject.toml - Primary)
v15版本(以pyproject.toml为主)
apps/my_custom_app/
├── pyproject.toml # Build configuration
├── README.md
├── my_custom_app/ # Main package
│ ├── __init__.py # MUST contain __version__!
│ ├── hooks.py # Frappe integration
│ ├── modules.txt # Module registration
│ ├── patches.txt # Migration scripts
│ ├── patches/ # Patch files
│ ├── my_custom_app/ # Default module
│ │ └── doctype/
│ ├── public/ # Client assets
│ └── templates/ # Jinja templates
└── .git/See:for complete directory structure.references/structure.md
apps/my_custom_app/
├── pyproject.toml # Build configuration
├── README.md
├── my_custom_app/ # Main package
│ ├── __init__.py # MUST contain __version__!
│ ├── hooks.py # Frappe integration
│ ├── modules.txt # Module registration
│ ├── patches.txt # Migration scripts
│ ├── patches/ # Patch files
│ ├── my_custom_app/ # Default module
│ │ └── doctype/
│ ├── public/ # Client assets
│ └── templates/ # Jinja templates
└── .git/参考:完整目录结构请查看。references/structure.md
Critical Files
关键文件
init.py (REQUIRED)
init.py(必填)
python
undefinedpython
undefinedmy_custom_app/init.py
my_custom_app/init.py
version = "0.0.1"
**CRITICAL**: Without `__version__` the flit build fails!version = "0.0.1"
**重要提示**:如果没有`__version__`,flit构建会失败!pyproject.toml (v15)
pyproject.toml(v15版本)
toml
[build-system]
requires = ["flit_core >=3.4,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "my_custom_app"
authors = [
{ name = "Your Company", email = "dev@example.com" }
]
description = "Description of your app"
requires-python = ">=3.10"
readme = "README.md"
dynamic = ["version"]
dependencies = []
[tool.bench.frappe-dependencies]
frappe = ">=15.0.0,<16.0.0"
erpnext = ">=15.0.0,<16.0.0"See:for all configuration options.references/pyproject-toml.md
toml
[build-system]
requires = ["flit_core >=3.4,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "my_custom_app"
authors = [
{ name = "Your Company", email = "dev@example.com" }
]
description = "Description of your app"
requires-python = ">=3.10"
readme = "README.md"
dynamic = ["version"]
dependencies = []
[tool.bench.frappe-dependencies]
frappe = ">=15.0.0,<16.0.0"
erpnext = ">=15.0.0,<16.0.0"参考:所有配置选项请查看。references/pyproject-toml.md
Modules
模块
modules.txt
modules.txt
My Custom App
Integrations
Settings
ReportsRules:
- One module per line
- Spaces in name → underscores in directory
- Every DocType MUST belong to a module
My Custom App
Integrations
Settings
Reports规则:
- 每行一个模块
- 模块名称中的空格对应目录名称中的下划线
- 每个DocType必须属于一个模块
Module Directory
模块目录
my_custom_app/
├── my_custom_app/ # "My Custom App" module
│ ├── __init__.py # REQUIRED
│ └── doctype/
├── integrations/ # "Integrations" module
│ ├── __init__.py # REQUIRED
│ └── doctype/
└── settings/ # "Settings" module
├── __init__.py # REQUIRED
└── doctype/See:for module organization.references/modules.md
my_custom_app/
├── my_custom_app/ # "My Custom App" module
│ ├── __init__.py # REQUIRED
│ └── doctype/
├── integrations/ # "Integrations" module
│ ├── __init__.py # REQUIRED
│ └── doctype/
└── settings/ # "Settings" module
├── __init__.py # REQUIRED
└── doctype/参考:模块组织方式请查看。references/modules.md
Patches (Migration Scripts)
补丁(迁移脚本)
patches.txt with INI Sections
带INI分段的patches.txt
ini
[pre_model_sync]ini
[pre_model_sync]Before schema sync - old fields still available
Before schema sync - old fields still available
myapp.patches.v1_0.backup_old_data
[post_model_sync]
myapp.patches.v1_0.backup_old_data
[post_model_sync]
After schema sync - new fields available
After schema sync - new fields available
myapp.patches.v1_0.populate_new_fields
myapp.patches.v1_0.cleanup_data
undefinedmyapp.patches.v1_0.populate_new_fields
myapp.patches.v1_0.cleanup_data
undefinedPatch Implementation
补丁实现
python
undefinedpython
undefinedmyapp/patches/v1_0/populate_new_fields.py
myapp/patches/v1_0/populate_new_fields.py
import frappe
def execute():
"""Populate new fields with default values."""
batch_size = 1000
offset = 0
while True:
records = frappe.get_all(
"MyDocType",
filters={"new_field": ["is", "not set"]},
fields=["name"],
limit_page_length=batch_size,
limit_start=offset
)
if not records:
break
for record in records:
frappe.db.set_value(
"MyDocType",
record.name,
"new_field",
"default_value",
update_modified=False
)
frappe.db.commit()
offset += batch_sizeundefinedimport frappe
def execute():
"""Populate new fields with default values."""
batch_size = 1000
offset = 0
while True:
records = frappe.get_all(
"MyDocType",
filters={"new_field": ["is", "not set"]},
fields=["name"],
limit_page_length=batch_size,
limit_start=offset
)
if not records:
break
for record in records:
frappe.db.set_value(
"MyDocType",
record.name,
"new_field",
"default_value",
update_modified=False
)
frappe.db.commit()
offset += batch_sizeundefinedWhen Pre vs Post Model Sync?
何时使用Pre与Post Model Sync?
| Situation | Section |
|---|---|
| Migrate data from old field | |
| Populate new fields | |
| Data cleanup | |
See:for complete patch documentation.references/patches.md
| 场景 | 分段 |
|---|---|
| 从旧字段迁移数据 | |
| 填充新字段 | |
| 数据清理 | |
参考:完整补丁文档请查看。references/patches.md
Fixtures
Fixture
hooks.py Configuration
hooks.py 配置
python
fixtures = [
# All records
"Category",
# With filter
{
"dt": "Custom Field",
"filters": [["module", "=", "My Custom App"]]
},
# Multiple filters
{
"dt": "Property Setter",
"filters": [
["module", "=", "My Custom App"],
["doc_type", "in", ["Sales Invoice", "Sales Order"]]
]
}
]python
fixtures = [
# All records
"Category",
# With filter
{
"dt": "Custom Field",
"filters": [["module", "=", "My Custom App"]]
},
# Multiple filters
{
"dt": "Property Setter",
"filters": [
["module", "=", "My Custom App"],
["doc_type", "in", ["Sales Invoice", "Sales Order"]]
]
}
]Exporting
导出数据
bash
bench --site mysite export-fixtures --app my_custom_appbash
bench --site mysite export-fixtures --app my_custom_appCommon Fixture DocTypes
常用Fixture文档类型
| DocType | Usage |
|---|---|
| Custom fields on existing DocTypes |
| Modify field properties |
| Custom roles |
| Workflow definitions |
See:for fixture configuration.references/fixtures.md
| 文档类型 | 用途 |
|---|---|
| 现有文档类型的自定义字段 |
| 修改字段属性 |
| 自定义角色 |
| 工作流定义 |
参考:Fixture配置请查看。references/fixtures.md
Minimal hooks.py
最简hooks.py
python
app_name = "my_custom_app"
app_title = "My Custom App"
app_publisher = "Your Company"
app_description = "Description"
app_email = "dev@example.com"
app_license = "MIT"
required_apps = ["frappe"] # Or ["frappe", "erpnext"]
fixtures = [
{"dt": "Custom Field", "filters": [["module", "=", "My Custom App"]]}
]python
app_name = "my_custom_app"
app_title = "My Custom App"
app_publisher = "Your Company"
app_description = "Description"
app_email = "dev@example.com"
app_license = "MIT"
required_apps = ["frappe"] # Or ["frappe", "erpnext"]
fixtures = [
{"dt": "Custom Field", "filters": [["module", "=", "My Custom App"]]}
]Creating and Installing App
创建与安装应用
bash
undefinedbash
undefinedCreate new app
Create new app
bench new-app my_custom_app
bench new-app my_custom_app
Install on site
Install on site
bench --site mysite install-app my_custom_app
bench --site mysite install-app my_custom_app
Migrate (patches + fixtures)
Migrate (patches + fixtures)
bench --site mysite migrate
bench --site mysite migrate
Build assets
Build assets
bench build --app my_custom_app
---bench build --app my_custom_app
---Version Differences
版本差异
| Aspect | v14 | v15 |
|---|---|---|
| Build config | setup.py | pyproject.toml |
| Dependencies | requirements.txt | In pyproject.toml |
| Build backend | setuptools | flit_core |
| Python minimum | >=3.10 | >=3.10 |
| INI patches | ✅ | ✅ |
| 方面 | v14 | v15 |
|---|---|---|
| 构建配置 | setup.py | pyproject.toml |
| 依赖 | requirements.txt | 在pyproject.toml中配置 |
| 构建后端 | setuptools | flit_core |
| 最低Python版本 | >=3.10 | >=3.10 |
| INI格式补丁 | ✅ | ✅ |
Critical Rules
关键规则
✅ ALWAYS
✅ 必须遵守
- Define in
__version____init__.py - Add in pyproject.toml
dynamic = ["version"] - Register modules in
modules.txt - Include in EVERY directory
__init__.py - Put Frappe dependencies in
[tool.bench.frappe-dependencies] - Add error handling in patches
- Use batch processing for large datasets
- 在中定义
__init__.py__version__ - 在pyproject.toml中添加
dynamic = ["version"] - 在中注册模块
modules.txt - 每个目录都必须包含
__init__.py - 将Frappe依赖放在中
[tool.bench.frappe-dependencies] - 在补丁中添加错误处理
- 对大型数据集使用批量处理
❌ NEVER
❌ 严禁操作
- Put Frappe/ERPNext in project dependencies (not on PyPI)
- Create patches without error handling
- Include user/transactional data in fixtures
- Hardcode site-specific values
- Process large datasets without batching
- 不要将Frappe/ERPNext加入项目依赖(它们不在PyPI上)
- 不要创建无错误处理的补丁
- 不要在Fixture中包含用户/交易数据
- 不要硬编码特定站点的值
- 不要不进行批量处理就直接处理大型数据集
Fixtures vs Patches
Fixture与补丁的对比
| What | Fixtures | Patches |
|---|---|---|
| Custom Fields | ✅ | ❌ |
| Property Setters | ✅ | ❌ |
| Roles/Workflows | ✅ | ❌ |
| Data transformation | ❌ | ✅ |
| Data cleanup | ❌ | ✅ |
| One-time migration | ❌ | ✅ |
| 用途 | Fixtures | Patches |
|---|---|---|
| 自定义字段 | ✅ | ❌ |
| 属性设置器 | ✅ | ❌ |
| 角色/工作流 | ✅ | ❌ |
| 数据转换 | ❌ | ✅ |
| 数据清理 | ❌ | ✅ |
| 一次性迁移 | ❌ | ✅ |
Reference Files
参考文件
| File | Contents |
|---|---|
| Complete directory structure |
| Build configuration options |
| Module organization |
| Migration scripts |
| Data export/import |
| Complete app examples |
| Mistakes to avoid |
| 文件 | 内容 |
|---|---|
| 完整目录结构 |
| 构建配置选项 |
| 模块组织方式 |
| 迁移脚本文档 |
| Fixture配置文档 |
| 完整应用示例 |
| 需避免的错误做法 |
See Also
相关链接
- - For hooks.py configuration
erpnext-syntax-hooks - - For DocType controllers
erpnext-syntax-controllers - - For implementation patterns
erpnext-impl-customapp
- - 用于hooks.py配置
erpnext-syntax-hooks - - 用于DocType控制器
erpnext-syntax-controllers - - 用于实现模式
erpnext-impl-customapp