Files
atlas-seller-kit/docs/architecture/exchange-rates.md
T

5.4 KiB

汇率:数据模型、数据源与更新策略

首期定价只需要 CNY → RUB,但表结构按任意法币对设计。汇率是全局参考数据,不属于平台、门店或工作空间。

1. 口径与使用边界

exchange_rates.rate 始终表示:1 单位 base_currency_code 可兑换多少单位 quote_currency_code。例如 CBR 返回 Nominal=1、Value=12.3343 的 CNY 数据,标准化保存为:

base_currency_code  = CNY
quote_currency_code = RUB
rate                = 12.3343

这是一种报价参考口径,不等同于卖家实际购汇、物流商结算或提现的成交汇率。因此定价保留三种来源:

报价来源 读取方式 是否写入 exchange_rates
系统汇率 读取当前有效的正式参考汇率 是。首期为 CBR 的 official_reference。
方案固定汇率 读取 pricing_policies.fixed_cny_to_rub_rate 否,报价快照记录该固定值。
本次覆盖 用户在定价弹窗输入 否,报价快照记录覆盖值和原因。

无论哪种来源,pricing_quotes 都固化 fx_cny_to_rub、fx_rate_origin、可空的 exchange_rate_id 和完整输入快照。后续系统汇率更新绝不改写已确认报价。

2. 数据库设计

DDL 位于 sql/001_foundation.sql 的 exchange_rates 表:

字段 含义
base_currency_code / quote_currency_code 币种方向;严禁把 CNY/RUB 与 RUB/CNY 混用。
rate 标准化后的“1 base = rate quote”。使用 NUMERIC,不使用浮点数。
kind official_reference、market_reference 或 manual。
source cbr、exchange_rate_api_open、frankfurter、manual。
effective_on 数据源声明的适用日期;不是系统抓取日期。
observed_at / fetched_at 来源观测时间与 Atlas 抓取/录入时间。
source_reference / raw_payload 可追溯的来源链接、批次说明和原始响应。

同一个“币种方向 + 口径 + 来源 + 适用日期”只能有一条记录。若来源在同一适用日修订汇率,Worker 应在事务中更新原始记录并保留修订审计,或另行建立修订表;首期 CBR 日汇率正常情况下不需要重复插入。

3. 首选数据源:俄罗斯央行 CBR

首期正式系统汇率使用 CBR 的 CNY 对 RUB 官方参考汇率:

GET https://www.cbr.ru/scripts/XML_daily.asp
GET https://www.cbr.ru/scripts/XML_daily.asp?date_req=dd/mm/yyyy
  • 不传 date_req 返回最近一个已发布工作日;传日期可补历史数据。
  • 解析 XML 中 CharCode=CNY 的 Nominal 与 Value;将逗号小数转换为 NUMERIC,按 Value / Nominal 标准化。
  • 记录 kind=official_reference、source=cbr、来源 XML URL、响应原文、响应对应的适用日期和抓取时间。
  • CBR 在周末与节假日可能返回上一工作日数据,这是正常结果,不创建重复记录也不标记请求失败。

CBR 是 Ozon-RU 定价的首选,因为它直接发布 CNY 对 RUB 的官方口径。它不保证等于卖家实际结算汇率,用户仍可选择固定或本次覆盖汇率。

4. 免费备用与未来扩展

服务 调用方式 适用范围 使用规则
CBR https://www.cbr.ru/scripts/XML_daily.asp 首期 CNY→RUB 正式口径 主来源。免费、官方、按工作日发布。
ExchangeRate-API Open Access https://open.er-api.com/v6/latest/CNY CNY→多币种可用性备用 无 Key、日更、需按其条款归属且有频率限制。只能标记为参考或备用,不能静默覆盖 CBR 正式记录。
Frankfurter https://api.frankfurter.dev/v2/rate/CNY/RUB 后续多币种、历史查询和数据源对照 无 Key;默认可能混合多个来源。需要时应记录 provider 元数据,不能把混合口径伪装为 CBR 官方口径。

不要在前端直接调用上述接口,也不要把第三方响应直接当作报价结果。所有请求只由后端 Worker 发起、校验、标准化、持久化后供报价引擎读取。

5. BullMQ 更新与故障策略

  1. 定时 Worker 在俄罗斯工作日每 2 小时请求一次 CBR;不依赖未经确认的固定发布时间。
  2. 以 effective_on 去重:没有新适用日期时直接结束;有新日期时插入一条 exchange_rates 记录。
  3. 每次任务记录 HTTP 状态、解析结果、原始响应摘要和耗时;禁止记录无关敏感信息。
  4. CBR 请求失败时保留上一条成功汇率并告警;不得自动以备用来源覆盖正式 CBR 数据。
  5. 若最近 CBR 有效记录距当前超过 72 小时,报价界面显示“系统汇率可能过期”,但仍允许使用上次值、方案固定值或本次覆盖值。
  6. 定价服务只读取当前有效的 CNY → RUB + official_reference + cbr 最新记录;若不存在则不能输出系统汇率报价,应提示选择固定/覆盖汇率或等待更新任务成功。

6. 实施接口边界

  • Worker 内部:ExchangeRateProvider 适配器接口,首期实现 CbrProvider;备用提供方独立实现,不影响报价公式。
  • 后台管理:查看当前系统汇率、历史记录、来源、抓取时间、异常与人工录入 manual 汇率;人工记录不得冒充 cbr。
  • 定价 API:返回最终汇率、来源、适用日期、抓取时间和是否过期;确认报价时只引用快照,不在请求中重新抓取第三方。