Skip to content

docs(contracts): 按到期/续约 flow 与 contract.object.ts 重写三语剩余三处失真 (#826) - #831

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-826-contracts-residual-drift
Aug 5, 2026
Merged

yinlianghui merged 1 commit into
mainfrom
claude/issue-826-contracts-residual-drift

Conversation

@yinlianghui

Copy link
Copy Markdown
Contributor

Fixes #826

#805 / PR #823 只裁定了同页的「合同激活时」小节。本 PR 收掉该页其余三处,均不由 #823 的改动导致,#823 的改动原样保留。

前提复核(逐条,基线 origin/main = 4c12791,#823 已在其中)

issue 说法 复核结果
到期扫描第 3 条「给客户负责人的通知」不存在 成立。src/flows/contract-expiration.flow.ts 循环体只有 mark_expired 与 notify_owner 两个节点,收件人是 {currentContract.owner_id} 单值;全流程没有第二个 notify,也没有任何地方读客户的 owner_id
续约提醒的「一键创建续约商机」不存在 成立。contract-renewal.flow.ts 的 notify_owner 只有 actionUrl: '/crm_contract/{currentContract.id}';续约商机由 create_renewal_opp 在 auto_renewal == true 且该客户无在途续约商机时自动建
同一句漏了真正会先做的 create_renewal_task 成立。边序为 create_renewal_task → notify_owner → check_auto_renewal,任务在通知之前
activation_date / renewal_terms / account_exec / order_form 是幽灵字段 成立。四个名字在 src/ 下各自 grep -rn 零命中
Renewal Terms 在同页被二次推荐 成立。「续约」小节的第三条 bullet 与「给合同所有者的提示」第三条,各推荐一次
文件面 content/docs/revenue/contracts.mdx ×3 成立

改了什么(三语同步)

1. 到期扫描:两步,不是三步

第 3 条删掉,第 2 条按声明写实(收件人只有合同负责人,channels: ['inbox','email'],链接指向合同)。并按 #823 的做法补两条决定「会不会轮到这份合同」的机制:扫描的 filter 只取 status: 'activated'(过了结束日期却停在 Draft / In Approval 的合同不动),limit: 500 封顶。另加一句明确「除合同负责人外无人收到」——这正是 issue 影响分析里「客户负责人以为合同到期会有人通知他」的那一条。

2. 续约提醒:按边序写全三步,并说明「不是你点出来的」

原文一句话里两处失真(有一键操作、只发提醒),现在按 flow 的执行顺序列三条:先建续约任务(页面此前从未提过)→ 通知(链接到合同详情页,没有任何一键操作,点开不创建任何东西)→ 仅当 auto_renewal 打开时开续约商机(写明它复制的值:金额取 contract_value、关闭日期取 end_date、负责人取 owner_id、阶段 proposal、类型 Existing Customer - Renewal、next step Confirm renewal terms with customer,以及「该客户已有在途续约商机则跳过」)。

补了两条读者最可能踩到的机制:

  • 幂等靠那条任务:find_existing_task 按 subject + status $nin ['completed'] 匹配,命中就整链停住(连通知都不发);把任务标记完成后,第二天的扫描会再建一条新的——这一点对「为什么它又提醒了一次」是直接答案。
  • 120 天前置过滤:query_contracts 的 end_date $lte {TODAY() + 120},所以续约通知天数设得大于 120 时,要到 120 天这个点才开始触发。页面同时在提示里教读者设 90 天,写清这条边界才不至于反过来误导。

3. 记录字段表:按 fieldGroups 重建,四个幽灵字段点名说明

按 issue 的建议、比照 #792 在 leads / contacts 上的做法,整张表用 contract.object.ts:29-36 的六个 fieldGroups 重写(Contract Information / Parties / Terms & Dates / Contract Value / Status & Approval / Renewal),21 个字段全覆盖,并补了此前表里根本没有的 Primary Contact(required: true)等字段,另标出必填集合。

四个幽灵名字没有默默删掉,而是点名交代能力实际落在哪儿——照着找过的读者需要一个去处:

  • Activation Date → 没有任何字段记录激活时刻,激活盖的是 Signed Date(docs(contracts): 以 contract.hook.ts 为唯一事实来源重写三语「合同激活时」小节 (#805) #823 刚写下的那条);
  • Renewal Terms → 续约只有两个字段,自由文本写进 Special Terms;
  • Account Exec → 所有权只有 owner_id 一个查找字段;
  • Order Form / 「两个 file 字段」→ Contract Document 是 Field.url(标签 Contract Document),是链接不是上传;已签署 PDF 走记录附件(enable.files: true,contract.object.ts:230),没有单独的 Order Form 字段。

「续约」小节与「给合同所有者的提示」里 Renewal Terms 的两处推荐一并改指 Special Terms;「三个字段驱动续约」改为两个。

同页一致性(#794 先例,已披露)

  • 表里的 Auto Renewal / Renewal Notice (Days) 取自对象声明的真实标签,「续约」小节与提示里的 Auto-Renew / Renewal Notice Days 随之对齐(并写上 defaultValue: 30)。
  • 两个 zh 页的计费频率 → 计费周期 / 計費週期:新表的字段名与区块名都取自语言包(src/translations/zh-CN.ts:535 billing_frequency.label = '计费周期',_sections 给出六个区块的中文名),若表内写「计费周期」而同页小标题仍写「计费频率」就是本次改动新造的不一致。按 docs(sales): 让 zh 页的线索状态名、到期日期、直属上级与区块名跟随语言包 (#801) #825「zh 页面按语言包对齐」的先例一并改成语言包的拼法(小标题 + 给管理员的提示各一处)。该小节内的选项列表本身另有失真,不由本次改动导致,未在本 PR 修改,见下。

越界发现(已单独立单,未在本 PR 修改)

同页另有四处与实现不符,均与本 issue 的三处无因果关系,按越界纪律另开一单(不带 label、未 assign),见 report。简述:标准列表视图五条全是幽灵(真实视图是 All Contracts / Renewal Calendar / Contract Terms / Contract Timeline);计费周期的 Custom、付款条款的 Net 45 与 Prepaid 三个选项不存在;「已激活的合同不能被删除」没有任何实现(删除权限只由 profile 控制,与状态无关),且该小节漏掉 hook 里两条真实校验与状态机;「给销售代表的提示」教销售代表创建合同并称商机链接会预填,但 sales-rep.profile.ts:52 是 allowCreate: false, allowEdit: false,且没有任何地方预填该链接。

不加钉子测试(散文)。仅文档,无 metadata / 行为 / 字段变更;src/** 与 content/docs/releases/ 未动。要不要真加 activation date / renewal terms / account exec、要不要把合同文档做成 file 字段,仍是产品决定。

验证

四件套全绿(flock -w 7200 /tmp/os-heavy-verify.lock,NODE_OPTIONS=--max-old-space-size=4096,vitest --maxWorkers=2):

pnpm validate  → ✓ 17 Objects 344 Fields / 24 Flows   exit=0
pnpm typecheck → tsc --noEmit                          exit=0
pnpm build     → ✓ Build complete (1502ms)             exit=0
pnpm test      → Test Files 64 passed (64)
                 Tests 1560 passed | 1 skipped (1561)  exit=0
pnpm lint      → 13 warning(s), 14 suggestion(s)       exit=0(均为既有,与本 PR 无关)
pnpm hygiene   → ✓ source hygiene clean

控制字符自扫(pnpm hygiene 只扫 src/test/e2e/scripts,不覆盖 content/):

grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' content/docs/revenue/contracts*.mdx \
  .changeset/contracts-docs-residual-drift.md
→ 零命中(exit=1)

Generated by Claude Code

…flows and the object (#826)

The expiration sweep's second notification, the renewal reminder's one-click
action, and four ghost fields on the record table — all three languages.

- contract-expiration.flow.ts notifies only `{currentContract.owner_id}`; the
  page's third step promised the account owner a message nobody sends.
- contract-renewal.flow.ts's notify carries actionUrl to the contract detail
  page. There is no "Create Renewal Opportunity" button; the renewal deal is
  created by the flow when auto_renewal is on, and the renewal task the flow
  files first was never documented at all.
- activation_date / renewal_terms / account_exec / order_form are zero hits
  under src/. The table is rebuilt from contract.object.ts's six fieldGroups
  (#792's shape), and Renewal Terms' second recommendation further down the
  page goes with it.

Docs only. No src/ change — whether Contract should carry any of those four
fields is a product decision and stays open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHrPAGEgFDoHjphqYG4BMa
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hotcrm Ignored Ignored Aug 5, 2026 10:44pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

contracts.mdx 剩下三处与实现不符:到期扫描的第二条通知、续约提醒的「一键操作」、记录字段表里的四个幽灵字段

2 participants