业务口径包花厂集采
包花厂集采业务逻辑
采购计划发布 → 按等级报价 → 自动定采 → 签到打印 → 扫码入库 → 盘点 → 超量处理 → T+3 结算的完整业务口径,附现场操作清单与常见问题排查
Markdown 原文(给 AI 用):https://doc.xfun.fun/bulk-purchase-logic.md
结论
包花厂集采是一条「运营发计划、供应商报价、系统定采、仓库收货、平台结算」的链路:
- 运营发布采购计划,写清品类、规格、各等级收购扎数和最高价、哪些供应商能报。
- 供应商按等级报单价和可供扎数,截止前可以改报。
- 报价截止后系统自动定采:每个等级取价格最低的前 5 家,依次分到需求量为止,给中选的供应商各生成一张供货单。
- 仓库给供货单签到 → 打印标签 → 开始盘点 → 扫码。每扫一张标签 = 入库 1 扎,库存在扫码那一刻就加上。
- 提交盘点后供货单进入待结算,3 天后按冻结报价自动结算;送多了(超量)要先人工处理才能结算。
三条贯穿全链路的口径:
- 单位一律是扎,单价是元/扎。每扎多少枝(
specNum)只用于展示和标签,不参与任何乘法。 - 价格在定采那一刻冻结到供货单,之后改商品售价、改报价都不影响结算。
- 采购计划和供货单的状态互相独立。计划「已完成」只表示定采流程结束,货还没收、钱还没结。
开发实现、接口、锁与定时任务见 包花厂集采开发文档。
角色与业务对象
| 角色 | 在系统里做什么 | 使用的端 |
|---|---|---|
| 运营 | 发布 / 追加 / 撤回 / 提前终止采购计划;查看定采结果;处理超量、改结算数、手动结算、取消供货单;管理包花厂商品上架和售价 | 运营后台 |
| 供应商(供货方) | 看可报计划、报价、改报;查看自己的供货单 | 供应商小程序 |
| 仓库作业人员 | 签到、打印标签、开始盘点、扫码、撤销扫码、提交盘点;也可以处理超量、改结算数、手动结算、取消 | 仓库 PDA |
| 发布主体 | 发布计划的内部自营供应商账号。货入它的库存、钱从它的余额扣 | 后台配置 |
| 对象 | 含义 |
|---|---|
| 采购计划(集采需求) | 一次收购安排:品类、规格、各等级收购量和最高价、供应商范围、两类供应商的报价截止和签到截止 |
| 报价 | 某供应商对某计划各等级的单价与可供扎数。每次改报存一个新版本,定采只看当前版本 |
| 供货单 | 定采中选后生成。同一计划下一个供应商只有一张供货单,可包含多个等级 |
| 货架码 | 当场次内用于现场找单的编号(JC 开头)。跨场次可能重复,不能单靠它判断是否同一张单 |
| 标签 | 一张标签 = 一扎。标签归属某张供货单的某个等级,有序号,不能跨单使用 |
数量与金额口径
| 字段 | 叫法 | 怎么来的 |
|---|---|---|
| 收购扎数 | 计划某等级要收多少 | 发布时的收购量 + 报价中追加的扎数 |
| 可供扎数 | 供应商承诺能供多少 | 报价时填写;填 0 表示这个等级只报价、不供货 |
confirmLabelNum 定采扎数 | 系统实际分给供应商多少 | 自动定采算出,可能小于供应商的可供扎数 |
actualLabelNum 实际产出 | 实际扫进来多少 | 每扫成功一张 +1;提交盘点时按各等级扫码数重新汇总校准 |
settleLabelNum 应结算扎数 | 最后按多少扎付钱 | 提交盘点时默认等于扫码数;待结算阶段可按等级人工改 |
totalAmount 应结算金额 | 最后付多少钱 | 各等级应结算扎数 × 该等级冻结单价,再求和 |
应结算金额 = Σ(等级应结算扎数 × 等级冻结单价)例:A 级 3 扎、2.50 元/扎,B 级 2 扎、1.80 元/扎,每扎 20 枝:
3 × 2.50 + 2 × 1.80 = 11.10 元 (不再乘 20 枝)冻结单价是定采时保存在供货单等级明细里的报价快照,不是商品当前售价。页面上的「超量金额 / 冻结金额」只是提示数字,不代表供应商账户里真的冻结了一笔钱。
主流程
运营配置品类、规格、等级数量、供应商范围、时间
└─ 发布采购计划(报价中)
└─ 供应商按等级报价 / 改报
└─ 两类供应商的报价截止都已过(或运营提前终止)
├─ 没人报价 / 没有可分配的量 ──→ 计划关闭
└─ 自动定采 → 生成供货单 → 计划立即「已完成」
└─ 供货单:待签到
└─ 签到 → 打印标签 → 开始盘点 → 扫码(同步入库)
└─ 提交盘点 → 待结算(未扫标签作废)
├─ 有超量 → 按等级确认结算数 → 处理超量
└─ 无超量 / 已处理 → 到期自动结算 或 手动结算 → 已结算采购计划状态
| 值 | 状态 | 含义 |
|---|---|---|
0 | 草稿 | 还没开放报价,可以改、可以删 |
1 | 报价中 | 平台层面仍在报价。两类供应商截止时间可能不同,不代表每家都还能报 |
2 | 待定采 | 正常只是自动定采过程中的一瞬间;长时间停在这里说明定采失败 |
3 | 已确认 | 历史状态 / 定采事务中的过渡状态 |
4 | 已完成 | 自动定采生成供货单后立即完成;少采也算完成 |
5 | 已关闭 | 无人报价、提前终止且无人报价、定采后没有任何中选结果 |
供货单状态
| 值 | 状态 | 可以做什么 |
|---|---|---|
10 | 待签到 | 签到;运营 / 仓库可取消 |
20 | 待盘点 | 打印、开始盘点、扫码、撤销扫码、提交盘点;无产出时可取消 |
30 | 待结算 | 补打 / 重打标签、改应结算扎数、处理超量、手动结算;到期自动结算 |
40 | 已结算 | 只能查看;不能重复结算、不能改量 |
90 | 已取消 | 未扫标签已作废,不能打印、扫码、重打 |
标签状态
| 值 | 状态 | 含义 |
|---|---|---|
10 | 已生成 / 未扫码 | 可以在本单盘点时扫 |
30 | 已扫码 | 已计入产出和库存;再扫会被拒绝,不会重复入库 |
90 | 已作废 | 提交盘点或取消供货单时,未扫的标签自动作废;不能扫、不能重打 |
规则:发布采购计划
发布前必须确定:发布主体、场次、二级分类、包装规格、毛花 / 成品花、商品规格、开放的等级,以及每个等级的收购扎数、最高价、最小提交量、单家最大提交量。
| 规则 | 说明 |
|---|---|
| 包装规格 | 二级分类必须配置了有效的 specNum,否则不能发布 |
| 商品规格 | 分类配置了商品规格时,必须选全(每个规格名选一个值) |
| 毛花 / 成品花 | 只是货物类型标识,不改变扎数和金额口径 |
| 最高价 | 必须大于 0,最多两位小数 |
| 最大提交量 | 不能小于最小提交量,不能大于收购扎数;不填或填 0 时保存为该等级收购扎数。历史数据里存的 0 仍按「不限」处理 |
| 时间 | 每类供应商(斗南 / 非斗南)的报价截止必须早于自己的签到截止;发布时报价截止不能已经过去 |
| 发布后锁定 | 主体、品类、规格等不能再改,只能追加供应商或追加扎数 |
供应商范围
| 值 | 范围 | 说明 |
|---|---|---|
1 | 全部供应商 | 用全员标记,不能再追加供应商 |
2 | 指定基地 | 发布时形成资格快照 |
3 | 品质优选 | 发布时形成资格快照 |
4 | 近 30 天销量阈值 | 发布时形成资格快照 |
5 | 指定供应商 | 发布时形成资格快照 |
6 | 白名单 | 发布时形成资格快照;之后修改全局白名单不影响旧计划 |
所有范围的基础条件都是「花材供应商且 data_status=2」。范围命中 0 家时不能发布。
产出截止(采集截止)
产出截止决定供货单最晚什么时候必须有产出,过了还没扫过一张就会被自动取消。
产出截止 = max(场次次日 12:00,最晚签到截止 + 2 小时)- 场次 11-05,最晚签到截止 11-05 20:00 → max(11-06 12:00,11-05 22:00)= 11-06 12:00
- 场次 11-05,最晚签到截止 11-06 11:00 → max(11-06 12:00,11-06 13:00)= 11-06 13:00
不要口头承诺「次日中午截止」,以计划上的 collectEndTime / 供货单上的 outputEndTime 为准。
发布后的调整
| 操作 | 允许条件 | 效果 |
|---|---|---|
| 追加供应商 | 报价中,且范围不是「全部供应商」 | 追加的供应商获得报价资格 |
| 追加扎数 | 报价中,且该等级已存在 | 抬高该等级收购扎数;不会自动抬高单家最大提交量;已提交的报价不回溯校验 |
| 撤回 | 报价中且没有任何报价 | 回到草稿 |
| 提前终止 | 报价中 | 有报价 → 立即进入自动定采;无报价 → 关闭 |
| 删除 | 仅草稿 | 删除计划 |
提前终止不是「停掉倒计时」,有报价时会马上定采并生成供货单。操作前要和业务负责人确认仍准备收货。
规则:供应商报价
| 规则 | 说明 |
|---|---|
| 资格 | 供应商 data_status=2;在计划的可报范围内;发布主体不能给自己的计划报价 |
| 等级 | 所有开放的等级都要报价格,不能漏;暂不供的等级可供扎数填 0 |
| 可供量 | 至少一个等级大于 0;大于 0 时必须 ≥ 最小提交量、≤ 单家最大提交量、≤ 该等级收购扎数(含追加) |
| 价格 | 大于 0、最多两位小数、不高于该等级最高价,且不超过 1000 元/扎 |
| 改报 | 报价中用「修改报价」,每次改都存新版本;内容完全没变时不生成新版本 |
| 同价排序 | 看当前版本的提交时间,越早越优先 |
报价截止提前 5 秒
供应商实际能提交的最后时刻 = 配置的报价截止 − 5 秒,到达该时刻即拒绝。
例:配置截止 10:00:00,供应商必须在 09:59:55 之前完成请求;09:59:55 已提示「报价已截止,报价和改价须在截止时间前5秒完成提交」。运营端仍按原截止时间(10:00:00)推进定采。
现场提醒供应商提前提交,不要等倒计时归零。
定采前调价
规则上要求:计划处于待定采、自己的报价未被定性、没有供货单、且仍在报价截止前 5 秒之前。正常流程中计划进入待定采时报价截止已过,所以自然截止后基本不可能调价,调价诉求应在报价中用「修改报价」完成。
供应商列表
列表只显示场次日期在服务器当天往前一个月及以后的计划(包括未来场次)。更早的计划在有权限时仍能打开详情。
页签 filterStatus | 范围 |
|---|---|
0 / 不传 | 全部可见计划 |
1 报价中 | 还没有本人供货单、仍在本人报价窗口内的计划(已报、未报都算) |
2 已采用 | 本人有未取消的供货单(含已结算) |
3 已截止 | 本人供货单已取消;或本人报价窗口已过 / 计划已结束且没有本人供货单 |
规则:自动定采
触发:两类供应商的报价截止都已过(系统每 5 分钟检查一次),或运营提前终止且有报价。
算法(每个等级独立计算):
- 候选 = 该等级可供扎数 > 0 的当前报价(填 0 的只报价不参与)。
- 排序:价格低优先 → 同价提交早优先 → 再按供应商 ID 小优先。
- 只取前 5 家。
- 从第 1 名开始,每家最多拿自己的可供量,凑满该等级需求就停。
- 前 5 家合计不够时如实少采,不找第 6 家补。
例:某等级需求 1000 扎,前 5 名按价格从低到高为 甲 500、乙 200、丙 500、丁 100、戊 100:
甲 500 + 乙 200 + 丙 300 = 1000 扎,丁、戊一扎不分例:需求 1000 扎,前 5 名可供合计只有 800 扎 → 分 800 扎,缺 200 扎,第 6 名也不补。
结果:
- 同一供应商在多个等级中选 → 合并成一张供货单;供货单保存各等级冻结单价。未中选的等级也可能保留报价明细(可在额度内为这些等级补打标签,见「规则:签到与打印标签」)。
- 有中选结果 → 生成供货单,计划立即「已完成」。
- 没人中选 → 计划「已关闭」。
- 判断结果以供货单为准,不以是否收到「已采用」消息为准。
规则:签到与打印标签
签到:待签到的供货单签到后转待盘点。超过签到截止仍可以签到,系统记迟到标记;集采签到不触发基地迟到处罚。
正常 / 增量打印(待盘点、待结算可用):
| 规则 | 说明 |
|---|---|
| 输入含义 | 每个等级填的是目标累计张数,不是本次新增张数 |
| 只增不减 | 目标不能小于已生成张数 |
| 上限 | 每个等级的目标、以及各等级合计,都不能超过整单定采扎数 × 2 |
| 等级范围 | 只能打供货单里已有的等级,不能临时加新等级 |
例:整单定采 50 扎(上限 100 张)。A 级已生成 10 张,改成 12 → 只新增 2 张(序号 11、12)。若 A 已 60 张、B 填 50 张 → 合计 110 张,超过 100 张被拒。
重打:按「等级 + 序号区间」重新取回原标签,复用原码,不新增数量。区间必须在 1 ~ 已生成张数之间,区间内有作废标签则不能重打。已取消的供货单不能重打。
打印机没出纸但后台已生成标签时,先看已生成张数和序号,用重打取回原区间,不要再增量打印。
规则:扫码入库
- 先点「开始盘点」占用这张供货单。同一张单同时只允许一个人盘点;扫码、撤销、提交盘点都必须是占用人本人。暂停或交班时用「释放占用」。
- 「首码识别」只用于确认标签属于哪张单,不计数、不入库。
- 扫码成功时,以下动作在同一个事务里完成:标签置已扫码、该等级扫码数 +1、整单实际产出 +1、发布主体对应商品库存 +1 扎。
库存在扫码时就增加了,不是等提交盘点。
扫码被拒(接口外层成功,但内层 data.success=false,本次不计数):
rejectReason | 原因 | 现场处理 |
|---|---|---|
2 | 该标签已扫描 | 不要重复计数;返回首次扫码时间和扫码人可核对 |
3 | 标签已作废 | 作废码不能再用 |
4 | 该标签属于其他供货单 | 换到正确的供货单扫 |
5 | 标签不存在 | 核对标签码 |
6 | 供货单当前状态不允许盘点 | 单据未签到、已提交盘点或已取消 |
撤销扫码:只能撤销本人扫的、且供货单仍待盘点的标签,同时扣回 1 扎库存。若这批库存已经卖出、剩余库存不够扣,撤销失败。
规则:提交盘点
| 条件 | 说明 |
|---|---|
| 状态 | 供货单待盘点,且由占用人提交 |
| 有产出 | 一张都没扫不能提交 |
| 少量备注 | 实际产出 < 定采扎数时必须填盘点备注 |
提交后系统:
- 按各等级扫码数重算实际产出,默认应结算扎数 = 扫码数,算出金额;
- 未扫标签全部作废;
- 供货单转待结算,释放占用;
- 计划结算时间 = 提交盘点时间 + 3 天;
- 实际产出 > 定采扎数时标记未处理超量
overFlag=1。
提交后不能再扫码或撤销。要改付款数量,在待结算阶段按等级改应结算扎数,不要改扫码数据或重复提交。
规则:超量处理
超量单仍是「待结算」,不单独设异常状态。有未处理超量的单既不会自动结算,也不能手动结算。
超量扎数 = max(实际产出 − 定采扎数,0)处理时选两种类型之一,并填写处理说明。
类型 1:供应商自身超送
供应商自己多送了。必须先按等级确认应结算扎数(哪怕决定全额结算,也要显式提交一次),再登记「自身超送」。
只在处理说明里写「按 40 扎结算」不会改变付款依据。没显式确认过结算数时,系统会拒绝处理并提示「应结算数量还没确认过」。
类型 2:混货 / 错贴标签
当前单扫到了别家的货。处理步骤:
- 按等级把当前单的应结算扎数改小,扣减量 = 扫码数 − 应结算数。
- 逐条登记被占用方:同一计划下的其他供应商、等级、被占用扎数、补偿方式。被占用方必须有效且已待结算(未提交盘点、已结算都不行),且其供货单包含该等级。
- 对平:每个等级的扣减量必须等于该等级所有补偿明细的被占用扎数合计(三种补偿方式都算),两边任何一个等级对不上都拒绝。
| 补偿方式 | 台账 | 被占用方应结算扎数和金额 |
|---|---|---|
1 登记补款 | 记录 | 增加补偿扎数,按被占用方该等级冻结单价重算,随其供货单一起结算 |
2 线下补偿 | 记录 | 不变,只记台账 |
3 无需补偿 | 记录 | 不变,只记台账 |
例:当前单 A 级扫码 20 扎、定采 11 扎,改应结算为 11 扎(扣减 9 扎)。被占用方原应结算 10 扎:
登记补款 2 扎 + 线下补偿 3 扎 + 无需补偿 4 扎 = 9 扎 (与扣减对平 ✔)
被占用方应结算 = 10 + 2 = 12 扎 (只有登记补款进系统应付)compensateAmount 补偿金额可以手填(≥ 0,最多两位小数),不填按被占用方冻结单价 × 扎数计算。它是台账金额,不会覆盖任何供货单的应结算金额。
处理之后
- 当前单
overFlag清为 0,记录处理人、时间、说明。 - 运营端列表:已处理的单显示超量扎数 0、超量金额 0.00;详情仍保留原始超量差额和按冻结价算的历史超量金额。
- 列表提示消失 ≠ 库存退回 ≠ 应结算金额变 0。各端显示不一致时先看处理标识、处理时间和等级结算明细,不要重复处理。
- 处理超量不等于付款。若计划结算时间已过,下一轮自动结算会接住;没到期则继续等,或手动结算。
- 历史已处理数据不会随新规则自动冲回,发现差异交开发和财务核对。
规则:结算
| 方式 | 条件 |
|---|---|
| 自动结算 | 待结算 + 计划结算时间已到 + overFlag=0,由定时任务执行 |
| 手动结算 | 待结算 + overFlag=0,填写原因(≤ 255 字);运营后台、仓库端都可操作 |
记账动作(运营后台、仓库端、自动任务共用同一套):
| 对象 | 余额 | 账变类型 |
|---|---|---|
| 供货供应商 | 增加应结算金额 | 95 集采收入 |
| 发布主体 | 扣减应结算金额(允许扣成负数) | 96 集采支出 |
| 供货单 | 置已结算 status=40、settleFlag=1,记结算时间 / 方式 | — |
- 金额为 0 时也置已结算并留审计,但不产生余额账变,仍会给供应商发结算通知。
- 结算记入的是供应商平台余额,不代表银行转账或提现已经完成。
- 结算通知在数据库提交后发送,消息没收到 ≠ 没结算,不能因此再结一次。
- 运营后台手动结算失败、超时或无返回时,先刷新供货单和账变确认结果,再决定是否重新操作。
规则:取消供货单
| 方式 | 条件 |
|---|---|
| 手动取消(运营 / 仓库) | 待签到或待盘点,且实际产出为 0 |
| 自动取消 | 待签到或待盘点、产出截止已到、实际产出为 0 |
取消后未扫标签全部作废。
已有扫码产出的供货单不能取消——扫码已经入了库存,取消不会退库存。仍待盘点且确需取消时,先由原扫码人逐张撤销扫码;库存已被卖掉、已提交盘点或已结算的,转技术和业务负责人处理,不能直接改数据库状态。
规则:商品与库存
- 商品归发布主体。打印时按「发布主体 × 二级分类 × 等级 × 商品规格」找商品映射,没有就自动建品(集采专用建品
type=3,不是到场货type=1)。 - 自动建的商品:价格 0、库存 0、下架、无图。库存靠扫码增加。
- 入库后需要运营在「包花厂商品」里确认售价并手动上架,0 元商品会被上架校验拦截。「已入库但采购端看不到」多半是没上架,不是扫码失败。
- 核对商品要同时看主体、分类、等级、完整规格和映射,不要只按商品名找。
- 改商品售价不影响供货单冻结报价。库存推送异常查推送日志,不要用再扫一次码来补。
现场操作清单
到场先确认
- 环境、当前场次、运营账号、仓库账号;当班业务负责人和技术升级联系人。
- 当天的采购计划和关联供货单;两类供应商的报价截止、签到截止;供货单的产出截止。
- 拿一张正常供货单走一遍签到、打印、开始盘点、扫码入口;确认打印机、标签纸、扫码枪可用。
- 当天待盘点、超量待处理、已到期未结算的单据,先处理会阻塞作业或付款的。
- 请开发确认运营端需求推进任务、供应商端自动结算 / 自动取消任务的启用状态和最近执行结果。
记录问题时至少写
环境、发生时间、账号角色、场次、采购计划号、供货单号、操作步骤、完整提示。扫码问题补标签码;资金问题补处理前后的应结算扎数和金额。
不要把登录 token、结算凭证、密码贴进问题记录。
交接时当面核对
现场环境和服务版本、当日场次与截止时间、可用账号和设备、待处理异常单清单、定时任务的频率与负责人、升级联系人、未完成的资金或库存核查。每项遗留都要有单号、当前状态、下一步、负责角色。
常见问题排查
| 现象 | 先核对 | 处理 / 升级 |
|---|---|---|
| 供应商找不到计划 | 账号、场次、一个月范围、页签、报价资格、本人是否已有供货单 | 切回「全部」并按准确场次找;仍找不到,记计划号和供应商 ID 交开发查资格 |
| 倒计时还剩几秒却报已截止 | 实际截止 = 配置时间 − 5 秒;服务器时间 | 以服务端为准,不能承诺补报 |
| 报价提示数量超限 | 最小提交量、单家最大提交量、收购量(含追加);不供的等级是否填 0 | 按提示改;追加扎数不会抬高最大提交量 |
| 报了价没中选 | 当前有效版本、该等级可供量、价格、该等级前 5 名 | 按等级看排序和分配,不能看整单总量 |
| 截止后一直待定采 | 两个原截止时间、定采错误日志、是否已过产出截止 | 交技术查任务;已过产出截止的不会自动重试,不要盲目重跑 |
| 计划已完成,供货单却待签到 | 是否刚自动定采 | 正常,供货单独立作业 |
| 打印成功没出纸 | 已生成张数、序号、打印机 | 按原序号区间重打,不要增量打印 |
| 提示他人正在盘点 | 当前占用人 | 原占用人释放后再开始;无法释放记录账号和单号升级 |
| 扫码返回成功但没加数 | data.success、rejectReason | 区分重复 / 作废 / 跨单,不按外层 code 手工加数 |
| 有产出无法取消 | 扫码记录、商品库存、供货单状态 | 待盘点时评估逐张撤销;其他状态升级处理 |
| 提交盘点失败 | 占用人、是否有产出、少量备注、状态 | 刷新核对在途扫码,不要手工改状态 |
| 混货对不平 | 每个等级「扫码数 − 应结算数」与三种补偿合计 | 补齐漏登的等级或修正扎数;三种方式都参与对平 |
| 线下补偿后对方结算数没加 | 补偿方式是 2 / 3 | 正常,只有登记补款会加 |
| 处理超量后详情仍有差额 | overFlag、处理时间、列表与详情口径 | 详情保留历史差额属正常,不要再扣一次 |
| 到期没结算 | 状态、计划结算时间、overFlag、任务结果、供应商档案 | 超量先处理;并发冲突查日志后重试;超时先查结果 |
| 已结算没收到消息 | 结算字段、95 / 96 账变、消息日志 | 账已成功就查消息,不要再结算 |
| 入库了但商品买不到 | 库存、上下架、价格、主体与规格 | 确认售价并上架,不要重复扫码 |
现场支持可以指导页面正常操作和只读核对。生产补数据、改余额、删标签、清 Redis 锁、批量重跑任务都必须另行确认方案,由开发处理。