Перейти до основного контенту
База знань · виробничий облік USD41,42 ПДВ20% МЗП8 000

Odoo

Модуль

Як думає Odoo — моделі, поля, view, workflow

Архітектурна основа: ORM, models, fields, views, actions, security. Без цього кастомізація — шаманство.

Шлях у меню
Developer mode → Settings → Technical
Технічна модель
ir.model, ir.model.fields, ir.ui.view, ir.actions.act_window
Редакція
2026-05-28

Що це і навіщо

Odoo — це не просто ERP, а фреймворк для побудови ERP. У ньому своя ORM, своя система view, своя модель прав і свій спосіб організувати бізнес-логіку. Якщо підходиш до Odoo як до SAP-альтернативи з GUI-конфігуратором — швидко впираєшся у стіну. Усе цікаве починається на рівні моделей і Python-коду.

Ця стаття — про базову ментальну модель. Що таке model, чим regular field різниться від computed, що показує form view, де живе workflow, як працює security. Без цього не зрозуміти, чому модулі мають саме таку структуру, чому не вийде «просто додати поле в таблицю» і чому одна група прав здатна зламати весь модуль.

Як це працює

Model — клас на Python, що мапиться на таблицю в PostgreSQL. Робить це Odoo ORM. Кожна модель — нащадок models.Model (звичайна), models.TransientModel (тимчасова — для wizard’ів) або models.AbstractModel (для міксинів).

class SaleOrder(models.Model):
    _name = 'sale.order'  # технічне ім'я → таблиця sale_order
    _description = 'Sales Order'
    _inherit = ['mail.thread', 'portal.mixin']  # підмішуємо chatter і portal
    _order = 'date_order desc, name desc'

    name = fields.Char(string='Order Reference', required=True, default='New')
    partner_id = fields.Many2one('res.partner', string='Customer', required=True)
    amount_total = fields.Monetary(compute='_compute_amount', store=True)

Fields бувають різні. Найважливіші типи:

  • Char, Text, Html — текстові.
  • Integer, Float, Monetary — числові. Monetary тягне валюту.
  • Date, Datetime — час.
  • Boolean, Selection — checkbox і dropdown.
  • Many2one, One2many, Many2many — реляції.
  • Binary — файли, картинки.
  • Computed — вираховуються через метод (compute='_compute_X'), можуть зберігатися в БД (store=True) або щоразу рахуватися (store=False).

Inheritance буває трьома способами:

  1. Class inheritance (_name = 'sale.order', _inherit = 'mail.thread') — підмішує міксин у новий клас.
  2. Extension inheritance (_inherit = 'sale.order' без _name) — додає поля/методи до існуючої моделі. Найпоширеніший спосіб.
  3. Delegation inheritance (_inherits = {'res.partner': 'partner_id'}) — створює новий клас, що проксує поля до батьківського запису.

Views — як модель показується в інтерфейсі. Окремий XML-запис у ir.ui.view:

  • form — форма однієї картки.
  • tree (тепер list) — таблиця списку.
  • kanban — карточки.
  • search — фільтри і групування.
  • pivot / graph — аналітика.
  • calendar, gantt — спеціальні.

Один і той же запис показується через ту view, яка викликана action’ом.

Actions — точки входу в інтерфейс. ir.actions.act_window — «відкрити вікно з такою моделлю і такими view-ями». Кнопки в меню — це action’и. Кнопки на формі — теж action’и.

Security — два шари:

  1. ir.model.access (ACL). Хто (група) має право CRUD на модель. Обов’язково: для кожної моделі — хоч один запис у ir.model.access.csv.
  2. ir.rule (record rules). Які саме records видно/доступні для редагування. Через домени. Наприклад: «менеджер бачить тільки SO своєї компанії».

Workflow в сучасному Odoo — це не окрема система (старий workflow engine викинули в Odoo 11), а просто:

  • Поле state (Selection) на моделі.
  • Кнопки з методами, які міняють state.
  • Computed-поля, що залежать від state (наприклад, editable).
  • @api.constrains і @api.depends для логіки.
def action_confirm(self):
    self.ensure_one()
    if not self.order_line:
        raise UserError(_('Cannot confirm empty order'))
    self.state = 'sale'
    self._create_picking()
    return True

Шлях у меню для дослідження: Developer mode → Settings → Technical → Models (всі моделі бази), → Views (всі views), → Security → Access Rights / Record Rules.

У контексті українського обліку

У стандартному Odoo моделі під українські реалії спроєктовані поверхово. Тому, коли кастомізуємо систему під UA, ми постійно:

  • Розширюємо account.move додатковими полями для ПН: тип причини, дата складання, статус ЄРПН, ІПН партнера.
  • Створюємо нові моделі для українських сутностей: tax.invoice.ua (ПН як окремий документ), sea.vat.balance (ліміт СЕА), m11.report (накладна-вимога М-11), eu.export.declaration (МД).
  • Додаємо аналітичні поля. analytic_distribution стандартний, але часто треба ще defense_contract_id, military_unit_id — наш specific.

Принцип: ніколи не міняй стандартну модель напряму. Завжди роби нову з _inherit. Так оновлюєш Odoo без втрати кастомізації.

Як ми робимо (defense-контекст)

ТОВ «УкрПром-Тех» має шар власних модулів поверх Oblik-ERP:

  • kit_defense_contract — модель defense.contract з номером А-XXXX, статусом, фінансами.
  • kit_defense_so — розширення sale.order з defense_contract_id, перевірками при підтвердженні.
  • kit_defense_mrp — розширення mrp.production з обов’язковими серійниками і прив’язкою до контракту.
  • kit_defense_blanks — кастомні QWeb-форми для М-11 з defense-смугою, сертифіката відповідності, EUC.

Security: окрема група Defense Officer, яка бачить тільки контракти зі статусом «Активний». Інші групи (наприклад, звичайні продажники) не бачать defense-документів — record rule на defense_contract_id != False.

Типові граблі

  • _inherit забули — створили нову модель. Замість розширення sale.order отримав свою sale.order.custom, ніяк не пов’язану зі стандартом. Інвойси не зв’язані з SO. Лікувати — переробити.
  • store=True на computed-полі без @api.depends. Значення розраховується раз і ніколи не оновлюється. Обов’язково: для зберігання — depends.
  • Поле без security. Створив model, але забув ir.model.access.csv. Інтерфейс показує «Access Denied» для всіх. Базове правило: на нову модель — хоча б два рядки в ACL (для users і для managers).
  • Запис у БД, але не у view. Поле є в моделі, але не виведено в form view. Користувач бачить «зник чи що». Не забувай оновлювати views при додаванні полів.
  • Record rule «всім видно». За замовчуванням після створення моделі бачить кожен, у кого є ACL. Якщо потрібен multi-company чи розмежування — ir.rule на основі компанії.
  • compute важка для БД. Метод робить агрегацію по 100k записів при кожному перегляді списку. Гальмує інтерфейс. Якщо потрібна агрегація — або store=True і триггери, або окрема віртуальна модель з SQL view.
  • Workflow через зовнішній сервіс. Замість state-машини і кнопок — REST-API, який щось «рухає». Працює рівно до першого збою. У Odoo workflow має бути всередині, з відкатами через action_cancel.

Дотичне

  • Документ-модель — як моделі складаються у бізнес-ланцюги
  • Accountingaccount.move як ключовий приклад моделі
  • QWeb — як моделі рендеряться у звіти
  • Cron — фонові процеси на моделях

Де цей модуль зустрічається6