更新日志

改了什么,
一条条记在这里。

已经上线的直接写;还没上线的会标明「尚未上线」。 目前共 794 条
同一条更新可能同时属于多个模块,因此各模块条数相加会大于总数。

第 27 页

2026-09-2120 条

後端

出庫算哪個營業日:改問 `business_date`,不再問『這列什麼時候寫進資料庫』

  • 每一筆出庫被算進哪一天的營業日,原本問的是資料列被寫入的時間。
  • 回填的資料因此永遠只落在一天,補貨建議等於被結構性關閉;改成問 `business_date`(`inventory_selector.py`)。
  • 補貨建議是店長看的,所以是產品更新。
後端

預約訂金合計端點:財務頁那一格從『讀不到』變成真數字(分桶的軸不是 `status`)

  • 財務頁上『預約訂金』那一格一直顯示讀不到,因為後端沒有這一個合計。
  • 這一條補上端點,並且分桶用的軸不是訂單狀態而是預約自己的狀態(`apps/members/urls.py`、`views.py`)。
  • 那一格現在顯示真數字,前端半也一起落地 ⇒ 使用者感覺得到。
後端

同租戶商品重名:應用層守衛先擋增量(索引與存量留給 rico8)

  • 同一個租戶可以建出兩個同名商品,列表上分不出誰是誰。
  • 這一條先在應用層擋住新增的重名(索引與既有資料留給另一條線處理),所以現在建重名會被拒絕。
  • 使用者會遇到這個拒絕訊息,所以是產品更新。
後端

訂單列表補上已退款金額與淨額兩欄

  • 訂單列表原本只給總額,看不出哪一張被退過、退了多少。
  • 這一條在列表序列化器補上 `refunded_amount` 與 `net_amount`;這一條同時解鎖了前端與 P2-299 的退款篩選。
  • 金額欄位是老闆直接看到的,所以是產品更新。
後端

訂單查詢新增『有沒有退款』篩選(後端 `has_refund`),詳情帶退款集合

  • 先前『日結的退款筆數』與『訂單查詢看到的退款』對不上,前端也因此做不出篩選。
  • 後端補上 `?has_refund=true|false` 與詳情裡的退款集合(`order_selector.py`、`serializers.py`、`views.py`)。老闆與店長在訂單查詢頁感覺得到。
股东

提现那一列,最重的手续加在唯一没有财务后果的动作上

  • 走查量到:批准是一次点击、没有确认也不用写理由;标记已打款有确认步骤;而拒绝要三个动作加一条必填理由。钱往外走的方向最顺,钱留在店里的方向最难。
  • 同事当天在另一个模块独立点名了同一个形状(拒绝要三个动作加必填理由、批准和已转出各一下),所以这是形状不是巧合。
  • 现在批准也要确认一步,确认句沿用这个页面「标记已打款」已经做对的写法:印出金额、开户行和卡号尾四位——那正是对外付款内控要核的两样,金额和收款人。
  • 为什么确认句要带卡号尾四位:后端记的开户行、卡尾、持卡人都是申请当下的快照,所以「核准之后改卡把钱改道」这条经典路径后端已经挡住了。批准这一步印出快照,是让审批的人在按下去之前就看到他实际在核准的收款人,而不是到打款那一步才第一次看到。
  • ⚠️ 没有加双人复核。同一个权限码仍然一个人走得完批准到已打款。那是产品决定(单店酒吧多半只有老板一个人有这个码),要补的是金额门槛——大额才需要第二个人,那需要新的设置项,已上报。

股东与分红

库存

[已并入 T-2549] 库存总览「充足」是默认值不是判断——同一缺陷由 T-2549 修复并上线,本条保留作为记录

  • 走查进销存的库存总览,四十七项商品每一项都挂着绿色的「充足」。拉原始资料看:安全水位四十七项全是空的、零项设过、零项库存为零。
  • 判准是:库存小於等於零就是缺货;有设水位而且低於水位就是偏低;其馀一律充足。也就是说没设水位时,只要还剩一毫升就是「充足」;而「偏低」这一档对这家店永远到不了——没有任何门槛能让它成立。
  • 老板扫过去看到四十七个绿色「充足」,以为库存健康;真相是一项都没有被评估过。「没设过」跟「真的没问题」在画面上长得一模一样。
  • 改法只落在渲染层:没设水位时徽章印「未设水位」并去掉绿底,其馀一字不动;再加一行只在真的有未设项时出现的说明,把数字讲出来,并点明「偏低」这一档对它们永远不会出现,以及去哪里设。
  • 刻意不新增第四个状态值:那个型别还餵着跨仓汇总与预警中心的「要注意的品项数」。这里要修的是这个字说了谎,不是统计算错了——没设水位确实不是缺货,计数把它排除是对的。下一个人最容易犯的错是顺手改成回「偏低」或新增状态值去一起修统计,那会让预警中心的数字从零跳到四十七,而那四十七项没有一项缺货,等於把一个文案缺陷换成一个天天误报的告警。
  • 验证含一个能区分新旧实作的负控:只看「四十七项都变成未设水位」是不够的,那一格没有证明我没把充足与偏低弄坏。所以临时给约五分之一的商品注入极高门槛、五分之一注入极低门槛,注入後三档同时出现(偏低四、充足十二、未设水位三十一),说明文字的计数也跟着从四十七降到三十一。还原後全库搜不到残留。
  • 中间量错过一次值得记:我用取服务器上的模组再搜注释标记的方式确认注入生效,得到零,差点判成热更新坏了。实际上是编译会把注释剥掉,而我的标记正好写在注释里;改搜变数名立刻看到它在。校准标记要选一个会活过那条管线的东西。
  • 型别检查与两支静态闸门皆零。尚未部署。

进销存

股东

一对叫老板「直接相减」的数字,印成了两种长相

  • 股东提现那一区并排两个数:「累计 pending 分红合计 ¥0」和「累计提现占用合计¥0.00」。左边没有小数、右边两位,而且右边还少一个空格。
  • 而它们上面那句开场白逐字写着「两个数字均为累计口径…所以可以直接相减」。要人相减的一对数字印成两种长相,第一眼会被读成两种东西。
  • 根因不在格式化函数,在两侧的输入:左边是后端字符串原样印、右边是前端自己加总之后补的两位。
  • 修法是在字符串层把小数补到两位——只补不截。小数超过两位时原样输出:后端现在是两位小数所以不会发生,但真发生了就代表上游变了,那时候要看到真相而不是一个被四舍五入过的好看数字。
  • 顺带把负号移到货币符号外面(原本印成 ¥-1,234.50)。这一页的净利和本月补亏真的会是负的。同事当天在另一个模块独立踩到同一件事并选了同样的写法,两边对齐——两个函数对同一个值印出不同长相,正是这一轮一直在修的病。
  • ⚠️ 值得记一笔:我当天早上才在这同一行修过另一件事(它读不到时会印 ¥0.00 冒充真值),而这个并排的格式差当时就在画面上,我没看见。有趣的决定吃掉了例行检查。

股东与分红

进销存

临期预警说「没有临期批次」时,现在会告诉你是真没有还是根本没数据

  • 这两件事以前在画面上长得一样:「确实没有快过期的货」和「一个批次都没填效期,所以这道检查查不出东西」。后者读起来像前者,老板会以为自己没事。
  • 现在:一个都没填的时候直接说「这家店 49 个在架批次没有一个填了效期,这道检查现在查不出任何东西,这不等于没有临期货」;有一部分填了的时候会写出比例。
  • 还没读到数据时维持中性说法——不说「你没事」也不说「你查不了」。

进销存

进销存

周转天数那张表其实只列了一部分,现在会说清楚

  • 那张表一直只列周转最慢的 20 项。演示店实测店里有 46 项有库存,另外 26 项从来没出现在这一页上,而画面上没有任何提示——没有分页、没有「更多」。
  • 现在会说明:上面是最慢的 20 项、这段时间一共 46 项、没列出来的那 26 项不代表它们周转健康,只是这一页没拿到它们的数字。
  • 超过一年的商品以前一律显示「> 365 天」。这张表就是按周转天数排序的,好几项都超过一年时会全部显示成同一句话,看不出该先处理哪一支。现在显示「严重积压・约 5.3 年」,既不像故障读数也保住了先后次序。

进销存

人事

月度出勤:同一次打卡被拿去对同一天每条排班各算一次——工时翻倍、整班没来被记成「早退」

  • 走查排班页的月度出勤时,把这家店唯一有排班的那个人的原始资料逐条拉出来看:排班十四次、准时零次、迟到两次、早退十三次、旷班零次;而累计实际工时是三千六百分钟,真实只有六天乘以三百等於一千八百分钟。
  • 最刺眼的一条:同一天排了早班十点到十八点、晚班十八点到二十三点半,而当天只打过一次卡、十点到十五点。早班判早退一百八十分钟是对的;晚班却算出「迟到负四百八十分钟」——也就是提前八小时到——而且被标成早退。整个晚班根本没来,系统记成早退,於是旷班那一栏一直是零。
  • 机制是配对的键错了:配对用的是「人加日期」,而真实的轴是「人加日期加班次时段」。於是同一天的每一条排班都拿到同一笔打卡记录。这支函式自己的说明写着它存在的理由就是「才追得到排了班但没来」——而分早晚班正是它追不到的那种没来,因为另一个班的打卡让配对成功了。
  • 第二个后果是钱:同一段三百分钟被累加两次,而累计实际工时正是月度工资估算的「实际工时」来源,工资是实际工时乘以时薪。也就是说工资会算成两倍。现在之所以没人被多发,只是因为时薪普遍没设——那是运气不是保护。分早晚班在餐饮是常态(峰谷排班),不是边角案例。
  • 改了两条,两条都属於无可争议那一类:打卡时段跟这条排班零重叠就是旷班不是早退,人不在场就是不在场;同一笔打卡的工时只能算一次,你不可能把同一段五小时上两次班。迟到早退的判定照算不受影响——那条排班确实被这次打卡覆盖到了一部分。
  • 刻意没碰的那个决定:实际工时现在仍然是「打卡时长」而不是「排班覆盖时长」。做满全天的人,早班拿到全部工时、晚班拿到零(已计过)。改成按重叠分摊会更好看,但那会把排班以外的加班时数丢掉,而那个数字要拿去估工资、於是变成少算。工时口径是产品决定不是技术决定,已另行点名,这里不擅自改。
  • 前端另修一条不同的事:那四栏加起来不等於排班数。一个班次可以同时迟到又早退,而表头把排班数摆在四个计数前面,读起来就像一个划分;实测零加二加十三加零等於十五,而排班数是十四。三个数字都对,只有「它们该加得起来」这个隐含关系是错的,而那个关系只存在於版面顺序里,型别测试契约都碰不到它。只在真的对不上时才出现一行说明,并且两个数字都印出来。
  • 要注意这两条是两件事:後端修完之後这家店会变成十四、零、一、七、七,四栏合计仍然是十五,因为九月二十号晚班那条还是既迟到又早退。所以前端那一行不是後端的补丁,後端修完它照样该在。
  • 验证:新增一支八个案例加一个负控的单元测试,不开框架不连资料库、笔电上就跑得动,用语法树从真正的那个档案挖出受测函式,函式改名或删掉会直接失败。破坏验证裸跑过:把两条规则都注回旧行为,退出码一、恰好两条转红,而且红出来的正是实测值;还原後退出码零。负控独立证明旧算法对晚班会得到负四百八十,跟正式机实测一致。
  • 一个自己踩的坑值得记:第一次跑破坏验证时管线尾巴接了截断指令,退出码读到的是截断指令的零,而输出里明明写着失败。重跑裸的才拿到一。管线最後一段决定退出码。
  • 前端型别检查与两支静态闸门皆零。尚未部署。

排班打卡

股东

分红页承诺了一道不存在的检查,而它旁边就是一个不能撤销的按钮

  • 确认分红那一块原本对老板说:「股比合计有没有超过 100%、有没有股东档案,这两道检查只有真正确认时才做得到」。第一道是真的,第二道不存在。
  • 后端的逻辑是:这家店一个启用中的股东都没有的时候,确认不会被挡,而是把可分配利润全额留存、一笔都不发。那是后端刻意的设计并且写了注释,不是缺陷——缺陷是前端承诺了一道不存在的检查。
  • 为什么要紧:确认之后没有撤销(整个服务里没有取消或反确认的入口),而它写下的月末结转数字,正是下个月月初要接着读的那个值。老板读了那句话以为系统会拦他,按下去,这个月就定了。
  • 现在改成真的预警:一个启用中的股东都没有时,在确认按钮上方直接说清楚三件事——不会被挡、全额留存一笔不发、确认之后没有撤销,并给一个去建档的入口。原来那句话里的「有没有股东档案」改成「有没有股东股比没填」,那才是真的存在的那一道。
  • ⚠️ 预警本身只在真的读到股东名单时才出声。读不到就什么都不说——在一个不可逆的动作旁边猜,比不说更糟。如果闸写成「读不到就当成空数组」,会对一家有五个股东的店说「你没有股东档案」。

股东与分红

进销存

预警中心的分类表以前只列前 8 类,剩下的没说

  • 那张按库存价值排的分类表一直只显示前 8 个分类,画面上没有任何提示。演示店实测:后端有 13 个分类,被藏起来的那 5 类占 42.6% 的 SKU。
  • 被藏起来的正好是主食、调酒辅料、葡萄酒、啤酒、软饮——整个非酒水的半边店。
  • 现在会说清楚还有几类、多少个 SKU、多少钱,并且可以一键全部展开。
  • 「在架 SKU 数」跟「库存总览」那一页的数字对不上时,现在会说明为什么(同一个商品分在多个仓会占两条库存记录)。

进销存

采购

应付每一行补上收货单号——对帐要的三张单,第二张一直在回应里没印出来

  • 应付帐款的行业控制叫三单匹配:采购单、收货单、发票三者对得上才付款。而应付页每一行原本只印应付单号加采购单号,少了收货单那一张,而它就在同一个回应里。
  • 没有它,拿着供应商送来的送货单想对帐的人,手上这一行对不上任何东西。
  • 补上之後三笔实测都带上了收货单号,宽窄两种版面共用同一支组字函式,不会一边有一边没有。
  • 要讲清楚的限制:这仍然是两单匹配不是三单。应付单上只有发票日期栏位、没有发票号栏位,而且这家店三笔的发票日期全是空的——第三张单根本还没有地方存。这句话写进了程式码注解,免得下一个人看到一行有三个号就以为三单齐了。後端补发票号那半已另报。
  • 型别检查与星号闸门皆零;浏览器实测三行都带收货单号。尚未部署。

采购

采购

采购建单:账期现在跟着供应商档案带出来,而且填 0(货到付款)不会再被悄悄改成 30

  • 走查采购到应付这条动线时,应付页第一行就是「已逾期三笔,共三十三元九角」。顺着到期日往回查:供应商档案上谈好的账期是三十天,而三张采购单上的账期是零 —— 没继承。於是到期日等於下单日,收货当天就到期、隔天全部逾期。
  • 账期直接决定应付的到期日,而到期日决定应付页的逾期告警,所以这个字段填错的代价不是显示问题。
  • 查下来是两个各自独立的缺陷,都在建单那张表单。第一,账期的预设是写死的三十天,不是选中供应商的账期——店里甲供应商四十五天、乙供应商七天时,每次建单都得自己记得改,而那个数字就在供应商档案里、一个字段的距离。第二,送出时那行写法会把零当成「没填」,於是使用者明确填零(货到付款,餐饮现金进货很常见)会被静默改成三十天;单子建出来了、没有错误、只是到期日晚了一个月。
  • 改法:换供应商时把账期带出来,但只在使用者还没动过那一格时;改过之後不再覆盖——那是他对这一单的决定,不是预设值。送出时只在「空白或不是合法天数」才回退,而回退目标是这家供应商的账期,不是一个跟谁都无关的常数;负数也当没填,因为下单日加负数等於一建出来就逾期。表单下面讲清楚这个数字哪来的,改过之後两个数字都给。
  • 验证:取值函式八个案例全过,关键那格是「填零加供应商三十」要得到零(旧版会得到三十)。浏览器实测时特地绕开一个陷阱:这家店唯一的供应商账期正好是三十,跟旧的硬编码预设一模一样,直接测「选了供应商後是不是三十」两种实作都会绿、一格都踩不到差异;所以临时把供应商账期改成七再测,选供应商前是三十、选了之後变七、填零之後保持零、再换一次供应商也不会被覆盖。两处临时改动都已还原,全库搜不到残留。
  • 没有真的送出一张采购单——那是对正式机的写入。送出那一行的取值由八个案例覆盖,没被执行过的是建单那一次呼叫本身。
  • 型别检查与两支静态闸门皆零。尚未部署。

采购

老板

会员页的金额栏七处格式不一致,右对齐的数字对不齐

  • 会员明细上「累计消费」和紧邻的「本年消费」用了两支不同的格式化函数。演示店上它们刚好是同一个值,于是画面并排印着 ¥4144.25 和 ¥4,144.25——看起来像两件事。
  • 会员列表那一栏是右对齐的金额列,而它混着 0 位和 2 位小数:¥4904 · ¥1722 · ¥3001.65 · ¥4144.25。右对齐金额列存在的全部意义就是数位对齐,而 ¥4904 排在 ¥3001.65 旁边会被读成约数。现在统一成 ¥4,904.00 · ¥1,722.00 · ¥3,001.65 · ¥4,144.25。
  • 这一页本地那支金额函数是裸的 toLocaleString,会吃掉尾零、还会四舍五入到三位印出不存在的精度。改成走站内统一的两位小数函数,一次修好它的 17 个调用点。
  • 「累计消费」和「储值余额」各有窄屏卡片和宽屏表格两份渲染,四处都改了。只改一边的症状是「换个屏幕宽度数字就变了」,而没有任何测试会说话。
  • 顺带修掉一句给用户看的文案里引用了内部文档:「暂无数据——…(见 TEAM.md 提案)」。老板不知道那是什么。改成直说这个功能还没做。

股东与分红

订位

「今日及未来预约」以前会把几个月前的订位也算进去

  • 这个标题从来没有按时间筛过——它筛的是状态。有家店打开这一页看到「今日及未来预约(61)」,而那 61 笔没有一笔是今日或未来。
  • 现在分两堆:今日及未来一堆,到店日期已经过去、状态还停在「待确认/已确认/已到店」的另一堆,后者有自己的入口,不会被藏起来。
  • 那一堆刻意不叫「爽约」:里面有客人真的来过、只是没人改状态的(全平台 27 笔),叫爽约是冤枉客人。

订位管理

进销存

库存现在按「瓶/罐」显示,不再只给你一个毫升数

  • 「现有库存」那一栏原本写「17,250 毫升」——盘点时你数的是瓶,不是毫升。现在显示「23 瓶 · 17,250 毫升」。
  • 开了一半的酒不会被抹平:「24.8 瓶」就是 24 整瓶加一瓶开了八成,这是真信息不是误差。
  • 换算词用商品规格里写的那个(480ml/罐 的就显示「罐」,不会一律写成「瓶」)。
  • 小吃这类本来就按份/杯记的商品完全不变。

进销存

体验

会员周报整篇渲染成繁体:prompt 第 5 条要求简体,而它自己把「本周会员周报」写成了繁体

  • 走查顾客页时第一屏就看到:标题是简体(前端写死的),而正文整篇是繁体(模型生成的)——「本週會員面:活躍4人、新客4人,全靠消費帶動,儲值仍為零」。同一屏其他文字全是简体,而这个产品面向的是大陆市场。
  • 根因是那段提示词自己在示范繁体:第五条逐字写着「简体中文,像周会跟老板口头汇报」,而同一段提示词里有三处繁体——开场的「本週會員週報」、规则二里的「本週会员面态势」、以及每次请求都再示范一次的「请据此生成本週會員週報」。模型跟着具体的那个词走,不跟着那条抽象规则走:输出的第一句就是规则二那个词组。
  • 母体量过:用语法树扫全部名字带提示词的字串常数加上所有直接传给模型的字串常数,含繁体的只有这一支。也就是说不是「AI 都会输出繁体」,是只有这一支提示词自己写成繁体,其他输出都是简体。
  • 为什麼静态检查看不见它,有两层。第一层:检查扫的是原始码里的字串,而使用者读到的是模型生成的字,那不是任何一个字串常数。提示词是第三类——既不是内部说明也不是使用者面文案,而是会长出使用者面文案的内部字串;其中一句就在基线里,被当成一句可以接受的内部字串放行了。
  • 第二层是这轮新发现的:那支检查有一行「超过两百字的字串直接跳过」,而这段提示词被语法树折叠成一个约两百五十字的常数,所以连基线都没进去。这条边界没有写在它自己的已知边界那一段里。量了一下这个洞现在有多大:含繁体的非说明字串里超过两百字的只有三处,加上本次修掉的共四处。洞很小,但漏掉的那一支正好是会生成使用者面文字的那一支——数量不是重点,种类才是。
  • 三处全部改成简体;语法树复查该档提示词常数残留繁体零处。後端繁简棘轮裸跑:命中从五百零三降到五百零二、基线从三百七十降到三百六十九,而基线以外的新违规维持九十二不变,也就是没有把任何既有违规塞进基线消音。
  • 一个没做的验证要讲清楚:没有真的重新生成一次周报去看输出变简体了——那要对正式机发一次强制重算的模型请求,既是写入也烧 token。本条只证明了提示词乾净,没有证明模型的输出。
  • 还有一件要知道的:改了提示词不会改掉已经生成的那一份。周报按租户、门店、本周週一快取一整周,要嘛等下周、要嘛带强制参数重新生成才会看到简体版,没有回填旧快取。

顾客 CRM

合规

礼品卡:发卡与充值现在会按记名/不记名提示预付卡的单张限额与有效期红线(含条文出处)

  • 礼品卡管的是预收款——客人先付钱、以后来喝,余额是店家欠客人的负债;而餐饮正是《单用途商业预付卡管理办法》明文适用的行业。这一页原本对那个办法的两条硬规定零提示。
  • 第十八条:单张记名卡限额不超过五千元、单张不记名卡不超过一千元;而且管的是充值后的资金余额,不只是发卡当下的金额。第十九条:记名卡不得设有效期;不记名卡有效期不得少于三年;对超过有效期尚有余额的不记名卡应提供激活换卡等配套服务。
  • 走查看到的:发卡表单的金额框只有下限没有上限;到期日是一个可以选明天的日期选择器,而且对两种卡一视同仁。后端发卡服务也没有任何金额或有效期校验,到期日原样落库。也就是说一张明天到期的六千元不记名卡现在可以一路绿灯发出去。
  • 这一页本来就分得出记名与不记名——绑到会员档案的就是记名,页面文案早就在用这两个词。缺的不是信息,是没把这件事接到那两个输入框上。现在填的当下就会按卡的类型给出对应的红线、数字和条文出处。
  • 刻意只提示不拦截:那个办法的适用主体是企业法人,而不少小店是个体工商户,严格说不在适用范围;各地还有自己的实施办法。我们没有足够信息替店主判定他适不适用,硬拦会挡掉合法用法,而默默放行等於让他在不知道有这条线的情况下越线。所以把线画出来,按不按是他的决定。同理也没有给日期框加浏览器层的最小值——那会变成点了没反应而不是知道为什麼。
  • 留给下一个人的坑:第十八条管的是余额不是单次金额,所以充值那一格传的是当前余额加这次充值。只看单次的话,一张九百元的不记名卡连充两次五百会一路绿灯到一千九。
  • 验证:真浏览器九个案例、含三个负控。五百元无到期日无提示;一千五和六千元触发不记名上限;到期日填明年触发三年下限并算出最早可填的日期;到期日填四年後无提示;金额与日期同时越线时两条一起出;绑上会员号後三千元无提示、六千元触发记名的五千上限、而填了到期日时出的是「记名卡不得设有效期」且三年那条正确地没有出现。判断记名与否读的是页面本来就在用的那个绑定结果,所以两句话不会各说各话。
  • 一个没走到的分支要讲清楚:充值那一格没有真的走过,因为这家店一张卡都没有,而造一张是对正式机的写入。用的是同一支提示函式,金额那半由上面九个案例覆盖;真正没被执行过的是取「当前余额加这次充值」这个动作。
  • 型别检查与两支静态闸门皆零。尚未部署。

顾客 CRM

这份日志从 2026 年 7 月记起,更早的没有逐条列。想看它现在都会什么,回全部功能,或者进演示店自己点一点。