/**
* A3 寻源询价的案例模型 —— **双表示同版本**:CMMN XML(机器面)与案例说明书(叙事面)。
*
* 业务出处:`docs/MVP示例工作流.html` §1.7,按 **MVP 简化口径**建模
* (2026-08-02 用户定:A3 与 A2 同为复杂活动,MVP 期间不展开大规模业务建模):
*
* 上游(A2 的询价受理清单,或 A1 直达的 B 类受理记录)进来 → 归一成
* **目标报价清单**底表,A 类行按库内历史价预填基准 → **一张执行单**让采购(PRM)
* 在系统外完成询价、把 B 类行的货源价格填回来 → 汇稿定盘 → 放行,
* 整份目标报价清单交给成本定价。
*
* SOP 里接需核史 / 选渠定策 / 发询比价那几段的实质工作(圈渠道、发函、催回价、
* 验价)在 PRM 系统外;四种场景(BOM早期/后期/现货/样品)的尺度之分是他的判断,
* 不是系统的步。系统的本分:归一、预填、组卡、齐检、留痕。
*
* 上一版(@2.0.0)只有「派单 + 放行」两项,入参必填 `pn + scenario`(单料形状,
* 与上游发的整份清单对不上),两条 L2 判据读活动自报数。这一版整个置换。
*/
export const CMMN_XML = `
update
quote_line_total > 0 and quote_sourcing_quote_list_rows = quote_line_total and hist_priced_total >= 0
update
sourced_total >= 0
update
route_decided_total > 0 and quote_sourcing_quote_list_rows > 0 and quote_sourcing_quote_list_missing = 0 and quote_sourcing_quote_list_price_basis_hist + quote_sourcing_quote_list_price_basis_sourced = quote_sourcing_quote_list_rows
`;
/**
* 案例说明书 —— **只写整单一以贯之的事**(逐步做法归剧本,两处不重复写同一件事)。
*/
export const NARRATIVE = `§0 开案:**一份清单要补齐每一行的价格基准**。来路三种,形状都收(宽进):
· **选型转来**:任务数据里有 \`rows\` 数组 —— 替代选型放行的全部落地行混在一起
(带 alt_pn / 现标的是清单行,带各种总数的是结论行,按 PN 归并自辨);
· **受理直达**:有 \`records\` 数组 —— 受理放行的落地行(受理记录行 + 分类表行 + 结论行);
· **单飞**:只有一段需求文字,列了几颗料要问价。
**这个活动是复杂活动的 MVP 简化形**:询价的实质工作(圈渠道、发函、催回价、验价)
由采购(PRM)在**系统外**完成;四种场景(BOM早期/后期/现货/样品)的尺度是他的判断。
系统只负责:归一清单、**A 类行按库内历史价预填基准**、把执行单组好交给他、
收回后齐检定盘。
**成品只有一样**:一份**目标报价清单** —— 整份行都在、**每一行都有基准价**
(A 类取历史价,B 类取 PRM 问回来的货源价),价源逐行可溯。它是成本定价的直接输入。
**这一单要经过人两次,不多不少**:PRM 在执行单上补货源价(那张单绑着整份清单,
必填空着按不下提交 —— 基座的闸看着,他改的格子也直接落账)、放行时 PRM 签字。
【一路上要说话】负责人正看着这一单。**每一拍都带一句 say** —— 说业务的话:
哪几颗料等着问价、历史价预填了几条、这单接下来到谁手上;不说系统词。
到了要找人的那一拍,先说清这一轮办完了什么、为什么现在需要他。
【怎么把一项干完 · 一拍连做】write 和 tool 都不会自动收步 —— 做完用 finish 宣告。
动作排进同一拍的 actions 串一口气给;只有调工具(出参下一拍才看得见)与
发卡 / 提交(挂起)必须停拍。**这一单常路 6-8 拍就该收口**。
§Z 结案:PRM 在验收单上签字,系统把草稿合并成正式清单并发出 quotation 口的载荷 ——
整份目标报价清单交给成本定价。`;
/**
* 步骤剧本 —— 一个计划项一条;`doneWhen` 是「成果已存在」的判据,不是「该不该做」。
*/
export const SOURCING_STEPS = [
{
item: 'S1_normalize',
intent: '上游清单整份归一成目标报价清单;A 类行按库内历史价预填基准',
writes: ['quote_sourcing.quote_list', 'quote_sourcing.verdict'],
/* 上游载荷数组不声明就会被整表段的截断刀砍掉(按字符截,砍掉的恰是要归一的行) */
reads: ['rows', 'records'],
/* 归一预填与 PRM 补价期间摆**询价工作单**;汇稿定盘后才换收口那张清单 */
view: 'sourcing-worksheet',
tools: ['crm.history-price-read'],
/*
* 归一 + 预填两轮都走完才算办完:行数两边对上,且 hist_priced_total 写过
* (没有 A 类就是 0;S-FEEL 未绑定的名字参与比较为假,所以「没写过」进不来)。
*/
doneWhen: 'quote_line_total > 0 and quote_sourcing_quote_list_rows = quote_line_total and hist_priced_total >= 0',
guide: `第一件事:把这一单的**目标报价清单**落出来,并把 A 类行的基准价预填好。
【料从哪儿来】
· 选型转来(有 \`rows\`):清单行带 pn / alt_pn / type_tag(现标)—— 照抄;
带 alt_line_total 这类总数的是结论行,不是料,别落进清单。
· 受理直达(有 \`records\`):受理记录行(带 eau/brand)为准,type_tag 照抄;
分类表行与结论行不落。**按 pn 归并**,一颗料一行。
· 单飞:照正文归一,列了几颗落几行;没说类别的按 B(要问价的料本来就是 B)。
【第一拍:只做两件事 —— 落清单行 + 串尾发一次查价】
① 写 \`quote_sourcing.quote_list\`,一颗料一行(rows 收数组):
pn(**一个字符不许改**)、customer_pn、category、brand、eau、target_price、lead_time、
**remark(客户备注:认证要求、预授权、急料标注 —— 问价口径的第一手依据,一个字别丢)**、
alt_pn(上游有就承继)、type_tag(照上游现标;单飞按 B)。
supplier / base_price / moq / source_lead_time / note **全部留空** —— 价还没来。
② 串尾调 \`crm.history-price-read\`:pns 收数组,把 **A 类行的取价对象**一次传完 ——
**取价对象 = alt_pn 有值取 alt_pn,否则取 pn**(选型转来的 A 行,行情稳的是替代料)。
**这一拍不写 \`quote_sourcing.verdict\`,一列都不写** —— 尤其 hist_priced_total:
它是「预填走完了」的凭据,提前写等于把闸提前打开,引擎会在下一拍开头当场收掉这一步,
**预填从此不会发生**(实测:A 类行底价空着、执行卡照发,而交代里说着「已预填」——
台账与嘴对不上)。没有 A 类行也一样:查价那一步省掉,直接进第二拍。
【第二拍:预填 A 行基准 + 记账 + 收步,一拍连做】
① 工具出参逐行照抄:hit=true 的 A 行写 base_price = lastPrice、price_basis 写 **HIST**
(大写,一个字母不许差 —— 基座按值现数,写别的数不出来)、note 记一句
「库内历史价 天」;hit=false 的 A 行**别编价** —— base_price 留空,
当 B 类待询处理(pending_total 把它数上;type_tag 不动,那是上游的标)。
② 这时才写 \`quote_sourcing.verdict\`(一次写全):rfq_ref(入参有就原样抄,
没有从主题认,认不出才造「SRC-<型号或类型>」,从头用到尾。
**只从本单来件取材,不许从台账里已有的别单单号里挑** —— 正式表里躺着的
MD14.1 之类是别人的单,借它的号等于把两单的行混进同一个案卷)、
customer_code / customer_name(顶层有就抄)、**quote_line_total** = 清单行数、
**pending_total** = 底价还空着的条数、**hist_priced_total** = 刚预填的条数(0 也要写)。
③ finish 这一项。`,
},
{
item: 'S2_fill',
intent: '一张执行单交 PRM:照询价工作单在系统外询价,供应商与底价就地填回',
writes: ['quote_sourcing.verdict'],
reads: ['quote_sourcing.quote_list'],
view: 'sourcing-worksheet',
tools: [],
/* 不给 doneWhen —— 发卡触达真人(manualActivation),引擎不替人按 */
guide: `清单归一好、A 类基准预填了,**该 PRM 出场了** —— 这是本活动唯一的一张执行单。
工作区摆的是**寻源询价工作单**:逐颗待询料的询价档案(要素/取价对象/客户约束)、
按场景圈渠道的规则、价格验证的尺、发询纪律与时限,填回区就长在上面。
这一步标了人工激活:发卡就算启动,不必单发 start;
引擎也不会替你收 —— 人交回后要你自己 finish。
【照这个骨架发,别少字段】(卡面是纯文本,steps/standard 里**别写星号记号**):
{"kind":"human","itemId":"S2_fill","workOrder":"execution","card":{
"title":"寻源补价:<单号> 待补价 颗",
"ask":"清单里底价空着的行要补货源价格:请照工作单上的场景规则在系统外完成询价,把供应商与底价填回表里对应行;MOQ、货源交期、备注能问到就一并填。",
"steps":["底价空着的行是本单要问价的料 —— 每行必须补上:供应商、底价(未税单价按内部口径归一);取价对象是替代料一栏有值的取替代料,否则取原型号",
"圈渠道按场景走(细则见工作单):BOM早期与样品可放宽;BOM后期按主供应商、备选、贸易商的顺序圈两三家,贸易商尽量不用;现货只选有库存实拍的供应商",
"回价登记一一对应不可缺项:价格、MOQ、交期能问到就填;验价按场景的尺核过再采,不实回价或远低行情的换渠道补询,别直接采用",
"确实问不到价的料,先与负责人商定:在件上把那一行撤掉(剔出本轮),或按内部估价填并在备注写明;A 类行已按库内历史价预填,可校可改"],
"standard":"每一行都有基准价与价源可溯,渠道与验价按场景的尺走过 —— 底价缺一行,这张单按不下提交(系统的闸看着)。",
"basis":[{"k":"<待补价 PN>","v":"<类别与年用量 + 客户约束(认证/急料),取价对象标明>"}]}}
· \`basis\` 逐条列待补价的料:PN + 类别/年用量。几颗写几条,别铺全表。
· **卡上不摆表、不摆格子**(2026-08-02 用户定:填写全在工作区):整份清单就在
工作单那份件上,供应商/底价/MOQ/货源交期/备注五列都能就地改、行能撤 ——
**别往卡里塞 \`blocks\` 或 \`fields\`**,塞了就是同一张表摆两处。
· **这张卡带提交闸**:底价(必填列)还空着,他按不下提交 —— 缺几格、缺在哪行,
闸上与件上的红带都写着(与放行门 L1 同一个数同一套算法)。
发完卡这一拍就结束了(发卡挂起)。
【人交回之后 —— 件上的值基座已经替你写回了】他在件上按「保存」那一刻改动就落进了
草稿层,按「提交」只是把卡交回来。你只做两件事,然后 finish:
① 清点原本底价空着、现在有价的条数,把 **sourced_total** 写进 verdict
(他在件上撤了行也算处置过,照实清点;0 也要写);
② 别再 write 那些行 —— 值没变的写入会被「写了等于没写」拒回。
【这张卡一单只发一次】人交回来之后不许再发同一张卡 —— 必填有提交闸兜着,
卡回来时底价一定是齐的(或那几行已被他撤掉)。`,
},
{
item: 'S3_compile',
intent: '价源逐行归档,齐检定盘:目标报价清单成稿',
writes: ['quote_sourcing.quote_list', 'quote_sourcing.verdict'],
reads: ['quote_sourcing.quote_list'],
view: 'sourcing-roster',
tools: [],
/*
* **收步判据与验收判据同源**:每行有价(基座按 required 现数)、价源守恒
* (基座按值现数)、定盘记账 —— 三样齐才收,松出来的那一截就是返工。
*/
doneWhen:
'quote_sourcing_quote_list_missing = 0 and quote_sourcing_quote_list_price_basis_hist + quote_sourcing_quote_list_price_basis_sourced = quote_sourcing_quote_list_rows and route_decided_total > 0',
guide: `PRM 补回来了,现在把清单**定盘**,一拍连做:
① **价源归档**:PRM 补了价的行(price_basis 还空着的),逐行写 price_basis = **SOURCED**
(大写,一个字母不许差);A 类预填的行已是 HIST,不动。
按 rfq_ref + pn 对行,主键一个字符不许改。
② 若还有行缺底价(他留空又没撤):照他备注的说明办 —— 写明剔除的用 \`drop\`
把那一行撤出本单草稿(主键照 \`_keys\` 名单**原样粘**),撤了哪几颗、为什么写进
verdict.summary,并把 quote_line_total 与 pending_total 改成撤后的实数;
什么说明都没有的,发一张**决策卡(decide)**问负责人「这几颗问不到价,剔出本轮还是退回」,
照答复办。**只问这一次**。
③ 写 verdict:**route_decided_total 记 1**、summary 一句人话
(几行历史价、几行货源价、剔了几颗、整份可交定价)。
④ finish 这一项。引擎按「每行有价 + 价源守恒 + 定盘记过」收步,三样有一样不齐都收不掉。
这一单只有一个出口(交成本定价),**没有去向要选** —— 定盘就是把账写齐。`,
},
{
item: 'T_release',
view: 'sourcing-roster',
intent: '清单已定盘,提交放行交 PRM 验收',
writes: [],
reads: [],
tools: [],
/* 放行触达世界,必须人按一下 —— 引擎不自动收它(剧本里也不给 doneWhen) */
guide: `每行有价、价源守恒、定盘已记 —— 可以走放行了(T_release 人工激活:
动它就算启动,不必单发 start)。先把裁量判据裁掉,然后 submit,同一拍连做:
· judge criterion="货源与价格来源可核:B 类行的供应商与底价来自真实询价或可靠渠道,PRM 对报价负责" ——
看清单里 SOURCED 行的供应商与备注:说得出来源就 satisfied=true;
有行说不出的,satisfied=**false**,rationale 逐行写清,交签字的人定。
**裁成不满足照样能提交** —— 理由连着卡一起交给他。
criterion 照判据名**整句原样抄**,写别的名字对不上。
终局唯放行:你不能自己宣布完成。`,
},
];
/**
* 阶段 —— 进度条的刻度,只给人看。除放行外每个计划项恰属一个阶段;
* 放行那一格由基座统一加,人看到的是 x/4。
*/
export const SOURCING_PHASES = [
{ name: '归一预填', items: ['S1_normalize'] },
{ name: '补货源价', items: ['S2_fill'] },
{ name: '汇稿定盘', items: ['S3_compile'] },
];