# Multi-entity & FX

> Consolidation and currency are where finance UIs quietly produce wrong numbers, because both involve summing things that look summable and aren't.

Source: https://lopifi.com/docs/domain/09-multi-entity-and-fx
Part of: Lopifi — US GAAP books on autopilot, checked by a CPA (https://lopifi.com)

---

# Multi-entity & FX

Consolidation and currency are where finance UIs quietly produce wrong numbers, because both involve summing things that look summable and aren't.

---

## 1. The consolidation model

```ts
type Entity = {
  id: string; name: string; legalName: string;
  functionalCurrency: string;       // the currency it primarily operates in
  parentId?: string;
  ownershipPct: number;             // of the immediate parent's interest
  consolidationMethod: "full" | "equity" | "proportional" | "none";
  fiscalCalendar: FiscalCalendar;   // subsidiaries can differ from the parent
};
```

| Ownership | Method | Treatment |
|---|---|---|
| Control (presumed > 50% of votes; a VIE or IFRS 10 power-and-returns test can override) | **Full consolidation** | Line-by-line, with non-controlling interest for the minority share |
| Significant influence (presumed 20–50%) | **Equity method** (ASC 323) | One line: investment in an equity-method investee (IFRS: an associate), moving with the investor's share of profit |
| No significant influence (typically < 20%) | **ASC 321** | Equity securities at fair value through net income — or, where fair value is not readily determinable, the measurement alternative (cost less impairment, adjusted for observable price changes) |
| Joint control | **Equity method** for a joint venture | IFRS 11 joint operations recognise their share of assets and liabilities; US GAAP allows proportionate consolidation only in narrow industries |

**UI rules:**
- **The consolidation scope is always stated in the statement header.** "Northwind Holdings Ltd. and subsidiaries" versus "Northwind Holdings Ltd. (standalone)" are different statements and must never be confused.
- **Entity selection is explicit, never inferred from a user's default.** A user who thinks they're looking at the group and is looking at one subsidiary is being misled.
- **Non-controlling interest appears on both statements** — as a component of equity on the balance sheet, and as an allocation of net income on the P&L. Omitting it overstates the parent's share.
- **Subsidiaries with different fiscal year-ends** require either aligned reporting or a stated adjustment. The UI flags the mismatch rather than silently summing.

---

## 2. Intercompany

Transactions between group entities must eliminate on consolidation. They are real for each entity and unreal for the group.

```
  Entity A sells $100k of services to Entity B
  ─────────────────────────────────────────────
  A: Dr IC receivable 100k / Cr Revenue 100k
  B: Dr Expense 100k        / Cr IC payable 100k
  Group elimination: Dr Revenue 100k / Cr Expense 100k
                     Dr IC payable 100k / Cr IC receivable 100k
  Group effect: zero
```

**UI rules:**
- **The intercompany matrix must net to zero.** `IntercompanyMatrix` renders an entity × entity grid of balances; every cell must have an equal and opposite counterpart. **Non-zero cells are the exception queue**, and they're the most common cause of a consolidation that doesn't tie.
- **Common breaks the UI must name**: timing differences (one side booked in a later period), FX differences (each side translated at a different rate), and one-sided entries (the other entity never booked it). These have different fixes, so the matrix labels the break type rather than showing a bare difference.
- **Unrealized profit in inventory** — goods sold intercompany and still on hand — must be eliminated too. Flagged, not computed, because it requires knowing what's still in stock.
- **Elimination entries are `source: "elimination"`** and exist only at the consolidated level. They never appear in an entity's standalone statements, and the UI makes that boundary visible.

---

## 3. Functional vs. presentation currency

The distinction that causes the most confusion, and the one that decides whether an FX difference hits the P&L or equity.

| | Definition |
|---|---|
| **Transaction currency** | What the invoice was denominated in |
| **Functional currency** | The currency of the entity's primary economic environment |
| **Presentation currency** | What the statements are shown in — IAS 21's term; ASC 830 calls it the *reporting currency* |

Three different processes, two different destinations:

| | **Transaction gains and losses** | **Remeasurement** | **Translation** |
|---|---|---|---|
| Converts | A foreign-currency-denominated monetary item → functional | Books kept in another currency → functional | Functional → reporting (presentation) |
| FX difference goes to | **P&L** (ASC 830-20-35-1) | **P&L** (ASC 830-10-45-17) | **Equity** (CTA, in OCI — ASC 830-30-45-12) |
| Applies to | One receivable, payable, loan or cash balance | An entity whose ledger is not in its functional currency | An entire foreign operation's statements |

**This is not a detail.** A EUR receivable held by a USD-functional entity produces a P&L gain or loss when rates move. That same entity's statements translated into a GBP-presentation group produce a CTA in OCI that bypasses the P&L until the foreign operation is sold or substantially liquidated, when it is reclassified to earnings. Confusing them misstates earnings.

---

## 4. Translation rates

| Item | Rate |
|---|---|
| Assets and liabilities | **Closing rate** at the balance sheet date |
| Income and expenses | **Rate at the date each item is recognized** — a weighted-average rate for the period is the usual practical approximation permitted by ASC 830-30-45, and is not appropriate when rates swing within the period |
| Equity | **Historical rate** at the date of each contribution |
| Retained earnings | Rolled forward, not re-translated |

Because these use different rates, **the translated balance sheet does not balance** — and the plug is the **cumulative translation adjustment**, recorded in other comprehensive income.

**UI rules:**
- **CTA is displayed as its own equity line, never buried.** It is the arithmetic consequence of the method, and hiding it makes the balance sheet look inexplicable.
- **Every translated statement shows the rates used** — closing, average, and the source. A translated number without its rate is unverifiable.
- **Average rate methodology is stated** (simple average of daily, monthly weighted, transaction-date). Different methods give different results and comparability depends on knowing which.
- **Hyperinflationary economies** differ by framework: IFRS (IAS 29) restates for inflation, then translates; US GAAP (ASC 830) remeasures as if the reporting currency were functional, with differences in the P&L. The UI flags the jurisdiction and the framework rather than attempting it.

---

## 5. FX gain and loss

Three events, three rates, on a single foreign-currency invoice:

```
  1. Invoice issued 1 Sep    €10,000 @ 1.0850 = $10,850   → AR recorded
  2. Period end 30 Sep       €10,000 @ 1.0920 = $10,920   → unrealized gain $70
  3. Payment received 12 Oct €10,000 @ 1.0790 = $10,790   → Sep unrealized gain reverses (−$70)
                                                              realized loss $60 vs. invoice rate
                                                            (October P&L −$130; cumulative −$60)
```

**UI rules:**
- **Realized and unrealized are separate lines and never combined.** Unrealized reverses; realized doesn't. Presenting one number destroys the reader's ability to tell what actually happened.
- **The revaluation entry at period end is a system entry** with the rate and source shown, reversing at the start of the next period.
- **Only monetary items are revalued.** Cash, receivables, payables, and debt — yes. Inventory, fixed assets, and prepaids — no, they stay at historical rate. Revaluing a non-monetary item is a common and material error, and the UI derives this from the account classification rather than trusting a flag.
- **The rate source and timestamp are recorded on every conversion.** A rate without provenance is not auditable.

---

## 6. Rate management

```ts
type ExchangeRate = {
  from: string; to: string;
  rate: number;
  asOf: Date;
  type: "spot" | "closing" | "average" | "historical" | "budget";
  source: string;                  // "ECB" | "OANDA" | "manual"
  enteredBy?: string;              // manual rates need an actor
};
```

- **Rate type is not optional.** The same pair on the same date has a different closing rate and average rate, and using the wrong one is a silent misstatement.
- **Manual rate overrides require a reason and an approver**, and are visibly distinguished from sourced rates everywhere they're used.
- **A missing rate is a blocking error**, never a silent 1.0. Defaulting to parity is the worst possible failure mode here.
- **Inverse rates are computed, never stored separately** — storing both invites them to drift.
- Rounding: **rates carry 5–6 significant figures**; converted amounts round once, at the end, per the currency's minor unit.

---

## 7. Multi-entity UI rules

1. **Entity is a required dimension on every transaction.**
2. **Every number states its entity scope and its currency.** Both, always.
3. **Never sum across currencies without a stated conversion**, with the rate, the type, and the as-of date reachable.
4. **A converted value is marked** with `≈` and its basis in a tooltip.
5. **Entity switching is a full context change**, so nothing animates and every cached figure is invalidated. A stale figure from the previous entity displayed for even one frame is a serious error.
6. **Consolidated and standalone views are visually distinct**, not just differently labeled — the consolidated view carries a persistent scope chip in the header.
7. **A user with access to a subset of entities sees totals for that subset only**, and the UI says so explicitly rather than presenting a partial total as a group total.

---

## 8. Component set

| Component | Purpose |
|---|---|
| `EntitySelector` | Explicit scope, with standalone/consolidated distinction |
| `ConsolidationView` | Entity columns + eliminations + group total |
| `IntercompanyMatrix` | Entity × entity, with break types named |
| `EliminationEntry` | Consolidation-level only, clearly scoped |
| `NciPanel` | Non-controlling interest on both statements |
| `TranslationSummary` | Rates used, by type, with sources |
| `CtaRollForward` | Opening CTA → movement → closing |
| `FxRevaluation` | Period-end revaluation preview and posting |
| `FxGainLossPanel` | Realized and unrealized, separated |
| `RateTable` | By pair, date, and type, with source and overrides flagged |
