☰
ERPNext 地区地址模板(Regional Address Template)开发指南:用 Jinja 为每个国家定制地址打印格式
2026/10/1 10:01:35 网站建设 项目流程
  • 后端
  • 企业应用

【免费下载链接】erpnext

Free and Open Source Enterprise Resource Planning (ERP)

项目地址:https://gitcode.com/GitHub_Trending/er/erpnext
点击查看免费下载

本文以 ERPNext 仓库中的 地址模板说明文档 为骨架,系统讲解如何为特定国家新增地址打印模板:从文件命名规则、Jinja 模板语法、可用字段,到模板的安装导入机制、渲染调用链与测试验证。读完本文,你将掌握在 ERPNext 中为一国地址定制打印版式(如邮编与城市排列、州省略规则、电话/传真展示等)的完整开发与调试方法。

一、Address Template 解决什么问题

在 ERPNext 中,Address(地址)是贯穿客户、供应商、公司、发货与开票的核心单据,凡是需要打印地址的场景——发票抬头、收货地址、公司信纸、发货标签——最终都以纯文本或多行 HTML 的形式呈现。但不同国家对地址书写格式有各自的习惯:

  • 美国习惯City, State Zip一行式排列,且本国地址不重复输出国家名;
  • 德国习惯邮编 城市且城市名大写,国家名大写置于末尾;
  • 台湾地区习惯国家 → 邮编 → 县市 → 地址逐级递减的倒序排版,并附带电话/传真/邮箱。

ERPNext 通过「地区地址模板(Address Template)」机制解决这一差异:每个国家可以拥有自己的一份Jinja 模板,系统根据地址所属国家自动选择对应模板来渲染地址显示文本。

二、如何为你的国家添加地址模板

根据 官方说明,只需两步:

2.1 文件命名规则

在erpnext/regional/address_template/templates/目录下放置一个新文件:

  • 文件名为:your_country.html,使用小写字母 + 下划线格式;
  • 文件内容为:一份 Jinja Template 模板。

例如美国对应united_states.html,德国对应germany.html。文件名会被自动转换为国家显示名(见下文安装机制中的country()函数),因此请确保文件名与国家名称一一对应。

2.2 模板内容与可用字段

模板中可以直接使用Address 单据的全部字段,包括通过自定义字段(Custom Fields)新增的字段。官方文档给出的基础示例:

{{ address_line1 }}<br> {% if address_line2 %}{{ address_line2 }}<br>{% endif -%} {{ city }}<br> {% if state %}{{ state }}<br>{% endif -%} {% if pincode %} PIN: {{ pincode }}<br>{% endif -%} {{ country }}<br> {% if phone %}Phone: {{ phone }}<br>{% endif -%} {% if fax %}Fax: {{ fax }}<br>{% endif -%} {% if email_id %}Email: {{ email_id }}<br>{% endif -%}

从示例与仓库内置模板中可以看到,地址模板常用字段包括:address_line1、address_line2、city、state、pincode、country、county、phone、fax、email_id等。

Jinja 模板要点
  • 普通输出:{{ field_name }},如{{ address_line1 }};
  • 条件输出:{% if field %}...{% endif -%},字段为空时跳过整段内容;
  • 行尾-%}是 Jinja 的空白控制符,用于去除紧跟其后的换行,避免生成多余空行;
  • 可调用 Jinja 内置过滤器,如{{ city | upper }}将城市名转为大写;
  • 可用{% if country != "United States" %}这类条件表达式做逻辑判断。

三、仓库内置模板实例解析

仓库在erpnext/regional/address_template/templates/下内置了 9 个国家/地区的模板,是学习地址格式差异的最佳范本:

文件格式特点
germany.html邮编 城市(城市名大写)+ 国家名大写,标准德语地址格式
denmark.html、sweden.html同德国式邮编 城市+ 国家名大写
united_states.htmlCity, State Zip单行式;{% if country != "United States" %}在本国地址中省略国家名
taiwan.html倒序排版:国家 → 邮编 → 县市(county)→ 地址行,末尾追加电话/传真/邮箱
bosnia_and_herzegovina.html、croatia.html、luxembourg.html、switzerland.html各按本国习惯排列基础字段

以 德国模板 为例:

{{ address_line1 }}<br> {% if address_line2 %}{{ address_line2 }}<br>{% endif -%} {{ pincode }} {{ city | upper }}<br> {{ country | upper }}

而以 美国模板 为例,它用条件判断在地址属于美国本土时省略国家字段,非常典型:

{{ address_line1 }}<br> {% if address_line2 %}{{ address_line2 }}<br>{% endif -%} {{ city }}, {% if state %}{{ state }}{% endif -%}{% if pincode %} {{ pincode }}{% endif -%}<br> {% if country != "United States" %}{{ country }}{% endif -%}

需要说明的是,county(县/郡)等字段来自 Frappe 框架contacts模块中Address单据的定义,因此字段是否可用以实际启用的 Address 表单为准;你在自定义字段中添加的任何字段同样会被传入模板。

四、模板的安装与导入机制(源码级)

仅仅放置 HTML 文件还不够,ERPNext 会在安装/初始化时把这些文件写入数据库中的Address Template单据(DocType)。这段逻辑位于 setup.py:

def set_up_address_templates(default_country=None): for country, html in get_address_templates(): is_default = 1 if country == default_country else 0 update_address_template(country, html, is_default)

其工作流程分三步:

4.1 扫描templates/目录

get_address_templates()遍历erpnext/regional/address_template/templates/目录下所有.html文件,并做两个转换:

def country(file_name): """Convert 'united_states.html' to 'United States'.""" suffix_pos = file_name.find(".html") country_snake_case = file_name[:suffix_pos] country_title_case = " ".join(country_snake_case.split("_")).title() return country_title_case
  • united_states.html→United States
  • bosnia_and_herzegovina.html→Bosnia And Herzegovina

这正解释了命名规则中「小写 + 下划线」的要求——文件名必须能被程序自动还原为国家标题。

4.2 校验并写入Address Template单据

update_address_template(country, html, is_default)负责持久化:

  • 若Country单据中不存在该国,记录错误日志后跳过(防止脏数据);
  • 若Address Template已存在,则用frappe.db.set_value更新template与is_default字段;
  • 若不存在,则frappe.get_doc(...).insert()新建单据。

4.3 在安装流程中被调用

在 install_fixtures.py 的初始化阶段(第 361 行),安装向导会调用:

set_up_address_templates(default_country=country)

default_country由安装向导选择的默认国家传入,该国模板会被标记为is_default = 1;该文件第 30~31 行同时确保即使没有地区模板,也至少为安装国创建一个空白的Address Template单据。

五、模板如何被渲染使用

模板的最终消费点在 ERPNext 对Address的扩展类中:accounts/custom/address.py 的get_shipping_address白名单方法:

address_as_dict = address[0] name, address_template = get_address_templates(address_as_dict) return address_as_dict.get("name"), frappe.render_template( address_template, address_as_dict, restrict_globals=True )
  • get_address_templates(address_as_dict)来自 Frappe 框架frappe.contacts.doctype.address.address,它会根据地址的国家字段匹配对应的Address Template单据并取回模板内容;
  • frappe.render_template(template, context, restrict_globals=True)使用 Jinja 渲染模板,address_as_dict作为上下文,因此 Address 的所有字段(含自定义字段)都能在模板中以{{ 字段名 }}直接引用;
  • restrict_globals=True限制模板可访问的全局对象,防止任意代码执行,属于安全加固。

注意区分两个同名的get_address_templates:setup.py中的用于导入(读取本地 HTML 文件),address.py中从 Frappe contacts 模块导入的用于渲染(按国家查数据库模板)。二者分别在开发期和运行期发挥作用。

六、如何验证你的模板

仓库提供了完整的单元测试:test_regional_address_template.py,覆盖导入与持久化两个环节:

def test_get_address_templates(self): """Get the countries and paths from the templates directory.""" templates = get_address_templates() self.assertIsInstance(templates, list) self.assertIsInstance(templates[0], tuple) def test_create_address_template(self): """Create a new Address Template.""" country = ensure_country("Germany") update_address_template(country.name, "TEST") doc = frappe.get_doc("Address Template", country.name) self.assertEqual(doc.template, "TEST") def test_update_address_template(self): """Update an existing Address Template.""" ... update_address_template(country.name, "NEW") doc = frappe.get_doc("Address Template", country.name) self.assertEqual(doc.template, "NEW")

测试验证了三点关键行为:目录扫描能正确返回(国家, HTML内容)元组列表;新建国家模板后数据库记录与文件内容一致;重复导入会更新而非重复创建。开发新模板时,可以仿照此测试补充针对你自己国家模板的断言。

七、端到端实操清单

  1. 编写模板:在erpnext/regional/address_template/templates/下新建your_country.html,参考 README 示例 与 德国模板、美国模板 的写法;
  2. 保证命名对应:确认文件名下划线命名可逆转为Country单据中已存在的国家名,否则导入时会被update_address_template跳过并记入错误日志;
  3. 触发导入:运行bench migrate或在安装向导中重新执行初始化(set_up_address_templates),模板将被写入Address Template单据;也可以在系统内直接编辑该单据的template字段;
  4. 验证渲染:为某个 Address 记录设置对应国家,通过调用get_shipping_address或在相关单据的地址打印处观察输出;
  5. 跑测试:执行bench run-tests --module erpnext.regional.address_template(或按项目测试约定运行ERPNextTestSuite)确认导入逻辑无回归。

八、小结

ERPNext 的地区地址模板是一个「约定优于配置」的轻量扩展点:放一个符合命名约定的 Jinja 文件到templates/目录,安装时自动入库,运行时按地址国家自动选模板渲染。它既能覆盖各国千差万别的地址排版习惯,又通过自定义字段透传保留了充分的灵活性,是理解 ERPNext「区域化定制」设计模式的绝佳入口。

  • 后端
  • 企业应用

【免费下载链接】erpnext

Free and Open Source Enterprise Resource Planning (ERP)

项目地址:https://gitcode.com/GitHub_Trending/er/erpnext
点击查看免费下载

相关推荐

上一篇:Path of Building 完整上手:离线模拟天赋、评估装备,算清流放之路 Build 的真实 DPS
下一篇:BepInEx终极指南:3步搞定Unity游戏模组框架安装、排错与插件开发

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询