Power Automate 中的 Excel 发票模板:从 SharePoint 列表填充发票,并使用 PDF4me 将每张发票存档为 PDF/A 文件

PDF4me Excel - Populate是一个 Power Automate 操作,用于将 JSON 数据填充到 Excel 发票模板中。首先,通过新建一个 SharePoint 列表项提供数据;然后,Populate 操作将数据写入模板的智能标记;最后,三个 PDF4me 操作会将工作簿转换为压缩的 PDF/A 发票,供 SharePoint 自动存储。
搜索Excel发票模板,第一页就是一个图库。微软、Vertex42、QuickBooks和Square都提供了一个设计精美的空白工作簿,但下载之后就结束了。它们都没有说明如何填写模板,实际上就是有人把客户信息复制到单元格里,导出为PDF,命名文件,然后把它放到文件夹里,一张一张地填写发票。这种流程保留了这些页面做得好的地方,任何人都能在Excel里设计模板,但却省略了下载之后的所有步骤。
一行数据被添加到 SharePoint 列表中。Power Automate 将其转换为 JSON 格式,填充到 Excel 发票模板中,将工作簿转换为 PDF,压缩 PDF,再转换为 PDF/A-2b 格式,最后将结果写入 SharePoint 文件夹。总共八个操作,每张发票大约耗时 36 秒,而且无需打开 Excel。
基于原因的问答
为什么要使用 Excel 工作簿作为发票模板?因为发票的设计已经在 Excel 中完成。列宽、合并单元格、字体和边框等所有设置都已在 Excel 中完成,因此布局所有者无需修改流程或学习 HTML 即可进行更改。唯一的要求是,每个包含数值的单元格都使用智能标记而不是示例文本,步骤 4 将详细展示智能标记的样式。
为什么流程需要Compose操作?因为 SharePoint 列表行是扁平的,而模板不是。列表将两个行项目存储为十个单独的列,分别为Item1Description到Item2TaxRate。模板只有一个项目行,该行会针对Items数组中的每个条目重复出现。Compose操作会将十列合并成一个包含两个元素的数组,正是这个数组使得行可以重复出现。
为什么要将发票转换为 PDF/A 格式而不是保留 .xlsx 文件?工作簿是动态文档。任何打开它的人都可以更改数量,公式在不同的计算机上可能会重新计算出不同的总数。PDF 格式可以修正实际的发票内容。PDF /A格式更进一步,嵌入了渲染页面所需的一切,包括字体,这正是您需要的,因为发票通常在发送后几年内都需要保持可读性。
为什么要把模板保存在 SharePoint 库中而不是流程内部?因为流程每次运行时都会读取最新的模板。在 SharePoint 中更改徽标、颜色或列顺序,下一张发票就会使用新的布局,无需任何人编辑流程。SharePoint 版本历史记录还会保留模板的每个早期版本,因此可以从中回滚错误的布局更改。
您将获得
输入:包含发票抬头、客户详细信息和两个明细项目的 SharePoint 列表行。输出:压缩后的 PDF/A-2b 发票文件ExcelArchived.pdf,位于同一站点的/Shared Documents/ArchivedExcel文件夹中。

数据源:每张发票对应一行,共二十二列。最后一行Morris - INV 生成了示例输出。

ArchivedExcel文件夹中的ExcelArchived.pdf,是由流程帐户在添加行后几秒钟内写入的。
你需要什么
- Power Automate。打开 Power Automate。基于标准连接器的云流。SharePoint 和 PDF4me 连接器无需高级计划。
- PDF4me API 密钥。获取您的 API 密钥。此流程使用三个 PDF4me 连接:PDF4me Excel、PDF4me Convert和PDF4me PDF。一个密钥即可授权所有三个连接。
- SharePoint 站点包含一个列表,其列与Compose映射相匹配,此外还有一个用于模板和输出的文档库。捕获的流程使用列表Excel Template、用于存放工作簿的文件夹/Shared Documents/Excel Template以及用于存放发票的文件夹/Shared Documents/ArchivedExcel。
- Excel 发票模板. pdf4me-excel-invoice-template.xlsx . 单页,已设置智能标记。
- Compose JSON 文件。compose compose-rootdata.json。步骤 2 中的 RootData 映射,可以直接粘贴。
- 最终发票.excel excel-archived-invoice.pdf /A-2b,与捕获的运行结果完全一致。
首先获取示例。将模板上传到 SharePoint 库,将 JSON 代码粘贴到Compose操作中,然后将首次运行结果与最终生成的发票进行比较。打开发票的文档属性,您应该会看到 PDF/A-2b 标识。了解正确的输出格式是判断运行是否成功的最快捷方法。
流程概览
- When an item is created (SharePoint 触发器)监视名为
Excel Template列表。 - Compose根据新行构建
RootDataJSON。 - Get file content using path从
/Shared Documents/Excel Template读取模板。 - Excel - Populate (PDF4me Excel)将 JSON 合并到工作表
1中。 - Convert to PDF (PDF4me Convert)会将工作簿渲染为
Invoice.pdf。 - PDF - Compress使用Optimize Profile
Web压缩 ( PDF4me PDF )。 - PDF - Create PdfA使用Compliance
PdfA2b创建 PdfA(PDF4me PDF)。 - 在
/Shared Documents/ArchivedExcel中Create file (SharePoint)。
完整流程概述

生成示例发票的运行过程。Convert、Compress和Create PdfA分别耗时 10 到 11 秒,除 SharePoint 写入需要 2 秒外,其他所有操作均在 1 秒内完成。预计每张发票耗时约 36 秒。
步骤 1:当 SharePoint 列表项创建时,如何触发流程?
目前流程:尚未启动,这是触发点。
列表中的每一行都是一张发票,因此触发器就是列表本身。
- 创建Automated cloud flow并选择SharePoint > When an item is created。
- 配置:
- Site Address:
PDF4me Sharepoints - https://ynoox1.sharepoint.com/sites/PDF4meSharepoints - List Name:
Excel Template
- Site Address:
SharePoint 触发器配置

一个列表,一个触发器。列表内置的Title列包含发票编号,因此下一步会将编号映射到Title。
提示:表达式使用的是列的内部名称,而不是列表中显示的名称。列表中显示的列名为Date and time,但触发器返回的名称是Dateandtime,而 Compose函数必须使用这个名称。名称错误不会导致运行失败。triggerBody() ? triggerBody()?['Dateandtime']中的问号会静默返回 null,因此生成的发票日期为空。
步骤 2:如何将 SharePoint 中的扁平行转换为 JSON 格式以用于 Excel 模板?
目前流程: SharePoint 触发器。
该模板需要一个嵌套结构:发票抬头、公司信息块、客户信息块和商品列表。商品列表行是扁平的。Compose 是Compose这两者之间的转换层。
- 添加Data Operation > Compose。
- 将此内容粘贴到Inputs中。每个值都是一个
triggerBody()?['<column>']表达式,指向列表中的一列。
{
"RootData": {
"Invoice": [
{
"Number": "@{triggerBody()?['Title']}",
"Date": "@{triggerBody()?['Dateandtime']}",
"DueDate": "@{triggerBody()?['DueDate']}",
"PONumber": "@{triggerBody()?['PONumber']}",
"PaymentTerms": "@{triggerBody()?['PaymentTerms']}"
}
],
"Company": [
{
"Email": "@{triggerBody()?['CompanyEmail']}",
"Address": "@{triggerBody()?['CompanyAddress']}"
}
],
"Customer": [
{
"Name": "@{triggerBody()?['CustomerName']}",
"Email": "@{triggerBody()?['CustomerEmail']}",
"Company": "@{triggerBody()?['CustomerCompany']}",
"Address": "@{triggerBody()?['CustomerAddress']}",
"CityStateZIP": "@{triggerBody()?['CustomerCityStateZIP']}"
}
],
"Items": [
{
"Description": "@{triggerBody()?['Item1Description']}",
"Qty": "@{triggerBody()?['Item1Qty']}",
"UnitPrice": "@{triggerBody()?['Item1UnitPrice']}",
"Discount": "@{triggerBody()?['Item1Discount']}",
"TaxRate": "@{triggerBody()?['Item1TaxRate']}"
},
{
"Description": "@{triggerBody()?['Item2Description']}",
"Qty": "@{triggerBody()?['Item2Qty']}",
"UnitPrice": "@{triggerBody()?['Item2UnitPrice']}",
"Discount": "@{triggerBody()?['Item2Discount']}",
"TaxRate": "@{triggerBody()?['Item2TaxRate']}"
}
]
}
}
Compose:代码视图

Invoice、Company和Customer都是包含一个元素的数组。Items 包含两个Items,分别对应列表中的每组项目列。
每个模板单元格如何获得其值
| 模板单元格 | 细胞内的智能标记 | Compose路径 | SharePoint 列 |
|---|---|---|---|
| Invoice No. (B12) | &=RootData.Invoice.Number(noadd) | Invoice[0].Number | Title |
| 日期(B13) | &=RootData.Invoice.Date(noadd) | Invoice[0].Date | Dateandtime |
| Due Date (B14) | &=RootData.Invoice.DueDate(noadd) | Invoice[0].DueDate | DueDate |
| PO Number (B15) | &=RootData.Invoice.PONumber(noadd) | Invoice[0].PONumber | PONumber |
| Payment Terms (B16) | &=RootData.Invoice.PaymentTerms(noadd) | Invoice[0].PaymentTerms | PaymentTerms |
| 电子邮件和地址(B4、B5) | &=RootData.Company.Email(noadd)和.Address | Company[0] | CompanyEmail, CompanyAddress |
| Customer区(B6 至 B10) | &=RootData.Customer.Name(noadd)和其他四个 | Customer[0] | CustomerName到CustomerCityStateZIP |
| 项目行(A19 至 E19) | &=RootData.Items.Description, .Qty, .UnitPrice, .Discount, .TaxRate | Items[0]和Items[1] | Item1和Item2列 |
From 栏(B3)为纯文本格式,PDF4me生成,因此每张发票上的内容都相同。请将其替换为模板中的公司名称。
步骤 3:流程从哪里读取 Excel 模板?
目前流程: SharePoint 触发器 + Compose。
模板是文档库中的一个普通文件。流程每次运行时都会读取它,因此,流程运行时 SharePoint 中当前的布局就是最终使用的布局。
- 添加SharePoint > Get file content using path。
- 配置:
- Site Address:
PDF4me Sharepoints - https://ynoox1.sharepoint.com/sites/PDF4meSharepoints - File Path:
/Shared Documents/Excel Template/PDF4me_Excel_SharePoint_Template_.xlsx - Infer content type (高级):
Yes
- Site Address:
Get file content using path:配置

列表和模板文件夹都叫做Excel Template。它们是不同的:一个是列表,另一个是Shared Documents中的一个文件夹。
步骤 4:Excel - Populate如何填充 Excel 发票模板?
目前流程: SharePoint 触发器 + Compose + Get file content using path。
这一步骤完成了模板库留给您的工作。Excel Excel - Populate会读取工作簿和 JSON 文件,查找每个智能标记,并将匹配的值写入相应的单元格。
- 添加Excel - Populate从PDF4me Excel连接填充。
- 配置:
- File Content:Get file content using path时返回的Body令牌
- JSON Data:Compose的输出(令牌显示为Body)
- File Name:
Populate.xlsx - Worksheet Indexes:
1
- 打开Advanced parameters,并设置以下四个参数中的三个:
- Strict JSON Strings:
Yes - Culture & Language Settings:
en-US - Calculate Formulas:
Yes
- Strict JSON Strings:
Excel - Populate:配置

这项工作主要由两个输入完成:来自 SharePoint 的模板字节和来自Compose JSON。其他一切都只是格式和范围设置。
该模板使用了两种标记笔,而它们之间的区别正是整个诀窍所在:
- 标题单元格(例如Invoice No.保留
&=RootData.Invoice.Number(noadd)。(noadd)修饰符会将值写入原地,而不会插入新行。 - 条目行包含
&=RootData.Items.Description、&=RootData.Items.Qty等,没有修饰符。该行会为Items数组中的每个元素写入一次,因此两个条目会生成两行,第三个条目会生成第三行。
完整的语法说明,包括修饰符、嵌套路径和公式处理,请参阅Excel Populate语法概述。要单独使用填充操作,并使用 Dropbox 模板和内联 JSON 有效负载,请参阅在 Power Automate 中从 JSON 填充 Excel 模板。
提示:在Compose中,每个值都以字符串插值的形式放在引号内,因此数量和价格会以文本形式传入模板。如果将Strict JSON Strings设置为Yes,它们将保持文本格式,这样可以正确打印,并且满足此模板的所有需求。如果您添加了行总计或求和,请将其设置为No,以便将看似数字的字符串转换为实际数字。否则,求和函数会跳过它们,因为 Excel 不会对以文本形式存储的数字进行求和。
步骤 5:如何将填充好的工作簿转换为 PDF?
目前的流程: SharePoint 触发器 + Compose + Get file content using path + Excel - Populate。
填充后的工作簿仅存在于本次运行中。它永远不会保存为 .xlsx 文件;它会直接进入转换器。
- 通过PDF4me Convert连接添加Convert to PDF。
- 配置:
- File Content:来自 Excel 的Output File Content标记Excel - Populate
- File Name:
Invoice.pdf
Convert to PDF:配置

Output File Content是已填充数据的工作簿。它不会以 .xlsx 文件的形式上传到 SharePoint。
提示:捕获到的流程将Invoice.pdf作为File Name传递,转换仍然正确。但是,Convert to PDF参考文档要求提供源文件的扩展名,因此如果您要自行构建 PDF 文件,Invoice.xlsx是更稳妥的选择。
请在模板中设置页面布局,而不是在流程中设置。 Convert to PDF请遵循工作簿的页面设置。示例模板的宽度略大于一张Letter纸张,因此生成的发票第一页包含 A 至 D 列,第二页仅包含Tax %列。在 Excel 中打开模板,转到Page Layout,将Scale to Fit > Width设置为1 page,然后将其保存回 SharePoint。之后,每张发票都将以单页显示。
步骤 6:如何压缩发票并将其转换为 PDF/A 格式?
目前流程:所有操作均通过Convert to PDF。
PDF4me PDF连接会执行两个操作:先压缩,后认证。如果顺序颠倒,压缩操作就会覆盖已经符合规范的文件。
- 添加PDF - Compress。
- File Content:来自Convert to PDF Body标记
- File Name:从上一个操作传递过来的
headers/FileName标记 - Optimize Profile:
Web
- 添加PDF - Create PdfA。
- File Content:PDF 中的Body标记PDF - Compress
- File Name:
headers/FileName标记 - Compliance:
PdfA2b - Allow Upgrade:
Yes - Allow Downgrade:
Yes
Compress 和 Create PdfA:参数
| 行动 | 范围 | 此处使用的值 | 它控制着什么 |
|---|---|---|---|
| PDF - Compress | Optimize Profile | Web | 交易规模与真实性成正比。一份只有文字和表格、没有图片的发票,其质量几乎没有下降的余地。 |
| PDF - Create PdfA | Compliance | PdfA2b | ISO 19005-2,B级。即使多年以后,该页面在任何查看器上的呈现方式都相同。 |
| PDF - Create PdfA | Allow Upgrade | Yes | 当请求的操作无法执行时,允许操作执行到更高的级别。 |
| PDF - Create PdfA | Allow Downgrade | Yes | 让它稳定在一个较低的水平,而不是直接失败。 |

Compress操作在转换后的发票上进行,在进行任何认证之前完成。

Create PdfA是处理文档的最后一个操作,这才是它应该在的位置。
对于 SharePoint 中已有的文件,同一对工具在 Power Automate 中使用无人值守 SharePoint 文件夹进行 PDF 归档时,也能执行相同的操作。
步骤 7:完成的发票保存在哪里?
目前流程:所有操作均通过Create PdfA。
最后一步操作是将已认证的发票写回同一个 SharePoint 站点。
- 添加SharePoint > Create file。
- 配置:
- Site Address:
PDF4me Sharepoints - https://ynoox1.sharepoint.com/sites/PDF4meSharepoints - Folder Path:
/Shared Documents/ArchivedExcel - File Name:
ExcelArchived.pdf - File Content:PDF 的Body标记PDF - Create PdfA
- Site Address:
SharePoint Create file:配置

PDF4me 的每个操作都会输出一个名为Body标记,因此仅凭标签无法告诉您选择了哪个操作。将鼠标悬停在其上,或查看代码视图中的 body('PDF_-_Create_PdfA')。
上线前请更改此设置。ExcelArchived.pdf ExcelArchived.pdf一个固定名称,因此每个新列表项都会写入同一个文件,导致文件夹中始终只包含最新的发票。请改为从行中构建名称。列表项 ID 根据定义是唯一的,因此concat('Invoice-', triggerBody()?['ID'], '.pdf')始终有效。Title中的发票编号也可以,只要它不包含 SharePoint 禁止在文件名中使用的字符,例如斜杠、冒号、星号或问号。
运行流程并验证
- Save右上角的流程。
- 在列表中添加一个名为Excel Template的新项目,并填写模板使用的每一列。
- 打开运行历史记录。所有八项操作都应显示为绿色,其中Convert、Compress和Create PdfA操作耗时最长。
- 打开
/Shared Documents/ArchivedExcel,检查 PDF 文件是否存在,并且Modified By显示该流程的帐户。 - 打开文件本身,将其与列表行进行比较,然后检查其文档属性中的 PDF/A 声明。
从捕获的运行结果中生成的发票大小为 37,876 字节。它呈现了一行Morris - INV:客户Morris Luma来自Invoicing.co,日期为 2026 年 9 月 1 日,到期日为 2026 年 9 月 20 日,包含两个行项目:PDF to Excel (数量 60)和 PDFA(数量 45)。其 XMP 元数据声明pdfaid:part为2,pdfaid:conformance为B,从内部看,这是 PDF/A-2b 格式。由于步骤 5 中所述的页面设置原因,它实际上是两页而不是一页。
你实际构建了什么?一个发票处理流程,其中唯一的手动步骤就是输入数据。布局文件保存在一个任何人都可以编辑的 Excel 文件中,数据存储在一个列表中,输出结果是一个独立的归档 PDF 文件,无需任何人手动归档。这个流程也不局限于 Power Automate:它同样适用于Make、Zapier 和 n8n 等工具,只要这些工具支持PDF4me Excel和 PDF/A 操作即可。
无需重建即可添加的常见变体
与其他开票方式相比,这种方式有何不同?
每一行描述了一种替代方案。最后一行就是这个流程。
| 比较 | 谁可以更改布局 | 模板是如何填写的 | 存档格式 |
|---|---|---|---|
| 手工填写的 Excel 模板与此流程 | 任何使用Excel的人 | 一次复制粘贴一张发票 | 除非有人设置了 PDF/A 导出选项,否则默认导出为纯 PDF 文件 |
| Excel VBA 宏与此流程 | 维护宏的人 | 自动,在已打开工作簿的桌面上 | 除非导出设置为 PDF/A,否则默认为纯 PDF |
| HTML模板加上将HTML Convert为PDF与此流程的对比 | 熟悉 HTML 和 CSS | 自动在云端 | |
| 这种流程 | 任何使用Excel的人 | 自动地,对于每个新的列表项 | PDF/A-2b |
关键区别在于:前两种方案保留了 Excel 中的布局,但需要人工参与;第三种方案则取消了人工参与,将布局操作移至代码中。只有这种流程能够同时实现这两种目标。
常见问题
是否有Excel格式的发票模板?
是的。Excel 自带发票模板:在桌面应用程序中,选择File > New,然后搜索发票;微软还在其在线模板库中发布了更多模板。这些模板是设计成需要手动填写的。
本文中使用的模板是为其他用途而构建的。它的值单元格包含智能标记而不是示例文本,因此流程可以填充它。您可以用同样的方法转换任何您喜欢的发票模板:保留设计,并将每个值替换为类似&=RootData.Invoice.Number(noadd)标记。
如何根据Excel数据生成发票?
将数据按行保存,将布局放在模板中,然后让某个工具将两者合并。在 Excel 中,这个工具可以是 Word 邮件合并或 VBA 宏,两者都运行在用户的桌面上。
在此流程中,数据行位于 SharePoint 列表中,Compose会将其中一行转换为 JSON 格式,Excel - Populate操作会将其合并到模板中。如果您的数据已经是 OneDrive 或 SharePoint 中的 Excel 表格,则可以使用Excel Online (Business)连接器的List rows present in a table 操作,在 Apply to each循环中调用相同的Compose 操作,并将 triggerBody() 替换为items('Apply_to_each')。从步骤 3 开始的所有操作保持不变。
如何在Excel中自动生成发票?
发票自动化意味着省去人工处理发票的每一个步骤:输入数值、导出为PDF、命名文件和归档。模板本身仍然是一个普通的Excel文件。
此流程移除了所有四个步骤。列表行是唯一的输入。模板由Excel - Populate填充,由Convert to PDF导出,由PDF - Create PdfA功能归档,并由Create file功能归档。一旦文件名按照步骤 7 所述从该行生成,就无需再进行任何手动操作。
Power Automate 能否将 Excel 文件转换为 PDF 文件?
是的。在云端流程中,OneDrive for Business连接器的Convert file操作会将 .xlsx 文件转换为 PDF 文件,但仅适用于存储在 OneDrive 中的文件,因此 SharePoint 流程通常会先将工作簿复制到 OneDrive,然后再将其删除。
PDF4me Convert to PDF直接从之前的操作中获取文件内容。因此,此流程中填充的工作簿不会保存到任何地方:它直接从Excel - Populate导入转换器,最终只会生成最终的 PDF/A 发票文件并上传到 SharePoint。
故障排除
检查Compose表达式中的列名。它必须是内部名称Dateandtime,而不是Date and time triggerBody()?['Dateandtime']中的问号会将错误的名称转换为 null 而不是报错,因此运行结果显示为绿色,单元格保持为空。如果名称正确,请检查 JSON 路径是否与标记一致:RootData,然后是Customer,最后是 Name,两者拼写必须完全相同。
模板宽度超过一页打印页的宽度。Convert to PDF时会沿用工作簿的页面设置,因此请在此处进行调整:Page Layout,Scale to Fit,宽度设置为1 page。将模板保存回 SharePoint,下次运行时即可适应一页宽度。
Create file File Name固定为文本ExcelArchived.pdf,因此每次运行都会使用相同的文件名。请使用列表项 ID 使每行文件名唯一,如步骤 7 所述。
Create file时,读取的是PDF - Compress或Convert to PDF,而不是PDF - Create PdfA。这三个标记都标记为Body,因此很容易出错,而且运行历史记录中没有任何错误。请确认表达式是否为body('PDF_-_Create_PdfA')。
后续步骤
同样的八步模式(列出行、重塑为 JSON、获取模板、填充、转换、压缩、认证、保存)可以处理任何以电子表格形式开始的文档:报价单、送货单、声明和证书。