news 2026/8/2 18:31:45

单笔超1万自动拆分:我用Python写了个Excel批量处理工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单笔超1万自动拆分:我用Python写了个Excel批量处理工具

今天给大家分享一个开箱即用的Python工具:自动读取Excel单据,按单价将大额记录拆分为多行,每行金额尽量接近阈值且不超限,输出结果自带专业格式美化,十几秒就能搞定原本大半天的手工活。

做财务、开票或者供应链的朋友,大概率都遇到过这个经典痛点:
公司规定单笔单据、发票金额不能超过10000元,但业务数据里经常出现一笔几十件、总金额数万的记录。

手动拆分?算每行数量、核对金额,几十行原始数据能拆出上百行明细,既耗时间又容易算错,反复核对更是折磨人。

一、拆分规则

先明确通用的拆分逻辑,阈值可根据自身需求调整:

  • 单笔总金额 ≤ 10000元:不拆分,原样保留
  • 单笔总金额 > 10000元:按固定单价拆分为多行
  • 每行金额尽可能接近10000元(不超过阈值),最后一行放置剩余数量
  • 拆分前后总数量、总金额完全一致,数据零误差

二、核心实现拆解

整个工具分为三层:拆分算法、数据批量处理、Excel格式美化。

1. 核心拆分算法

拆分的本质是一道基础算术题:已知总数量、单价、金额上限,求单行最大数量与拆分行数。

核心逻辑步骤:

  1. 计算单笔总金额,未超过阈值直接返回原数据
  2. 用「阈值 ÷ 单价」向下取整,得到单行可放置的最大数量
  3. 总数量除以单行最大数量,得到完整行数与剩余数量
  4. 拼接完整行与余数行,形成最终拆分结果

额外处理了边界场景:若单件单价本身高于阈值,无法拆分则直接保留原行。

2. Excel批量读写

基于pandas实现全量数据处理:

  • 读取原始Excel表格,支持指定工作表
  • 逐行调用拆分算法,生成明细行
  • 保留原始日期、名称、单价等字段,仅更新数量与金额
  • 自动兼容文件已存在、不存在两种场景,避免重复运行报错

3. 自动格式美化

很多脚本导出的Excel都是无格式的“裸数据”,还需要手动排版。这个工具直接通过openpyxl完成美化:

  • 深色表头搭配白色加粗字体,层级清晰
  • 全表单元格居中对齐,统一细边框
  • 预设合理列宽,无需手动调整
  • 冻结首行,滚动查看数据时表头始终可见

导出的结果文件可直接用于汇报、发同事,无需二次加工。

三、完整代码与使用方法

1. 安装依赖

运行前先安装所需第三方库:

pipinstallpandas openpyxl

2. 配置说明

修改代码开头CONFIG字典即可适配你的表格:

  • input_path:原始Excel文件路径
  • output_path:拆分结果输出路径
  • *_col:对应你表格中的列名
  • threshold:拆分金额阈值,默认10000,可自由调整

3. 完整可运行代码

#!/usr/bin/env python3# -*- coding: utf-8 -*-""" 金额按单价拆分工具 规则:金额 ≥ 阈值时,按单价拆分为多行, 每行金额尽量接近阈值(不超过),最后一行是余数。 """importmathimportosimportpandasaspdfromopenpyxlimportload_workbookfromopenpyxl.stylesimportFont,Alignment,PatternFill,Border,Side# ===================== 配置区 =====================CONFIG={"input_path":"sample.xlsx","output_path":"result.xlsx","date_col":"日期","name_col":"名称","qty_col":"数量","price_col":"单价","amount_col":"金额","threshold":10000,# 大于此金额才拆分"sheet_name":0,# 读取第几个工作表,从0开始}# ==================================================defsplit_row(qty,price,threshold=10000):""" 把 (数量, 单价) 拆成 [(数量, 金额), ...] 规则:每行金额尽量接近 threshold(不超过),最后一行是余数 """total_amount=qty*price# 不超过阈值 → 不拆iftotal_amount<=threshold:return[(qty,round(total_amount,2))]# 找每行最大数量:floor(threshold / price)per_qty=math.floor(threshold/price)# 如果单价 > 阈值,单行就超了 → 只能拆成1行ifper_qty<1:return[(qty,round(total_amount,2))]# 完整份数 + 余数full_parts=qty//per_qty remainder=qty%per_qty result=[]for_inrange(int(full_parts)):result.append((per_qty,round(per_qty*price,2)))ifremainder>0:result.append((int(remainder),round(remainder*price,2)))returnresultdefprocess(input_path,date_col,name_col,qty_col,price_col,amount_col,threshold=10000,sheet_name=0):"""读取Excel并逐行拆分"""df=pd.read_excel(input_path,sheet_name=sheet_name)rows=[]for_,rindf.iterrows():qty=r[qty_col]price=r[price_col]splits=split_row(qty,price,threshold)fornew_qty,new_amountinsplits:rows.append({date_col:r[date_col],name_col:r[name_col],qty_col:new_qty,price_col:price,amount_col:new_amount,})returnpd.DataFrame(rows)defsave(result_df,output_path,cols):"""保存结果并美化格式"""ifnotos.path.exists(output_path):withpd.ExcelWriter(output_path,engine="openpyxl")aswriter:result_df.to_excel(writer,sheet_name="拆分结果",index=False)else:withpd.ExcelWriter(output_path,engine="openpyxl",mode="a",if_sheet_exists="replace")aswriter:result_df.to_excel(writer,sheet_name="拆分结果",index=False)_beautify(output_path,"拆分结果",cols)def_beautify(file_path,sheet_name,cols):"""Excel样式美化"""wb=load_workbook(file_path)ws=wb[sheet_name]# 表头样式header_font=Font(name="微软雅黑",size=11,bold=True,color="FFFFFF")header_fill=PatternFill(start_color="2C3E50",end_color="2C3E50",fill_type="solid")thin_border=Border(left=Side(style="thin"),right=Side(style="thin"),top=Side(style="thin"),bottom=Side(style="thin"))center_align=Alignment(horizontal="center",vertical="center")# 应用表头样式forcolinrange(1,ws.max_column+1):cell=ws.cell(row=1,column=col)cell.font=header_font cell.fill=header_fill cell.alignment=center_align cell.border=thin_border# 应用内容样式forrinrange(2,ws.max_row+1):forcinrange(1,ws.max_column+1):cell=ws.cell(row=r,column=c)cell.alignment=center_align cell.border=thin_border# 预设列宽widths={"A":14,"B":20,"C":10,"D":10,"E":12}forcol_letter,winwidths.items():ws.column_dimensions[col_letter].width=w ws.freeze_panes="A2"wb.save(file_path)if__name__=="__main__":print("="*60)print(" 金额拆分工具")print("="*60)print(f" 输入文件:{CONFIG['input_path']}")print(f" 拆分阈值:{CONFIG['threshold']}元")print()cols=[CONFIG["date_col"],CONFIG["name_col"],CONFIG["qty_col"],CONFIG["price_col"],CONFIG["amount_col"]]# 执行拆分result=process(CONFIG["input_path"],CONFIG["date_col"],CONFIG["name_col"],CONFIG["qty_col"],CONFIG["price_col"],CONFIG["amount_col"],CONFIG["threshold"],CONFIG["sheet_name"],)# 保存结果save(result,CONFIG["output_path"],cols)# 校验结果threshold=CONFIG["threshold"]max_amt=result[CONFIG["amount_col"]].max()print(f" 原始行数 → 拆分后{len(result)}行")print(f" 最大单行金额:{max_amt}元 (阈值{threshold}元)")status="全部符合阈值要求"ifmax_amt<=thresholdelse"存在超阈值行"print(f" 校验状态:{status}")print()# 按名称分组打印明细print(" 拆分详情:")forname,subinresult.groupby(CONFIG["name_col"]):total_amt=sub[CONFIG["amount_col"]].sum()total_qty=sub[CONFIG["qty_col"]].sum()rows=len(sub)print(f"{name}:{rows}行,{int(total_qty)}件, 合计{total_amt:.2f}元")for_,rinsub.iterrows():print(f" └─{r[CONFIG['qty_col']]:>4}×{r[CONFIG['price_col']]:>6.2f}={r[CONFIG['amount_col']]:>8.2f}")print(f"\n结果已写入:{CONFIG['output_path']}→「拆分结果」工作表")

四、运行效果

脚本运行后,控制台会输出完整的校验信息:

  • 拆分前后行数对比
  • 最大单行金额校验,确认是否全部符合阈值要求
  • 按商品分组的明细清单,每行数量、单价、金额清晰展示

相当于自动完成了数据核对,不用再手动求和校验总数。

这个工具逻辑不复杂,但解决的是非常高频的办公痛点。把重复、机械的拆分核对工作交给代码,既能提升效率,也能避免人工计算的失误。

你可以根据自己的业务需求继续扩展:比如支持多sheet批量处理、增加汇总统计、对接开票系统直接生成发票明细等等。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/2 18:31:43

Hyper Browser 2.0:基于WebDav实现浏览器环境便携化与跨设备同步

这次我们来看一个名为 Hyper Browser 2.0 的项目。它不是一个AI模型&#xff0c;而是一个集成了启动器、WebDav同步和浏览器插件功能的桌面效率工具。简单来说&#xff0c;它试图解决多设备、多浏览器环境下书签、扩展、配置同步的痛点&#xff0c;让你在Windows、macOS或Linux…

作者头像 李华
网站建设 2026/8/2 18:29:02

【HR与算法工程师必读】:为什么你的AI流失预警模型上线后AUC暴跌37%?——基于127家企业的模型衰减实证分析

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;AI流失预警模型的业务价值与失效危机 在数字化运营深度演进的今天&#xff0c;AI驱动的客户流失预警模型已成为企业精细化运营的核心基础设施。它不再仅是后台算法模块&#xff0c;而是直接关联营收稳定性、营…

作者头像 李华
网站建设 2026/8/2 18:25:55

【单片机毕设案例分享】单片机 OLED 显示水质浊度温度预警设备设计与实现 基于单片机的便携式水体浊度温度检测报警装置开发(021601)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于单片机&#xff0c;STM32单片机&#xff0c;51单片机&#xff0c;J…

作者头像 李华
网站建设 2026/8/2 18:18:30

MemcardRex终极指南:5步掌握PS1记忆卡编辑与管理

MemcardRex终极指南&#xff1a;5步掌握PS1记忆卡编辑与管理 【免费下载链接】memcardrex Advanced PlayStation 1 Memory Card editor 项目地址: https://gitcode.com/gh_mirrors/me/memcardrex 还在为PS1游戏存档的管理而烦恼吗&#xff1f;MemcardRex是一款专业的PS1…

作者头像 李华
网站建设 2026/8/2 18:18:28

基于YOLO的舰船检测系统:从模型训练到网页部署全流程详解

1. 项目概述&#xff1a;从“看见”到“认知”的跨越在海洋监测、港口管理、海事安全乃至国防领域&#xff0c;舰船目标的自动检测与识别一直是一项核心且富有挑战性的任务。传统方法依赖雷达、AIS&#xff08;自动识别系统&#xff09;或人工瞭望&#xff0c;各有局限&#xf…

作者头像 李华
网站建设 2026/8/2 18:15:55

XIAO nRF52840 NFC标签模拟实战:从原理到动态应用开发

1. 项目概述&#xff1a;为什么要在XIAO nRF52840上玩NFC&#xff1f; 如果你手头有一块Seeed Studio XIAO nRF52840&#xff08;或者带传感器的Sense版本&#xff09;&#xff0c;除了用它做蓝牙项目、跑TinyML&#xff0c;有没有想过它内置的NFC功能能玩出什么花样&#xff1…

作者头像 李华