币种管理汇率逻辑调整 PRD

来源:币种管理汇率逻辑调整_PRD_v2_20260512.md

币种管理汇率逻辑调整 PRD

版本:v1.1 | 创建日期:2026-05-12 | 更新日期:2026-07-31

需求来源:产品现状问题 + 本地代码验证 + 竞品录屏调研 + 官方文档

优先级:P1 | 文档状态:草稿

适用范围:多币种管理、金额字段个人币种展示、汇率函数、原币到转换币查询接口


一、需求概述

1.1 需求背景

核心问题: 当前纷享销客多币种管理中,既可以在本位币视角维护“1原币 -> n本位币”的汇率,也可以在某个原币视角维护“1其他原币 -> n当前原币”的汇率。现有运行逻辑只读取指定方向的人工汇率,不会同时取两套值;问题在于各方向需独立维护,容易漏维护、长期未更新或与本位币口径不一致。

核心结论:汇率人工维护只保留“原币 -> 本位币”一个事实源。新企业默认使用该模型;历史企业通过不可逆的一次性开关切换,开启后原币间人工汇率直接失效。

本需求不是反馈驱动,而是系统汇率模型的逻辑优化。背景部分只记录当前系统现状、截图情况和由此产生的产品问题。

系统现状与截图情况:

系统现状截图/依据当前表现问题与优化方向
本位币入口可维护原币到本位币汇率币种管理维护原币与本位币之间汇率管理员可以从本位币视角维护其他币种到本位币的汇率该入口符合中心汇率模型,应保留为唯一人工维护入口
非本位币入口也可维护原币到原币汇率币种管理维护原币之间的汇率从某个原币进入“调整汇率”后,可以维护其他原币到当前原币的汇率各方向汇率独立维护,缺少统一推导口径;统一换算后移除该入口
前台展示个人币种换算值展示转换后的个人币种值金额字段展示原币金额,同时在括号中展示个人币种金额;这个汇率的参考就是取的 原币到原币的汇率转换展示能力需要保留,但汇率应由本位币汇率派生,不应要求管理员单独维护原币间汇率
系统已开放原币到转换币查询能力EXCHANGERATE(currency1,currency2,defaultValue)find_exchange_rate_by_currency公式和接口可按原币、转换币查询汇率不能直接删除原币到原币能力,需要在原有查询链路中增加本位币派生兜底

竞品情况:

产品截图关键机制产品判断
SalesforceSalesforce 币种列表管理有效币种、公司币种标识、兑换率、小数位数汇率围绕 Corporate Currency 维护,不提供任意原币对原币的人工维护入口
SalesforceSalesforce 新增币种新增币种时填写兑换率和小数位数新增币种的汇率心智是相对公司币种
HubSpotHubSpot 账户币种列表账户币种列表展示汇率、格式、更新时间,支持自动汇率更新和汇率日志围绕 Company Currency 管理汇率,强调中心化维护和更新记录
Zoho CRMZoho CRM 手册:货币列表与基础货币手册截图中货币列表直接标识“基础货币:人民币-CNY”,其它货币围绕基础货币展示汇率Zoho 将基础货币作为组织级汇率锚点,而不是维护任意原币对
Zoho CRMZoho CRM 手册:编辑货币汇率编辑货币弹窗中维护单个货币的“汇率”字段汇率维护入口围绕单个货币到基础货币的关系展开

官方资料:

为什么围绕本位币维护汇率是更规范的方案:

下图说明两种模式的本质差异。左侧任意两个币种之间均可双向人工维护;以 AED、USD、CNY 三个币种为例,共有 3 × 2 = 6 条有向汇率关系。右侧只维护“非本位币 -> 本位币”两条中心汇率,其余四条有向关系均由系统派生。

币种汇率两种维护模式示意图:现状为三币种两两双向独立维护共六条关系,结果可能不一致;目标仅有 AED 到 CNY、USD 到 CNY 两条单向人工维护关系,其余四条由系统派生

图示结论:现状按换算方向直接读取对应的人工汇率,不会同时比较本位币派生值,因此不存在多套结果同时参与计算的取值冲突。问题在于六条汇率独立维护,正反向可能不互为倒数,原币间汇率也不会随本位币汇率同步更新。目标态的实线箭头仅允许单向指向本位币:只维护 AED -> CNYUSD -> CNY 两条中心汇率;CNY -> AEDCNY -> USDAED -> USDUSD -> AED 均为唯一的派生结果。

对比维度围绕本位币维护汇率维护任意原币到原币汇率结论
汇率事实源每个币种只维护一条“原币 -> 本位币”汇率,其他方向统一派生每个换算方向都是独立人工配置,彼此无法自然校验本位币方案口径唯一,更容易解释和审计
维护成本N 种币种只需维护 N-1 条汇率N 种币种理论上需维护 N×(N-1) 条汇率,容易漏维护或长期未更新本位币方案维护量更低,币种越多优势越明显
汇率更新任一本位币汇率变化后,相关原币间汇率自动重新派生本位币汇率变化后,原币间汇率不会同步,需要管理员逐条调整本位币方案避免关联汇率过期
数据一致性原币间及正反向汇率均由同一公式计算,可相互验证正反向可能不互为倒数,原币间汇率也可能与本位币汇率隐含结果不一致本位币方案保证不同换算方向使用同一推导口径
报表与统计金额展示、公式、接口和报表可统一使用组织本位币口径各方向仅能读取对应的人工汇率,无法自然形成统一的本位币推导口径CRM 业务需要组织级本位币口径
前台个人币种展示通过“数据原币 -> 本位币 -> 个人币种”稳定派生需要提前维护数据原币到各个人币种的单向汇率,否则无法完成对应换算本位币方案保留展示能力,同时减少配置依赖
适用边界适合 CRM 中金额展示、统计、报表和通用换算适合需要交易级外汇牌价、买入价/卖出价的金融场景当前多币种管理更接近 CRM 记账与展示场景,应采用本位币锚点

因此,本期不是下掉“原币到原币换算能力”,而是把它从“独立人工维护”调整为“系统统一派生”。这样既能保留个人币种展示、函数和接口查询,又能减少漏维护、汇率过期和不同方向结果不一致的问题。

现状依据:

类型依据结论
本地代码vui/src/modules/multi-currency/modules/adjust_rate.vue当前调整汇率弹窗区分本位币入口和非本位币入口;非本位币入口会查询目标币种下的原币汇率
本地代码vui/src/modules/multi-currency/common/api.js管理端存在批量修改汇率和单独更新原币到目标币汇率 API
本地代码vui/src/modules/multi-currency/modules/adjust_rate.vue现有管理端人工汇率输入限制为整数最多 10 位、小数最多 6 位
本地代码vui/src/modules/multi-currency/modules/update.vueadjust_rate.vueupdate_gray.vue现有校验覆盖必填、格式和小数位,未校验汇率必须大于 0
本地代码fs-paas-appframework/fs-paas-app-metadata-util/src/main/java/com/facishare/paas/appframework/metadata/MtCurrency.java币种模型中exchangeRate 表示“到本币的汇率”
本地代码fs-paas-appframework/fs-paas-app-metadata-dao/src/main/java/com/facishare/paas/appframework/metadata/repository/model/MtCurrencyExchange.java当前汇率对象支持from_currency_codeto_currency_code
本地代码fs-paas-appframework/fs-paas-app-metadata/src/main/java/com/facishare/paas/appframework/metadata/MultiCurrencyLogicServiceImpl.java个人币种展示会查询“原币 -> 个人币种”的汇率集合
本地代码vui/src/components/expression/config/expression_function.js前端已暴露EXCHANGERATE(currency1,currency2,defaultValue)
本地代码fs-paas-appframework/fs-paas-app-core/src/main/java/com/facishare/paas/appframework/core/predef/service/ObjectMultiCurrencyService.java服务端存在find_exchange_rate_by_currency 接口,按原币和转换币查询汇率
本地代码fs-paas-appframework/fs-paas-app-metadata/src/main/java/com/facishare/paas/appframework/metadata/expression/Expression.java通用公式数值结果按字段精度使用HALF_UP 舍入

产品价值:

  1. 统一多币种汇率推导口径,使不同换算方向的结果可以相互验证。
  2. 降低管理员维护成本,从维护 N×(N-1) 条有向汇率收敛为维护 N-1 条原币到本位币汇率。
  3. 保留个人币种展示、汇率函数、汇率查询接口等现有能力,降低存量企业受影响风险。

1.2 需求目标

  1. 管理端只允许人工维护“原币 -> 本位币”的中心汇率
  2. 新企业从启用多币种起不再创建或维护原币到原币汇率;原币间及个人币种换算均按中心汇率实时派生。
  3. 历史企业提供一次性开启入口;开启后不可关闭,已有原币间人工汇率立即失效。
  4. 个人币种展示、汇率查询和换算仍保留,统一使用本位币汇率实时派生的结果。
  5. 人工录入的汇率必须大于 0,前端与服务端统一校验。

二、产品方案

2.1 整体方案

本次采用“中心汇率 + 派生换算”方案:只人工维护“原币 -> 本位币”汇率,原币间汇率由系统实时计算。

  • 新企业:默认使用统一换算,不展示模式开关和原币间“调整汇率”入口。
  • 历史企业:未开启时保持现状;企业管理员可一次性开启“本位币统一换算”,开启后不可关闭。

派生规则:

rate(A -> B) = rate(A -> 本位币) / rate(B -> 本位币)

示例:

币种到本位币 CNY 汇率
AED0.888
USD7.200
AED -> USD = 0.888 / 7.200 = 0.123333

1 AED = 0.123333 USD

2.2 管理端交互与文案

最新交互稿:https://www.figma.com/design/jNBOlieKd8r8cMqTL8FAsz/%E5%9B%BD%E9%99%85%E5%8C%96?node-id=7971-2925

开关区域

文案中文English
名称本位币统一换算Functional Currency Conversion
说明开启后,仅维护“原币 -> 本位币”汇率,原币间汇率由系统实时计算。Once enabled, only source-to-functional-currency rates are maintained. Cross-currency rates are calculated automatically.
操作了解并开启Review and Enable

开启确认弹窗

文案中文English
标题开启本位币统一换算Enable Functional Currency Conversion
警示开启后不可关闭This change cannot be reversed.
原因开启后,系统将统一以“原币 -> 本位币”汇率作为换算依据,避免原币间人工汇率与系统计算结果不一致。Once enabled, source-to-functional-currency rates become the single basis for conversion, preventing differences between manually maintained cross-currency rates and system-calculated rates.
示例假设 USD 是企业本位币,AED -> CNY 将根据 AED -> USD 和 CNY -> USD 计算,不再使用单独维护的 AED -> CNY 汇率。For example, if USD is the functional currency, AED -> CNY is calculated from AED -> USD and CNY -> USD instead of using a separately maintained AED -> CNY rate.
影响 11. 汇率规则:原币间人工汇率立即失效,后续根据两种原币各自到本位币的汇率实时计算。1. Rate rules: Manually maintained cross-currency rates become invalid immediately. Future rates are calculated in real time from each currency's rate to the functional currency.
影响 22. 管理入口与历史记录:币种列表不再展示原币间“调整汇率”;“查看历史汇率”仅展示人工修改的“原币 -> 本位币”汇率。2. Management and history: Cross-currency rate adjustment is removed from the currency list. Rate history only shows manually changed source-to-functional-currency rates.
影响 33. 函数与 OpenAPI:原币间汇率更新函数及 OpenAPI 不再接受写入;查询和换算能力继续可用,并使用系统计算的汇率。3. Functions and OpenAPI: Cross-currency rate update functions and OpenAPI no longer accept writes. Queries and conversions remain available and use system-calculated rates.
影响 44. 业务数据:历史单据和已落库金额不重新计算;若原人工汇率与系统计算结果不同,开启后的新查询和新换算结果可能变化。4. Business data: Historical records and stored amounts are not recalculated. If previous manual rates differ from system-calculated rates, new queries and conversions may return different results after enablement.
确认勾选我已了解以上影响,并确认将当前企业切换为本位币统一换算模式。I understand the impact and confirm enabling Functional Currency Conversion for this organization.
主按钮确认开启Enable
次按钮取消Cancel

仅历史企业且尚未开启时展示该配置;新企业和已开启的历史企业均不展示。

2.3 并发管理员的失效入口处理

管理员 A 开启统一换算后,管理员 B 的未刷新页面可能仍显示原币间“调整汇率”。系统以服务端的最新企业模式为准:点击入口时重新校验,保存接口也必须再次校验,不允许通过旧页面继续写入。

文案中文English
标题汇率调整不可用Rate Adjustment Unavailable
提示当前企业已开启本位币统一换算,原币间汇率不再支持调整。请刷新页面查看最新设置。Functional Currency Conversion has been enabled. Cross-currency rates can no longer be adjusted. Refresh the page to view the latest settings.
按钮知道了Got It

2.4 运行逻辑调整

场景优化后规则
原币到原币换算新企业和已开启统一换算的历史企业,均按两边到本位币汇率实时派生
个人币种展示统一使用本位币实时派生结果
EXCHANGERATE函数签名和查询能力不变;统一返回本位币派生汇率
find_exchange_rate_by_currency入参、出参和查询能力不变;统一返回本位币派生汇率
原币间汇率更新函数 / OpenAPI统一换算开启后停止写入,返回明确失败结果
历史业务记录不批量回刷,已有记录上的汇率快照保持不变

“查看历史汇率”仅记录管理员人工变更的“原币 -> 本位币”汇率;原币间派生结果不落历史记录。

派生汇率精度与舍入

原币到原币的派生可能产生无限循环小数,例如 1 / 3 = 0.333333...。本期将“汇率精度”和“金额精度”分开处理:汇率用于计算和追溯,金额才是用户最终看到或写入业务记录的值。不得在中间派生步骤按金额小数位截断。

环节精度与舍入规则说明
人工维护的中心本位币汇率沿用现有上限:整数最多 10 位、小数最多 6 位;数值必须大于 0仅适用于“原币 -> 本位币”输入
派生汇率计算直接按 6 位小数HALF_UP 得到派生汇率rate(A -> B) = rate(A -> 本位币) / rate(B -> 本位币);除不尽时在第 6 位四舍五入
派生汇率展示与接口返回展示并返回同一个 6 位派生汇率;末尾无意义的 0 可隐藏与手动录入的汇率位数要求一致
金额展示/金额落库使用同一个 6 位派生汇率完成换算,再按目标金额字段或目标币种现有的小数位与舍入规则处理例如金额字段为 2 位小数时,仅在最终金额结果处按现有规则舍入
公式函数EXCHANGERATE 返回同一个 6 位派生汇率;公式最终结果仍遵循该公式字段自身的精度和 HALF_UP 规则接口、公式和金额换算对“汇率值”的口径一致

计算约束: 每次派生都直接引用同一中心汇率版本的两条“到本位币汇率”,按 6 位 HALF_UP 得到唯一业务汇率。不得用已有派生汇率继续派生,也不得用 A -> B 的已输出值再取倒数生成 B -> A;反向币对必须按中心汇率公式重新计算,避免多轮换算产生累计误差。

2.5 汇率大于 0 校验

现有管理端只校验必填、数字格式和小数位,未校验汇率必须大于 0。本期将规则统一补充到新增币种、编辑币种、调整“原币 -> 本位币”汇率及相关写入接口。

汇率不得为零校验示意

校验项规则
校验时机失去焦点时给出字段提示;保存时前端再次校验;服务端对所有写入再次校验。
有效条件rate > 0;空值继续使用现有必填提示,0 或负数禁止保存。
中文提示汇率必须大于 0
EnglishExchange rate must be greater than 0.
历史 0 值不回刷历史业务数据;相关币种再次保存或历史企业开启统一换算前,必须先修正为有效汇率。

2.6 历史企业兼容规则

  1. 未开启统一换算时,历史企业继续按现有单向人工汇率运行。
  2. 开启后,原币间人工汇率直接失效,不再展示、不再写入、不再记入“查看历史汇率”。
  3. 开启只改变后续查询和换算口径,不重新计算历史单据和已落库金额。
  4. 不设置差异清单或逐币对处理流程;开启前通过确认弹窗一次性告知影响。

三、其他说明

3.1 多语能力支持

开关、确认弹窗、并发失效提示和汇率校验提示均提供中英文,具体文案见 2.2、2.3 和 2.5。

3.2 需求埋点/日志

无新增产品埋点。

系统侧保留企业开启记录、旧页面写入拦截和接口失败日志,用于客诉定位与灰度观测。

3.3 沙盒/更改集能力

待确认现有币种管理配置是否支持沙盒/更改集。本期如果只调整系统换算逻辑,不应新增更改集对象。

3.4 对象与字段影响

无新增业务对象。需在企业级保存统一换算开启状态、操作人和开启时间,具体字段由研发设计评审确认。

3.5 影响调研

对象调研结论影响判断
BI当前未使用原币间“调整汇率”入口移除该入口对 BI 现有使用无直接影响
宽频该国际化企业当前未使用原币间“调整汇率”入口移除该入口对其现有配置无直接影响

边界:上述结论仅表明两者未使用该管理入口;公式、查询接口和个人币种展示等下游链路仍需按灰度方案验证。

3.6 风险点

ID风险类型涉及功能点影响范围响应策略
R-01存量逻辑变化原币到原币显式汇率使用过原币间汇率维护的历史企业仅历史企业提供一次性开启,在确认弹窗中告知新查询和换算结果可能变化
R-02公式结果变化EXCHANGERATE使用汇率函数的企业函数签名不变,开启后使用本位币派生结果
R-03前台金额展示变化个人币种展示开启“显示用户币种转换值”的企业灰度验证金额展示一致性
R-04历史数据争议历史记录汇率快照已产生业务数据默认不回刷历史记录
R-05精度差异派生汇率计算金额字段、报表、函数手动和派生汇率统一 6 位HALF_UP;所有消费者使用同一汇率,金额仅在最终结果按既有字段精度舍入
R-06并发页面过期原币间调整入口多管理员同时操作入口点击和保存接口都以服务端最新模式复验,拦截旧页面写入并提示刷新
R-07无效汇率人工汇率为 0新增、编辑、调整和开放接口前端即时校验 + 服务端强制校验 rate > 0;历史企业开启统一换算前修正历史 0 值

3.7 上线策略

3.7.1 收费标准

  • [X] 不收费
  • [ ] 收费

3.7.2 上线节奏

  • [ ] 全网
  • [X] 灰度
项目说明
灰度发布原因涉及汇率函数、个人币种展示、管理端配置逻辑,需要验证存量企业影响
灰度企业范围优先选择已开启多币种、已开启个人币种展示、已维护原币间汇率且币种数量较少的历史企业
全网前置条件新企业不创建显式交叉汇率;开关、函数/接口、并发拦截和汇率大于 0 校验经灰度验证

3.7.3 适应版本

待确认。建议与当前多币种能力支持版本保持一致。


四、验收标准

ID验收项验收标准
AC-01本位币入口可维护管理员可在本位币视角维护所有启用原币到本位币的汇率
AC-02原币间维护入口移除新企业及已开启统一换算的历史企业,币种列表均不展示原币间“调整汇率”入口
AC-03新企业只用实时派生新企业不创建显式原币间汇率;任一中心汇率变更后,前台展示、函数和接口使用最新派生值
AC-04历史企业一次性开启仅未开启的历史企业可见开启入口;确认后不可关闭,原币间人工汇率立即失效
AC-05历史汇率口径“查看历史汇率”仅展示人工变更的“原币 -> 本位币”汇率,不记录原币间派生结果
AC-06函数和接口保持兼容EXCHANGERATEfind_exchange_rate_by_currency 不破坏存量调用,并按有效汇率返回
AC-07历史数据不回刷已有业务记录上的mc_exchange_ratemc_exchange_rate_version 默认不被批量重算
AC-08并发过期页面拦截其他管理员仍从旧页面点击或保存原币间汇率时,服务端拒绝写入并提示刷新页面
AC-09精度一致派生汇率与手动录入汇率均按 6 位HALF_UP 展示、存储和返回;金额换算、接口和公式使用同一个汇率值
AC-10汇率必须大于 0新增、编辑、调整和接口写入时,0 或负数均不能保存,统一提示“汇率必须大于 0”

五、待确认事项

ID待确认问题影响
Q-01原币间更新函数及 OpenAPI 被拒绝时的错误码和返回结构影响存量调用方识别与改造
Q-02一次性开启是否仅限企业超级管理员影响权限配置与误操作风险

附1:需求变更记录

变更日期变更人变更内容
2026-05-12孙浩 / Codex按 PRD 模板偏好重新生成需求文档,收敛模板化章节

附2:需求 Story 列表

ID需求描述涉及端与开发人员是否有依赖项
Story-01本位币行保留“调整汇率”,统一换算后移除非本位币行的原币间调整入口vui / 后端,负责人待确认
Story-02新企业不创建原币到原币显式汇率,按中心汇率实时派生fs-paas-appframework,负责人待确认
Story-03历史企业提供不可逆的企业级开启能力,开启后原币间人工汇率失效fs-paas-appframework,负责人待确认
Story-04原币到个人币种展示按有效汇率查询并展示来源fs-paas-appframework,负责人待确认
Story-05EXCHANGERATE 和查询接口按有效汇率返回fs-paas-appframework / core,负责人待确认
Story-06拦截未刷新页面的原币间汇率写入,并提示刷新后端 / vui,负责人待确认
Story-07新增币种、编辑币种、调整汇率及相关接口统一校验汇率大于 0后端 / vui,负责人待确认