BigBooks Docs
Multi-Currency

Exchange Rates

As an admin, you will keep BigBooks' daily foreign-exchange rates current so that every foreign-currency invoice, bill, and payment converts to LAK at the right buying or selling rate — and so the figure each transaction was booked at never changes after the fact.

What you'll accomplish

As an Admin, you will keep BigBooks' daily foreign-exchange rates current so that every foreign-currency invoice, bill, and payment converts to LAK at the right buying or selling rate — and so the figure each transaction was booked at never changes after the fact.

Before you start

Exchange rates live at /[lang]/exchange-rates. This screen is a date-pickable rate grid, not a list-detail screen: you pick a date in the secondary header, then edit rates directly in the page and save them all at once. Viewing requires the canViewExchangeRates permission; editing rates requires an admin (or account-manager) role — other roles see the grid read-only.

The currencies on the grid are driven by an upstream Currency activation card at the top of the same page: you choose the company's base currency (LAK by default) and toggle on the foreign currencies you transact in. Each active foreign currency adds one rate pair (e.g. USD → LAK, THB → LAK) to the grid below — there is no separate settings route for this.

Each pair has three rate types, shown as three columns: AR Buying (the rate used when money comes in — sales), AP Selling (the rate used when money goes out — purchases), and Mid (the book rate for internal entries). Each cell reads as a sentence — "1 USD = ____ LAK" — so the conversion direction is never ambiguous.

Steps

Pick the date and activate currencies Open /[lang]/exchange-rates. Use the date picker in the secondary header to choose the day you are setting rates for (it defaults to today; you cannot pick a future date). In the Currency activation card, confirm your base currency and switch on each foreign currency you use — every active currency adds a pair to the grid.

Currency activation card: base currency locked to LAK with USD and THB toggled on, each adding a pair to the grid.
Currency activation card: base currency locked to LAK with USD and THB toggled on, each adding a pair to the grid.

Enter the day's rates For each pair, fill the AR Buying, Mid, and AP Selling cells. Each cell shows yesterday's value in muted text and a 7-day sparkline, so you can sanity-check the magnitude. A small info tooltip on each column explains what that rate type is for. Changed cells are highlighted and counted in a "N changed" badge so you can see exactly what Save will write.

Rate grid for USD → LAK and THB → LAK showing the AR Buying / Mid / AP Selling cells, yesterday values, and 7-day sparklines.
Rate grid for USD → LAK and THB → LAK showing the AR Buying / Mid / AP Selling cells, yesterday values, and 7-day sparklines.

Carry forward when nothing changed If a day's rates are unchanged from the last published values, press Use yesterday's rates to prefill every cell from the most recent prior value. The cells that were filled flash briefly; this counts as a carry-forward, not a manual edit.

The Use yesterday's rates action with the changed-count badge and Save button in the secondary header.
The Use yesterday's rates action with the changed-count badge and Save button in the secondary header.

Save Press Save to write all changed cells at once. If any cell would overwrite a rate already saved for that date, a confirmation dialog appears first. Cells whose rate has already been used by a journal entry are locked (a lock icon) and skipped automatically — they cannot be silently changed.

A locked AR Buying cell with the lock icon, indicating the rate has already been referenced by a posting for that date.
A locked AR Buying cell with the lock icon, indicating the rate has already been referenced by a posting for that date.

What happens behind the scenes

Saving rates writes rows to the exchangeRates table keyed by company, currency pair, rate type, and effectiveDate (YYYY-MM-DD), with a source of manual or carried_forward (saveTodaysRates in currencies/mutations.ts). Nothing posts to the general ledger here — these rates are the inputs other postings read.

When a transaction posts, BigBooks picks the rate type by the kind of document, not by hand. The single source of truth is lib/rateTypeForSourceType.ts:

  • Sales-side → AR Buying. Invoices, goods receipts, and customer payments received. You "buy" the foreign currency when the customer hands it over, so the bank's buy rate applies.
  • Purchase-side → AP Selling. Expenses, supplier invoices, payroll, purchase orders, and supplier payments made. You "sell" foreign currency to pay the supplier, so the bank's sell rate applies.
  • Internal → Mid. Manual journal entries, opening balances, closing and adjustment entries — the canonical book rate.

The chosen rate is stamped onto the transaction at the moment it is created or issued: a foreign-currency invoice stores its exchangeRate on the document (and a non-LAK invoice cannot be issued without one), and a payment stamps the rate effective on its payment date. The journal entry then values its LAK base from that stamped rate (invoices/mutations.ts uses invoice.exchangeRate ?? 1). Because the rate is captured on the source document, editing today's grid does not re-value anything already posted — historical entries keep the rate they were booked at, which is what makes the audit trail stable for MoF 2020.

The rate gate (checkRateGate in currencies/queries.ts) reports readiness for a date: ready when every active pair has its rates, soft_block when a pair is missing today's rate but has a prior value to carry forward, and hard_block when a pair has no historical rate at all (cold start). The grid shows a banner for soft- and hard-block so you know to enter a rate before posting FX transactions for that date.

Common problems

  • No rate for the date (hard block): A pair with no historical rate at all blocks FX postings — enter at least one rate for it before transacting.
  • Carry-forward available (soft block): A pair missing today's rate but with a prior value shows the carry-forward prompt; press Use yesterday's rates, review, and save.
  • Locked cell won't change: Once a journal entry on that date references a rate, the cell locks. Saving again skips locked cells rather than altering a posted figure; correct it via an adjustment instead.
  • Editing a rate after postings exist: Changing a rate only affects future postings — already-posted entries keep their stamped rate and are not re-valued.
  • Only one rate type entered: Sales convert on AR Buying and purchases on AP Selling, so leaving one column blank can block the matching transaction. Fill both for any pair you both buy and sell in.
  • Read-only grid: If the cells are not editable you have view-only access — maintaining rates needs an admin (or account-manager) role.
  • Inverted rate: The cell reads "1 {foreign} = ____ LAK"; check the magnitude against the muted yesterday value if a conversion looks wildly off.

On this page