VBA学习(75):电子发票管理小助手/电子发票信息读取

news/2024/9/18 14:10:35/ 标签: excel, VBA

“电子发票管理助手”设计过程与思路

1、定义一个过程 ReadInvoiceFile

Sub ReadInvoiceFile()On Error Resume NextDim FileExtn As StringDim iRow As IntegerInvoiceCode = ""InvoiceNo = ""SellerName = ""SellerTaxID = ""Amount = ""TaxAmount = ""invoiceDate = ""ItemName = ""BuyerName = ""currInvoiceFile = FileSelectedIf currInvoiceFile = "" Then Exit SubFileExtn = GetExtn(currInvoiceFile)'StopIf FileExtn = ".pdf" ThenCall ReadPDFInvoiceInfoElseIf FileExtn = ".ofd" ThenCall ReadOFDInvoiceInfoEnd If'发票信息写入工作表Sheets("Result").ActivateWith ActiveSheetiRow = .UsedRange.Rows.Count + 1Cells(iRow, 1) = BuyerNameCells(iRow, 2) = invoiceDateCells(iRow, 3) = "'" & InvoiceCodeCells(iRow, 4) = "'" & InvoiceNoCells(iRow, 5) = SellerNameCells(iRow, 6) = "'" & SellerTaxIDCells(iRow, 7) = ItemNameCells(iRow, 8) = AmountCells(iRow, 9) = TaxAmountCells(iRow, 10) = CDbl(Amount) + CDbl(TaxAmount).Hyperlinks.Add Anchor:=.Cells(iRow, 11), _Address:=currInvoiceFile, _TextToDisplay:="打开文件"End WithMsgBox "发票信息读取完毕,请仔细核对! " & Chr(10) & "若有错误,请手工修改!" & Chr(10) & "空白部分,请手工填写!"
End Sub

代码解析:

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

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

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

tempFolder = "c:\temp\"
If Dir(tempFolder, vbDirectory) = "" ThenMkDir 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 NextDim fs As ObjectDim folder As ObjectDim subFolder As ObjectDim file As Object' 创建 FileSystemObjectSet fs = CreateObject("Scripting.FileSystemObject")' 获取目录对象Set folder = fs.GetFolder(folderPath)' 遍历目录中的子目录并递归删除For Each subFolder In folder.SubFoldersDeleteDirectory subFolder.PathNext subFolder' 删除目录中的文件For Each file In folder.Filesfile.DeleteNext file' 删除目录folder.Delete' 释放对象引用Set file = NothingSet subFolder = NothingSet folder = NothingSet fs = Nothing
End Sub

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

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

Function GetRARPath()Dim rarPath As StringOn 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 = rarPathElse' RAR未安装GetRARPath = ""End IfOn 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位发票号码。

其他一些过程什么的就不说了,上面的示例代码仅为部分代码,并且后续可能会修改,感兴趣的朋友可以参看第二条文章或者索取示例文件查看。


http://www.ppmy.cn/news/1526332.html

相关文章

初识Linux · 进程(4)

目录 前言&#xff1a; 进程的状态 直接谈论进程的状态 僵尸进程和孤儿进程 纯理论部分 运行态&#xff1a; 阻塞态&#xff1a; 挂起态&#xff1a; 进程的优先级以及切换问题 切换&#xff1a; 优先级&#xff1a; 前言&#xff1a; 承接上文&#xff0c;进程1到…

Laravel接口中实现WebSocket服务消息发送PHP中使用socket扩展搭建WebSocket服务

要在Laravel接口中实现WebSocket服务消息发送&#xff0c;你可以使用Laravel的Pusher库。首先&#xff0c;你需要安装Pusher库&#xff1a; composer require pusher/pusher-php-server然后&#xff0c;在你的Laravel项目中创建一个WebSocket事件类&#xff0c;例如WebSocketE…

【30天玩转python】装饰器与闭包

装饰器与闭包 装饰器和闭包是 Python 中非常强大的特性。理解它们不仅有助于写出更简洁和模块化的代码&#xff0c;还能极大地提高代码的复用性和灵活性。本节将详细介绍装饰器与闭包的概念、用法及其在实际编程中的应用。 1. 闭包 闭包&#xff08;Closure&#xff09;是指一…

Linux之ansible的playbook剧本(yaml文件)

playbook剧本 一个剧本&#xff08;即playbook&#xff09;&#xff0c;可以包含多个play 每个play用于在指定的主机上&#xff0c;通过模块和参数执行相应的任务 每个play可以包含多个任务。 任务有模块和参数构成。 paly要建立在ansible文件夹下才能使用 因为yaml文件对格式…

精简实用!一分钟搭建文件管理服务!

大家好&#xff0c;我是 Java陈序员。 今天&#xff0c;给大家介绍一款精简实用的文件托管服务&#xff0c;一分钟即可搭建使用&#xff01; 关注微信公众号&#xff1a;【Java陈序员】&#xff0c;获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。 项目介绍 Du…

Linux 入门:简单的基础操作

“批判他人总是想的太简单 剖析自己总是想的太困难” 文章目录 前言Linux 入门&#xff1a;从基础操作到 WSL2 安装文章有误敬请斧正 不胜感恩&#xff01;1. 什么是 Linux&#xff1f;2. Linux 和其他系统有啥不同&#xff1f;3. Linux 的主要组成4. 常见 Linux 发行版5. 基本…

【深度学习】搞懂卷积神经网络(一)

卷积神经网络是一种具有局部连接&#xff0c;权重共享等特性的深层前馈神经网络。一般是由卷积层&#xff0c;池化层&#xff0c;全连接层交叉堆叠而成&#xff0c;使用反向传播算法进行训练。卷积神经网络具有一定程度上的平移&#xff0c;缩放和旋转不变性&#xff0c;较前馈…

k8s 中的 Service 简介

前言 k8s 集群中的每一个 Pod 都有自己的 IP 地址&#xff0c;那么是不是有 IP 了&#xff0c;访问起来就简单了呢&#xff0c;其实不然。 因为在 k8s 中 Pod 不是持久性的&#xff0c;摧毁重建将获得新的 IP&#xff0c;客户端通过会变更 IP 来访问显然不合理。另外 Pod 还经…

每天五分钟深度学习PyTorch:不同的神经网络层设置不同的学习率

本文重点 我们前面学习了基本网络模型的搭建,获取网络模型的子结构,以及优化器optim,我们发现我们设置优化器的时候,是对整个模型设置的,也就是说整个模型的参数学习率是一样,本节课程我们学习如何给不同的网络层设置不同的学习率。主要还是通过优化器optim来实现的,本…

Radware 报告 Web DDoS 攻击活动

新一代 HTTPS 洪水攻击的频率和强度急剧增加&#xff0c;攻击者引入的复杂程度也在迅速提高。2024 年上半年&#xff0c;Web 分布式拒绝服务 (DDoS) 攻击的频率和强度显著增加。其中很大一部分活动可以归因于受政治紧张局势驱使的黑客活动分子。 众所周知&#xff0c;当今的黑…

Python中匹配HTML标签时<.*>和<.*?>有什么区别

在讨论Python中匹配HTML标签时使用的正则表达式<.*>与<.*?>的区别&#xff0c;实际上是在讨论正则表达式中的贪婪模式&#xff08;Greedy Mode&#xff09;与非贪婪模式&#xff08;Non-Greedy Mode&#xff09;或懒惰模式&#xff08;Lazy Mode&#xff09;之间的…

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADCDMA采样时&#xff0c;遇到了一些小坑记录一下&#xff1b; 一、ADCDMA采样时进入死循环&#xff1b; 解决方法&#xff1a;ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高&#xff0c;且增大ADCHAL_ADC_Start_DMA(&ha…

git 命令---想要更改远程仓库

在 Git 中&#xff0c;origin 是默认的远程仓库名称。可以使用以下命令查看当前 Git 仓库的 origin 名称及其对应的 URL&#xff1a; git remote -v这个命令会列出所有配置的远程仓库及其名称&#xff0c;其中 origin 通常是克隆时自动设置的默认远程仓库名称。输出示例&#…

堆排序,快速排序

目录 1.堆排序 2.快速排序 1.hoare版本 2.挖坑法 3.前后指针法 注意点 1.堆排序 void Swap(int* a, int* b) {int tmp *a;*a *b;*b tmp; } void adjustdown(int* a, int n, int parent) {int child parent * 2 1;while (child < n){if (child 1 < n &&am…

<Linux> 进程间通信

目录 一、进程间通信介绍 1. 进程间通信概念 2. 进程间通信目的 3. 进程间通信的本质 4. 进程间通信发展 5. 进程间通信分类 管道&#xff08;文件缓冲区&#xff09; System V IPC POSIX IPC 二、管道 1. 匿名管道 1.1 匿名管道原理 1.2 pipe系统调用 1.3 匿名管道的使用 1.4…

Leetcode 第 414 场周赛题解

Leetcode 第 414 场周赛题解 Leetcode 第 414 场周赛题解题目1&#xff1a;3280. 将日期转换为二进制表示思路代码复杂度分析 题目2&#xff1a;3281. 范围内整数的最大得分思路代码复杂度分析 题目3&#xff1a;3282. 到达数组末尾的最大得分思路代码复杂度分析 题目4&#xf…

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef 1. AOSPXRef1.1. http://aospxref.com/android-14.0.0_r2/1.2. build/envsetup.sh 2. AndroidXRef2.1. http://androidxref.com/9.0.0_r3/2.2. build/envsetup.sh 3. HELLO AndroidReferences 1. AOSPXRef http://aospx…

Go中如何找到哪里依赖了某个module,如何找到所有module的最大GoVersion

如何找到哪里依赖了某个module 举例&#xff1a;如何找到哪个模块依赖了 github.com/Shopify/toxiproxy&#xff1f; 你可以使用以下方法查找 github.com/Shopify/toxiproxy 是通过哪个依赖模块引入的&#xff1a; 1. 使用 go mod graph go mod graph 命令可以输出模块的依…

四、(JS)JS中常见的加载事件

一、文档加载监听 &#xff08;1&#xff09;抛出疑惑&#xff0c;什么是文档加载监听&#xff1f;为什么要有这个东西&#xff1f; 老样子&#xff0c;我们先讲一个场景&#xff0c;带着大家熟悉为什么会有文档加载监听&#xff0c;是来解决什么问题来着的。 我们先看下这段…

【操作系统】二、进程管理:4.死锁(银行家算法、系统安全状态、静态分配策略、资源有序分配法)

五、死锁 文章目录 五、死锁1.产生1.1产生情况1.2产生的4个必要条件 2.处理方式2.1预防死锁2.1.1破坏互斥条件2.1.2破坏请求和保持条件2.1.3破坏不可抢占条件2.1.4破坏循环等待条件 2.2避免死锁2.2.1系统安全状态❗2.2.2银行家算法 2.3检测死锁2.4解除死锁 死锁&#xff1a;资源…