页面

您可以通过向网站的 /www 文件夹添加页面来创建您的网站。您网站的 URL 将与 /www 文件夹中页面的路径相匹配。

页面必须是 .html 或 .md(Markdown)文件。frappe 中的 frappe/templates/base_template.html 提供了基本的 HTML 模板。

脚本报表

您可以通过创建新的报表,使用服务器端脚本来生成表格形式的报表。

注意:您需要拥有管理员权限才能执行此操作。

由于这些报表通过 Python 脚本为您提供不受限制的访问权限,因此只能由管理员创建。报表的脚本部分会成为应用程序代码库的一部分。如果您尚未创建应用程序,请阅读此文档。

注意:您必须处于开发者模式才能执行此操作。

1. 创建新报表

  1. 将“报表类型”设置为“脚本报表”
  2. 将“是否标准”设置为“是”
  3. 选择您要添加此报表的模块
  4. 在模块文件夹中(例如,如果是在 ERPNext 的 Accounts 模块中,文件夹将为 erpnext/accounts/report/[report-name]),您会看到将创建报表文件的模板。
  5. 在 .js 文件中,您可以为报表设置筛选条件。
  6. 在 .py 文件中,您可以编写用于生成报表的脚本。

2. 添加筛选条件

您可以在 .js 中添加筛选条件。示例如下:

frappe.query_reports["Accounts Receivable"] = {
    "filters": [
        {
            "fieldname":"company",
            "label": ("Company"),
            "fieldtype": "Link",
            "options": "Company",
            "default": frappe.defaults.getuserdefault("company")
        },
    ]
}
  1. 这些属性的设置方式与您在 DocType 中设置 DocField 时相同。

3. 添加脚本

在 .py 文件中,您可以添加用于生成报表的脚本。

  1. 在 execute 方法中,会返回两个列表 columns 和 data。
  2. 列必须是一个字典列表,其中包含 fieldname、label、fieldtype、options、width 等字段。例如:
[
    {
        "fieldname": "account",
        "label": _("Account"),
        "fieldtype": "Link",
        "options": "Account",
        "width": 300,
    },
    {
        "fieldname": "currency",
        "label": _("Currency"),
        "fieldtype": "Link",
        "options": "Currency",
    },
]
  1. 您可以使用所有服务器端模块来构建您的报表。
  2. 例如,请参阅现有报表(如资产负债表)。

  1. 在模块文件夹中(例如,如果是在 ERPNext 的 Accounts 模块中,文件夹将为 erpnext/config/accounts.py),您会看到各个部分的标签和项目。新报表可以添加到项目列表中,如下例所示:
def get_data():
    return [
        {
            "label": _("Accounting Statements"),
            "items": [
                {
                    "type": "report",
                    "name": "Balance Sheet",
                    "doctype": "GL Entry",
                    "is_query_report": True,
                }
            ],
        }
    ]

预生成报表

某些脚本报表在浏览器中运行时间过长。预生成报表 会将执行过程移至后台任务,这样用户在报表运行时就不会被阻塞。

当在报表上勾选预生成报表选项时,每次运行都会被加入队列,而不是同步执行。用户会看到进度指示器,并在结果准备好时收到通知。完成的结果会作为预生成报表文档存储,之后可以使用相同的筛选条件重新打开。

预生成报表还解锁了以下功能:

  • 生成 CSV — 可选择在 JSON 结果之外同时生成 CSV 附件
  • 超时时间(秒) — 后台任务在被视为失败之前可以运行的时间长度(默认值:1500 秒)

预生成报表适用于运行缓慢但稳定的报表。用户需要等待并稍后回来查看结果,而不是在浏览器中立即获得表格。

报表打印格式

在 4.1 版本中,我们引入了报表打印格式。这些是 HTML 模板,您可以使用它们来格式化查询报表数据以供打印。

1. 创建新的打印格式

要创建新的打印格式,只需在查询报表的文件夹中放入一个 .html 文件。例如,对于 ERPNext 中的总分类账报表,您可以在 .js 和 .py 文件旁边放入一个名为 general_ledger.html 的文件。

erpnext/accounts/general_ledger 的目录结构
general_ledger/
├── __init__.py
├── general_ledger.html
├── general_ledger.js
├── general_ledger.json
└── general_ledger.py

2. 模板语法

对于模板,我们使用了 John Resig 的微模板脚本的改编版本。如果您了解 Javascript,那么掌握这种模板语言会非常容易。

以下是一些示例(来自 John Resig 的博客):

示例:属性:

![](<%=profile_image_url%>)

**[<%=from_user%>](<%=from_user%>):** <%=text%>

示例:代码结构、循环

<% for ( var i = 0; i < users.length; i++ ) { %>
- [<%=users[i].name%>](<%=users[i].url%>)
<% } %>

注意:请务必注意,您不应在模板中使用单引号(’),因为引擎无法有效处理它们。

3. 数据

模板可用的数据如下:

  • data:这是一个记录列表,每条记录是一个对象,其属性由标签转换为 slug 格式。例如,“过账日期”变为“posting_date”
  • filters:报表中设置的筛选条件
  • report:报表视图对象

4. 示例

以下是总分类账报表的构建方式:

总分类账打印格式模板

报表效果如下:

注释:
  1. Bootstrap 样式表已预先加载。
  2. 您可以使用所有全局函数,如 fmt_money 和 dateutil。
  3. 可翻译的字符串应写成 __("text") 的形式。
  4. 您可以使用 {% include "templates/includes/formats/common_format" %} 创建模块并进行导入。

如何制作查询报表

您可以通过创建新的报表,使用复杂的 SQL 查询来生成表格形式的报表。这些报表可由系统管理员创建,并存储在数据库中。

注意:您需要拥有系统管理员权限才能执行此操作。

要创建新的查询报表:

1. 创建新报表

  1. 将类型设置为“查询报表”
  2. 设置参考文档类型 – 拥有该参考文档类型访问权限的用户将可以访问此报表
  3. 设置模块 – 该报表将出现在模块的“自定义报表”部分中。
  4. 添加您的查询语句

2. 设置查询

您可以定义复杂的查询,例如:

SELECT
tabProduction Order.name as “生产订单:Link/生产订单:200”,
tabProduction Order.creation as “日期:Date:120”,
tabProduction Order.production_item as “物料:Link/物料:150”,
tabProduction Order.qty as “待生产数量:Int:100”,
tabProduction Order.produced_qty as “已生产数量:Int:100”
FROM
tabProduction Order
WHERE
tabProduction Order.docstatus=1
AND ifnull(tabProduction Order.produced_qty,0) = tabProduction Order.qty
AND EXISTS (SELECT name from tabStock Entry where production_order =tabProduction Order.name)

  1. 要格式化列,请按以下格式为每列设置标签:[标签]:[字段类型]/[选项]:[宽度]

3. 检查报表

4. 高级(添加筛选器)

如果您正在制作标准报表,可以通过在查询报表文件夹中添加 .js 文件,像脚本报表一样在查询报表中添加筛选器。要在查询中包含筛选器,请使用 %(filter_key)s,该位置将显示您的筛选值。

例如

SELECT … FROM … WHERE item_code = %(item_code)s ORDER BY …


注意:标准脚本报表

如果您正在为某个应用开发标准报表,请务必将“是否标准”设置为“是”

在哪里找到标准打印格式

标准打印格式是根据 DocType 的布局自动生成的。您可以通过以下方式自定义标准格式:

1. 自定义标准打印

前往 设置 > 自定义 > 自定义表单视图,您可以:

  1. 通过拖放重新排列字段
  2. 通过添加 HTML 类型字段并在选项中添加您的 HTML 来添加静态元素
  3. 通过设置打印隐藏属性来隐藏字段

2. 基于打印格式创建新布局

由于标准打印格式没有生成的模板,您需要使用 Jinja 模板语言从头创建新模板,具体操作如下:

设置 > 打印和品牌 > 打印格式

  1. 查看打印格式帮助。
  2. 您可以使用 Bootstrap CSS 框架来布局您的打印格式

提示:您可以导入标准模板宏来构建您的打印格式。

例如,添加标准页眉:

{%- from "templates/print_formats/standard_macros.html" import add_header -%}

{{ add_header() }}

如何启用社交登录

使用 Facebook、Google 或 GitHub 身份验证登录 Frappe,您的用户将无需再记住另一个密码。

系统使用这些服务提供的电子邮件地址来匹配 Frappe 中的现有用户。如果未找到此类用户,且网站设置中未禁用注册功能,则会创建一个默认类型为“网站用户”的新用户。任何系统管理员之后都可以将用户类型从“网站用户”更改为“系统用户”,以便该用户可以访问桌面。

启用社交登录后的登录界面

要启用这些注册功能,您需要从这些身份验证服务中为您的 Frappe 站点获取客户端 ID 和客户端密钥。客户端 ID 和客户端密钥需在 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端 ID 和 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端密钥 中设置。以下是获取这些凭据的步骤。

如果您的站点启用了 HTTPS,请使用 https://{{ yoursite }}。


Frappe

这里假设您在 Frappe 框架上构建了两个站点。站点 A 是 https://sitea.com,站点 B 是 https://siteb.com。您希望使用 https://sitea.com 作为登录提供方,并在 https://siteb.com 上设置社交登录,以便通过 https://sitea.com 登录。

  1. 前往作为登录提供方的 https://sitea.com
  2. 转到 OAuth 客户端列表
  3. 创建新的 OAuth 客户端
  4. 输入应用程序名称(用于标识站点 B 的名称)
  5. 在“重定向 URI”和“默认重定向 URI”中输入 https://siteb.com/api/method/frappe.integrations.oauth2_logins.login_via_frappe
  6. 保存文档后,将生成应用程序客户端 ID 和应用程序客户端密钥
  7. 前往您要设置社交登录的 https://siteb.com
  8. 转到“社交登录密钥”并创建一个新密钥
  9. 输入在步骤 6 中获取的客户端 ID 和客户端密钥
  10. 选择“Frappe”作为社交登录提供方
  11. 输入 https://sitea.com 作为基础 URL,然后保存文档。

Facebook

  1. 前往 https://developers.facebook.com
  2. 点击(顶栏中的)“应用”> “新建应用”,并填写表单。
  3. 转到“设置”> “基本”,设置联系邮箱并保存更改。
  4. 转到“设置”> “高级”,找到有效的 OAuth 重定向 URI 字段,并输入:
    http://{{ yoursite }}/api/method/frappe.integrations.oauth2_logins.login_via_facebook
  5. 在“高级”选项卡中保存更改。
  6. 转到“状态和审核”,并开启“您是否希望将此应用及其所有实时功能提供给公众?”
  7. 转到“仪表盘”,点击“应用密钥”旁边的“显示”按钮,将应用 ID 和应用密钥复制到 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端 ID 和 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端密钥 中。

Google

  1. 前往 https://console.developers.google.com
  2. 创建一个新项目并填写表单。
  3. 点击“API 和服务”> “凭据”> “创建新的客户端 ID”
  4. 填写表单:
  • Web 应用程序
  • 已授权的 JavaScript 来源为 http://{{ yoursite }}
  • 已授权的重定向 URI 为
    http://{{ yoursite }}/api/method/frappe.integrations.oauth2_logins.login_via_google
  1. 转到“Web 应用程序的客户端 ID”部分,将客户端 ID 和客户端密钥复制到 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端 ID 中。

GitHub

  1. 前往 https://github.com/settings/applications
  2. 点击“注册新应用程序”
  3. 填写表单:
  • 主页 URL 为 http://{{ yoursite }}
  • 授权回调 URL 为
    http://{{ yoursite }}/api/method/frappe.integrations.oauth2_logins.login_via_github
  1. 点击“注册应用程序”。
  2. 将生成的客户端 ID 和客户端密钥复制到 桌面 > 网站 > 设置 > 社交登录密钥 和 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端密钥 中。

Office 365

  1. 前往 https://portal.azure.com
  2. 创建新的 Azure Active Directory > 应用注册。
  3. 点击“新建应用程序注册”
  4. 填写表单:
  • 应用程序名称
  • 选择“任何组织目录中的帐户(任何 Azure AD 目录 – 多租户)”。
  • 应用程序类型 – Web 应用 / API
  • 重定向 URI 为
  • 主页 URL 为 http://{{ yoursite }}
  • 授权回调 URL 为 http://{{ yoursite }}//api/method/frappe.integrations.oauth2_logins.login_via_office365
  1. 点击“注册应用程序”。
  2. 转到 Azure 门户中的“概述”部分,将应用程序(客户端)ID 复制到 **桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端 ID
  3. 转到 Azure 门户中的“证书和机密”部分,创建新的客户端机密,然后通过添加到 桌面 > 集成 > 身份验证 > 社交登录密钥 > 客户端密钥 来复制客户端机密。
  4. 选择“Office 365”作为社交登录提供方
  5. 点击“启用社交登录”并保存
  6. 转到“令牌配置”部分,点击“添加可选声明”
  • 添加令牌类型 > ID > 电子邮件

迁移

项目在其生命周期中经常会经历与数据库结构相关的变更。
有时也可能需要对现有数据进行修补。Frappe 内置了处理这些场景的工具。

当你从任何 Frappe 应用(包括 Frappe 本身)拉取更新时,应运行
bench migrate 来应用结构变更和数据迁移(如果有)。

结构变更

你可以编辑 DocType 来添加、删除或修改字段。保存 DocType 时,
包含 DocType 数据的 JSON 文件会被添加到应用的源代码树中。
当你将应用添加到站点时,DocType 会使用此 JSON 文件进行安装。
要进行结构变更,需要在配置中设置 developer_mode。

运行同步(bench migrate)时,系统中的 doctype 会根据应用中的 JSON 文件
同步到其最新版本。

注意:字段是软删除的,即列不会从数据库表中移除,
但它们将不会在文档中可见。这样做是为了避免任何潜在的数据丢失情况,
并允许你编写可能需要已删除字段值的数据迁移脚本。

注意:Frappe 不支持反向结构迁移。

数据迁移

在引入与数据相关的更改时,你可能希望运行一次性脚本来
修改现有数据,以符合新代码的预期。

要向代码中添加数据迁移,你需要编写一个 execute
函数到一个 Python 模块中,并将其添加到应用的 patches.txt 中。
或者,你可以使用以下命令以交互方式创建一个新的补丁:

$ bench create-patch
Select app for new patch (frappe, hrms, ecommerce_integrations, erpnext): frappe
Provide DocType name on which this patch will apply: User
Describe what this patch does: Improve Indexing
Provide filename for this patch [improve_indexing.py]:
Patch folder '/home/ankush/benches/develop/apps/frappe/frappe/core/doctype/user/patches' doesn't exist, create it? [Y/n]: y
Created /home/ankush/benches/develop/apps/frappe/frappe/core/doctype/user/patches/improve_indexing.py and updated patches.txt

建议在路径中创建一个包含补丁编号和名称的文件,
并将其添加到应用中的补丁包(目录)中。然后,你可以将补丁模块的
点分路径添加到 patches.txt 中。

Frappe 中遵循的目录结构如下所示:

frappe
└── patches
└── 4_0
└── my_awesome_patch.py

可以通过添加如下一行来将补丁添加到 patches.txt:

frappe.patches.4_0.my_awesome_patch

在 execute 函数中可用的元数据(即 DocType)将是应用中的 JSON 文件所对应的
最新版本。但是,你将无法访问系统任何先前状态的元数据。

一次性 Python 语句

你还可以使用以下语法在 patches.txt 中添加一次性 Python 语句:
execute:{python 语句}

例如:
execute:frappe.get_doc(“User”, “Guest”).save()

注意:patches.txt 中的所有行必须是唯一的。如果你想运行某行两次,
可以通过添加不同的注释使其唯一。

例如:

execute:frappe.installer.make_site_dirs() #2014-02-19

如何将文档类型变更迁移到生产环境

1. 文档类型 / 架构变更

如果您处于 developer_mode 中,每个 DocType 对应的 .json 文件会自动更新。

当您在生产环境中通过 --latest 或 bench update 进行更新时,这些更改也会同步到站点的架构中!

2. 权限

权限不会自动更新,因为用户可能已经对其进行了修改。若要更新权限,您可以在应用的 patches.txt 中添加一个新的补丁。

执行:frappe.permissions.reset_perms(“[docype]”)

后台任务失败邮件通知

Frappe 按以下方式处理任务失败:

  1. 如果任务失败(抛出异常),它会被记录在调度器日志和 logs/worker.error.log 中。
  2. 系统会保留一个锁文件,如果锁文件存在,则不再运行该任务。
  3. 如果锁文件存在时间超过 10 分钟,则会抛出 LockTimeoutError 异常。

您可以通过编写一个内容如下的文件 sites/common_site_config.json 来配置调度器错误的邮件通知。

{
  "celery_error_emails": {
 "ADMINS": [
 [
 "Person 1",
 "[email protected]"
 ],
 [
 "Person2 ",
 "[email protected]"
 ]
 ],
 "SERVER_EMAIL": "[email protected]"
 }
}

一个限制是,它将使用本地邮件服务器(端口 25)来发送邮件。