9 серпня Odoo опублікувала в блозі анонс: нативний конектор TikTok Shop і Tokopedia для Enterprise 19.0+. Переклав, звірив із технічною документацією 19.0 — і з'ясував, що з двох маркетплейсів у заголовку задокументований лише один.
Що каже блог
Ключова цитата з оригіналу — умова доступу:
«No third-party apps required. This feature is available to users with an active Odoo Enterprise subscription for version 19.0 or higher.»
Тобто це не community-конектор і не окремий платний додаток з Apps Store — фіча вшита в Enterprise-підписку і працює на всіх трьох варіантах хостингу: Odoo Online, Odoo.sh, on-premise. У блозі перелічено чотири напрямки: синхронізація каталогу, замовлень, залишків і доставки.
Розглянемо, що насправді описано в setup.html і manage.html
Технічна документація 19.0 підтверджує написане в блозі — але тільки для TikTok Shop. Підключення йде через TikTok Shop Partner Center, категорія «App developers (ISV)»:
Redirect URL:
https://<database url>.odoo.com/tiktok/return_from_authorization
Обов'язкові API-сервіси (Partner Center → App & Service):
Finance Information
Fulfillment Basic
Logistics Basic
Order Information
Product Basic
Product Modify
Shop Authorized Information
Global Shop Information
Після авторизації Odoo сама заводить крон-задачі з різним кроком: замовлення й вебхуки — кожні 5 хвилин, етикетки доставки — кожні 15, інвентар — кожні 30. Підтримується лише модель Fulfilled by Merchant (FBM): продавець сам організовує відправку і повертає номер відстеження в TikTok.
Важливо! Синхронізуються тільки замовлення в статусах AWAITING_SHIPMENT і AWAITING_COLLECTION — ті, що реально потребують дії. SHIPPED, CANCEL, UNPAID, COMPLETED в Odoo не тягнуться. І окремо в документації прямим текстом написано: скасування замовлення в Odoo на TikTok Shop не відображається. Синхронізація статусів — одностороння, з майданчика в Odoo.
А де Tokopedia?
Тут блог випереджає документацію. Окремої сторінки на кшталт tokopedia_connector/setup.html в 19.0 немає — у переліку конекторів (toctree сторінки sales.html) значаться тільки Amazon, Lazada, Shopee й TikTok Shop. Офіційного вбудованого конектора для Tokopedia в Odoo немає, і задокументований він теж ніде не був. Але це не означає, що на ринку порожньо: на Apps Store знайшлося кілька сторонніх рішень — izi_tokopedia (14.0-17.0), старіший yudha_tokopedia_connector (12.0-14.0) і, що важливіше, платний tokopedia_store_management (автор ECOSIRE, €430.43) саме під версію 19.0. Тому точніше формулювання таке: офіційного конектора для Tokopedia в 19.0 немає, документації на нього теж немає, а те, чого бракує в Enterprise-підписці, закривають сторонні розробники.
Український зріз: та сама задача, інша інфраструктура
У нас немає TikTok Shop чи Tokopedia, зате є та сама задача на інших майданчиках — модулі kw_marketplace_rozetka_api, kw_marketplace_promua_api, kw_marketplace_kasta_hub_api, kw_marketplace_horoshop_api. Архітектура своя: базовий фреймворк kw_marketplace (моделі kw.mp.merchant, kw.mp.offer, kw.mp.stage) і окремий платний модуль на кожен майданчик, а не одна вбудована Enterprise-фіча.
Крон у нас теж інтервальний, тільки без TikTok-івської диференціації 5/15/30 хвилин на різні сутності — усе на п'яти хвилинах:
<record id="kw_marketplace_kw_mp_merchant_load_orders" model="ir.cron">
<field name="name">Marketplace: load_orders</field>
<field name="model_id" ref="model_kw_mp_merchant"/>
<field name="state">code</field>
<field name="code">model.cron_load_orders()</field>
<field name='interval_number'>5</field>
<field name='interval_type'>minutes</field>
</record>
Залишки ми не тягнемо батчем раз на пів години — реагуємо на подію одразу. Запис у stock.quant кладе товар у чергу на перерахунок офера, а той самий п'ятихвилинний крон її розбирає:
class StockQuant(models.Model):
_inherit = 'stock.quant'
def write(self, vals):
res = super().write(vals)
self.env['kw.mp.offer'].action_reset_by_product_ids(
self.sudo().mapped('product_id.id'))
return res
Тепер про різницю, яка справді цінна для проєктування такої інтеграції. Неправильно закладати в архітектуру універсальне правило «статус завжди летить в обидва боки» — це неправда навіть для одного вендора. TikTok Shop, за офіційною документацією, синхронізує статуси лише в один бік: скасування в Odoo на майданчику не з'явиться. Правильно перевіряти це окремо для кожного маркетплейсу: у Rozetka, наприклад, зворотний зв'язок є — зміна стадії замовлення в Odoo реально йде назад через PUT /orders/{id}/:
def action_kw_mp_stage_change_rozetka(self):
data = {'status': int(self.kw_mp_new_stage_id.ref)}
res = self.kw_mp_merchant_id.request(
method='PUT', url=f'/orders/{self.kw_mp_ref}/', data=data,
silent=False, )
if res:
self.kw_mp_update_from_marketplace(
merchant=self.kw_mp_merchant_id, res=res.get('content'), )
return res
Модель доставки теж не переноситься один в один — і в самому Rozetka таких моделей насправді дві. TikTok Shop працює по FBM: продавець сам генерує ярлик і повертає tracking number. Прямий аналог у Rozetka — власна кур'єрська мережа Rozetka Delivery (rz-delivery-octopus.rozetka.ua): окрема модель тримає відправника й отримувача з типами door-door/door-dept/dept-door/dept-dept, і продавець сам через наш модуль замовляє забір і повертає track. Але коли покупець на Rozetka обирає доставку Новою поштою, у гру вступає інший ланцюжок модулів — kw_marketplace_rozetka_api_np → kw_marketplace_np → kw_novaposhta_delivery. Розпізнавання йде за delivery_service_id з відповіді маркетплейсу:
# kw_marketplace_np — загальний диспетчер для будь-якого маркетплейсу
def is_np_delivery(self, res):
self.ensure_one()
fname = f'is_np_delivery_{self.code}'
return getattr(self, fname)(res) if hasattr(self, fname) else False
# kw_marketplace_rozetka_api_np — конкретна перевірка для Rozetka
def is_np_delivery_rozetka(self, res):
return res.get('delivery') and \
res.get('delivery').get('delivery_service_id') in (5, 43660)
Далі модуль-адаптер підбирає відділення чи адресу через kw.np.warehouse/kw.np.city і передає їх у kw_novaposhta_delivery, який уже й генерує накладну. Два перевізники в одному маркетплейсі — і два різні шматки коду під капотом. А от аналога TikTok-івського FBS — коли платформа сама зберігає і комплектує товар — у Rozetka чи Prom немає: склад завжди на боці продавця.
Ну ось і вся різниця між «нативний Enterprise-конектор для азійського ринку» і «набір окремих модулів для українського»: задача одна — товари, замовлення, залишки, доставка, — а хто відповідає за останню милю і чи їде статус в обидва боки, щоразу треба перевіряти окремо.
Переклад і адаптація статті https://www.odoo.com/blog/business-hacks-1/odoo-tiktok-shop-and-tokopedia-integration-2380. Код і поведінку перевірено на Odoo 19.