报告一批批出齐分发这一步才开始按客户要的文件名改一遍、一份报告发给两个收件人、纸质件按合同寄几份、发完再回头把发放登记表补齐。手工做法是复制、改名、粘进客户文件夹再对着台账填表——名字改错一个客户收到的就是别人的报告登记表漏一行追溯时拿不出证据。为了解决这个问题Python 提供了 pathlib 和 shutil配上 openpyxl 写登记表三份表加一个原件目录读进来按每家客户的模板改名、按客户拆包顺手生成发放登记表与客服分发清单。本文按四步走配置路径与状态常量、读四份东西、按客户模板改名并挑出不能发的、写登记表与分发清单。仓库里两个 pyrun.py跑主线source/build_fixtures.py造数据自动装依赖、写日志、回读校验是外壳不逐行贴。一、卡在哪名字是客户定的记录是制度定的第三方检测是「一单客户独立走一遍」洽询、送样、收样通知、检测、报告、关账。报告出来以后这一段制度上要登记发放编号、数量、领取单位、领取人、发放日期客户那边又对文件名各有要求。两头都得满足手工做就容易出错。卡点手工做法本文做法每家客户命名要求不一样一家记一套改的时候翻记录一行命名模板 占位符改模板不改代码客户名尾巴粘着全角空格被当成两家收件人查不到客户名先压成比较键报告待审核、已作废夹在中间一起发出去状态先判挂起的不占分发件一份报告两个收件人、纸质要三份登记表只记一行按「报告 × 收件人」展开份数分方式给二、四步走第 1 步配置路径与状态常量。路径从脚本自己的位置长出来拷到别的电脑不用改。三个常量是刻意的发放日期写死不许用date.today()——隔天重跑同一批报告日期就变了跟客服手上的邮件时间对不上不能分发的状态单独列表作废件流出去是合规事故非法字符统一替换产品名里的斜杠不换连文件都建不出来。出处run.py顶部的路径与状态常量区from pathlib import Path这类顶层 import 都在文件顶部。ROOT Path(__file__).resolve().parent RAW_DIR ROOT / 01_raw_data OUT_DIR ROOT / 02_output TPL_DIR ROOT / source / templates LOG_FILE ROOT / source / run_log.txt ORIG_DIR RAW_DIR / 报告原件 REPORT_CSV RAW_DIR / 报告台账.csv NAMING_CSV RAW_DIR / 客户命名规则.csv RECIPIENT_CSV RAW_DIR / 客户收件人.csv TPL_XLSX TPL_DIR / 报告发放登记表.xlsx LEDGER_XLSX OUT_DIR / 发放登记台账.xlsx MANIFEST_CSV OUT_DIR / 客户分发清单.csv PACK_DIR OUT_DIR / 报告分发 # 发放日期登记表上「发放日期」这一栏填哪天得是定的。 # **不许用 date.today()**——隔天重跑同一批报告的发放日期就变了跟客服手上的邮件时间对不上。 SEND_DAY date(2026, 9, 25) # 不对外分发的报告状态。作废报告的电子件流出去是合规事故宁可挂起也不改名。 BLOCK_STATUS {待审核: 报告未出具不能分发, 已作废: 报告已作废不对外分发} # 文件名里不许出现的字符。产品名、委托单号里都可能带斜杠不换掉连文件都建不出来。 ILLEGAL_RE re.compile(r[\\/:*?|\r\n\t]) LEFTOVER_RE re.compile(r\{[^}]*\}) # 拼完还剩花括号 模板里有不认识的字段 DATE_FMTS (%Y-%m-%d, %Y/%m/%d, %Y.%m.%d, %Y%m%d) DATE_FMT yyyy-mm-dd # 写进 Excel 的日期格要顺手设格式否则显示成序列号第 2 步读四份东西含归堆。台账一行一份报告命名规则按客户名收成字典收件人收成「客户 → 收件人列表」——一家客户可能有两个收件人。读 CSV 有两个小动作必须做第一列为空的行整行跳过表尾合计行、说明行第一列都是空的说明文字写进第一列就多出一份报告原件编号按字符串处理、不做int()老系统留下的编号是0000122转成整数就变122跟台账永远对不上。出处run.py的read_csv_rows()读数据一节最前面、read_reports()/read_naming()/read_recipients()紧跟其后与scan_originals()读数据一节末尾。def read_csv_rows(path): 读 CSV。第一列为空的行一律跳过——表尾的合计行、说明行第一列都是空的 说明文字要是写进第一列就会被当成一份报告混进分发清单。 with open(path, r, encodingutf-8-sig, newline) as f: rows list(csv.reader(f)) header [clean(x) for x in rows[0]] out [] for raw in rows[1:]: if not raw or not clean(raw[0]): continue out.append({header[i]: clean(raw[i]) if i len(raw) else for i in range(len(header))}) return outdef scan_originals(): 扫报告原件目录用文件名去扩展名当报告编号。 文件名一律按字符串处理**不做 int 转换**——老系统留下的编号是 0000122 转成整数就变成 122跟台账永远对不上人还看不出是哪儿错了。 found {} for path in sorted(ORIG_DIR.glob(*.pdf)): found[path.stem] path return found第 3 步判定能不能发再拼文件名。判定顺序就是业务顺序一步都错不得动作为什么这么写先判状态再判别的作废件不管名字对不对都不能发顺序反了挂起理由会张冠李戴拼完再查一遍残留的花括号客户模板里字段名写错一个字带花括号的文件名就发给客户了撞名两份都挂起只挂后一份前一份照样发出去两家客户的报告就混了出处check_report()分发判定一节开头、make_filename()紧跟其后、plan()末段。def check_report(rep, naming, recipients, originals): 判定顺序就是业务顺序报告没出 → 不说名字的事客户没登记收件人 → 不判原件 原件不在 → 不拼名字。 顺序反了挂起理由就会张冠李戴一份还没审核的报告被标成「原件缺失」 客服拿着错理由去补资料补完还是发不出去。 if rep[状态] in BLOCK_STATUS: return 挂起, rep[状态], BLOCK_STATUS[rep[状态]] rule naming.get(cust_key(rep[客户名称])) if rule is None: return 挂起, 客户命名规则缺失, 台账里的客户在命名规则表里查不到不知道按谁的规矩改名 if not recipients.get(cust_key(rep[客户名称])): return 挂起, 未登记收件人, 客户收件人表里没有这一家报告不知道发给谁 if clean(rep[报告编号]) not in originals: return 挂起, 原件缺失, 报告原件目录里找不到这份报告改不了名 if rep[报告日期] is None: return 挂起, 报告日期认不出, 日期列写法不在支持列表里不能用它拼文件名 return 正常, , def make_filename(rep, rule): 按客户给的模板拼文件名先换占位符再换非法字符最后统一加 .pdf。 拼完必须回头查一遍还有没有没换掉的花括号——客户把字段名写错一个字 {产品名}不检查就会把一个带花括号的文件名发给客户。 name rule[模板] for key in (报告编号, 委托单号, 产品名称): name name.replace({%s} % key, clean(rep[key])) name name.replace({客户}, clean(rule[写客户]) or clean(rep[客户名称])) name name.replace({报告日期}, rep[报告日期].strftime(rule[日期写法])) if LEFTOVER_RE.search(name): raise ValueError(f模板里有不认识的占位符{LEFTOVER_RE.findall(name)}) return ILLEGAL_RE.sub(-, name).strip() .pdfdup {k for k, group in keys.items() if len(group) 1} if dup: kept [] for item in items: if item[键] in dup: held.append({报告编号: item[rep][报告编号], 客户名称: item[rep][客户名称], 问题: 命名撞名, 说明: f同一家客户下另有报告算出同名文件 {item[文件名]} 两份都挂起先跟客户确认改名规则}) else: kept.append(item) items kept return items, held第 4 步出分发件、写登记表。分发件按客户建目录、把原件复制过去登记表按「报告 × 收件人」一行份数按发放方式给——纸质按合同份数电子只记一份多记会让台账数量虚高。最后给客服一份分发清单照着发就行。登记表往模板里填表头行按栏目名反查模板上加标题行、改列顺序都不影响。出处pack()输出一节最前面、ledger_rows()紧跟其后、write_manifest()输出一节末尾。def pack(items, originals): 按客户建目录、把原件**复制**成分发件。 复制不是移动原件是归档凭证动它等于动了可追溯性分发件只是副本 目录每次重跑先清空免得上一版留下的文件被当成这一版发出去。 if PACK_DIR.exists(): shutil.rmtree(PACK_DIR) rows [] for item in items: cust_dir PACK_DIR / ILLEGAL_RE.sub(-, clean(item[rep][客户名称])) cust_dir.mkdir(parentsTrue, exist_okTrue) shutil.copy2(originals[clean(item[rep][报告编号])], cust_dir / item[文件名]) rows.append(item) return rowsdef ledger_rows(items): 发放登记表按「报告 × 收件人」一行——制度里的登记表记的是**每一次发放动作** 一份报告发给两个人就是两次发放。 份数按发放方式给纸质按委托约定的份数台账里的报告份数电子只记 1 份。 电子件多记份数会让台账上的数量虚高对不上客户实际拿到的纸。 rows [] for item in items: rep item[rep] for rec in item[收件人]: paper rec[发放方式] 纸质 rows.append([rep[报告编号], rep[产品名称], rep[报告份数] if paper else 1, rep[客户名称], rec[收件人], rec[电话], rec[发放方式], SEND_DAY, item[文件名], , f纸质件按 {rep[报告份数]} 份寄出 if paper else 电子件加密发送]) return rowsdef write_manifest(items): 给客服一份分发清单哪个收件人、要发哪几份、邮箱是哪个照着发就行。 groups {} for item in items: for rec in item[收件人]: key (item[rep][客户名称], rec[收件人], rec[发放方式], rec[邮箱]) groups.setdefault(key, []).append(item[文件名]) with open(MANIFEST_CSV, w, encodingutf-8-sig, newline) as f: w csv.writer(f) w.writerow([客户名称, 收件人, 电子邮箱, 发放方式, 报告数, 分发文件, 建议邮件主题]) for (cust, who, way, mail), files in groups.items(): w.writerow([cust, who, mail, way, len(files), .join(sorted(files)), f【检测报告】{cust} 报告已出具{len(files)} 份]) return groups三、踩过的坑都在这份数据上复现过坑现象怎么改判定顺序排错没登记收件人的客户全被挂「未登记收件人」撞名分支根本没跑到等于没测按业务顺序排状态 → 命名规则 → 收件人 → 原件 → 日期编号转成整数0000122变122跟台账对不上编号全程当字符串date写进 Excel、读回是datetime回读校验假失败比之前先.date()表尾说明文字放进第一列台账上多出一份不存在的报告说明行第一列留空分发件用移动而不是复制原件目录被搬空归档凭证没了复制重跑先清空分发目录总结这段活的难点不是改名是两边都不许错客户要的文件名得对得上制度要的发放记录一行不能少。所以脚本分三件事——按客户模板改名、把不能发的挑出来挂起、把登记表和分发清单一起生成。判定顺序按业务排挂起理由才指向该补的东西。配套示例可复跑台账 11 行 → 分发件 4 份 → 登记 6 行 → 挂起 7 份回读校验 26 项全过。完整源码本文配套的可运行示例已开源把01_raw_data/里的表换成自己机构的克隆下来直接复跑huang_jianhua0101/examples - Gitee.com关于我在实验室一线待了 13 年9 年制药 4 年第三方检测做的一直是实验室信息化。做过 STARLIMS 的甲方 PM——一期、二期两轮上线都由我主导招标到 3Q 验证到验收全流程也在系统上自己做过二次开发——把纸质的账号申请流程搬到线上跑在 STARLIMS 之前还有 6 年多 CS 架构 LIMS 的使用与运维经验其中一段经 Citrix 远程接入。现在专做实验室里那些重复劳动报表自动生成、仪器数据对接、合规文档批量处理。本科物理化学、硕士计算机化学既听得懂 QA 说的变更控制也看得懂仪器导出的原始数据长什么样。SOP、偏差、OOS、样本流转这些词不用你解释。现在主要做这几类- 检验报告与台账批量生成模板不动数据自动填格式一步不错- 仪器数据对接色谱、光谱、酶标仪导出的原始文件解析、清洗、入库、转成报表- 合规文档自动化SOP、验证方案、批记录这类重复文档的批量生成与核对- 数据完整性核查按 ALCOA 逐条核对原始数据与记录是否对得上手里有这类活儿卡着或者只是想问问能不能自动化都欢迎评论区聊先把问题说清楚再谈怎么做。
企业数字化 ERP 产品动态
相关推荐
Agent工具的投入产出比怎么算才合理?用TaoToken统一Key拆解Token计价到业务交付的ROI账本 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:41:49
Manus全栈式智能体生产力革命:TaoToken统一API接入与配置实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:41:49
防评测作弊——当“所有模型都在作弊”,如何为Agent判一张干净的卷 防评测作弊——当“所有模型都在作弊”,如何为Agent判一张干净的卷期数:智能体评测卷 第8期
作者:Valhalla Matrix 治理实验室
原创声明:本文为原创技术博客,基于 Valhalla 工程实践编写。
论文锚点:Rewar… · 2026/9/27 22:41:49
OpenRouter工具注册中心treg:CLI异常的根源与诊断指南 1. “treg”不是拼写错误,而是OpenRouter生态中一个被严重低估的CLI工具代号最近在翻OpenRouter官方文档的边缘角落时,我偶然看到一行不起眼的注释:“tregis the internal registry CLI for agent tool discovery and catalog sync”。当时没… · 2026/9/27 23:56:27
合肥建设网站制作哪个好? 3个免费工具避坑指南 合肥建设网站制作哪个好? 3个免费工具避坑指南 别被那些花里胡哨的“一键生成”忽悠了,模板网站看着快,实则丑得让人想砸键盘,根本撑不起你的品牌调性。很多合肥的老总问我, 合肥建设网站制作哪个好 ,是不是找个大厂就稳了?… · 2026/9/27 23:56:27
仓库数字孪生进阶:用Antigravity与Blender MCP驱动实时数据可视化 上一期我用 Antigravity 加 Blender MCP 搭起了一个仓库数字模型的骨架:货架、托盘、输送线、AGV 小车都有了,能转到任何一个视角,也能导出几张渲染图。但那离“数字孪生”还差得很远。很多朋友跑到这一步就卡住了:模型是有了&… · 2026/9/27 23:56:27
Antigravity+Blender+MCP:自然语言驱动数字孪生仓储建模实战 1. Antigravity Blender MCP:这套组合到底解决了数字孪生里的什么难题在仓储物流这个行业摸爬滚打几年之后,我越来越觉得,数字孪生不该只是大厂PPT里的漂亮名词。一个真实的智慧仓储数字孪生,背后是成千上万的货架、托盘、AGV路… · 2026/9/27 23:56:20
华硕AMD笔记本超频真相:不是调频率,而是调散热与固件策略 1. 华硕AMD笔记本超频的现实边界:先搞清“能超什么、为什么难超、超了真有用吗”华硕AMD笔记本超频软件——这个搜索词背后,藏着大量用户的真实困惑:天选系列、幻14/幻16、无畏系列的用户反复在论坛提问,“R9-7940HS能超频吗&… · 2026/9/27 23:56:20
实战KNN:从量化交易到工业异常检测的工程化落地 1. 这不是教科书里的KNN,是我在量化策略回测、工业传感器异常识别、电商推荐冷启动中反复打磨出来的实战版KNN——K-近邻算法,听起来像机器学习入门课上那个“最朴素”的模型,但如果你真把它当成一个玩具,那在实际项目里摔的跟头会… · 2026/9/27 23:56:14
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01