Технічне завдання: передача документів для звітності в податкову через Медок для Python
download_receipts.py
title: "Декларація платника єдиного податку"
</syntaxhighlight> Очікувана відповідь:
15. Робота зі статусами
! | Отримати офіційну документацію та тестовий доступ. Очікуваний результат MEDOC_RETRY_BACKOFF_SECONDS=5 MEDOC_PASSWORD=******** 5. SEO-опис 1. |}
storage/
"medoc_document_id": response.id,
Python-сервіс повинен приймати документ від ERP. Поле </syntaxhighlight>
Як користувач системи,
! Обов'язковість
- прийом даних звітності з ERP / облікової системи;
- формування або прийом готового XML-документа;
- перевірку документа перед передачею;
- передачу документа в M.E.Doc;
- запуск підписання та відправки через M.E.Doc, якщо підтримується API;
- отримання зовнішнього ID документа;
- синхронізацію статусів;
- отримання квитанцій або результатів обробки;
- збереження історії передачі;
- обробку помилок;
- повторну відправку;
- журналювання всіх технічних і бізнес-подій. | платформа зберігає причину відхилення. | Відображати зрозумілу помилку та дозволяти повторне підписання. |-
| ReadyToSend | Документ готовий до передачі. |- | Rejected | Документ відхилено. Компонент
config.py new_status = status_mapper.map_medoc_status(medoc_status)
23. Етапи реалізації
4. Записати подію в журнал. # Чи активований компонент M.E.Doc REST API / інтеграційні функції ERP? |- | Персональні інформаційні дані | Документи можуть містити РНОКПП, ЄДРПОУ, фінансові інформаційні дані. |}
18. Безпека
MEDOC_COMPANY_CODE=12345678
- xml core/
Етап 7. Квитанції та результати обробки
|- | AC-8 | Документ створено в M.E.Doc. Поле
)
Для реалізації задачі необхідно отримати:
"status": "Signed",
{ ! |- | StatusMappingError | Невідомий статус від M.E.Doc. "message": "Document created"
6. технічна архітектура рішення для бізнесу
11. API Python-сервісу
8.7. Отримання квитанцій
! № POST /api/v1/tax-reports/{report_id}/send-to-medoc
audit_logger.log(
6.2. Основні компоненти Python-сервісу
Етап 2. Робота з документами
tax_report_repository.py
"medoc_status": medoc_status.raw_status, v
"new_status": "WaitingForSignature", timeout_seconds: int = 30
TaxReportStatus.SENT_TO_MEDOC,
== 17. Обробка помилок ==
report = tax_report_repository.get_by_id(db, report_id)
},
requires_signature: true
date=report.document_date,
POST /api/v1/tax-reports/{report_id}/send-to-medoc
report.status = TaxReportStatus.SENT_TO_MEDOC
{| class="wikitable"
"file_format": "xml",
pass
}
{| class="wikitable"
}
docker-compose.yml
! 7. Отримати результат підписання. # Чи підтримуються webhook-и? Ризик
"message": "Document sent to M.E.Doc"
я хочу ініціювати підписання та відправку документа через M.E.Doc,
v
Як бухгалтер,
=== 8.6. Отримання статусів ===
<pre>
! | Маскувати логи та обмежити доступ. ! |-
| Containers
| Docker. |-
| signed
| Signed
| Документ підписано. Тип
щоб не виконувати ці дії вручну в окремому вікні, якщо це підтримується API. # Які endpoint-и використовуються для отримання квитанцій? |}
APP_ENV=production
== 28. Definition of Done ==
=== 21.1. Створення документа ===
"taxpayer_id": report.taxpayer_id,
STATUS_SYNC_INTERVAL_SECONDS=300
|-
| id
| uuid
| ID події.== 29. Джерела ==
def send_report_to_medoc(report_id: UUID, db: "Session") -> "TaxReport":
pass
</syntaxhighlight>
=== Етап 8. Production hardening ===
RECEIPT_DOWNLOAD_ENABLED=true
raise InvalidStatusError(
</syntaxhighlight> {
TaxReportStatus.WAITING_FOR_SIGNATURE,
SEO title: Технічне завдання: Передача документів для звітності в податкову через M.E.Doc для Python
SEO keywords: Python, M.E.Doc, Медок, Medoc REST API, податкова звітність, ДПС, API, XML, КЕП, електронна звітність, технічне завдання
</noinclude>
{{SEO
Шаблон для службового SEO-опису сторінки.
}}
}
sync_statuses.py tax_report_service.py
def sign_and_send_report(report_id: UUID, db: "Session") -> "TaxReport":
19.1. Змінні середовища
=== 7.2. Підписання та відправка ===
class MedocSettings(BaseSettings):
)
! ! # Який механізм авторизації застосовується для?=== 11.8. Отримання журналу ===
api_key: str | None = None
report_id=report.id,
=== 16.1. tax_reports ===
6. | Додати healthcheck інтеграції та повідомлення адміністратору. Компонент
[[Категорія:API]]
|-
| id
| uuid
| ID файлу. |}
return report
send_response = medoc_client.send_document(report.medoc_document_id)
* timeout;
* тимчасової недоступності M.E.Doc API;
* HTTP 429;
* HTTP 500;
* HTTP 502;
* HTTP 503;
* HTTP 504;
* тимчасових мережевих помилок. | Основна платформа для подання звітності. # Зберегти зовнішній ID у БД.<syntaxhighlight lang="json">
* реалізувати авторизацію;
* реалізувати upload_tax_report;
* реалізувати create_document;
* реалізувати get_document_status;
* реалізувати download_document;
* реалізувати download_receipts;
* реалізувати обробку помилок;
* реалізувати retry. # Чи потрібно робити UI, чи тільки backend API? |-
| Помилки авторизації
| Доступ до API здатна бути неправильним або простроченим. Валідація та збереження документа
def download_original(self, document_id: str) -> bytes:
== 13. Передача документа в M.E.Doc ==
|
| 3. платформа повинна забезпечити:
* реалізувати background worker;
* реалізувати періодичне оновлення версій статусів;
* реалізувати мапінг статусів;
* реалізувати обробку невідомих статусів.=== 17.2. Retry-логіка ===
Очікувана відповідь:
)
! | Опційно. |-
| Medoc REST API
| API для інтеграції облікових систем з M.E.Doc. | Опційно. |-
| report_id
| uuid
| ID документа. Режим
=== Етап 5. Підписання та відправка ===
response = medoc_client.upload_tax_report(payload)
[[Категорія:M.E.Doc]]
requires_signature: true
=== Передача документа в M. 8.3.E.Doc ===
v
я хочу отримати квитанції в ERP,
from uuid import UUID
</syntaxhighlight>
POST /api/v1/tax-reports/{report_id}/validate
=== 13.2. Приклад Python-логіки ===
Retry не застосовується для:
<syntaxhighlight lang="yaml">
=== 21.5. Квитанції та файли ===
"message": "Document sent to tax authority via M.E.Doc"
щоб скоротити час підготовки та подання звітності. | Статус документа змінюється на SentToTax.<pre>
Як користувач системи ERP,
"id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
def create_document(self, document: "DocumentPayload") -> "MedocDocumentResponse":
}
{
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
8. |-
| waiting_receipt
| WaitingForTaxReceipt
| Очікується квитанція.<syntaxhighlight lang="json">
== Див. 30. так само ==
if new_status != report.status:
Retry застосовується для:
=== 7.4. Отримання квитанцій ===
migrations/
logging.py
[[Категорія:Інтеграції]]
|-
| taxpayer_id
| string
| Так
| РНОКПП або ЄДРПОУ платника. | Статус документа змінюється на Signed. |-
| report_type
| string
| Так
| Тип звіту або документа. | платформа дає можливість передачу в M.E.Doc. |-
| Webhook
| Отримання подій від M.E.Doc, якщо підтримується. |-
| report_type
| varchar
| Тип звіту. Очікуваний результат
=== Етап 6. Синхронізація статусів ===
== 22. MVP ==
! |-
| Повторна відправка
| Причина, користувач системи, дата. # Записати подію в журнал. | як приклад K2 ERP або інша платформа.== 8. Функціональні вимоги ==
<syntaxhighlight lang="python">
file_repository.py
workers/
=== 7.5. Повторна відправка ===
</div>
MEDOC_TIMEOUT_SECONDS=30
# Отримати документ із локальної БД. # Отримати зовнішній ID документа в M.E.Doc. платформа повинна завантажувати та зберігати:
* реалізувати завантаження квитанцій;
* реалізувати збереження PDF/XML/receipt-файлів;
* реалізувати прив'язку файлів до документа;
* реалізувати перегляд історії. |-
| medoc_raw_status
| varchar
| Останній raw-статус M.E.Doc. SEO-опис
До MVP не входить:
=== 8.5. Відправка документа до ДПС ===
MEDOC_USERNAME=integration_user
MEDOC_RETRY_BACKOFF_SECONDS=5
Окремо варто відзначити який формує, перевіряє, передає і контролює документи податкової звітності через інтеграцію з M. |-
| old_status
| varchar
| Попередній статус. |-
| MedocTimeoutError
| Перевищено час очікування. models.py
== 16. Модель даних ==
"id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
title: "Декларація з ПДВ"
tax_reports.py
! | У документі зберігається medoc_document_id. |}
</div>
платформа повинна логувати:
POST /api/v1/tax-reports/{report_id}/sync-status
<pre>
"status": "SentToTax",
Логічний endpoint Python-сервісу:
=== 8.4. Підписання документа ===
4. |}
unit/
{| class="wikitable"
* встановлений та налаштований M.E.Doc;
* активний компонент M.E.Doc інтеграційні функції ERP / REST API;
* мережевий доступ до M.E.Doc API;
* базовий URL M.E.Doc REST API;
* спосіб авторизації в API;
* технічну документацію endpoint-ів;
* перелік доступних типів звітності;
* формат передачі файлів;
* формат метаданих документа;
* правила створення документа в M.E.Doc;
* правила підписання документа;
* правила відправки документа;
* правила отримання статусів;
* правила отримання квитанцій;
* тестовий контур або тестову організацію;
* технічний контакт з боку постачальника M.E.Doc. |-
| title
| varchar
| Назва документа. |-
| error_message
| text
| Остання помилка. |-
| file_name
| varchar
| Назва файлу. |-
| M.E.Doc REST API
| Інтеграційний API для роботи з документами. |-
| updated_at
| timestamp
| Дата оновлення версій. Термін
services/
schemas.py
|-
| ValidationError
| Некоректні інформаційні дані документа. |-
| Підписання
| Результат, дата, raw-відповідь M.E.Doc. Коментар
* додати Dockerfile;
* додати docker-compose;
* додати structured logging;
* додати metrics;
* додати alerting;
* додати rate limiting;
* додати security review. |-
| waiting_signature
| WaitingForSignature
| Очікується підпис. |-
| Accepted
| Документ прийнято. Записати подію в журнал. |}
def cancel_document(self, document_id: str, reason: str) -> "MedocDocumentResponse":
details={
"new_status": new_status,
app/
<syntaxhighlight lang="python">
|-
| AC-12
| Worker запускає синхронізацію.== 12. Medoc Integration Client ==
=== Етап 4. Передача документів ===
{| class="wikitable"
== 3. Джерела інтеграції ==
title: "Запит до податкової"
ДПС
allowed_formats:
=== 13.1. Логічний бізнес-процес ===
class MedocClient:
=== 14.1. Логічний бізнес-процес підписання ===
!<pre>
</div>
{| class="wikitable"
payload = DocumentPayload(
== 25. Відкриті питання ==
== 21. Acceptance Criteria ==
api/
щоб мати підтвердження результату подання звітності. |-
| Залежність від локального M.E.Doc
| API здатна працювати тільки за наявності встановленого та налаштованого M.E.Doc. Критерій
=== 17.1. Типи помилок ===
[[Категорія:K2 ERP]]
{| class="wikitable"
title: "Об'єднана формування звітів"
raise InvalidStatusError(
== Підписання та відправка через M. 14.E.Doc ==
! |-
| Передача в M.E.Doc
| Endpoint, час, статус відповіді, зовнішній ID. |-
| period
| varchar
| Звітний період. ! |-
| AC-11
| Відправка виконана успішно. # Які endpoint-и використовуються для підписання? | Перевіряти medoc_document_id перед відправкою. | Передбачити healthcheck M.E.Doc API. |}
metadata={
</pre>
POST /api/v1/tax-reports
{| class="wikitable"
! №
Dockerfile
allowed_formats:
! Очікуваний результат
<pre>
"report_type": "single_tax_declaration",
</pre>
}
! |-
| file_format
| varchar
| XML, PDF, ZIP тощо. Викликати метод підписання M.E.Doc. | Виконати retry. SEO-опис
Очікувана відповідь:
event_type="STATUS_SYNC_FAILED",
pass
details={"raw_status": send_response.status},
reports = tax_report_repository.get_reports_for_sync()
file_format=report.file_format,
</pre>
report.sent_to_tax_at = datetime.now(timezone.utc)
def send_document(self, document_id: str) -> "MedocDocumentResponse":
щоб не створювати документ заново. Тип
<syntaxhighlight lang="json">
MEDOC_API_KEY=********
</pre>
</pre>
! retry_backoff_seconds: int = 5
MEDOC_RETRY_COUNT=3
=== 11.9. Завантаження квитанцій ===
raise InvalidStatusError("Report is not created in M.E.Doc")
|-
| Draft
| Документ створено, але ще не готовий до передачі.=== 15.2. Приклад worker-а ===
event_type="SIGNED_IN_MEDOC",
</pre>
{| class="wikitable"
Очікувана відповідь:
|-
| AC-1
| ERP передає інформаційні дані документа у Python-сервіс. return report
{| class="wikitable"
! |-
| DuplicateDocumentError
| Документ вже був переданий. |-
| Receipt1Received
| Отримано квитанцію №1. # Який SLA по оновленню статусів? SEO-опис
v
4. №
=== 11.1. Створення документа ===
def download_receipts(self, document_id: str) -> list [bytes]:
Python-сервіс повинен мати метод для передачі документа в M.E.Doc. Оновити статус на SentToTax або Failed. |-
| Receipt Loader
| Завантажує квитанції та результати обробки. |-
| Sending
| Документ передається в M.E.Doc. # Чи потрібна технічна підтримка ФОП, юридичних осіб або обох варіантів? # Оновити статус документа. # Який базовий URL API? |-
| CreatedInMedoc
| Документ створено в M.E.Doc. Поле
=== 16.2. tax_report_events ===
Мінімальний набір вхідних даних:
! |-
| AC-16
| Документ відхилено. |-
| new_status
| varchar
| Новий статус. |-
| document_number
| string
| Так
| Номер документа. |-
| medoc_document_id
| varchar
| ID документа у M.E.Doc. Дія системи
event_type="SENT_TO_TAX",
</pre>
|-
| Python-сервіс
| Окремий backend-сервіс або компонент, який виконує інтеграцію з M.E.Doc. # Викликати метод M.E.Doc для відправки.=== 14.2. Логічний бізнес-процес відправки ===
requires_receipt: true
Очікувана дія:
== 24. Ризики ==
"taxpayer_id": "1234567890",
details={"error": str(exc)},
MEDOC_BASE_URL=http://medoc-server.local:8080
Метою задачі виступає як створення Python-сервісу для передачі документів податкової звітності через M.E.Doc. |-
| AC-13
| M.E.Doc повертає новий статус. Тип
db/
details={
Python Tax Reporting Service
"medoc_document_id": "external-document-id",
<syntaxhighlight lang="json">
DATABASE_URL=postgresql+psycopg://user:password@db:5432/reports
! |-
| AC-7
| Документ вже був переданий. |-
| file_name
| varchar
| Назва файлу. |-
| file_path
| varchar
| Шлях до файлу у сховищі. |-
| document_date
| date
| Дата документа. Зберегти ID у локальній БД. |}
<syntaxhighlight lang="python">
Як бухгалтер,
! Повторна відправка дозволена тільки для документів у статусах:
|
| 7. |-
| size_bytes
| integer
| Розмір файлу. |-
| event_type
| varchar
| Тип події. Очікуваний результат
"taxpayer_name": report.taxpayer_name,
Очікувана відповідь:
},
{| class="wikitable"
! |-
| content_type
| varchar
| MIME-тип. | платформа дає можливість відправку до ДПС. SEO-опис
=== 11.4. Підписання документа ===
tax_report_repository.update_status(
</pre>
функції ERP застосовується для для автоматизації передачі документів податкової звітності з ERP або облікової системи до M.E.Doc з подальшим поданням до ДПС. | Повторити пізніше, повідомити адміністратора. |-
| accepted_at
| timestamp
| Дата прийняття. |-
| Medoc Client
| Python-клієнт для роботи з M.E.Doc REST API. |-
| created_at
| timestamp
| Дата створення. |-
| receipt_1
| Receipt1Received
| Отримано квитанцію №1.
- реалізувати endpoint send-to-medoc;
- зберігати medoc_document_id;
- оновлювати статуси;
- логувати API-взаємодію. Статус документа
event_type="SENT_TO_MEDOC", "medoc_status": "waiting_signature"
POST /api/v1/tax-reports/{report_id}/resend
signing_service.py
=== 11.5. Відправка до ДПС ===
__TOC__
Попередній логічний мапінг:
|-
| id
| uuid
| Внутрішній ID документа. f"Report {report_id} cannot be sent from status {report.status}"
== 7. User Story ==
requires_signature: true
def get_document_status(self, document_id: str) -> "MedocStatusResponse":
2. |-
| imported
| SentToMedoc
| Документ імпортовано / передано в M.E.Doc. pass
verify_ssl: bool = True
! |-
| metadata
| object
| Ні
| Додаткові реквізити для M.E.Doc. # Оновити статус на SentToTax. |-
| XML
| Формат електронного документа звітності. |-
| DeliveryError
| Помилка доставки. Спосіб
6. SEO-опис
"id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
=== 12.1. Призначення ===
)
new_status=new_status,
# Перевірити, що документ створено в M.E.Doc. SEO-опис
db.commit()
M.E.Doc
! {
"document_number": "DECL-2026-0001",
details={"raw_status": sign_response.status},
|
| 1. | Інкапсулювати API в окремому MedocClient. |-
| M.E.Doc / Медок
| Програмний комплекс для електронної звітності та документообігу. | платформа завантажує квитанцію №2 або результат обробки. Викликати метод відправки M.E.Doc. |-
| file_path
| varchar
| Шлях до файлу. |}
! |-
| Background jobs
| Celery, RQ або APScheduler. |-
| AC-17
| користувач системи відкриває картку документа. |-
| КЕП
| Кваліфікований електронний підпис. |-
| Недоступність M.E.Doc
| Сервер M.E.Doc або мережа можуть бути тимчасово недоступні. SEO-опис
<pre>
! |
| 5. №
<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
def download_signed_document(self, document_id: str) -> bytes:
status_sync_service.py
)
=== Передача в M. 21.2.E.Doc ===
def sync_pending_reports() -> None:
"metadata": {
integration/
Очікувана дія:
! | Реалізується в межах цього ТЗ. |}
{| class="wikitable"
# Яка реліз системи M.E.Doc застосовується для? |-
| Status Sync Worker
| Фоновий бізнес-процес для оновлення версій статусів. Отримати файл зі сховища. "message": "Document signed via M.E.Doc"
file_content=file_bytes,
if report.status != TaxReportStatus.READY_TO_SEND:
security.py
base_url: str
receipt_service.py
'''Заборонено:''' зберігати API key, паролі, токени або паролі КЕП у коді, Git-репозиторії чи відкритих логах. "id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
! Реальні коди статусів потрібно взяти з API-документації M.E.Doc.<pre>
* webhook-інтеграція;
* інтеграційні функції ERP напряму з ДПС;
* власний компонент КЕП;
* складний UI;
* автоматичне оновлення версій XSD;
* технічна підтримка всіх типів звітності;
* автоматичне створення декларацій з бухгалтерських даних. |-
| HTTP client
| httpx. |-
| SentToMedoc
| Документ успішно передано в M.E.Doc. Отримати результат відправки. щоб оперативно знаходити причину помилок інтеграції. |-
| Tests
| pytest. |-
| status
| varchar
| Внутрішній статус. README.md
* повна заміна інтерфейсу M.E.Doc;
* власна реалізація подання напряму до API ДПС;
* власна реалізація КЕП, якщо підписання виконується у M.E.Doc;
* автоматичне оновлення версій всіх XSD-схем;
* повноцінний UI для бухгалтера;
* автоматична бухгалтерська перевірка сум;
* технічна підтримка всіх типів податкової, статистичної та фінансової звітності. |-
| sent
| SentToTax
| Документ відправлено. |-
| taxpayer_name
| string
| Так
| Назва компанії або ПІБ ФОП. # Хто має доступ до API key? Оновити статус на Signed або Failed. |-
| rejected
| Rejected
| Документ відхилено. # Отримати файл зі сховища. | Використовувати retry та чергу задач. # Де виконується КЕП: у Python-сервісі, у M.E.Doc або користувачем у клієнті M.E.Doc? |}
'''Уточнення:''' значення статусів виступає як попередніми. '''Головна ідея:''' розробити Python-сервіс.E.Doc / Medoc REST API. Компонент
old_status = report.status
Python Tax Reporting Service
== 27. Технічні вимоги до Python ==
report = tax_report_repository.get_by_id(db, report_id)
ERP / Accounting System
POST /api/v1/tax-reports/{report_id}/download-receipts
FILE_STORAGE_PATH=/data/tax-reports
Логічний endpoint Python-сервісу:
entity_id=report.id,
! Передача документа через Medoc REST API
pyproject.toml
retry_count: int = 3
|
| 4. |-
| source_system
| varchar
| ERP або інша система-джерело. |}
<pre>
я хочу бачити журнал API-запитів і відповідей,
* квитанцію №1;
* квитанцію №2;
* квитанцію про відхилення;
* підписаний документ;
* PDF-візуалізацію, якщо доступна;
* технічний протокол обробки, якщо доступний;
* raw-відповідь M.E.Doc. Критерій
== 20. Логування та аудит ==
! |-
| SignatureError
| Помилка підписання документа. Підписання / відправка / обробка
це Python-клас або пакет, який інкапсулює роботу з M виступає ключовою рисою Medoc Integration Client.E.Doc REST API. Записати подію в журнал. |- | created_by | varchar | користувач системи або system. | Raw-статус зберігається, створюється подія UnknownStatus. |- | AC-2 | Передано файл документа. |- | rejected_at | timestamp | Дата відхилення. |- | Квитанція | Підтвердження прийняття, відхилення або обробки звіту. 6. Що зберігати }
def get_document(self, document_id: str) -> "MedocDocumentResponse":validation_service.py "errors": [] v
| Python | 3.11 або вище. number=report.document_number,
5. |- |
Скасування документа | Причина, користувач системи, дата. SEO-опис
vat_declaration: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| M.E.Doc | Статуси документів оновлюються автоматизовано. |}
pass audit_logger.log("created_by": "user@example.com" "document_date": "2026-04-15", pass {
|