如何启用备份加密

备份过程中创建的文件可以使用自动生成的密钥进行加密。

系统要求

对于 MacOS,请确保系统中已安装 gnupg。使用以下命令安装 gnupg:

brew install gnupg

大多数 Linux 发行版已经预装了 GnuPG,当前版本很可能默认使用 GnuPG 2.0。

加密备份选项

  1. 打开系统设置表单。
  2. 在备份部分中,勾选加密备份复选框。

系统使用由站点配置提供的自动生成的密钥。如果找不到此类密钥,则会生成一个新密钥。任何系统管理员之后都可以在下载备份页面查看该密钥。

它会对公共文件、私有文件以及部分备份文件进行加密。

备份加密状态

  1. 加密备份存储在常规备份的相同位置:YOUR_BENCH/sites/{site}/private/backups。
  2. 加密备份可以从下载备份页面下载。
  3. 加密备份通过 key icon 进行区分。

备份加密密钥

  1. 要获取备份加密密钥,请前往下载备份页面。
  2. 点击“获取加密密钥”按钮并验证您的密码。

复制该密钥以恢复加密的备份文件。

恢复加密的备份文件

  1. 可以使用 bench restore SQL_FILE_PATH 恢复文件,无需 --backup-encryption-key,因为它会自动从站点配置中获取。
  2. 如果因密钥错误导致恢复失败,可以使用 --backup-encryption-key 提供密钥来恢复文件。
  3. 用法:
    对于完整备份文件
    bench --site {site} restore --backup-encryption-key {key} [OPTIONS]
    对于部分备份文件
    bench --site {site} partial-restore --backup-encryption-key {key} [OPTIONS]

手动解密加密的备份文件

gpg --yes --passphrase $BACKUP_ENCRYPTION_KEY --pinentry-mode loopback -o $OUTPUT_FILE -d $INPUT_FILE

批次拆分

将一大批物料转化为许多小的、可单独追溯的批次,每切割出一件,就对应一个批次。

场景故事:切割一根 50 公斤的棒材

您的工厂购买了一根 50 公斤的铁棒。它作为一个批次到达,对应一次采购、一份质量证书、一个批号。在车间,您将它切割成五段,每段 10 公斤,从那一刻起,这些分段就各自独立:它们会进入不同的机器、不同的订单,甚至可能交付给不同的客户。

如果这五段都沿用铁棒原来的单一批号,您就无法单独追踪它们。批次拆分功能可以解决这个问题:在切割时,ERPNext 会自动为每一段创建一个新批次,并且每个新批次都会记录它来自哪根铁棒。

BCH-000001  Iron Rod · 50 KG
     │
     ✂  cut into pieces of 10 KG
     │
     ├─ BCH-000002  10 KG
     ├─ BCH-000003  10 KG
     ├─ BCH-000004  10 KG
     ├─ BCH-000005  10 KG
     └─ BCH-000006  10 KG

每一段都会根据物料的常规批次系列获得自己的批号。每一段都会将 BCH-000001 记录为其父批次,因此,对任何一段的投诉都可以追溯到确切的那根铁棒、其供应商及其采购收货单。

何时使用此功能

当散装物料被物理分割成多个部分,并且您需要单独跟踪每个部分时,请使用批次拆分功能:

  • 金属棒材、条材或管材按长度切割
  • 钢卷或纸卷分切成较小的卷材
  • 布料或薄膜卷切割成较短的卷材
  • 从原木上切割出的木板

它不适用于混合或掺混(多种投入变成一种产出)的情况,也不适用于您根本不按批次跟踪的物料。

开始之前

在代表切割后部件(产出)的物料上,启用以下设置:

物料设置 原因
具有批号 部件需要按批次进行跟踪。
自动创建新批次 ERPNext 会在切割时自动为您创建部件批次。
批次号系列 新部件批次将按物料自身的系列编号,例如 BCH-.######。

您切割的原材料(铁棒)也必须是按批次跟踪的物料,这样系统才能确切知道每个部件来自哪根铁棒。

方式 1 – 作为生产制造中的一个步骤

当切割是生产过程中的一道工序时使用此方法,例如,在机械加工件的工艺路线中有一个名为棒材切割的工序。

  1. 打开物料清单 (BOM) 并启用跟踪半成品,以便每道工序都产出自己的物料项目。
  2. 在切割工序行上,勾选批次拆分并设置单件重量 — 对于我们的棒材,设置为 10。
  3. 照常进行生产:创建生产工单,然后为切割工序创建作业卡。两者都会自动携带批次拆分设置。
  4. 完成作业卡并制作其库存单据。原材料消耗和产出数量与往常完全一致 — 产出 50 仍然消耗 50。
  5. 提交。 ERPNext 将产出数量除以单件重量(50 ÷ 10 = 5),并创建五个批次,每批 10 个,每个批次都链接到其父棒材批次。

温馨提示: 单件重量仅控制产出如何分批。它绝不会改变原材料的消耗量,消耗量仍遵循您的 BOM 数量。

方式 2 – 从仓库进行手动拆分

当没有生产订单时使用此方法,仓库管理员只需切割一根棒材,并希望货架上的部件作为单独的批次存在。

  1. 创建库存单据并选择类型批次拆分(这是内置类型,用途为重新包装)。
  2. 设置单件重量 — 选择批次拆分类型后,该字段会立即出现。
  3. 添加两行:被消耗的棒材(源仓库,数量 50)和被生产的部件物料(目标仓库,数量 50,标记为成品物料)。
  4. 提交。 系统会创建五个 10 单位的批次并放入库存,每个批次都指向其切割来源的棒材。

系统会为您检查的内容

规则 示例
产出数量必须能被单件重量整除。 50 ÷ 10 = 5 件 ✓ · 55 ÷ 10 会被拒绝。
只能消耗一种按批次跟踪的原材料,以确保来源明确无误。 切割只消耗棒材 — 不能同时消耗棒材和卷材。
每个被消耗的批次必须能够提供完整的部件。一个部件总是从一根棒材上切割而来 — 绝不会由两根拼接而成。 两根 25 公斤的棒材可以产出四件完整的 10 公斤部件,而不是五件。要求五件会被拒绝并给出明确提示。
当消耗多根棒材时,部件将按每根棒材供应的比例进行分配。 一根 30 公斤和一根 20 公斤的棒材制作五件 → 第一根产出 3 件,第二根产出 2 件。

事后追溯拆分记录

打开任何作为拆分一部分的批次,你会看到一个批次拆分树按钮。点击后会打开一个报告,显示完整的家族关系,从上到下——原始棒材位于根部,其分割件缩进显示在下方,任何进一步的切割件则继续缩进排列:

BCH-000001   Iron Rod        50 KG   ← the purchased rod
├─ BCH-000002   10 KG
├─ BCH-000003   10 KG
│  ├─ BCH-000007    5 KG   ← this piece was cut again
│  └─ BCH-000008    5 KG
├─ BCH-000004   10 KG
├─ BCH-000005   10 KG
└─ BCH-000006   10 KG

每个批次恰好有一个父级,因为每个物理件都是从一根物理棒材上切割下来的。再次切割的件本身就成为父级——树的深度可以随你的工艺流程无限延伸。

如果拆分条目被取消

取消库存条目会逆转库存变动,但已创建的批次记录会被保留,这是ERPNext对自动创建批次的标准行为。这些批次不持有库存,会从批次拆分树中消失,也不会造成干扰。只需重新创建一条新条目即可再次拆分。

替代成品

问题

在流程行业(例如化工行业)中,有时工单生产出的可销售物料与预期的成品不同,可能是质检时发现的不同等级或规格。它既不是废品,也不是预期的成品。

此功能是什么?

使用此功能,您可以一键告诉 ERPNext:“此工单实际生产的是物料 B,而不是物料 A。” 系统会创建一张关联到该工单的库存凭证,将库存从计划物料转移到实际物料,结转生产成本,并在生产报表中显示真实产出。

何时使用?

当以下所有条件都满足时,请使用更改成品物料:

  • 工单已提交,且已有部分数量生产完成。
  • 质检(或任何检验)发现产出是不同但可销售的物料——不同的等级、纯度或规格。
  • 实际物料是计划物料的预先批准的备选物料之一。

在以下情况下不要使用:

  • 产出是废料或废品 → 请使用正常的废品流程。
  • 只是产量少于计划 → 请使用工艺损耗。
  • 需要重新包装成不同的包装规格 → 请使用正常的重新包装库存凭证。

实际案例

日出化工运行了一张工单,计划生产100 公斤环氧树脂 – A 级。

生产完成,100 公斤已入库到成品仓库。在质检过程中,实验室发现该批次中有20 公斤不符合 A 级的粘度标准——但完全符合B 级规格,而 B 级也是公司销售的产品(价格较低)。

如果没有此功能,仓库管理员需要手动创建一张与工单无关联的重新包装凭证——报表将永远显示”生产了 100 公斤 A 级”,这是错误的。

有了此功能,主管打开工单,点击更改成品物料,选择环氧树脂 – B 级并输入20。ERPNext 将:

  • 从成品仓库中减少 20 公斤 A 级物料,
  • 在成品仓库中增加 20 公斤 B 级物料,按相同的生产成本计价,
  • 保持凭证与工单的关联,
  • 工单汇总报表现在显示:Grade A: 80, Grade B: 20。

一次性设置(管理员)

步骤 1 — 启用此功能

打开制造设置,启用允许备选成品(在BOM 与生产选项卡中),然后保存。

步骤 2 — 在计划物料上允许备选物料

打开您通常生产的物料(例如环氧树脂 – A 级),启用允许备选物料,然后保存。

步骤 3 — 定义允许的等级

为流程可能生产的每个等级创建一个物料备选记录:

字段 示例值
物料编码 环氧树脂 – A 级 (计划物料)
备选物料编码 环氧树脂 – B 级 (可能的实际产出)
双向 仅当 B 级工单也可以改级为 A 级时勾选

设置完成。除非引入新的等级,否则无需重复此操作。

日常使用(操作员 / 主管)

  • 照常完成生产。 完成工单的生产入库凭证,使生产数量入库。
  • 打开工单。 质检确认等级变更后,打开工单并点击更改成品物料按钮。

  • 填写对话框。

  • 实际成品物料 – 当只有一个备选物料时,系统会自动默认选择,或选择质检批准的等级(仅显示预先批准的备选物料)。

  • 转换数量 – 实际为其他等级的生产数量。对话框会显示可转换的数量。

  • 创建库存凭证。

    • 在弹出的窗口中,您会看到”创建库存凭证”,点击后 ERPNext 会打开一张预填好的重新包装草稿凭证。为两行分别填写批次/序列号(被消耗的批次和新建的批次),然后提交。
  • 查看报表(可选)。 打开工单汇总 — 实际成品列会显示真实产出

补充说明

  • 成本自动结转。 实际物料按工单生产的相同成本计价——无需手动输入费率。
  • 转换数量不能超过生产数量。 系统会跟踪之前的转换记录,并阻止超出剩余生产数量的转换操作。
  • 投入数量等于产出数量。 转换数量必须与新项目的数量一致。(如需真正的数量变更操作,请使用常规的重新包装条目。)
  • 支持部分转换。 您可以今天转换20公斤,明天再转换10公斤,只要总转换量不超过生产数量即可。
  • 输入错误? 取消转换的库存条目——库存和成本将退回至计划项目,转换数量将重新变为可用状态。
  • 若功能关闭,则无任何变化。 该按钮和报表列仅在制造设置中启用“允许替代成品”时才会显示。

Frappe 异步请求

在 Frappe Framework 中,你可以通过 frappe.call 来管理 ajax 调用。frappe.call 以异步方式工作,即发送请求并通过回调机制处理响应。

frappe.call 结构

frappe.call({
 method: "",
 type: "POST",
 args: {},
 success: function(r) {},
 error: function(r) {},
 always: function(r) {},
 btn: opts.btn,
 freeze: false,
 freeze_message: "",
 async: true,
 url: "" || frappe.request.url,
});

参数说明

  • method:白名单后端方法的点分路径
  • type:字符串参数,HTTP 请求类型 “GET”、”POST”、”PUT”、”DELETE”。默认设置为 “POST”。
  • args:关联数组,随请求传递的参数。
  • success:函数参数,代码片段,在请求成功执行后运行
  • error:函数参数,代码片段,在请求失败后执行
  • always:函数参数,代码片段,无论成功或失败都会执行
  • btn:对象参数,触发对象
  • freeze:布尔参数,如果设置为 true,则在收到响应前冻结实例
  • freeze_message:字符串参数,屏幕处于冻结状态时显示的消息。
  • async:布尔参数,默认设置为 true。因此每次 frappe.call 都是异步的。若要使调用同步,请将参数值设置为 false
  • url:字符串参数,发起请求的位置

如何使用 frappe.call?

调用标准 API

frappe.call({
 method: 'frappe.client.get_value',
 args: {
 'doctype': 'Item',
 'filters': {'name': item_code},
 'fieldname': [
 'item_name',
 'web_long_description',
 'description',
 'image',
 'thumbnail'
 ]
 },
 callback: function(r) {
 if (!r.exc) {
 // code snippet
 }
 }
});
  • 参数说明:

  • doctype:你要获取信息的 DocType 名称

  • filters:条件限定符

  • fieldname:你可以在数组中指定希望在响应中返回的字段

调用白名单方法

  • 在客户端,我们指定要调用的服务端 method。这是通过服务端 Python 模块的点分路径,最后一部分是方法名。
frappe.call({
method: "frappe.core.doctype.user.user.get_all_roles", //dotted path to server method
callback: function(r) {
// code snippet
}
});
  • 上述请求调用服务端方法 get_all_roles,该方法位于文件 $MY_BENCH/apps/frappe/frappe/core/doctype/user/user.py 中:
@frappe.whitelist()
def get_all_roles():
// business logic
return value

注意:任何需要通过 frappe.call() 访问的服务端方法都必须使用装饰器 @frappe.whitelist() 进行白名单授权。

Frappe 应用

Frappe 应用是使用 Frappe 平台的 Python 包。它们可以存放在 Python 路径
中的任何位置,
并且必须在 apps.txt 文件中有一个条目。

创建应用

Frappe 自带一个新应用的样板。命令 bench new-app app-name 通过启动一个交互式 shell 来帮助你开始创建新应用。

 % bench new-app sample_app
 App Name: sample_app
 App Title: Sample App
 App Description: This is a sample app.
 App Publisher: Acme Inc.
 App Icon: icon-linux
 App Color: #6DAFC9
 App Email: [email protected]
 App URL: http://example.com
 App License: MIT

上述命令将创建一个具有以下目录结构的应用。

 sample_app
 ├── license.txt
 ├── MANIFEST.in
 ├── README.md
 ├── sample_app
 │   ├── __init__.py
 │   ├── sample_app
 │   │   └── __init__.py
 │   ├── config
 │   │   ├── desktop.py
 │   │   └── __init__.py
 │   ├── hooks.py
 │   ├── modules.txt
 │   ├── patches.txt
 │   └── templates
 │   ├── generators
 │   │   └── __init__.py
 │   ├── __init__.py
 │   ├── pages
 │   │   └── __init__.py
 │   └── statics
 └── setup.py

该样板包含的文件刚好足以在 [工作台] 上显示你的应用图标。

应用中的文件

hooks.py

hooks.py 文件定义了你的应用的元数据以及它与 Frappe 或 Frappe 应用
其他部分的集成点。这些部分的示例包括任务调度或监听系统中不同文档的更新。
目前,它只包含你在创建应用时输入的详细信息。

 app_name = "sample-app"
 app_title = "Sample App"
 app_publisher = "Acme Inc."
 app_description = "This is a sample app."
 app_icon = "fa-linux"
 app_color = "black"
 app_email = "[email protected]"
 app_url = "http://example.com"
 app_version = 0.0.1

modules.txt

Frappe 中的模块帮助你组织 Frappe 中的文档,它们定义在
你的应用的 modules.txt 文件中。每个 [DocType] 都必须
归属于一个模块。默认情况下,会添加一个以你的应用名称命名的模块。
此外,每个模块在 [工作台] 上都会有一个图标。例如,[ERPNext] 应用
按以下模块进行组织。

accounts(账户)
buying(采购)
home(首页)
hr(人力资源)
manufacturing(制造)
projects(项目)
selling(销售)
setup(设置)
stock(库存)
support(支持)
utilities(工具)
contacts(联系人)

将应用添加到站点

一旦你有了一个应用,无论是你刚刚创建的还是你下载的其他应用,
你都需要执行以下操作。

通过 git 下载应用

bench get-app https://github.com/org/app_name

将应用安装到你的站点

bench --site site_name install-app app_name

指南

Frappe 是一个全栈式“开箱即用”的框架。它提供了从身份验证、定时任务到管理不同货币、报表以及构建表单等所有功能的库和 API。

在本节中,我们将尝试涵盖客户端和服务器端最常用的 API,这些 API 对应用开发非常有用。

  1. 基础知识
  2. 应用开发
  3. 部署
  4. 报表与打印
  5. 门户开发
  6. 数据
  7. 集成
  8. 数据库设置
  9. 自动化测试
  10. 工作台

脚本编写

Frappe 框架允许您直接在框架内对标准模型和视图进行脚本编写,无需额外代码。

脚本编写的不同方式:

  1. 客户端脚本
  2. 服务器端脚本
  3. 脚本报表
  4. 系统控制台

附件

Frappe 允许将文件附加到文档中。对特定文档拥有读取权限的用户也可以访问附加到该文档的文件。用户还可以从侧边栏访问文件管理器。

如何附加新文件

有几种方法可以将文件附加到文档中。

选择文件

拖放

已上传的文件

将之前上传的文件附加到另一个文档中。

如果您使用独立的文件服务器或使用 Dropbox、Docs 等在线服务,您可以通过提供文件链接来附加文件。

相机

使用设备相机拍照来附加图片。

文件管理器

所有附加的文件都会列在文件管理器中。您可以通过以下路径访问它们:

首页 > 工具 > 文件

导入 Zip 压缩包

您还可以使用“导入 Zip”功能一次批量导入多个文件。

  1. 转到 文件列表 > 菜单 > 导入 Zip。
  2. 上传一个 zip 压缩包文件。
  3. zip 文件上传后,其内容将被解压,每个文件将作为一条新的文件记录创建。

注意:从 zip 文件导入时,不会解压隐藏文件(以 . 开头的文件)。

导出为 Zip 压缩包

您还可以使用“导出为 Zip”功能一次批量导出多个文件。

  1. 转到 文件列表。
  2. 选择多个文件。
  3. 点击“操作 > 导出为 zip”。
  4. zip 文件下载后,您可以使用“导入 Zip”功能将其导入到另一个站点,或通过电子邮件发送。

裁剪图片

您可以通过点击裁剪图标来裁剪 .jpeg 和 .png 图片。

优化图片

可以优化图片以减小其文件大小。目前,优化图片会执行以下操作:

  1. 将其大小调整为最大宽度 1920 像素、最大高度 1080 像素,同时保持宽高比
  2. 使用最佳编码器设置
  3. 将质量降低至 85%

上传时切换优化

优化已上传的图片

限制

默认情况下,每个附件的文件大小限制为 10MB。对于自托管用户,可以通过在站点配置文件中设置 max_file_size 来更改此限制。

每个文档的附件数

您可以限制特定文档可以附加的文件数量。

步骤 1:导航至“自定义表单”

首页 > 自定义 > 自定义表单

步骤 2:选择文档类型

选择您要为其设置此限制的文档类型。

步骤 3:设置限制

将最大附件数的值设置为允许此文档类型附加的最大附件数量。

对更改满意后,点击更新按钮。就这样!现在,每次向此类型的文档添加新附件时,都会验证每个文档的最大附件数。

打印

Frappe 框架对为文档生成打印格式并将其转换为 PDF 提供了一流的支持。Frappe 使用 Jinja 作为打印格式的模板语言。

可以从任何文档的表单视图中访问打印视图。系统会根据表单布局和其中的必填字段,为所有 DocType 生成标准打印格式。 打印视图

要自定义打印格式,您需要创建标准打印格式的副本,并使用打印格式构建器对其进行自定义。这些打印格式可由用户编辑,并且不会作为文件与应用捆绑在一起。

打印格式构建器

自定义 HTML

您还可以向打印格式中添加自定义 HTML。只需将左侧边栏中的“自定义 HTML”按钮拖放到您的打印格式编辑器中即可。

在“自定义 HTML”字段中,您可以使用任何有效的 HTML,并使用 Bootstrap 3 类进行样式设置。您还可以使用 Jinja 模板为 HTML 添加动态内容。请参阅可在 Jinja 模板中使用的方法列表。

自定义 HTML

自定义 CSS

要更改打印格式的样式,您还可以添加自定义 CSS。

点击“自定义”> “编辑属性”以添加自定义 CSS

自定义 CSS

自定义 CSS 预览

高级打印格式

如果您想完全更改打印格式的布局,打印格式构建器的功能就会受到限制。您还可以从头开始编写自己的 HTML,并构建您想要的打印布局。

要创建新的打印格式,请在 AwesomeBar 中输入“new print format”并按回车键。

  1. 为您的格式选择一个唯一的名称。
  2. 将“标准”设置为“否”。
  3. 勾选“自定义格式”。
  4. 将打印格式类型选择为“Jinja”。
  5. 编写您的自定义 HTML。

如果您将“标准”设置为“是”并且启用了开发者模式,那么系统将为您的打印格式生成一个 JSON 文件,并且您必须将其与您的应用一起检入到版本控制中。

打印格式中的自定义 HTML

Frappe 允许您为查询和脚本报表创建自定义打印格式。这些打印格式无法通过用户界面创建。

要为报表创建打印格式,请在报表文件夹中创建一个名为 {report-name}.html 的 HTML 文件。

例如,请查看总账。

JS 模板

这些打印格式是在客户端生成的,因此我们不能使用 Jinja。我们使用 John Resig 模板的改编版本。它看起来与 Jinja 类似,因此您无需学习任何新内容。

以下是 JS 模板的片段。

{% for(var i=0, l=data.length; i<l i>
    {% if(data[i].posting_date) { %}
        {%= frappe.datetime.str_to_user(data[i].posting_date) %}

            {% if(!(filters.party || filters.account)) { %}
                {%= data[i].party || data[i].account %}
                <br>
            {% } %}

            {{ __("Against") }}: {%= data[i].against %}
            <br>{%= __("Remarks") %}: {%= data[i].remarks %}

    {% } else { %}
        <b>{%= frappe.format(data[i].account, {fieldtype: "Link"}) || " " %}</b>

 {%= data[i].account && format_currency(data[i].debit, filters.presentation_currency) %}

 {% } %}

{% } %}
</l>

简介

什么是 Frappe 框架?

Frappe,发音为 fra-pay,是一个全栈式、功能完备的 Web 框架,使用 Python 和 Javascript 编写,并以 MariaDB 作为数据库。它是驱动 ERPNext 的底层框架,具有很好的通用性,可用于构建数据库驱动的应用程序。

为什么选择 Frappe?

Frappe 与其他框架的关键区别在于,元数据也被视为数据。这使得您可以非常轻松地构建前端。我们信奉单体架构,因此 Frappe 几乎包含了构建现代 Web 应用所需的一切。它拥有一个功能齐全的管理界面,称为 Desk,开箱即用地处理表单、导航、列表、菜单、权限、文件附件等众多功能。更多信息请点击此处阅读。

主要特性

  1. 全栈框架:Frappe 同时涵盖前端和后端开发,使开发人员能够使用单一框架构建完整的应用程序。
  2. 内置管理界面:提供预构建、可自定义的管理仪表板,用于管理应用程序数据,减少开发时间和工作量。
  3. 基于角色的权限:全面的用户和角色管理系统,用于控制应用程序内的访问和权限。
  4. REST API:为所有模型自动生成 RESTful API,便于与其他系统和服务的集成。
  5. 可自定义的表单和视图:通过服务器端脚本和客户端 JavaScript 实现灵活的表单和视图定制。
  6. 报表生成器:强大的报表工具,允许用户无需编写任何代码即可创建自定义报表。

安装

在使用 Frappe 之前,您需要先安装它。我们有一份完整的安装指南,涵盖了所有可能的情况,本指南还将帮助您了解后端技术栈。

学习与社区

  1. Frappe School – 通过维护者或社区提供的各种课程学习 Frappe 框架和 ERPNext。
  2. GitHub – 探索源代码、贡献代码,并与 Frappe 社区协作。
  3. 讨论论坛 – 在我们的论坛上与不断壮大的社区互动,提问、帮助他人并成为社区的一员。
  4. buildwithhussain.dev – 观看 Frappe 框架在实际项目中如何被用于构建世界级的 Web 应用。