ZUGFeRD 电子发票:使用 PDF4me 在 Power Automate 中从 SharePoint 列表将 JSON 转换为 EN 16931 XML 和 PDF/A-3 文件

PDF4me Create ZUGFeRD Invoice是一个 Power Automate 操作,可将发票数据转换为混合PDF/A-3电子发票。它指向一个 SharePoint 列表,获取Compose操作从每行数据生成的 JSON,写入EN 16931 XML,将可读的发票绘制到基础 PDF 上,归档结果并通过电子邮件发送给买方。
搜索ZUGFeRD,你会找到以下三种结果之一:格式说明、验证器(用于判断你已有的文件是否正确)或面向开发人员的 PHP、Java 或 C# 库(用于构建发票软件)。这三种结果都假设发票已经存在于某个地方。然而,它们都没有回答财务团队真正面临的问题:发票数据可能存储在列表、电子表格或其他任何记录销售信息的系统中,最终必须以符合规范的电子发票形式输出。而这个流程正是填补了这一空白,只需七个步骤,无需编写任何代码。
一条包含卖家、买家、一条商品信息和日期的记录被添加到 SharePoint 列表中。四秒钟后,文档库中就会出现一份PDF/A-3格式的发票:这是一个可阅读的页面,其中嵌入了EN 16931 XML 数据,供买家的软件处理。您无需编写 XML 代码。您只需将发票描述为一个简短的 JSON 对象,PDF4me 就会生成相应的架构。记录会获得状态和链接,买家会通过电子邮件收到文件。
基于原因的问答
为什么要将发票数据保存在 SharePoint 列表中?因为大多数小型财务团队的数据格式已经是这样的:每张发票占一行,由专人填写。列表中的列与标准要求的字段一一对应,这意味着任何打开列表的人都能看到这种对应关系,而且每张新发票都会在列表中显示为新行,而不是在受监控的文件夹中创建一个新文件。
为什么要把发票描述成 JSON 而不是 XML 格式?因为Cross Industry Invoice语法冗长且严格:嵌套的命名空间、难以记忆的元素名称、以及必须精确放置在正确位置的代码。JSON 对象用更少的代码行数就能表达相同的内容,其键值也直接代表了业务术语。PDF4me 会将其转换为 XML 模式,因此,最容易出错的部分正是您无需维护的部分。
为什么要将发票渲染到基础 PDF 上?因为ZUGFeRD文件由两部分组成,两者必须保持一致。XML 供买方软件使用,打印页面供打开它的人使用。 Render Invoice on PDF会使用生成 XML 的相同数据将发票绘制到基础页面上,因此两者永远不会像布局分开维护时那样出现偏差。
为什么选择PDF/A-3而不是普通的 PDF 文件?因为PDF/A-3是一种允许携带附件的归档容器,而嵌入的 XML 就是该附件。它也确保了发票在多年后仍然可读:字体和颜色配置文件都包含在文件内部,这对于大多数公司需要保存十年的文件来说至关重要。
您将获得
输入:一行包含发票编号、日期、货币、卖方信息、买方信息以及一个项目明细。输出: ZUGFeRD Invoices库中生成ZUGFeRD PDF/A-3发票,更新该行信息(包含发票状态和链接),并向买方发送一封包含该发票附件的电子邮件。

每张发票占一行。此窗格中的每一列都将成为流程构建的 JSON 中的一个键。

每个发票号对应一个文件,由流程账户写入。

买家看到的同一文件的可读部分。
你需要什么
- Power Automate。打开 Power Automate。基于标准连接器的自动化云流程。SharePoint、 Office 365 Outlook和 PDF4me 无需高级套餐。
- PDF4me API 密钥。获取您的 API 密钥。此流程使用一个 PDF4me 连接, PDF4me PDF。
- 用于记录请求的 SharePoint 列表。捕获的列表名为ZUGFeRD Requests,包含InvoiceNumber、 InvoiceDate、 DueDate、Currency、 Seller模块(名称、街道、邮政编码、城市、国家/地区、增值税ID)、 Buyer模块、 ItemDescription、Quantity、 UnitPrice、 VATRate、 Email列、 Status选择列以及流程写入的OutputLink列。
- 基础发票 PDF 文件。捕获的流程会将
BaseInvoice.pdf保存在名为ZUGFeRD Templates的库中。发票就绘制在这个页面上,因此您的信头应该放在这里。 - 用于存放已完成发票的库。捕获的流程会将数据写入ZUGFeRD Invoices。
- 您自己的卖家详细信息,包括增值税ID。这些信息会添加到列表列中,以便同一流程可以为多个法人实体开具发票。
流程概览
- When an item is created (SharePoint)监视名为
ZUGFeRD Requests列表。 - Compose根据该行构建发票 JSON。
- Get file content using path
/ZUGFeRD Templates/BaseInvoice.pdf。 - Create ZUGFeRD Invoice (PDF4me PDF)将 JSON 转换为EN 16931 XML 并返回混合 PDF。
- Create file (SharePoint)将其保存为
ZUGFeRD_<invoice number>.pdf。 - Update item (SharePoint)将Status设置为
Generated,并填充OutputLink。 - Send an email (V2) (Office 365 Outlook)将发票发送给买方。
完整流程概述

从头到尾大概需要四秒多一点,而电子发票本身生成大约需要一秒钟。最慢的步骤是 SharePoint 写入文件。
第一步:当收到请求时,如何触发电子发票?
目前流程:尚未启动,这是触发点。
添加行是请求发票的方式,所以这就是信号。
- 创建Automated cloud flow并选择SharePoint > When an item is created。
- 配置:
- Site Address:
PDF4me Support - https://ynoox1.sharepoint.com/sites/PDF4meSupport - List Name:
ZUGFeRD Requests
- Site Address:
When an item is created:配置

新行中的每一列都成为一个标记,接下来的六个操作都可以使用这个标记。
步骤 2:如何根据列表列构建发票 JSON?
目前为止的流程: SharePoint 触发器。
一次Compose操作即可描述整张发票。在这里,列名符合标准规范,并且足够简洁,可以在一屏内阅读完毕。
- 添加Data Operation > Compose。
- 将以下对象粘贴到输入中,并将每个值替换为匹配的标记。
{
"InvoiceId": "@{triggerBody()?['InvoiceNumber']}",
"TypeCode": "380",
"InvoiceType": "RECHNUNG",
"IssueDate": "@{triggerBody()?['InvoiceDate']}T00:00:00",
"DeliveryDate": "@{triggerBody()?['InvoiceDate']}T00:00:00",
"IsTest": false,
"Seller": {
"Name": "@{triggerBody()?['SellerName']}",
"VatId": "@{triggerBody()?['SellerVATID']}",
"Address": {
"Street": "@{triggerBody()?['SellerStreet']}",
"PostalCode": "@{triggerBody()?['SellerPostalCode']}",
"City": "@{triggerBody()?['SellerCity']}",
"Country": "@{triggerBody()?['SellerCountry']}"
}
},
"Buyer": {
"Name": "@{triggerBody()?['BuyerName']}",
"Address": {
"Street": "@{triggerBody()?['BuyerStreet']}",
"PostalCode": "@{triggerBody()?['BuyerPostalCode']}",
"City": "@{triggerBody()?['BuyerCity']}",
"Country": "@{triggerBody()?['BuyerCountry']}"
}
},
"LineItems": [
{
"ProductName": "@{triggerBody()?['ItemDescription']}",
"Quantity": @{triggerBody()?['Quantity']},
"UnitCode": "C62",
"UnitPrice": @{triggerBody()?['UnitPrice']},
"LineTotal": @{float(...)}
}
],
"Totals": {
"Currency": "@{triggerBody()?['Currency']?['Value']}",
"LineTotal": @{float(...)},
"TaxBasisTotal": @{float(...)},
"TaxPercent": @{triggerBody()?['VATRate']},
"TaxTotal": @{float(...)},
"GrandTotal": @{float(...)},
"ChargeTotal": 0,
"AllowanceTotal": 0
},
"Payment": {
"Currency": "@{triggerBody()?['Currency']?['Value']}",
"PaymentReference": "@{triggerBody()?['InvoiceNumber']}",
"DueDate": "@{triggerBody()?['DueDate']}T00:00:00"
}
}
Compose:配置

文本值是用引号括起来的标记。金额和数量是纯数字,所以它们使用float进行处理。
发票各部分的来源
| JSON 密钥 | 它承载着什么 | 来源 |
|---|---|---|
InvoiceId, TypeCode, InvoiceType | 发票号码、商业发票的单据类型代码380以及打印在页面上的标签 | InvoiceNumber,然后是固定值 |
IssueDate, DeliveryDate | 发票开具时间和提供服务的时间 | InvoiceDate,后缀为T00:00:00 |
Seller | 姓名、增值税ID和完整地址 | SellerName, SellerVATID, SellerStreet, SellerPostalCode, SellerCity, SellerCountry |
Buyer | 客户的姓名和地址 | BuyerName, BuyerStreet, BuyerPostalCode, BuyerCity, BuyerCountry |
LineItems | 描述、数量(单位代码C62、单价和行总计 | ItemDescription、数量、 UnitPrice |
Totals | 货币、净额、税基、增值税税率和金额、总计 | 货币、 VATRate和计算金额 |
Payment | 货币单位、买方付款时提供的参考编号以及到期日 | 货币、 InvoiceNumber、 DueDate |
提示:只有金额键需要进行算术运算,而且它们必须以纯数字形式输出,而不是带引号的LineTotal, float表达式就是用来处理字符串的。LineTotal 是数量乘以单价, TaxBasisTotal是各行总计之和, TaxTotal是税基乘以税率再除以 100, GrandTotal是这两项之和。对于捕获的行,这些值分别为 1005、1005、190.95 和 1195.95。带引号的"1005"会被拒绝,而纯1005 会被接受。
步骤 3:基础 PDF 文件来自哪里?
目前流程:触发器 + Compose。
ZUGFeRD文件有一个可读页面,这是它的起始页。
- 添加SharePoint > Get file content using path。
- 配置:
- Site Address:
PDF4me Support - https://ynoox1.sharepoint.com/sites/PDF4meSupport - File Path:
/ZUGFeRD Templates/BaseInvoice.pdf - Infer content type (高级):
Yes
- Site Address:
Get file content using path:配置

请将您的信头保存在此文件中。每次运行系统都会读取新的信头,因此更改信头会影响下一张发票。
步骤 4:如何将 JSON 转换为ZUGFeRD PDF/A-3?
目前的流程:触发、 Compose和Get file content using path。
此操作会生成电子发票。它读取 JSON 数据,写入EN 16931 XML 格式的数据,并将包含这两部分数据的文件返回给系统。
- 通过PDF4me PDF连接添加Create ZUGFeRD Invoice。
- 配置:
- ZUGFeRD version and Input Format:
2.0-JSON - Output Mode:
XmlWithPdf - Invoice JSON Data:表达式
base64(outputs('Compose')) - Conformance Level:
EN16931 - Render Invoice on PDF:
Yes - File Content: Get file content using path后,对内容进行
base64()编码 - File Name:
BaseInvoice.pdf
- ZUGFeRD version and Input Format:
Create ZUGFeRD Invoice:配置

输入格式决定了显示哪个数据字段。选择2.0-JSON,则操作会要求Invoice JSON Data,而不是Invoice XML Data。
每个设置决定什么
| 场地 | 这里的价值 | 它控制着什么 |
|---|---|---|
| ZUGFeRD version and Input Format | 2.0-JSON | 输出遵循哪个ZUGFeRD生成版本,以及数据是否以 JSON 格式到达。正是这个选择使得Invoice JSON Data字段得以显示 |
| Output Mode | XmlWithPdf | 返回一个混合文件,即嵌入了 XML 的 PDF 文件,而不是单独的 XML 文件 |
| Invoice JSON Data | base64(outputs('Compose')) | 发票对象在传输过程中进行了base64编码 |
| Conformance Level | EN16931 | 发票声称符合的配置文件,以及因此 JSON 必须提供的键 |
| Render Invoice on PDF | Yes | 将清晰可读的发票绘制到基础 PDF 上,而不是保持页面原样 |
| File Content, File Name | 基础PDF | 发票所在的页面,以及操作报告的名称 |
提示:此操作会根据下拉菜单中的格式选项显示Invoice XML Data、 Invoice JSON Data或Invoice CSV Data。请仅填写与您的选择相符的选项。在同一次运行中填写两个数据字段是导致此操作验证失败的最常见原因。
第五步:发票归档在哪里?
目前流程:所有操作均通过Create ZUGFeRD Invoice。
发票编号是文件名,这样可以方便地搜索资料库。
- 添加SharePoint > Create file。
- 配置:
- Site Address:
PDF4me Support - https://ynoox1.sharepoint.com/sites/PDF4meSupport - Folder Path:
/ZUGFeRD Invoices - File Name:
ZUGFeRD_后跟InvoiceNumber标记和.pdf - File Content:来自Create ZUGFeRD Invoice Body令牌
- Site Address:
Create file:配置

对于RE-2026-0007这将写入ZUGFeRD_RE-2026-0007.pdf。
步骤 6:如何记录请求结果?
目前流程:所有操作均通过Create file。
要求提供发票的行也应该说明发票的处理情况。
- 添加SharePoint > Update item。
- 配置:
- Site Address:
PDF4me Support - https://ynoox1.sharepoint.com/sites/PDF4meSupport - List Name:
ZUGFeRD Requests - Id:触发器中的ID令牌
- Title:触发器中的Title令牌
- Status Value (高级):
Generated - OutputLink (高级):库 URL,后跟
ZUGFeRD_、 InvoiceNumber标记和.pdf
- Site Address:
Update item:配置

该链接由库 URL 和相同的名称模式Create file组成,库名称中的空格已编码为 %20。
步骤 7:如何将发票发送给买家?
目前流程:所有操作均通过Update item完成。
尚未开具留在图书馆的电子发票,因此最后一步操作是将其交付。
- 添加Office 365 Outlook > Send an email (V2)。
- 配置:
- 收件人:触发器中的Email令牌
- 主题:
Your ZUGFeRD e-invoice后跟InvoiceNumber编号 - Body:一行文字,注明买方和发票名称,并说明文件为嵌入了EN 16931 XML 的PDF/A-3格式
- 打开Advanced parameters并添加附件:
- Attachments名称 - 1:
ZUGFeRD_加上InvoiceNumber标记,再加上.pdf - Attachments内容 - 1:来自Create ZUGFeRD Invoice File Content令牌
- Importance:
Normal
- Attachments名称 - 1:
Send an email (V2):配置

附件的字节来自生成该附件的操作,因此 SharePoint 永远不会读取该附件的字节。
运行流程并验证
- Save流量。
- 向ZUGFeRD Requests中添加一行,其中包含买家、一个项目、日期和地址,以便您可以进行检查。
- 打开运行历史记录。所有七项操作都应该显示为绿色,整个运行过程应该只需几秒钟。
- 打开ZUGFeRD Invoices库,检查发票编号下是否存在该文件。
- 返回到该行: Status应显示Generated, OutputLink应打开发票。
- 打开电子邮件附件并检查两部分:页面应显示正确的数量,并且文件应包含 XML 内容。
捕获的运行过程总共耗时约四秒,其中一秒内生成了电子发票。结果文件ZUGFeRD_RE-2026-0007.pdf大小约为 331 KB,显示为一份德国发票:卖方为Berlin Muster GmbH增值税ID为DE123456789;客户为Muenchen Test Kunde AG公司;文档类型为 380;包含一项Consulting服务,增值税税率为 19%,净额为 1,005.00 欧元,增值税额为 190.95 欧元,总计为 1,195.95 欧元。
你实际构建了什么?一个从你自己的记录开始的电子发票流程。数据保留在财务部门,标准由你无需编写的 XML 代码满足,买方会收到一个他们的软件可以自动读取、员工也可以在屏幕上查看的文件,请求记录行会记录发票已发出。
无需重建即可添加的常见变体
与其他生成ZUGFeRD发票的方式相比,这种方式有何异同?
每一行描述了一种替代方案。最后一行就是这个流程。
| 比较 | 谁在运营它 | 数据来源 | 你所维护的 |
|---|---|---|---|
| 与ZUGFeRD导出相比,发票软件的流程 | 任何人,在该产品内部 | 产品自身的记录 | 订阅,以及产品支持的任何内容 |
| 电子发票平台与此流程 | 通过门户网站进行金融交易 | 上传或集成 | 按文件签订合同及其关联 |
| 开发者库与此流程 | 应用程序内部的开发人员 | 通过代码实现您的数据库 | 代码、架构更新和版本发布 |
| 这种流程 | 任何可以添加列表行的人 | 团队维护的 SharePoint 列表 | 一个 JSON 对象和一个基础 PDF |
常见问题
什么是ZUGFeRD发票?
ZUGFeRD发票是一个双向运作的文件。它既是一个普通的 PDF 文件,可以打开阅读,又包含一个 XML 附件,其中包含以结构化数据形式存储的发票信息。买方的会计系统读取 XML 文件并自动记账,无需人工输入,而应付账款人员仍然可以看到一个单独的页面。
该格式源自德国电子发票论坛FeRD,其法国对应版本是Factur-X,只是名称不同,但理念相同。
什么是ZUGFeRD格式?
从技术角度讲,它是一个PDF/A-3容器,其中嵌入了一个采用Cross Industry Invoice语法的XML文件,以及一个用于描述数据完整性的配置文件。此处使用的配置文件是EN16931,它对应于欧洲电子发票语义标准: EN 16931定义的发票核心字段集。
对于自动化流程而言,实际结果是输出结果取决于 XML 文件,而不是页面本身。只要提供配置文件所需的数据,文件就能通过审核;即使页面美观,结果也一样。
如何创建ZUGFeRD发票?
你需要三样东西:结构化的发票数据、供人阅读的页面,以及将 XML 写入 PDF 并作为PDF/A-3附件的工具。
在此流程中,数据是 SharePoint 中的一行数据,已转换为 JSON 格式;页面是BaseInvoice.pdf; Create ZUGFeRD Invoice操作使用Output Mode XmlWithPdf执行第三部分。如果您的数据已以Cross Industry Invoice XML 或 CSV 行的形式存在,请切换输入格式并使用该格式的数据。流程的其余部分保持不变。
ZUGFeRD和XRechnung有什么区别?
两者都符合相同的欧洲标准,区别在于封装方式。ZUGFeRD 是一种混合ZUGFeRD:它包含 XML 数据,并以可读 PDF 格式呈现,适合发送给客户,方便他们手动打开。XRechnung XRechnung完全是 XML 格式,也是德国公共部门采购人员要求的格式。
如果您要发送给企业,混合文件通常是更安全的选择,因为任何打开它的人都可以读取。如果您要向公共机构开具发票,请在发送前确认该机构要求的文件格式。
故障排除
在运行历史记录中打开Compose输出,并首先将其读取为 JSON 格式。空列会导致键为空,而保留引号的货币值会以文本形式返回,而预期是数字。这两种情况都会生成一个看起来没问题的对象,但转换仍然失败。
Conformance Level决定了配置文件所需的字段。如果 JSON 文件缺少EN16931配置文件所需的键,即使文件可以正常打开,也会验证失败。要么补充缺失的键,要么降级到较低的配置文件级别。
Render Invoice on PDF设置为否,因此 XML 已嵌入,但未绘制任何内容。该文件仍然是有效的电子发票,但其中显示的内容与基础 PDF 文件中的内容相同。
检查电子邮件步骤中的附件内容和Create file中的File Content。两者都必须来自Create ZUGFeRD Invoice。如果附加基础 PDF 文件,则发送的页面虽然看起来正常,但实际上没有任何内容可供对方软件读取。
后续步骤
无论买家最终需要哪种格式,所有电子发票指令实际上都要求遵循相同的七步模式(一行数据到达,发票被描述为数据,生成文件,归档,记录和发送)。