Archived
A2-A7 全部补齐到验收线;顺手把几处「门拦住却不给路」的坑填了
活动: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>
This commit is contained in:
@@ -1,115 +1,441 @@
|
||||
/**
|
||||
* A6 报价议价的案例模型 —— **发出去是触达世界的一下,等回音是立监听**
|
||||
* (2026-07-31 照 A1 的状态机模式重做)。
|
||||
* A6 报价议价的案例模型 —— **双表示同版本**:CMMN XML(机器面)与案例说明书(叙事面)。
|
||||
*
|
||||
* 这个活动的要害不是步数,是**两处不可省的边界**:
|
||||
* · 发正式报价单 = 触达外界 → 必须人工激活(铁律③ / AM 4.1);
|
||||
* · 客户什么时候回是**外界的事** → 立监听等它,不在这一单里轮询、也不假装等到了。
|
||||
* 业务出处:`docs/MVP示例工作流.html` §1.4(S1 发报留档 → S2 跟进议价 → S3 定案交接),
|
||||
* 按 A4 同一条形状建模(2026-08-03 重写 @3.0.0):
|
||||
*
|
||||
* 三项:
|
||||
* T_compose —— 把草案落成正式报价单(条款齐全),写进台账;
|
||||
* T_send —— 发出并等回音:人工激活 → 登记发信意向 + 立监听;
|
||||
* T_release —— 放行(人工激活),三个去向由输出选择组给出。
|
||||
* 上游(A5 批准的报价草案,A4 `draft` 口的载荷 `{rfqRef, customerCode, items}`)进来 →
|
||||
* 归一成**正式报价函**底表(逐条条款齐备 + 按 P-04 注明有效期)→ **一张执行单**
|
||||
* 交 BD:把报价函发给客户,回音回来后逐条落单(客户表态那一列 AI 一格都不写)→
|
||||
* 按议价结果 N-01 逐条定案(接受 / 还价 / 不成交)→ **只有还价那几条才叫人拍板**
|
||||
* (决策卡:照客户价成交 / 退回定价重批 / 守住现价)→ 放行,去向由三口的谓词算出来。
|
||||
*
|
||||
* 上一版(@2.1.0)四处不合现行口径,这一版整个置换:
|
||||
* ① 入参必填 `rfqRef + customerCode + items` —— 而宽进严出是全线口径,归一在活动内做;
|
||||
* ② 三条 L1/L2 判据读的是活动自报的 `missing_field_total` / `validity_days` /
|
||||
* `followup_total` —— 「机检只读基座数得出来的数」违反史第六类;
|
||||
* ③ 台账一个 `required` 都没有 —— 执行卡的闸没牙,人不填也能交卷;
|
||||
* ④ 三个出口没有 `when`:往哪走要模型自己选,而**去向该是算出来的**。
|
||||
*
|
||||
* 【为什么没有 `listen` 动作】等客户回音这一段落在**执行工单**上,不落 `listen`:
|
||||
* `listen` 在引擎里恒挂起(status: 'awaiting'),要外部事件才唤得醒;而这一单里
|
||||
* 「客户回了什么」的落单人本来就是 BD(他从自己的邮箱收信,再把结论录进系统)——
|
||||
* MVP 示例工作流 §1.4 的 S1「生成发出」与 S2「记录反馈」写的也都是**人工任务**。
|
||||
* 时限那一侧照旧硬约束:`declarations.listeners` 三条静态监听(D+3 催 / D+7 到期 /
|
||||
* 客户回音)由基座在开案那一刻注册,时限必配 —— 「无来源又无时限的等待」一条都没有。
|
||||
*/
|
||||
|
||||
export const CMMN_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL">
|
||||
<case id="negotiate">
|
||||
<!--
|
||||
案卷项的 id **就是任务视图里的键名**。上游载荷(items)与本活动台账列都摊平到
|
||||
任务视图顶层,照它们命名;quote_negotiate_* 那几个是**基座读数**
|
||||
(行数 / 缺必填 / 按值现数),由基座现算,模型碰不着。
|
||||
-->
|
||||
<caseFileModel>
|
||||
<caseFileItem id="quote_no" name="报价单号(开案即有)"/>
|
||||
<caseFileItem id="quote_total" name="报价行条数"/>
|
||||
<caseFileItem id="items" name="上游报价草案条目(已批准,流内开案即有)"/>
|
||||
<caseFileItem id="line_total" name="报价函条数(自报)"/>
|
||||
<caseFileItem id="composed_total" name="已排版落表的条数(排版走完的凭据)"/>
|
||||
<caseFileItem id="replied_total" name="已落客户回音的条数(人环走完的凭据)"/>
|
||||
<caseFileItem id="route_decided_total" name="已定案"/>
|
||||
<caseFileItem id="quote_negotiate_line_rows" name="报价函行数(基座现数)"/>
|
||||
<caseFileItem id="quote_negotiate_line_missing" name="缺客户表态的行数(基座现数)"/>
|
||||
<caseFileItem id="quote_negotiate_line_deal_status_haggle" name="还价了但还没拍板的条数(基座现数)"/>
|
||||
<caseFileItem id="quote_negotiate_line_reply_type_counter" name="客户还了价的条数(基座现数 —— 客户自己那一格)"/>
|
||||
</caseFileModel>
|
||||
<casePlanModel id="plan" name="报价议价" autoComplete="true">
|
||||
<!--
|
||||
① 排版完了 —— 交 BD 发出那一步的入场前提。
|
||||
行数两边对上(自报 = 基座现数),且排版那一轮走完(composed_total 是排完之后
|
||||
显式写下的数;「大于等于 0」对「写过的 0」为真、对「没写过」为假)。
|
||||
-->
|
||||
<sentry id="s_composed">
|
||||
<onPart id="op_cp" caseFileItemRef="quote_total"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_cp"><condition>quote_total > 0</condition></ifPart>
|
||||
<onPart id="op_cp" caseFileItemRef="composed_total"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_cp"><condition>line_total > 0 and quote_negotiate_line_rows = line_total and composed_total >= 0</condition></ifPart>
|
||||
</sentry>
|
||||
<!--
|
||||
② 回音齐了 —— 逐条定案那一步的入场前提。
|
||||
replied_total 只在人交回执行单之后才产生,它就是「经过人了」的凭据;
|
||||
缺表态的行数由基座按 required 现数(与执行卡的提交闸、放行门 L1 同一个数)。
|
||||
-->
|
||||
<sentry id="s_replied">
|
||||
<onPart id="op_rp" caseFileItemRef="replied_total"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_rp"><condition>replied_total > 0 and quote_negotiate_line_rows > 0 and quote_negotiate_line_missing = 0</condition></ifPart>
|
||||
</sentry>
|
||||
<!--
|
||||
③ **还价才叫人** —— 这个活动的要害(与 A4「超限才叫人」同一形状)。
|
||||
|
||||
它读的是**客户自己那一格**(reply_type = COUNTER 的条数,基座按取值域现数),
|
||||
不是模型判出来的 deal_status。两版都栽过,病根是同一个 ——
|
||||
**「该不该叫人」不能由被叫的那一方说了算**:
|
||||
· 一版读 deal_status = HAGGLE,而 revise 那条路让「定案不动」,人点完了那个数
|
||||
还在,哨兵照旧成立,模型读同一段做法就再发一张卡(同一张连发六次);
|
||||
· 修成「拍板必须清 HAGGLE」之后,模型改在定案那一步**直接写 REVISE** ——
|
||||
HAGGLE 一条没有,这道门整个不开,单子一路 released 而没人拍过板
|
||||
(实测:决策卡 0 张,让步梯度成了摆设)。
|
||||
现在钉在客户填的那一格上:客户还了价,这一步就必须入场,模型绕不过去。
|
||||
-->
|
||||
<sentry id="s_haggle">
|
||||
<onPart id="op_hg" caseFileItemRef="quote_negotiate_line_reply_type_counter"><standardEvent>update</standardEvent></onPart>
|
||||
<ifPart id="if_hg"><condition>quote_negotiate_line_reply_type_counter > 0 and replied_total > 0</condition></ifPart>
|
||||
</sentry>
|
||||
<!--
|
||||
── 放行门的入场条件:**认「办完了没有」,且读基座数**────────────────
|
||||
· 每条都有客户表态(quote_negotiate_line_missing 由基座按 required 现数);
|
||||
· 定案逐条落定且守恒(四档相加 = 行数,两边都是基座按值现数);
|
||||
· **没有还压在 HAGGLE 上的条目**(还价的要么接、要么退回重批、要么守价不让);
|
||||
· 定案过了(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_negotiate_line_rows > 0 and quote_negotiate_line_missing = 0 and quote_negotiate_line_deal_status_haggle = 0 and quote_negotiate_line_deal_status_won + quote_negotiate_line_deal_status_haggle + quote_negotiate_line_deal_status_revise + quote_negotiate_line_deal_status_lost = quote_negotiate_line_rows</condition></ifPart>
|
||||
</sentry>
|
||||
|
||||
<!-- 落正式报价单:条款齐全才叫一份能发出去的件 -->
|
||||
<humanTask id="T_compose" name="落正式报价单:条款齐全,逐条落台账">
|
||||
<itemControl><repetitionRule id="r_cp"/></itemControl>
|
||||
<!-- ① 归一报价函:逐条条款齐备 + 按 P-04 注明有效期(能算的不问人) -->
|
||||
<humanTask id="S1_compose" name="落正式报价函:逐条条款齐备,按报价有效期注明到期日">
|
||||
<itemControl><repetitionRule id="r_s1"/></itemControl>
|
||||
</humanTask>
|
||||
|
||||
<!-- 发出并等回音:**触达外界**,必须人工激活 -->
|
||||
<humanTask id="T_send" name="发出报价并等客户回音">
|
||||
<entryCriterion id="ec_sd" sentryRef="s_composed"/>
|
||||
<itemControl><manualActivationRule id="m_sd"/><repetitionRule id="r_sd"/></itemControl>
|
||||
<!--
|
||||
② 发出去并把回音落回来 —— **一张执行单**(触达客户的那一下由人做)。
|
||||
manualActivation + 不给 doneWhen(发卡触达真人,引擎不替人按)。
|
||||
-->
|
||||
<humanTask id="S2_send" name="发出报价函并落客户回音:工作单上逐条落表态">
|
||||
<entryCriterion id="ec_s2" sentryRef="s_composed"/>
|
||||
<itemControl><manualActivationRule id="m_s2"/></itemControl>
|
||||
</humanTask>
|
||||
|
||||
<!--
|
||||
③ 逐条定案 —— SOP 里的 S3,一件独立的事:按客户表态判成交 / 还价 / 不成交,
|
||||
还价的再按让步梯度 N-02 给出处置建议。它不触达世界,所以给 doneWhen,
|
||||
引擎自己收 —— 从前这一段藏在「等回音」的收尾里,模型写完 replied_total
|
||||
就把那一项收了,定案一格没写,放行门当场判「定案没落定」而拒回只会说
|
||||
「数不对/行不对」——两扇打不开的门(A4 实测 8 次拒回熔断)。
|
||||
-->
|
||||
<humanTask id="S3_settle" name="逐条定案:按客户表态判成交/待拍板/不成交,还价的给让步处置">
|
||||
<entryCriterion id="ec_s3" sentryRef="s_replied"/>
|
||||
<itemControl><repetitionRule id="r_s3"/></itemControl>
|
||||
</humanTask>
|
||||
|
||||
<!-- ④ 异议拍板:让价触达公司利益的那一下,必须人工激活;只在还有还价条目时入场 -->
|
||||
<humanTask id="T_haggle" name="异议拍板:客户还的价接不接,要人定">
|
||||
<entryCriterion id="ec_hg" sentryRef="s_haggle"/>
|
||||
<itemControl><manualActivationRule id="m_hg"/><repetitionRule id="r_hg"/></itemControl>
|
||||
</humanTask>
|
||||
|
||||
<!-- 议价结果放行:终局唯放行 —— 触达世界,必须人工激活 -->
|
||||
<humanTask id="T_release" name="议价结果验收放行">
|
||||
<entryCriterion id="ec_rel" sentryRef="s_composed"/>
|
||||
<entryCriterion id="ec_rel" sentryRef="s_ready"/>
|
||||
<itemControl><manualActivationRule id="m_rl"/></itemControl>
|
||||
</humanTask>
|
||||
</casePlanModel>
|
||||
</case>
|
||||
</definitions>`;
|
||||
|
||||
export const NARRATIVE = `§0 开案:拿到报价草案即开案。成品是**一份发出去的正式报价单**,外加一个明确的结果
|
||||
(成交 / 有异议 / 拒绝)—— 那三个去向由放行时的选择组定。
|
||||
/**
|
||||
* 案例说明书 —— **只写整单一以贯之的事**(逐步做法归剧本,两处不重复写同一件事)。
|
||||
*/
|
||||
export const NARRATIVE = `§0 开案:**一份已批准的报价要发出去,并谈出一个结果**。来路两种,形状都收(宽进):
|
||||
· **流内转来**:任务数据里有 \`items\` 数组 —— A4 的报价草案条目(每条带拟报单价与门禁处置),
|
||||
A5 已经批过;这是最全的一种来路;
|
||||
· **单飞**:只有一段需求文字,说了要给谁发报价、几颗料什么价。
|
||||
|
||||
这一单有两处不能含糊:
|
||||
· **发出去是触达世界的一下** —— 那一项标了人工激活,人不按你发不出去;
|
||||
· **客户什么时候回是外界的事** —— 立监听等它,别在这一单里轮询,更别假装等到了。
|
||||
**成品只有一样**:一份**正式报价函** —— 整份条目都在、**每一条都有客户表态**,
|
||||
而且每一条都定了案:成交 / 退回重批 / 不成交。人签的不是「发出去了」,
|
||||
是**这一单谈成了什么**。它决定整条流往哪走。
|
||||
(还价那一档 HAGGLE 是过渡态:**客户还了价、还没拍板**。放行前它必须清零 ——
|
||||
拍板那一下把它换成成交、退回重批或不成交,三条路都是结论,都算办完。)
|
||||
|
||||
【T_compose 落正式报价单】把草案落成能发出去的件:单价 / 交期 / SPQ / MOQ / 贸易条款 /
|
||||
有效期,逐条写进 \`quote_negotiate.formal_quote\`,并把 quote_total(条数)写上。
|
||||
条款缺一样都不算一份能发的报价单 —— 缺了就问,别自己填一个"看起来合理"的。写完 finish。
|
||||
**能算的不问人,该客户说的不代说**:议价结果 N-01(表态 → 定案)、让步梯度 N-02
|
||||
(还价幅度 → 处置建议),两支判定表说了算,你不临场拍;而**客户表态那一列是人落的,
|
||||
你一格都不写** —— 客户回了什么只有收信的人知道,系统不替客户表态。
|
||||
|
||||
【T_send 发出并等回音】**先 start T_send**(人工激活:发出去触达客户)。
|
||||
然后用 \`mail.send\` 登记发信意向(写类工具:过程中只登记,放行那一刻才真发),
|
||||
接着 listen 一个 data 事件等客户回音,**时限必配**(比如 P7D)——
|
||||
不配时限就是个幽灵等待,这一单会永远挂着。
|
||||
回音到了再看:成交 / 有异议 / 拒绝,分别对应放行时的三个出口。
|
||||
**四步走**:归一排版报价函 → 交 BD 发出并落回音 → 逐条定案 → 拍板定案放行。
|
||||
|
||||
【提交放行】**先 start T_release**(人工激活),提交前用 judge 裁掉裁量判据
|
||||
(criterion 照判据名原样写),然后 submit。终局唯放行:你不能自己宣布完成。
|
||||
**这一单要经过人一到两次**:BD 在议价工作单上逐条落客户表态(那张单绑着整份报价函,
|
||||
表态缺一条按不下提交 —— 基座的闸看着,他填的格子直接落账);
|
||||
**只有客户还了价的那几条才另外叫人拍板**(一张决策卡)。每条都叫人,人就成了橡皮图章;
|
||||
一条都不叫,授权红线就是摆设。最后 BD 放行签字。
|
||||
|
||||
【一路上要说话】每一拍带一句 say,说**业务的话**:报了什么价、什么时候发的、客户回了什么。
|
||||
一两句、口语。别报「写草稿 N 行」这种系统词。`;
|
||||
**去向是算出来的,不是你选的**:有条目判了退回重批 → 退回定价重批;有成交 → 转订单履约;
|
||||
全都没成 → 转情报归档。三口各带谓词,放行那一刻基座按序求值,你只要把定案落准。
|
||||
|
||||
【这一单只有一个岔路口,它长这样 —— 无论哪一拍都照这个发,别自己另编一张】
|
||||
客户还了价要人拍板,那张决策卡**三处写死**:
|
||||
· \`"itemId":"T_haggle"\` —— 英文计划项号。**别写中文名「异议拍板」**:中文名不是 id,
|
||||
写了当场被拒(【目标缺口】那一段摆的就是中文名,别照它抄);
|
||||
· \`"ask":"<N> 条客户还了价,按哪条路办?"\` —— 只把 N 换成条数,**别的字一个都不改**。
|
||||
换了问法,系统就认不出这是同一张卡:人已经点过的那张会被你再发一遍;
|
||||
· 三个 \`value\`:\`accept-encounter\` 不对,是 \`accept-counter\`(照客户还的价成交)、
|
||||
\`revise\`(退回成本定价重批)、\`hold\`(守住现价不让)。label 与 consequence 可以按
|
||||
本单的数改写,**value 不行**。
|
||||
**REVISE(退回重批)这个码只有拍板那一步写得出来** —— 定案那一步遇到客户还价一律落
|
||||
HAGGLE,替他写了 REVISE,那张卡就永远不会发,让步梯度成了摆设。
|
||||
拍板之前**别急着发卡也别绕路** —— 定案那一步先把三档写完、finish;
|
||||
下一拍引擎会把拍板那一步的做法摊开给你,那时再发。
|
||||
|
||||
【一路上要说话】负责人正看着这一单。**每一拍都带一句 say** —— 说业务的话:
|
||||
报价函排了几条、有效期到哪天、客户回了什么、哪几条要拍板;不说系统词。
|
||||
到了要找人的那一拍,先说清这一轮办完了什么、为什么现在需要他。
|
||||
|
||||
【怎么把一项干完 · 一拍连做】write 和 tool 都不会自动收步 —— 做完用 finish 宣告。
|
||||
动作排进同一拍的 actions 串一口气给;只有发卡 / 提交(挂起)必须停拍。
|
||||
**这一单常路 6-8 拍就该收口**。
|
||||
|
||||
§Z 结案:BD 在验收单上签字,系统把草稿合并成正式报价函并按定案发出对应那一口的载荷 ——
|
||||
成交转订单履约,有异议退回成本定价,不成交转情报归档。`;
|
||||
|
||||
/**
|
||||
* 步骤剧本 —— 与 A1 同一套。
|
||||
* `T_send` 与 `T_release` 都不给 `doneWhen`:一个触达客户、一个触达世界,都得人按一下。
|
||||
* 步骤剧本 —— 一个计划项一条;`doneWhen` 是「成果已存在」的判据,不是「该不该做」。
|
||||
*
|
||||
* 三处不给 `doneWhen`:`S2_send`(发卡触达真人)、`T_haggle`(要人拍板)、
|
||||
* `T_release`(签下去触达世界)—— 给了等于给引擎一把替人签字的钥匙。
|
||||
*/
|
||||
export const NEGOTIATE_STEPS = [
|
||||
{
|
||||
item: 'T_compose',
|
||||
intent: '把草案落成条款齐全的正式报价单,并结算条数',
|
||||
writes: ['quote_negotiate.formal_quote', 'quote_negotiate.verdict'],
|
||||
reads: [],
|
||||
item: 'S1_compose',
|
||||
intent: '整份归一成正式报价函:逐条抄齐条款、补 SPQ/MOQ/贸易条款、按 P-04 注明有效期',
|
||||
writes: ['quote_negotiate.line', 'quote_negotiate.verdict'],
|
||||
/* 上游载荷数组不声明就会被整表段的截断刀砍掉(砍掉的恰是要归一的行) */
|
||||
reads: ['items'],
|
||||
view: 'negotiate-worksheet',
|
||||
tools: [],
|
||||
doneWhen: 'quote_total > 0',
|
||||
guide: `逐条写进 \`quote_negotiate.formal_quote\`:单价 / 交期 / SPQ / MOQ / 贸易条款 / 有效期,
|
||||
并把 quote_total 写上。条款缺一样都不算一份能发的报价单 ——
|
||||
缺了就问,**别自己填一个「看起来合理」的值**。
|
||||
**同一拍再写一行 \`quote_negotiate.verdict\`**(验收机检读的就是它):
|
||||
· quote_total = 报价行条数;missing_field_total = 六项条款还缺的条数(要 = 0);
|
||||
· validity_days = 报价有效期天数(要 > 0);
|
||||
· followup_total = 已建跟进条数(**要 ≥2** —— D+3 与 D+7 两条,没有跟进的报价等于没报);
|
||||
· summary 一句人话结论。写不对 submit 会被门挡回来。写完再 finish。
|
||||
**每一行都要带 \`rfq_ref\`** —— 它是这一单的单标识(起单入参里就有,原样抄进去)。
|
||||
台账主键第一列就是它:不写,这一行会和**别的单**同料号的那一行撞主键,把人家覆盖掉
|
||||
(实测栽过:A4 的报价草案主键只有 pn,跑四轮只剩最后一轮的 3 行)。`,
|
||||
/*
|
||||
* 归一 + 排版走完才算办完:行数两边对上(一边是基座现数),
|
||||
* 且 composed_total 写过(S-FEEL 未绑定的名字参与比较为假,所以「没写过」进不来)。
|
||||
*/
|
||||
doneWhen: 'line_total > 0 and quote_negotiate_line_rows = line_total and composed_total >= 0',
|
||||
guide: `第一件事:把这一单的**正式报价函**落出来 —— 一拍连做,别拆成两拍。
|
||||
|
||||
【条目从哪儿来】
|
||||
· 流内转来(\`items\` 里的行带 quoted_price / disposition):照抄 —— **报出去的价就是
|
||||
上游批准的那个价**,一个数字都别改;带 quote_line_total 这类总数的是结论行,不是料,
|
||||
别落进报价函。
|
||||
· 单飞:照正文归一,列了几颗落几行;正文里说的批准价就是报出去的价。
|
||||
**按 pn 归并,一颗料一行**;pn 一个字符不许改(它是主键,改一个字就是新开一行)。
|
||||
|
||||
【写 \`quote_negotiate.line\`,一颗料一行】(rows 收数组)
|
||||
rfq_ref(入参有就原样抄;没有从主题认;认不出才自己造一个,**造出来的必须以 \`NEG-\` 开头**
|
||||
(\`NEG-<主题或第一颗料的型号>\`)。两条硬规矩:
|
||||
**① 整单只有一个单号,不是一颗料一个** —— 它是这一单的案号,报价函所有行、verdict 那一行
|
||||
用的都得是同一个串(实测栽过:两颗料造出两个号,一单裂成两单);
|
||||
**② 只从本单来件取材** —— 台账里躺着的 RFQ-xxxx 是别人的单,借它的号等于把两单的行
|
||||
混进同一个案卷(实测栽过一轮))、pn、customer_pn、category、brand、eau、lead_time、
|
||||
remark(客户约束/急料,一个字别丢)、type_tag(照上游现标;认不出按 B)、
|
||||
**quoted_price**(上游批准的报价,原样抄)。
|
||||
条款三列**照这个口径补齐**(它们是报价函的必备条款,不是可选项):
|
||||
· spq —— 最小包装量:上游给了就抄;没给按 eau 的量级给一个常规值(千位以下 100,
|
||||
千到万 1000,万以上 5000)并在 remark 里注明是按常规包装估的;
|
||||
· moq —— 最小起订量:同上,没给就取 spq;
|
||||
· trade_terms —— 贸易条款:统一写 \`EXW 深圳\`,客户来件另有约定的照客户的写。
|
||||
· valid_until —— 有效期到期日:按**报价有效期 P-04:7 个日历天**从今天算,写成
|
||||
\`YYYY-MM-DD\`。整单同一个日子,不是一行一个。
|
||||
|
||||
【**这三列你一格都不写**:reply_type / counter_price / reply_note】
|
||||
客户表态、客户还的价、客户原话 —— 这三样只有收信的人知道,**系统不替客户说话**。
|
||||
它们是 BD 在工作单上落的;deal_status / concession / final_price 三列要等表态回来
|
||||
才判得了,这一步也别写。
|
||||
这不是客气话:一条要你分辨「这行能不能替客户填」的规矩会走岔;
|
||||
**「这几列不写」没有分支可走岔。**
|
||||
|
||||
【同一拍写 \`quote_negotiate.verdict\`(一行)】
|
||||
rfq_ref、**quote_no**(报价单号:\`Q-\` 开头 + 本单案号的尾段,整单一个)、
|
||||
customer_code / customer_name(顶层有就抄)、**line_total** = 报价函行数、
|
||||
**valid_days** = 7、**composed_total** = 这一拍排版落表的条数(0 也要写)、
|
||||
summary 一句人话(几条料、报给谁、有效期到哪天)。
|
||||
写完 finish 这一项。`,
|
||||
},
|
||||
{
|
||||
item: 'T_send',
|
||||
intent: '发出报价并立监听等客户回音',
|
||||
writes: [],
|
||||
reads: [],
|
||||
tools: ['mail.send'],
|
||||
// 触达客户 —— 人工激活,不给 doneWhen
|
||||
guide: `**先 start T_send**(人工激活:发出去触达客户)。
|
||||
用 \`mail.send\` 登记发信意向(写类工具:只登记,放行那一刻才真发),
|
||||
再 listen 一个 data 事件等回音,**时限必配**(如 P7D)—— 不配就是幽灵等待,这一单会永远挂着。`,
|
||||
item: 'S2_send',
|
||||
intent: '一张执行单交 BD:把报价函发给客户,回音回来后逐条落客户表态',
|
||||
writes: ['quote_negotiate.verdict'],
|
||||
reads: ['quote_negotiate.line'],
|
||||
view: 'negotiate-worksheet',
|
||||
tools: [],
|
||||
/* 不给 doneWhen —— 发卡触达真人(manualActivation),引擎不替人按 */
|
||||
guide: `报价函排好了,**该 BD 出场了** —— 这是本活动唯一的一张执行单。
|
||||
触达客户的那一下由人做:他把报价函发出去、按 D+3/D+7 催问、拿回客户的话。
|
||||
工作区摆的是**议价工作单**:逐颗料一张报价档案卡(条款、报价、客户约束),
|
||||
让步梯度与议价纪律挂在上面,填回区长在同一屏 —— 他在「客户表态」那一列逐行落。
|
||||
|
||||
这一步标了人工激活:发卡就算启动,不必单发 start;引擎也不会替你收 ——
|
||||
人交回后要你自己 finish。
|
||||
|
||||
【照这个骨架发,别少字段】(卡面是纯文本,steps/standard 里别写星号记号)
|
||||
{"kind":"human","itemId":"S2_send","workOrder":"execution","card":{
|
||||
"title":"报价函发出并跟进:<单号> 共 <N> 条待回音",
|
||||
"ask":"报价函已按批准价排好版,条款与有效期都在工作单上。请把它发给客户,按 D+3/D+7 的节奏催问;客户回话之后,在工作单的「客户表态」一列逐行落:接受 / 还价 / 拒绝 / 无回复,还价的把客户报的那个价也填上。",
|
||||
"steps":["发出去之前先核一遍条款:单价、交期、SPQ、MOQ、贸易条款、有效期 —— 报价函一旦发出,这几项就是对客户的承诺",
|
||||
"客户表态每一行都要有 —— 缺一行这张单按不下提交;客户只回了一部分料的,没回的那几行按无回复落,别替客户猜",
|
||||
"客户还价的行:把他报的价填进「客户还价」那一格,再把他的原话记进备注 —— 争的是价格、交期还是 MOQ,后面拍板全看这一句",
|
||||
"D+3 第一轮催问确认收到探态度,D+7 最后一催;催到有效期过仍无回复的,按无回复定案,不要一直挂着"],
|
||||
"standard":"整份报价函每一条都有客户表态,还价的那几条填了客户报的价并记下他的原话 —— 缺一条这张单按不下提交(系统的闸看着)。",
|
||||
"basis":[{"k":"<PN>","v":"<报价 · 交期 · 有效期到 YYYY-MM-DD>"}]}}
|
||||
· \`basis\` 逐条列本单的料:PN + 报价与有效期。几颗写几条,别铺全表。
|
||||
· **卡上不摆表、不摆格子**(执行卡零输入):整份报价函就在工作单那份件上,
|
||||
客户表态、客户还价、备注三列都能就地改、行能撤 —— **别往卡里塞 \`blocks\` 或 \`fields\`**。
|
||||
· **这张卡带提交闸**:客户表态(必填列)还空着,他按不下提交 —— 缺几格、缺在哪行,
|
||||
闸上与件上的红带都写着(与放行门 L1 同一个数同一套算法)。
|
||||
发完卡这一拍就结束了(发卡挂起)。
|
||||
|
||||
【人交回之后 —— 他落的表态基座已经替你写回台账了】这一步你只做两件事,然后 finish:
|
||||
① 写 verdict:**replied_total** = 已落表态的条数(照报价函行数记);
|
||||
他在件上撤掉了行的话,**line_total 跟着改成撤后的实数**。
|
||||
② finish 这一项。
|
||||
**别在这一拍判定案** —— 逐条定案是下一步的活(它有自己的一段做法),这里判了也白判。
|
||||
报价函行你一列都不用重写:他落的值基座已经落进台账了,重写会被「写了等于没写」拒回。
|
||||
|
||||
【这张卡一单只发一次】人交回来之后不许再发同一张卡 —— 必填有提交闸兜着,
|
||||
卡回来时客户表态一定是齐的(或那几行已被他撤掉)。`,
|
||||
},
|
||||
{
|
||||
item: 'S3_settle',
|
||||
intent: '逐条定案:按客户表态判成交/待拍板/不成交,还价的按让步梯度给处置建议',
|
||||
writes: ['quote_negotiate.line', 'quote_negotiate.verdict'],
|
||||
reads: ['quote_negotiate.line'],
|
||||
view: 'negotiate-worksheet',
|
||||
tools: [],
|
||||
/*
|
||||
* **收步判据与验收判据同源**:四档定案的条数加起来等于行数(两边都是基座现数)——
|
||||
* 判完了才算办完。`_rows > 0` 那一半不能省:开案时行数是 0,而 0+0+0+0 = 0
|
||||
* 会让这一步开局即收(未绑定名字的坑之外,还有「全零相等」这一坑)。
|
||||
*/
|
||||
doneWhen:
|
||||
'quote_negotiate_line_rows > 0 and quote_negotiate_line_deal_status_haggle = quote_negotiate_line_reply_type_counter and quote_negotiate_line_deal_status_won + quote_negotiate_line_deal_status_haggle + quote_negotiate_line_deal_status_revise + quote_negotiate_line_deal_status_lost = quote_negotiate_line_rows',
|
||||
guide: `客户的话都落回来了,**现在才轮到定案** —— 这一步是纯查表,一拍连做:
|
||||
|
||||
① **逐行按客户表态 reply_type 判 deal_status**,按议价结果 N-01,
|
||||
只许写这四个大写码之一,一个字母不许差:
|
||||
· ACCEPT(客户接受)→ **WON**,同一行 final_price 记 quoted_price(成交价就是报价);
|
||||
· COUNTER(客户还价)→ **HAGGLE**,final_price **留空**(还没谈定,别替客户成交);
|
||||
· REJECT(客户拒绝)→ **LOST**,final_price 留空;
|
||||
· NOREPLY(催到有效期过仍无回复)→ **LOST**,final_price 留空。
|
||||
**第四个码 REVISE「退回重批」这一步一格都不写** —— 它是人在决策卡上拍出来的,
|
||||
不是你判出来的。你替他写了,那张卡就永远不会发,让步梯度成了摆设(实测栽过一轮:
|
||||
一单从头到尾 released 而没有人拍过板)。客户还了价 = 落 **HAGGLE**,句号。
|
||||
**两个数要对上,都是基座现数,你改不动它们**:
|
||||
· 待拍板条数 quote_negotiate_line_deal_status_haggle
|
||||
**必须等于**客户还价条数 quote_negotiate_line_reply_type_counter ——
|
||||
对不上这一步收不掉(把写错的那行改回 HAGGLE 就对上了);
|
||||
· 四档定案的条数加起来必须等于 quote_negotiate_line_rows(基座数的行数),一行都不能漏。
|
||||
现在四档都是 0,就是一行都还没判 —— 这一步没办完,放行门开不了。
|
||||
② **还价的那几行(且只有那几行)再算一格 concession**:让步梯度 N-02 看还价幅度
|
||||
gap =(quoted_price − counter_price)/ quoted_price,只许写这三个大写码之一:
|
||||
· gap ≤ 0.03(三个点以内)→ **ACCEPT_COUNTER**(意思意思的压价,接了拿单);
|
||||
· 0.03 < gap ≤ 0.10(三到十个点)→ **NEGOTIATE**(在授权内回旋一轮,让一半再报回去);
|
||||
· gap > 0.10(超过一成)→ **ESCALATE**(超出授权,退回成本定价重批,不私自破线)。
|
||||
不是还价的行 concession 给空串 \`""\`,**不许写 0 也不许编一个码** ——
|
||||
没还价就没有让步幅度这回事。
|
||||
③ 看这一拍写完之后的**待拍板条数**(deal_status = HAGGLE 的行):
|
||||
· 一条都没有 → 同一拍把 verdict 写全:**outcome**(全按 N-01 的结果算:
|
||||
有 WON 就写 \`won\`,一条 WON 都没有就写 \`lost\`)、**route_decided_total 记 1**、
|
||||
**settled_total** = 定案条数、reason(不成交时写清缘由:客户拒绝还是超时无回复)、
|
||||
summary 补一句人话,然后 finish 这一项;
|
||||
· 还有 → **别写 outcome 也别写 route_decided_total**,只写 settled_total 再 finish ——
|
||||
下一拍会有一步专门叫人拍板。
|
||||
|
||||
【finish 之后这一拍到此为止】**别在这一拍顺手发决策卡** —— 那张卡属于下一步
|
||||
(itemId 要写 T_haggle),这一步收掉之后再往它上面挂任何行动都会被拒
|
||||
(实测:同一串里 write / write / finish / decide,最后那个 decide 挂着 S3_settle,当场被拒)。
|
||||
下一拍引擎会把「异议拍板」那一步的做法摊开给你,那时再发。`,
|
||||
},
|
||||
{
|
||||
item: 'T_haggle',
|
||||
intent: '客户还的价接不接要人定 —— 发一张决策卡,照他选的那条路把定案改掉',
|
||||
writes: ['quote_negotiate.line', 'quote_negotiate.verdict'],
|
||||
reads: ['quote_negotiate.line'],
|
||||
view: 'negotiate-roster',
|
||||
tools: [],
|
||||
/* 人工激活 + 要人拍板 —— 不给 doneWhen,引擎不许替人收 */
|
||||
guide: `**这一单只发一张决策卡。动手之前先在轨迹里找一行 \`[card-reply]\` 带「人选了:」:**
|
||||
|
||||
· **找到了** —— 跳到下面【人点完之后】那一段,照他选的那条路把那几行的 deal_status
|
||||
从 HAGGLE 改掉、写 outcome 与 route_decided_total、finish。**一个 decide 都不许再发**
|
||||
(实测栽过:人点完了,而这一步又从头念了一遍「发一张决策卡」,同一张卡连发六次,
|
||||
前两次无事发生、后四次被拒 —— 他点过的那一下就白点了);
|
||||
· **没找到** —— 才轮到下面【发一张决策卡】那一段。
|
||||
|
||||
【这一步办完了没有,看一个数】待拍板条数 quote_negotiate_line_deal_status_haggle:
|
||||
**它归零就是这一步办完了**。HAGGLE 是过渡态(客户还了价、还没拍板),
|
||||
拍板那一下必须把它换成 WON / REVISE / LOST 之一 —— 三条路都是结论。
|
||||
这个数不归零,放行门开不了;它归零,这一步也就不会再找你。
|
||||
|
||||
这一步只在**客户还过价**(基座现数 quote_negotiate_line_reply_type_counter > 0)时入场 ——
|
||||
读的是客户自己填的那一格,不是你判的定案:该不该叫人,不由被叫的那一方说了算。
|
||||
它触达公司利益,标了人工激活:发卡就算启动,不必单发 start。
|
||||
工作区这时摆的是**成交定案清单**,整份报价函与定案分布都在上面,他看得见全局再拍板。
|
||||
|
||||
【发一张决策卡,照这个骨架】(选项少于两个基座拒发)
|
||||
**三处一个字都不许改**(与说明书里那一段是同一份):
|
||||
· \`itemId\` 只写英文计划项号 \`T_haggle\` —— **别写中文名「异议拍板」**,
|
||||
中文名不是 id,写了当场被拒(实测栽过两拍:「计划项不存在:异议拍板」);
|
||||
【目标缺口】那一段摆的是中文名,它不是 id,别照它抄。
|
||||
· \`ask\` 照抄「<N> 条客户还了价,按哪条路办?」,**只把 N 换成条数** ——
|
||||
换了问法系统就认不出这是同一张卡,人已经点过的那张会被你再发一遍(实测发出去两张)。
|
||||
· 三个 \`value\` 照抄 \`accept-counter\` / \`revise\` / \`hold\` —— 它们是这一单三条路的
|
||||
代号,换了名字下一段的对应关系就对不上,你自己也不知道人点的是哪条。
|
||||
label 与 consequence 可以按本单的数改写,value 不行。
|
||||
{"kind":"decide","itemId":"T_haggle","ask":"<N> 条客户还了价,按哪条路办?",
|
||||
"options":[
|
||||
{"value":"accept-counter","label":"照客户还的价成交","consequence":"当场拿下这几条,毛利让到客户的价位上,让出去的部分不再回来"},
|
||||
{"value":"revise","label":"退回成本定价重批","consequence":"这几条超出让价授权,回 A4 重新算价再谈 —— 这一单本轮不成交,客户要多等一轮"},
|
||||
{"value":"hold","label":"守住现价不让","consequence":"报价不动,客户不接受即视为不成交,这几条转情报归档"}],
|
||||
"basis":[{"k":"<PN>","v":"报价 <X> · 客户还价 <Y> · 让幅 <Z>% · 让步梯度判 <码>"}]}
|
||||
· basis 逐条摆还价的那几颗料:报价、客户还价、让幅、N-02 的处置码 —— 裸卡基座拒发。
|
||||
· **recommended 按让步梯度 N-02 标**,标在与处置码对应的那一项上,只标一项:
|
||||
ACCEPT_COUNTER → accept-counter;NEGOTIATE → accept-counter;ESCALATE → revise。
|
||||
几条料的码不一致时,按**最靠后那一档**标(有一条要 ESCALATE 就标 revise)。
|
||||
· 发完这一拍就结束了(发卡挂起)。
|
||||
|
||||
【人点完之后】轨迹上那一行长这样:\`[card-reply] …人选了:xxx\`。**照那条路把定案改掉,
|
||||
别再发第二张卡**,一拍连做 —— 三条路**都要动 deal_status**,一条都不许留在 HAGGLE:
|
||||
· 选 accept-counter:那几行 deal_status 改 **WON**、**final_price 记该行的
|
||||
counter_price**(那个数不是你定的,是客户报的、人点头认的,你只是替他落账)、
|
||||
reply_note 补一句「按客户还价成交,由负责人拍板」;verdict 的 outcome 写 \`won\`;
|
||||
· 选 revise:那几行 deal_status 改 **REVISE**、final_price 留空,
|
||||
reply_note 补一句「让幅超出授权,退回成本定价重批」;verdict 的 outcome 写 \`revise\`、
|
||||
reason 写清超了多少;
|
||||
· 选 hold:那几行 deal_status 改 **LOST**、final_price 留空,
|
||||
reply_note 补一句「守价不让,客户未接受」;verdict 的 outcome 写 \`lost\`、
|
||||
reason 写「客户还价未达成,守价不让」。
|
||||
然后把 verdict 写全:**route_decided_total 记 1**、settled_total = 定案条数、
|
||||
summary 补一句拍板结果,finish 这一项。
|
||||
**outcome 那一格照上面三条写死的对应关系填,别自己另造词** —— 下游三条边读的就是它。
|
||||
改完之后待拍板条数就是 0 了,这一步再也不会找你。`,
|
||||
},
|
||||
{
|
||||
item: 'T_release',
|
||||
intent: '议价有结果,提交放行交 BD 验收',
|
||||
intent: '定案已落,提交放行交 BD 验收',
|
||||
writes: [],
|
||||
reads: [],
|
||||
view: 'negotiate-roster',
|
||||
tools: [],
|
||||
guide: `**先 start T_release**(人工激活),提交前用 judge 裁掉裁量判据,然后 submit。
|
||||
三个去向(成交 / 有异议 / 拒绝)由放行时的选择组定。
|
||||
**台账里要写 outcome**(won / revise / lost)—— 下游三条边读的就是它,不写整条流走不下去。`,
|
||||
/* 放行触达世界,必须人按一下 —— 引擎不自动收它(剧本里也不给 doneWhen) */
|
||||
guide: `每条都有客户表态、定案守恒、待拍板清零、定案已记 —— 可以走放行了
|
||||
(T_release 人工激活:动它就算启动,不必单发 start)。先把裁量判据裁掉,然后 submit,同一拍连做:
|
||||
|
||||
· judge criterion="议价过程说得清:报价函条款齐备、每一轮客户反馈与让价理由逐条可溯,BD 对这个结果负责" ——
|
||||
看报价函里每一行的条款、客户原话与让价理由:说得出来路就 satisfied=true;
|
||||
有行说不出的(比如还价成交却没记客户的话),satisfied=**false**,rationale 逐行写清,
|
||||
交签字的人定。**裁成不满足照样能提交** —— 理由连着卡一起交给他。
|
||||
criterion 照判据名**整句原样抄**,写别的名字对不上。
|
||||
|
||||
**去向不必你选**:三口各带谓词,放行那一刻基座按序求值 ——
|
||||
有条目判了退回重批就走「退回调整」,有成交就走「转订单履约」,全都没成就走「转情报归档」。
|
||||
你要做的只是把定案落准,别在提交里手选出口。
|
||||
|
||||
终局唯放行:你不能自己宣布完成。`,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 阶段 —— 进度条的刻度,只给人看。除放行外每个计划项恰属一个阶段;
|
||||
* 放行那一格由基座统一加,人看到的是 x/5。
|
||||
*/
|
||||
export const NEGOTIATE_PHASES = [
|
||||
{ name: '排版报价函', items: ['S1_compose'] },
|
||||
{ name: '发出并等回音', items: ['S2_send'] },
|
||||
{ name: '逐条定案', items: ['S3_settle'] },
|
||||
{ name: '异议拍板', items: ['T_haggle'] },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user