Нотатки з архітектури8 хв читання

6 речей, на які має відповідати кожна специфікація модуля Odoo

Автор: Maryana Zelinska · Співзасновниця OdoMate

Ілюстрація обкладинки: 6 речей, на які має відповідати кожна специфікація модуля Odoo

Якщо ви колись бралися за «швидку» доробку в Odoo й дивилися, як вона перетворюється на три тижні переписки з клієнтом, проблема, найпевніше, була не в коді. Вона була в специфікації.

Здебільшого переробки кастомних модулів беруться не з поганого Python. Вони беруться із запиту, що звучав зрозуміло на зустрічі, але виявився таким, у якому бракує чогось, про що ніхто не подумав спитати: що станеться, якщо погоджувач у відпустці? У якому статусі перебуває запис, поки чекає? Кого повідомляють, коли його відхилено? Поки ці запитання виринуть, вони виринуть уже як запит на зміну — коли модуль наполовину зроблено.

Коротко: надійна специфікація модуля Odoo відповідає на шість речей ще до того, як хтось відкриє IDE — тригер, дійові особи, дані, машина станів, сповіщення й крайові випадки. Далі в цій статті ми розберемо кожну з них, а потім перепишемо реальний однорядковий запит, використавши всі шість.

Одне зауваження про сферу застосування перед фреймворком: він побудований для модулів типу «робочий процес і погодження» — тих, де є дійові особи, стани й сповіщення. Модулю звітності потрібні джерело даних, фільтри й макет, а не машина станів. Інтеграції потрібні ендпойнти, автентифікація й напрямок синхронізації, а не дійові особи. Якщо ви специфікуєте саме таке, сприймайте цей матеріал як частковий збіг і шукайте приклад, що має форму робочого процесу, деінде.

І ще одна перевірка перед фреймворком: переконайтеся, що модуль тут узагалі потрібен — у статті як можна доопрацювати Odoo під себе розібрано всі п'ять варіантів, починаючи з налаштування.

Шість речей, на які має відповідати кожна специфікація модуля Odoo

1. Тригер — Яка дія чи подія запускає робочий процес? Натискання кнопки, запланована задача, досягнення полем певного значення, вхідний лист? «Запускається, коли хтось натискає submit» і «запускається, коли замовлення на купівлю перевищує $5 000» — це різні модулі.

2. Дійові особи — Хто що робить? Не просто «користувач» — яка саме роль: ініціатор, погоджувач, адміністратор, зовнішній постачальник через портальний доступ? Що кожен із них може бачити й робити такого, чого не можуть інші? (Мовою Odoo саме тут права доступу — ir.model.access плюс record rules — перетворюються на пункт специфікації, а не просто ярлик ролі. «Ініціатор не може погодити власний PO» — це record rule, і його варто прописати явно, а не припускати, що він сам випливе з назв ролей.)

3. Дані — Які поля це насправді потребує, на якій моделі, з якими обмеженнями? Обовʼязкова дата, необовʼязкова примітка, обчислюваний підсумок, many2one на наявний запис? Саме тут «просто додайте прапорець погодження» непомітно перетворюється на шість полів і повʼязану модель.

4. Машина станів — У яких статусах може перебувати запис і які переходи між ними реально дозволені? Draft → Submitted → Approved — це легко. Чи може Approved повернутися в Draft? Чи можуть двоє людей погодити той самий запис? Що станеться, коли хтось скасує процес на півдорозі? Це зазвичай найменш специфікована частина будь-якого запиту.

5. Сповіщення — Кого повідомляють, про що й коли? На поданні, на погодженні, на відхиленні, на спливанні дедлайну? Email, внутрішній chatter Odoo, обидва? Тиша тут означає лише те, що хтось дізнається на три дні пізніше, особисто й роздратовано.

6. Крайові випадки — Щонайменше три названі сценарії, де щасливий шлях ламається. Не «коректно обробляти помилки», а конкретні: що, якщо погоджувач — це той самий ініціатор? Що, якщо запис відредагували після подання, але до погодження? Що, якщо сума змінилася?

Специфікація, що відповідає на всі шість, не обовʼязково довша за однорядковий запит, з якого вона почалася. Вона просто точна замість розмитої — і саме ця точність прибирає значну частину роботи з реалізації, якої можна було уникнути, бо на запитання відповідають один раз, письмово, а не по одному й посеред розробки.

До і після: реальний однорядковий запит

Ось запит, який майже кожен партнер Odoo чи внутрішній бізнес-аналітик отримував у тій чи іншій формі:

Нам потрібні погодження для замовлень на купівлю.

Це завершене речення й незавершена специфікація. Варто одразу сказати: Odoo вже «з коробки» має базове двоетапне погодження PO (Purchase → Configuration → double validation, з прив’язкою до порогу суми), а в Enterprise поверх цього є ще й загальний застосунок Approvals. Цей приклад припускає, що ви вже вперлися в межі того, що вони покривають — погоджувачі по відділах, ескалація, відкат замовлення після редагування вже погодженого — і вам справді потрібен кастомний процес, а не галочка в налаштуваннях. Ось той самий запит, пропущений через 6 запитань.


Тригер

Замовлення на купівлю переходить з Draft у «Waiting Approval», коли ініціатор натискає Submit for Approval. Замовлення нижче за налаштовуваний поріг (за замовчуванням: $1 000) пропускають погодження й підтверджуються автоматично.

Дійові особи

  • Requester (ініціатор) — створює й подає PO. Не може погодити власний PO, незалежно від ролі (забезпечено як record rule, а не залишено на розсуд домовленостей).
  • Approver (погоджувач) — користувач із групою безпеки «PO Approver», призначений або за фіксованим правилом (менеджер відділу), або за налаштовуваним правилом порогу (PO понад $10 000 потребує другого, старшого погоджувача).
  • Finance admin (фінансовий адміністратор) — може перепризначити погоджувача, якщо початковий недоступний; бачить усі очікувані погодження по всіх відділах.

Дані

  • approval_state (selection: draft / waiting_approval / approved / rejected / confirmed) — накладається поруч із рідним станом PO, а не замінює його; тут винесено окремо, щоб логіку погодження було легше простежити. У продакшн-збірці це радше згорнули б у наявне поле стану або керували б через computed stage, щоб два стани не розʼїжджалися.
  • approver_id (many2one, res.users, з доменним обмеженням на групу PO Approver)
  • approval_threshold (налаштування конфігурації, на компанію)
  • rejection_reason (text, обовʼязкове, коли стан → rejected)
  • approval_date / approved_by (для аудиту)

Машина станів

Draft → Waiting Approval → (Approved → Confirmed) або (Rejected → назад у Draft, редаговане). Cancelled досяжний напряму з Draft або Waiting Approval — але не з Confirmed, бо відкат повністю опрацьованого PO потребує стандартного reversal-процесу Odoo, а не цих воріт погодження. PO, відредагований після Waiting Approval, автоматично повертається в Draft і потребує повторного подання — він не може лишатися «approved» проти зміненого замовлення.

Сповіщення

  • Approver: сповіщається (chatter + email) тієї ж миті, коли PO входить у Waiting Approval.
  • Requester: сповіщається про погодження чи відхилення, з причиною в разі відхилення.
  • Finance admin: сповіщається, якщо PO лежить у Waiting Approval понад 3 робочі дні (ескалація).

Крайові випадки

  • Погоджувача деактивовано або він залишає компанію посеред погодження → Finance admin отримує автоматичну пропозицію перепризначення.
  • Суму PO відредаговано після подання → замовлення повертається в Draft (див. машину станів вище); запобігає «погодь зараз, роздми потім».
  • Для того самого PO існують два кваліфіковані погоджувачі → перемагає перша дія; другий бачить «вже опрацьовано» замість можливості погодити вдруге.
  • Мультивалютний PO, де поріг задано у валюті компанії → конвертується за курсом PO на момент подання, а не на момент погодження.

Зверніть увагу, що змінилося. Однорядковий запит і переписана версія описують ту саму бізнес-потребу — «погодження для замовлень на купівлю» — але лише одну з них можна реально оцінити, зібрати й протестувати без трьох раундів «стоп, а що станеться, якщо…». Розробник, який читає версію з шести частин, може почати одразу: поля, стани й правила сповіщень уже вирішено. Розробник, який читає однорядковий запит, змушений або вгадувати, або повертатися й питати — і кожне таке вгадування є місцем, звідки модуль може повернутися на переробку.

Чого це не виправляє

Точна специфікація прибирає уникну переробку — ту, що спричинена неоднозначністю, яку можна було розвʼязати на папері. Вона не прибирає всю переробку. Деякі крайові випадки зʼявляються лише тоді, коли модуль торкаються реальні користувачі (робочий процес, що на папері виглядає завершеним, усе одно може здивувати вас на другому тижні реального використання). І написання доброї специфікації все одно потребує когось, хто достатньо знає бізнес-процес, щоб правильно назвати дійових осіб, пороги й крайові випадки — структура не вигадує це знання, вона лише дає йому куди подітися до початку розробки, а не під час неї.

FAQ

Що має містити специфікація модуля Odoo? Щонайменше шість речей: що запускає робочий процес, які дійові особи задіяні й що кожна може робити, які поля даних потрібні, через які стани може проходити запис, кого й коли сповіщають, і щонайменше три названі крайові випадки, де звичайний перебіг ламається.

Чому кастомні модулі Odoo потребують стільки переробки? Зазвичай не через помилки в коді — через специфікації, що звучать завершено на зустрічі, але лишають поза увагою крайові випадки, правила сповіщень чи переходи станів, які виринають лише тоді, коли модуль уже наполовину зроблено.

Чи застосовний цей фреймворк до кожного типу модулів Odoo? Ні. Він побудований для модулів типу «робочий процес і погодження». Звітам, інтеграціям і суто UI-змінам потрібна власна форма специфікації — звіту потрібні джерело даних і фільтри, а не машина станів; інтеграції потрібні ендпойнти й напрямок синхронізації, а не дійові особи.

Чи достатньо вбудованого погодження купівель в Odoo, чи потрібен кастомний модуль? Рідне двоетапне погодження Odoo з налаштовуваним порогом суми покриває базові випадки. Кастомний модуль виправдовує себе тоді, коли вам потрібне те, чого рідний Odoo не робить «з коробки» — погоджувачі по відділах, ескалація чи повернення в Draft після редагування вже погодженого.

Який найшвидший спосіб перевірити, чи готова специфікація до передачі? Пропустіть її через Шаблон специфікації модуля Odoo + чекліст готовності до ШІ нижче — ті самі шість прогалин передбачають переробку, незалежно від того, передаєте ви специфікацію розробнику чи генератору на основі специфікації.

Як це повʼязано з OdoMate

Ми побудували spec-асистента OdoMate саме навколо цієї структури. Коли ви описуєте бізнес-потребу мовою, якою працюєте — англійською, українською, німецькою чи будь-якою іншою — він ставить уточнювальні запитання, засновані на цих шести фундаментах — тригер, дійові особи, дані, машина станів, сповіщення, крайові випадки — перш ніж щось генерувати, замість того щоб лишати їх на те, аби розробник виявив їх посеред розробки.

Як це виглядає на реальному прогоні, коли вимога просить те, що Odoo вже вміє: чому генератор не побудував функцію, яку ми просили.

Хочете спершу пропрацювати це на власній специфікації? Візьміть заповнюваний Шаблон специфікації модуля Odoo + чекліст готовності до ШІ — ті самі шість розділів, готові до заповнення.

Цікаво, як це працює на реальній специфікації? Подайте запит на ранній доступ до бети.

Ми розглядаємо запити на постійній основі й підключаємо невеликими когортами.

Про автора

Maryana Zelinska

Співзасновниця OdoMate

Maryana Zelinska — співзасновниця OdoMate. Вісімнадцять років в IT у продуктовій розробці та підтримці — керівниця продуктової команди, скрам-майстриня, сервіс-менеджерка — останні три роки навколо кастомізації Odoo. Пише про якість специфікацій, прототипування та про те, що насправді видає AI-генерація, коли перевіряєш результат.

  • business analysis
  • requirements engineering
  • ERP delivery
  • specification quality

Обговоріть цю статтю зі своїм AI

Відкриває новий чат із доданою статтею. Асистент спершу запитає про вашу конфігурацію Odoo, а вже потім радитиме.

Кнопки відкривають асистента в новій вкладці з уже заповненим запитом. Із цієї сторінки нічого не надсилається — ви натискаєте «надіслати» там, і жодних персональних даних ми не передаємо.