一个人给自家塑料加工厂做 ERP 的起步复盘——最贵的不是技术,是「想当然」。
接手加工行业的系统,最先做的不是挑 Vue 还是 React,而是把业务口径钉死。一家塑料包装厂的账,本质是每张单据:金额怎么构成、重量按什么单位、单号怎么归零、时间以谁为准。这些事在白板上吵清楚的代价,远低于上线之后改代码——尤其是时间口径,页面、数据库、报表三处一旦不一致,对账永远差一天。
复刻期真正造成返工的,没有一次是因为技术难,几乎全是「我替用户做了假设」。下面四类最典型。
我以为「件数」就是数量,直接拿它当主数量字段。用户一句话纠正:老系统的「数量」另有含义。结果全部重做。类似还有明细列序——我按「逻辑顺序」排了列,用户要求逐字对齐老系统一屏的列序;打印金额取整——我按财务习惯保留两位小数,老系统是 Math.round 取整,用户真机截图对比后打回。
金额构成是(材料费 + 加工费)× 折扣% + 其他费用。代码里写了折扣默认值兜底:
// 错误示范:discount_rate 为 0 时当 falsy,被 || 100 顶成「不打折」
const rate = order.discount_rate || 100;
客户明确「这单不要折扣、折扣就是 0」,系统却算出 100% 折扣——金额直接归零。根因是把「0」当成了「没填」。正确做法是显式判断 null/undefined,而不是用逻辑或兜底。另一处是统计报表把已作废的单据混进了求和,欠款、业绩一夜数倍膨胀。
页面显示北京时间,MySQL 列存 UTC,「今日」指的是北京自然日。三套口径只要有一处没对齐,月底对账就永远差一天。比如列表「处理日期」用 handle_time,明细「开单时间」用 created_at,两者时区来源不同;order_date 字段类型更是不敢动(全系统 187 处引用)。
解法不是临时换算,而是把时间口径收敛成一条真源函数,所有页面、报表、接口都调它,谁也不准自己 new Date() 硬算。
单据编号每天从 1 重新开始(SC20261009xxxx)。早期「取当前最大编号 +1」的实现,在有人删单后,新单会复用被删的号,造成「两个不同单同一个号」的硬冲突。修正:nextCode 必须把已删除的行也算进序号,编号一经发出不复用。
这套纪律是在返工里换来的。技术栈随便换,但「先听懂工厂怎么算账,再写代码」这一条,跨行业都成立。