Перейти до вмісту

Інтеграція з Horoshop

Матеріал з K2 ERP Wiki

)

hs_order = horoshop_order_repository.get_by_k2_order_id(db, k2_order_id)


class HoroshopClient:

3. Тип

POST /api/v1/horoshop/products/sync-batch

self.timeout_seconds = timeout_seconds
id uuid Статус передається в Horoshop. try:
  • створення нового клієнта в K2 ERP на основі замовлення Horoshop;
  • пошук клієнта за телефоном;
  • пошук клієнта за email;
  • оновлення версій ПІБ;
  • оновлення версій адреси доставки;
  • історію замовлень клієнта;
  • мапінг customer_id Horoshop ↔ customer_id K2 ERP. |}

21.2. Логіка оновлення версій залишків

"payment": {

13.2. Загальні принципи

style="background:#c8e6c9;" | Зелений
Потребує перевірки NEEDS_REVIEW Заблокувати синхронізацію ціни. Тип
"status": "new",
"status": "new"

22.5. horoshop_category_mappings

class HoroshopApiError(Exception):

db=db,
payload = horoshop_product_mapper.to_payload(product)

27. Безпека

},
- Клієнти style="background:#c8e6c9;" | Зелений
Приховано HIDDEN Товар прихований на сайті. Python-сервіс формує доступну кількість. Поле
payload=response,

платформа повинна забезпечити:

  • регулярно отримувати нові замовлення;
  • перевіряти, чи замовлення вже імпортоване;
  • створювати замовлення в K2 ERP;
  • створювати або оновлювати клієнта;
  • зберігати товари замовлення;
  • зберігати оплату;
  • зберігати доставку;
  • зберігати коментар покупця;
  • резервувати товар;
  • змінювати статус замовлення в Horoshop, якщо потрібно. Резервує товар у K2 ERP. except Exception as exc:

HOROSHOP_API_LOGIN=integration_user

13.3. Основні методи клієнта

audit_logger.log(

18. Валідація товарів

hs_product.raw_response = response

Метою задачі виступає як створення Python-сервісу для інтеграції K2 ERP / CRM / WMS з інтернет-магазином на платформі Horoshop. SEO-опис

db.commit()
  • створення інтеграції Horoshop;
  • перевірка підключення;
  • синхронізація категорій або мапінг категорій;
  • синхронізація товарів;
  • синхронізація цін;
  • синхронізація залишків;
  • імпорт замовлень;
  • імпорт клієнтів із замовлень;
  • оновлення версій статусів замовлень;
  • передача ТТН;
  • дедублікація;
  • retry-механізм;
  • журнал подій;
  • dashboard API;
  • unit-тести;
  • mock Horoshop client. Тип
- sync_products_enabled boolean Синхронізація товарів. Об'єкт


 "quantity": 1,
 db=db,
 if data.get("status") in ["error", "failed"]:
http(s)://<DOMAIN>/api/
До MVP не входить:
{| class="wikitable"
http(s)://<DOMAIN>/api/<FUNCTION>/
 self.api_password = api_password
{| class="wikitable"
 "external_customer_id": "HS-CUSTOMER-001",

! |-
| Некоректний товар
| Товар не публікується. | Вони підсвічуються помаранчевим. "stock_quantity": 12,
! ],

* реалізувати Order Import Worker;
* реалізувати дедублікацію;
* реалізувати створення замовлення в K2 ERP;
* реалізувати створення клієнта;
* реалізувати резервування товарів. |-
| Замовлення
| Імпорт замовлень із Horoshop. Ключ
 return
 "type": "online_card",
 "https://example.com/images/sku-001-1.jpg",
|-
| AC-11
| На сайті з'явилось нове замовлення. | Вони підсвічуються жовтим. |}

 payload = {

 "name": "Смартфон Example X 128GB",

* домен сайту Horoshop;
* API base URL;
* API login;
* API password;
* доступ до адмінпанелі Horoshop;
* список API-методів, які доступні на конкретному тарифі / сайті;
* актуальну документацію API;
* правила мапінгу категорій;
* правила мапінгу характеристик;
* список статусів замовлень Horoshop;
* список статусів замовлень K2 ERP;
* список типів оплат;
* список типів доставок;
* правила синхронізації цін;
* правила синхронізації залишків;
* правила обробки замовлень;
* правила передачі ТТН. Очікуваний результат

 base_url: str
 db.commit()

'''критично:''' приклад авторизації виступає як архітектурним. |-
| new_status
| varchar
| Новий статус. Замовлення, клієнти, статуси
! k2_order = k2_order_service.create_from_horoshop(order_payload)

POST /api/v1/horoshop/integrations/{integration_id}/check-connection

* отримати подію зміни ціни;
* визначити канали продажу;
* перевірити активність товару;
* застосувати правила округлення;
* застосувати правила акційної ціни;
* передати нову ціну в Horoshop;
* зберегти історію зміни. | Вони підсвічуються червоним. # Чи виступає як модифікації / варіанти товарів? |-
| Stock Engine
| Формує доступний залишок. |-
| Stock Sync Worker
| Передає залишки. |-
| Payment
| Оплата. KPI
<pre>
! | K2 ERP
| критично для комерційного контролю. |-
| Статуси
| оновлення версій статусів замовлень на сайті. |-
| Price
| Ціна товару. |-
| is_active
| boolean
| Активність. | платформа показує AuthError і не виконує синхронізацію. Коментар
|-
| Товарів у синхронізації
| Кількість товарів, що передаються на сайт. |}

! |-
| AC-21
| виступає як нові замовлення. # Які статуси Horoshop потрібно замапити? |-
| amount
| numeric
| Сума. |-
| Price Sync Worker
| Передає ціни. |-
| Зміна API
| Методи або поля можуть змінитись. |-
| Дублювання замовлень
| Повторний імпорт здатна створити дубль. | Horoshop / платіжний сервіс / K2 ERP
| Потребує мапінгу. |-
| Product Mapper
| Перетворює товар K2 ERP у формат Horoshop. Створюється задача Stock Sync. Колір
 "sku": "SKU-001",
 v
 language: str = "ua"
 pass

=== Етап 3. Horoshop Client ===
POST /api/v1/horoshop/orders/{order_id}/tracking-number

2. Тип

def get_order(self, order_id: str) -> "OrderResponse":

15.4. Синхронізація товару

"address": null

5. Дія

  • Офіційна документація Horoshop API. |-
Імпорт замовлення - sync_stocks_enabled boolean - horoshop_status varchar style="background:#fff9c4;" | Увага
Імпортовано замовлень Замовлення створені в K2 ERP. Якщо замовлення нове — створює його в K2 ERP. Код

синхронізації товарів забезпечується через Головна ідея: розробити Python-сервіс, який інтегрує K2 ERP / CRM / WMS з інтернет-магазином на платформі Horoshop / Хорошоп; так само реалізовано категорій, характеристик, цін, залишків, клієнтів, замовлень, статусів, оплат, доставок і журналу помилок. | K2 ERP / WMS

Критичний бізнес-процес. №
continue

Як адміністратор,

orders = response.get("orders", [])

Етап 1. Аналіз API Horoshop

error=str(exc),

3. №

)
"customer_name": order_payload.get("customer", {}).get("name"),
db.commit()
pass

5. |-

AC-16 - оновлення версій цін Високий - AC-6 - Недоступність API Синхронізація зупинена. function="orders/get/",
  • реалізувати мапінг статусів;
  • реалізувати Status Export Worker;
  • реалізувати передачу ТТН;
  • реалізувати журнал статусів. | K2 ERP
- Status Export Worker Передає статуси назад у Horoshop. sku=product.sku,

Етап 7. Статуси та доставка

  • отримати доступ до API;
  • створити API login/password в адмінпанелі;
  • перевірити base_url;
  • перевірити тестовий запит;
  • визначити методи товарів;
  • визначити методи замовлень;
  • визначити методи статусів;
  • визначити методи цін і залишків;
  • визначити обмеження API. |-
Horoshop Product Товар на сайті Horoshop.=== 5.3. оновлення версій залишків ===
self.base_url = base_url.rstrip("/")
критично: назви методів Python-клієнта виступає як внутрішньою абстракцією. | Unique constraint по external_order_id + site_id.
- sku varchar } Пріоритет

Критично критично: товар без SKU, категорії, ціни або головного фото не повинен автоматизовано передаватися в Horoshop. SEO-опис

{

Draft, hidden, cancelled. db=db,

1. |}

return data

15.7. оновлення версій залишків

17. Приклад замовлення з Horoshop

POST /api/v1/horoshop/orders/{order_id}/update-status </syntaxhighlight>

- product_hash Hash назви, опису, ціни, залишку, характеристик. Напрям
def __init__(self, base_url: str, api_login: str, api_password: str, timeout_seconds: int = 30):
Тип

15.8. Імпорт замовлень

pass
def get_customers(self, filters: dict) -> "CustomerListResponse":
available_stock = stock_engine.calculate_available_stock(
- Attribute Валідація і статус NEEDS_CORRECTION. | Horoshop Замовлення створюються покупцями на сайті. external_order_id = str(order_payload ["id"]) - k2_product_id uuid Заблокувати синхронізацію залишку. |- horoshop_status varchar - Зміна залишку - Статуси замовлень K2 ERP → Horoshop K2 ERP Статус стає SYNCED. |- product_hash varchar - Ціни K2 ERP → Horoshop K2 ERP Актуальні ціни на сайті.
  • підключення до Horoshop API;
  • перевірку доступності API;
  • синхронізацію категорій;
  • синхронізацію товарів;
  • синхронізацію модифікацій / варіантів товарів;
  • синхронізацію характеристик;
  • синхронізацію фото;
  • синхронізацію цін;
  • синхронізацію знижок і акцій, якщо підтримується API;
  • синхронізацію залишків;
  • імпорт замовлень;
  • імпорт клієнтів;
  • оновлення версій статусів замовлень;
  • передачу ТТН / ЕН у замовлення;
  • синхронізацію оплат і доставок;
  • журналювання API-запитів;
  • контроль помилок;
  • dashboard для менеджерів і керівника. |-
Product Image - AC-3 інтеграційні функції ERP зберігається в системі. |- last_synced_stock numeric Останній переданий залишок. Сутність
"comment": order.manager_comment,
}
def get_orders(self, filters: dict) -> "OrderListResponse":

14. Конфігурація клієнта

21. Черги синхронізації

28. Логування та аудит

)
id uuid style="background:#c8e6c9;" | Зелений
Скасовано CANCELLED Високий пріоритет Stock Sync. |}
"phone": "+380671112233",
- Order - Order Item - sync_prices_enabled boolean - Зміна ціни - Доставка Передача служби доставки, адреси, ТТН. ! Критерій
  • отримати залишок із K2 ERP або WMS;
  • врахувати резерви;
  • врахувати мінімальний страховий залишок;
  • сформувати доступний залишок для сайту;
  • передати залишок у Horoshop;
  • приховати товар, якщо залишок 0, якщо це передбачено правилами;
  • відновити товар, якщо залишок з'явився. |-
site_domain varchar Домен сайту. * timeout;
  • HTTP 429;
  • HTTP 500;
  • HTTP 502;
  • HTTP 503;
  • HTTP 504;
  • тимчасової недоступності API;
  • тимчасової помилки імпорту замовлень;
  • тимчасової помилки оновлення версій ціни;
  • тимчасової помилки оновлення версій залишку;
  • тимчасової помилки оновлення версій статусу. |-
horoshop_category_id varchar Категорія Horoshop. SEO-опис
product = product_repository.get_by_id(db, product_id)

Це відповідає офіційній документації Horoshop API, де вказано, що шлюз має формат `http(s)://<DOMAIN>/api/`, а функції передаються через адресний рядок. |-

Залишки K2 ERP/WMS → Horoshop K2 ERP / WMS Актуальна наявність. :contentReference [oaicite:2]{index=2}
def call_api(self, function: str, payload: dict | None = None) -> dict:

</syntaxhighlight>

hs_product.status = "SYNC_ERROR"
function="catalog/update_stock/",
style="background:#eeeeee;" | Сірий
Помилка ERROR - Блакитний #bbdefb style="background:#ef9a9a;" | Критично
Оновлено цін - AC-20 платформа передає нову ціну в Horoshop. "date_from": sync_state_repository.get_last_order_sync_date(db),
=== 29.6. Dashboard ===
</pre>
! Товари, ціни, залишки, статуси
Перед створенням замовлення в K2 ERP платформа повинна перевірити:
HOROSHOP_TIMEOUT_SECONDS=30
 |
 | 2. | Товар приховується або позначається як недоступний за правилом. |-
| delivery_service
| varchar
| Служба доставки. | K2 ERP або Horoshop
| Визначається правилами проєкту. |-
| created_at
| timestamp
| Дата створення. |-
| quantity
| numeric
| Кількість. Значення
інтеграційні функції ERP призначена для:
я хочу отримувати замовлення з Horoshop у K2 ERP, 

=== 21.1. Логіка синхронізації товарів ===

! 

{| class="wikitable"
</pre>
! ! |-
| raw_payload
| jsonb
| інформаційні дані замовлення. |-
| API Event
| Технічна подія інтеграції. Створюється задача Product Sync. |-
| style="background:#f3e5f5;" | Фіолетовий
| #f3e5f5
| Ручна перевірка або нестандартний сценарій. |-
| AC-7
| Товар успішно передано. Подія
! |-
| Product
| Товар у K2 ERP. K2 ERP змінює товар. Статус K2 ERP

HOROSHOP_RETRY_BACKOFF_SECONDS=5
 "price": 12999.00,
{| class="wikitable"
! Стан
 response = await client.call_api(
! Призначення
 timeout_seconds: int = 30

 )

 k2_product_id=product.id,

7. | style="background:#bbdefb;" | Блакитний
|-
| Синхронізується
| SYNCING
| Виконується API-запит до Horoshop. Компонент
6. |-
| total_amount
| numeric
| Сума. Поле

</pre>
Retry заборонений для:
 product_status_service.set_status(
! SEO-опис

! Дата
! |-
| Оплата
| Статус і тип оплати. # Які типи оплат і доставок потрібно підтримати? |-
| Order Mapper
| Перетворює замовлення Horoshop у формат K2 ERP. API-запити виконуються до шлюзу:
 }

== 26. Dashboard керівника ==

 integration = horoshop_integration_repository.get_active(db)
{| class="wikitable"
4. "price": 12999.00,
 payload=payload,
|-
| Товари
| Створення та оновлення версій товарів на Horoshop. def check_connection(self) -> "ConnectionStatus":

 )
Order Import Worker

=== 15.2. Перевірка підключення ===
=== 23.5. оновлення версій статусу замовлення ===

 v

=== 5.2. оновлення версій цін ===
Python-сервіс повинен:

! |-
| Клієнти
| Horoshop  K2 ERP
| Horoshop
| Створення клієнтів із замовлень. Перевіряє external_order_id. |-
| Замовлення
| Horoshop  K2 ERP
| Horoshop
| Обробка продажів. Колір
 self.api_login = api_login

! | style="background:#c8e6c9;" | Норма
|-
| Потребують перевірки
| Замовлення з невідомими товарами або даними. |-
| Помилка API
| Код, текст, raw-відповідь без секретів. payload=payload,
платформа повинна підтримувати:
 client = horoshop_client_factory.create(integration)

 data = response.json()

</pre>

=== 13.1. Призначення ===

{| class="wikitable"

* отримати товар із K2 ERP;
* перевірити обов'язкові поля;
* визначити категорію;
* підготувати назву;
* підготувати SEO-опис;
* підготувати характеристики;
* підготувати фото;
* підготувати ціну;
* підготувати залишок;
* створити або оновити товар у Horoshop;
* зберегти external_product_id;
* записати результат у журнал. | ТТН передається в Horoshop. |-
| style="background:#ef9a9a;" | Червоний
| #ef9a9a
| Критична помилка. Тип


! |-
| customer_phone
| varchar
| Телефон. |-
| Customer
| Покупець. Точну схему передачі login/password, token або session потрібно звірити з актуальною документацією Horoshop API для конкретного методу. Критерій
|-
| API Layer
| REST API для команд із K2 ERP. |
 | 5. |-
| payment_status
| varchar
| Статус оплати. щоб вони автоматизовано з'являлися та оновлювалися на сайті Horoshop. |-
| order_number
| Номер замовлення. SEO-опис

 "external_order_id": external_order_id,

{| class="wikitable"

* SKU заповнений;
* назва заповнена;
* SEO-опис заповнений;
* категорія визначена;
* категорія Horoshop замаплена;
* ціна більша за 0;
* залишок не від'ємний;
* фото доступні;
* головне фото визначене;
* характеристики заповнені;
* бренд заповнений, якщо потрібен;
* штрихкод валідний, якщо застосовується для;
* товар не дублюється за SKU;
* товар не дублюється за external_product_id;
* текст опису не містить небезпечного HTML;
* активність товару відповідає правилам публікації. Поле
</pre>
! |-
| Stock
| Залишок товару.=== Етап 9. Production hardening ===
Приклад `.env`:
! За потреби оновлює статус у Horoshop.=== 29.5. Статуси та ТТН ===
 payload=payload,
 "name": "Іван Петренко",
=== Етап 6. Замовлення ===
{| class="wikitable"
 external_order_id=external_order_id,
 pass
 "images": [
<syntaxhighlight lang="python">
 "product_id": "K2-PRODUCT-000123",
class HoroshopClient:
== 34. Джерела ==
{| class="wikitable"
</pre>
! |-
| horoshop_product_id
| varchar
| ID товару Horoshop. |-
| Залишки
| оновлення версій доступної кількості. |-
| style="background:#eeeeee;" | Сірий
| #eeeeee
| Чернетка, приховано, скасовано або архів. | Retry, dashboard warning. SEO-опис

<pre>
! | style="background:#fff9c4;" | Жовтий
|-
| Потребує виправлення
| NEEDS_CORRECTION
| Не вистачає категорії, ціни, фото, опису або характеристик. |-
| style="background:#ffcc80;" | Помаранчевий
| #ffcc80
| Потрібна дія менеджера. | style="background:#c8e6c9;" | Норма
|-
| Нові замовлення
| Нові замовлення з Horoshop. class HoroshopSettings(BaseSettings):
=== 15.6. оновлення версій цін ===
</pre>
 horoshop_order_repository.create(
! | style="background:#bbdefb;" | Блакитний
|-
| Виконано
| COMPLETED
| Замовлення завершено. |-
| entity_id
| uuid
| ID сутності. | Retry, queue, dashboard помилок. | style="background:#ef9a9a;" | Критично
|}

Python Horoshop Integration Service

щоб оперативно знаходити технічні помилки інтеграції. |}

! SEO-опис
 retry_backoff_seconds: int = 5
=== 15.9. оновлення версій статусу замовлення ===
! SKU

* додати rate limiting;
* додати retry policy;
* додати dead letter queue;
* додати alerting;
* додати моніторинг;
* додати резервне копіювання;
* додати безпечне зберігання secret-ів. |-
| Audit Logger
| Запити, відповіді, помилки, статуси. Валідація, мапінг, черги, дедублікація
== 2. Область сценарії використання ==
 db.commit()
 |
 | 3. Очікуваний результат
POST /api/v1/horoshop/prices/sync
|-
| AC-18
| Керівник відкриває dashboard. |}

я хочу бачити dashboard інтеграції, 

# Чи K2 ERP виступає як головним джерелом товарів? |-
| Order Import Worker
| Імпортує замовлення. |-
| Синхронізація категорій
| Низький
| Довідник. pass

! # Чи потрібно синхронізувати фото? Де застосовується для
! Замовлення

<syntaxhighlight lang="python">
 try:
 product_id=product.id,

<pre>

{| class="wikitable"
 hs_product.last_synced_price = product.price
 )

<pre>

 db=db,
<pre>
 k2_status=order.status,

 hs_product.error_message = str(exc)

<syntaxhighlight lang="python">
 "external_order_id": "HS-ORDER-000123",
 "payment_type": order_payload.get("payment", {}).get("type"),

== 1. Мета ==

POST /api/v1/horoshop/orders/import
{| class="wikitable"
=== 15.1. Створення інтеграції ===

<pre>

щоб контролювати помилки, продажі та реалізація, синхронізацію товарів і проблемні замовлення. | style="background:#eeeeee;" | Сірий
|-
| Очікує валідації
| PENDING_VALIDATION
| Товар очікує перевірки. # Чи потрібно синхронізувати акційні ціни?=== 22.7. horoshop_events ===
 pass
|-
| AuthError
| Невірний API login або password. # Які поля товару обов'язкові для MVP?== 5. Основні бізнес-сценарії ==
|-
| style="background:#c8e6c9;" | Зелений
| #c8e6c9
| Успішно: синхронізовано, опубліковано, імпортовано, виконано. |-
| Передача ТТН
| Номер замовлення, ТТН, служба доставки. Назва

 pass

* external_order_id;
* номер замовлення;
* дату замовлення;
* телефон покупця;
* список товарів;
* SKU кожного товару;
* кількість;
* ціну;
* суму;
* тип оплати;
* статус оплати;
* тип доставки;
* адресу або відділення;
* чи не імпортоване замовлення раніше;
* чи існують товари в K2 ERP;
* чи достатньо залишку для резервування. Критерій
! |-
| PriceError
| Некоректна ціна. |-
| Product Sync Worker
| Передає товари. |-
| ValidationError
| Некоректний товар або замовлення. HTML
 if not validation_result.is_valid:
! | Check-connection і alert адміністратору. |}

! |-
| AC-10
| Залишок став 0. |-
| sync_orders_enabled
| boolean
| Імпорт замовлень. |}

=== Етап 4. Товари ===

! Очікуваний результат

Для реалізації задачі необхідно отримати:
</div>
! | style="background:#c8e6c9;" | Зелений
|-
| Опубліковано
| PUBLISHED
| Товар доступний на сайті. Поле

Функції API викликаються через URL:

Перед передачею товару в Horoshop платформа повинна перевірити:

 "is_active": true

== 32. Ризики ==

 "attributes": {
{| class="wikitable"
}

{| class="wikitable"

=== 12.1. Загальна схема ===
POST /api/v1/horoshop/categories/sync
=== 29.3. Ціни та залишки ===

 pass

=== 22.2. horoshop_products ===

! Він повинен потрапляти у статус NEEDS_CORRECTION. |-
| error_message
| text
| Остання помилка. Джерело

 )
 async with httpx.AsyncClient(timeout=self.timeout_seconds) as client:
7. | Маскування телефону/email. |-
| Category Mapper
| Мапить категорії. # Чи потрібно синхронізувати декілька складів? |-
| idempotency_key
| Ключ повторної обробки. |-
| ConnectionError
| API Horoshop недоступне. |}

 )

! |}

 "warranty": "12 місяців"

async def sync_stock_to_horoshop(product_id: str, db: "Session") -> None:
 },
6. | Версіонування клієнта і contract-тести.<pre>

* створити FastAPI-проєкт;
* налаштувати PostgreSQL;
* створити моделі інтеграцій, товарів, замовлень, мапінгів, подій;
* налаштувати Alembic;
* реалізувати healthcheck. | Дубль не створюється. Джерело істини
 raise HoroshopApiError(str(data))
=== 23.2. Синхронізація товару ===
=== 5.6. Обмін клієнтами ===
</pre>
|-
| SKU-001
| Смартфон Example X
| style="background:#ffcc80;" | Потребує виправлення
| Не замаплена категорія
| Заповнити мапінг
|-
| SKU-002
| Навушники Example Air
| style="background:#ef9a9a;" | Помилка
| Фото недоступне
| Перевірити URL фото
|-
| SKU-003
| Кавоварка Example
| style="background:#ffcc80;" | Потребує виправлення
| Немає ціни
| Заповнити ціну
|}

 response = await client.post(url, json=request_payload)

 response=response,
Інтернет-магазин Horoshop
 "barcode": "4820000000000",
<pre>
 "total_amount": 12999.00,
{| class="wikitable"
 def update_order_status(self, order_id: str, payload: dict) -> "OrderStatusResponse":
|-
| 07.05.2026
| HS-ORDER-001
| Іван Петренко
| style="background:#ffcc80;" | Потребує перевірки
| Не знайдено SKU
| Прив'язати товар
|-
| 07.05.2026
| HS-ORDER-002
| Олена Сидоренко
| style="background:#ef9a9a;" | Помилка
| Не створено клієнта
| Перевірити телефон/email
|-
| 07.05.2026
| HS-ORDER-003
| ТОВ «Альфа»
| style="background:#ffcc80;" | Потребує перевірки
| Невідомий тип доставки
| Заповнити мапінг доставки
|}

== 31. Етапи реалізації ==

</pre>

* зберігання API login/password тільки у secret storage;
* заборону логування паролів;
* HTTPS для всіх API-запитів;
* перевірку SSL;
* рольову модель доступу;
* окремі права на синхронізацію товарів;
* окремі права на зміну цін;
* окремі права на зміну залишків;
* окремі права на імпорт замовлень;
* окремі права на оновлення версій статусів;
* журнал усіх дій;
* маскування персональних даних покупців;
* захист від дублювання замовлень;
* контроль доступу до raw API payload. | K2 ERP
| ERP керує виконанням замовлень. |-
| Horoshop Client
| Python-клієнт для Horoshop API.<syntaxhighlight lang="python">

== 12. технічна архітектура рішення для бізнесу ==
[[Категорія:WMS]]
'''Критично критично:''' інтеграційні функції ERP не повинна створювати дублікати товарів. |-
| direction
| varchar
| IMPORT або EXPORT. |-
| delivery_address
| text
| Адреса доставки. client = horoshop_client_factory.create(integration)

{{DISPLAYTITLE:Технічне завдання: Інтеграція з Horoshop / Хорошоп для Python}}

 status="NEEDS_CORRECTION",
 "amount": 12999.00
 error=str(exc),
|-
| Перевірка підключення
| URL, результат, час, без пароля. Статус
 errors=validation_result.errors,

! Worker передає залишок у Horoshop. |-
| k2_status
| varchar
| Статус K2 ERP. |-
| оновлення версій статусів замовлень
| Високий
| Впливає на клієнтський досвід. db=db,
|-
| AC-1
| Адміністратор створює інтеграцію Horoshop. |-
| horoshop_site_id
| ID сайту, якщо магазинів декілька. | API-запити, черги, обробка. Колір

! |-
| AC-17
| Статус не замаплений. |-
| event_type
| varchar
| Тип події. | K2 ERP / служби доставки
| Нова пошта, Укрпошта тощо. # Чи потрібно передавати ТТН у Horoshop? SEO-опис
=== 7.4. Керівник ===
</pre>
__TOC__
<pre>
2. Задача
 "city": "Київ",
 horoshop_status = status_mapping_repository.map_k2_to_horoshop(
! * Сторінка Horoshop API. |}

POST /api/v1/horoshop/products/{product_id}/sync

 audit_logger.log(
Як менеджер товарного каталогу, 
== 23. Приклад Python-логіки ==
 "service": "nova_poshta",
|-
| id
| uuid
| ID замовлення. SEO-опис
! |-
| ImageError
| Фото недоступне. 
|-
| Імпорт замовлень
| Критичний
| Впливає на продажі та реалізація. | Він переходить у NEEDS_CORRECTION. |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування дії або оплати. | Заблокувати передачу товару. Критерій

 new_status="SYNCED",
{| class="wikitable"

Коли ціна змінюється в K2 ERP, Python-сервіс повинен: </syntaxhighlight>

- AC-13 - created_at timestamp Дата створення. Тип помилки
[[Категорія:CRM]]
|-
| id
| uuid
| ID інтеграції. Worker регулярно запитує нові замовлення Horoshop.[[Категорія:Python]]

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

 v

* отримати статус замовлення з K2 ERP;
* замапити його у статус Horoshop;
* передати статус у Horoshop;
* передати ТТН / ЕН, якщо виступає як;
* передати коментар менеджера, якщо підтримується;
* записати подію в журнал. Показник

 entity_type="order",
 "order_id": hs_order.external_order_id,
== 30. MVP ==
 ],
! Призначення
! |-
| k2_product_id
| ID товару в K2 ERP. | платформа передає новий залишок. Коментар
я хочу бачити журнал API-запитів, 

 db=db,

== 3. Основні функції ERP інтеграції ==
 "sku": "SKU-001",
 "order_number": "000123",
 verify_ssl: bool = True
</syntaxhighlight>

 "status": "paid",
GET /api/v1/horoshop/dashboard?date_from=2026-05-01&date_to=2026-05-31
{

=== 7.3. Менеджер продажів ===
 )
 product = product_repository.get_by_id(db, product_id)
 if existing:

=== 29.2. Товари ===
K2 ERP виступає як головним джерелом операційного статусу. |-
| is_active
| boolean
| Активність. |-
| AC-19
| виступає як помилки синхронізації. |}

HOROSHOP_LANGUAGE=ua

 event_type="HOROSHOP_PRODUCT_SYNCED",

 api_login: str
{| class="wikitable"
 |
 | 1. Якщо товар не знайдено — статус NEEDS_REVIEW.== 29. Acceptance Criteria ==
}
|-
| Чернетка
| DRAFT
| Товар створений у K2 ERP, але ще не готовий до передачі. | style="background:#bbdefb;" | Блакитний
|-
| Синхронізовано
| SYNCED
| Товар успішно передано або оновлено. |-
| is_active
| boolean
| Активність. request_payload ["password"] = self.api_password

* неправильного API login/password;
* товару без SKU;
* товару без категорії;
* товару без ціни;
* товару без фото;
* незамапленого статусу;
* дубліката замовлення;
* помилки бізнес-логіки K2 ERP. |-
| payload
| jsonb
| Технічні інформаційні дані. | style="background:#fff9c4;" | Жовтий
|-
| Оплачено
| PAID
| Оплата отримана. 4. # Чи потрібно створювати категорії в Horoshop автоматизовано? |-
| status
| varchar
| Статус синхронізації. * Центр допомоги Horoshop. Призначення
 try:
! |-
| Товари
| K2 ERP → Horoshop
| K2 ERP
| Публікація каталогу. Окремо варто відзначити клієнтів або замовлень. |-
| status
| varchar
| Статус K2 ERP. function="catalog/import/",
</syntaxhighlight>

=== 15.10. Передача ТТН / ЕН ===
 "description": "SEO-опис товару для сайту.",
[[Категорія:Технічні завдання]]
<div style="border-left: 6px solid #2e7d32; background: #e8f5e9; padding: 12px 16px; margin: 16px 0;">
[[Категорія:API]]
! |-
| sync_statuses_enabled
| boolean
| оновлення версій статусів. |-
| Характеристики
| Передача атрибутів товарів. №
 "payment_status": order_payload.get("payment", {}).get("status"),
 "email": "client@example.com"
4. * Документація K2 ERP щодо товарів, залишків, цін і замовлень. |}

! | Він не передається і показується менеджеру. | style="background:#e3f2fd;" | інформаційні матеріали
|-
| Синхронізовано товарів
| Товари успішно передані. |}

K2 ERP / CRM / WMS

5. Worker викликає Horoshop API. |-
| AC-12
| Замовлення вже імпортоване. Колір
 validation_result = product_validator.validate(product)
 "comment": "Зателефонувати перед відправкою",
|-
| Horoshop Integration
| конфігурація підключення до конкретного сайту. SEO-опис

 integration = horoshop_integration_repository.get_active(db)
=== Етап 5. Ціни та залишки ===
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
== 24. Обробка помилок ==
{| class="wikitable"

Коли змінюється залишок на складі, Python-сервіс повинен:

pass

15.5. Масова синхронізація товарів

12.2. Основні компоненти Python-сервісу

stock=available_stock,
def update_product_price(self, product_id: str, payload: dict) -> "PriceResponse":

10. Статуси замовлень

if response.status_code >= 400:

19. Валідація замовлень

},

Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker. |-

name varchar Замовлення потрапляє в ручну перевірку. |- AC-14 - Category Dashboard, товари, замовлення. |- k2_category_id varchar Manual review. |- DuplicateOrderError - Продаж відсутнього товару Зупинити інтеграцію, повідомити адміністратора. |- horoshop_product_id style="background:#c8e6c9;" | Норма
Оновлено залишків - last_synced_price numeric - Dashboard API інформаційні дані для контролю інтеграції. },
 "total_amount": order_payload.get("total"),
=== 21.3. Логіка імпорту замовлень ===
 "order_number": order_payload.get("number"),
 )
 "order_date": "2026-05-07T12:10:00+03:00",
=== 5.4. Імпорт замовлень ===
HOROSHOP_API_PASSWORD=********
</div>
Retry дозволений для:
1. |-
| horoshop_category_id
| varchar
| Категорія Horoshop. | NEEDS_CORRECTION / NEEDS_REVIEW. |-
| Категорії
| Синхронізація структури каталогу. "status": "IMPORTED",
Як комірник або WMS, 

! Як менеджер продажів, 

 except Exception as exc:

* інтернет-магазинів на Horoshop;
* компаній, які ведуть обліковий облік у K2 ERP;
* компаній, які мають CRM і хочуть імпортувати замовлення з сайту;
* складів, які мають оновлювати залишки на сайті;
* менеджерів продажів;
* e-commerce відділів;
* компаній із кількома інтернет-магазинами;
* компаній, які продають через сайт і маркетплейси одночасно. # Чи потрібно підтримувати кілька сайтів Horoshop? |-
| Price Engine
| Формує ціни для сайту. |-
| Ціни
| оновлення версій базових, акційних, роздрібних цін. | style="background:#ffcc80;" | Помаранчевий
|-
| Готовий до синхронізації
| READY_TO_SYNC
| Товар можна передавати. |-
| Delivery
| Доставка. |-
| ТТН / ЕН
| K2 ERP → Horoshop
| K2 ERP / доставка
| Інформування покупця про доставку. |-
| base_url
| varchar
| URL API. |}

 k2_product_id=product.id,

 "items": [
== 7. User Story ==
import httpx
{| class="wikitable"
|-
| AC-4
| Товар має всі обов'язкові поля. |-
| Персональні інформаційні дані в логах
| Ризик витоку даних.</syntaxhighlight>

 "delivery": {

HOROSHOP_RETRY_COUNT=3
 client = horoshop_client_factory.create(integration)
 "brand": "Example",
|-
| sku
| базовий артикул. |-
| sku
| varchar
| Артикул.=== 21.4. Пріоритети задач ===
{| class="wikitable"
 def create_or_update_product(self, payload: dict) -> "ProductResponse":
 "amount": 12999.00
 payload = {

 def update_product_stock(self, product_id: str, payload: dict) -> "StockResponse":
!</div>
 order = k2_order_repository.get_by_id(db, k2_order_id)
|-
| AC-8
| У K2 ERP змінилась ціна. # Чи потрібно синхронізувати SEO-поля? |-
| Attribute Mapper
| Мапить характеристики. |}

=== 5.5. оновлення версій статусу замовлення ===

event_type="HOROSHOP_ORDER_STATUS_EXPORTED",
db=db,

Див. 35. так само

Що зберігати

7.2. складський облік

"color": "Black",
payload=order_payload,
hs_product.status = "SYNCING"

13. Horoshop API Client

1. |-

payment_type varchar Тип оплати. Статус
horoshop_product_repository.set_sync_error(

Етап 2. Базовий Python-сервіс

23.1. Базовий Horoshop Client

22.6. horoshop_status_mappings

15.3. Синхронізація категорій

v
SEO-опис


26.2. Приклад dashboard

Імпорт у K2 ERP

11. Єдина логіка кольорів

POST /api/v1/horoshop/integrations

HOROSHOP_BASE_URL=https://example.com/api/

k2_product_id=product.id,
- updated_at timestamp }

6. Напрям

"customer": {
for order_payload in orders:
client = horoshop_client_factory.create(integration)
K2 ERP style="background:#ef9a9a;" | Червоний
# Як часто оновлювати залишки?
  • реалізувати call_api;
  • реалізувати check_connection;
  • реалізувати get_orders;
  • реалізувати update_order_status;
  • реалізувати create_or_update_product;
  • реалізувати update_price;
  • реалізувати update_stock;
  • реалізувати обробку помилок. |-
updated_at timestamp - customer_name varchar Покупець. Причина
payload=response,
horoshop_product_repository.update_stock_sync_result(

7.5. Адміністратор

- entity_type varchar - old_status varchar - оновлення версій залишків Критичний - оновлення версій статусу Старий статус, новий статус. Кожен товар, замовлення, клієнт ERP, зміна ціни, залишку, статусу і API-запит повинні мати внутрішній ID, external_id, журнал подій і захист від повторної обробки. Очікуваний результат
pass
pass
response = await client.call_api(
 v
 },
=== 23.4. оновлення версій залишку ===
! Заборонено зберігати їх у коді, Git, frontend-змінних або відкритих логах. | Він бачить товари, замовлення, ціни, залишки, помилки. # Чи потрібно приховувати товар при нульовому залишку? Враховуються резерви та страховий залишок. |-
| tracking_number
| varchar
| ТТН / ЕН. |-
| price
| numeric
| Ціна. | style="background:#ffcc80;" | Помаранчевий
|-
| Підтверджено
| CONFIRMED
| Менеджер підтвердив замовлення. |-
| AC-5
| Товар не має SKU. |-
| AC-2
| Адміністратор перевіряє підключення. Ключ
 "customer_email": order_payload.get("customer", {}).get("email"),
 payload={
 "horoshop_status": order_payload.get("status"),
 "horoshop_category_id": "h-category-001",

'''Управлінський результат:''' менеджер і керівник повинні бачити, які товари синхронізовані з Horoshop, які мають помилки, які замовлення імпортовані, які статуси передані, які залишки не оновились, які товари не мають фото, категорії або характеристик. |-
| order_number
| varchar
| Номер замовлення. Як зменшити

async def export_order_status_to_horoshop(k2_order_id: str, db: "Session") -> None:
 "customer_phone": order_payload.get("customer", {}).get("phone"),
 db=db,
 "old_price": 13999.00,
|-
| Невірні API-доступи
| інтеграційні функції ERP не працюватиме. 
== 22. Модель даних ==
=== 26.4. Проблемні замовлення ===
 "tracking_number": order.tracking_number,

! Очікуваний результат
from pydantic_settings import BaseSettings

== 25. Retry-логіка ==
<pre>
 entity_id=hs_order.id,
платформа повинна логувати:
! Поле

! |-
| created_at
| timestamp
| Дата. SEO-опис
{| class="wikitable"
Python-сервіс повинен:
 "status": horoshop_status,
'''Критично критично:''' логін і пароль API Horoshop потрібно зберігати тільки у secret storage або в зашифрованому вигляді. | Статус стає IMPORTED.<pre>

* реалізувати dashboard API;
* реалізувати список проблемних товарів;
* реалізувати список проблемних замовлень;
* реалізувати список помилок API;
* реалізувати експорт, якщо потрібно. | style="background:#ffcc80;" | Потрібна дія
|-
| Помилки API
| Технічні помилки інтеграції. |-
| Product Variant
| Варіант / модифікація товару. | Він передається в Horoshop. | Horoshop / K2 ERP
| Залежить від бізнес-логіки. Поле

 retry_count: int = 3
 "https://example.com/images/sku-001-2.jpg"
== 33. Відкриті питання ==

 )

POST /api/v1/horoshop/stocks/sync
 entity_id=hs_product.id,
 },

! Ризик
 "delivery_service": order_payload.get("delivery", {}).get("service"),
== 16. Приклад запиту на синхронізацію товару ==
 pass
{| class="wikitable"
 response = await client.call_api(
=== 26.1. Основні KPI ===
 }
2.=== 23.3. Імпорт замовлень ===
|-
| AC-15
| K2 ERP змінила статус замовлення. | Передати менеджеру каталогу. Тип
=== 29.1. інтеграційні функції ERP ===
 "quantity": available_stock,

! |-
| UnknownStatusError
| Статус не замаплений. SEO-опис
Horoshop API Client  це Python-клас або пакет, який інкапсулює роботу з API конкретного сайту Horoshop. warehouse_id=product.default_warehouse_id,
response = await client.call_api(
- api_password_encrypted text style="background:#c8e6c9;" | Зелений
Комплектується PROCESSING - k2_order_id uuid - barcode Таблиця status_mappings і ручна перевірка. Значення

</syntaxhighlight>

if not hs_order:
"sku": product.sku,
Сервіс повинен забезпечити: raise HoroshopApiError(response.text) return
style="background:#fff9c4;" | Жовтий
Імпортується IMPORTING - AttributeMappingError - CategoryMappingError }

26.3. Проблемні товари

Очікуваний результат
Категорії K2 ERP → Horoshop або Horoshop → K2 ERP Залежить від проєкту Єдина структура каталогу.
{
"k2_order_id": k2_order.id,
Дія системи

6. Основні сутності

data={

7.1. Менеджер товарного каталогу

request_payload ["login"] = self.api_login

я хочу вести товари в K2 ERP,

Нове NEW Замовлення отримано з Horoshop. api_password: str
except Exception as exc:
Повернути існуюче замовлення. |- api_login_encrypted text - Синхронізація товарів Середній - external_order_id ID замовлення Horoshop. Як керівник, Перевести в ручну перевірку. horoshop_order_repository.create_error_record(
  • повна технічна підтримка всіх API-методів Horoshop;
  • складна SEO-оптимізація товарів;
  • автоматичне створення маркетингових акцій;
  • складний UI керування каталогом;
  • інтеграційні функції ERP з усіма маркетплейсами;
  • автоматичне виправлення товарних даних;
  • ML-мапінг категорій і характеристик. Статус

щоб покупці не замовляли товар, якого немає. ! {| class="wikitable" Horoshop API Client я хочу, щоб залишки автоматизовано оновлювалися на сайті,

def authenticate(self) -> "AuthResult":
}
клієнт ERP === 29.4. Замовлення ===

22.3. horoshop_orders


 integration = horoshop_integration_repository.get_active(db)
! Дія
Python-сервіс повинен:
 "name": "Смартфон Example X 128GB",
[[Категорія:E-commerce]]
! Код
! external_order_id=external_order_id,

* реалізувати Product Mapper;
* реалізувати Category Mapper;
* реалізувати Attribute Mapper;
* реалізувати валідацію;
* реалізувати Product Sync Worker. |-
| Retry
| Причина, кількість спроб, результат. | Помилки мапінгу, неповні товари, review. K2 ERP / Dashboard / Менеджери

* реалізувати Price Engine;
* реалізувати Stock Engine;
* реалізувати чергу оновлення версій;
* реалізувати історію змін. |-
| order_id
| uuid
| Замовлення. Товар проходить валідацію. # Чи потрібно імпортувати категорії з Horoshop? Результат записується в журнал. | style="background:#c8e6c9;" | Норма
|-
| Помилки товарів
| Товари з помилками валідації або API. | style="background:#eeeeee;" | Сірий
|-
| Помилка синхронізації
| SYNC_ERROR
| API повернув помилку або товар не передано. | style="background:#ef9a9a;" | Червоний
|}

=== Етап 8. Dashboard та аудит ===

=== 22.4. horoshop_order_items ===
{| class="wikitable"
 )
K2 ERP виступає як головним джерелом товарного каталогу. |-
| Синхронізація товару
| SKU, статус, відповідь API. SEO-опис
 existing = horoshop_order_repository.get_by_external_id(

 url = f"{self.base_url}/{function.strip('/')}/"
 request_payload = payload or {}
integration = horoshop_integration_repository.get_active(db)

20.1. Дедублікація товарів

До MVP входить:

- StockError style="background:#c8e6c9;" | Зелений
Відправлено SHIPPED - external_order_id varchar API error, sync error. | style="background:#bbdefb;" | Блакитний
Очікує оплати WAITING_PAYMENT style="background:#bbdefb;" | Блакитний
Імпортовано IMPORTED Передати менеджеру каталогу. Поле
)
product_id=product_id,
Помилка

<syntaxhighlight lang="json">
db.commit() щоб опрацьовувати всі продажі та реалізація в єдиній системі. Критерій "category_id": "phones",
id uuid - AC-9 У K2 ERP змінився залишок. HTTP/HTTPS API Horoshop async def call_api(self, function: str, payload: dict | None = None) -> dict: entity_type="product", }

5.1. Передача товарів з K2 ERP у Horoshop

hs_product.status = "SYNCED"

22.1. horoshop_integrations

20. Дедублікація

function="orders/update_status/",
id uuid - k2_product_id uuid ID товару K2 ERP. Критерій finally: hs_product.last_synced_stock = product.available_stock hs_product.horoshop_product_id = response.get("product_id") or hs_product.horoshop_product_id SEO title: Технічне завдання: Інтеграція з Horoshop / Хорошоп для Python SEO keywords: Python, Horoshop, Хорошоп, Horoshop API, Хорошоп API, інтеграція інтернет-магазину, K2 ERP, CRM, WMS, товари, замовлення, ціни, залишки, FastAPI, ecommerce
</noinclude>
 {{SEO
Шаблон для службового SEO-опису сторінки. 

}}


4. Передумови

15. API Python-сервісу

async def sync_product_to_horoshop(product_id: str, db: "Session") -> None:

- name varchar - raw_response jsonb Відповідь API.== 8. Напрями синхронізації ==
"warehouse": "Відділення №1",
Активні товари 12 450 інформаційні матеріали
Синхронізовано 12 100 Норма
Потребують виправлення 180 Потрібна дія
Помилки синхронізації 24 Критично
Оновлено цін сьогодні 820 Норма
Оновлено залишків сьогодні 1 540 Норма
Нові замовлення 42 Увага
Імпортовано замовлень 39 Норма
Замовлення на перевірці 3 Потрібна дія
) )
- customer_email varchar Email. async def import_horoshop_orders(db: "Session") -> None: <syntaxhighlight lang="python"> Horoshop виступає як джерелом замовлень, які створюють покупці на сайті. |- Незамаплений статус платформа повертає успішний або помилковий статус. |- Створення клієнта Замовлення переходить у NEEDS_REVIEW. |} "raw_payload": order_payload,
<syntaxhighlight lang="json">
 "memory": "128GB",
 hs_product = horoshop_product_repository.get_or_create(
id uuid Воно імпортується в K2 ERP. SEO-опис

9. Статуси товарів

20.2. Дедублікація замовлень

def create_or_update_category(self, payload: dict) -> "CategoryResponse":

15.11. Dashboard

Нові замовлення, очікування оплати. K2 ERP отримує статус. |} 3. Тому для кожного сайту потрібно зберігати власний base_url, логін, пароль, статус інтеграції, правила синхронізації та технічний журнал.