多币种-存储什么并何时转换?

44

我在SO上阅读了有关多币种的不同问答,但是它们对我的用例来说要么不够清楚,要么没有提供足够的细节。

场景:

Raddo公司拥有3个分支机构,分别位于英国、法国和美国。Raddo公司使用的基准货币为美元。预算以美元创建。Raddo公司将支持的货币汇率存储在数据库中。

英国员工使用英镑创建采购订单,在法国使用欧元创建采购订单。

Q1: 在采购订单/订单项数据库表中应该存储什么——分支机构所在货币和当前汇率或转换后的美元基准货币金额?请记住,汇率必须是创建PO时的汇率。

Q2: 什么需要转换以及何时进行转换,才能生成以美元/基准货币为基础的报告?

Q3: 如果有人在2年后将基准货币从美元更改为澳大利亚元,对现有数据会产生什么影响?

Q4: 如何处理多币种是最好的方法,以便应用程序处理尽可能少的转换?

2个回答

62
请注意,您收到的答案将是主观的。在此免责声明之后,这是我建立这样一个系统的方法。 TL;DR:使用货币汇率表来存储不同货币以及适用日期的货币汇率。同时将金额存储为本地货币和计算出的美元价值。
货币汇率表 创建一个形式为FX汇率的货币表:
FX_RATES 
-------- 
SOURCE_CURRENCY  -- e.g. USD, GBP, EUR 
TARGET_CURRENCY  -- as above 
EXCHANGE_RATE    -- a suitable decimal field representing the conversion 
VALID_FROM_DATE  -- date range when the above exchange rate is valid 
VALID_TO_DATE    -- as above 
  • 前4列的组合将表示唯一记录。
  • 建议每当输入货币对(USD->GBP)的记录时,也插入等价的反向记录(GBP->USD),可以使用真实汇率(单向转换可能使用不同的汇率),也可以使用原始记录的倒数。
  • 对于一对货币,连续的行必须展示日期的连贯性(即对于一对货币,永远不应该存在一个日期既不在VALID_FROM_DATEVALID_TO_DATE之间的行)。
  • 为了方便起见,还要输入一行('USD','USD',1,smallest_date,largest_date) ,其中包含数据库支持的最小和最大日期。这样可以更容易地处理以基础货币本身进行的输入情况。
  • 您需要确定一个货币汇率源,用于向该表提供信息,并确定更新频率。例如,即使货币市场上的值每天都会发生变化,您的财务团队也可能发布每周的外汇汇率表。

示例表如下所示。尽管看起来有重叠的部分,但查找操作仅在一列上检查相等性(即>= VALID_FROM_DATE AND < VALID_TO_DATE

SOURCE_CURRENCY TARGET_CURRENCY EXCHANGE_RATE          VALID_FROM_DATE VALID_TO_DATE 
--------------- --------------- ---------------------- --------------- -------------- 
GBP             USD             1.250000               06-Mar-2017     13-Mar-2017 
GBP             USD             1.260000               13-Mar-2017     20-Mar-2017 
GBP             USD             1.240000               20-Mar-2017     27-Mar-2017 
GBP             USD             1.250000               27-Mar-2017     03-Apr-2017 
USD             GBP             0.800000               06-Mar-2017     13-Mar-2017 
USD             GBP             0.793651               13-Mar-2017     20-Mar-2017 
USD             GBP             0.806452               20-Mar-2017     27-Mar-2017 
USD             GBP             0.800000               27-Mar-2017     03-Apr-2017 
USD             USD             1.000000               01-Jan-1900     31-Dec-9999 

PO表中的列

在采购订单表中,保留以下字段:

PURCHASE_ORDERS 
--------------- 
... other fields 
PO_TXN_DATE         -- Date for the PO that represents the financial transaction 
ORDER_VALUE_LOC     -- Decimal field with the order value in local currency 
ORDER_CURRENCY_LOC  -- The currency used for ORDER_VALUE_LOC (e.g. GBP/EUR) 
ORDER_VALUE_USD     -- The order value in USD (as this is the company's base currency) 
... other fields 

填充采购单列

已经有一个填充采购单表的流程,需要进行扩展以填充以下字段:

  • PO_TXN_DATE 代表采购单上的财务交易日期。根据您的业务规则,这可能是创建/提出采购单的日期,也可能不是。
  • ORDER_VALUE_LOC 是本地货币中交易的价值。
  • ORDER_CURRENCY_LOC 是本地货币的货币代码。
  • 这三个字段将用于查找外汇汇率表。
  • ORDER_VALUE_USD 的填充是通过在 FX_RATES 表中查找汇率来完成的:

通过以下伪代码演示了填充 ORDER_VALUE_USD

ORDER_VALUE_USD = PURCHASE_ORDERS.ORDER_VALUE_LOC * FX_RATES.EXCHANGE_RATE 
                  WHERE 
                        FX_RATES.SOURCE_CURRENCY = PURCHASE_ORDERS.ORDER_CURRENCY_LOC 
                    AND FX_RATES.TARGET_CURRENCY = 'USD' 
                    AND PURCHASE_ORDERS.PO_TXN_DATE >= FX_RATES.VALID_FROM_DATE 
                    AND PURCHASE_ORDERS.PO_TXN_DATE <  FX_RATES.VALID_TO_DATE 

OP问题的答案

Q1:应当在采购订单/订单项目数据表中存储什么信息——分店位置货币和当前汇率,还是转换后的美元基础货币金额?请记住,汇率必须为创建PO时的汇率。

如上所述,在采购订单表格中存储本地货币价值、交易日期、本地货币名称;同时计算并存储基础货币(美元)的价值。如果需要,可以再次查找汇率,不需要在此处冗余存储。

存储USD值是为了更方便地在单一货币下进行聚合(例如生成显示总未结PO值的报告发送到总部)。如果用例不需要此类使用场景,则无需存储USD值,它可以根据FX汇率表在需要时进行计算。然而,下一个问题暗示会有相当大的需要在基础货币(USD)中获得价值。

Q2:要转换什么内容以及何时才能生成以美元/基础货币计价的报告?

通过将数值存储在基础货币和USD中,可以大大简化此类报表的生成。这就是我们采取一次性成本计算和存储USD值的原因,因此它可以被多次读取。

Q3:如果有人——比如在两年后——将基础货币从美元更改为澳大利亚元,对现有数据的影响是什么?

从技术上讲,如果预计会进行这种更改,请不要使用“USD”命名任何数据库结构,而应使用一些通用名称,例如“BASE”:-)

如果进行此类更改,公司财务部门将指示您如何重新表述财务数据-例如,是否应根据交易时的实际汇率重新计算基础价值,还是只使用一个固定转换因子?无论哪种情况,一旦给您提供了这个决策,您只需要将适当的转换因子输入FX_RATES表格,并运行一次性过程以重新填充PURCHASE_ORDERS.ORDER_VALUE_BASE列。除了汇率之外,此查找所需的所有其他信息已经存在于PURCHASE_ORDERS表中且没有更改。

Q4:处理多种货币的最佳方法是什么,以便应用程序处理最少量的转换?

这又将由您的业务需求驱动,而不是技术决策。如果经常需要报告本地货币以及基础(USD)货币,则存储相关交易值的两种货币将有所帮助。通过计算并存储一次,您可以从此后访问存储的数据获益。

此外,由于您没有丢弃任何数据,如果需要,您可以随时重新计算财务数据。一些可能需要重新计算的情况包括:

  • 公司决定基准货币使用提出采购订单时的汇率,但在关闭或开具发票时应重新计算基准(美元)货币。在这种情况下,您将使用不同的日期查找FX_RATES表以关闭PO。
  • 如果英镑突然暴跌,从1 GBP=1.25 USD变为1.5 GBP=1 USD,则可能需要计算此类变化对美元的影响。然后,您可以获取存储的ORDER_VALUE_USD值与使用FX_RATES表中今天的汇率重新计算的值之间的差异,以确定此类变化的美元影响。

Q5:无法将交易时的汇率存储在采购订单表中吗?这样,系统就不需要在FX汇率表中查找汇率了。(通过后续评论提出)

交易时的汇率肯定可以存储在PO表中,而不是USD金额。在PO表中存储汇率本质上没有什么“错误”,也没有存储美元金额是“正确”的。

当然,这将引出一个问题:如果您不首先将其存储在某个查找表中,那么从哪里获取汇率以填充到PO表中。请记住,在大型/全球性公司中,FX汇率很可能不是通过LOB应用程序本身填充的,它将是一些外部来源,例如确定跨公司使用的FX汇率的FX汇率团队。这种情况下,将FX汇率存储在单独的表格中更加方便。

我在下面列出了不同方法的一些好处。您需要根据自己的需求选择使用哪种方法。

  • 在PO表中存储USD的好处: USD金额可以直接使用,无需进行进一步计算(即在运行报告时,不需要计算ORDER_VALUE_LOC x EXCHANGE_RATE)。
  • 单独FX汇率表的好处: FX汇率集中存储在一个单独的表中,更容易更新和审核(请记住,大型企业可能会有一个专门的团队负责修复整个公司的FX汇率),以及验证(例如,检查FX汇率的连续性——在上面的例子中,通过串联连续行上的有效日期来检查FX汇率是否存在空缺非常简单)。FX汇率不会分散在多个表中。
  • 在PO表中存储FX汇率的好处: 无需单独的FX_RATES表。

当然,你可以冗余地存储额外的信息(牺牲存储空间)来获得好处(例如,在PO表中存储本地货币金额、FX汇率和USD金额,并保持单独的FX汇率表。这使得您可以轻松打印出显示本地货币金额以及用于将其转换为USD金额的FX汇率的PO文档。同时,FX汇率表仍然是汇率的权威来源)。

请记住,这个问题及其答案都是主观的,所以没有对错之分。将所有这些建议调整为符合您的要求和公司标准。


谢谢您详细的回复和时间。我正在努力理解。不过,有一个问题,交易时的汇率不能存储在购买订单表中吗?这样,系统就不需要在外汇汇率表中查找汇率了。您有什么看法? - Iffi
谢谢。你在第五个问题的结尾提到了我的要点。我将创建一个单独的表来存储外汇汇率,同时在采购订单表中使用汇率,以便能够知道采购订单创建时的汇率。因此,在显示采购订单详细信息时,不需要从另一个表中查找已使用的汇率。 - Iffi
3
这样的答案值得点赞 +1。 - Stackcraft_noob
1
@Phylyp 很棒的回答。我有一个关于采购订单中货币字段的问题,考虑到有一个单独的货币表,包含每种货币的信息(名称、符号、名称等),现在我有两个选项:1. 在采购订单中创建一个字段,并在每次写入值时保持该字段的值与FX表中的值相同,以避免潜在的转换问题;2. 在PO和货币之间创建关系,这将有助于提供额外的货币信息,如货币名称/符号,但比第一种选项更慢。我想听听您的想法,谢谢。 - Albert
1
真是个很棒的解释,我都忘了我的StackOverflow凭证,但是为了给你点赞,我又重新登录了。 - undefined
显示剩余2条评论

1
通常情况下,您使用公司所在国家的货币并支付其税款。因此,您应该使用交易时有效的汇率将其他货币转换为美元。一旦您获得所有数据,就会进行转换。 更改货币的影响是未知的,因为它可能会改变许多事情,而不仅仅是货币。 我不知道最佳方法是什么,但似乎跟踪每次交易时所有汇率是合理的,这样您可以提供适当的数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接