技术标签: python reportlab 正则表达式 PyPDF2 Python
博客主页:https://tomcat.blog.csdn.net
博主昵称:农民工老王
主要领域:Java、Linux、K8S
期待大家的关注点赞收藏留言
我们部门偶尔加班,领导让我统计同事们的加班情况,并处理加班餐的报销工作,其中比较麻烦的一个事情是整理发票,我们公司对电子发票的要求是:
每月有20多张报销发票,平均每天加班有10多名同事,光誊写这些名字就挺耗时。如果手动操作文件的重命名,也很容易出错。我就想到用代码来解决这个问题。Java在处理Excel表格,PDF文件稍显麻烦,我就用Python作为编程语言,写了个自动化工具,要求1是文件的重命名,实现起来就比较简单,可以复制原有的发票文件,存储为所要求的文件名即可;要求2的实现是通过在电子发票PDF文件中再加一页,并在其中写入报销信息,然后就可以直接批量双面打印。
我在PyCharm中创建了项目。其中outputForPrint为双面打印的输出文件夹,outputForRename为重命名后的输出文件夹,receiptOriginal为原始发票文件夹,msyh.ttc为字体文件,receipt.xlsx为存储报销信息的表格,receiptTool.py为python脚本。
receipt.xlsx仅有sheet1工作表,内容如下表所示,备注中的金额与人员用英文分号进行分割。
日期 | 备注 |
---|---|
4月01日 | 金额-50;人员-老王,老罗 |
4月06日 | 金额-300;人员-老王,肖美女,兵哥,阿杜,老李,老胡,小毛,老荣,老罗,涛哥,杰哥,核姐 |
4月07日 | 金额-275;人员-肖美女,兵哥,阿杜,老李,老胡,小毛,老荣,老罗,涛哥,杰哥,核姐 |
4月08日 | 金额-150;人员-老王,老荣,老罗,涛哥,杰哥,核姐 |
4月09日 | 金额-250;人员-老王,肖美女,兵哥,阿杜,老李,老胡,小毛,老荣,涛哥,核姐 |
4月11日 | 金额-250;人员-老王,肖美女,兵哥,老李,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月12日 | 金额-250;人员-老王,肖美女,兵哥,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月13日 | 金额-250;人员-老王,肖美女,兵哥,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月14日 | 金额-250;人员-老王,肖美女,兵哥,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月16日 | 金额-175;人员-老王,阿杜,老荣,老罗,杰哥,核姐,老姚 |
4月18日 | 金额-225;人员-肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐 |
4月19日 | 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月20日 | 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月21日 | 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月24日 | 金额-225;人员-老王,肖美女,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚 |
4月25日 | 金额-300;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚,追风少年 |
4月26日 | 金额-275;人员-肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚,追风少年 |
4月27日 | 金额-275;人员-老王,肖美女,兵哥,老李,老荣,老罗,涛哥,杰哥,核姐,老姚,追风少年 |
4月28日 | 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,涛哥,杰哥,核姐,老姚,追风少年 |
# ------------------------------------------
# Filename : receiptTool.py
# Version : 1.1
# Date : 2022-7-15 19:50:15
# Author : 农民工老王@CSDN
# Email : [email protected]
# Website : https://blog.csdn.net/monarch91
# Description : 用于处理电子发票
# ------------------------------------------
import pandas
import PyPDF2
import os
import pathlib
import pdfplumber
import re
from shutil import copyfile
from PyPDF2 import PdfFileReader
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen.canvas import Canvas
from reportlab.pdfbase import pdfmetrics, ttfonts
outputDir = "outputForRename"
printDir = "outputForPrint"
if not pathlib.Path(outputDir).is_dir():
os.makedirs(outputDir)
if not pathlib.Path(printDir).is_dir():
os.makedirs(printDir)
pdfmetrics.registerFont(ttfonts.TTFont('msyh', 'msyh.ttc'))
receiptData = pandas.read_excel("receipt.xlsx", sheet_name="Sheet1", index_col="日期")
for index, row in receiptData.iterrows():
pdfPath = "receiptOriginal" + os.sep + str(index) + ".pdf"
if type(index) == str and pathlib.Path(pdfPath).is_file():
print("检测到%s有对应发票,正在处理。" % (index))
pdfStr = ""
with pdfplumber.open(pdfPath) as p:
page = p.pages[0]
pdfStr = page.extract_text()
fpdm = re.search(r"发票代码[::]\s?(\d+)", pdfStr).group(1)
fphm = re.search(r"发票号码[::]\s?(\d+)", pdfStr).group(1)
receiptPdf = PdfFileReader(open(pdfPath, 'rb'))
pdfSize = receiptPdf.getPage(0).mediaBox
pdfH = float(pdfSize[2])
pdfV = float(pdfSize[3])
canvas = Canvas("temp.pdf", pagesize=(pdfH, pdfV))
fontSize = 18 * pdfV / A4[1]
canvas.setFont("msyh", fontSize)
canvas.drawString(pdfH / 20, pdfV / 2 + fontSize * 1.5, index)
for i, item in enumerate(row["备注"].split(";")):
canvas.drawString(pdfH / 20, pdfV / 2 - fontSize * i * 1.5, item)
canvas.save()
pdf_merger = PyPDF2.PdfFileMerger()
pdf_merger.append(pdfPath)
pdf_merger.append("temp.pdf")
pdfOutput = open(printDir + os.sep + index + "-print.pdf", 'wb')
copyfile(pdfPath, outputDir + os.sep + index + "-" + fpdm + "-" + fphm + ".pdf")
pdf_merger.write(pdfOutput)
pdf_merger.close()
os.remove("temp.pdf")
运行后,在控制台有以下输出:
顺利实现文件重命名:
顺利生成用于双面打印的文件:
用于双面打印的文件:
如需转载,请注明本文的出处:农民工老王的程序员秘密https://blog.csdn.net/monarch91 。
Smarty的使用中,有一些麻烦的事。比如在模版可以用{$data}这样的写法,但因为很多模版一般都有它独自的javascript,所以写成了 或 [{$data} 的样子。使用标签{literal}[javascript code]{/literal}虽然是一个解决办法,当然,你也可以为所需的javascript单独写个文件引用(麻烦)。但如果javascript中需要php变量时,这就不合适
题目给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。示例:输入: [0,1,0,3,12]输出: [1,3,12,0,0]思路通过设定快指针i 和慢指针j,将不为0的数字移动到数组的前方j对应的数字如果不为0(nums[j]),则将慢指针对应的数字(nums[i])改为nums[j],然后慢指针j+1然后把之后的将慢指针之后的改为0实现public void moveZeroes(int[] nums) {
在VScode新建的HTML文档中输入!+tab键可生成HTML默认格式代码,未更改前的代码如下: Document123456789101112由于一些代码不需要使用,而每次生成后都需要删除,在这里我们修改默认的HTML代码找到VScode安装目录下的目标文件 VScode\resources\app\extensi...
注:题目:给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。示例 1:输入: Tree 1 Tree 2 1 2
axios的get方法传递对象数组问题描述解决办法问题描述使用axios发送get请求,传递参数如下格式:const params = { filter: [{ property: 'optionTypeId', operator: 'eq', value:'TYPE10' }] }发送请求后,发现请求失败,查看控制台参数为
1、LCD显示单位:帧(1)显示器上一整个画面的内容成为一个帧,整个显示器工作是一帧一帧的在显示。(2)电源实际就是以每秒种24帧的速度在播放图片。(3)帧内数据:一帧分为多行,一行分为多像素,因此一帧图像其实就是多个像素组成的矩阵。(4)帧外数据:整个视频由很多个帧构成,最终播放视频时逐个播放各个图像帧即可。2、LCD显示一帧图像的过程(1)首先把帧分为行,然后再把行分为...
上次小泽给大家介绍了9月份GitHub上star最多的java开源项目,这次我们就和大家介绍下 GitHub 上 最受欢迎的 11 个Python开源项目,看看在这些项目中,你有在用或用过哪些呢?1、Pythonhttps://github.com/TheAlgorithms/Python用Python实现的所有算法,不过创建者表示这些仅用于演示目的。Python标准库中有许多种...
本篇文章给大家带来的内容是关于php如何快速导出数据库到csv(代码实现),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。需求需要在浏览器页面,通过下载按钮将数据库全部导出到本地.方案每读一行数据库记录,echo一行到输出;实现//导出函数,参数$mycli已打开数据库的mycli对象function exportDbTable($mysqi){//首先输出头部header("Co...
展开全部以AP3010DN-AGN为例瘦模式转换为胖模式1 待AP启动完成后,从console口登录,e5a48de588b662616964757a686964616f31333433616162波特率为9600,账号默认为admin,密码为[email protected];2 登录成功后,AP默认的IP地址为169.254.1.1/16;我们可以将电脑的IP设置成同网段的IP,比如169.25...
1 使用场景在一些项目中,需要在程序中根据条件,动态生成es的index,达到整理数据的目的。例如,大数据量的系统日志,需要按天分index,这时就需要动态生成Index。2 Spel动态生成Index这里使用spring-data-elasticsearch的ElasticsearchRestTemplate操作es,版本为3.2.0。<dependency> <groupId>org.springframework.data</groupId> <
这是Nginx中变量的实现下篇,上篇可以点这里 1.初始化变量 尽管是同一个变量,但在定义和索引的时候nginx会创建两个ngx_http_variable_t结构体,然后分别存在于两个不同的容器中。一般情况下定义变量的时候该变量携带的信息更全,而索引变量时则相对少一些。 初始化变量的过程其实就是两个容器融合的过程,这个过程在nginx中对应ngx_http_vari...
一、选择题 ◎ 单选 1、蓝凤凰及其诸位女弟子通过水蛭将血输到令狐冲体内,你可以得到以下那种推 测: a、令狐冲为ab型血,蓝凤凰及其弟子为a、b、或ab型 b、令狐冲为b型血,蓝凤凰及其弟子为ab、b或o型 c、令狐冲为o型血,蓝凤凰及其弟子为a、b或o型 d、令狐冲为a型血,蓝凤凰及其弟子为ab或o型 e、以上推测都不对 ...