币种管理汇率逻辑调整 PRD

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

币种管理汇率逻辑调整 PRD

版本:v1.0 | 创建日期:2026-05-12

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

优先级: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 -> USDUSD -> AED 可以分别人工维护,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 位
本地代码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 原币汇率收敛为维护 N 个原币到本位币汇率。
  3. 保留个人币种展示、汇率函数、汇率查询接口等现有能力,降低存量企业受影响风险。

1.2 需求目标

  1. 管理端只允许人工维护“原币 -> 本位币”的中心汇率
  2. 新企业从启用多币种起不再创建或维护原币到原币汇率;原币间及个人币种换算均按中心汇率实时派生。
  3. 历史企业不再允许新增或修改原币到原币汇率;已有显式汇率在兼容期内可继续作为原有调用的有效值,避免公式和前台金额突然变化。
  4. 前台金额字段在未命中历史显式汇率或新企业场景下,仍能按本位币汇率派生并展示个人币种换算值。
  5. EXCHANGERATE(currency1,currency2,defaultValue)find_exchange_rate_by_currency 保持兼容,并能返回有效的历史配置值或本位币派生值。

二、产品方案

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 管理端界面改造方案

本期 UI 改造基于现有币种管理页面调整,不新增独立配置页。

界面/入口当前界面现状优化后界面规则
本位币行“调整汇率”币种管理维护原币与本位币之间汇率(保持现状)保持可编辑,作为唯一人工维护入口;
非本位币行“调整汇率”币种管理维护原币之间的汇率新老企业均调整为“查看汇率”;去掉输入态和保存动作,不再新增或修改独立原币间汇率
非本位币汇率弹窗内容当前展示其他原币到当前原币的可编辑汇率展示有效汇率、来源、计算公式和更新时间;值不可编辑。派生值示例:AED -> USD = AED -> CNY / USD -> CNY
历史汇率查看展示历史汇率继续展示;原币到原币结果按来源标识“系统派生”或“历史配置值(兼容期)”。每次中心汇率版本变更后,实际变化的派生币对也按该版本记录

非本位币入口不建议直接隐藏,新老企业均保留并统一命名为“查看汇率”。该入口承担“查看某币种换算到其他币种的有效结果”的职责,避免用户误解为原币换算能力被删除;它不再是配置入口。

2.3 企业类型与历史兼容

本期以“企业是否已在上线前开通多币种”为分界。入口形态保持一致,但有效汇率的来源不同,必须在查看页明确标识,避免管理员把历史配置值误认为实时派生值。

企业类型原币到原币汇率数据非本位币入口查看结果与实时性公式、接口和个人币种展示
新企业不创建原币到原币显式汇率记录统一为“查看汇率”,只读均为“系统派生(实时)”;任一到本位币汇率变更后立即按最新值计算始终使用本位币派生值
历史企业,某币对已有显式汇率停止编辑,原记录在兼容期保留统一为“查看汇率”,只读显示“历史配置值(兼容期)”,不因本位币汇率变更而实时变化;同时展示按当前中心汇率计算的参考派生值和差异兼容期内沿用历史有效值,避免既有公式和展示结果突变
历史企业,某币对无显式汇率不补写显式记录统一为“查看汇率”,只读显示“系统派生(实时)”使用本位币派生值
历史企业完成汇率治理后显式记录退出有效计算链路,保留审计信息保持“查看汇率”,只读全部显示“系统派生(实时)”统一使用本位币派生值

查看汇率的实时规则: 只有来源为“系统派生”的结果实时变化。其值由当前两侧“到本位币汇率”计算得出,任一中心汇率保存成功后,下一次查看、公式计算、接口查询和前台展示均应使用新结果。来源为“历史配置值(兼容期)”的结果固定为该条历史配置,不随中心汇率变化;页面需同时给出“当前中心汇率派生值”和“差异提示”,推动企业完成治理。

历史企业的兼容期不应无限期保留两套有效事实源。推荐以“历史汇率差异已确认 + 企业切换完成”为退出条件:对每个企业一次性切换到中心汇率派生模型;切换后原币间显式记录仅保留审计,不再参与查询和展示。

2.4 运行逻辑调整

场景优化后规则
原币到原币换算新企业始终按两边到本位币汇率实时派生;历史企业在兼容期内优先使用已有显式值,未命中时派生
个人币种展示按有效汇率展示:新企业/未命中历史显式值时实时派生;
EXCHANGERATE函数签名不变;按有效汇率返回,未命中历史显式值时按本位币实时派生
find_exchange_rate_by_currency入参和出参不变;按有效汇率返回,必要时在内部返回或记录来源标识
历史业务记录不批量回刷,已有记录上的汇率快照保持不变

派生汇率版本与查看历史汇率

本期的“实时派生”指当前查询始终基于最新中心汇率返回结果,但不意味着历史不可追溯。每次管理员保存“到本位币汇率”后,系统创建一个中心汇率版本,并按该版本重新计算当前启用币种间的全部有向汇率关系;与上一生效版本按汇率精度比较后,只有实际发生变化的派生结果写入“查看历史汇率”。

例如 CNY 为本位币、AED 的“到 CNY 汇率”发生变化时,系统需要计算 AED、USD、CNY 三个币种的六个有向换算结果。其中 AED -> CNY、CNY -> AED、AED -> USD、USD -> AED 会随之变化,USD -> CNY、CNY -> USD 不变。历史记录只新增前四条变化结果,并关联本次中心汇率版本;这四条均为“系统派生”历史快照,不能在历史页编辑,也不会重新成为交叉汇率主数据。

派生汇率精度与舍入

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

环节精度与舍入规则说明
人工维护的中心本位币汇率沿用现有输入上限:最多 6 位小数(新企业是 10 位)仅适用于“原币 -> 本位币”输入,不增加管理员维护复杂度
派生汇率计算直接按 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;反向币对必须按中心汇率公式重新计算,避免多轮换算产生累计误差。

异常边界: 中心汇率必须大于 0;任一所需中心汇率为空、为 0 或无效时,不生成派生率或派生历史快照。前台按现有无汇率兜底处理,EXCHANGERATE 返回其 defaultValue

2.5 兼容策略

对象兼容要求建议策略
存量显式原币到原币汇率不能立即删除或覆盖仅历史企业在兼容期保留为有效值;停止编辑,提供冲突检测和企业级切换
新企业原币到原币汇率不应产生第二套事实源不创建显式记录;全部按中心汇率实时派生
个人币种展示不能因未维护显式原币汇率而不展示按有效汇率展示;未命中历史显式值时按本位币实时派生
EXCHANGERATE函数签名和兜底行为不变按有效汇率返回;无法派生时返回defaultValue
find_exchange_rate_by_currency入参和出参不破坏存量调用按有效汇率返回,内部标识汇率来源
历史业务记录不默认重算保持原汇率快照,避免影响历史金额口径

历史企业中显式汇率与派生汇率同时存在时,兼容期采用“历史显式值优先 + 差异识别”。新企业不存在该优先级分支。历史企业完成差异确认并切换后,统一改为“本位币派生优先”,不再回退到显式原币间汇率。

历史汇率差异处理(是否需要处理,待定)

这里的“差异”不是泛指历史数据有问题,而是指同一企业、同一币对同时满足以下条件:已有原币到原币的人工配置值,且按当前两条“到本位币汇率”计算出的结果与该人工值超出既定精度容差。例如历史配置 AED -> USD = 0.120000,当前中心汇率推导为 0.888 / 7.200 = 0.123333,该币对进入差异列表。

系统在灰度前和企业切换前生成“历史汇率差异列表”。列表只用于让管理员确认迁移口径,不要求管理员再编辑原币间汇率;每条至少展示企业、币对、历史配置值、当前派生值、差异比例、当前生效来源,以及受影响的公式/接口/个人币种展示范围。

差异情况管理员确认动作系统结果
差异在精度容差内无需逐币对处理,可确认切换企业切换后按本位币派生,结果在既定精度内保持一致
历史配置值符合当前业务口径选择“暂保留历史配置”,并设置兼容期结束时间原调用继续使用历史值;查看页同时显示实时派生参考值;到期前必须完成下一步确认
本位币汇率应以历史配置为准由有权限的管理员调整相关“到本位币汇率”,使中心汇率口径正确系统重新计算所有相关币对;需提示该修改会影响同一币种的其他换算
确认以本位币推导值为准选择“切换为系统派生”该币对立即停止使用历史配置,后续查看、公式、接口和前台展示均使用实时派生值

业务记录上的汇率快照不参与上述处理,也不因企业切换而回刷。历史配置值在切换后保留审计信息,供追溯“切换前为何显示该结果”,但不再作为新的计算来源。


三、其他说明

3.1 多语能力支持

无。

3.2 需求埋点/日志

无新增产品埋点。

系统侧建议保留后台日志,用于定位派生汇率计算、显式汇率冲突、函数兜底命中情况。

3.3 沙盒/更改集能力

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

3.4 对象与字段影响

无新增业务对象。若研发需要新增 manual/derived 等汇率来源标识,仅作为技术字段评估。

3.5 风险点

ID风险类型涉及功能点影响范围响应策略
R-01存量逻辑变化原币到原币显式汇率使用过原币间汇率维护的历史企业兼容期保留显式值,先做差异识别和企业级切换
R-02公式结果变化EXCHANGERATE使用汇率函数的企业函数签名不变,派生作为兜底;灰度验证后再调整优先级
R-03前台金额展示变化个人币种展示开启“显示用户币种转换值”的企业灰度验证金额展示一致性
R-04历史数据争议历史记录汇率快照已产生业务数据默认不回刷历史记录
R-05精度差异派生汇率计算金额字段、报表、函数手动和派生汇率统一 6 位HALF_UP;所有消费者使用同一汇率,金额仅在最终结果按既有字段精度舍入

3.6 上线策略

3.6.1 收费标准

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

3.6.2 上线节奏

  • [ ] 全网
  • [X] 灰度
项目说明
灰度发布原因涉及汇率函数、个人币种展示、管理端配置逻辑,需要验证存量企业影响
灰度企业范围优先选择已开启多币种、已开启个人币种展示、已维护原币间汇率且币种数量较少的历史企业
全网前置条件历史企业显式汇率冲突数据扫描完成;新企业不创建显式交叉汇率;函数/接口命中派生无明显异常

3.6.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派生历史可追溯每次中心汇率变更后,系统计算全部有效有向币对,并在“查看历史汇率”中记录实际变化的派生结果、来源和关联版本

五、待确认事项

ID待确认问题影响
Q-01历史企业的兼容期由版本、日期还是企业主动确认切换作为结束条件决定两套有效值并存时长
Q-02历史显式汇率冲突是否需要提供独立治理页面,或仅导出清单影响管理员处理成本和数据治理范围
Q-03派生历史记录按逐币对快照落库,还是按中心汇率版本在查看时回放影响历史查询性能和存储成本
Q-05灰度企业是否需要提前扫描已维护原币到原币汇率的数据量影响上线风险评估

附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存量显式原币到原币汇率冲突检测后端,负责人待确认
Story-07中心汇率变更后计算受影响派生币对,并写入可追溯的历史汇率版本后端 / vui,负责人待确认