-
ErpClient.fieldOptions 调 /ai/fieldOptions(契约见 docs/erp-tasks-field-options.md): ERP 按其控件配置给候选,带行级数据权限、级联过滤(产品限定在已选客户名下)、 联动回填映射——这三样本地直查库都没有。404/异常/mode=none 一律回落到 FormResolverService.fkOptionPage,5 分钟退避避免反复撞未上线的端点。 前端 FK 选择器改传 (formId, 字段, ctx):ctx = 表单上已绑定记录的 id,供级联过滤; ERP 报 need_context 时提示'请先选择客户'而不是给空列表。预览卡新增 formId 与 fk 字段的 boundId,使修改单据时也有初始级联上下文。
-
…expired key; preview save name-keyed + empty=abandon-change; previewId atomic claim; transactional batch queue + column truncation; digest zone token-budgeted; window-orphan tool_result trim; convId length cap; readFormData authoritative moduleId + /form/options permission gate (security audit); WRITE_CLAIM state-statement lookahead
-
…p+CAS, tenant enforcement Audit findings 1-5 confirmed real; root causes were (a) identity self-reported by the client, (b) every failure path defaulting open. - ERP /ai/whoami (saas-8s+ @c8e0057 follow-up) resolves token → real user/tenant/type; AuthzService.resolveIdentity is now the single identity entry point. Client-supplied userid/brandsid/usertype removed from all request bodies and from chat.html. - dev-login is a real switch (erp.dev-login.enabled, default false) and its ERP creds no longer have built-in admin/666666 defaults; blank token in production → 401, never a silent fall back to the dev (sysadmin) account. - conversations/op/form endpoints require login; conversation ids are namespaced by user id and ownership-checked (403 otherwise); /op/pending no longer returns sPayload. - op confirm/cancel check the proposer, and confirm claims the draft via CAS so concurrent/repeat confirms cannot execute twice; bill numbers are regenerated at execution time instead of replaying the propose-time snapshot. - FK options take the tenant from the introspected identity and return empty rather than dropping the sBrandsId predicate. - secrets moved to env vars (DB_URL/DB_USERNAME/DB_PASSWORD/REDIS_*/LLM_*/ERP_BASEURL); allowMultiQueries=false. NOTE: the previously committed credentials must be rotated. - ids interpolated into ERP URLs are validated (safeId) to stop query/path injection. - update path rejects system columns, resolves FK names, and coerces by column type; numeric coercion now rejects unparseable input instead of writing 0/truncating, and proposal summaries show the value that will actually be written. - ResponseStatusException keeps its 401/403 status instead of being wrapped as 200. - anti-fabrication guard stays on when the intent gate itself fails.
-
…r free-input flag, readFormData paging - POST /api/agent/form/submit: structured fields go straight to proposeWrite(action=create), no LLM re-encoding; ledger/state/memory recorded - GET /api/agent/form/options: {columns,rows,total,page,pageSize} with name search - askUser result carries allowFree=true (last option is always free text) - readFormData(page?) with page shown in output
-
User: form rendered every field as a plain text box; no type (dropdown/date/number), and FK fields didn't pull options from their source tables. - FormCollect schema now carries per-field type: fkselect | select | number | date | text (+ options for select, fkTable for fkselect, hint for placeholder). Types inferred from column data type for generic forms; curated for quote. - New GET /api/agent/form/options?table=&q=&brandsid= -> FK options from the source table (elecustomer/eleproduct/elematerials...), whitelisted to tables that appear as sFkTable in the field dict (rejects arbitrary tables e.g. gdslogininfo), tenant-filtered + LIMIT. - chat.html renderFormCollect renders by type: fkselect = searchable <input list=datalist> that fetches options on focus/typing; select = <select>; number = <input type=number>; date picker; text. - Fix: tolerant label matching (strip parentheticals) so '多数量' maps whether or not the LLM keeps the '(逗号分隔)' hint -> multi-qty rows now reliably created. Verified via agent: quote form shows 客户/产品/物料=fkselect, 单位/印刷/颜色/单双面=select, 尺寸/数量/单价/系数=number; options endpoint returns real names (客户 q=Little -> Little Antelope); non-FK table rejected; full write incl 多数量 (BJD202607086 -> 2000/4000/6000).