背景
在日常的工作中,我们不免需要面临费用报销问题,在进行费用报销时,我们需要提供费用相关的发票,并需要在报销单上填写相关的金额数据。这时我们将面临核对和计算发票金额的需求。
核对发票
如今,电子发票越来越普及,如果是纸质发票,为了方便管理和后期核对,我们也推荐将纸质发票先扫描或者拍照为电子版,再进行发票的核对的管理。
如下👇,是一个demo, 我们在 totalCommander 软件中,可以很方便的查阅我们选择的发票的内容,并根据图像来修改我们的发票文档名称。
如下👇,我们在widnow资源管理器中也一样可以很方便的选择和预览发票内容。
如下👇,我们在核对发票的时候,我们选择和浏览发票内容,将必要的发票信息体现在发票文档名称中。
按以上操作,将我们需要报销的每张发票都完成信息/金额的核对,我们将得到所有核对后的发票文档及其文档名信息。
计算发票总金额
在 totalCommander 中,我们可以很方便的调用和运行 py 脚本,来对我们已经核对过的发票文档计算其金额总和。效果如下:
脚本开发
以上是核对发票和快速计算发票总金额的一个过程和效果展示,如果你对以上过程和效果有兴趣,我们一起看一下具体的python脚本吧。
python脚本
首先, 欠需要开发用于发票金额解析和计算的python脚本。以下贴出脚本代码:
# -*- coding:UTF-8 -*-
# region 导入必要的依赖包
import os
import re # 引入 re 模块
模块名 = 'pyperclip'
try:
import pyperclip # 需要安装 pyperclip 模块,以支持粘贴板操作
except ImportError as impErr:
print(f"尝试导入 {模块名} 依赖时检测到异常:{impErr}")
print(f"尝试安装 {模块名} 模块:")
try:
os.system(f"pip install {模块名}")
except OSError as osErr:
print(f"尝试安装模块 {模块名} 时检测到异常:{osErr}")
exit(0)
else:
try:
import pyperclip
except ImportError as impErr:
print(f"再次尝试导入 {模块名} 依赖时检测到异常:{impErr}")
exit(0)
模块名 = 'DebugInfo'
try:
from DebugInfo.DebugInfo import *
except ImportError as impErr:
print(f"尝试导入 {模块名} 依赖时检测到异常:{impErr}")
print(f"尝试安装 {模块名} 模块:")
try:
os.system(f"pip install {模块名}")
except OSError as osErr:
print(f"尝试安装模块 {模块名} 时检测到异常:{osErr}")
exit(0)
else:
try:
from DebugInfo.DebugInfo import *
except ImportError as impErr:
print(f"再次尝试导入 {模块名} 依赖时检测到异常:{impErr}")
exit(0)
# endregion
# 定义一个 命令行参数类,用于解析和记录命令行参数
class 命令行参数类(入参基类):
def __init__(self):
super().__init__()
self._添加参数('srcDir', str, '指定需要处理的路径')
# region 访问器
@property
def srcDir(self) -> str:
if 'srcDir' in self._参数字典:
return self._参数字典['srcDir'].值
else:
return ''
@srcDir.setter
def srcDir(self, 值: str):
if 'srcDir' in self._参数字典:
if isinstance(值, str):
self._参数字典['srcDir'].值 = 值
# endregion
def 提取文档列表(目标路径: str = None, 画板: 打印模板 = None) -> list[str]:
"""
提取指定路径下的文档,将文档名整理成列表返回
:param 目标路径: 指定需要处理哪个路径下的文档
:param 画板: 提供打印输出的模板对象
:return: list[文档名]
"""
画板 = 画板 if isinstance(画板, 打印模板) else 打印模板()
画板.执行位置(提取文档列表)
文档列表: list[str] = []
if 目标路径:
if os.path.isdir(目标路径):
for itm in os.listdir(目标路径):
文档列表.append(itm)
else:
画板.提示调试错误('tgtDir is not a valid dir: ', 目标路径)
else:
画板.提示调试错误('tgtDir is inValid: ', 目标路径)
return 文档列表
def 金额求和(文档列表: list[str] = None, 画板: 打印模板 = None) -> float:
"""
解析指定文档名列表中的金额信息(以¥开头的数字),对这些金额进行求和,并自动复制入粘贴板
:param 文档列表: 指定需要处理的文档名列表
:param 画板: 提供打印输出的打印模板对象
:return: 计算的总金额
"""
画板 = 画板 if isinstance(画板, 打印模板) else 打印模板()
画板.执行位置(金额求和)
class 文档信息类:
def __init__(self):
self.文档名: str = ''
self.格式化的文档名: str = ''
self.金额: float or None = None
def toStr(self):
if not self.格式化的文档名:
self.格式化的文档名 = self.文档名
if self.金额 is None:
return 红底(self.格式化的文档名)
else:
return str(self.格式化的文档名)
求和: float = 0
文档信息表: list[文档信息类] = []
if 文档列表:
匹配模式 = r'¥\s*([+-]?\s*\d+\.?\d*)'
画板.准备表格('c')
画板.添加分隔行(修饰方法=红字, 适应窗口=True)
画板.添加一行('序号', '文档', '金额').修饰行(青字)
序号: int = 0
for 文档名 in 文档列表:
文档信息 = 文档信息类()
文档信息.文档名 = 文档名
序号 += 1
匹配集合 = re.findall(匹配模式, 文档名)
if 匹配集合:
try:
字串: str = 匹配集合[0]
文档信息.格式化的文档名 = 文档信息.文档名.replace(字串, 绿字(字串))
字串 = re.sub(r'\s', '', 字串)
文档信息.金额 = float(字串)
except Exception as err:
画板.提示调试错误('fail to parse ' + 匹配集合[0] + ' to float: ', err)
文档信息.金额 = None
if 文档信息.金额 is not None:
文档信息表.append(文档信息)
画板.添加一行(序号, 文档信息.格式化的文档名, 文档信息.金额)
else:
画板.添加一行(序号, 文档信息.toStr())
求和 = 0 if not 文档信息表 else sum([文档信息.金额 for 文档信息 in 文档信息表 if 文档信息.金额 is not None])
画板.添加分隔行(修饰方法=红字, 适应窗口=True)
画板.添加一行('', '', 绿字(求和))
画板.展示表格()
return 求和
if __name__ == '__main__':
画板 = 打印模板(True)
画板.执行位置(__file__)
入参 = 命令行参数类()
入参.解析入参(画板=画板.副本.缩进())
if 入参.srcDir:
画板.消息('目标路径:', 入参.srcDir)
文档列表: list[str] = 提取文档列表(目标路径=入参.srcDir, 画板=画板.副本.缩进())
if 文档列表:
求和: float = 金额求和(文档列表=文档列表, 画板=画板.副本.缩进())
求和字串: str = '{:.3f}'.format(求和)
pyperclip.copy(求和字串)
画板.消息(f'总金额 ({绿字(求和)}) 已复制')
else:
入参.展示()
画板.提示错误('names\' list is empty: ')
else:
画板.提示错误('srcDir 参数无效')
- 【命令行参数类】
【命令行参数类】主要用于处理命令行调用时的传入参数。这个类中,我们添加了一个命令行参数:srcDir,表示将要处理的发票文档所在的路径。 - 【提取文档列表】
【提取文档列表】方法用于在指定的路径下,读取所有的文档名,并整理成 list[str] 列表对象返回,以供下游处理。 - 【金额求和】
【金额求和】方法用于将指定的文档列表,识别文档名中的金额信息,并进行求和计算,然后将所求的总金额值复现到粘贴板中,最后整理并打印显示结果。
bat脚本
如下👇,有了 py 脚本,我们使用时需要以 python xxx.py --srcDir="xxxxxx" 的格式来使用, 但这样的使用方式不够人性化。
为了更方便的使用 py 脚本,我们需要更人性化的使用方式。我们需要借助 totalCommander 来实现快捷调用 py 脚本的能力,我们需要一个为此创建一个bat文档做为媒介。bat脚本如下👇:
::可以通过在total中调用此脚本,达到直接在当前窗口路径下打开cmd窗口的操作
@echo off
set srcDir=%~s1
python %~dp0计算总账.py --srcDir=%srcDir%
echo.
pause
以上脚本中,我们通过接收 totalCommander 调用时传入的路径参数,将其做为 计算总账.py 的 srcDir 参数传入 py 脚本内,从而实现对指定路径下发票文档的金额的计算。
totalCommander 配置
上文提到,我们需要借助 totalComamander 的能力来通过 bat 脚本调用 python 脚本,在totalCommander中, 我们的配置如下👇:
按照上图的步骤,我们可以在 totalCommander 中创建一个快捷键,当我们激活发票文档时,通过该快捷件可以直接调用我们的 py 脚本来进行发票金额的核算。
小结
好了,以上就是这次分享的 py 脚本协助计算发票金额的方法和脚本了。欢迎讨论。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。