feat(stocktake): 落地动盘(活跃库位抽盘)与导出盲盘保护

【导出收尾】/export-stocktake
会话 active 且 mode=blind 时,汇总表/差异明细/账实相符/未盘点四张 Sheet 的
账面数与差异数一律输出 '—',实盘数照常输出。会话 finished 后自动解锁 ——
盘点结束后核对差异是正常流程,否则报告本身没法用。
批量替换时误伤了 update_stocktake_quantity 里的差异计算,被静态检查脚本
抓出(会拿占位符 '—' 做减法),已改回按真实账面值计算。

【动盘算法】get_active_locations(company_name, days=30, top_n=50)
近 N 天异动最频繁的库位。出库经 (source_table, stock_id) 回查库存表取库位
(trans_outbound.warehouse_location 历史上 900 条里 829 条为空,实测回查
覆盖率 298/299);入库以库存表自身的 in_date / production_date 计时;
借出用 trans_borrow.location。报废/维修表无库位字段,未纳入。

【范围冻结】/draft/start-new
移除 scope_type=active 的 400 拦截,改为在开单时算出活跃库位并**冻结**进
scope_config。必须开单时算好 —— 若各接口实时计算,两次调用之间活跃度变化
会导致范围漂移,结束盘点时把已掉出范围的库存误判成盘亏。

【同源过滤】all-items / merged-list / generate-missing
三者都读同一份冻结的 scope_config。generate-missing 是重中之重:漏盘比对
只针对范围内库存,绝不把范围外未盘库存标成盘亏。
merged-list 一并加了过滤(原指令未提),否则抽屉仍会列出范围外物资,
与「总品项」对不上。

【前端】移除「活跃库位抽盘」的 disabled。

实测(IRIS,全仓 1126 → 抽盘 537):
  生成盘亏 537 条 | 落在抽盘范围内 537 | 落在范围外 0
  导出: 盲盘 active → 账面数/差异数 = '—';盲盘 finished → 76 / -76(解锁)
This commit is contained in:
yueli
2026-09-11 13:41:56 +08:00
parent 97c1a9131c
commit eabe70b00a
2 changed files with 194 additions and 23 deletions

View File

@ -80,13 +80,15 @@
<span class="task-form-label">盘点范围</span>
<el-radio-group v-model="newScopeType" size="large">
<el-radio-button value="full">全仓盘点</el-radio-button>
<!-- 抽盘的范围过滤尚未实现此时开放会导致把范围外库存批量标成盘亏 -->
<el-radio-button value="active" disabled>活跃库位抽盘</el-radio-button>
<el-radio-button value="active">活跃库位抽盘</el-radio-button>
</el-radio-group>
</div>
<div class="task-form-hint">
{{ newMode === 'blind' ? '盲盘:作业时不显示账面数与差异' : '明盘:作业时可查看账面数与差异' }}
</div>
<div v-if="newScopeType === 'active'" class="task-form-hint">
抽盘仅盘点近 30 天有出入库/借还记录的前 50 个活跃库位
</div>
<div v-if="creatingNew" class="task-form-warn">
开启新一轮会把当前进行中的盘点置为已结束历史数据仍保留
</div>