夜雨聆风学习资料网

ARTICLE · 1100182

第381讲:VBA(Office 原生)和 Python(跨平台批量)实现报销单/发票批量生成 Word/PDF

第381讲:VBA(Office 原生)和 Python(跨平台批量)实现报销单/发票批量生成 Word/PDF

每到月底,财务同事的桌面大概是这样的:一个塞满明细的 Excel、十几个手动复制出来的 Word 报销单、命名从“报销单1”到“报销单final真最终版”……复制、粘贴、调格式、另存为 PDF,一套流程下来,两三个小时就没了,还容易串行。

这一讲,我们不讲“自动化神话”,只解决一个非常具体的活:把 Excel 报销明细,一键灌进 Word 模板,批量导出带编号的 PDF,并规规矩矩地归档。

我会同时给两套实现:VBA(Office 原生)和 Python(跨平台批量),你可以按团队环境选。


一、先理清业务骨架

假设 Excel 结构如下:

报销编号

姓名

部门

事由

金额

日期

BX20240901

张三

市场部

差旅

1860.50

2026-09-01

目标产物:

  • 每个报销单一个 PDF

  • 文件名规则:BX20240901_张三_报销单.pdf

  • 归档目录:归档/2024/09/

这个“数据→模板→PDF→归档”的链路,核心只有两步:填充模板 + 导出固定格式。


二、VBA 方案:Office 内邮件合并的“老派稳”

VBA 的优势是不用装环境,财务电脑自带。思路用 Word 的邮件合并(MailMerge),再用 ExportAsFixedFormat落 PDF。

关键步骤

  1. 在 Word 里做好模板,占位符用 «姓名» «报销编号»这类合并域。

  2. Excel 作为数据源连接。

  3. 逐条执行合并 → 另存 PDF。

核心 VBA 片段(Word端)

Sub BatchExportPDF()    Dim wd As Document, rec As Long    Set wd = ActiveDocument    wd.MailMerge.DataSource.ActiveRecord = 1    For rec = 1 To wd.MailMerge.DataSource.RecordCount        wd.MailMerge.Destination = wdSendToNewDocument        wd.MailMerge.Execute False        With ActiveDocument            .ExportAsFixedFormat _                OutputFileName:="D:\归档\2024\09\" & _                .MailMerge.DataFields("报销编号").Value & "_报销单.pdf", _                ExportFormat:=wdExportFormatPDF            .Close False        End With        wd.MailMerge.DataSource.ActiveRecord = rec + 1    NextEnd Sub

💡 踩坑提示:邮件合并对“金额”默认会丢小数位,需在 Excel 里先把金额格式成文本 "1860.50",或在域里用 \# "0.00"开关。

适用场景:财务只跑 Windows + Office,模板样式复杂(页眉页脚、骑缝章位置),VBA 最省事。


三、Python 方案:批量、可复现、跨平台

当一次要跑几百条、或者要在 Linux 服务器/CI 里定时生成,VBA 就力不从心了。Python 用 python-docx填模板,Jinja2做文本渲染,docx2pdf(Win)或 LibreOffice headless(跨平台)转 PDF。

方案选型对照

环节

库

说明

读Excel

pandas/ openpyxl

稳定读 xlsx

填Word

python-docx

替换占位符 {{姓名}}

复杂排版

Jinja2+ docx 段落渲染

适合循环明细行

转PDF

docx2pdf(Win)/ libreoffice --headless

跨平台首选后者

Python 完整示例

import pandas as pdfrom docx import Documentimport osfrom docx2pdf import convert  # Windows环境TEMPLATE = "报销单模板.docx"OUT_DIR = "归档/2024/09"os.makedirs(OUT_DIR, exist_ok=True)df = pd.read_excel("报销明细.xlsx")def fill_template(row):    doc = Document(TEMPLATE)    # 简单占位符替换(段落+表格单元格)    mapping = {        "{{报销编号}}": str(row["报销编号"]),        "{{姓名}}": row["姓名"],        "{{部门}}": row["部门"],        "{{事由}}": row["事由"],        "{{金额}}": f'{row["金额"]:.2f}',        "{{日期}}": str(row["日期"])[:10],    }    for p in doc.paragraphs:        for k, v in mapping.items():            if k in p.text:                p.text = p.text.replace(k, v)    # 处理表格内占位符    for tbl in doc.tables:        for r in tbl.rows:            for cell in r.cells:                for k, v in mapping.items():                    if k in cell.text:                        cell.text = cell.text.replace(k, v)    docx_path = f"{OUT_DIR}/{row['报销编号']}_tmp.docx"    doc.save(docx_path)    return docx_pathfor _, row in df.iterrows():    tmp = fill_template(row)    pdf_path = tmp.replace("_tmp.docx", f"_{row['姓名']}_报销单.pdf")    convert(tmp, pdf_path)    os.remove(tmp)print("✅ 批量生成完成")

📌 进阶干货:如果报销单要带“多行费用明细”(一条报销含机票/酒店/打车多行),纯占位符不够用。此时用 Jinja2 渲染 HTML → WeasyPrint 转 PDF,比硬改 docx 表格优雅得多:

from jinja2 import Template
html = Template(open("tpl.html").read()).render(rows=detail_rows)
# WeasyPrint(html, writer).write("out.pdf")

Python vs VBA 实战取舍

维度

VBA

Python

环境

Office自带

需装Python

样式还原

100%(原生Word)

docx还原好,HTML转PDF更灵活

批量几百条

慢、易卡

秒级

定时/服务端

不支持

配合cron/任务计划

学习成本

财务易上手

需一点开发基础


四、交付规范(别只给文件,给“规矩”)

自动化不是只出PDF,而是让归档可审计:

  1. 编号规则:BX + 年份 + 月份 + 3位流水,如 BX202409001

  2. 文件名:{编号}_{姓名}_报销单.pdf

  3. 目录结构:

    归档/└── 2024/    └── 09/        ├── BX202409001_张三_报销单.pdf        └── 生成日志_20240930.txt
  4. 日志:记录每条生成状态(成功/跳过/金额异常),财务留痕用。

小经验:金额>5000的报销单,建议在文件名前加标记 [审],方便复核人一眼筛。


五、随堂小测(5道选择题)

1. 使用 VBA 批量导出 Word 为 PDF,核心方法是?

A. SaveAs2

B. ExportAsFixedFormat

C. PrintOut

D. MailMerge.Execute

2. Python 中用于读取 Excel 报销明细的常用库是?

A. python-docx

B. Jinja2

C. pandas / openpyxl

D. pdfkit

3. 关于邮件合并“金额丢小数”问题,下列最稳妥的处理是?

A. 忽略,四舍五入即可

B. Excel 预格式化为文本 "1860.50"或用 \# "0.00"域开关

C. 在Word里手改

D. 改用PPT做单

4. 需要“一条报销含多行费用明细”的复杂排版,推荐方案是?

A. VBA 邮件合并硬塞

B. Jinja2渲染HTML + WeasyPrint转PDF

C. 手动复制表格

D. 截图贴图

5. 下列文件名符合本讲编号规范的是?

A. 报销单_final.docx

B. 张三.pdf

C. BX202409001张三报销单.pdf

D. 9月1号.pdf


🔑 答案(拉到底才看哦)

  1. B 2. C 3. B 4. B 5. C

相关学习资料