Технічне завдання: передача документів для звітності в податкову через Edin для Python
Головна ідея: розробити Python-сервіс, який інтегрує K2 ERP або іншу облікову систему з платформою EDIN для передачі електронних документів, податкових накладних, первинних документів, супровідних файлів та документів, пов'язаних із податковою звітністю.
Критично важливо: перед початком розробки потрібно підтвердити у EDIN, які саме типи документів можуть передаватись через API у конкретному акаунті: податкові накладні, первинні документи, структуровані документи DocFlow, EDI-документи, е-ТТН або саме податкова звітність до ДПС.
Важливо: EDIN не слід автоматично вважати універсальним каналом подання всіх декларацій до ДПС. Для класичної податкової звітності потрібно окремо перевіряти, чи підтримує EDIN потрібний сценарій передачі, підписання, отримання квитанцій та статусів.
Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker.
Управлінський результат: керівник або бухгалтер повинен бачити, які документи сформовано, які підписано, які передано в EDIN, які прийнято, які відхилено, які очікують підпису або дії користувача.
1. Мета
Метою задачі є створення Python-сервісу для інтеграції з EDIN з метою передачі електронних документів, які використовуються у процесах податкового, бухгалтерського та юридично значущого документообігу.
Сервіс повинен забезпечити:
- формування електронного документа у внутрішній системі;
- валідацію документа перед передачею;
- підготовку XML / JSON / PDF / XLSX / вкладень;
- підписання КЕП або передачу документа на підписання;
- відправку документа в EDIN;
- отримання статусу документа;
- отримання підтверджень, квитанцій або службових повідомлень, якщо доступні;
- збереження ID документа EDIN;
- збереження історії зміни статусів;
- повторну передачу документа після технічної помилки;
- захист від дублювання;
- передачу статусу назад у K2 ERP;
- формування dashboard для контролю.
2. Область застосування
Інтеграція може використовуватись для:
- передачі податкових накладних;
- передачі розрахунків коригування;
- передачі первинних документів;
- передачі актів, рахунків, видаткових накладних;
- передачі структурованих документів через EDIN DocFlow;
- передачі EDI-документів;
- передачі е-ТТН, якщо використовується відповідний API EDIN;
- передачі документів між контрагентами;
- підготовки пакета документів, які потрібні бухгалтеру для податкової звітності;
- контролю статусів підписання та доставки документів.
Важливо: якщо бізнес-процес передбачає саме подання декларацій до ДПС, потрібно окремо підтвердити, що EDIN API підтримує цей тип звітності. Якщо не підтримує — EDIN використовується для ЕДО та первинних документів, а податкова звітність подається через інший канал.
3. Джерела інтеграції
| Компонент | Призначення | Коментар |
|---|---|---|
| EDIN | Платформа електронного документообігу. | Основний зовнішній сервіс. |
| EDIN DocFlow API | API для роботи зі структурованими документами, компаніями, статусами та списками документів. | Використовується, якщо підключено DocFlow. |
| EDIN EDI Network | Платформа для EDI-документообігу з контрагентами. | Використовується для ORDER, DESADV, INVOICE та інших EDI-документів. |
| EDIN Tax Invoice / Податкова накладна | Сценарій роботи з електронною податковою накладною на платформі EDIN. | Потрібно перевірити конкретний API та тип документа. |
| Python Integration Service | Інтеграційний шар між K2 ERP та EDIN. | Реалізується в межах цього ТЗ. |
| K2 ERP / ERP / CRM | Джерело документів, контрагентів, статусів і задач. | Внутрішня система замовника. |
4. Передумови
Для реалізації задачі необхідно отримати:
- акаунт EDIN;
- доступ до EDIN API або EDIN DocFlow API;
- тестове середовище або тестову компанію, якщо доступно;
- логін / пароль або API token;
- дані компанії-відправника;
- дані контрагентів;
- перелік типів документів, які потрібно передавати;
- XML / JSON-специфікації документів;
- правила підписання;
- КЕП / ЕЦП або сценарій делегованого підписання;
- вимоги до вкладень;
- правила отримання статусів;
- правила отримання квитанцій;
- правила повторної відправки;
- контакт технічної підтримки EDIN.
Критично важливо: без офіційної API-документації EDIN для конкретного продукту не можна фіксувати production endpoint-и, назви методів і формати payload як остаточні. У цьому ТЗ endpoint-и Python-сервісу є внутрішніми, а EDIN endpoint-и мають уточнюватись за документацією EDIN.
5. Варіанти інтеграції
5.1. Варіант 1. EDIN DocFlow API
Python-сервіс створює або передає структуровані документи через DocFlow API.
| Параметр | Опис |
|---|---|
| Підходить для | Юридично значущих документів, актів, рахунків, договорів, первинних документів. |
| Переваги | Робота зі статусами, компаніями, документами, структурованими даними. |
| Обмеження | Потрібно перевірити доступність конкретних типів документів. |
| Основні операції | Створення документа, редагування, зміна статусу, отримання списку документів. |
5.2. Варіант 2. EDI Network API
Python-сервіс передає EDI-документи між компаніями та торговельними мережами.
| Параметр | Опис |
|---|---|
| Підходить для | ORDER, ORDRSP, DESADV, INVOICE, COMDOC, e-ТТН та інших EDI-сценаріїв. |
| Переваги | Стандартизований обмін документами з контрагентами. |
| Обмеження | Документ залежить від схеми конкретної мережі або контрагента. |
| Основні операції | Формування XML, передача, отримання статусу, отримання відповіді контрагента. |
5.3. Варіант 3. Податкові накладні через EDIN
Python-сервіс формує або передає документи, пов'язані з електронною податковою накладною.
| Параметр | Опис |
|---|---|
| Підходить для | Податкових накладних, розрахунків коригування, пов'язаних документів. |
| Переваги | Можливість працювати з податковими документами в одному ЕДО-середовищі. |
| Обмеження | Потрібно підтвердити формат API, підписання, статуси та квитанції. |
| Основні операції | Підготовка документа, підписання, передача, статуси, квитанції. |
5.4. Варіант 4. Гібридна схема
K2 ERP передає різні типи документів через різні API EDIN.
| Тип документа | Канал |
|---|---|
| Первинні документи | EDIN DocFlow. |
| EDI-документи | EDI Network. |
| Податкові накладні | EDIN-сценарій податкових накладних, якщо доступний. |
| е-ТТН | EDIN ETTN API, якщо підключено. |
| Податкові декларації | Окремо підтверджується; за потреби використовується інший канал. |
6. Основні сутності
| Сутність | Опис |
|---|---|
| Integration Account | Обліковий запис інтеграції EDIN. |
| Organization | Компанія-відправник або отримувач. |
| Counterparty | Контрагент. |
| Document Type | Тип документа: податкова накладна, акт, рахунок, EDI-документ тощо. |
| Document | Внутрішній документ K2 ERP. |
| EDIN Document | Документ, створений або переданий в EDIN. |
| Attachment | Вкладення: PDF, XML, XLSX, скан, архів. |
| Signature | Підпис КЕП / ЕЦП. |
| Status | Статус документа в K2 ERP та EDIN. |
| Receipt / Confirmation | Квитанція, підтвердження або службове повідомлення. |
| API Event | Подія інтеграції. |
7. User Story
7.1. Передача документа
Як бухгалтер, я хочу натиснути кнопку «Передати через EDIN», щоб документ із K2 ERP був сформований, перевірений, підписаний і переданий в EDIN.
7.2. Підписання
Як відповідальна особа, я хочу бачити документи, які очікують підпису, щоб підписати їх КЕП перед відправкою.
7.3. Контроль статусів
Як бухгалтер, я хочу бачити статус документа після відправки, щоб знати, чи документ прийнятий, відхилений, доставлений або очікує дії.
7.4. Повторна передача
Як адміністратор, я хочу повторити передачу після технічної помилки, щоб не створювати документ вручну повторно.
7.5. Dashboard керівника
Як керівник бухгалтерської компанії, я хочу бачити загальну картину по документах EDIN, щоб контролювати прострочені, відхилені, непідписані та проблемні документи.
8. Типи документів
8.1. Основні типи документів для MVP
| Тип документа | Код | Формат | Канал | Важливість |
|---|---|---|---|---|
| Податкова накладна | TAX_INVOICE | XML / структурований документ | EDIN Tax Invoice / DocFlow, якщо доступно | Критична |
| Розрахунок коригування | TAX_ADJUSTMENT | XML / структурований документ | EDIN Tax Invoice / DocFlow, якщо доступно | Критична |
| Акт виконаних робіт | ACT | XML / PDF / структурований | EDIN DocFlow | Важлива |
| Рахунок | INVOICE | XML / PDF / структурований | EDIN DocFlow / EDI Network | Додаткова |
| Видаткова накладна | EXPENSE_INVOICE | XML / PDF / структурований | EDIN DocFlow / EDI Network | Важлива |
| ТТН / е-ТТН | ETTN | XML / структурований | EDIN ETTN API, якщо підключено | Важлива |
| Договір | CONTRACT | PDF / структурований | EDIN DocFlow | Додаткова |
| Довільний файл | FILE | PDF / XLSX / DOCX / ZIP | EDIN DocFlow, якщо підтримується | Супровідна |
Критично важливо: для кожного типу документа потрібно окремо зберігати схему, канал передачі, правила підписання, допустимі вкладення та правила отримання статусу.
9. Статуси документів
| Статус | Код | Опис | Колір |
|---|---|---|---|
| Чернетка | DRAFT | Документ створено в K2 ERP, але ще не готовий до передачі. | Сірий |
| Готовий до перевірки | READY_FOR_REVIEW | Документ сформований і очікує перевірки. | Блакитний |
| Потребує виправлення | NEEDS_CORRECTION | Виявлено помилки у документі. | Помаранчевий |
| Очікує підпису | WAITING_SIGNATURE | Документ готовий, але ще не підписаний. | Жовтий |
| Підписано | SIGNED | Документ підписано КЕП. | Зелений |
| Очікує відправки | PENDING_SEND | Документ у черзі передачі. | Жовтий |
| Відправляється | SENDING | Виконується API-запит до EDIN. | Блакитний |
| Передано в EDIN | SENT_TO_EDIN | Документ переданий у EDIN, очікується фінальний статус. | Блакитний |
| Доставлено | DELIVERED | Документ доставлений отримувачу або системі. | Зелений |
| Прийнято | ACCEPTED | Документ прийнятий. | Зелений |
| Відхилено | REJECTED | Документ відхилено. | Червоний |
| Помилка передачі | SEND_ERROR | Технічна помилка передачі. | Червоний |
| Потребує повтору | NEEDS_RETRY | Документ можна передати повторно. | Помаранчевий |
| Скасовано | CANCELLED | Документ скасовано користувачем. | Сірий |
10. Єдина логіка кольорів
| Колір | HTML | Значення | Де використовується |
|---|---|---|---|
| Зелений | #c8e6c9 | Успішно: підписано, доставлено, прийнято. | Список документів, dashboard, картка документа. |
| Блакитний | #bbdefb | Документ у роботі або передається. | Черга, статус API. |
| Жовтий | #fff9c4 | Очікування дії: підпис, відправка, перевірка. | Черга підпису, календар задач. |
| Помаранчевий | #ffcc80 | Потрібна дія користувача або повтор. | Помилки валідації, retry. |
| Червоний | #ef9a9a | Відхилено або критична помилка. | Dashboard, проблемні документи. |
| Фіолетовий | #f3e5f5 | Спеціальний або індивідуальний документ. | е-ТТН, нестандартні документи, ручні сценарії. |
| Сірий | #eeeeee | Чернетка, скасовано або не застосовується. | Списки, архів. |
11. Архітектура рішення
11.1. Загальна схема
K2 ERP / ERP / CRM
|
| 1. Формування документа
v
Python EDIN Integration Service
|
| 2. Валідація, мапінг, підготовка файлів
v
Signature Service / KEP Module
|
| 3. Підписання або передача на підпис
v
Python EDIN Client
|
| 4. API EDIN / DocFlow / EDI Network
v
EDIN
|
| 5. Доставка / обробка / статуси
v
Python Status Sync Worker
|
| 6. Оновлення статусів
v
K2 ERP / Dashboard / Задачі відповідальних
11.2. Основні компоненти Python-сервісу
| Компонент | Опис |
|---|---|
| API Layer | REST API для прийому документів із K2 ERP. |
| Document Validator | Перевіряє обов'язкові поля, суми, контрагентів, формати. |
| Document Mapper | Перетворює документ K2 ERP у формат EDIN. |
| Signature Adapter | Підписує документ або передає його на підписання. |
| EDIN Client | Python-клієнт для API EDIN. |
| Document Queue | Черга відправки документів. |
| Status Sync Worker | Періодично синхронізує статуси з EDIN. |
| Receipt Collector | Завантажує квитанції, підтвердження, службові повідомлення. |
| Audit Logger | Зберігає всі дії, запити, відповіді та помилки. |
| Dashboard API | Видає статистику по документах, статусах і помилках. |
12. EDIN Client
12.1. Призначення
EDIN Client — це Python-клас або пакет, який інкапсулює роботу з EDIN API.
12.2. Основні методи
class EdinClient:
def check_connection(self) -> "ConnectionStatus":
pass
def authenticate(self) -> "AuthResult":
pass
def refresh_token(self) -> "AuthResult":
pass
def create_document(self, payload: "EdinDocumentPayload") -> "EdinDocumentResponse":
pass
def update_document(self, edin_document_id: str, payload: "EdinDocumentPayload") -> "EdinDocumentResponse":
pass
def upload_attachment(self, edin_document_id: str, file: bytes, filename: str) -> "AttachmentResponse":
pass
def send_document(self, edin_document_id: str) -> "SendDocumentResponse":
pass
def get_document_status(self, edin_document_id: str) -> "DocumentStatusResponse":
pass
def get_document(self, edin_document_id: str) -> "EdinDocumentResponse":
pass
def get_document_list(self, filters: dict) -> "DocumentListResponse":
pass
def download_receipt(self, edin_document_id: str, receipt_id: str) -> bytes:
pass
def cancel_document(self, edin_document_id: str, reason: str) -> "CancelDocumentResponse":
pass
Важливо: назви методів у Python-клієнті є внутрішньою абстракцією. Реальні EDIN API endpoint-и потрібно підставити з офіційної документації EDIN для конкретного продукту: DocFlow, EDI Network, ETTN або податкові накладні.
12.3. Конфігурація клієнта
from pydantic_settings import BaseSettings
class EdinSettings(BaseSettings):
base_url: str
auth_url: str | None = None
api_login: str | None = None
api_password: str | None = None
api_token: str | None = None
company_id: str
integration_mode: str = "docflow"
timeout_seconds: int = 30
retry_count: int = 3
retry_backoff_seconds: int = 5
verify_ssl: bool = True
Приклад `.env`:
EDIN_BASE_URL=https://api.example.edin EDIN_AUTH_URL=https://api.example.edin/auth EDIN_API_LOGIN=******** EDIN_API_PASSWORD=******** EDIN_API_TOKEN=******** EDIN_COMPANY_ID=company-001 EDIN_INTEGRATION_MODE=docflow EDIN_TIMEOUT_SECONDS=30 EDIN_RETRY_COUNT=3 EDIN_RETRY_BACKOFF_SECONDS=5
Заборонено: зберігати логін, пароль, API token, КЕП, пароль до КЕП або інші секрети у коді, Git-репозиторії, відкритих логах або frontend-змінних.
13. API Python-сервісу
13.1. Створення інтеграції
POST /api/v1/edin/integrations
13.2. Перевірка підключення
POST /api/v1/edin/integrations/{integration_id}/check-connection
13.3. Створення документа
POST /api/v1/edin/documents
13.4. Передача документа в EDIN
POST /api/v1/edin/documents/{document_id}/send
13.5. Підписання документа
POST /api/v1/edin/documents/{document_id}/sign
13.6. Завантаження вкладення
POST /api/v1/edin/documents/{document_id}/attachments
13.7. Синхронізація статусу
POST /api/v1/edin/documents/{document_id}/sync-status
13.8. Повторна відправка
POST /api/v1/edin/documents/{document_id}/retry
13.9. Отримання квитанцій
GET /api/v1/edin/documents/{document_id}/receipts
13.10. Dashboard
GET /api/v1/edin/dashboard?date_from=2026-05-01&date_to=2026-05-31
14. Приклад запиту на створення документа
{
"external_document_id": "K2-TAX-INVOICE-2026-000123",
"idempotency_key": "K2-TAX-INVOICE-2026-000123-v1",
"document_type": "TAX_INVOICE",
"organization_id": "org-001",
"counterparty_id": "counterparty-001",
"document_number": "123",
"document_date": "2026-05-07",
"currency": "UAH",
"total_amount": 12000.00,
"vat_amount": 2000.00,
"payload_format": "xml",
"payload": {
"xml_file_id": "file-001"
},
"attachments": [
{
"filename": "tax_invoice_123.xml",
"content_type": "application/xml",
"file_id": "file-001"
},
{
"filename": "tax_invoice_123.pdf",
"content_type": "application/pdf",
"file_id": "file-002"
}
],
"signing_required": true,
"send_after_signing": true
}
15. Валідація документа
Перед відправкою система повинна перевірити:
- наявність external_document_id;
- наявність idempotency_key;
- тип документа;
- організацію-відправника;
- контрагента;
- ЄДРПОУ / ІПН / податковий номер сторін;
- дату документа;
- номер документа;
- валюту;
- суму;
- ПДВ, якщо застосовується;
- формат XML / JSON / PDF;
- відповідність схемі документа;
- наявність обов'язкових вкладень;
- наявність КЕП або сценарію підписання;
- чи не був документ уже відправлений;
- чи дозволений повтор для поточного статусу.
Критично важливо: документ зі статусом ACCEPTED або DELIVERED не можна автоматично відправляти повторно. Повторна відправка дозволена тільки для технічних помилок або спеціальних статусів, визначених бізнес-правилами.
16. Підписання КЕП
16.1. Сценарії підписання
| Сценарій | Опис | Коментар |
|---|---|---|
| Підписання в K2 ERP | Документ підписується до передачі в EDIN. | Потрібен модуль КЕП у K2 ERP. |
| Підписання в Python-сервісі | Python-сервіс викликає внутрішній Signature Service. | Потрібно безпечно зберігати ключі або використовувати HSM/хмарний КЕП. |
| Підписання в EDIN | Документ передається в EDIN і підписується користувачем на платформі. | Потрібно підтвердити підтримку цього сценарію для типу документа. |
| Делеговане підписання | Підписує відповідальна особа після отримання задачі. | Потрібен workflow задач. |
16.2. Статуси підписання
| Статус | Код | Колір | Опис |
|---|---|---|---|
| Не потребує підпису | SIGN_NOT_REQUIRED | Сірий | Документ не потребує КЕП. |
| Очікує підпису | WAITING_SIGNATURE | Жовтий | Документ очікує підписання. |
| Підписується | SIGNING | Блакитний | Виконується підписання. |
| Підписано | SIGNED | Зелений | КЕП накладено. |
| Помилка підпису | SIGN_ERROR | Червоний | Підписання не виконано. |
17. Дедублікація
Система повинна не допускати дублювання документів.
Ключі дедублікації:
| Ключ | Призначення |
|---|---|
| external_document_id | ID документа у K2 ERP. |
| idempotency_key | Унікальний ключ конкретної версії відправки. |
| document_hash | Hash XML/JSON/PDF документа. |
| document_number + document_date + organization_id + counterparty_id | Бізнес-ключ документа. |
Приклад hash:
sha256(document_type + document_number + document_date + total_amount + organization_tax_id + counterparty_tax_id)
18. Черга передачі
Для надійності передача документів повинна виконуватись через чергу.
18.1. Логіка черги
1. K2 ERP створює документ. 2. Python-сервіс виконує валідацію. 3. Документ отримує статус READY_FOR_REVIEW або WAITING_SIGNATURE. 4. Після підпису документ переходить у PENDING_SEND. 5. Worker відправляє документ у EDIN. 6. EDIN повертає ID документа або технічну відповідь. 7. Python-сервіс зберігає EDIN ID. 8. Status Sync Worker періодично оновлює статус. 9. Квитанції та підтвердження зберігаються в картці документа. 10. K2 ERP отримує фінальний статус.
18.2. Пріоритети задач
| Тип задачі | Пріоритет | Коментар |
|---|---|---|
| Податкова накладна | Критичний | Впливає на податковий облік. |
| Розрахунок коригування | Критичний | Впливає на ПДВ та реєстрацію. |
| Первинний документ | Високий | Важливий для бухгалтерії. |
| е-ТТН | Високий | Важливий для логістики. |
| Довільний файл | Середній | Супровідний документ. |
| Синхронізація статусів | Середній | Фоновий процес. |
| Завантаження квитанцій | Середній | Не блокує первинну відправку. |
19. Модель даних
19.1. edin_integrations
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID інтеграції. |
| provider | varchar | edin. |
| integration_mode | varchar | docflow, edi_network, tax_invoice, ettn, hybrid. |
| name | varchar | Назва інтеграції. |
| base_url | varchar | URL API. |
| api_login_encrypted | text | Зашифрований логін. |
| api_password_encrypted | text | Зашифрований пароль. |
| api_token_encrypted | text | Зашифрований token. |
| company_id | varchar | ID компанії в EDIN. |
| is_active | boolean | Активність. |
| created_at | timestamp | Дата створення. |
| updated_at | timestamp | Дата оновлення. |
19.2. edin_document_types
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID типу документа. |
| code | varchar | TAX_INVOICE, ACT, INVOICE, ETTN тощо. |
| name | varchar | Назва типу документа. |
| integration_mode | varchar | Через який канал передається. |
| payload_format | varchar | XML, JSON, PDF, mixed. |
| schema_version | varchar | Версія схеми. |
| requires_signature | boolean | Чи потрібен КЕП. |
| requires_attachments | boolean | Чи потрібні вкладення. |
| is_active | boolean | Активність. |
19.3. edin_documents
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | Внутрішній ID документа. |
| integration_id | uuid | ID інтеграції. |
| document_type_id | uuid | Тип документа. |
| external_document_id | varchar | ID документа в K2 ERP. |
| edin_document_id | varchar | ID документа в EDIN. |
| idempotency_key | varchar | Ключ дедублікації. |
| document_number | varchar | Номер документа. |
| document_date | date | Дата документа. |
| organization_id | uuid | Організація-відправник. |
| counterparty_id | uuid | Контрагент. |
| status | varchar | Поточний статус. |
| signing_status | varchar | Статус підписання. |
| total_amount | numeric | Загальна сума. |
| vat_amount | numeric | Сума ПДВ. |
| payload_format | varchar | XML, JSON, PDF. |
| payload_hash | varchar | Hash документа. |
| raw_request | jsonb | Запит до EDIN. |
| raw_response | jsonb | Відповідь EDIN. |
| error_message | text | Остання помилка. |
| sent_at | timestamp | Дата передачі. |
| accepted_at | timestamp | Дата прийняття. |
| created_at | timestamp | Дата створення. |
19.4. edin_attachments
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID вкладення. |
| document_id | uuid | ID документа. |
| filename | varchar | Назва файлу. |
| content_type | varchar | MIME type. |
| file_size | integer | Розмір файлу. |
| file_hash | varchar | Hash файлу. |
| storage_path | varchar | Шлях у сховищі. |
| edin_attachment_id | varchar | ID вкладення в EDIN. |
| created_at | timestamp | Дата створення. |
19.5. edin_receipts
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID квитанції. |
| document_id | uuid | ID документа. |
| receipt_type | varchar | Квитанція, підтвердження, службове повідомлення. |
| external_receipt_id | varchar | ID квитанції в EDIN. |
| status | varchar | Статус квитанції. |
| received_at | timestamp | Дата отримання. |
| file_id | uuid | Файл квитанції. |
| raw_payload | jsonb | Дані квитанції. |
19.6. edin_events
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID події. |
| document_id | uuid | ID документа. |
| event_type | varchar | Тип події. |
| old_status | varchar | Попередній статус. |
| new_status | varchar | Новий статус. |
| source | varchar | K2_ERP, PYTHON_SERVICE, EDIN, USER. |
| payload | jsonb | Технічні дані. |
| created_at | timestamp | Дата події. |
20. Приклад Python-логіки
20.1. Створення документа
from datetime import datetime, timezone
def create_edin_document(command: "CreateEdinDocumentCommand", db: "Session") -> "EdinDocument":
existing = edin_document_repository.get_by_idempotency_key(
db=db,
idempotency_key=command.idempotency_key,
)
if existing:
return existing
document_validator.validate(command)
payload_hash = document_hash_service.calculate(command.payload)
document = edin_document_repository.create(
db=db,
data={
"external_document_id": command.external_document_id,
"idempotency_key": command.idempotency_key,
"document_number": command.document_number,
"document_date": command.document_date,
"document_type_id": command.document_type_id,
"organization_id": command.organization_id,
"counterparty_id": command.counterparty_id,
"status": "DRAFT",
"signing_status": "WAITING_SIGNATURE" if command.signing_required else "SIGN_NOT_REQUIRED",
"total_amount": command.total_amount,
"vat_amount": command.vat_amount,
"payload_format": command.payload_format,
"payload_hash": payload_hash,
"raw_request": command.model_dump(),
},
)
audit_logger.log(
document_id=document.id,
event_type="DOCUMENT_CREATED",
new_status=document.status,
payload={"external_document_id": command.external_document_id},
)
db.commit()
return document
20.2. Відправка документа
def send_edin_document(document_id: str, db: "Session") -> None:
document = edin_document_repository.get_by_id(db, document_id)
if document.status in ["ACCEPTED", "DELIVERED"]:
return
if document.signing_status == "WAITING_SIGNATURE":
raise BusinessError("Document must be signed before sending")
try:
document.status = "SENDING"
db.commit()
payload = edin_mapper.to_edin_payload(document)
response = edin_client.create_document(payload)
document.edin_document_id = response.document_id
document.raw_response = response.raw_payload
document.status = "SENT_TO_EDIN"
document.sent_at = datetime.now(timezone.utc)
audit_logger.log(
document_id=document.id,
event_type="DOCUMENT_SENT_TO_EDIN",
old_status="SENDING",
new_status="SENT_TO_EDIN",
payload={"edin_document_id": response.document_id},
)
except TemporaryEdinError as exc:
document.status = "NEEDS_RETRY"
document.error_message = str(exc)
except Exception as exc:
document.status = "SEND_ERROR"
document.error_message = str(exc)
finally:
db.commit()
20.3. Синхронізація статусів
def sync_edin_document_status(document_id: str, db: "Session") -> None:
document = edin_document_repository.get_by_id(db, document_id)
if not document.edin_document_id:
return
status_response = edin_client.get_document_status(document.edin_document_id)
old_status = document.status
new_status = status_mapper.from_edin(status_response.status)
if old_status != new_status:
document.status = new_status
if new_status == "ACCEPTED":
document.accepted_at = datetime.now(timezone.utc)
audit_logger.log(
document_id=document.id,
event_type="DOCUMENT_STATUS_SYNCED",
old_status=old_status,
new_status=new_status,
payload=status_response.raw_payload,
)
db.commit()
21. Обробка помилок
21.1. Типи помилок
| Тип помилки | Опис | Дія системи |
|---|---|---|
| ValidationError | Некоректні дані документа. | Не відправляти документ, показати список помилок. |
| AuthError | Невірні облікові дані EDIN. | Зупинити інтеграцію, повідомити адміністратора. |
| SignatureError | Помилка підписання. | Перевести в SIGN_ERROR. |
| SchemaError | Документ не відповідає XML/JSON-схемі. | Перевести в NEEDS_CORRECTION. |
| CounterpartyError | Контрагент не знайдений або не має потрібного ідентифікатора. | Перевести в NEEDS_CORRECTION. |
| SendError | API EDIN повернув помилку. | Зберегти raw-відповідь. |
| TimeoutError | Перевищено час очікування. | Перевести в NEEDS_RETRY. |
| DuplicateDocumentError | Документ уже існує. | Повернути існуючий документ. |
| ReceiptError | Помилка отримання квитанції. | Не змінювати фінальний статус без перевірки. |
21.2. Retry-логіка
Retry дозволений для:
- timeout;
- HTTP 429;
- HTTP 500;
- HTTP 502;
- HTTP 503;
- HTTP 504;
- тимчасової недоступності EDIN;
- тимчасової помилки отримання статусу;
- тимчасової помилки завантаження квитанції.
Retry заборонений для:
- помилок валідації;
- неправильного логіна / пароля / token;
- помилки КЕП;
- невідповідності схемі документа;
- документа, який уже прийнято;
- документа, який явно відхилено через бізнес-помилки.
22. Dashboard керівника
22.1. Основні KPI
| KPI | Опис | Колір |
|---|---|---|
| Документів створено | Загальна кількість документів за період. | Інформація |
| Очікують підпису | Документи без підпису. | Увага |
| Передано в EDIN | Документи, які вже відправлені. | В роботі |
| Прийнято | Успішно прийняті документи. | Норма |
| Відхилено | Документи з негативним статусом. | Критично |
| Потребують повтору | Технічні помилки, які можна повторити. | Потрібна дія |
| Без квитанції | Документи без підтвердження. | Контроль |
22.2. Приклад dashboard
| Показник | Значення | Стан |
|---|---|---|
| Документів за місяць | 1840 | Інформація |
| Очікують підпису | 43 | Увага |
| Передано в EDIN | 1290 | В роботі |
| Прийнято | 1218 | Норма |
| Відхилено | 12 | Критично |
| Потребують повтору | 18 | Потрібна дія |
22.3. Проблемні документи
| Дата | Документ | Організація | Контрагент | Статус | Помилка | Дія |
|---|---|---|---|---|---|---|
| 07.05.2026 | Податкова накладна №123 | ТОВ «Альфа» | ТОВ «Бета» | Відхилено | Помилка схеми XML | Виправити |
| 07.05.2026 | Акт №45 | ТОВ «Альфа» | ТОВ «Гамма» | Очікує підпису | Немає КЕП відповідального | Підписати |
| 07.05.2026 | е-ТТН №77 | ТОВ «Логістика» | ТОВ «Покупець» | Потребує повтору | Timeout EDIN API | Повторити |
23. Безпека
Система повинна забезпечити:
- зберігання EDIN credentials тільки у secret storage або в зашифрованому вигляді;
- заборону логування паролів, token, ключів КЕП;
- маскування персональних даних;
- HTTPS для всіх API-запитів;
- перевірку SSL;
- рольову модель доступу;
- окремі права на підписання;
- окремі права на повторну відправку;
- окремі права на скасування документа;
- журнал усіх дій;
- захист від дублювання документів;
- контроль доступу до вкладень;
- обмеження розміру файлів;
- антивірусну перевірку вкладень, якщо потрібно.
24. Логування та аудит
Система повинна логувати:
| Подія | Що зберігати |
|---|---|
| Створення документа | Тип, номер, дата, організація, контрагент. |
| Валідація | Результат, список помилок. |
| Підписання | Хто підписав, коли, результат. |
| Відправка в EDIN | Час, endpoint, request_id, EDIN document ID. |
| Отримання статусу | Старий статус, новий статус, джерело. |
| Отримання квитанції | Тип квитанції, час, файл. |
| Помилка передачі | Код, повідомлення, raw-відповідь. |
| Повторна відправка | Хто запустив, причина, результат. |
| Скасування | Хто скасував, причина. |
25. Acceptance Criteria
25.1. Інтеграція
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-1 | Адміністратор створює інтеграцію EDIN. | Інтеграція зберігається в системі. |
| AC-2 | Адміністратор перевіряє підключення. | Система повертає успішний або помилковий статус. |
| AC-3 | Облікові дані неправильні. | Система показує AuthError і не відправляє документи. |
25.2. Документи
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-4 | K2 ERP створює документ. | Python-сервіс створює запис зі статусом DRAFT. |
| AC-5 | Документ проходить валідацію. | Статус змінюється на READY_FOR_REVIEW або WAITING_SIGNATURE. |
| AC-6 | Документ потребує підпису. | Без підпису він не відправляється. |
| AC-7 | Документ підписано. | Статус підписання змінюється на SIGNED. |
| AC-8 | Документ відправлено в EDIN. | Зберігається EDIN document ID. |
25.3. Статуси та квитанції
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-9 | EDIN повертає новий статус. | Python-сервіс оновлює статус у K2 ERP. |
| AC-10 | EDIN повертає квитанцію. | Квитанція зберігається в картці документа. |
| AC-11 | Документ відхилено. | Статус підсвічується червоним. |
| AC-12 | Документ прийнято. | Статус підсвічується зеленим. |
25.4. Дедублікація та повтор
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-13 | Повторний запит має той самий idempotency_key. | Другий документ не створюється. |
| AC-14 | EDIN API тимчасово недоступний. | Документ переходить у NEEDS_RETRY. |
| AC-15 | Користувач запускає retry. | Система повторює передачу без дублювання. |
| AC-16 | Документ уже прийнятий. | Повторна відправка блокується. |
25.5. Dashboard
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-17 | Керівник відкриває dashboard. | Він бачить кількість створених, підписаних, відправлених, прийнятих і відхилених документів. |
| AC-18 | Є відхилені документи. | Вони підсвічуються червоним. |
| AC-19 | Є документи без підпису. | Вони підсвічуються жовтим. |
| AC-20 | Є документи, що потребують повтору. | Вони підсвічуються помаранчевим. |
26. MVP
До MVP входить:
- створення інтеграції EDIN;
- перевірка підключення;
- довідник типів документів;
- створення документа;
- валідація документа;
- завантаження вкладень;
- базовий сценарій підписання або статус «очікує підпису»;
- передача документа в EDIN;
- збереження EDIN document ID;
- синхронізація статусу;
- отримання квитанцій, якщо доступно через API;
- дедублікація;
- retry-механізм;
- журнал подій;
- dashboard API;
- базові unit-тести;
- mock EDIN API для інтеграційних тестів.
До MVP не входить:
- автоматичне подання всіх декларацій до ДПС без підтвердження EDIN API;
- повна підтримка всіх документів EDIN;
- повна підтримка всіх EDI-мереж;
- повна підтримка е-ТТН, якщо не підключено ETTN API;
- власний модуль КЕП без окремого ТЗ;
- складний UI підписання;
- автоматичне виправлення XML-помилок;
- юридична перевірка змісту документа.
27. Етапи реалізації
Етап 1. Аналіз EDIN API
- отримати офіційну документацію EDIN;
- визначити продукт: DocFlow, EDI Network, Tax Invoice, ETTN або гібрид;
- визначити авторизацію;
- визначити формати документів;
- визначити статуси;
- визначити правила підписання;
- визначити квитанції та підтвердження.
Етап 2. Базовий Python-сервіс
- створити FastAPI-проєкт;
- налаштувати PostgreSQL;
- створити моделі інтеграції, документів, вкладень, подій;
- налаштувати Alembic;
- реалізувати healthcheck.
Етап 3. EDIN Client
- реалізувати авторизацію;
- реалізувати check_connection;
- реалізувати create_document;
- реалізувати upload_attachment;
- реалізувати send_document;
- реалізувати get_document_status;
- реалізувати get_document_list;
- реалізувати download_receipt;
- реалізувати обробку помилок.
Етап 4. Документи та валідація
- реалізувати створення документа;
- реалізувати мапінг K2 ERP → EDIN;
- реалізувати валідацію;
- реалізувати hash документа;
- реалізувати дедублікацію.
Етап 5. Підписання
- реалізувати сценарій WAITING_SIGNATURE;
- реалізувати інтеграцію з Signature Service, якщо є;
- реалізувати перевірку підпису;
- реалізувати журнал підписання.
Етап 6. Черга та статуси
- реалізувати чергу передачі;
- реалізувати worker відправки;
- реалізувати worker синхронізації статусів;
- реалізувати retry;
- реалізувати збереження квитанцій.
Етап 7. Dashboard та аудит
- реалізувати dashboard API;
- реалізувати список проблемних документів;
- реалізувати фільтри;
- реалізувати експорт, якщо потрібно.
Етап 8. Production hardening
- додати rate limiting;
- додати моніторинг;
- додати alerting;
- додати dead letter queue;
- додати резервне копіювання;
- додати безпечне зберігання секретів.
28. Ризики
| Ризик | Опис | Як зменшити |
|---|---|---|
| EDIN не підтримує потрібний тип звітності | Не всі податкові декларації можуть бути доступні через EDIN. | Підтвердити API та типи документів до розробки. |
| Неправильний формат XML | Документ може бути відхилено. | Валідація за схемою до відправки. |
| Помилка КЕП | Документ не буде підписано. | Окремий статус SIGN_ERROR і журнал підписання. |
| Дублювання документів | Повторний запит може створити дубль. | Idempotency key і document_hash. |
| Невідомий статус | EDIN може повернути статус, якого немає в мапінгу. | Таблиця status_mapping і статус UNKNOWN. |
| Немає квитанції | Документ передано, але підтвердження не отримано. | Фоновий retry отримання квитанцій. |
| Зміна API | EDIN може змінити API або схему. | Версіонування клієнта і contract-тести. |
29. Відкриті питання
- Який саме продукт EDIN використовується: DocFlow, EDI Network, Tax Invoice, ETTN чи гібрид?
- Чи підтримує EDIN потрібний тип податкової звітності?
- Які типи документів потрібно передавати в MVP?
- Чи потрібне підписання в K2 ERP, Python-сервісі або на стороні EDIN?
- Чи потрібно зберігати КЕП у системі?
- Чи потрібна інтеграція з хмарним КЕП?
- Які формати документів використовуються: XML, JSON, PDF, XLSX?
- Чи потрібна валідація XML за XSD?
- Чи потрібно отримувати квитанції автоматично?
- Як часто синхронізувати статуси?
- Чи потрібно надсилати документи пакетно?
- Чи потрібно підтримувати декілька юридичних осіб?
- Чи потрібно підтримувати декілька акаунтів EDIN?
- Чи потрібен UI для підписання?
- Чи потрібен dashboard у K2 ERP?
- Чи потрібно експортувати журнал передачі в Excel?
30. Джерела
- https://edin.ua/
- https://edin.ua/edi-network/
- https://edin.ua/integraciya/
- https://edin.ua/integracijni-rishennya-edin/
- https://wiki.edin.ua/
- https://wiki-df.edin.ua/
- https://wiki.edin.ua/uk/latest/retail_2.0/Formuvannya_Podatkovoyi_Nakladnyy_na_pidstavi_Prybutkovoyi_nakladnoyi.html
- https://wiki.edin.ua/uk/latest/API_ETTNv3_1/API_ETTNv3_1_list.html