Archived
活动:A2 选型 / A3 寻源 / A4 定价 / A6 议价 / A7 归档五件各补成真活动包 —— 契约宽进(input.required 空,归一在活动内)、台账必填声明(含行级 requiredWhen)、 入场哨兵与 L1/L2 判据一律读基座数、两份件(在办可编辑 + 办结静态快照)、 三案例常备、包内自测。e2e 各三案例 released、行动被拒 0、发口正确、提交闸每单真拦。 基座(共享面,改一处影响所有活动,故每处都带回归): · 重发判断走在站上场之前 —— 人答完那步常已收掉,readyToWork 先抛「不能再往它上面挂活」, 于是「重发已答过的卡 = 无事发生」这条唯一活路在最需要时够不着,A1 基线当场熔断; · 决策卡补幂等兜底(与执行工单同一把尺):头两次无事发生,第三次起才算被拒; · 输出没成形先就地重问一次,原话进工作日志、不再摆上卡面; · 工具调用读数 tool_<名>_calls —— 「机检只读基座数」这条纪律第一次覆盖到工具; · 执行卡 steps/standard 补进出参 schema(从前能到卡面全靠厂商 JSON 模式宽松); · 件的就地更新改逐节点 morph,保存先把新值镜像进只读那份 —— 不闪、不等回声。 A1(基线,全程守住):措辞三档对齐(必填/建议/选填)、禁止拿历史价当客户目标价、 卡骨架从步骤剧本搬进说明书(压成一拍连做时剧本没摊开,会发出没有指导书的裸卡)。 契约两处**新增可选字段**(非破坏):FieldDeclaration.requiredWhen、工单 finalHtml; api-report 同批更新。docs/adr 与 docs/archive 的 13 份文件在工作树里不见了, 本次予以恢复而非提交删除。 门禁:typecheck / lint / depcruise / test(1366)全绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
388 lines
27 KiB
TypeScript
388 lines
27 KiB
TypeScript
/**
|
||
* A4 成本定价的案例模型 —— **双表示同版本**:CMMN XML(机器面)与案例说明书(叙事面)。
|
||
*
|
||
* 业务出处:`docs/MVP示例工作流.html` §1.2(S1 取价基准 → S2 逐条定价 → S3 底价自检),
|
||
* 按 A3 同一条形状建模(2026-08-03 重写,@3.0.0):
|
||
*
|
||
* 上游(A3 的目标报价清单 / A2 的询价受理清单 / A1 直达的受理记录)进来 → 归一成
|
||
* **报价草案**底表,逐条按 P-01 利润模型算出底价线与拟报单价、过 P-02 底价门禁 →
|
||
* **一张执行单**交 BD 核价(拟报单价可校可改,无基准的那几行由他定价)→
|
||
* **只有压在拦截档上的那几条才叫人拍板**(决策卡)→ 放行,整份报价草案交定价审批。
|
||
*
|
||
* 上一版(@2.0.0)三处不合现行口径,这一版整个置换:
|
||
* ① 入参必填 `rfqRef + customerCode + records` —— 而 A3 发的是 `{rfqRef, rows}`,
|
||
* 门口拦的恰是主路(现在宽进到底,归一在活动内做);
|
||
* ② 台账一个 `required` 都没有 —— 执行卡的闸没牙,人不填也能交卷;
|
||
* ③ 入场哨兵 `s_priced` 读活动自报的 `draft_total`(「机检只读基座数」第 5 类违反)——
|
||
* 模型不记这个账,门就永不开,而它一步也没做错。
|
||
*/
|
||
|
||
export const CMMN_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
||
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL">
|
||
<case id="pricing">
|
||
<!--
|
||
案卷项的 id **就是任务视图里的键名**。上游载荷(rows / records)与本活动台账列
|
||
都摊平到任务视图顶层,照它们命名;quote_pricing_* 那几个是**基座读数**
|
||
(行数 / 缺必填 / 按值现数),由基座现算,模型碰不着。
|
||
-->
|
||
<caseFileModel>
|
||
<caseFileItem id="rows" name="上游清单行(寻源/选型转来,流内开案即有)"/>
|
||
<caseFileItem id="records" name="上游受理记录(受理直达时有)"/>
|
||
<caseFileItem id="line_total" name="草案条目数(自报)"/>
|
||
<caseFileItem id="priced_total" name="已算出拟报价的条数"/>
|
||
<caseFileItem id="confirmed_total" name="BD 已核价条数(人环走完的凭据)"/>
|
||
<caseFileItem id="route_decided_total" name="已定盘"/>
|
||
<caseFileItem id="quote_pricing_draft_rows" name="草案行数(基座现数)"/>
|
||
<caseFileItem id="quote_pricing_draft_missing" name="缺拟报单价的行数(基座现数)"/>
|
||
<caseFileItem id="quote_pricing_draft_disposition_block" name="压在拦截档的条数(基座现数)"/>
|
||
</caseFileModel>
|
||
<casePlanModel id="plan" name="成本定价" autoComplete="true">
|
||
<!--
|
||
① 算完了 —— 交 BD 核价那一步的入场前提。
|
||
行数两边对上(自报 = 基座现数),且算价那一轮走完(priced_total 是算完之后
|
||
显式写下的数;「大于等于 0」对「写过的 0」为真、对「没写过」为假)。
|
||
-->
|
||
<sentry id="s_priced">
|
||
<onPart id="op_pr" caseFileItemRef="priced_total"><standardEvent>update</standardEvent></onPart>
|
||
<ifPart id="if_pr"><condition>line_total > 0 and quote_pricing_draft_rows = line_total and priced_total >= 0</condition></ifPart>
|
||
</sentry>
|
||
<!--
|
||
② 人定完价了 —— 底价自检那一步的入场前提。
|
||
confirmed_total 只在人交回执行单之后才产生,它就是「经过人了」的凭据。
|
||
-->
|
||
<sentry id="s_confirmed">
|
||
<onPart id="op_cf" caseFileItemRef="confirmed_total"><standardEvent>update</standardEvent></onPart>
|
||
<ifPart id="if_cf"><condition>confirmed_total > 0</condition></ifPart>
|
||
</sentry>
|
||
<!--
|
||
③ **超限才叫人** —— 这个活动的要害。
|
||
「压在拦截档上的条数」由基座按 disposition 的取值域现数(不是活动自报),
|
||
且要等 BD 核过价(confirmed_total 只在人交回执行单之后才产生)——
|
||
他自己回调掉的那几条不必再惊动第二个人。
|
||
-->
|
||
<sentry id="s_over">
|
||
<onPart id="op_ov" caseFileItemRef="quote_pricing_draft_disposition_block"><standardEvent>update</standardEvent></onPart>
|
||
<ifPart id="if_ov"><condition>quote_pricing_draft_disposition_block > 0 and confirmed_total > 0</condition></ifPart>
|
||
</sentry>
|
||
<!--
|
||
── 放行门的入场条件:**认「办完了没有」,且读基座数**────────────────
|
||
· 每行都有拟报单价(quote_pricing_draft_missing 由基座按 required 现数,
|
||
与执行卡的提交闸、验收 L1 同一个数同一套算法);
|
||
· 门禁处置逐条落定且守恒(三档相加 = 行数,两边都是基座按值现数);
|
||
· **没有还压在拦截档上的条目**(要么回调、要么经人拍板改记附理由放行);
|
||
· 定盘过了(route_decided_total 是定盘那一步显式写下的记账数)。
|
||
-->
|
||
<sentry id="s_ready">
|
||
<onPart id="op_rd" caseFileItemRef="route_decided_total"><standardEvent>update</standardEvent></onPart>
|
||
<ifPart id="if_rd"><condition>route_decided_total > 0 and quote_pricing_draft_rows > 0 and quote_pricing_draft_missing = 0 and quote_pricing_draft_disposition_block = 0 and quote_pricing_draft_disposition_pass + quote_pricing_draft_disposition_note + quote_pricing_draft_disposition_block = quote_pricing_draft_rows</condition></ifPart>
|
||
</sentry>
|
||
|
||
<!-- ① 归一草案 + 取基准 + 逐条算价过门禁(能算的不问人) -->
|
||
<humanTask id="S1_price" name="归一报价草案:取成本基准、按利润模型算底价线与建议价">
|
||
<itemControl><repetitionRule id="r_s1"/></itemControl>
|
||
</humanTask>
|
||
|
||
<!--
|
||
② 交 BD 核价 —— **一张执行单**(拟报价可校可改,无基准的行由他定价)。
|
||
manualActivation + 不给 doneWhen(发卡触达真人,引擎不替人按)。
|
||
-->
|
||
<humanTask id="S2_review" name="交BD定价:工作单上逐条定价,收回后过底价门禁">
|
||
<entryCriterion id="ec_s2" sentryRef="s_priced"/>
|
||
<itemControl><manualActivationRule id="m_s2"/></itemControl>
|
||
</humanTask>
|
||
|
||
<!--
|
||
③ 底价自检 —— SOP 里的 S3,一件独立的事:按人定的价算毛利、偏离度、门禁处置。
|
||
它不触达世界,所以给 doneWhen(三档处置的条数加起来等于行数就算判完了),
|
||
引擎自己收 —— 从前这一段藏在「交人核价」的收尾里,模型写完 confirmed_total
|
||
就把那一项收了,三列处置一格没写,放行门当场判「处置没落定」,而拒回只会说
|
||
「数不对/行不对」—— 两扇打不开的门(实测 8 次拒回熔断)。
|
||
-->
|
||
<humanTask id="S3_gate" name="底价自检:按定下的价算毛利与偏离度,逐条过底价门禁">
|
||
<entryCriterion id="ec_s3" sentryRef="s_confirmed"/>
|
||
<itemControl><repetitionRule id="r_s3"/></itemControl>
|
||
</humanTask>
|
||
|
||
<!-- ④ 超限拍板:触达客户利益的那一下,必须人工激活;只在拦截档还有条目时入场 -->
|
||
<humanTask id="T_approve" name="超限拍板:压在拦截档的条目要人定怎么办">
|
||
<entryCriterion id="ec_ap" sentryRef="s_over"/>
|
||
<itemControl><manualActivationRule id="m_ap"/><repetitionRule id="r_ap"/></itemControl>
|
||
</humanTask>
|
||
|
||
<!-- 草案放行:终局唯放行 —— 触达世界,必须人工激活 -->
|
||
<humanTask id="T_release" name="报价草案验收放行">
|
||
<entryCriterion id="ec_rel" sentryRef="s_ready"/>
|
||
<itemControl><manualActivationRule id="m_rl"/></itemControl>
|
||
</humanTask>
|
||
</casePlanModel>
|
||
</case>
|
||
</definitions>`;
|
||
|
||
/**
|
||
* 案例说明书 —— **只写整单一以贯之的事**(逐步做法归剧本,两处不重复写同一件事)。
|
||
*/
|
||
export const NARRATIVE = `§0 开案:**一批料要定出各自的拟报单价**。来路三种,形状都收(宽进):
|
||
· **寻源转来**:任务数据里有 \`rows\` 数组 —— 目标报价清单的落地行,每行带底价(base_price)
|
||
与价源;这是最全的一种来路;
|
||
· **受理/选型直达**:有 \`records\` 或 \`rows\` 而行上没有底价 —— 只有料号与年用量;
|
||
· **单飞**:只有一段需求文字,列了几颗料要报价。
|
||
|
||
**成品只有一样**:一份**报价草案** —— 整份行都在、**每一行都有拟报单价**,
|
||
而且每个价都说得出来路:基准从哪来、毛利档是哪一档、偏离底价线多少、门禁怎么判。
|
||
人签的不是一个数字,是**这个数字的来路**。它是定价审批的直接输入。
|
||
|
||
**能算的不问人,该人签的不代签**:P-01(利润模型)给毛利档、P-02(底价门禁)给处置,
|
||
两支判定表说了算,你不临场拍价;而**拟报单价那一列是 BD 定的,你一格都不写** ——
|
||
你给的是**建议价**,他确认或改成自己的数。你的活是把判据取齐、把结论落进台账。
|
||
|
||
**四步走**:归一取基准算建议价 → 交 BD 定价 → 底价自检(按他定的价算毛利、偏离度、
|
||
门禁处置)→ 定盘放行。
|
||
|
||
**这一单要经过人一到两次**:BD 在定价工作单上逐条定价(那张单绑着整份草案,
|
||
拟报单价缺一行按不下提交 —— 基座的闸看着,他填的格子直接落账);
|
||
**只有还压在拦截档上的条目才另外叫人拍板**(一张决策卡)。每条都叫人,人就成了橡皮图章;
|
||
一条都不叫,底价门禁就是摆设。最后 BD 放行签字。
|
||
|
||
【一路上要说话】负责人正看着这一单。**每一拍都带一句 say** —— 说业务的话:
|
||
这批料算下来什么价、哪几条压线、要不要找人拍板;不说系统词。
|
||
到了要找人的那一拍,先说清这一轮办完了什么、为什么现在需要他。
|
||
|
||
【怎么把一项干完 · 一拍连做】write 和 tool 都不会自动收步 —— 做完用 finish 宣告。
|
||
动作排进同一拍的 actions 串一口气给;只有调工具(出参下一拍才看得见)与
|
||
发卡 / 提交(挂起)必须停拍。**这一单常路 7-9 拍就该收口**。
|
||
|
||
§Z 结案:BD 在验收单上签字,系统把草稿合并成正式草案并发出 draft 口的载荷 ——
|
||
整份报价草案交给定价审批。`;
|
||
|
||
/**
|
||
* 步骤剧本 —— 一个计划项一条;`doneWhen` 是「成果已存在」的判据,不是「该不该做」。
|
||
*
|
||
* 三处不给 `doneWhen`:`S2_review`(发卡触达真人)、`T_approve`(要人拍板)、
|
||
* `T_release`(签下去触达世界)—— 给了等于给引擎一把替人签字的钥匙。
|
||
*/
|
||
export const PRICING_STEPS = [
|
||
{
|
||
item: 'S1_price',
|
||
intent: '整份归一成报价草案:取成本基准 → 按利润模型算出底价线与建议价,逐条落表',
|
||
writes: ['quote_pricing.draft', 'quote_pricing.verdict'],
|
||
/* 上游载荷数组不声明就会被整表段的截断刀砍掉(砍掉的恰是要归一的行) */
|
||
reads: ['rows', 'records'],
|
||
view: 'pricing-worksheet',
|
||
tools: ['crm.history-price-read'],
|
||
/*
|
||
* 归一 + 算价两轮都走完才算办完:行数两边对上(一边是基座现数),
|
||
* 且 priced_total 写过(全是无基准的单子这个数就是 0;S-FEEL 未绑定的名字
|
||
* 参与比较为假,所以「没写过」进不来)。
|
||
*/
|
||
doneWhen: 'line_total > 0 and quote_pricing_draft_rows = line_total and priced_total >= 0',
|
||
guide: `第一件事:把这一单的**报价草案**落出来,并把能算的价都算出来。
|
||
|
||
【料从哪儿来】
|
||
· 寻源转来(\`rows\` 里的行带 base_price / price_basis):照抄 —— 底价就是成本基准,
|
||
一个数字都别改;带 quote_line_total 这类总数的是结论行,不是料,别落进草案。
|
||
· 受理/选型直达(\`records\` 或没有底价的 \`rows\`):料号、品类、制造商、年用量、
|
||
客户目标价、类别(type_tag)照抄,**底价一栏留空**。
|
||
· 单飞:照正文归一,列了几颗落几行;没说类别的按 B。
|
||
**按 pn 归并,一颗料一行**;pn 一个字符不许改(它是主键,改一个字就是新开一行)。
|
||
|
||
【第一拍:只做两件事 —— 落草案行 + 串尾发一次查价】
|
||
① 写 \`quote_pricing.draft\`,一颗料一行(rows 收数组):
|
||
rfq_ref(入参有就原样抄;没有从主题认;认不出才自己造一个,**造出来的必须以 \`PRC-\` 开头**
|
||
(\`PRC-<主题或第一颗料的型号>\`)。两条硬规矩:
|
||
**① 整单只有一个单号,不是一颗料一个** —— 它是这一单的案号,草案所有行、verdict 那一行
|
||
用的都得是同一个串(实测栽过:两颗料造出两个号,一单裂成两单);
|
||
**② 只从本单来件取材** —— 台账里躺着的 RFQ-xxxx 是别人的单,借它的号等于把两单的行
|
||
混进同一个案卷(实测栽过一轮))、pn、customer_pn、category、
|
||
brand、eau、target_price(客户目标价)、lead_time、remark(客户约束/急料,一个字别丢)、
|
||
type_tag(照上游现标;单飞按 B)、base_price(上游给了就抄,没有留空)。
|
||
suggested_price / margin_band / floor_price **这一拍全部留空** —— 基准还没取齐。
|
||
**quoted_price / margin / deviation / disposition 这四列从头到尾都不是你写的**(见下)。
|
||
② 串尾调 \`crm.history-price-read\`:pns 收数组,把**底价还空着的那几颗料**一次传完
|
||
(上游已经给了底价的不必查)。
|
||
**这一拍不写 \`quote_pricing.verdict\`,一列都不写** —— 尤其 priced_total:
|
||
它是「算价走完了」的凭据,提前写等于把闸提前打开,引擎会在下一拍开头当场收掉这一步,
|
||
**算价从此不会发生**(A3 实测栽过:嘴上说预填了,台账里没有)。
|
||
|
||
【**这一列你一格都不写**:quoted_price】
|
||
拟报单价是 **BD 在工作单上定的那个数** —— 人签的就是它。你给的是**建议价**
|
||
(suggested_price),他确认或改成自己的数;margin / deviation / disposition 三列
|
||
要等他定完价才算得出来,这一步也别写。
|
||
这不是客气话:从前只有一列价、剧本写着「算不出的留空」,实测跑单时两颗库里查不到的料
|
||
照样被编出了价(一颗抄客户目标价、一颗凭空写了个数),而交代里还说着「价空着等你定」。
|
||
**一条要你分辨「这行算得出/算不出」的规矩会走岔;「这一列不写」没有分支可走岔。**
|
||
|
||
【第二拍:算建议价 + 记账 + 收步,一拍连做】
|
||
① 补基准:**只补上一拍 base_price 空着的那几行** —— 工具出参里 hit=true 的写
|
||
base_price = lastPrice、price_basis 写 **HIST**;hit=false 的**别编价**,base_price 留空,
|
||
它就是「无基准」那一档。
|
||
**上游已经给了 base_price 的行:工具回什么都不采用,那一格一个数字都别改** ——
|
||
上游给的是本单问回来的货源底价,工具给的是库内历史价;这一单的成本是前者
|
||
(实测栽过:两行上游底价被历史价盖掉,毛利从 20% 变成 115%,数字全对而结论是假的)。
|
||
② 逐条算**建议价**,规矩写死,照做即可(**这些是算术,不是判断**):
|
||
· 毛利档 margin_band 按利润模型 P-01 取(客户等级 × 类别):
|
||
战略客户 + A 类(大批量长单)→ 8%~10%;普通客户 + A 类 → 12%~15%;
|
||
B 类 → 15%~20%;C 类 → 20%~50%;拿不准按 12%~15%。写成「12%~15%」这样的文本。
|
||
· **底价线** floor_price = base_price ×(1 + 档下限)。保留四位小数。
|
||
· **建议价** suggested_price:
|
||
- 客户没给目标价(target_price 空)→ 取 base_price ×(1 + 档上限);
|
||
- 客户目标价 ≥ 底价线 → 就取客户目标价(接得住,毛利还在档内);
|
||
- 客户目标价 < 底价线 → 仍取客户目标价(贴着客户报),这一条到门禁那儿会亮灯;
|
||
- **base_price 空(无基准)→ margin_band / floor_price / suggested_price 三列一起留空**。
|
||
不要拿一个不相干的价去凑一个数出来 —— 那比没有建议更危险,它看起来像有依据。
|
||
· **「没有」要给空串 \`""\`,不许写 0** —— 0 是一个数,底价线写 0 看起来像「成本为零」,
|
||
偏离度写 0 看起来像「正好压在底价线上」。空串基座会当成「这一列不写」。
|
||
③ 这时才写 \`quote_pricing.verdict\`(一次写全):rfq_ref、customer_code / customer_name
|
||
(顶层有就抄)、customer_grade(来件认得出就写,认不出写「普通客户」)、
|
||
**line_total** = 草案行数、**basis_total** = 有成本基准的条数、
|
||
**priced_total** = 这一拍算出建议价的条数(0 也要写)。
|
||
④ finish 这一项。`,
|
||
},
|
||
{
|
||
item: 'S2_review',
|
||
intent: '一张执行单交 BD:工作单上逐条定价(拟报单价归他);收回后过底价门禁并定盘',
|
||
writes: ['quote_pricing.draft', 'quote_pricing.verdict'],
|
||
reads: ['quote_pricing.draft'],
|
||
view: 'pricing-worksheet',
|
||
tools: [],
|
||
/* 不给 doneWhen —— 发卡触达真人(manualActivation),引擎不替人按 */
|
||
guide: `建议价算完了,**该 BD 出场了** —— 这是本活动唯一的一张执行单,
|
||
**拟报单价是他定的,不是你定的**。工作区摆的是**定价工作单**:逐颗料一张定价档案卡
|
||
(成本基准、毛利档、客户目标价、底价线、系统建议价),利润模型与底价门禁两把尺挂在上面,
|
||
填回区长在同一屏 —— 他在「拟报单价」那一列逐行填(照建议价确认,或改成自己的数)。
|
||
|
||
这一步标了人工激活:发卡就算启动,不必单发 start;引擎也不会替你收 —— 人交回后要你自己 finish。
|
||
|
||
【照这个骨架发,别少字段】(卡面是纯文本,steps/standard 里**别写星号记号**):
|
||
{"kind":"human","itemId":"S2_review","workOrder":"execution","card":{
|
||
"title":"报价定价:<单号> 共 <N> 条待你定价",
|
||
"ask":"系统已按成本基准与利润模型算出每一颗的建议价,请在工作单的「拟报单价」一列逐行定价:认可建议价就照抄,不认可就改成你的数;库内没有成本基准的那几行没有建议价,由你定。",
|
||
"steps":["拟报单价每一行都要有 —— 缺一行这张单按不下提交;它是这一单最后签下去的那个数,系统不替你填",
|
||
"建议价是从成本基准按利润模型的毛利档推出来的:照抄就是认可这个毛利,改高改低都可以,改了在备注里写一句缘由",
|
||
"低于底价线的价会被底价门禁标出来:两成以内附理由即可放行,超过两成的要另外找人拍板 —— 你在这里往上调一点,就不必再惊动一个人",
|
||
"库内查不到成本的料没有建议价:按你的经验定价,并在备注写明依据;实在定不了的按行首 × 把这一条撤出本轮"],
|
||
"standard":"每一行都有拟报单价,而且每个价都说得出来路(基准 / 毛利档 / 让价理由)—— 缺一行这张单按不下提交(系统的闸看着)。",
|
||
"basis":[{"k":"<PN>","v":"<类别 · 成本基准 · 毛利档 · 建议价>"}]}}
|
||
· \`basis\` 逐条列本单的料:PN + 基准与建议价。几颗写几条,别铺全表。
|
||
· **卡上不摆表、不摆格子**(执行卡零输入):整份草案就在工作单那份件上,
|
||
拟报单价与备注两列都能就地改、行能撤 —— **别往卡里塞 \`blocks\` 或 \`fields\`**。
|
||
· **这张卡带提交闸**:拟报单价(必填列)还空着,他按不下提交 —— 缺几格、缺在哪行,
|
||
闸上与件上的红带都写着(与放行门 L1 同一个数同一套算法)。
|
||
发完卡这一拍就结束了(发卡挂起)。
|
||
|
||
【人交回之后 —— 他填的价基座已经替你写回台账了】这一步你只做两件事,然后 finish:
|
||
① 写 verdict:**confirmed_total** = 他定过价的条数(照草案行数记);
|
||
他在件上撤掉了行的话,**line_total 跟着改成撤后的实数**。
|
||
② finish 这一项。
|
||
**别在这一拍算门禁** —— 底价自检是下一步的活(它有自己的一段做法),这里算了也白算。
|
||
草案行你一列都不用重写:他填的值基座已经落进台账了,重写会被「写了等于没写」拒回。
|
||
|
||
【这张卡一单只发一次】人交回来之后不许再发同一张卡 —— 必填有提交闸兜着,
|
||
卡回来时拟报单价一定是齐的(或那几行已被他撤掉)。`,
|
||
},
|
||
{
|
||
item: 'S3_gate',
|
||
intent: '底价自检:按人定下的价逐条算毛利、偏离度与门禁处置,判完即定盘',
|
||
writes: ['quote_pricing.draft', 'quote_pricing.verdict'],
|
||
reads: ['quote_pricing.draft'],
|
||
view: 'pricing-worksheet',
|
||
tools: [],
|
||
/*
|
||
* **收步判据与验收判据同源**:三档处置的条数加起来等于行数(两边都是基座现数)——
|
||
* 判完了才算办完。`_rows > 0` 那一半不能省:开案时行数是 0,而 0+0+0 = 0
|
||
* 会让这一步开局即收(未绑定名字的坑之外,还有「全零相等」这一坑)。
|
||
*/
|
||
doneWhen:
|
||
'quote_pricing_draft_rows > 0 and quote_pricing_draft_disposition_pass + quote_pricing_draft_disposition_note + quote_pricing_draft_disposition_block = quote_pricing_draft_rows',
|
||
guide: `人把价定完了,**现在才轮到算门禁** —— 这一步是纯算术,一拍连做:
|
||
|
||
① **逐行按他定的 quoted_price 算三列**(**quoted_price 你一格都不写,只写这三列**):
|
||
· margin =(quoted_price − base_price)/ base_price,四位小数;
|
||
· **偏离度** deviation =(quoted_price − floor_price)/ floor_price,四位小数;
|
||
· **门禁处置** disposition 按底价门禁 P-02 判,只许写这三个大写码之一,一个字母不许差:
|
||
- deviation ≥ 0 → **PASS**(在底价线之上,直接放行)
|
||
- −0.20 ≤ deviation < 0 → **NOTE**(低于底价线两成以内,附理由放行)
|
||
- deviation < −0.20 → **BLOCK**(低于两成以上,压在拦截档,要人拍板)
|
||
· **base_price 空(无基准)的行**:margin / deviation 给空串 \`""\`(**不许写 0** ——
|
||
0 看起来像「正好压在底价线上」,而这一行压根没有底价线)、disposition 记 **NOTE**,
|
||
price_note 里保留他写的定价依据(他没写就补一句「库内无成本基准,由 BD 定价」)。
|
||
**一行都不能漏**:三档处置的条数加起来必须等于 quote_pricing_draft_rows(基座数的行数)。
|
||
现在三档都是 0,就是一行都还没判 —— 这一步没办完,放行门开不了。
|
||
② 看这一拍写完之后的**拦截档条数**(disposition = BLOCK 的行):
|
||
· 一条都没有 → 同一拍把 verdict 的 **route_decided_total 记 1**(定盘)、
|
||
summary 写一句人话(几条直接放行、几条附理由),然后 finish 这一项;
|
||
· 还有 → **别写 route_decided_total**,只 finish 这一项 —— 下一拍会有一步专门叫人拍板。`,
|
||
},
|
||
{
|
||
item: 'T_approve',
|
||
intent: '压在拦截档的条目要人拍板 —— 发一张决策卡,照他选的那条路把草案改掉',
|
||
writes: ['quote_pricing.draft', 'quote_pricing.verdict'],
|
||
reads: ['quote_pricing.draft'],
|
||
view: 'pricing-roster',
|
||
tools: [],
|
||
/* 人工激活 + 要人拍板 —— 不给 doneWhen,引擎不许替人收 */
|
||
guide: `**这一单只发一张决策卡。动手之前先分清你在哪一半:**
|
||
|
||
· 轨迹里**已经有**「decision 卡回传」/「人选了:xxx」—— 那就跳到下面【人点完之后】那一段,
|
||
照他选的那条路改草案、写 route_decided_total、finish。**一个 decide 都不许再发**
|
||
(实测栽过:人点完了,而这一步又从头念了一遍「发一张决策卡」,同一张卡连发四次,
|
||
调人预算烧光,单子 exhausted —— 他点过的那一下就白点了);
|
||
· 轨迹里**还没有** —— 才轮到下面【发一张决策卡】那一段。
|
||
|
||
这一步只在还有条目压在拦截档(基座现数 quote_pricing_draft_disposition_block > 0)时入场;
|
||
它触达客户利益,标了人工激活:发卡就算启动,不必单发 start。
|
||
工作区这时摆的是**报价草案清单**,整份草案与门禁分布都在上面,他看得见全局再拍板。
|
||
|
||
【发一张决策卡,照这个骨架】(选项少于两个基座拒发):
|
||
{"kind":"decide","itemId":"T_approve","ask":"<N> 条低于底价线两成以上,按哪条路办?",
|
||
"options":[
|
||
{"value":"floor","label":"回调到底价线报","consequence":"守住毛利下限,客户可能不接受这个价","recommended":true},
|
||
{"value":"as-is","label":"照现价破线报,附理由","consequence":"接住客户目标价拿单,毛利跌破下限,理由随草案交审批"},
|
||
{"value":"drop","label":"这几条本轮不报","consequence":"撤出本单草案,客户拿到的是一份缺项的报价"}],
|
||
"basis":[{"k":"<PN>","v":"成本基准 <X> · 底价线 <Y> · 拟报 <Z> · 偏离 <W>"}]}
|
||
· basis 逐条摆压在拦截档的那几颗料:基准、底价线、拟报价、偏离度 —— 裸卡基座拒发。
|
||
· 发完这一拍就结束了(发卡挂起)。
|
||
|
||
【人点完之后】轨迹上会出现「decision 卡回传 —— 人选了:xxx」。**照那条路把草案改掉,
|
||
别再发第二张卡**,一拍连做:
|
||
· 选 floor:**这是全活动唯一一次你可以写 quoted_price** —— 那个数不是你定的,
|
||
是他在卡上点下的(就是该行的底价线),你只是替他落账:
|
||
那几行 quoted_price 改成本行的 floor_price,margin 记该行毛利档的下限、deviation 记 0、
|
||
disposition 改 **PASS**,price_note 写「按底价线回调,由负责人拍板」;
|
||
· 选 as-is:价不动,disposition 改 **NOTE**,price_note 写明破线的理由与拍板人;
|
||
· 选 drop:用 \`drop\` 把那几行撤出本单草稿(主键照 \`quote_pricing_draft_keys\` 名单**原样粘**),
|
||
并把 verdict 的 line_total 改成撤后的实数。
|
||
然后写 verdict:**route_decided_total 记 1**、summary 补一句拍板结果,finish 这一项。
|
||
拦截档清零之后,放行门才开得了。`,
|
||
},
|
||
{
|
||
item: 'T_release',
|
||
intent: '草案已定盘,提交放行交 BD 验收',
|
||
writes: [],
|
||
reads: [],
|
||
view: 'pricing-roster',
|
||
tools: [],
|
||
/* 放行触达世界,必须人按一下 —— 引擎不自动收它(剧本里也不给 doneWhen) */
|
||
guide: `每行有价、门禁处置守恒、拦截档清零、定盘已记 —— 可以走放行了
|
||
(T_release 人工激活:动它就算启动,不必单发 start)。先把裁量判据裁掉,然后 submit,同一拍连做:
|
||
|
||
· judge criterion="报价的来路说得清:基准价来源、毛利档与让价理由逐条可溯,BD 对报价负责" ——
|
||
看草案里每一行的基准、毛利档与备注:说得出来路就 satisfied=true;
|
||
有行说不出的(比如无基准由人定的价没写缘由),satisfied=**false**,rationale 逐行写清,
|
||
交签字的人定。**裁成不满足照样能提交** —— 理由连着卡一起交给他。
|
||
criterion 照判据名**整句原样抄**,写别的名字对不上。
|
||
|
||
终局唯放行:你不能自己宣布完成。`,
|
||
},
|
||
];
|
||
|
||
/**
|
||
* 阶段 —— 进度条的刻度,只给人看。除放行外每个计划项恰属一个阶段;
|
||
* 放行那一格由基座统一加,人看到的是 x/4。
|
||
*/
|
||
export const PRICING_PHASES = [
|
||
{ name: '取基准算建议价', items: ['S1_price'] },
|
||
{ name: '交BD定价', items: ['S2_review'] },
|
||
{ name: '底价自检', items: ['S3_gate'] },
|
||
{ name: '超限拍板', items: ['T_approve'] },
|
||
];
|