Odoo
МодульCron і scheduled actions — нічна логіка Odoo
ir.cron, model_id, function_id. Які стандартні cron важливі. Як писати власні — для перевірки ЄРПН-статусу, нагадувань, переоцінок.
Що це і навіщо
Половина Odoo живе у фоні. Поки бухгалтер виставляє інвойси, в системі тихо працюють cron’и: оновлюють курс НБУ, перевіряють статус ПН в ЄРПН, генерують нагадування про оплату, переоцінюють залишки, запускають reordering rules, чистять застарілі вкладення. Без них Odoo — лише форма для введення даних, а не жива система.
Усе це — ir.cron (Scheduled Actions). Прості записи в БД, які описують: коли запускати, який метод викликати, як часто, скільки спроб. Спрощено — це cron з crontab, тільки керований через ORM.
Як це працює
Модель:
class IrCron(models.Model):
_name = 'ir.cron'
name = fields.Char()
model_id = fields.Many2one('ir.model')
state = fields.Selection([('code', 'Python Code')])
code = fields.Text() # рядок типу "model.cron_clean_old_logs()"
interval_number = fields.Integer(default=1)
interval_type = fields.Selection([
('minutes', 'Minutes'),
('hours', 'Hours'),
('days', 'Days'),
('weeks', 'Weeks'),
('months', 'Months'),
])
nextcall = fields.Datetime() # коли наступний запуск
numbercall = fields.Integer(default=-1) # -1 = безкінечно
doall = fields.Boolean() # чи виконати пропущені прогони
active = fields.Boolean(default=True)
Перебіг:
- Odoo має базовий процес
cron worker(відокремлений від web/api workers). - Він раз на хвилину сканує
ir.cronдеactive=True AND nextcall<=now(). - Для кожного знайденого — виконує
codeвід імені користувачаuser_id(за замовчуванням — суперюзер). - Оновлює
nextcall = now() + interval.
Метод викликається в контексті ORM, тож усередині доступне все звичне — self.env, пошук, запис. Якщо метод впав з винятком, cron спробує ще раз на наступному циклі; за numbercall > 0 спроби рахуються до вичерпання.
# Свій cron — перевіряти статус ПН в ЄРПН
def _cron_check_erpn_status(self):
pending = self.env['tax.invoice.ua'].search([('state', '=', 'sent')])
for pn in pending:
new_state = self._erpn_api.check_status(pn.erpn_id)
if new_state != pn.state:
pn.state = new_state
if new_state == 'registered':
pn.message_post(body=_('ПН зареєстрована в ЄРПН'))
<!-- Запис у XML -->
<record id="cron_check_erpn" model="ir.cron">
<field name="name">ЄРПН: перевірка статусу ПН</field>
<field name="model_id" ref="model_tax_invoice_ua"/>
<field name="state">code</field>
<field name="code">model._cron_check_erpn_status()</field>
<field name="interval_number">15</field>
<field name="interval_type">minutes</field>
<field name="active" eval="True"/>
</record>
Шлях у меню (developer mode): Settings → Technical → Automation → Scheduled Actions.
У контексті українського обліку
Стандартні cron, які точно потрібні в UA-проєкті:
- Update Currency Rate. Щодня тягне курс НБУ. Без цього експортно-імпортні операції рахуються за неправильним курсом.
- Anglo-Saxon Periodic COGS. Закриває WIP-проводки виробничого циклу. Без цього собівартість «зависає».
- Reordering rules. Запускає purchase requisitions під min-stock.
- Payment Reminders. Шле нагадування про прострочку.
- Mass Mailing — Queue. Якщо використовуєш email-розсилки.
Що треба дописати самим:
- ЄРПН — перевірка статусу. Раз на 15 хвилин, для PN/RK у статусі
sent. - СЕА — оновлення ліміту. Раз на годину, тягне з ДПС.
- Реєстр ЄРПН — порівняння внутрішніх ПН з реєстром. Раз на день, для виявлення розходжень.
- Контроль термінів реєстрації ПН. Щодня вранці, якщо до дедлайну менше 3 днів — нагадування бухгалтеру.
- Курсова переоцінка на дату балансу. На останній день місяця — автоматична переоцінка валютних залишків. Перевірити, що НБУ є.
- Перевірка прострочки авансових звітів. Щодня. Якщо підзвіт прострочений (більше 10 робочих днів — для відрядження або 5 — для готівки) — алерт співробітнику і бухгалтеру.
- Закриття місяця — чек-лист. На 1 число — нагадування з чек-листом: WIP закрито, переоцінка зроблена, ПДВ збалансовано, lock date встановлено.
Як ми робимо (defense-контекст)
ТОВ «УкрПром-Тех» має такий парк власних cron:
| Cron | Періодичність | Призначення |
|---|---|---|
Check ERPN status | 15 хв | Статус ПН/РК в ЄРПН |
Update SEA balance | 1 година | ΣНакл з кабінету ДПС |
Reconcile ERPN registry | 1 день, 02 | Порівняння внутрішніх ПН з реєстром |
ПН deadline warning | 1 день, 09 | Нагадування за 3 дні до 15-денного дедлайну |
Defense contract status | 1 день, 06 | Тягне статуси контрактів з Прозоро.МО |
Calculate WIP for defense MOs | 1 день, 23 | Розрахунок реальної собівартості для відкритих захищених MO |
Check ВТП export licenses | 1 день, 07 | Перевірка термінів дозволів ДСЕКУ |
Currency revaluation (auto) | last day of month | Переоцінка валютних залишків |
Особливість: cron, що ходять до зовнішніх API (ЄРПН, ДПС, Прозоро), мають retry-логіку і таймаути. Якщо API недоступне — не падаємо, а логуємо у mail.activity для адміна.
Типові граблі
- Cron не запускається. Перевір: 1)
active=True; 2)nextcallне залишився далеко в минулому (заdoall=FalseOdoo такий прогін просто пропустить); 3) процесcron workerзапущено (--no-cronйого вимикає); 4) користувач, від якого йде запуск, має права на цю модель. - Cron «застрягає». Метод працює довше, ніж interval. Наступний запуск чекає, поки попередній закінчиться. Якщо це cron на годину, а виконується 90 хв — частина запусків просто пропаде. Або скорочуй роботу, або запускай частіше і з batching (по 100 записів за раз).
- Cron впав мовчки. Виняток поглинула внутрішня логіка cron worker. Дивися в
mail.messageвід моделі — Odoo іноді логує. Краще — обгортай весь код уtry/exceptі пиши в_logger.error+ створюйmail.activity. - Конкурентні cron. Два cron одночасно пишуть в одну таблицю. Транзакції конфліктують, один результат втрачається. Використовуй
with_lockабо синхронізацію через lock-файл уir.attachment. - Бойовий cron відпрацював на тестовій копії. Скопіювали БД, а зовнішні cron не вимкнули — test-копія повторно зареєструвала ПН у реальному ЄРПН, і дублікат отримав статус «реєстрація вже існує». Завжди вимикай зовнішні cron при клонуванні БД (
active=False). numbercallлишився 1 (або його забули виставити). Cron спрацював один раз і назавжди замовк. Перевір: для постійного завжди-1.- Cron логи розпухли. Якщо метод щохвилини пише в
_logger.info— за тиждень логи на 10 GB. Логуй тільки помилки і важливі стани, а не кожен тік. - Cron-користувач без 2FA — а аудитор про це питає. Cron’и зазвичай ходять від суперюзера, у якого 2FA немає. Заведи окремих
service_userіз мінімальними правами під конкретні cron — і security audit пройде спокійно.
Дотичне
- Як думає Odoo — як моделі викликаються з cron
- Валюта — cron для курсу НБУ і переоцінки
- ПН/РК — cron моніторингу ЄРПН
- СЕА ПДВ — cron оновлення ліміту СЕА
- Декларація ПДВ — cron порівняння з реєстром
Де цей модуль зустрічається3
- ГайдКурсові на дату балансуПерерахунок монетарних статей у валюті на 31 число за курсом НБУ. Що таке монетарна стаття за П(С)БО 21, які р…
- OdooВалютаВалютні рахунки, currency revaluation, курс НБУ як джерело. Дати в експорті: МД, надходження валюти, баланс — …
- OdooЯк думає OdooАрхітектурна основа: ORM, models, fields, views, actions, security. Без цього кастомізація — шаманство.