Repository navigation
Finance records its own review through a Record Finance Review action - #194
Merged
Merged
Conversation
Add the record_finance_review action on clm_contract and the screen flow it starts. Finance cannot write a clm_review directly on a contract in review or in approval: the detail is controlled_by_parent and finance edits contracts only from approved onward. The flow runs system-elevated, gated by clm_finance.access on both the action and the flow, and creates or updates the caller's finance-stage review on the contract the route loaded in the caller's scope. It writes nothing on the contract. The demo deals the 7 pre-approval finance reviews back to the finance controller, and the README counts follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
A custom record page replaces the default header, so a declared action is reachable from the record only once the page names it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
Contributor
Author
席位核对 — ACCEPT · head
|
| check | reading |
|---|---|
| shape | → main, Fixes #190; mergeable clean |
| CI on the head | both Validate check-runs success on 1692389 = PR head.sha |
| scope | 11 files (+339/−26), inside the claim as amended (comment 6609066644). New record_finance_review action on clm_contract (record header, visible only in in_review / in_approval, gated on clm_finance.access, which only the finance set holds, so no new capability). It starts a type: 'screen', runAs: 'system' flow of the same name, gated on the same token, as in the PR #177 precedent. The flow creates or updates the caller's stage=finance review with reviewer = the caller, and writes nothing on the contract. The contract is the one the action route loaded in the caller's own scope. reviewerOf gives all 23 finance reviews back to the finance controller. Nothing governed; lint 0 warnings |
| ruling D, measured as finance@ (zh-CN) | in_review: the first press creates 1 review (200), the second updates the same row. in_approval: create then update, 1 row; the seeded review is updated in place. Direct PATCH clm_contract, POST clm_review, and a PATCH of its own review are all still 403. submitted and active are refused with a translated sentence and nothing written. requester1 is refused at the action route and at the trigger route, and sees no button. In the browser: the button shows in in_review / in_approval only, the dialog is translated, and the toast reads 「财务审查已记录。」 |
| re-run | pnpm demo twice: 1130 rows, nothing refused. The 2 reviews the action created are left alone, with no duplicates |
| residuals (noted) | a review write moves the contract's updated_at (the platform's roll-up recompute; same for a direct legal edit). The 审查与偏离 tab badge lagged its list once after refresh. On a DB seeded before this change and not re-seeded, a press can add a second finance review beside the one still dealt to the legal head; re-running pnpm demo resolves it |
| governed text | the §04 cell 「RCU(stage=finance)经「记录财务审查」动作」 and the §10 dealing sentence without the pre-approval exception go to PR #120 |
Landing: under the maintainer's merge authorization (project thread: 「你可以自己审核的就自己合并」).
Generated by Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #190
Clause-②: no
Metadata-protocol: none
Ruling D (comment 6607878401): finance records its own finance review through a declared action while the contract is In Review or In Approval. Finance still gets no edit on the contract, and the direct writes it was refused before are still refused.
What changed
src/actions/finance-review.actions.ts(new):record_finance_review(记录财务审查) onclm_contract.type: 'flow',record_header,visiblewhilestatusisin_revieworin_approval,requiredPermissions: ['clm_finance.access']. The dialog has three field-backed params withobjectOverride: 'clm_review':decision(required),risk_level_assessed,comments. They inherit the review's labels and options in both locales.src/flows/finance-review.flow.ts(new): therecord_finance_reviewflow.type: 'screen',runAs: 'system',requiredPermissions: ['clm_finance.access']. This is the same shape asexecuted_upload([Decision] §06 F16 说补录动作「档案岗**或**法务可用」,但实现只能给档案岗——权限是 AND,没有两边都持有的能力 #43, PR §06 F16 说补录动作「档案岗或法务可用」,但实现只能给档案岗——权限是 AND,没有两边都持有的能力 #177), because 18.2 refuses non-system starts of a self-triggered system flow. The flow:record, the row the action route loaded in the caller's scope. A contract finance cannot read answers 404 before the flow runs. The flow declares no input that could name a different contract.stage: 'finance'review (reviewer == current_user.id), updates it if it exists, and creates it otherwise. On the update path, a field left empty in the dialog keeps its stored value.src/flows/index.ts: registers the flow.src/pages/contract_detail.page.ts: addsrecord_finance_reviewto the header'sactions. The custom record page replaces the default header, so without this line the action has no button (start_renewalhit the same thing).en/zh-CNobjects.contract.ts, and the two refusal sentences inen/zh-CNflows.ts.src/data/keys.ts:reviewerOfnow deals all 23 finance reviews to the finance controller. The 7 on contracts that are not yet approved (6in_review, 1in_approval, all routed to finance) used to go to the head of legal. The doc comment is rewritten to match.README.md: persona table: Head of Legal now has 1 review, Finance Controller has 23. The review-dealing paragraph is updated.No capability added.
clm_finance.accessis held byclm_financealone, andclm_legal.accessalready serves the legal-only actions the same way.clm_admindoes not hold it, but admin writes reviews directly.Measured (18.2.0,
pnpm demo:zh, port 3163, throwaway DB, declared demo staff, zh-CN)Before (origin/main 7e7c2dc):
Finance · Head of Legal7 ·Finance · Finance Controller16 ·Legal · Head of Legal1.POST /api/v1/actions/clm_contract/record_finance_review/ID-> 404 "has no declaration".POST /api/v1/data/clm_review(stage finance, in_review contract) -> 403 "requires edit access to its master record". The same 403 forPATCHof the in_approval contract's finance review.After (HEAD 1692389), API as finance@:
Finance · Finance Controller), decisionchanges_requested, riskmedium, the comment,decided_atstamped, andcreated_by/updated_by= finance@.decision: approved-> 200. It updates the same row (the review id is unchanged and there is still 1 finance review). The comments and risk are kept.PATCH clm_contract-> 403 PERMISSION_DENIED.POST clm_review-> 403 "insert on 'clm_review' requires edit access to its master record".PATCHof finance@'s own in_review review -> 403 "update ... requires edit access to its master record".refusedwith 「财务审查在合同处于「审查中」或「审批中」时记录。从「已批准」起,财务直接在合同上修改这条审查。」. Nothing is written.POST /api/v1/automation/trigger/record_finance_review, with arecordsmuggled into params ->refusedwith 「财务审查要从它所审查的合同上记录。…」. Nothing is written.After, browser (Chromium, zh-CN):
POST /api/v1/actions/clm_contract/record_finance_review -> 200and the toast 「财务审查已记录。」.approved, and the comment is kept.Finance · Finance Controller · 财务 · Finance Controller · 通过 · 中.Re-run safety:
pnpm demo:zhrun 1 on a clean DB -> 1,130 rows (contracts 120, versions 300, reviews 60, deviations 25, signatures 30, obligations 200, payment plans 300, parties 40). Reviews dealt: Finance · Finance Controller 23, Legal · Head of Legal 1, Legal Counsel 1/2 16/18, Business 1/1. Run 2 on the same DB -> bannerSeeds: app.objectstack.hotclm 1130 rows, nothing refused. Reviews 62 = the 60 seeded plus the 2 the action created, which were left alone. No duplicates.Gates (HEAD 1692389)
pnpm install-> exit 0pnpm validate-> exit 0,✓ Validation passed. The 7 warnings are the pre-existing hierarchy-security and contract_approval ones.pnpm lint-> exit 0,6 suggestion(s), 0 warnings (same as main)pnpm typecheck-> exit 0pnpm lint:i18n-gate-> exit 0,✓ i18n gate · COVERAGE : 0 missing keys across 2 locale(s)CLM_DEMO_SEED=1 pnpm validate-> exit 0,✓ Validation passedAcceptance notes
updated_atmoves on every review write. It is not the flow writing the contract: the platform recomputes the contract'ssummaryroll-ups on every child write, and that stamps the parent. Measured: after a press onlyupdated_atchanged. Control: a legal head's directPATCHof a review movedupdated_atandupdated_bythe same way. No contract field the flow could write is touched.started_atis left empty on a review the action creates. The ruling names three fields, and onlydecided_atis stamped (review_decision_stamp).externalId: ['contract', 'stage'], while the action keys on(contract, stage, reviewer)as the ruling asks. On a database seeded before this PR and not yet re-seeded, a finance press on a contract whose seeded finance review still names the head of legal would add a second finance-stage row. Not measured. Apnpm demore-run moves the reviewer to finance first.1while the list showed 2 rows after the in-page refresh. Not investigated.src/data/keys.ts/negotiation.seed.tsand the README. This PR also touchessrc/flows/finance-review.flow.ts,src/flows/index.ts,src/translations/{en,zh-CN}/flows.ts(the flow the dispatch prescribed, after the [Decision] §06 F16 说补录动作「档案岗**或**法务可用」,但实现只能给档案岗——权限是 AND,没有两边都持有的能力 #43 precedent) andsrc/pages/contract_detail.page.ts(without it the button is unreachable).src/profiles/**,objectstack.config.tsandnegotiation.seed.tsare untouched.Governed text (proposed, not edited; for the design-doc PR #120)
clm_review·clm_finance:RCU(stage=finance)经「记录财务审查」动作clm_reviewrow: 审查人按环节分派:法务 → 合同法务负责人(无则法务负责人);财务 → 财务负责人;合规 → 法务负责人;业务 → 发起人🤖 Generated with Claude Code
https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn