从 Excel 营业流水到可验证测试订单:测试数据导入工具工程复盘

Engineering Case Study · RCA · Postmortem · Excel Import · Test Data · MySQL

**脱敏说明:**本文已替换真实小程序、门店、手机号、订单号、数据库连接和业务金额;保留真实的数据关系、算法、故障原因与修复逻辑。

一、背景:需求不是"导 Excel",而是"把营业流水变成可信的历史测试订单"

最初需求是:给定某天的营业额,自动生成一组完整订单数据。随着实际样本加入,需求逐步收敛为:Excel 每一行对应一笔历史测试订单;工具根据选中的测试门店,从当前上架商品中组合出至少 3 个不同菜品,并通过优惠金额和小额退款把订单净营业额精确调整到 Excel 金额。

对于宴席类记录,Excel 备注中可能出现"12 桌""40 桌"等信息。工具将整行作为一笔订单,但商品明细数量按桌数放大,例如 5 个菜、12 桌,则每种菜数量为 12。

图 1:Excel 测试订单导入工具整体架构

二、先把金额口径说清楚

这一步非常关键。最容易出错的是把 discount_fee 重复减一次。最终确认的金额关系是:

复制代码
order_total   = 菜品原价合计
discount_fee = 优惠金额
total        = 实际支付金额 = order_total - discount_fee
refund_fee   = 已退款金额

实际营业额
= total - refund_fee
= order_total - discount_fee - refund_fee

因此对账不能写成 total - discount_fee - refund_fee,否则优惠金额会被重复扣减。

图 2:单笔订单金额求解过程

三、数据模型与写入边界

图 3:数据模型与表关系

工具读取小程序、门店、商品和 SKU 作为基础资料;实际写入只保留和历史样本对齐的订单主表 + 订单商品明细。一开始曾计划额外写生命周期和操作日志,但在拿到真实历史数据链后,发现目标样本中需要对齐的核心节点只有订单和明细,因此主动缩小写入范围。

表/实体 职责 操作
jy_mch 小程序/企业主体 只读,用于模糊定位
jy_merchant 门店 只读,用于选择测试门店
jy_merchant_goods 商品主数据 只读,筛选正常且上架商品
jy_merchant_goods_sku 商品规格与价格 只读,生成订单商品快照
jy_order 订单主表 写入,每个 Excel 数据行一笔
jy_order_detail 订单商品快照 写入,一单多条明细

图 4:明确的写入/不写入边界

工具不会修改库存、会员余额、积分、商户资金,不会写 Redis,不会调用真实微信支付,不会触发 MQ、打印或第三方配送。这样做的目的,是生成历史测试数据,而不是重演一遍真实交易副作用。

四、为什么最终选择 Python 工具,而不是纯 SQL

SQL 很适合固定映射,但不适合处理动态 Excel、随机菜品组合、金额求解、宴席桌数、重试策略、预览和回滚。Python 更适合把"输入数据解析 → 订单规划 → 金额精确求解 → 事务写入 → 对账"组织成一个可测试的工作流。

金额统一转换成"分"进行整数运算,避免浮点误差。每笔订单先选至少 3 个不同商品,再逐步增加商品或数量,使原价合计 G 不小于目标金额 T,然后利用折扣和极小退款把净额精确拉回 T。

五、门店选择:不要求用户手抄 merchant_id

为了降低选错测试门店的风险,工具增加了模糊搜索:输入小程序名称、门店名称或 merchant_id 的部分内容,查询后展示匹配的小程序及其门店、营业状态和上架商品数量,用户人工选择并二次确认。

这样既避免把生产 ID 写死在工具里,也让同一小程序多门店场景可控。

六、Excel 解析为什么必须"像读报表",而不是"像读数据库表"

真实 Excel 并不稳定:表头不一定在第一行,列顺序会变化,可能存在多个季度 Sheet、空白 Sheet、备注跨列、宴席桌数,以及页尾合计。

输入变化 处理策略
列顺序变化 按表头名称识别,不按列下标
表头名称变化 支持"日期/下单日期""金额/营业金额(元)""桌数"等别名
备注跨多个空表头列 连续内容合并为备注
多 Sheet 合并所有有效工作表
空白 Sheet 自动忽略
页尾合计 日期为空且属于汇总行时跳过,不当订单
宴席备注 从备注/桌数字段识别桌数,明细数量按桌数放大
CSV/TSV 与 Excel 使用统一规范化模型

七、执行流程:Preview First

图 5:导入执行时序

"导入 Excel"不等于"立即写库"。工具先解析文件、生成订单计划和金额方案,再展示订单数量、营业额、折扣、退款、菜品组合等预览;只有人工确认后才开启数据库事务写入。任何一条主表或明细写入失败,整个批次回滚。

八、历史样本对齐:为什么从 4 张表收缩到 2 张表

Symptoms

最初方案准备写入 jy_order、jy_order_detail、生命周期、操作日志四张表。

Investigation

拿真实历史订单的数据链与查询结果对齐后,确认目标测试场景需要模拟的是历史订单主数据和商品快照,并不需要真的重演支付、接单、配送、积分、流水等生产业务链。

Root Cause

第一版设计把"完整生产下单链"与"测试数据要满足的查询链"混为一谈,导致写入范围过大。

Resolution

最终只写 jy_order 和 jy_order_detail。固定对齐历史样本的核心状态,如已完成、堂食、已支付状态等;但不伪造真实微信 transaction_id,不调用真实支付。

Lessons Learned

造测试数据最重要的不是"写得越多越真实",而是先明确目标页面/查询到底依赖哪些数据节点,只写足够支撑目标验证的最小集合。

九、detail_hash:做到唯一,但没有声称"完全复刻"

当前工具会生成 40 位 SHA-1 并写入 jy_order.detail_hash,用途主要是保证测试订单唯一、避免冲突。但它没有完全复刻生产下单链。

来源 算法
工具当前实现 SHA1(batch_id + order_id + Excel 行号 + 金额 + SKU/数量)
普通新版下单 SHA1(goods_detail 原始 JSON + 秒级时间戳 + member_id)
桌台点单 SHA1(goods_detail 原始 JSON + 秒级时间戳 + table_id)
某些历史样本 出现非 SHA-1 的十进制值,可能来自旧版本/其他导入路径

因此当前 detail_hash 的设计结论是:满足唯一性,不保证语义复刻。如果后续有业务逻辑依赖它的具体生成规则,需要先确定要模拟的真实下单入口再调整。

十、Troubleshooting:真实 Excel 为什么导入失败

图 6:合计行误解析的 RCA

Symptoms

真实工作簿导入报错。文件包含多个季度工作表,其中页尾有合计金额行;这些行金额有值,但日期为空。

Investigation

逐 Sheet 检查后发现,解析器把"金额非空"当成了足够强的订单判定条件,因此把季度合计当成订单。另一个工作表为空白,也需要自动忽略。

Root Cause

Excel 是给人看的报表,不是严格的数据库数据集。汇总行、标题行、空白行、跨 Sheet 都属于报表语义;第一版解析器对"订单行"的业务约束不够严格。

Resolution

增加订单行判定:必须存在有效日期;自动跳过合计行与空白 Sheet;合并有效工作表;继续保持按表头名称识别,不依赖固定列顺序。

Verification

修复后真实工作簿成功解析 1,132 笔订单,其中 18 笔宴席,最大宴席桌数 40;11 项自动测试全部通过。公开文档不展示真实总营业金额。

Lessons Learned

Excel 导入工具一定要把"格式兼容"当成核心功能,而不是边角逻辑。测试数据不能只覆盖标准模板,必须主动构造合计行、乱序列、多 Sheet、空 Sheet、别名表头等异常样本。

十一、数据库配置安全

工具支持保存数据库配置,但密码不会明文落盘。沿用同目录其他工具的方式,使用 Windows DPAPI 加密后写入本地 config.json;启动时自动解密。密文与当前 Windows 用户/机器绑定,复制到其他环境通常无法直接解密。

DPAPI 解决的是"本机配置文件明文密码"问题,不等于凭证治理完成。正式环境仍应优先使用测试库账号、最小权限和网络隔离。

十二、关键验证规则

复制代码
批次级:
Σ(total - refund_fee) == Excel 金额合计

订单级:
order_total - discount_fee == total
total - refund_fee == Excel 当前行金额
discount_fee / order_total <= 20%

明细级:
每单不同 goods_id >= 3
goods_id / sku_id 必须属于所选门店
订单明细总额与订单级金额口径一致

事务级:
任一 order 或 order_detail 写入失败 → 整批回滚

对于宴席订单,还需要验证桌数展开是否正确:例如桌数为 N,则选中的每种宴席菜品数量按 N 生成。

十三、测试演进

阶段 测试状态
固定示例数据 4 项自动测试;示例 16 笔订单金额可精确对齐
收缩写入表范围 5 项测试,验证只写 order/detail
乱序列 / 灵活表头 7 项测试
DPAPI 配置保存 9 项测试 + GUI 启动检查
真实多 Sheet Excel + 合计行 11 项测试;1,132 笔实测解析成功

十四、方案取舍

方案 优点 问题 结论
调用真实下单接口批量造单 业务链最完整 会扣库存、触发打印/Redis/支付/流水,历史时间也不自然 放弃
纯 SQL 随机生成 实现简单 动态 Excel、菜品组合、金额求解和回滚难维护 放弃
Python 直接生成测试订单 可预览、可测试、可精确金额求解 需要自行维护字段语义 采用
写完整生产链所有表 "看起来真实" 副作用大、风险高、与目标查询无关 放弃
最小写入 order + detail 风险可控、对齐历史查询 部分依赖汇总表的页面需要另行重算 采用

十五、已知限制与后续优化

优先级 优化项 原因
P0 增加异常行报告 不要只跳过,需告诉用户哪行因日期/金额/格式被忽略
P0 提供工作表勾选 支持只导入指定季度/月份,避免一次性导入全部
P1 导入后自动生成 rollback.sql / validation.sql 增强可回滚和核账能力
P1 批次标识与审计 明确哪些订单由工具生成,便于清理
P1 汇总表重算入口 如果目标页面依赖日营业额汇总表,可按批次重算而不是伪造业务链
P2 detail_hash 策略可选 按目标下单链选择"唯一模式 / 严格复刻模式"
P2 大文件分批事务 数千行以上避免一个超大事务长期持锁

十六、总结

这次工作的本质不是"Excel 导 MySQL",而是把一份非结构化程度较高的营业流水报表,转换成满足业务查询口径、金额严格守恒、写入范围可控、可以预览和回滚的测试订单数据。

整个过程里最有价值的几个转折是:先纠正金额公式;再从真实历史链反推最小写表范围;把 Excel 解析改成表头语义驱动;最后通过真实工作簿暴露并修复"合计行被当订单"的问题。

**一句话总结:**可靠的数据导入工具,不是把每一行塞进数据库,而是先识别输入语义、建立可验证的数据模型,再把副作用限制在最小范围内。

相关推荐
用户0332126663673 小时前
Python 实现 Excel 转 XML:快速上手
python·excel
asdzx674 小时前
Excel 水印方案对比:页眉图片 vs 背景图片(附 C# 实现)
c#·excel
Data-Miner20 小时前
怎么用AI给Excel去重?先核对这7条再下手,别让好数据被删错:数以轻舟方案解析
人工智能·excel
Data-Miner1 天前
做表格数据分析的AI工具怎么选?先对一下这三个真实需求,再看哪些真能落地
人工智能·数据分析·excel
尤鸟倦7 天前
OneNote table复制到Excel遇到的各种问题
excel
2501_930707788 天前
使用C#代码使用条件格式为 Excel 隔行设置颜色
c#·excel
leihefeng8 天前
PX04-用 Python 读 Excel 画折线图,还能直接插回 Excel 文件
python·excel
yanlaifan8 天前
Excel中指定单元格不能输入内容的方法
excel
babe小鑫9 天前
信息与计算科学专业应届生面试 怎么证明自己能解决业务问题
学习·r语言·excel