Ukrainian compliance — Foreign Exchange

NBU Exchange Rates + Exchange Differences

Daily automatic import of official exchange rates from the National Bank of Ukraine (bank.gov.ua). Exchange differences calculated automatically per P(S)BO 21 — gain posted to account 714, loss to account 945.

Daily 10:15 Kyiv auto-import USD EUR GBP PLN CHF CZK P(S)BO 21 differences Conflict-free upsert

Daily auto-import from bank.gov.ua — 10:15 Kyiv time

CurrencyRateScheduler runs on every weekday at 10:15 Kyiv time via robfig/cron/v3. FetchIfNeeded() checks whether rates for today already exist — if they do, the API call is skipped entirely.

  • Schedule: weekdays only, 10:15 Europe/Kyiv — weekends and holidays skipped automatically
  • FetchIfNeeded(): skips if today's rate already exists in DB — idempotent, safe to call multiple times
  • Currencies: USD, EUR, GBP, PLN, CHF, CZK — configurable in NBUConfig
  • Upsert: ON CONFLICT (from_currency, to_currency, effective_date, source) DO UPDATE — no duplicates
  • GetRates(ctx, date): fetch rates for any past date from the NBU API archive
  • GetRateForCurrency(currency, date): single-currency lookup — used by invoice posting and bank reconciliation
Валюта Код Курс НБУ bank.gov.ua 🇺🇸 USD 840 🇪🇺 EUR 978 🇬🇧 GBP 826 🇵🇱 PLN 985 🇨🇭 CHF 756 🇨🇿 CZK 203 bank.gov.ua · 10:15 ⏰ · weekdays Europe/Kyiv
П(С)БО 21 · Exchange Differences Gain Кт 714 FX income rate rose · UAH weakened Dt receivable / Ct 714 Loss Дт 945 FX expense rate fell · UAH strengthened Dt 945 / Ct receivable = 0 no journal entry · ledger stays clean 714 → Form 2 income 945 → Form 2 expense

Exchange difference calculation — P(S)BO 21

The exchange difference is calculated when a foreign-currency invoice is paid at a rate different from the invoice date rate. Three outcomes: gain, loss, or zero. Only gain and loss generate journal entries.

Gain — rate increased (UAH weakened)

  • Dt receivable account / Ct 714 (income from exchange differences)
  • Example: invoice at USD/UAH = 38.00, payment at 41.50 → gain
  • 714 feeds directly into P&L Form 2 (financial income section)

Loss — rate decreased (UAH strengthened)

  • Dt 945 (losses from exchange differences) / Ct receivable account
  • Example: invoice at USD/UAH = 41.50, payment at 38.00 → loss
  • 945 feeds directly into P&L Form 2 (financial expense section)
Zero difference (rates are equal): no journal entry created — prevents cluttering the ledger.

How automatic scheduling works — every weekday at 10:15 Kyiv

The NBU scheduler is started in main.go via NBUScheduler.Start(). It uses the same robfig/cron/v3 engine as all automation scripts — consistent, production-tested, cron expression based. Europe/Kyiv timezone is set explicitly for correct DST handling.

cron expression
"15 10 * * 1-5" — weekdays, 10:15 Europe/Kyiv
↑ minute↑ hour↑ day↑ month↑ weekday 1510**1-5
  • NBUScheduler.Start() launched in main.go alongside all other background services
  • Cron expression: "15 10 * * 1-5" — weekdays only, 10:15 Kyiv
  • ParseExchangeDate(): handles the NBU API date format differences across API versions
  • NBUConfig struct: currencies list, timezone, API base URL — configurable in config.go
  • Same robfig/cron/v3 engine as S-UA06 (daily cash balance) and S-UA07 (overdue AR) scripts
12 3 6 9 10:15 Europe/Kyiv CurrencyRateScheduler Mo Tu We Th Fr Sa Su "15 10 * * 1-5" FetchIfNeeded() · idempotent
NBU Rates GetRateForCurrency() 🧾 Invoicing GetRateForCurrency( currency, invoice_date) 🏦 Client-Bank rate on value date + FX difference entry 📈 Form 2 (ФФР) 714 + 945 auto-post → financial income/expense bank.gov.ua

How other modules consume exchange rates

Exchange rates are not just stored — they are actively used by three other contexts in Axiom. Every foreign-currency operation pulls the exact transaction date rate from the rates table.

🧾 Invoicing

Foreign-currency invoice posting → GetRateForCurrency(currency, invoice_date) → UAH equivalent in journal entry.

🏦 Client-Bank

Statement line in USD → NBU rate on value date → UAH booking amount + FX difference.

📈 Financial Statements

FX gain (Ct 714) and loss (Dt 945) flow into Form 2 financial income/expense lines automatically.

Related modules