快速计算发票金额

news2024/12/28 18:26:58

快速计算发票总额

背景

在日常的工作中,我们不免需要面临费用报销问题,在进行费用报销时,我们需要提供费用相关的发票,并需要在报销单上填写相关的金额数据。这时我们将面临核对和计算发票金额的需求。

核对发票

如今,电子发票越来越普及,如果是纸质发票,为了方便管理和后期核对,我们也推荐将纸质发票先扫描或者拍照为电子版,再进行发票的核对的管理。

如下👇,是一个demo, 我们在 totalCommander 软件中,可以很方便的查阅我们选择的发票的内容,并根据图像来修改我们的发票文档名称。
20231014224240

如下👇,我们在widnow资源管理器中也一样可以很方便的选择和预览发票内容。
20231014224610

如下👇,我们在核对发票的时候,我们选择和浏览发票内容,将必要的发票信息体现在发票文档名称中。
20231014224914

按以上操作,将我们需要报销的每张发票都完成信息/金额的核对,我们将得到所有核对后的发票文档及其文档名信息。

计算发票总金额

在 totalCommander 中,我们可以很方便的调用和运行 py 脚本,来对我们已经核对过的发票文档计算其金额总和。效果如下:
20231014225438

脚本开发

以上是核对发票和快速计算发票总金额的一个过程和效果展示,如果你对以上过程和效果有兴趣,我们一起看一下具体的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” 的格式来使用, 但这样的使用方式不够人性化。
20231014230748

为了更方便的使用 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中, 我们的配置如下👇:
20231014232148

按照上图的步骤,我们可以在 totalCommander 中创建一个快捷键,当我们激活发票文档时,通过该快捷件可以直接调用我们的 py 脚本来进行发票金额的核算。

小结

好了,以上就是这次分享的 py 脚本协助计算发票金额的方法和脚本了。欢迎讨论。

alComamander 的能力来通过 bat 脚本调用 python 脚本,在totalCommander中, 我们的配置如下👇:
[外链图片转存中…(img-RIVDArou-1697297449159)]

按照上图的步骤,我们可以在 totalCommander 中创建一个快捷键,当我们激活发票文档时,通过该快捷件可以直接调用我们的 py 脚本来进行发票金额的核算。

小结

好了,以上就是这次分享的 py 脚本协助计算发票金额的方法和脚本了。欢迎讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1093479.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于和声优化的BP神经网络(分类应用) - 附代码

基于和声优化的BP神经网络(分类应用) - 附代码 文章目录 基于和声优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.和声优化BP神经网络3.1 BP神经网络参数设置3.2 和声算法应用 4.测试结果:5.M…

STM32成熟变频逆变器方案

该方案是一款成熟的变频逆变器的方案,主要是把电源从直流到3相交流的转换,包含变频控制板,逆变主板,IO板,变频控制板主控是STM32F103VET6,配套软件。每一块板子都是原理图和PCB一一对应,并且配套…

函数调用:为什么会发生stack overflow?

在开发软件的过程中我们经常会遇到错误,如果你用 Google 搜过出错信息,那你多少应该都访问过Stack Overflow这个网站。作为全球最大的程序员问答网站,Stack Overflow 的名字来自于一个常见的报错,就是栈溢出(stack ove…

Python中图像相似性度量方法汇总

1. 引言 在当前到处充满着图像的世界里,测量和量化图像之间的相似性已经成为一项关键的任务。无论是图像检索、内容推荐还是视觉搜索,图像相似性方法在现代计算机视觉的应用中都发挥着关键的作用。 幸运的是,Python提供了大量的工具和库&am…

Zabbix监控系统系列之二十二:ESXi虚拟化监控

背景概述 此前写了一篇VMware虚拟化监控的文章,但它主要是针对vCenter Server而不是ESXi。 Zabbix监控系统系列之七:VMware虚拟化监控 本次自己家中组建HomeLab实验环境,因此我将对于ESXi单机环境的监控方式进行记录。 操作步骤 创建ESXi普…

独立式三相无源逆变电源设计

摘要 面对全球日趋严重的能源危机问题,可再生能源的开发和利用得到了人们的高度重视。其中辐射到地球太阳能资源是十分富饶的,绿色清洁的太阳能不会危害我们的生存环境,因而受到了人们的广泛利用。光伏发电作为可再生能源被广泛的应用&#x…

阿里云在云原生领域喜获多项 OSCAR 开源尖峰案例奖

当前,国内开源技术正逐渐在各领域落地,越来越多的企业已经或准备使用开源,优秀的开源案例可以起到领航和参考作用。为了更好地推动开源技术在中国市场的落地,鼓励企业和厂商使用开源,鼓励企业或个人进一步探索我国开源…

Leetcode 23.旋转排序数组

整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..…

crypto:rsarsa

题目 下载压缩包后得到提示文本 根据提示文本信息&#xff0c;我们知道p q e c&#xff0c;可以求出n、φ(n)、d&#xff0c;进而求出m import gmpy2p 964842302901051567659055174001042653494573763923573980064398935203985250729849139956103500916342705037010757073363…

数据结构之堆排序和前,中,后,层序遍历,链式二叉树

首先我们要知道升序我们要建小堆&#xff0c;降序建大堆&#xff0c;这与我们的大多人直觉相违背。 因为我们大多数人认为应该将堆顶的数据输出&#xff0c;但如果这样就会导致堆顶出堆以后&#xff0c;堆结构会被破坏&#xff0c;显然我们不能这样。 所有我们反其道而行&…

anzo capital昂首资本:MT4和MT5 EA测试的主要区别

MT4和MT5EA测试仪的主要区别&#xff0c;anzo capital昂首资本认为体现在以下方面&#xff1a; 首先&#xff0c;对于专业模式的测试&#xff0c;MT4所需的时间大约为30分钟&#xff0c;MT5最多需要10分钟&#xff0c;显然MT5效率更高。 在优化方面&#xff0c;MT4对优化建议…

嵌入式养成计划-41----C++ auto--lambda表达式--C++中的数据类型转换--C++标准模板库(STL)--list--C++文件操作

九十九、auto 99.1 概念 C11引入了自动类型推导&#xff0c;和Python不一样&#xff0c;C中的自动类型推导&#xff0c;需要auto关键字来引导比如 &#xff1a;auto a 1.2; 会被编译器自动识别为 a 为 double 类型 99.2 作用 auto修饰变量&#xff0c;可以自动推导变量的数…

PyQt5开发相关

代码来源&#xff1a;cxinping/PyQt5: 《PyQt5快速开发与实战》配套代码 (github.com) 《PyQt5快速开发与实战》 (1)使用气泡提示 import sys from PyQt5.QtWidgets import QWidget, QToolTip, QApplication from PyQt5.QtGui import QFontclass Winform(QWidget):def __ini…

缺少 Google API 密钥,因此 Chromium 的部分功能将无法使用

当前版本&#xff1a;Chromium 114.0.5724.0 (开发者内部版本) &#xff08;32 位&#xff09; 1 使用 chromedriver.exe 驱动打开&#xff0c;则没有&#xff0c;于是查看参数&#xff0c;发现 --test-typewebdriver。 2 将 chrome.exe 发送到桌面&#xff0c;右键--属性--目…

零代码编程:用ChatGPT批量下载podomatic播客RSS页面音频

podomatic播客上的音频&#xff0c;怎么批量下载呢&#xff1f; 以这个播客为例&#xff1a;https://nosycrow.podomatic.com/rss2.xml 右边有一个RSS Feed的黄色图标&#xff0c;点击打开&#xff1a; 可以看到所有的音频和标题&#xff1a; 查看源代码&#xff0c;音频标题…

asp.net酒店管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net酒店管理系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 asp.net 酒店管理系统1 二、功能介绍 …

2023.10.14 关于 synchronized 基本介绍

目录 synchronized 的特性 互斥 理解阻塞等待 可重入 synchronized 的使用 修饰方法 修饰代码块 synchronized 的特性 JVM 称 synchronized 为监视器锁&#xff08;monitor lock&#xff09; 互斥 synchronized 会起到互斥效果某个线程执行到某个对象的 synchronized 中…

解决:PowerDesigne找不到右边表的工具栏

下载压缩包&#xff1a; PowerDesigner16.5压缩包 https://pan.baidu.com/s/1PxGafZUb5kcqSuPnxT4zgA?pwd6nyz http://PowerDesigner16.5压缩包 提取码&#xff1a;6nyz PowerDesigne破解版 找不到右边表的工具栏&#xff1f; 问题&#xff1a;PowerDesigner 快捷工具栏…

【C语言】通讯录的简单实现

通讯录的内容 contect.h #pragma once // 包含头文件 #include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h>// 使用枚举常量定义功能 enum Function {quit, // 注意这是逗号&#xff0c;不是分号save,addition,delete,s…

TCP 协议的相关(部分)特性

TCP的报文结构 首部长度&#xff1a; 与UDP不同&#xff0c;TCP没有有描述数据的长度的变量&#xff08;UDP的是UDP长度&#xff09;&#xff0c;但有描述TCP的报头的长度&#xff0c;为什么要和UDP不同呢&#xff1f;其实是UDP的报头长度是固定的&#xff0c;而TCP的报头是“变…