Наприкінці місяця у вас на балансі лежать валютні залишки, дебіторка й кредиторка в USD чи EUR — а курс НБУ за місяць зрушив. Поки ви їх не перерахуєте за курсом на 31-ше число, баланс показує валютні активи й зобов’язання в застарілій гривневій оцінці. Тут ви проженете в Odoo переоцінку монетарних статей, визнаєте курсові різниці доходом чи витратою періоду — і не зачепите аванси, які за П(С)БО 21 лишаються за історичним курсом. Головна пастка чекає саме на авансах і на поділі операційних курсових від фінансових, тож пройдемо це покроково.
Результат
Після цієї процедури:
- Усі монетарні статті у валюті (валютні рахунки в банку, валютна дебіторка/кредиторка, валютні позики) на 31-ше число перераховані за курсом НБУ на дату балансу.
- Курсові різниці визнані доходом (714/744) або витратою (945/974) періоду — операційні окремо від неопераційних.
- Немонетарні статті у валюті (наприклад, аванси за товар чи запаси, оплачені в EUR) не переоцінюються — лежать за історичним курсом.
- Баланс на 31-ше показує реальну гривневу оцінку валютних активів і зобов’язань.
Передумови
- Odoo 17/18 з налаштованим multi-currency (
Settings → Accounting → Multi-Currency). - На
res.company.currency_idстоїть UAH. currency_provider = 'nbu', cronUpdate Currency Rateзапускається щодня без помилок.- У
res.currency.rateє курси за всі дні місяця (особливо 31-ше — критично). - На кожному валютному рахунку плану (362, 316, 314, валютні субрахунки 632) у
account.accountстоїтьcurrency_id = USD/EURабоFalseдля multi. - У налаштуваннях компанії заповнені поля:
income_currency_exchange_account_id— рахунок 714 (доходи від операційних курсових).expense_currency_exchange_account_id— рахунок 945 (втрати від операційних курсових).- Окремо для неопераційних — 744 і 974.
Як це зробити
1. Розберіться, що переоцінюється, а що ні
Це базове правило, без якого Odoo налаштувати правильно неможливо. ⚖Сила законуП(С)БО 21 ділить статті у валюті на дві категорії.
Монетарні статті — переоцінюються на кожну дату балансу.
Це права отримати або обов’язки сплатити фіксовану суму грошей. Конкретно:
- 314 — Поточний рахунок в іноземній валюті.
- 316 — Спеціальні рахунки в іноземній валюті.
- 312 — Поточний рахунок в банку за межами України.
- 302 — Готівка в іноземній валюті (каса).
- 362 — Розрахунки з покупцями у валюті (валютна дебіторка).
- 632 (валютний субрахунок) — Розрахунки з постачальниками у валюті (валютна кредиторка).
- 506 / 507 — Інші довгострокові позики у валюті.
- 602 / 612 — Короткострокові кредити банків у валюті.
Немонетарні статті — НЕ переоцінюються.
Це активи й зобов’язання, які стануть товаром/послугою, а не грошима. Конкретно:
- 371 (аванси видані постачальникам у валюті за товар) — лежать за курсом на дату перерахування.
- 681 (аванси одержані від покупців у валюті) — лежать за курсом на дату отримання.
- 201, 281 (запаси, оприбутковані у валютних інвойсах) — за курсом на дату оприбуткування.
- 152 (капінвестиції в обладнання, придбане за валюту) — за курсом на дату введення в експлуатацію.
Перша граблиця Odoo для українського обліку — саме 371 і 681 у валюті. За замовчуванням Odoo ставить на них currency_id і вмикає revaluation, тож переоцінює аванси як монетарні. За П(С)БО 21 це неправильно: аванс віддасться товаром, а не грошима. На 371 і 681 явно поставте currency_revaluation = False — або тримайте їх узагалі без currency_id, тоді Odoo сам виключить їх із переоцінки.
2. Перевірте курс НБУ на 31-ше число
Accounting → Configuration → Currencies → USD → Rates (або EUR). На 31 травня має бути запис з provider = NBU. Якщо немає:
- Cron
Update Currency Rateне пройшов — подивіться Settings → Technical → Scheduled Actions його лог. - Курс НБУ на 31-ше може бути взагалі відсутнім, якщо 31-ше — субота/неділя/свято. Тоді діє курс попереднього робочого дня. Положення про встановлення офіційного курсу, постанова НБУ № 309 від 12.11.2003 Завантажте курс п’ятниці вручну з полем
name = 2026-05-31.
3. Запустіть Currency Revaluation
Accounting → Operations → Unrealized Currency Gains/Losses.
Вкажіть:
journal_id— Журнал «Курсові різниці» (заведіть окремий, типgeneral).expense_provision_account_id— рахунок 945.income_provision_account_id— рахунок 714.- Дата — 31.05.2026.
Натисніть «Adjust Balance». Odoo:
-
Для кожного валютного рахунку (з
currency_id ≠ Falseіcurrency_revaluation = True) обчислює:revalued_uah = amount_currency × rate_31_maycurrent_uah = sum(debit) − sum(credit)diff = revalued_uah − current_uah -
Створює
account.moveз типомMiscна дату 31.05 з рядками для кожного рахунку, деdiff ≠ 0. -
Для дебіторки в USD з ростом курсу (наприклад, з 41,2 до 41,8):
- Для кредиторки в USD з ростом курсу (нам платити більше):
- Для валюти на рахунку в банку з падінням курсу:
4. Розділіть операційні і неопераційні курсові
⚖Сила законуП(С)БО 21 п.8 ділить курсові на операційні (від основної діяльності) і неопераційні (від інвестиційної та фінансової). Це впливає на P&L:
- Операційні курсові (з основної дебіторки/кредиторки, валютних залишків) → 714 / 945. У P&L це «Інші операційні доходи/витрати».
- Неопераційні курсові (з кредитів, інвестиційних позик, депозитів) → 744 / 974. У P&L це «Фінансові доходи/витрати».
Odoo з коробки не розділяє — wizard кидає все на один pair 714 / 945. Тож або:
- Варіант А. Запускаєте wizard двічі — окремо для операційних рахунків (362, 632, 314), окремо для фінансових (506, 602, 612). Перед другим запуском у налаштуваннях компанії тимчасово міняєте
expense/income_currency_exchange_account_idна 974/744. - Варіант Б. Запускаєте один раз, потім ручкою переносите
account.move.lineз 714/945 на 744/974 за фінансовими рахунками. ЧерезMiscmove.
ТОВ «УкрПром-Тех» працює за Варіантом А — менше ручної роботи на місяць, чисто в обліковій політиці.
5. Перевірте, що ревальвація сторнується наступного періоду
Odoo має параметр currency_exchange_journal_id.refund_sequence і auto_reverse — account.move курсових різниць має автоматично сторнуватися 1-го числа наступного місяця. Це щоб не задвоювати курсові: на 31-ше визнали різницю до балансу, 1-го сторнували, а реальна різниця визнається на дату фактичного руху коштів.
Перевірте: на account.move курсових різниць у полі auto_post = 'at_date', reversal_date = 2026-06-01. Якщо ні — встановіть руками.
6. Перевірте баланс після ревальвації
Через Reporting → Balance Sheet на 31.05.
- Сума за 314 у гривні має дорівнювати
amount_currency_USD × 41,80(за останнім курсом НБУ). - Сума за 362 у гривні — те саме.
- Сума за 632 у гривні — те саме.
- Аванси на 371/681 — лишаються за історичним курсом, не за курсом 31-го.
Якщо щось не сходиться — або revaluation не пройшов по всіх рахунках, або хтось ставить currency_revaluation = False на монетарний рахунок (або True на немонетарний — і Odoo переоцінив 371, як буває).
Перевірка
- Курс НБУ на 31-ше число завантажено в
res.currency.rate(для робочого дня — за фактом, для вихідного — за попередньою п’ятницею). - На 371, 681, 201, 281 у плані рахунків
currency_revaluation = False(абоcurrency_id = False). - На 314, 316, 362, 632 (валютному), 506, 602 у плані рахунків —
currency_id = USD/EURіcurrency_revaluation = True. - Заведений окремий журнал «Курсові різниці» з
auto_reverse = Trueіreversal_date = 01.06.2026. - Запущено wizard
Unrealized Currency Gains/Lossesна 31.05. - Операційні курсові пішли на 714 / 945, неопераційні — на 744 / 974.
- Гривнева оцінка валютних залишків у Balance Sheet =
amount_currency × rate_31_may. - Створений
account.moveревальвації маєreversal_move_idна 01.06.
Якщо щось пішло не так
Wizard не створив жодного account.move. Найімовірніше, на валютних рахунках стоїть currency_revaluation = False за замовчуванням після міграції. Перевірте через Accounting → Configuration → Chart of Accounts → 314 → дивитись поле. Або курс на 31-ше = курсу попереднього перерахунку — тоді diff = 0 і Odoo нічого не створює (нормально).
Wizard переоцінив 371 (аванси у валюті) — а не повинен був. Тимчасово на 371 стояло currency_id, бо хтось завів партнера як USD-постачальника без розділення «авансу» і «розрахунків». Виправте: currency_revaluation = False на 371, сторнуйте помилкову проводку, повторно запустіть.
Курс НБУ на 31-ше — субота. Cron взяв курс п’ятниці, але присвоїв йому дату суботи. Це коректно для постанови НБУ № 309 (вихідні = курс попереднього робочого дня). Перевірте name = 2026-05-31, rate = 41,80 — це і є офіційний курс на 31-ше.
Ревальвація створила проводку, але на наступний місяць вона не сторнувалась. На account.journal не виставлено auto_reverse. Виправте налаштування і вручну створіть зворотній move на 01.06 (через Action → Reverse Entries). Альтернативно — встановіть reversal_date на ручному проведенні account.move.
Операційні і фінансові курсові злилися на 714/945. За одне закриття — переживете, перенесіть ручкою на 744/974 з тим самим datum 31.05. На наступне закриття — окремо запускайте wizard з тимчасово зміненими expense/income_currency_exchange_account_id.
Експорт у валюті: ПЗ декларуються за курсом МД, а курсові обліку — за курсом 31-го. Не плутайте. Курс МД фіксує ПДВ-зобов’язання для декларації (за ПКУ 187.1). Курсові різниці на 362 рахуються від курсу інвойсу до курсу 31-го. Це різні курси, різні проводки. Деталі — у статті Експорт ГП із 0%.
На 506 (валютний кредит) курсова за весь рік накопичилась до 1,2 млн ₴ збитку. Чи це нормально? Так, це механізм: кредит у валюті — це «зашита» курсова експозиція. Якщо гривня ослабла на 10% — ваше зобов’язання збільшилось на 10% у гривневому еквіваленті, і це зараз визнається як збиток у P&L (974). Управлінсько — це повідомлення про FX-ризик, який треба хеджувати. Інакше курсові «з’їдять» прибуток від основної діяльності.
Дотичне
- Закриття місяця — чеклист — крок 8 цього чеклисту.
- Multi-currency в Odoo — налаштування з нуля.
- Експорт ГП із 0% ПДВ — курс МД vs курс отримання валюти.
- Cron і автоматизація — як працює
Update Currency Rate. - Звітний період — навіщо взагалі робиться revaluation на 31-ше.