💱 Exchange differences
Updated
How a sale under a contract in a foreign currency, or a purchase from a supplier who bills in one, is owed, paid and carried in the books. The debt is in the counterparty's currency. The general ledger, tax, revenue and stock value are in the legal entity's own currency. The gap between the two is the exchange difference: realised at payment, unrealised at period end.
How the process works#
Sales realization "Released" ──► Receivable: Amount (contract currency) + AmountFunc (entity currency)
rate on the invoice date Dr receivables / Cr revenue, at that rate
│
Customer payment "Paid" ──► settles Amount, takes AmountFunc off at its carrying value
rate on the payment date Dr cash at the payment rate, Cr receivables at carrying,
│ the gap → exchange gain or loss (realised)
Receivable revaluation "Posted" ──► moves AmountFunc to open amount × period-end rate
rate on the last day the gap → exchange gain or loss (unrealised)
- The currency comes from the contract. The Currency field of the
SalesContractdictionary record decides it. The invoice, its credit and debit notes, returns and payments all follow their contract. A contract in the legal entity's own currency works exactly as before: the rate is 1, and nothing below produces a difference. - Each document stamps its rate. The rate is the contract currency's rate to the entity currency on the document date, taken from Exchange rates. It is written on the document as Exchange rate, so the document remembers the rate it was posted at, not today's.
- The debt has two sides. The
Receivableregister keepsAmountin the contract's currency (what the customer is asked to pay) andAmountFuncin the entity's currency (what the debt is carried at in the books). - A payment settles the average. The register has no open items: debt is
one balance per customer and contract. A payment of part of it takes off the
same share of
AmountFunc, and that share is the line's Carrying amount. The part of a payment above the open debt is an advance and is carried at the payment's own rate. - A revaluation moves only the entity-currency side. It is a document of
its own,
ReceivableRevaluation. Fill revaluation lists every open foreign-currency slice of one legal entity at the rate on the document date. Post revaluation books the differences. Cancel revaluation takes them back. The revalued carrying amount stays: it is not reversed next period, and the next payment's difference is measured against it. Realised and unrealised therefore add up to the whole difference.
A credit note, debit note and return use the rate of the invoice they correct. Tax was recognised at that rate, so it is reversed at that rate.
Purchases#
The purchase side mirrors the sale, with three differences:
- The currency comes from the supplier contract. A payable is kept in the
Currency of the document's
SupplierContract; a document without a contract, or a contract with no currency, takes the Currency of theSuppliercard; empty means the buyer legal entity's own currency. One supplier may hold contracts in several currencies at once — a hryvnia and a dollar contract of the same vendor, as in 1C — and each is owed, paid and revalued in its own currency. - The stock is valued at the receipt's rate. A receipt in 100 EUR at 40
enters stock at 4000 in
InventoryValueand the cost lots, so cost of sales later is in the entity's currency. A supplier invoice difference is booked at the rate on the supplier's invoice date. - The signs are mirrored. A payable is a liability: when the rate rises,
the entity owes more, so a payment or a revaluation at a higher rate is an
exchange loss.
PayableRevaluation(Purchasing → Documents → Payable revaluations) works like the receivable one.
Settings#
Exchange rates#
Where: model Common → dictionary ExchangeRate. Ribbon → Common →
Dictionaries → Exchange rates.
Each row is one currency's Rate to base in a date window (Effective from / Effective to). The base currency is the one whose rate is 1. A rate between two currencies is computed through the base, so you enter one number per currency, not one per pair.
| Value | What changes |
|---|---|
| A window covers the document date | The document stamps the rate and posts |
| No window covers the date (foreign currency) | The invoice is not released, and the payment is not posted. The refusal names the date the rate is missing for |
| The contract currency is the entity's own | No rate is needed; the rate is 1 |
Default: no rows. A single-currency stand needs none.
Example. The entity's currency has rate 1. EUR has 40 from 1 to 15 June and 42 from 16 to 25 June. An invoice dated 10 June stamps 40; a payment dated 20 June stamps 42.
Reporting in another currency#
The books do not store a third currency. A document form, a print layout or a
turnover that must show the same amounts in dollars (or any other currency
you keep rates for) converts on the day of the report through
ICurrencyRateService.ConvertMoneyAsync. The order card already prints the
contract currency's Symbol next to the total; it does not convert.
| Value | What changes |
|---|---|
| A window covers the report date for both currencies | The amount is converted, rounded to Amount scale, and shown with the target Symbol (or Code if Symbol is empty) |
| No window on that date | Nothing is converted. The caller leaves the cell empty or refuses the report |
| The source is already the target | The amount is unchanged; no rate row is required |
Where: the same Exchange rates dictionary. There is no extra setting named "reporting currency".
Default: no conversion. Totals stay in the contract currency (the card)
or in the legal entity's currency (AmountFunc on the register).
Example. Books are hryvnia. 100 EUR of June invoices sit in AmountFunc
as 4000. On 30 June EUR is 42 and USD is 40 (both to the base). Convert
4000 UAH → USD on that day: 4000 / 40 = 100 USD. Convert the 100 EUR
themselves on 30 June: 100 × 42 / 40 = 105 USD. Those are two different
questions — "as in the books, in dollars" versus "what the euros are worth
today". Pick one per report. Do not add a euro invoice to a dollar invoice
and then convert the sum.
Supplier currency#
Where: model Purchasing → dictionary SupplierContract, field
Currency; and extension Supplier.Purchasing on the Supplier dictionary,
field Currency (on the supplier card). The contract's wins; the card's
fills a contract saved without one and covers documents with no contract.
| Value | What changes |
|---|---|
| A currency other than the buyer entity's | Receipts, supplier invoices, returns and payments under this contract stamp a rate and carry the payable in two currencies |
| (empty) or the entity's own currency | Rate 1, everything posts as before |
Default: empty.
Example. Supplier «Rexon» bills in USD (card). Its contract «Seal Odesa» is in UAH. A receipt of 3 × 10 under «Seal Odesa» owes 30 UAH at rate 1; a receipt of 2 × 50 under the USD contract owes 100 USD, carried at 4000 at rate 40. A revaluation on 30 June at 41 revalues only the USD contract: +100.
Amount in words#
Where: model Common → dictionary Currency → group Amount in words
on the currency card. The order summary (the document-totals card) spells
the total out with these words.
| Field | What it holds | Example, Ukrainian |
|---|---|---|
WordsUnitOne / WordsUnitFew / WordsUnitMany |
the unit after 1 (21, 31…), after 2–4 (22–24…), after 5+ and 11–14 | гривня / гривні / гривень |
WordsUnitGender |
Masculine, Feminine or Neuter: decides одна/один/одне and дві/два before the unit |
Feminine |
WordsMinorOne / WordsMinorFew / WordsMinorMany |
the hundredth, same three forms | копійка / копійки / копійок |
WordsMinorGender |
gender of the hundredth | Feminine |
The six word fields are translatable: each language keeps its own words, and
the card shows the words of the language you are working in. English and
Arabic use only the «one» and «many» forms. A field left empty keeps the
built-in word, which exists for UAH, RUB, USD, EUR, SAR and AED. A currency
with neither prints the hundredths as a fraction: одна тисяча вісім 63/100.
Example. A total of 1,008.63 UAH reads одна тисяча вісім гривень 63 копійки in Ukrainian and
одна тысяча восемь гривен 63 копейки in Russian. 1.00 EUR reads
одне євро 00 центів: euro is neuter.
Which currency. The card takes the document's own Currency. A document
without one — a sales order — takes its contract's currency, then its legal
entity's, then CommonSettings.DefaultCurrency.
Exchange gain and loss accounts#
Where: model Accounting → dictionary AccountingSettings → group
Exchange differences, fields Exchange gain account and Exchange loss
account. Ribbon → Accounting → Settings → Accounting settings.
| Value | What changes |
|---|---|
| A postable account | The difference is booked to it: a gain as Cr gain, a loss as Dr loss |
| (empty) | The payment posts as before FX (Dr cash / Cr receivables at what came in), and the difference stays in the receivables account. A revaluation moves the register but books nothing |
Default: empty. The same pair serves realised and unrealised differences.
Revalue on period close#
Where: the same group, Revalue on period close.
| Value | What changes |
|---|---|
| On | Closing a fiscal period (its Status set to anything but Open) first posts a ReceivableRevaluation and a PayableRevaluation dated the period's last day for every legal entity with foreign-currency debt. If one cannot be posted — a rate is missing on that day — the period stays open and the refusal names the currency and the date. Closing again after reopening revalues nothing twice: the difference is already booked |
| Off | Revaluation is a document you create and post yourself |
Default: off.
Example. 100 EUR open at 4000; the rate on 30 June is 41. Closing June with the setting on posts a receivable revaluation of +100 dated 30 June before the period closes. Without a rate on 30 June, June stays open.
Example with numbers#
The entity keeps its books in its own currency (rate 1). The contract is in EUR. Rates: 40 until 15 June, 42 from 16 to 25 June, 41 from 26 to 30 June.
| Step | Document | Amount (EUR) |
AmountFunc |
Ledger |
|---|---|---|---|---|
| 10 June | Invoice 100 EUR, rate 40 | 100 | 4000 | Dr receivables 4000 / Cr revenue 4000 |
| 20 June | Payment 60 EUR, rate 42 | 40 | 1600 | Dr cash 2520 / Cr receivables 2400 / Cr exchange gain 120 |
| 30 June | Revaluation, rate 41 | 40 | 1640 | Dr receivables 40 / Cr exchange gain 40 |
| 30 June | Payment 40 EUR, rate 41 | 0 | 0 | Dr cash 1640 / Cr receivables 1640 |
The payment on 20 June settles 60 of 100 EUR, so it takes off 60% of 4000 = 2400, not 60 × 40 at today's guess. The last payment books no difference: the revaluation had already carried the debt at 41. The customer paid 4160 in total for a sale recognised at 4000, and the 160 of gain splits 120 realised and 40 unrealised.
What is posted#
| Document | Transition | Register | Ledger |
|---|---|---|---|
SalesRealization |
→ Released | Receivable Amount +, AmountFunc + at the invoice rate; Revenue at the invoice rate |
Dr receivables / Cr revenue at the invoice rate; output tax on the converted base |
SalesCreditNote, SalesDebitNote |
→ Posted | Receivable tax part, both sides, at the invoice's rate |
tax reversal or addition on the converted base |
SalesReturn |
→ Posted | Receivable and Revenue minus, at the invoice's rate |
Dr revenue / Cr receivables, converted |
CustomerPayment |
→ Paid | Receivable Amount − line amount, AmountFunc − Carrying amount |
Dr cash (amount × payment rate) / Cr receivables (carrying) / the gap to gain or loss |
ReceivableRevaluation |
→ Posted | Receivable AmountFunc ± difference |
gains: Dr receivables / Cr gain; losses: Dr loss / Cr receivables, as two sums |
PurchaseOrder |
→ Received | Payable Amount +, AmountFunc + at the receipt rate; InventoryValue and cost lots at that rate |
Dr inventory / Cr payables, converted; input tax on the converted base |
VendorPayment |
→ Paid | Payable Amount − line amount, AmountFunc − Carrying amount |
Dr payables (carrying) / Cr cash (amount × payment rate) / the gap: owed more than paid → Cr gain, paid more → Dr loss |
PayableRevaluation |
→ Posted | Payable AmountFunc ± difference |
a rise: Dr loss / Cr payables; a fall: Dr payables / Cr gain |
Boundaries and edge cases#
- No rate, no posting. A foreign-currency invoice or payment without a rate window on its date is refused, and the message names the date.
- A contract may use a currency other than the seller's. The invoice, notes, returns and payments follow the contract currency, not the legal entity's.
- Revaluation reads the balance on its own date. The open amount and its carrying value are summed from the movements dated on or before the revaluation date. You can fill June's revaluation in July: July's invoices and payments do not enter it. If a July payment was posted before the June revaluation, it settled the debt at the unrevalued value; the July revaluation then removes what remains, and the total over the two months is still exact. A payment is likewise measured against the debt as it stood on the payment date.
- The currency is fixed while debt is open. A contract's Currency or a supplier's Currency cannot change while the contract or supplier owes or is owed anything; the refusal names the open amount. Close the debt first (pay, or issue a credit note), then change the currency. This is also why there is no "debt from before FX": a currency can only be set on a clean slice.
- Payables are kept per legal entity and contract.
Payablecarries the legal entity and the supplier contract of each document, so a supplier billed by two of your entities, or under contracts in two currencies, is revalued and paid per entity and contract, each in its own currency. - An advance carries at the payment rate. If an invoice is later set
against that advance, a small entity-currency residual can remain on a slice
whose
Amountis zero. The next revaluation clears it. - Gains and losses are not netted in a revaluation: a loss on one customer does not hide behind a gain on another.
What's not there yet#
- A payment settles the average carrying value of the contract slice, not a particular invoice. There is no open-item matching.
- The register totals tab does not pick a reporting currency. A form, print
layout or report script that needs one calls
ConvertMoneyAsyncon a slice that is already one currency (Amountof one contract, orAmountFunc).
Same topic for other readers: User · Developer