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>
471 lines
23 KiB
TypeScript
471 lines
23 KiB
TypeScript
/**
|
|
* 活动包清单 —— 统一报价 A4 · 成本定价(案例活动)。
|
|
*
|
|
* 业务素材:`docs/MVP示例工作流.html` §1.2(S1 取价基准 → S2 逐条定价 → S3 底价自检):
|
|
* 「BD 逐条定价:价格 = 底价 × 利润模型。提交审批前先自查底价门禁 ——
|
|
* 超限的自己先调,不把问题留给 PM。」
|
|
*
|
|
* 形状与 A3 同一条(2026-08-03 重写 @3.0.0):归一算价 → 一张执行单交人 → 超限才叫人
|
|
* 拍板 → 放行。**能算的不问人**(P-01 毛利档、P-02 底价门禁两把尺写死),
|
|
* **该人负责的不自算**(拟报单价是必填,库内没有基准的那几行系统一个价都不编)。
|
|
*
|
|
* 与 @2.0.0 的差别(三处都是踩过的账):
|
|
* ① `input.required` 从 `['rfqRef','customerCode','records']` 清空 —— 宽进严出,
|
|
* 上游(A3)发的是 `{rfqRef, rows}`,门口拦的恰是主路;
|
|
* ② 台账补 `required` —— 从前一个必填都没有,执行卡的闸没牙,人不填也能交卷;
|
|
* ③ 判据与哨兵全部换成**基座读数**(`_rows` / `_missing` / `_<列>_<值>`)——
|
|
* 从前 L1 读 `unpriced_total`、哨兵读 `draft_total`,两个都是活动自报的数。
|
|
*/
|
|
import type { ActivityManifest, DmnModel } from '@contracts';
|
|
import { activityIdSchema } from '@contracts';
|
|
import { PRICING_SKILLS } from './skills.ts';
|
|
import { CMMN_XML, NARRATIVE, PRICING_PHASES, PRICING_STEPS } from './case-model.ts';
|
|
import { PRICING_ROSTER, PRICING_WORKSHEET } from './views/report.ts';
|
|
|
|
const D = 'quote_pricing';
|
|
const ACTIVITY_ID = activityIdSchema.parse('quote-pricing');
|
|
|
|
/**
|
|
* 两把尺 —— **规则本身不是数据**,随包冻结。
|
|
*
|
|
* · 利润模型 P-01:客户等级 × 类别 → 目标毛利区间(FIRST,行序即业务优先级);
|
|
* · 底价门禁 P-02:相对底价线的偏离度 → 处置码。
|
|
*
|
|
* 出参就是台账列的取值(`disposition` 的三个大写码),模型算完照抄即可 ——
|
|
* 「出参键名与台账列同名」是为了它拿回去直接 write(规范 §5.6)。
|
|
* 两把尺的档位在三处出现:这张表、剧本 guide、工作单上的规则块 ——
|
|
* 包内自测把三处钉在一起(改一处不改另两处,测就红)。
|
|
*/
|
|
export const P01_DMN: DmnModel = {
|
|
drd: [
|
|
{ decision: 'p01-margin', requires: [], inputs: ['customer_grade', 'type_tag'] },
|
|
{ decision: 'p02-floor', requires: ['p01-margin'], inputs: ['deviation'] },
|
|
],
|
|
tables: [
|
|
{
|
|
id: 'p01-margin',
|
|
label: '利润模型 P-01',
|
|
hitPolicy: 'FIRST',
|
|
inputs: [
|
|
{ name: 'customer_grade', expression: 'customer_grade' },
|
|
{ name: 'type_tag', expression: 'type_tag' },
|
|
],
|
|
outputs: [{ name: 'margin_low' }, { name: 'margin_high' }],
|
|
rules: [
|
|
{ id: 'p01-1', when: ['"战略客户"', '"A"'], then: [0.08, 0.1], annotation: '战略客户 A 类标准件(大批量长单)8%~10%' },
|
|
{ id: 'p01-2', when: ['"普通客户"', '"A"'], then: [0.12, 0.15], annotation: '普通客户 A 类标准件 12%~15%' },
|
|
{ id: 'p01-3', when: ['-', '"B"'], then: [0.15, 0.2], annotation: 'B 类波动件 15%~20%' },
|
|
{ id: 'p01-4', when: ['-', '"C"'], then: [0.2, 0.5], annotation: 'C 类替代/停产件 20%~50%(一事一议)' },
|
|
{ id: 'p01-default', when: ['-', '-'], then: [0.12, 0.15], annotation: '拿不准按普通客户标准件档' },
|
|
],
|
|
},
|
|
{
|
|
/** 底价门禁 P-02 —— 偏离底价线 ±20% 即止;出参就是台账 `disposition` 的取值 */
|
|
id: 'p02-floor',
|
|
label: '底价门禁 P-02',
|
|
hitPolicy: 'FIRST',
|
|
inputs: [{ name: 'deviation', expression: 'deviation' }],
|
|
outputs: [{ name: 'disposition' }, { name: 'passable' }],
|
|
rules: [
|
|
{ id: 'p02-1', when: ['>= 0'], then: ['PASS', true], annotation: '在底价线之上 → 直接放行' },
|
|
{ id: 'p02-2', when: ['[-0.20..0)'], then: ['NOTE', true], annotation: '低于底价线两成以内 → 附理由放行' },
|
|
{ id: 'p02-3', when: ['< -0.20'], then: ['BLOCK', false], annotation: '低于两成以上 → 拦截,人拍板' },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
export const manifest: ActivityManifest = {
|
|
identity: {
|
|
activityId: ACTIVITY_ID,
|
|
name: 'A4 · 成本定价',
|
|
packageVersion: '3.5.0',
|
|
category: '统一报价',
|
|
sdkVersion: '0.1.0-m5',
|
|
checksum: 'dev-checksum-quote-pricing',
|
|
},
|
|
|
|
/* ── 契约七件 ────────────────────────────────────────────────── */
|
|
contract: {
|
|
activityId: ACTIVITY_ID,
|
|
version: '1.0.0',
|
|
input: {
|
|
/*
|
|
* **宽进到底:一个必填都不设**(与 A1/A2/A3 同口径 —— 宽进严出,
|
|
* 输入契约在活动内部归一 + 补全)。
|
|
*
|
|
* 来路三种形状:寻源转来(rows,行上带 base_price)、受理/选型直达(records/rows,
|
|
* 没有底价)、单飞(一段文字)。上一版必填 `rfqRef + customerCode + records`,
|
|
* 而 A3 的 `quotation` 口发的是 `{rfqRef, rows}` —— 门口拦的恰是主路。
|
|
*/
|
|
data: {
|
|
type: 'object',
|
|
required: [],
|
|
properties: {
|
|
rfqRef: { type: 'string', title: '询价单号(单标识,贯穿全流程)' },
|
|
customerCode: { type: 'string', title: '客户码' },
|
|
rows: { type: 'array', title: '目标报价清单(寻源/选型转来,行上带底价)' },
|
|
records: { type: 'array', title: '上游受理记录(受理直达)' },
|
|
subject: { type: 'string', title: '需求主题' },
|
|
body: { type: 'string', title: '需求正文' },
|
|
attachments: {
|
|
type: 'array',
|
|
format: 'file',
|
|
title: '附件',
|
|
items: {
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string', title: '文件名' },
|
|
contentType: { type: 'string', title: '类型' },
|
|
size: { type: 'integer', title: '字节数' },
|
|
ref: { type: 'string', title: '存档号' },
|
|
text: { type: 'string', title: '读出来的文本' },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
messageAllowed: true,
|
|
messageHint: '客户等级、急单、竞对价、这一单的让价授权写这里',
|
|
},
|
|
output: {
|
|
/*
|
|
* 只有一个出口:报价草案交定价审批(流程包 E8 是无条件边)。没有选择组 ——
|
|
* 没有去向要选,定盘就是把账写齐。
|
|
*
|
|
* 载荷键名照下游(A6 议价)的入参写:`rfqRef / customerCode / items` ——
|
|
* 边读什么、下游要什么,上游就得发什么。标量都有台账列承载(自测钉着)。
|
|
*/
|
|
mandatory: [
|
|
{
|
|
name: 'draft',
|
|
payload: {
|
|
type: 'object',
|
|
required: ['rfqRef', 'items'],
|
|
properties: {
|
|
rfqRef: { type: 'string', title: '询价单号(单标识 —— 下游台账的主键)' },
|
|
customerCode: { type: 'string', title: '客户码' },
|
|
items: { type: 'array', title: '报价草案(每条带拟报单价、偏离度与门禁处置)' },
|
|
},
|
|
},
|
|
description: '报价草案(全条目带拟报单价与门禁处置)',
|
|
},
|
|
],
|
|
selective: [],
|
|
},
|
|
/*
|
|
* 必交付物只有一件:**报价草案**。定价结论(verdict)是它的结论栏,
|
|
* `ledgers` 说清这份成果由哪几张表承载(一份成果,不是两份)。
|
|
*/
|
|
requiredDeliverables: [
|
|
{
|
|
key: 'quote-draft',
|
|
label: '报价草案(每条带拟报单价与门禁处置)',
|
|
ledger: `${D}.draft`,
|
|
/* 验收页上让 BD 就地改的两列 —— 恰是他的职权面(定价与让价理由) */
|
|
editableAtRelease: ['quoted_price', 'price_note'],
|
|
ledgers: [`${D}.draft`, `${D}.verdict`],
|
|
},
|
|
],
|
|
/*
|
|
* 验收判据 —— **机检(L1/L2)只读基座数得出来的数**:
|
|
* `_rows` 基座数行数、`_missing` 基座按 required 现数(与执行卡提交闸同一个数
|
|
* 同一套算法)、`_disposition_*` 基座按值现数。
|
|
* 上一版两条机检读活动自报的 `unpriced_total` / `unresolved_over_total` ——
|
|
* 那不是门,是「改哪个数能过」的提示(违反史已记四次,这是第五类)。
|
|
*/
|
|
acceptanceCriteria: [
|
|
{
|
|
key: 'roster-complete',
|
|
label: '草案齐:上游条目逐条承继,说了几条草案里就躺着几行',
|
|
level: 'L1',
|
|
predicate: `line_total > 0 and ${D}_draft_rows = line_total`,
|
|
},
|
|
{
|
|
key: 'all-priced',
|
|
label: '每条都有拟报单价:库内无基准价的那几行也由人定过价,缺一行放不了',
|
|
level: 'L1',
|
|
predicate: `${D}_draft_rows > 0 and ${D}_draft_missing = 0`,
|
|
},
|
|
{
|
|
key: 'floor-gate',
|
|
label: '底价门禁已过:处置逐条落定,没有还压在拦截档上的条目 —— 超限的要么回调、要么经人拍板附理由',
|
|
level: 'L2',
|
|
modelRef: 'p02-floor',
|
|
predicate: `${D}_draft_disposition_block = 0 and ${D}_draft_disposition_pass + ${D}_draft_disposition_note + ${D}_draft_disposition_block = ${D}_draft_rows`,
|
|
},
|
|
/*
|
|
* 报价来路可核是**裁量**(L3):基准是不是那个基准、让价理由站不站得住,
|
|
* 机器数不出来。这句 label 与剧本里 judge 的 criterion **必须逐字一致**。
|
|
*/
|
|
{
|
|
key: 'price-defensible',
|
|
label: '报价的来路说得清:基准价来源、毛利档与让价理由逐条可溯,BD 对报价负责',
|
|
level: 'L3',
|
|
},
|
|
/* L5 是责任关:那张卡本身就是这道关,卡面上不摆它(基座统一滤) */
|
|
{ key: 'bd-release', label: 'BD 放行:签下去这份报价草案即定盘并交定价审批', level: 'L5' },
|
|
],
|
|
revisableAtRelease: [],
|
|
prohibitions: [
|
|
{ key: 'no-silent-override', statement: '不得静默绕开底价门禁的结论;要破线只能走「人 · 决策」并留下理由' },
|
|
{ key: 'no-made-up-basis', statement: '没有成本基准的料不许编一个偏离率出来:基准空着就空着,价由人定并注明依据' },
|
|
{ key: 'no-stale-floor', statement: '底价超一周未更新的,先刷底价再判 —— 拿过期的成本算出来的毛利是假的' },
|
|
],
|
|
authorization: {
|
|
discretion: [{ key: 'margin-band', statement: '在 P-01 给出的毛利区间内自决;出区间要么回调,要么调人拍板' }],
|
|
preauthorizedActions: [],
|
|
/* 一张执行单 + 可能一张决策卡 + 放行 = 三次;留一倍余量 */
|
|
humanCallBudget: 5,
|
|
},
|
|
resources: {
|
|
tools: [{ name: 'crm.history-price-read' }],
|
|
skills: PRICING_SKILLS.map((s) => s.id),
|
|
models: ['deepseek-v4-flash'],
|
|
roles: ['BD'],
|
|
/* SLA <2h(MVP示例 §1.2);预算按 A3 实测(6-8 拍 / 40-50k)留一倍余量 */
|
|
budget: { steps: 60, tokens: 400_000, activeMinutes: 120, humanCalls: 5 },
|
|
},
|
|
},
|
|
|
|
/* ── 声明 ────────────────────────────────────────────────────── */
|
|
declarations: {
|
|
models: ['deepseek-v4-flash'],
|
|
tools: [{ name: 'crm.history-price-read' }],
|
|
ledger: [
|
|
{
|
|
domain: D,
|
|
object: 'draft',
|
|
kind: 'record',
|
|
caseKey: 'rfq_ref',
|
|
label: '报价草案',
|
|
fields: [
|
|
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
|
{ name: 'pn', type: 'text', primaryKey: true, masked: false, label: 'PN' },
|
|
{ name: 'customer_pn', type: 'text', primaryKey: false, masked: false, label: '客户料号' },
|
|
{ name: 'category', type: 'text', primaryKey: false, masked: false, label: '品类' },
|
|
{ name: 'brand', type: 'text', primaryKey: false, masked: false, label: '制造商' },
|
|
{ name: 'eau', type: 'integer', primaryKey: false, masked: false, label: '年用量 EAU' },
|
|
{ name: 'lead_time', type: 'text', primaryKey: false, masked: false, label: '客户要求交期' },
|
|
/* 客户备注承继自上游 —— 认证要求、预授权、急料标注,让价时的第一手依据 */
|
|
{ name: 'remark', type: 'text', primaryKey: false, masked: false, label: '客户备注(约束/急料)' },
|
|
{ name: 'type_tag', type: 'text', primaryKey: false, masked: false, label: '类别(承继)', tally: ['A', 'B', 'C'] },
|
|
/*
|
|
* **客户目标价标 `expect`** —— 客户该给而没给的那一问不能省(件上出橘色
|
|
* 「建议填」胶囊)。它不拦单:`_gaps` 只喂 L4,而本活动没有 L4 判据。
|
|
* 注意边界:我方自己写的注(price_note)**不标 expect** —— 标了 `_gaps`
|
|
* 恒大于 0,那条判据永远绿不了(A1 的账)。
|
|
*/
|
|
{ name: 'target_price', type: 'number', primaryKey: false, masked: false, expect: true, label: '客户目标价' },
|
|
/* 成本基准:上游底价或库内历史价。**取不到就空着** —— 空着不是异常,是「无基准」那一档 */
|
|
{ name: 'base_price', type: 'number', primaryKey: false, masked: false, label: '成本基准' },
|
|
{ name: 'price_basis', type: 'text', primaryKey: false, masked: false, label: '基准来源', tally: ['HIST', 'SOURCED'] },
|
|
{ name: 'margin_band', type: 'text', primaryKey: false, masked: false, label: '毛利档(P-01)' },
|
|
{ name: 'floor_price', type: 'number', primaryKey: false, masked: false, label: '底价线' },
|
|
/*
|
|
* **系统建议价是 AI 的活,拟报单价是人的活** —— 两列分开是**结构治**,不是措辞治。
|
|
*
|
|
* 实测账(2026-08-03,单飞那条案例):从前只有 `quoted_price` 一列,剧本写着
|
|
* 「无基准的行留空,由 BD 定」—— 模型照样给两颗库里查不到的料编了价
|
|
* (一颗抄了客户目标价,另一颗凭空写了 0.085),交代里还说着「价空着等你定」。
|
|
* 一条要模型分辨「这行算得出/算不出」的规矩,它十次里会走岔;
|
|
* 而「这一列你一格都不写」没有分支可走岔。
|
|
*
|
|
* 于是:AI 只写 `suggested_price`(算得出就给,算不出就空着),
|
|
* **`quoted_price` 永远是人在件上定的那个数** —— 它标 `required`,
|
|
* 件上的缺价红带、执行卡的提交闸、放行门 L1 三处同源(都数基座的 `_missing`)。
|
|
* 不用 `requiredWhen`:每一行都要有价,没有「这一行还没轮到」的情形。
|
|
*/
|
|
{ name: 'suggested_price', type: 'number', primaryKey: false, masked: false, label: '系统建议价' },
|
|
{ name: 'quoted_price', type: 'number', primaryKey: false, masked: false, required: true, label: '拟报单价(BD 定)' },
|
|
{ name: 'margin', type: 'number', primaryKey: false, masked: false, label: '毛利率' },
|
|
{ name: 'deviation', type: 'number', primaryKey: false, masked: false, label: '偏离底价线' },
|
|
/*
|
|
* **门禁处置:取值域给出来,条数由基座现数** —— PASS / NOTE / BLOCK。
|
|
* 守恒判据、分布条、门禁徽读的全是基座读数;值是机器码,
|
|
* 人读名(直接放行 / 附理由 / 拦截待拍板)由模版样式表翻译。
|
|
*/
|
|
{ name: 'disposition', type: 'text', primaryKey: false, masked: false, label: '门禁处置', tally: ['PASS', 'NOTE', 'BLOCK'] },
|
|
{ name: 'price_note', type: 'text', primaryKey: false, masked: false, label: '备注 / 让价理由' },
|
|
],
|
|
},
|
|
{
|
|
/*
|
|
* 定价结论 —— 一单一行的**汇总表**,哨兵与报告读它。
|
|
* 汇总列与逐行列**故意不同名**:任务视图把草稿行摊平到顶层是「后写的赢」,
|
|
* 拿逐行列求值只会验到最后写的那一行,那不叫机检、叫抽样(A1 的教训)。
|
|
*/
|
|
domain: D,
|
|
object: 'verdict',
|
|
kind: 'record',
|
|
caseKey: 'rfq_ref',
|
|
label: '定价结论',
|
|
fields: [
|
|
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
|
{ name: 'customer_code', type: 'text', primaryKey: false, masked: false, label: '客户码' },
|
|
{ name: 'customer_name', type: 'text', primaryKey: false, masked: false, label: '客户名称' },
|
|
/* 客户等级是 P-01 的入参之一(战略客户 / 普通客户),认不出按普通客户 */
|
|
{ name: 'customer_grade', type: 'text', primaryKey: false, masked: false, label: '客户等级' },
|
|
{ name: 'line_total', type: 'integer', primaryKey: false, masked: false, label: '草案条目数' },
|
|
{ name: 'basis_total', type: 'integer', primaryKey: false, masked: false, label: '有成本基准的条数' },
|
|
/* 算价走完的凭据(0 也要写)—— 哨兵按它放交人核价那一步入场 */
|
|
{ name: 'priced_total', type: 'integer', primaryKey: false, masked: false, label: '已算出建议价条数' },
|
|
/* 「BD 核过价了」的凭据 —— 只在人环走完才产生 */
|
|
{ name: 'confirmed_total', type: 'integer', primaryKey: false, masked: false, label: 'BD 已核价条数' },
|
|
{ name: 'route_decided_total', type: 'integer', primaryKey: false, masked: false, label: '已定盘' },
|
|
{ name: 'summary', type: 'text', primaryKey: false, masked: false, label: '定价结论' },
|
|
],
|
|
},
|
|
],
|
|
listeners: [
|
|
{
|
|
/** 时限过半:SLA <2h,给 BD 与负责人提个醒 —— 静态监听,时限必配 */
|
|
origin: 'static',
|
|
eventType: 'time',
|
|
keyFilter: { kind: 'half-deadline' },
|
|
semantic: 'observe',
|
|
deadline: 'PT1H',
|
|
escalation: ['nudge'],
|
|
},
|
|
],
|
|
harness: {
|
|
memoryWindow: 22,
|
|
// SLA <2h(MVP示例 §1.2 留痕 · SLA)
|
|
stallAfter: 'PT2H',
|
|
nudge: [{ after: 'PT1H', action: 'nudge' }],
|
|
retry: { times: 2, backoff: 'PT30S' },
|
|
},
|
|
},
|
|
|
|
/* ── 资产初始版 ──────────────────────────────────────────────── */
|
|
assets: {
|
|
businessModel: {
|
|
cmmnXml: CMMN_XML,
|
|
narrative: NARRATIVE,
|
|
dmn: P01_DMN,
|
|
steps: PRICING_STEPS,
|
|
phases: PRICING_PHASES,
|
|
},
|
|
skills: PRICING_SKILLS,
|
|
/*
|
|
* 两个局面各一张(与 A2/A3 同款口径):
|
|
* · `pricing-worksheet` 定价工作单 —— 算价与 BD 核价期间摆它(逐颗定价档案、
|
|
* 两把尺、填回工作表);
|
|
* · `pricing-roster` 报价草案清单 —— 拍板、放行、归档摆它。
|
|
*/
|
|
viewTemplates: [
|
|
{ name: 'pricing-worksheet', html: PRICING_WORKSHEET },
|
|
{ name: 'pricing-roster', html: PRICING_ROSTER },
|
|
],
|
|
cardSchemas: {},
|
|
distillHooks: [
|
|
{
|
|
on: 'terminal',
|
|
prompt: '归纳本单定价:哪些组合的毛利档被人回调过、底价门禁拦下的形态、破线的理由与拍板结果。',
|
|
},
|
|
],
|
|
},
|
|
|
|
/* ── 样例集 —— 三条形状真不同(常备案例即验收案例)───────────── */
|
|
samples: [
|
|
{
|
|
/*
|
|
* ① 寻源转来 · 常路:A3 `quotation` 口的真实形状 —— rows 里清单行(带底价与价源)
|
|
* 混着结论行。客户目标价都在底价线之上,全 PASS,不必叫人拍板。
|
|
*/
|
|
name: '寻源转来 · 两条料底价齐 · 全在底价线之上(常路)',
|
|
input: {
|
|
rfqRef: 'RFQ MD14.1',
|
|
customerCode: 'CU-0142',
|
|
customer_name: 'Itelma',
|
|
rows: [
|
|
{
|
|
rfq_ref: 'RFQ MD14.1',
|
|
pn: 'BBPY00201209601Y00',
|
|
customer_pn: '4-14-01502',
|
|
category: '滤波器',
|
|
brand: 'YAGEO',
|
|
eau: 30000,
|
|
target_price: 0.085,
|
|
lead_time: '8周',
|
|
type_tag: 'B',
|
|
base_price: 0.058,
|
|
price_basis: 'SOURCED',
|
|
supplier: '深圳华强渠道',
|
|
},
|
|
{
|
|
rfq_ref: 'RFQ MD14.1',
|
|
pn: 'CJTB0101R6N',
|
|
customer_pn: '4-00-04102',
|
|
category: '集成电路',
|
|
brand: 'Jiangsu Changjing',
|
|
eau: 60000,
|
|
target_price: 0.42,
|
|
lead_time: '6周',
|
|
type_tag: 'A',
|
|
base_price: 0.35,
|
|
price_basis: 'HIST',
|
|
},
|
|
{ rfq_ref: 'RFQ MD14.1', quote_line_total: 2, route_decided_total: 1, customer_name: 'Itelma', summary: '两条底价齐,交定价' },
|
|
],
|
|
},
|
|
expect: { ports: ['draft'] },
|
|
},
|
|
{
|
|
/*
|
|
* ② 有超限条目:客户把目标价压到成本之下(0.06 对成本 0.082)——
|
|
* 偏离底价线超过两成,门禁判 BLOCK,必须叫人拍板(决策卡)。
|
|
*/
|
|
name: '客户压价 · 一条低于底价线两成以上 → 决策卡叫人拍板',
|
|
input: {
|
|
rfqRef: 'RFQ-2026-0777',
|
|
customerCode: 'CU-0311',
|
|
customer_name: '青岛海洋电子',
|
|
rows: [
|
|
{
|
|
rfq_ref: 'RFQ-2026-0777',
|
|
pn: 'PESD2ETH-XR',
|
|
category: '二极管',
|
|
brand: 'Nexperia',
|
|
eau: 30000,
|
|
target_price: 0.06,
|
|
lead_time: '8周',
|
|
type_tag: 'B',
|
|
base_price: 0.082,
|
|
price_basis: 'SOURCED',
|
|
remark: '客户明说这个价是竞对给的,要跟',
|
|
},
|
|
{
|
|
rfq_ref: 'RFQ-2026-0777',
|
|
pn: 'NE555P',
|
|
category: '定时器',
|
|
brand: 'TI',
|
|
eau: 5000,
|
|
target_price: 1.05,
|
|
lead_time: '4周',
|
|
type_tag: 'A',
|
|
base_price: 0.85,
|
|
price_basis: 'HIST',
|
|
},
|
|
{ rfq_ref: 'RFQ-2026-0777', quote_line_total: 2, route_decided_total: 1, customer_name: '青岛海洋电子' },
|
|
],
|
|
},
|
|
expect: { ports: ['draft'] },
|
|
},
|
|
{
|
|
/*
|
|
* ③ 单飞宽进:没有单号没有清单,正文列料 —— 归一造案号;库内查不到历史价,
|
|
* 系统一个价都不编,两行拟报单价空着交 BD 定 → **提交闸真拦**空手交卷。
|
|
*/
|
|
name: '单飞需求 · 正文列两颗料 · 库内无基准 → 价由人定(闸真拦)',
|
|
input: {
|
|
subject: '两颗料报个价',
|
|
body: '客户要两颗料的报价:XCJ-7788T 电源模块 8K,目标价 12.5;LMR-3302QQ 稳压器 15K,没给目标价。库里应该没做过这两颗,你先出个草案。',
|
|
},
|
|
expect: { ports: ['draft'] },
|
|
},
|
|
],
|
|
|
|
entry: { file: 'index.js', checksum: 'dev-entry-quote-pricing' },
|
|
};
|