Kitworks Event Suite — повний гід з налаштування

Від чистої бази до проданого квитка та розрахунку з гідом. На прикладі екскурсійної компанії «Цікавий Київ» (Odoo 19).

Odoo 19.0 34 модулі Каталог → події Квитки & знижки Бюджет-матриця Розрахунки з гідом REST API

Цей гід проходить весь шлях з нуля на чистій базі event19 з demo-даними. Усі скриншоти — реальні екрани локального стека Odoo 19.

0. Що це за система і кому вона потрібна

Kitworks Event Suite — це надбудова над модулем Events ядра Odoo, заточена під компанії, що регулярно проводять платні заходи з виїзним персоналом: екскурсійні бюро, тури, майстер-класи, виїзні лекції. Ключові відмінності від «голого» Odoo Events:

Каталог замість ручного створення
Один шаблон екскурсії → з нього штампуються десятки конкретних подій (регулярних або індивідуальних) однією дією.
Квитки зі знижками-пресетами
Повний / пільговий / дитячий квиток з автоматичним розрахунком ціни від базової, з вікнами продажу.
Бюджет-матриця події
Планований / підтверджений / оплачений дохід і витрати в одній таблиці, що перераховується автоматично.
Гід як підрядник
Ставка гіда (за годину / за подію / за групу / % прибутку), гаманець гіда та взаєморозрахунок після турів.
Види витрат
Транспорт, харчування, вхідні квитки — з формулою «фікс + на людину + мінімалка» і одержувачем оплати.
REST API
Створення подій, реєстрацій та продаж квитків із зовнішнього сайту (WordPress/WooCommerce).
Логіка під капотом. Уся система обертається навколо ланцюга:
Каталог (шаблон) Подія Квитки Реєстрації Продаж (SO) Бюджет Розрахунок з гідом
Налаштування (розділи 1–5) готують довідники цього ланцюга. Робота (розділи 6–10) — це сам ланцюг.

1. Які модулі встановити для якого функціоналу

Suite складається з ~34 опційних модулів kw_event_*. Встановлюйте не «усе підряд», а під потрібний функціонал — залежності підтягнуться автоматично. Нижче — групи за призначенням.

1.1 База (встановити завжди)

МодульЩо дає
kw_event_catalogКаталог екскурсій — шаблони подій, місця збору (start places), тривалість, тип.
kw_event_saleКвитки як товари: типи квитків, пресети, знижки, вікна продажу, продаж через Sale Order.
kw_event_type_uiПеремикачі вкладок на типі події (Питання / Спілкування / Мульти-слоти).
kw_event_configЗагальні налаштування suite (меню «Конфігурація»).

1.2 Ціни та квитки

МодульЩо дає
kw_event_catalog_ticket_presetБазова ціна квитка на каталозі + перевизначення ціни/знижки на рівні каталогу (kw.event.catalog.ticket).
kw_event_catalog_priceПрайс-логіка для каталогу.
kw_event_registration_paymentОплата реєстрації, статуси «оплачено», звʼязок з платежами.
kw_event_invoice_preset / kw_invoice_presetПресети рахунків для швидкого виставлення.

1.3 Бюджет та аналітика

МодульЩо дає
kw_event_sale_accountДвигун бюджету події — матриця Планований/Підтверджений/Оплачений; event._kw_recompute_budget.
kw_event_state_analytic_matrix + kw_matrix_widgetВіджет-матриця станів аналітики на вкладці «Бюджет».
kw_event_accountПривʼязка події до аналітичного рахунку, проводки.
kw_purchase_analyticАналітика на закупівлях (витрати події).

1.4 Гіди / виконавці та витрати

МодульЩо дає
kw_event_performerГід/виконавець як партнер; гаманець гіда (каса гіда).
kw_event_performer_feeСтавка гіда: за годину / за подію / за групу / % прибутку.
kw_event_performer_fee_invoiceРахунки підряднику (гіду) за його ставкою.
kw_event_performer_settlementВзаєморозрахунок з гідом: вкладка розрахунків, майстер по кількох турах, кольори списку.
kw_event_expenseВиди витрат: фікс + на людину + мінімалка, групові тарифи, одержувач оплати.
kw_event_catalog_expenseВитрати на рівні каталогу (автододаються в подію).
kw_event_catalog_performerГіди за замовчуванням на каталозі.

1.5 Логістика, формати, додаткове

МодульЩо дає
kw_event_truckage (+ kw_truckage*)Транспорт/логістика: автобуси, водії, тип ТЗ під розмір групи.
kw_event_onlineОнлайн-події (без локації).
kw_event_parentСкладені події: батьківська подія з під-подіями (багатоденний тур).
kw_event_seats_planПланована кількість місць (seats_plan) для бюджету.
kw_event_language / kw_event_catalog_languageМови екскурсій.
kw_event_timezoneЧасовий пояс за замовчуванням на типі події.
kw_event_utmUTM-мітки (звідки прийшов учасник), вкладка «Маркетинг».
kw_event_client_modeРежим «є клієнт» (B2B-захід на замовлення) + прапор «учасники впливають на бюджет».
kw_event_customerКлієнт події (замовник).
kw_event_registration_participant / kw_event_registration_extraДодаткові поля учасника (паспорт, дата народження тощо).
kw_event_attendee_opsМасові операції над учасниками.
kw_event_access / kw_event_catalog_accessПрава доступу до подій і каталогу.
kw_events_apiREST API /kw_api/* (потребує kw_api).
Рекомендований мінімум для екскурсійної компанії: kw_event_catalog, kw_event_sale, kw_event_catalog_ticket_preset, kw_event_sale_account, kw_event_state_analytic_matrix, kw_event_expense, kw_event_catalog_expense, kw_event_performer, kw_event_performer_fee, kw_event_performer_settlement, kw_event_seats_plan, kw_event_type_ui, kw_event_registration_payment. Решта — за потребою (онлайн, транспорт, API, UTM).

2. Які довідники заповнити і в якому порядку

Порядок важливий: кожен наступний довідник посилається на попередній. Не можна зробити каталог без типу події, а тип події без продукту-квитка не дасть продавати.

1Компанія, валюта, журнали

  • Компанія — назва, реквізити, лого («Цікавий Київ»).
  • Валюта — UAH як основна.
  • Журнали обліку: Каса (Cash), Банк (Bank), Продажі, Закупівлі. Для кожного гіда згодом створюється окрема каса-гаманець.

2Податки та продукти-послуги

  • Налаштувати ставки ПДВ / без ПДВ під ваш режим оподаткування.
  • Базові продукти-послуги для витрат (вони створюються автоматично з видів витрат, але можна й вручну).

3Мови екскурсій (kw.event.language)

Українська, англійська тощо. Прапор «Іноземна» відрізняє внутрішні мови від іноземних.

4Місця збору (kw.event.start.place)

Точки старту екскурсій («Майдан Незалежності», «Золоті ворота») з адресою та координатами. Перевикористовуються в каталозі.

5Типи квитків та пресети

  • Типи квитків додаються в окремому довіднику (меню «Типи квитків»). Атрибут товару створювати не треба — системний атрибут «Тип квитка» підвʼязується автоматично до кожного нового запису.
  • Створіть значення: Повний, Пільговий, Дитячий — кожне зі знижкою (kw_price_discount + тип знижки %/грн) та вікнами продажу (днів до події).
  • Зберіть їх у пресет (kw.event.ticket.preset), напр. «Стандартні квитки екскурсії».

6Види витрат (kw.event.expense)

Транспорт, харчування, вхідні квитки — з формулою та одержувачем оплати. Деталі — розділ 3.

7Гіди та їхні ставки

  • Контакт гіда (партнер) з позначкою «Виконавець» (kw_event_is_performer).
  • Каса-гаманець гіда створювати не треба — журнал «Готівка в <ім'я>» створюється автоматично, щойно партнера позначено виконавцем.
  • Ставки у вкладці «Performance fee»: за годину / за подію / за групу / %. Деталі — розділ 4.

8Типи подій (event.type)

«Регулярна екскурсія», «Індивідуальна екскурсія», «Онлайн-лекція» — з усіма перемикачами (пресети квитків, вкладки, бюджет). Деталі — розділ 5.

9Каталог екскурсій (kw.event.catalog)

Фінальний крок налаштування: шаблон конкретної екскурсії, що звʼязує все вище. Деталі — розділ 6.

Коротко про залежності: Мови + Місця збору + Пресети квитків + Види витрат + Гіди → потрібні для Каталогу. Каталог + Тип події → потрібні для Події. Тому послідовність 3→9 строга.

3. Види витрат

Вид витрат (kw.event.expense) — це багаторазова категорія собівартості події: оренда автобуса, обід, вхідні квитки до музею. Кожен вид описує формулу вартості, продукт для обліку і одержувача оплати.

3.1 Поля виду витрат

ПолеПризначення
Назва«Оренда автобуса», «Обід», «Вхідні квитки».
Продукт (product_id)Товар/послуга для рахунка постачальнику (створюється автоматично, якщо немає).
Фіксована вартість (fixed_cost)Базова сума незалежно від кількості людей.
Вартість на людину (person_cost)Додається за кожного учасника.
Мінімальна вартість (minimal_cost)Підлога: підсумок не може бути нижчим.
Одержувач оплати (cash_recipient)performer — гіду · manager — менеджеру події · partner — компанії-постачальнику.
Журнал (journal_id)Журнал оплати (для грошового потоку).
Групові тарифи (group_expense_ids)Різна ціна для діапазонів кількості (1–15, 16–30, 31+).

3.2 Формула вартості

підсумок = fixed_cost + (person_cost × К-сть_учасників) + груповий_тариф + коригування
фінал    = max(підсумок, minimal_cost)
Приклад «Обід». Фікс 20 грн (оренда столу) + 8 грн/особа + мінімалка 20 грн.
  • Група 10 осіб: 20 + 8×10 = 100 грн
  • Група 25 осіб: 20 + 8×25 = 220 грн

3.3 Три суми кожної витрати в події

Коли вид витрат потрапляє в подію (рядок kw.event.expense.line), система рахує три величини — вони ж видно у вкладці «Бюджет»:

СумаВід чого рахуєтьсяДе видно
Планована (planned)За планованою к-стю місць (kw_seats_plan)Колонка «Планований»
Підтверджена / «До сплати» (confirmed)За фактичними реєстраціями (стан open/done)«Підтверджений» + вкладка розрахунків
Оплачена (paid)Сума проведених рахунків постачальника«Оплачений» + розрахунок з гідом
Ручне перевизначення. Поле custom_amount замінює розраховану «Підтверджену» суму. Напр. вид витрат рахує 500 грн, але ви домовилися на 400 — вписуєте 400, і саме 400 піде в бюджет, у рахунок та в розрахунок з гідом.

3.4 Витрати на каталозі

У каталозі (kw.event.catalog.expense) перелічуються види витрат, які автоматично клонуються в кожну подію, створену з цього каталогу. Так ви один раз описуєте собівартість екскурсії, а далі вона зʼявляється в кожному виїзді.

4. Принципи розрахунку ставки гіда

Ставка гіда — це сума, яку компанія платить гіду за проведену екскурсію. Suite підтримує чотири способи розрахунку. Спосіб задається у вкладці «Performance fee» на контакті гіда (kw.event.performance.type.fee), а сума фіксується на події у вкладці «Виконавці» (kw.event.performance).

За годину (per_hour)
ставка × тривалість події.
25 грн/год × 3 год = 75 грн
За подію (per_event)
Фіксована сума за виїзд, незалежно від людей і годин.
напр. 100 грн / екскурсію
За групу (per_group)
Різна сума для діапазонів розміру групи.
1–5 → 50 · 6–10 → 75 · 11+ → 100
% від прибутку (percent)
Відсоток від чистого прибутку події (дохід − усі витрати). Рахується при завершенні події.
15% × max(0, прибуток)

4.1 Як це працює на події

У вкладці «Виконавці» додаєте рядок: гід + тип виступу (Екскурсовод) + спосіб розрахунку. Система:

  1. Бере ставку гіда з його довідника ставок.
  2. Для фіксованих типів: сума = ставка × кількість (1 для per_event, години для per_hour).
  3. Для %: відкладається до завершення події (бо потрібен підсумковий прибуток).
  4. confirmed_amount («До сплати») = custom_amount (якщо вписали вручну) або розрахована сума.

4.2 Особливість «% від прибутку»

Гід-відсоток не може бути порахований одразу: прибуток = дохід − витрати, а його ставка сама є витратою. Тому система рахує спочатку всі не-відсоткові витрати, визначає прибуток, і лише тоді: гонорар = % × max(0, прибуток). Клемп на нулі — при збитку гонорар не стає відʼємним. Остаточний нарахунок і рахунок підряднику створюються коли подія переходить у стан «Завершено».

5. Тип події — за що відповідає кожне налаштування

Тип події (event.type) — це «профіль поведінки» події. Більшість налаштувань — це перемикачі-фічі: вмикаєш — зʼявляється вкладка/поле/логіка, вимикаєш — приховується (і відповідні записи не створюються).

Форма типу події з перемикачами
Тип події «Регулярна екскурсія»: ліворуч — «Показ на події» (вкладки, квитки, терміни продажу), праворуч — «Правила розрахунку» (Онлайн, Складена, Має клієнта, Учасники впливають на бюджет, Набори квитків).

5.1 Видимість вкладок (UI)

ПолеЗа замовч.Що робить
Показати вкладку «Питання»
kw_show_question_page
ТакВкладка з кастомними питаннями реєстрації. Вимкнено → вкладки немає.
Показати вкладку «Спілкування»
kw_show_communication_page
ТакЗаплановані листи учасникам (підтвердження, нагадування). Вимкнено → вкладка зникає і заплановані листи видаляються.
Показати мульти-слоти
kw_show_multi_slots
ТакРеєстрація на кілька слотів однієї події.
Показати сторінку «Маркетинг»
kw_show_marketing_page
ТакUTM-мітки (джерело/канал/кампанія) для відстеження звідки прийшов учасник.

5.2 Формат і структура події

ПолеЗа замовч.Що робить
Онлайн kw_is_onlineНіПодія онлайн-лише: локація не обовʼязкова, інші шаблони листів.
Складена kw_is_compoundНіБатьківська подія з під-подіями (багатоденний тур). Один рівень вкладеності.
Потребує перевезення kw_is_truckageНіВмикає панель логістики/транспорту (автобуси, водії).

5.3 Квитки та ціни

ПолеЗа замовч.Що робить
Має квиток kw_has_ticketТакРеєстрація вимагає вибору типу квитка з ціною. Вимкнено → проста реєстрація імʼя/email без цін.
Інтервал дат квитків kw_use_ticket_date_intervalТакВікна продажу рахуються як зсув у днях від дати події (відкрити за 30 днів, закрити за 5). Вимкнено → дати вручну.
Авто-підтвердження реєстрацій auto_confirmТакУчасник підтверджується одразу. Вимкнено → реєстрація в чернетці, потрібне ручне підтвердження.
Набори квитків preset_idsПресети, з яких автоматично генеруються квитки при створенні події (якщо каталог не перевизначає).
Продукт продажу kw_sale_product_idЗапасний товар для SO, якщо немає товару-квитка.

5.4 Клієнт і бюджет

ПолеЗа замовч.Що робить
Має клієнта kw_event_has_clientНіB2B-режим: подія на замовлення зовнішнього клієнта, якому виставляють рахунок.
Учасники впливають на бюджет kw_is_attendee_affect_budgetТакУвімкнено → витрати/дохід на місце множаться на к-сть учасників. Вимкнено → фіксований бюджет незалежно від відвідуваності (flat-fee).
Часовий пояс default_timezoneТЗ за замовчуванням для подій цього типу (Europe/Kyiv).
Принцип «вимкнув → не створюється». Коли вкладка вимкнена, це не просто приховування: відповідні записи (листи спілкування, питання) не створюються взагалі. Це важливо для чистоти даних.

6. Створюємо екскурсію в каталозі

Практична частина. Створюємо каталог «Оглядова екскурсія Старим Києвом» — шаблон, з якого далі штампуватимемо конкретні виїзди.

1Відкрийте «Події → Каталог» і натисніть «Новий»

Заповніть шапку каталогу:

  • Каталожна назва — «Оглядова екскурсія Старим Києвом».
  • Тривалість 2,5 · Тип інтервалу — годин (екскурсія триває 2,5 год).
  • Типи подій — обидва: «Регулярна екскурсія» і «Індивідуальна екскурсія» (каталог годиться для обох форматів).
  • Місце початку — «Майдан Незалежності», «Золоті ворота».
  • Мова — Українська, Англійська.
  • Базова ціна квитка — 400 грн (від неї рахуються знижки пресету).
  • Набір квитків — «Стандартні квитки екскурсії» (Повний/Пільговий/Дитячий).
  • Запланована кількість людей 20 · Мінімум місць 10 (нижче — тур скасовується).
  • Метод розрахунку витрат за замовчуванням — «За подію» (так рахується гонорар гіда).

2Вкладка «Витрати» — собівартість туру

Додайте види витрат, що автоматично потраплятимуть у кожну подію з цього каталогу: «Оренда автобуса» (фікс 2000, отримувач — Партнер) та «Вхідні квитки до музею» (60 грн/особа, отримувач — Гід, бо гід купує квитки на місці готівкою).

3Вкладка «Хто може проводити»

Закріпіть гіда за каталогом: «Олександр Екскурсовод», тип виступу «Екскурсовод», розрахунок «За подію». Цей гід підставлятиметься в нові події за замовчуванням.

Форма каталогу екскурсії
Готовий каталог «Оглядова екскурсія Старим Києвом»: шапка з усіма параметрами + вкладка «Витрати» з видами витрат і отримувачами оплати.

7. Регулярна подія з каталогу

З каталогу створюємо регулярний виїзд на конкретну дату з авто-згенерованими квитками.

1На каталозі натисніть «Створити подію»

Відкривається майстер, попередньо заповнений із каталогу: каталог, Категорія = «Регулярна екскурсія», мова, набір квитків, запланована/мінімальна к-сть, гід. Лишається задати дату/час і місце початку.

Майстер створення події з каталогу
Майстер «Створити подію»: усе підтягнулось із каталогу; гід «Олександр Екскурсовод» з типом розрахунку «За подію» вже в списку виконавців.

2Подію створено — квитки згенерувались автоматично

Натисніть «Створити подію». Система створює event.event і з пресету каталогу сама генерує квитки з розрахованими цінами та вікнами продажу. Зверху — лічильники (Учасники, Оплати, Витрати), статуси «Новий → Зарезервовано → Оголошено → Закінчений», вкладки suite (Квитки, Зв'язок, Витрати, Запитання, Гонорари, Розрахунки з гідом, Маркетинг, Бюджет).

Форма створеної регулярної події
Готова регулярна подія: дата 30 черв. 13:00→15:30, шаблон «Регулярна екскурсія», місце «Золоті ворота», план 20 / мінімум 10.

3Вкладка «Квитки»

Три типи квитків з пресету, ціни розраховані від базової 400 ₴: Повний 400 ₴, Пільговий 200 ₴ (−50%), Дитячий 0 ₴ (−100%). Вікна продажу: відкрито за 30 днів, закрито за 1 день до події.

Згенеровані квитки з цінами
Авто-згенеровані квитки: знижки пресету застосовані до базової ціни, дата кінця продажу = за день до екскурсії.

8. Індивідуальна подія

Той самий каталог, але індивідуальний захід на замовлення (режим «є клієнт»).

1Створення з тим самим каталогом, але іншою категорією

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

Майстер з категорією Індивідуальна
Той самий каталог, обрана категорія «Індивідуальна екскурсія».

2Різниця: зʼявляється поле «Клієнт»

Оскільки тип «Індивідуальна екскурсія» має увімкнений прапор «Має клієнта», на події зʼявляється поле Клієнт — замовник заходу, якому виставлятимуть рахунок за весь тур (а не продаватимуть окремі квитки відвідувачам). Вкладка «Зв'язок» одразу містить автоматичні листи (підтвердження, нагадування за 1 год і за 3 дні) — це фіча «Показати вкладку Спілкування».

Форма індивідуальної події з полем Клієнт
Індивідуальна подія: поле «Клієнт» (замовник) + автоматичні комунікації. Це і є практична різниця між регулярним (продаж квитків людям) та індивідуальним (продаж туру клієнту) форматами.
Один каталог — два формати. Каталог описує зміст екскурсії (маршрут, тривалість, собівартість, гід). Тип події вирішує як її продавати: регулярна — роздрібно по квитках; індивідуальна — оптом одному клієнту.

9. Як записувати людей і продавати квитки

Реєстрація учасників + продаж квитків + прийом оплати — все в одному майстрі «Запис/Квитки».

1Кнопка «Запис/Квитки» на події

Відкриває майстер продажу. Заповніть:

  • Партнер — покупець (хто оплачує; для роздрібу можна загального).
  • Прайс-лист — обовʼязковий.
  • Кількості по типах квитків (напр. Повний ×3, Пільговий ×2).
  • Тип оплати «Оплата гіду» + Куди сплачуютькаса гіда, якщо гроші збирає гід на місці готівкою. Саме так надходження потрапляють у гаманець гіда для подальшого розрахунку.
Майстер продажу квитків
Продаж: 3×Повний + 2×Пільговий = 5 квитків на 1 600 ₴, оплата в «Касу гіда — Олександр».

2«Купити квитки» — що відбувається

Одна дія робить одразу все:

  • створює 5 реєстрацій (учасників) у стані «open»;
  • створює замовлення на продаж (SO) з рядками-квитками;
  • реєструє платіж 1 600 ₴ у касу гіда (статус «оплачено»).

Кнопка «Запис без оплати» — лише реєструє людей без прийому грошей (оплата пізніше).

3Бюджет одразу оновлюється

Вкладка «Бюджет» показує матрицю в трьох станах. Числа круглі, бо компанія без ПДВ:

  • Заплановано (на 20 місць): дохід 8 000, витрати 3 700 (автобус 2 000 + вхідні 60×20 + гонорар 500), баланс +4 300.
  • Записано (5 фактичних): дохід 1 600, витрати 2 800 (вхідні 60×5=300), баланс −1 200.
  • Оплачено: 1 600 надійшло, баланс +1 600.
Матриця бюджету події
Бюджет-матриця: дохід (Вхідні) / витрати (Вихідні) / Баланс × Заплановано / Записано / Оплачено. Перераховується автоматично при кожному продажу.

4Прийняти оплату пізніше — масово зі списку учасників

Якщо людей записали через «Запис без оплати», гроші можна прийняти згодом одразу від кількох учасників, не відкриваючи кожного окремо.

  • Відкрийте список учасників події → відмітьте галочками потрібних → у шапці списку зʼявиться кнопка «Прийняти оплату».
  • У майстрі поле «Журнал» за замовчуванням підтягує касу основного гіда події (можна змінити). Нижче — рядок на кожного вибраного учасника з трьома полями, що редагуються: «Тип квитка», «Ціна квитка» та «Сума до сплати» (за замовчуванням несплачений залишок).
  • Зміна типу квитка чи ціни. Якщо в рядку змінити «Тип квитка» (учасника буде переведено на інший квиток цієї події) або вручну виправити «Ціну квитка», поле «Сума до сплати» автоматично перерахується під нову ціну. При «Зареєструвати» замовлення на продаж учасника теж перепишеться на новий квиток/ціну.
  • Часткова оплата. Поле «Сума до сплати» можна зменшити — напр. при ціні квитка 300 прийняти лише 150. Учасник залишиться «Підтверджено» (не «Оплачено»), поки решту не буде внесено; повторний запуск майстра підставить залишок.
  • «Зареєструвати» реєструє платіж по кожному рядку → повністю оплачені учасники переходять у стан «Оплачено», а стовпець «Оплачено» у Бюджеті оновлюється.
  • Обмеження: усі вибрані учасники мають належати одній події; якщо серед них є вже повністю оплачений або без замовлення на продаж — майстер зупиниться з попередженням.

5Статуси учасника у списку

У списку учасників (та у статус-барі картки) стан кожної реєстрації позначено кольоровим тегом:

Непідтверджено Підтверджено Оплачено Відвідав Скасовано
  • Непідтверджено — реєстрація в чернетці, оплату/підтвердження ще не отримано.
  • Підтверджено — учасника підтверджено (раніше називалося «Зареєстровано»). Нова назва діє скрізь: у списку, у статус-барі картки та у фільтрах.
  • Оплачено — оплату прийнято повністю.
  • Відвідав — учасник прийшов на подію.
  • Скасовано — реєстрацію скасовано (мʼяке видалення).
Кнопки в рядку списку: «Сплатити» прихована для Скасовано реєстрацій (платити нема за що). Кнопка «Позначити як Прийшов» залишається доступною навіть для Оплачено учасників — оплата не закриває можливість відмітити прихід.

10. Концепція оплати гіду та взаєморозрахунок

Це найтонша частина. Ідея: гід має власний «гаманець» (каса), у який падають готівкові оплати з його екскурсій, і з якого оплачуються його витрати й гонорар. Після туру рахується, хто кому винен, і робиться один підсумковий переказ.

10.1 Гаманець гіда

Кожному гіду автоматично заводиться окрема каса («Готівка в <ім'я>») — щойно партнера позначено «Виконавець». Окремо її створювати не треба. Баланс каси = скільки готівки «на руках» у гіда. Позитивний — гід має нашу готівку; відʼємний — компанія винна гіду.

10.2 Вкладка «Розрахунки з гідом» (одна екскурсія)

На події вкладка показує чотири блоки:

БлокЩо це
Надходження (Receipts)Готівка, що впала в гаманець гіда з продажів цієї події.
Витрати й гонорари (Owed)Скільки винні гіду: його витрати (cash_recipient = performer) + його ставка.
Сплачено (Paid)Скільки вже виплачено по рахунках підрядника.
До сплати = max(Owed − Paid, 0)Залишок. Якщо > 0 — зʼявляється кнопка «Сплатити».

Підсумок події:

net = Надходження − Винні_гіду − Раніше_переказано
Гід винен компанії = max(net, 0)
Компанія винна гіду = max(−net, 0)
Розраховано?        = усі «До сплати» = 0  І  net = 0
Вкладка Розрахунки з гідом
Реальна вкладка «Розрахунки з гідом» нашої екскурсії: надходження від квитків 1 600 ₴, винні гіду 800 ₴ (вхідні 300 + гонорар 500), підсумок «Борг компанії: 800 ₴» + кнопка «Перевести компанії».
Розбір цього прикладу (з екрана вище).
Гід зібрав готівкою в свій гаманець: 1 600 ₴ (5 квитків).
Компанія винна гіду: гонорар 500 ₴ + вхідні квитки, що він купив за свої 300 ₴ = 800 ₴.
net = 1 600 − 800 = 800 ₴гід винен компанії 800 ₴.
Кнопки «Оплатити» гасять гонорар і витрати гіда (стовпчик «Оплачено»), а «Перевести компанії» переказує підсумкові 800 ₴ з гаманця гіда в касу компанії — після чого подія стає зеленою (розраховано).

10.3 Взаєморозрахунок по кількох екскурсіях

Кнопка «Розрахувати» у списку подій відкриває майстер (kw.event.guide.multi.settlement.wizard), що зводить гіда одразу по кількох турах, пулячи його гаманець:

  1. Обираєте гіда (зі списку гідів з касою).
  2. Підтягуються всі нерозраховані тури цього гіда.
  3. Кожен тур показує «гід винен компанії» або «компанія винна гіду»; галочкою обираєте, які звести.
  4. Майстер рахує net по всіх обраних — прибуткова екскурсія перекриває збиткову.
  5. По кожній події гасяться рахунки з гаманця, фіксується kw_settlement_transferred, і робиться один підсумковий переказ пулового net.
Приклад двох екскурсій.
Тур А: гід винен компанії 1200 грн. Тур Б: компанія винна гіду 300 грн (виїзд був збитковим/гід доплатив за вхідні).
Пуловий net = 1200 − 300 = 900 грн → один переказ: гід здає 900 грн. Замість двох окремих рухів — один.

10.4 Кольори списку турів

КолірУмоваЗначення
🔴 Червонийkw_under_min_seatsНе набрано мінімум місць.
🔵 Синійє активність, не розрахованоЄ нерозраховані витрати/гонорари — треба звести.
🟢 Зеленийє активність, розрахованоПовністю зведено (усе сплачено, net = 0).
⚪ Без кольорунемає активностіНічого робити.

11. REST API

Модуль kw_events_api дає REST-ендпоінти /kw_api/* для інтеграції із зовнішнім сайтом (WordPress/WooCommerce): створення подій, реєстрація учасників, продаж і оплата квитків. Автентифікація — токенна.

11.1 Автентифікація

Спершу отримуєте токен, далі передаєте його у заголовку Authorization: Bearer <token> (або access_token). Токен живе 24 год (налаштовується).

POST /kw_api/event_auth

// запит
{ "db": "event19", "login": "admin", "password": "admin" }

// відповідь
{ "status":"200", "result":"OK",
  "data": { "uid":2, "access_token":"abc123…", "expires_in":"2026-07-01 12:30:45" } }

11.2 Створення події

POST /kw_api/create_event  (потрібен токен)

Створює подію з каталогу. Ідемпотентно за ключем слоту (catalog_id, date_begin, date_end) — повторний виклик не плодить дублі.

ПараметрОбовʼязк.Опис
event_nameтакНазва події.
start_datetime / end_datetimeтакISO 8601, у ТЗ користувача.
catalog_idніКаталог-шаблон (місця, мова, гіди, ціни).
event_type_idніТип події.
seats_max / seats_planніМакс. і планована к-сть місць.
base_ticket_priceніБазова ціна для пресетів квитків.
disc_priceніЦіна пільгового квитка (перевизначає формулу пресета).
preset_id, guide_id, language_idніПресет квитків, гід, мова.
utm_source/medium/campaignніUTM-мітки.
curl -X POST https://HOST/kw_api/create_event \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "event_name": "Оглядова Старим Києвом — 15.08",
    "start_datetime": "2026-08-15T11:00:00",
    "end_datetime":   "2026-08-15T13:30:00",
    "catalog_id": 5,
    "seats_max": 25,
    "base_ticket_price": 400
  }'
// → { "data": { "event_id": 42 } }

11.3 Реєстрація / продаж квитків

POST /kw_api/create_registration

Створює один або кілька квитків-реєстрацій. Ідемпотентно за order (advisory-lock проти подвійного спрацювання). Кожен квиток — у власному savepoint.

ПараметрОбовʼязк.Опис
event_idтакID події.
tickets[]такМасив: ticket_id (значення атрибута типу квитка), price, опц. coupon_code, certificate_number.
orderніЗовнішній № замовлення (WP) — вмикає ідемпотентність.
name, email, phoneніДані учасника.
is_paid, journal_idніПозначити оплаченим + журнал для реєстрації платежу.
payment_statusні0=чернетка · 1=відкрито · 2=оплачено.
curl -X POST https://HOST/kw_api/create_registration \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "event_id": 42,
    "order": "WP-2026-08-001",
    "tickets": [ { "ticket_id": 1, "price": 400 } ],
    "name": "Олена Коваль", "email": "olena@example.com",
    "phone": "+380501234567", "is_paid": true, "journal_id": 6, "payment_status": 2
  }'
// → { "data": { "event_id":42, "registrations":[123], "order":"WP-2026-08-001" } }

11.4 Інші ендпоінти

МетодШляхПризначення
PUT/kw_api/change_registrationЗамінити всі квитки замовлення (видаляє старі, створює нові). Заборонено для оплачених.
PUT/kw_api/update_registrationОновити лише статус оплати (payment_status) без перестворення квитків.
DELETE/kw_api/delete_registrationСкасувати реєстрації замовлення (state = cancel, мʼяке видалення).

11.5 Формат відповіді

{
  "status":  "200",          // код HTTP рядком
  "result":  "OK",           // OK | error
  "error":   "",             // код помилки: auth_error | parameters_missing | validation_error
  "message": "",             // повідомлення для користувача
  "data":    { ... },        // корисне навантаження
  "count":   1               // к-сть полів у data
}

11.6 Повний приклад (Python)

import requests
BASE = "https://HOST"

# 1. токен
tok = requests.post(f"{BASE}/kw_api/event_auth",
    json={"db":"event19","login":"admin","password":"admin"}
).json()["data"]["access_token"]
H = {"Authorization": f"Bearer {tok}"}

# 2. подія
ev = requests.post(f"{BASE}/kw_api/create_event", headers=H, json={
    "event_name":"Оглядова Старим Києвом — 15.08",
    "start_datetime":"2026-08-15T11:00:00",
    "end_datetime":"2026-08-15T13:30:00",
    "catalog_id":5, "seats_max":25, "base_ticket_price":400
}).json()["data"]["event_id"]

# 3. продаж квитка + оплата
requests.post(f"{BASE}/kw_api/create_registration", headers=H, json={
    "event_id":ev, "order":"WP-2026-08-001",
    "tickets":[{"ticket_id":1,"price":400}],
    "name":"Олена Коваль","email":"olena@example.com",
    "is_paid":True,"journal_id":6,"payment_status":2
})