Два модулі для Odoo 19 автоматизують один і той самий процес продажу — три перемикачі на рівні складу за тією самою кнопкою Confirm, і функції в обох однакові. Різниця проявляється лише тоді, коли якийсь крок дає збій, і про це повідомляє тільки один із модулів.
Головне коротко:
- Функції однакові: обидва модулі додають ті самі три перемикачі на рівні складу за тією самою кнопкою Confirm.
- Справжня різниця — в обробці збоїв: згенерований модуль коректно відкочує зміни, називає крок, який зламався, і записує це там, де відкат не зітре запис — у готового модуля такого немає взагалі.
- «Нічого виставляти» — це нормальна конфігурація, а не помилка: згенерований модуль так це й трактує, готовий блокує підтвердження замовлення.
- У готового модуля — десять релізів Odoo практичного досвіду і вп'ятеро менше коду; згенерований натомість постачається з 12 тестами, демоданими та описаним розділом обмежень.
- Кожна відмінність походить із двох абзаців у письмовій специфікації, а не з якості коду.
Один модуль — sale_order_automation від Craftsync Technologies: понад 8 000 завантажень, представлений на Apps Store для кожного релізу Odoo від 10-го до 19-го. Другий, sale_warehouse_auto_fulfillment, ми згенерували з письмової специфікації за допомогою OdoMate — нашого генератора модулів Odoo на основі ШІ. Жоден розробник не писав його моделі, тести чи обробку помилок — і саме він у центрі цього допису.
Цього разу список функцій ідентичний, тож усе залежить від того, що робить кожен модуль, коли крок дає збій. Кожна відмінність тут записана в специфікації ще до того, як з'явився перший рядок коду.
Обсяг і докази: порівнюємо OdoMate sale_warehouse_auto_fulfillment v19.0.1.0.0 із Craftsync sale_order_automation v19.0.1.1, станом на 25 серпня 2026 року. Кожне твердження про код Craftsync походить із прочитання реального пакета v19.0.1.1, завантаженого з Apps Store, — це не живий тест один проти одного. OdoMate — наш власний продукт.
Чому в Odoo доводиться робити чотири кліки, щоб відвантажити й виставити рахунок за замовлення?
Продавець підтверджує замовлення. Odoo зупиняється. Відвантаження висить у статусі «Готово», а рахунка ще не існує.
Хтось відкриває переміщення й тисне Validate, повертається до замовлення й тисне Create Invoice, відкриває чернетку й тисне Confirm — три кліки й дві зміни екрана, на кожному замовленні, завжди. Для складу, який відвантажує все, що продає, з залишків, яким довіряє, це просто церемонія.
Обидва модулі вирішують цю проблему однаково. Три перемикачі на рівні складу — і та сама кнопка Confirm, якою ваша команда й так користується, робить решту. Жодного нового меню, нового екрана, нового статусу.
Ми обрали цю задачу навмисно: це складніший тест, ніж порівняння зі знижками, де згенерований модуль випередив готовий за чотирма пунктами зі списку функцій. Тут переваги за функціями просто немає — списки ідентичні, і саме тому порівняння стає по-справжньому цікавим.
Може, Odoo 19 вже сама все це вміє?
Варто знати перед тим, як щось встановлювати, бо для частини читачів відповідь — «не встановлюйте жодного».
Odoo 19 справді автоматично виставляє рахунки — створює рахунок, проводить його і надсилає клієнту, — але тільки коли пройшла онлайн-оплата. Це налаштування Invoice automatically on payment в налаштуваннях eCommerce (код відкритий). Для замовлення, яке продавець підтверджує вручну, рідного шляху немає — і товари, які виставляються за фактично відвантаженою кількістю, теж прямо виключені з цього налаштування, незалежно від оплати; це знадобиться далі, коли мова піде про випадок «нічого виставляти».
Автоматичного підтвердження відвантаження в Odoo немає взагалі. Майстер миттєвого переміщення, який раніше це покривав, існував в Odoo 16.0 і зник із релізом 17.0 — у директорії stock/wizard/ Odoo 19 його теж немає.
Тож прогалина, яку закривають обидва модулі, реальна. Якщо ваші замовлення надходять через eCommerce і оплачуються онлайн, Odoo вже про це подбала — і навіть надсилає рахунок клієнту, чого не робить жоден із модулів. Перевірте це налаштування першим ділом.
Список функцій ідентичний
Функції для покупця — те, на що дивиться покупець, що показує сторінка в магазині, що демонструє демо:
| Odoo 19 «з коробки» | Craftsync, 8 000+ завантажень | Згенеровано OdoMate | |
|---|---|---|---|
| Перемикач на складі: підтверджувати відвантаження при Confirm | ⬜ | ✅ | ✅ |
| Перемикач на складі: створювати рахунок клієнту | ⚠️ лише при оплаті | ✅ | ✅ |
| Перемикач на складі: проводити рахунок | ⚠️ лише при оплаті | ✅ | ✅ |
| Працює через наявну кнопку Confirm, без нового екрана | ➖ | ✅ | ✅ |
| Надсилає рахунок клієнту після проведення | ✅ | ⬜ | ⬜ |
✅ так · ⚠️ лише за умови · ⬜ ні · ➖ не застосовується
За кожним рядком тут обидва модулі однакові. Це і є нічия.
Обробка збоїв і докази — та сама функція, яка або працює погано, або працює добре, або не постачається взагалі:
| Craftsync | Згенеровано OdoMate | |
|---|---|---|
| Будь-яка обробка помилок у ланцюжку | ⬜ | ✅ |
| Повідомлення про збій із назвою кроку, що зламався | ⬜ | ✅ |
| Запис про збій там, де відкат його не зітре | ⬜ | ✅ |
| «Нічого виставляти» — пропускається, а не блокує | ⬜ | ✅ |
| Явне вимкнення часткового відвантаження (backorder) | ⬜ | ✅ |
| Автоматичні тести | ⬜ | 12 |
| Демодані, які можна прогорнути | ⬜ | 6 замовлень |
| README з описаним розділом обмежень | ⬜ | ✅ |
Тут нема жодної функції, яку сторінка в магазині рекламувала б. Це те, що відбувається, коли шлях без проблем закінчується.
Що вказувала специфікація, чого не покаже жоден список функцій?
Специфікація, з якої згенерували цей модуль, постачається разом із ним як SPEC.md — можна прочитати вхід поруч із виходом. Більшість там очікувана: три поля, значення за замовчуванням, де вони стоять у формі.
А там є, серед іншого, ось такі два пункти.
Перший — про обробку справжніх помилок (не плутати зі звичайними бізнес-ситуаціями): якщо на етапі підтвердження відвантаження, створення рахунку чи його проведення станеться реальна помилка, уся автоматизація — включно зі зміною статусу замовлення на «Підтверджено» — відкочується одним записом у базі даних. Причина помилки записується окремо, через незалежний канал, щоб пережити цей відкат, а продавець бачить не сирий системний збій, а зрозуміле повідомлення з назвою етапу й причиною.
Другий — про випадок, коли виставляти нічого: якщо товар оплачується за фактично відвантаженою кількістю, а автоматичне відвантаження вимкнене, і на момент підтвердження виставляти ще нічого, це не вважається помилкою. Автоматизація тихо пропускає цей крок, лишає нотатку в чаті замовлення — і підтвердження проходить як зазвичай.
Жоден із цих двох пунктів не описує окрему функцію — ніхто не пише «сам обробляє власні помилки» на сторінці в магазині, бо це й так мається на увазі. Але саме в них — уся різниця між двома модулями, і генератор реалізував обидва.
Ось що прийшло у відповідь на перший із них — повідомлення, за яким продавець може одразу щось зробити:
Автоматичне виконання не вдалося для S00042 на складі Main Warehouse.
Етап: автоматичне проведення рахунку
Причина: у клієнта немає рахунку дебіторської заборгованості.
Нічого не збережено: замовлення залишається комерційною пропозицією,
відвантаження не підтверджено, рахунок не створено. Виправте причину
вище й підтвердьте замовлення знову, або вимкніть автоматизацію на
складі, щоб підтвердити його вручну.Тут важливі три речі: названо, який саме з трьох кроків зламався; дано причину замість технічного повідомлення про помилку; і сказано, що саме збереглося, а що ні — «чи спрацювало це наполовину?» це перше запитання, яке виникає в будь-кого, і найважче, на яке можна відповісти, дивлячись лише на технічний лог.
Цей запис іде через окремий курсор бази даних, тож переживає відкат — без нього невдала автоматична спроба виставити рахунок не залишила б жодного сліду, і замовлення просто виглядало б як комерційна пропозиція, яку ніхто не підтверджував.
У чому насправді розходяться два модулі?
Обробка помилок. sale_order_automation не має її взагалі — ні try, ні except, ні raise на всіх його 44 рядках, а єдиний імпорт, який натякає на неї (from odoo import ... exceptions), ніде не використовується. Коли крок ламається, продавець бачить те, що підняв сам Odoo.
Часткові відвантаження (backorders). Згенерований модуль передає skip_backorder=True під час підтвердження, тож повне відвантаження одразу переходить у статус Done. У модуля Craftsync цього параметра немає, тож Odoo може повернути майстер часткового відвантаження — діалог із питанням, відповісти на яке нікому, чиє значення модуль просто відкидає, а потім усе одно примусово завершує переміщення.
Підтвердження кількох замовлень одночасно. Їхній цикл читає self.picking_ids замість order.picking_ids всередині циклу, який і так уже перебирає замовлення — виберіть десять комерційних пропозицій і натисніть Confirm, і переміщення кожного замовлення обробляться по разу на кожне замовлення в пакеті. Згенерований модуль обробляє кожне замовлення один раз, хоч і огортає весь вибір одним savepoint, тож одна невдача відкочує всі десять. Це реальний компроміс, а не перемога — про нього нижче, серед обмежень.
Що входить у комплект?
Згенерований модуль постачається з 12 автоматичними тестами, які покривають значення за замовчуванням, кожен перемикач окремо, відвантаження в мінус по залишках, тихий пропуск, обидва шляхи відкату та ізоляцію між складами — усе це можна прочитати ще до встановлення. У модуля Craftsync немає директорії tests/.
Він також постачається із шістьма демонстраційними комерційними пропозиціями, на яких можна натиснути Confirm і побачити конкретну поведінку, і README з розділом Known limitations, який серед іншого каже, що рахунки проводяться, але ніколи не надсилаються, і що історія автоматизації живе лише в ir.logging.
Це не про якість коду. Це про те, чи можна оцінити модуль до того, як він торкнеться вашої бази даних, і перевіряти його заново після кожного точкового релізу Odoo.
Що можна перевірити самостійно
Ось твердження, у яке найлегше не повірити: це саме той модуль, який згенерувала система, а не згенерований модуль, який потім хтось причесав.
Репозиторій публічний, тож нічого не доведеться приймати на слово. Модуль потрапив у коміт 3b7066e одразу після генерації. Код, який виконує реальну роботу, — models/ і tests/ — відтоді не змінився.1 Те, що додалося зверху відтоді, — публікаційна рутина: довший опис для магазину, банер і скріншоти, а від 17 серпня — ще й видалення артефакту генератора, якому не місце в публічному пакеті.
Скріншоти на сторінці — з живого демо-розгортання, яке платформа підняла під час генерації, а не зі стендового середовища, зібраного нами згодом.
Що є у модуля Craftsync такого, чого немає в нашого?
Десять релізів Odoo практичного досвіду. Їхній модуль представлений для кожної серії від Odoo 10 до 19, і його завантажили понад 8 000 разів. Завантаження — це не розгортання, але експозиція такого масштабу виявляє проблеми, яких не передбачить жоден набір тестів — наш модуль це перший реліз із жменькою завантажень і взагалі без практичної історії. Якщо ваша інтуїція каже, що це важить більше за все перелічене вище, — це обґрунтована позиція, і ми не будемо вас переконувати в іншому.
У п'ять разів менший обсяг. 44 рядки Python у models/ проти наших 224 — та сама директорія, той самий підрахунок для обох.2 Менше коду — менше перевіряти, і для односкладського магазину, який підтверджує замовлення по одному зі звичайними складованими товарами, ці зайві 180 рядків купують обробку крайових випадків, до яких цей магазин, можливо, ніколи не дійде.
Ми також знайшли одну річ, яка не є компромісом, а просто звичайною ціною підтримки модуля живим упродовж десяти релізів: він досі передає default_immediate_transfer=True — контекстний ключ для майстра, якого Odoo прибрала у 17.0. У 19-й версії він не робить нічого. Модуль, згенерований під сьогоднішню Odoo, починає з того, що платформа робить зараз — та сама причина, з якої він колись відмовився дублювати звіт, що в Odoo вже є — перевага, яку він отримує безкоштовно і за яку не заслуговує на визнання.
Чого це порівняння не доводить?
- Жодного прогону тестів, жодного очного протистояння. 12 тестів постачаються й читабельні, але їх ніхто не запускав для цього порівняння, і жоден із модулів не тестувався один проти одного на живій системі — усі твердження вище походять із читання коду обох модулів і коду Odoo 19 станом на 25 серпня 2026, версії v19.0.1.0.0 проти v19.0.1.1.
- Пакетне підтвердження — усе або нічого. Один savepoint огортає весь вибір — підтвердьте десять замовлень, і якщо десяте зламається, відкотяться всі десять. Для одних команд це правильна поведінка, для інших — дратівлива.
- Згенерований код усе одно потребує перевірки людиною перед продакшеном. Обидва модулі за задумом можуть завести залишки в мінус. Це рішення для рецензента, а не те, що можна успадкувати без перевірки.
- Один модуль, одна задача. Це невеликий, чітко окреслений процес продажу. Він нічого не каже ні про важку бухгалтерську логіку, ні про інтеграцію із зовнішньою системою.
Що ми з цього насправді виносимо
Попереднє порівняння ми виграли за функціями. Це — ні, бо списки функцій виявилися однаковими ще до старту, а це чесніший тест, бо він прибирає можливість перемогти, просто попросивши більше.
Залишався лише шлях обробки збою, і цей шлях був у специфікації: savepoint, повідомлення з назвою етапу, запис у лог, який переживає відкат, рішення, що «нічого виставляти» — це нормальний результат, а не помилка. Комусь довелося подумати, що має статися в поганий день, і записати це звичайними реченнями — усе інше вже було генерацією.
Ось що варто винести з цього. Генератор не переграв постачальника інженерно. Він побудував те, що сказала специфікація, включно з абзацами про збої, яких у більшості специфікацій просто немає.
Спробуйте на своїй задачі
Прочитайте специфікацію і модуль, який вона породила, поруч одне з одним, або подивіться, як це вписується у те, що ми з'ясували, генеруючи модулі Odoo зі ШІ протягом 2026 року. А тоді принесіть власну вимогу — бажано таку, для якої ви вже знаєте, що має статися, якщо щось піде не так. Огляньте модуль, а тоді подайте заявку на ранній бета-доступ — ми розглядаємо заявки послідовно й підключаємо користувачів невеликими групами.
FAQ
Як зробити так, щоб Odoo підтверджувала відвантаження і виставляла рахунок одразу після підтвердження замовлення?
У Odoo 19 немає рідного налаштування для цього на замовленнях, які підтверджує людина. Рідне автоматичне виставлення рахунків існує, але спрацьовує лише після онлайн-оплати, а рідного автоматичного підтвердження відвантаження немає взагалі — майстер для цього прибрали з релізом 17.0. Варіанти включають написану вручну серверну дію через Automation Rules, сторонній модуль автоматизації workflow, або модуль із перемикачами на рівні складу саме для цього — два таких: sale_order_automation від Craftsync Technologies і sale_warehouse_auto_fulfillment від OdoMate, обидва порівняні в цьому дописі.
Чи може модуль, згенерований зі специфікації, зрівнятися з готовим модулем від усталеного постачальника? У цій задачі списки функцій виявилися однаковими. Згенерований модуль іде далі в обробці помилок, у випадку «нічого виставляти», у вимкненні часткових відвантажень і в тому, що постачається разом із кодом. У готового модуля — понад 8 000 завантажень і десять релізів Odoo практичного досвіду, яких у згенерованого немає.
Чи редагували згенерований модуль вручну перед публікацією?
Ні. Директорії models/ і tests/ побайтово ідентичні між комітом, який видав генератор, і гілкою, опублікованою на Apps Store. Змінився лише опис у маніфесті, плюс банер, скріншоти й файл специфікації, додані для публікації.
Що відбувається, якщо один з автоматичних кроків дає збій?
Увесь запуск проходить в одному savepoint бази даних: замовлення повертається в статус комерційної пропозиції, нічого не підтверджується і не виставляється, а продавець отримує повідомлення з назвою кроку, який зламався, і причиною. Про збій також пишеться запис у ir.logging через окрему транзакцію, тож він переживає відкат.
Чи відвантажить будь-який із модулів товар, якого на складі немає? Так, обидва. Жоден не перевіряє наявність перед підтвердженням відвантаження, тож автоматичне відвантаження може завести залишки в мінус. Згенерований модуль пише про це у своїй специфікації, README і в тесті. Вмикайте це лише на складах, чиїм залишкам ви довіряєте.
Footnotes
-
git diff 3b7066e origin/19.0 -- sale_warehouse_auto_fulfillment/models sale_warehouse_auto_fulfillment/testsна свіжому клоні репозиторію не повертає нічого — кожен рядок логіки і кожен тест побайтово збігаються з тим, що видав генератор. ↩ -
Обидва числа — рядки Python лише в директорії
models/кожного модуля, підрахованіwc -l, і нічого більше — це не та сама метрика, яку показує сторінка Apps Store для свого калькулятора вартості супроводу: там зараз 173 і 53 для двох модулів відповідно. ↩
