百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Excel VBA 应用案例分享/电子发票管理小助手/电子发票信息读取

yuyutoo 2025-02-04 16:54 1 浏览 0 评论

本文于2023年5月31日首发于本人同名公众号:Excel活学活用,更多文章案例请搜索关注!

☆本期内容概要☆

  • 发票文件选择,取得文件名
  • VBA正则表达式
  • PDF文件信息读取
  • OFD文件信息读取

大家好,我是冷水泡茶,这几天一直在修改我的《电子发票管理系统》,这是我一年多以前做的一个应用,在公司里正常使用。搞这个系统的缘由很简单,发票数字化、电子化是一个不可阻挡的趋势,看看最近多家省市又开始全电发票试点的新闻就知道了。数字发票好处是很多,但是对我们财务人员来讲,却谈不上有多少好处。困难倒是不少,主要有两个,一是电子发票可以重复打印,如何避免重复报销入账(不管是有意还是无意),都是一个难题;二是电子数据归档问题,财政部和国家档案局都有明确规定,简要说来就是,各个会计主体、核算单位,都要把电子发票的数据文件保存下来,如果有ERP、OA等信息系统的,可以只保存电子文档,其他以打印出来的纸质发票报销入账的单位,要同时保存相应的电子发票文档,并且要求与会计凭证能够对应,方便查询,至少要把每个月的电子发票归类到一个独立的目录中,比如202305之类的。

虽然很多单位都没能做到这一点,好象也没有谁来查,但我们不能就这样糊弄着过吧,总得做点什么。

我看到有的财务是自己登记的,把发票号码输入到一个EXCEL表中,可以检查是否重复,但不仅工作量大,而且容易出错,万一号码登记错了呢?增加了重复报销的可能性,那不都变成财务的责任了?这样的事,咱是不干的;还有发票电子文档的收集、整理,那也是让人崩溃的事,所有这些,最后都集中到财务这来,真是压力山大呀。这咱也不能干。

事情还是要做的,那就寻找解决办法呗。

经过一段时间(具体多少日子记不清了),我终于完成了《电子发票管理系统》的设计,以EXCEL为客户端,Access为数据存储端,以共享文件夹为发票电子文档、Access数据库保存目录,实现每人可以在自己的电脑登录操作。基本流程是这样的:

1、报销人下载、打印好电子发票,然后登录系统,进入“发票登记”模块,填写发票的关键信息,选择电子发票文件完整路径。

2、填写完毕后保存,程序会检验发票号码是否重复,重复则不能保存。各种校验无误后,自动将电子发票的文档复制到共享的数据库文件夹里,同时可以自动打印“报销单”,这个功能是省事了。

3、报销人持报销单及发票打印件到财务审核,财务人员登录系统,进入“发票审核”模块,双击一条记录,可以打开发票电子文档,进行核对,核对无误后点审核。

4、财务审核后,报销人将报销单报领导审批(线下签字),审批完成后,交财务出纳处付款。出纳登录系统,进入“出纳付款”模块,列出已审核未付款的报销单,确认无误后点付款。

5、最后,财务记账归档,财务人员登录系统,进入“发票记账“模块,列出所有已付款未记账的报销单,对应到财务记账凭证号,把凭证号录入系统,这样可以方便地查询。整个流程结束。

看起来还是不错的,就这样运行了一年多,也没出什么问题。我是财务审核人,不忙的时候就看得仔细点,忙的时候就看得马虎些,自始至终没有审出一张有问题的发票来。但心里总是隐隐感觉有那么点不踏实。

本来也没有想去更新这个系统,直到我自己填了几次报销单,就一个字:烦!虽然我也搞了一些复制发票、项目选择的功能,以减轻录入发票的工作量,但是真的比较烦,工作量确实比较大。于是萌生了一个念头:要是能自动读取发票信息就好了!

于是就上网各种搜,“电子发票信息读取”、“EXCEL操作PDF”......

最后,搜到一个公众号文章:【电子发票台账T006(V1.1.3)】,他提供了文件下载,于是赶紧下载来看看。他的功能是是读取一个文件夹下所有发票文件,然后把关键信息登记下来,形成一个发票台账。

他的代码对我来说非常有价值,在此表示感谢。他的思路简要说明如下:

1、PDF文档可以转换成WORD文档,然后读取WORD文档的内容,运用正则表达式提取发票关键信息,要求电脑上装有“Adobe Acrobat Pro“。

2、OFD文档可以通过RAR解压,得到XML文档,然后读取XML文档内容,提取发票关键信息,要求电脑上装有RAR压缩软件。

扯了这么多,终于到我今天要分享的工具了“电子发票管理助手”。在“电子发票台账T006”在基础上,按照我自己需求,进行了重新编写:

1、参考的地方:

(A)总体思路,发票文件的读取、转化方法。

(B)部分正则表达式。

(C)其他

2、优化与改进的地方:

(A)RAR程序是否安装的判断与路径的直接获取。

(B)临时文件夹建立、删除方式。

(C)OFD文件的信息提取方式,并增加了最新发票格式的读取。

(D)正则表达式优化与扩展,增加了2种版本的发票读取。

(E)获取的发票信息采取变量方式存储。

下面来说一说我的“电子发票管理助手”设计过程与思路吧

1、定义一个过程 ReadInvoiceFile

Sub ReadInvoiceFile()
    On Error Resume Next
    Dim FileExtn As String
    Dim iRow As Integer
    InvoiceCode = ""
    InvoiceNo = ""
    SellerName = ""
    SellerTaxID = ""
    Amount = ""
    TaxAmount = ""
    invoiceDate = ""
    ItemName = ""
    BuyerName = ""
    currInvoiceFile = FileSelected
    If currInvoiceFile = "" Then Exit Sub


    FileExtn = GetExtn(currInvoiceFile)
    'Stop
    If FileExtn = ".pdf" Then
        Call ReadPDFInvoiceInfo
    ElseIf FileExtn = ".ofd" Then
        Call ReadOFDInvoiceInfo
    End If
    '发票信息写入工作表
    Sheets("Result").Activate
    With ActiveSheet
        iRow = .UsedRange.Rows.Count + 1
        Cells(iRow, 1) = BuyerName
        Cells(iRow, 2) = invoiceDate
        Cells(iRow, 3) = "'" & InvoiceCode
        Cells(iRow, 4) = "'" & InvoiceNo
        Cells(iRow, 5) = SellerName
        Cells(iRow, 6) = "'" & SellerTaxID
        Cells(iRow, 7) = ItemName
        Cells(iRow, 8) = Amount
        Cells(iRow, 9) = TaxAmount
        Cells(iRow, 10) = CDbl(Amount) + CDbl(TaxAmount)
        .Hyperlinks.Add Anchor:=.Cells(iRow, 11), _
        Address:=currInvoiceFile, _
        TextToDisplay:="打开文件"
    End With
    MsgBox "发票信息读取完毕,请仔细核对! " & Chr(10) & "若有错误,请手工修改!" & Chr(10) & "空白部分,请手工填写!"
End?Sub

代码解析:

先把一些公共变量值清空,然后选择文件,根据文件后缀判断,是PDF的,我们运行ReadPDFInvoiceInfo过程,是OFD的,我们运行ReadOFDInvoiceInfo过程,这两个过程都是用来读取发票信息的,读取到的信息存到变量中,完成后,回到本过程再把发票信息写入工作表,并添加发票文件链接。

2、读取PDF文件过程ReadPDFInvoiceInfo,代码较多,我贴到第二条文章。

(1)设置临时文件夹c:\temp\,如果没有则创建。

tempFolder = "c:\temp\"
If?Dir(tempFolder,?vbDirectory)?=?""?Then
????MkDir?tempFolder
End?If

(2)创建 Acrobat 应用程序对象,打开PDF发票文件,转存为WORD文件。

'创建?Acrobat?应用程序对象
Set acrobatApp = CreateObject("AcroExch.App")
'创建 Acrobat AVDoc 对象
Set AcrobatAVDoc = CreateObject("AcroExch.AVDoc")
'打开选择的 PDF 文件
AcrobatAVDoc.Open currInvoiceFile, ""
acrobatApp.Hide
Set AcrobatPDDoc = AcrobatAVDoc.GetPDDoc
Set jsObj = AcrobatPDDoc.getjsobject
'创建 Word 应用程序对象
Set WordApp = CreateObject("Word.Application")
'关闭安全提示
WordApp.Application.AutomationSecurity = msoAutomationSecurityForceDisable
'将 PDF 转换为 Word
WordFilePath = tempFolder & Format(Time, "hhmmss") & ".docx"
jsObj.SaveAs WordFilePath, "com.adobe.acrobat.docx"
'关闭和清理 Acrobat
AcrobatAVDoc.Close 1
acrobatApp.Exit

(3)打开WORD文件,读取信息到变量wordContent,然后通过正则表达式提取相应的发票关键字信息存入变量。

(4)读取完成后,删除临时文件夹。这里建立了一个删除文件夹的过程,看看代码就知道是ChatGPT生成的,基本没改。

Sub DeleteDirectory(ByVal folderPath As String)
    On Error Resume Next
    Dim fs As Object
    Dim folder As Object
    Dim subFolder As Object
    Dim file As Object
    ' 创建 FileSystemObject
    Set fs = CreateObject("Scripting.FileSystemObject")
    ' 获取目录对象
    Set folder = fs.GetFolder(folderPath)
    ' 遍历目录中的子目录并递归删除
    For Each subFolder In folder.SubFolders
        DeleteDirectory subFolder.Path
    Next subFolder
    ' 删除目录中的文件
    For Each file In folder.Files
        file.Delete
    Next file
    ' 删除目录
    folder.Delete
    ' 释放对象引用
    Set file = Nothing
    Set subFolder = Nothing
    Set folder = Nothing
    Set fs = Nothing
End Sub

3、读取OFD文件过程ReadOFDInvoiceInfo,代码也不少,同样我贴到第二条文章。

(1)检查有没有RAR压缩文件,有就取得其安装路径,没有就退出程序。这里定义了一个自定义函数GetRARPath,也是ChatGPT贡献的

Function GetRARPath()
    Dim rarPath As String
    On Error Resume Next
    ' 打开WinRAR的注册表项
    rarPath = CreateObject("WScript.Shell").RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe\")
    If Err.Number = 0 Then
        ' 获取WinRAR的安装路径
        GetRARPath = rarPath
    Else
        ' RAR未安装
        GetRARPath = ""
    End If
    On Error GoTo 0
End Function

(2)把OFD文件解压到临时文件夹下,这里通过shell函数执行RAR解压命令,由于解压需要点时间,所以用了个Sleep函数暂停1秒,不然没完全解压就执行后面的代码会报错,虽然后面Do Until~Loop也是起等待的作用,在原来只有一种发票格式的情况下可行,后来增加了一种发票就不太行了,有时会报错,这里以后再优化:

destFolder = tempFolder & Format(Time, "hhmmss") & "\"
rarCmd?=?rarPath?&?"?X?"?&?currInvoiceFile?&?"?"?&?destFolder
Result?=?shell(rarCmd,?vbHide)
Sleep?1000?'?Delay?for?2?seconds?(2000?milliseconds)
'等待解压完成
Do?Until?Dir(destFolder?&?"Doc_0\Attachs\original_invoice.xml")?<>?""?_
    Or Dir(destFolder & "Doc_0\Pages\Page_0\Content.xml") <> ""
        DoEvents
Loop

(3)读取发票信息

 NewDOMD.Load destFolder & "Doc_0\Attachs\original_invoice.xml"
?Set?xmld?=?NewDOMD.DocumentElement.SelectSingleNode("//eInvoice")
?Set?SelectedNode?=?xmld.SelectSingleNode("//fp:InvoiceCode")
?InvoiceCode?=?SelectedNode.Text
?
......


NewDOMD.Load destFolder & "Doc_0\Pages\Page_0\Content.xml"
Set?xmld?=?NewDOMD.DocumentElement.SelectSingleNode("//ofd:Page")
Set?SelectedNode?=?xmld.SelectSingleNode("//ofd:TextObject[@ID='6922']/ofd:TextCode")
InvoiceCode?=?Left(SelectedNode.Text,?12)
InvoiceNo?=?Right(SelectedNode.Text,?8)

代码解析:

(A) NewDOMD.Load加载XML文件

(B)Set xmld取得一个节点

(C)Set SelectedNode选中一个具体的节点

(D)InvoiceCode = SelectedNode.Text ,把节点TEXT赋值给变量。

(E)开头是旧式的电子发票,有密码区的,后面的最近的数电发票,两者的结构是不一样的,有兴趣的朋友可以找来这样的发票解压后分析。新式发票没有发票代码,发票号码是20位,这里我们还是把它处理成12位发票代码和8位发票号码。

其他一些过程什么的就不说了,上面的示例代码仅为部分代码,并且后续可能会修改,感兴趣的朋友可以参看下一篇文章。好,今天就到这吧,欢迎点赞、留言、分享,谢谢大家,我们下期再会。


☆猜你喜欢☆

【重磅】Excel VBA 应用分享/中医诊所收费系统/Excel+ListBox版

Excel VBA 动态添加控件/学生成绩筛选

Excel VBA 这样酷炫的日期控件,你不想要吗?

Excel 公式函数/数据透视表/固定资产折旧计提表!

Excel VBA 自定义函数/数组字段定位/数组字段排序

Excel 功能/公式函数/VBA/多种姿势处理重复值

Excel VBA 最简单的收发存登记系统

Excel 公式函数/查找函数之LOOKUP

Excel VBA 文件批量改名

Excel 公式函数/数据验证/动态下拉列表

Excel VBA 输入逐步提示/TextBox+ListBox

Excel 基础功能【数据验证】,你会怎么用?


本文于2023年5月31日首发于本人同名公众号:Excel活学活用,更多文章案例请搜索关注!

相关推荐

微软Win10/Win11版Copilot上线:支持OpenAI o3推理模型

IT之家4月3日消息,科技媒体WindowsLatest昨日(4月2日)发布博文,报道称Windows10、Windows11新版Copilot应用已摘掉Beta帽...

WinForm 双屏幕应用开发:原理、实现与优化

在当今的软件开发领域,多屏幕显示技术的应用越来越广泛。对于WinForm应用程序来说,能够支持双屏幕显示不仅可以提升用户体验,还能满足一些特定场景下的业务需求,比如在演示、监控或者多任务处理等场景...

推荐一个使用 C# 开发的 Windows10 磁贴美化小工具

...

OpenJDK 8 安装(openjdk 8 windows)

通常OpenJDK8和11都能互相编译和通用。我们建议使用11,但是如果你使用JDK8的话也是没有问题的。建议配置使用OpenJDK,不建议使用OracleJDK,主要是因为版...

基于 Linux 快速部署 OpenConnect VPN 服务(ocserv 实战指南)

一、前言在如今远程办公和内网穿透需求日益增长的背景下,搭建一套安全、稳定、高效的VPN系统显得尤为重要。OpenConnectServer(ocserv)是一个开源、高性能的VPN服务端软件...

巧妙设置让Edge浏览器更好用(edge怎么设置好用)

虽然现在新版本的Edge浏览器已经推出,但是毕竟还处于测试的状态中。而Win10系统里面自带的老版Edge浏览器,却越来越不被人重视。其实我们只需要根据实际情况对老版本的Edge浏览器进行一些简单的设...

WPF做一个漂亮的登录界面(wpf页面设计)

...

微软开源博客工具Open Live Writer更新:多项Bug修复

OpenLiveWriter前身是WindowsLiveWriter,是微软WindowsLive系列软件之一,曾经是博主们非常喜爱的一款所见即所得博文编辑工具,支持离线保存,还支持图像编辑...

基于OpenVINO的在线设计和虚拟试穿 | OPENAIGC大赛企业组优秀作品

在第二届拯救者杯OPENAIGC开发者大赛中,涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到,我们特意开设了优秀作品报道专栏,旨在展示其独特之处和开发者的精彩故事。...

C#开源免费的Windows右键菜单管理工具

...

Windows10或11中隐藏的功能,用它再也不用担心电脑中病毒!

...

Python open函数详解(python open函数源码)

演示环境,操作系统:Win1021H2(64bit);Python解释器:3.8.10。open是Python的一个内置函数,一般用于本地文件的读写操作。用法如下。my_file=open(fi...

Windows 11 安装 Docker Desktop(Windows 11 安装助手 Windows 易升 关系)

...

Windows 11 新版发布:屏幕亮度自适应控制,小组件界面重新设计!

...

世界上最好用的Linux发行版之一,OpenSUSE安装及简单体验

背景之前无意在论坛里看到openSUSE的Linux发行版,被称为世界上最好用的Linux发行版之一(阔怕),一直想体验一下,于是这期做一个安装和简单体验教程吧。...

取消回复欢迎 发表评论: