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

Технічне завдання: передача документів для звітності в податкову через Медок для Python

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


10.; Мапінг статусів M.E.Doc

!; |- | Validation Layer | Перевіряє реквізити, структуру та статус документа.;=== 13.2.; Приклад Python-логіки ===

12.1.; Призначення

)
def upload_tax_report(self, document: "DocumentPayload") -> "MedocDocumentResponse":
security.py

19.2.; Конфігурація типів документів

25.; Відкриті питання

file_name=report.file_name,

POST /api/v1/tax-reports/{report_id}/sign

def download_signed_document(self, document_id: str) -> bytes:
- pdf

from uuid import UUID |- | taxpayer_id | string | Так | РНОКПП або ЄДРПОУ платника.; # Які endpoint-и використовуються для підписання?; |- | Migrations | Alembic.; |- | imported | SentToMedoc | Документ імпортовано / передано в M.E.Doc.; | Зупинити відправку, повідомити адміністратора.; |- | Передача в M.E.Doc | Endpoint, час, статус відповіді, зовнішній ID.; | платформа зберігає причину відхилення.; |- | MedocApiError | API повернув помилку.; характеристика from datetime import datetime, timezone !; | Виконати retry.; |- | content_type | varchar | MIME-тип.; |- | taxpayer_name | varchar | Назва платника.; Компонент

medoc_status = medoc_client.get_document_status(

платформа повинна підтримувати два способи актуалізація статусів:

"status": "Generated",
client.py

!; |- | XSD | Схема перевірки XML-документа.; |- | error | Failed | Помилка обробки.; |- | title | varchar | Назва документа.; | Заборонити повтор без підтвердження.; |- | SignatureError | Помилка підписання документа.; |- | Receipt1Received | Отримано квитанцію №1.; | Не відправляти документ, показати список помилок.; Як зменшити !; |- | file_content_base64 | string | Так | Вміст документа у Base64.; |- | accepted | Accepted | Документ прийнято.; | Зафіксувати помилку, повідомити адміністратора.; характеристика

TaxReportStatus.CREATED_IN_MEDOC,
def download_original(self, document_id: str) -> bytes:
db.commit()

8.; "taxpayer_id": report.taxpayer_id,

  • реалізувати авторизацію;
  • реалізувати upload_tax_report;
  • реалізувати create_document;
  • реалізувати get_document_status;
  • реалізувати download_document;
  • реалізувати download_receipts;
  • реалізувати обробку помилок;
  • реалізувати retry.; характеристика
date=report.document_date,

|- | ValidationError | Некоректні інформаційні дані документа.; | платформа завантажує квитанцію №2 або результат обробки.; |- | file_path | varchar | Шлях до файлу.; {| class="wikitable"

}:

6.1.; Загальна схема

POST /api/v1/tax-reports

Передача в M.; 21.2.E.Doc

event_type="SENT_TO_TAX",

}

"id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
tax_reports.py
report.status = TaxReportStatus.SENT_TO_MEDOC
v
event_repository.py
report.sent_at = datetime.now(timezone.utc)

29.; Джерела

APP_ENV=production </syntaxhighlight>

session.py
file_repository.py

class MedocSettings(BaseSettings):

!; GET /api/v1/tax-reports/{report_id}/events

POST /api/v1/tax-reports/{report_id}/send-to-tax я хочу ініціювати підписання та відправку документа через M.E.Doc, ERP / Accounting System

"document_date": "2026-04-15",

Python-сервіс повинен приймати документ від ERP.; |}

Передача документа в M.; 7.1.E.Doc

 - zip
{| class="wikitable"
== 26.; Приклад структури Python-проєкту ==
|-
| AC-4
| Документ має статус ReadyToSend.; |-
| waiting_signature
| WaitingForSignature
| Очікується підпис.; |-
| Document Builder
| Формує XML або приймає готовий файл.; !; # Де зберігати файли: локально, S3, MinIO, DMS?; |-
| rejected
| Rejected
| Документ відхилено.; |-
| medoc_raw_status
| varchar
| Останній raw-статус M.E.Doc.; Критерій
Метою задачі є собою створення Python-сервісу для передачі документів податкової звітності через M.E.Doc.; |-
| file_name
| varchar
| Назва файлу.; return report
 v
=== 16.3. tax_report_files ===
|-
| AC-12
| Worker запускає синхронізацію.; |-
| created_at
| timestamp
| Дата події.; характеристика
 file_format=report.file_format,
}

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

Medoc Integration Adapter
 audit_logger.log(
MEDOC_BASE_URL=http://medoc-server.local:8080

=== 21.1.; Створення документа ===
 unit/

!;=== 11.2.; Перевірка документа ===

{

}
 allowed_formats:
!; Критерій

 - zip

 README.md

* створення Python API для прийому документів;
* створення клієнта інтеграції з M.E.Doc REST API;
* формування XML або прийом готового XML;
* збереження документа;
* перевірка обов'язкових реквізитів;
* передача документа в M.E.Doc;
* запуск підписання / відправки через M.E.Doc;
* отримання статусів;
* отримання квитанцій;
* журнал подій;
* retry-механізм;
* захист API-ключів і службових доступів;
* інтеграційні функціональні можливості з ERP.; # Зберегти зовнішній ID у БД.; |-
| FileStorageError
| Неможливо прочитати або записати файл.; # Хто має доступ до API key?; Фінальний мапінг статусів потрібно побудувати після отримання офіційного довідника статусів M.E.Doc.; |-
| Storage Layer
| Зберігає документи, квитанції, статуси та логи.; |-
| period
| string
| Так
| Звітний період.; |-
| sent_at
| timestamp
| Дата передачі в M.E.Doc.; |-
| Tests
| pytest.; |-
| Polling
| Періодичне опитування зовнішнього API.; {

 pass
=== 8.6.; Отримання статусів ===


document_types:
щоб розуміти, чи документ створено, передано, підписано, відправлено до ДПС, прийнято або відхилено.; |}

!; |-
| Medoc Client
| Python-клієнт для роботи з M.E.Doc REST API.; Python-сервіс повинен мати метод для передачі документа в M.E.Doc.; response = medoc_client.upload_tax_report(payload)

 "medoc_document_id": response.id,
!; # Де виконується КЕП: у Python-сервісі, у M.E.Doc або користувачем у клієнті M.E.Doc?; |-
| Невідомі статуси
| M.E.Doc має змогу повертати статуси, яких немає в системі.; Викликати метод підписання M.E.Doc.; # Які endpoint-и використовуються для відправки?; |-
| sent_to_tax_at
| timestamp
| Дата відправки до ДПС.; # Оновити статус документа.; Підписання / відправка / обробка
!; |-
| Accepted
| Документ прийнято.; |-
| AC-11
| Відправка виконана успішно.; |-
| Generated
| Файл документа сформовано.; |-
| DuplicateDocumentError
| Документ вже був переданий.; | Отримати офіційну документацію та тестовий доступ.; |-
| Зміна API
| Endpoint-и або формати відповіді можуть змінюватися.; |-
| Персональні інформаційні дані
| Документи можуть містити РНОКПП, ЄДРПОУ, фінансові інформаційні дані.; | Статус документа змінюється на Signed.; |-
| Webhook
| Механізм отримання подій від зовнішньої системи.; | платформа надає можливість відправку до ДПС.; | Передбачити healthcheck M.E.Doc API.; Тип

!; функціональні можливості застосовується для автоматизації передачі документів податкової звітності з ERP або облікової системи до M.E.Doc з подальшим поданням до ДПС.; Отримати документ з БД.; |-
| Завантаження квитанції
| Тип файлу, назва, дата.; Квитанції / статуси
=== 14.2.; Логічний бізнес-процес відправки ===
 entity_id=report.id,
 |
 | 6.; |-
| WaitingForTaxReceipt
| Очікується квитанція або результат обробки.; |}

== 20.; Логування та аудит ==

POST /api/v1/tax-reports/{report_id}/validate

* квитанцію №1;
* квитанцію №2;
* квитанцію про відхилення;
* підписаний документ;
* PDF-візуалізацію, якщо доступна;
* технічний протокол обробки, якщо доступний;
* raw-відповідь M.E.Doc.; |-
| created_at
| timestamp
| Дата створення.; |-
| file_path
| varchar
| Шлях до файлу у сховищі.; Підготувати метадані.; №

== 11.; API Python-сервісу ==
 )
щоб мати підтвердження результату подання звітності.; |-
| AC-17
| користувач системи відкриває картку документа.; |-
| error_message
| text
| Остання помилка.; |-
| document_date
| date
| Так
| Дата документа.; Викликати метод відправки M.E.Doc.; Зберегти ID у локальній БД.; |-
| AC-10
| Документ підписано.; Очікуваний результат

!; # Який базовий URL API?; |-
| Receipt Loader
| Завантажує квитанції та результати обробки.; | ключовий режим.; |-
| file_name
| varchar
| Назва файлу.; |-
| file_format
| varchar
| XML, PDF, ZIP тощо.; |-
| AC-9
| Підписання виконано успішно.; !; Окремо варто відзначити який формує, перевіряє, передає і контролює документи податкової звітності через інтеграцію з M.E.Doc / Medoc REST API.; # Чи потрібна супровід ФОП, юридичних осіб або обох варіантів?; |-
| event_type
| varchar
| Тип події.; |-
| Помилки авторизації
| Доступ до API має змогу бути неправильним або простроченим.; Отримати ID документа в M.E.Doc.;=== 8.8.; Повторна відправка ===

* реалізувати endpoint send-to-medoc;
* зберігати medoc_document_id;
* оновлювати статуси;
* логувати API-взаємодію.; |-
| source_system
| varchar
| ERP або інша система-джерело.;=== 12.2.; Основні методи ===
 audit_logger.log(

 - pdf
платформа повинна логувати:

=== 14.1.; Логічний бізнес-процес підписання ===
=== 17.2.; Retry-логіка ===

=== 17.1.; Типи помилок ===
</syntaxhighlight>

 db.commit()
== 18.; Безпека ==

 details={
=== Передача документа в M.; 8.3.E.Doc ===

Сервіс повинен забезпечити:
Як користувач системи ERP, 
3.; | Він бачить всі пов'язані файли та статуси.; Поле
 allowed_formats:
Логічний endpoint Python-сервісу:
=== 7.4.; Отримання квитанцій ===
 "status": "SentToMedoc",

!; Тип
title: "Запит до податкової"

Очікувана відповідь:

requires_receipt: true
docker-compose.yml
"metadata": {

Очікувана відповідь: MEDOC_PASSWORD=********

5.; Записати подію в журнал.; Спосіб Очікувана дія:

платформа повинна мати background worker, який періодично оновлює статуси документів.; характеристика

{

  • зберігання API key тільки у змінних середовища або secret storage;
  • заборону логування API key;
  • заборону зберігання паролів КЕП у відкритому вигляді;
  • маскування персональних даних у технічних логах;
  • контроль доступу до документів;
  • контроль доступу до квитанцій;
  • журналювання всіх операцій;
  • HTTPS для API-запитів, якщо M.E.Doc API розгорнутий з TLS;
  • перевірку SSL-сертифіката, якщо застосовується HTTPS;
  • обмеження доступу до адміністративних endpoint-ів;
  • резервне копіювання документів і квитанцій.; Перевірити, що документ має статус ReadyToSend.; |-

| AC-16 | Документ відхилено.; |- | size_bytes | integer | Розмір файлу.; |- | updated_at | timestamp | Дата актуалізація.; # Перевірити, що документ підписано або готовий до підписання.; # Підготувати метадані.; |}

retry_count: int = 3

це Python-клас або пакет, який інкапсулює роботу з M виступає ключовою рисою Medoc Integration Client.E.Doc REST API.;</syntaxhighlight>

v pass STATUS_SYNC_ENABLED=true entity_id=report.id, щоб не виконувати ці дії вручну в окремому вікні, якщо це підтримується API.; |-
taxpayer_id varchar РНОКПП або ЄДРПОУ.; TaxReportStatus.SENT_TO_MEDOC,
"old_status": "SentToMedoc",
  • створити FastAPI-проєкт;
  • налаштувати PostgreSQL;
  • створити моделі tax_reports, tax_report_events, tax_report_files;
  • реалізувати конфігурацію через environment variables;
  • реалізувати healthcheck endpoint.; Перевірити, що документ не був відправлений раніше.; |}

28. Definition of Done

def create_document(self, document: "DocumentPayload") -> "MedocDocumentResponse":

15.; Робота зі статусами

Етап 1.; Базова структура Python-сервісу

)
</syntaxhighlight> )

11.7.; Отримання документа

tax_request:
payload = DocumentPayload(

21.4.; Статуси

7.3.; Отримання статусу

23.; Етапи реалізації

def sync_pending_reports() -> None: STATUS_SYNC_INTERVAL_SECONDS=300

report.status = TaxReportStatus.SIGNED
entity_id=report.id,
)
- Logging structlog або стандартний logging у JSON-форматі.;
* webhook-інтеграція;
* інтеграційні функціональні можливості напряму з ДПС;
* власний компонент КЕП;
* складний UI;
* автоматичне актуалізація XSD;
* супровід всіх типів звітності;
* автоматичне створення декларацій з бухгалтерських даних.; Коментар
</div>
ДПС
!; |}

<syntaxhighlight lang="json">

# Яка реліз M.E.Doc застосовується?; |-
| taxpayer_name
| string
| Так
| Назва компанії або ПІБ ФОП.; |-
| report_id
| uuid
| ID документа.; # Який механізм авторизації застосовується?; Критерій

FILE_STORAGE_PATH=/data/tax-reports

1.; # Оновити статус на SentToTax.; 
[[Категорія:API]]
 v
 "document_number": "DECL-2026-0001",
MEDOC_API_KEY=********

 def send_document(self, document_id: str) -> "MedocDocumentResponse":

 storage/
<pre>
!; Отримати результат відправки.; Викликати MedocClient.upload_tax_report().; 
Задача вважається завершеною, якщо:

!; # Який формат документа підтримується: XML, PDF, ZIP, JSON?; | Файл зберігається у файловому сховищі.; |-
| CreatedInMedoc
| Документ створено в M.E.Doc.; |-
| AC-2
| Передано файл документа.; | платформа надає можливість передачу в M.E.Doc.; характеристика
<pre>
</pre>
 audit_logger.log(

 download_receipts.py

<syntaxhighlight lang="python">
 "period": "2026-Q1",
{| class="wikitable"
 "message": "Document created"
[[Категорія:K2 ERP]]
- xml
sign_response = medoc_client.sign_document(report.medoc_document_id)
for report in reports:

Повторна відправка не дозволена для статусів:

</syntaxhighlight> "medoc_document_id": "external-document-id",
- MedocAuthError Помилка авторизації в M.E.Doc API.; unified_report:

15.2.; Приклад worker-а

main.py
- Скасування документа Причина, користувач системи, дата.;=== 8.7.; Отримання квитанцій ===

Логічний endpoint Python-сервісу:

title=report.title, v
Неповна або закрита API-документація - Відправка до ДПС Результат, дата, raw-відповідь M.E.Doc.; я хочу отримати квитанції в ERP,
vat_declaration:

MEDOC_USERNAME=integration_user

POST /api/v1/tax-reports/{report_id}/send-to-medoc

"file_content_base64": "BASE64_XML_CONTENT",
audit_logger.log(

5.; Терміни та скорочення

я хочу бачити журнал API-запитів і відповідей,

"id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
; Очікуваний результат

11.6.; актуалізація статусу

pass
config.py
 def get_document(self, document_id: str) -> "MedocDocumentResponse":
 "id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",


 entity_id=report.id,
== 27.; Технічні вимоги до Python ==

 file_storage.py
4.; |-
| Failed
| Технічна помилка.; | Опційно.; "taxpayer_name": report.taxpayer_name,
 )
ERP / Accounting System

 services/

'''Технічний стек:''' Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Docker.; |-
| document_number
| varchar
| Номер документа.; {| class="wikitable"
До області задачі входить:
 new_status = status_mapper.map_medoc_status(medoc_status)
 verify_ssl: bool = True

 - xml
 )
'''Заборонено:''' зберігати API key, паролі, токени або паролі КЕП у коді, Git-репозиторії чи відкритих логах.; |-
| Webhook
| Отримання подій від M.E.Doc, якщо підтримується.; Термін
 app/

<pre>
Очікувана відповідь:

POST /api/v1/tax-reports/{report_id}/download-receipts
6.; |}

 TaxReportStatus.WAITING_FOR_SIGNATURE,

Retry застосовується для:

== Підписання та відправка через M.; 14.E.Doc ==

{| class="wikitable"
 metadata={
def send_report_to_medoc(report_id: UUID, db: "Session") -> "TaxReport":
 requires_receipt: true
|-
| created
| CreatedInMedoc
| Документ створено в M.E.Doc.; |-
| old_status
| varchar
| Попередній статус.; |-
| Cancelled
| Документ скасовано.; |-
| period
| varchar
| Звітний період.; |-
| WaitingForSignature
| Документ очікує підписання.; |-
| Containers
| Docker.; f"Report {report_id} cannot be signed from status {report.status}"

* Accepted;
* SentToTax;
* WaitingForTaxReceipt;
* SentToMedoc;
* WaitingForSignature.; # Який SLA по оновленню статусів?; Перевірити, що документ створено в M.E.Doc.; Реальні коди статусів потрібно взяти з API-документації M.E.Doc.; |-
| XML
| Формат електронного документа звітності.; | як ілюстрація K2 ERP або інша платформа.; |-
| M.E.Doc REST API
| Інтеграційний API для роботи з документами.; |-
| accepted_at
| timestamp
| Дата прийняття.; |-
| AC-7
| Документ вже був переданий.; Очікуваний результат
 file_content=file_bytes,
!; Призначення
 report_id=report.id,
!;<syntaxhighlight lang="python">
 "report_type": "single_tax_declaration",

{| class="wikitable"

== 2.; Область сфера застосування ==
{| class="wikitable"
!; |-
| Дублювання документів
| Повторна відправка має змогу створити дубль.; |-
| ДПС
| Державна податкова служба України.; | Маскувати логи та обмежити доступ.; |-
| Signed
| Документ підписано.; |-
| StatusMappingError
| Невідомий статус від M.E.Doc.; |-
| КЕП
| Кваліфікований електронний підпис.; інформаційні дані для звітності або готовий XML
 pass
 details={"error": str(exc)},
 |
 | 2.; workers/
<syntaxhighlight lang="python">
!; |-
| receipt_1
| Receipt1Received
| Отримано квитанцію №1.; |-
| M.E.Doc / Медок
| Програмний комплекс для електронної звітності та документообігу.; Записати подію в журнал.; |
 | 7.; | Повторити пізніше, повідомити адміністратора.; Інтервал перевірки
|-
| Підписання в M.E.Doc
| Документ передається в M.E.Doc, а підписання виконується засобами M.E.Doc.; # Отримати зовнішній ID документа в M.E.Doc.; Компонент

</div>
!; # Чи Python-сервіс має сам формувати XML, чи отримує готовий XML з ERP?; | платформа зберігає помилку та не втрачає документ.; |-
| Python
| 3.11 або вище.; Записати подію в журнал.; |}

 api/

[[Категорія:Інтеграції]]

 raw_status=medoc_status.raw_status,
 timeout_seconds: int = 30
щоб скоротити час підготовки та подання звітності.; exceptions.py

* реалізувати background worker;
* реалізувати періодичне актуалізація статусів;
* реалізувати мапінг статусів;
* реалізувати обробку невідомих статусів.; |-
| Повторна відправка
| Причина, користувач системи, дата.;== 12. Medoc Integration Client ==
!; details={"raw_status": sign_response.status},

Як бухгалтер, 

 requires_signature: true

=== 7.6.; Технічний аудит ===
Рекомендована періодичність:
<syntaxhighlight lang="json">

 file_bytes = file_storage.read(report.file_path)

# Отримати документ із локальної БД.; |-
| Sending
| Документ передається в M.E.Doc.; характеристика

== 7. User Story ==
<syntaxhighlight lang="yaml">
<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">

6.; | Резервний режим.; def cancel_document(self, document_id: str, reason: str) -> "MedocDocumentResponse":
<pre>
=== 8.4.; Підписання документа ===
 new_status=new_status,
|-
| AC-1
| ERP передає інформаційні дані документа у Python-сервіс.; Поле
3.; |}

 medoc/

 schemas.py
 f"Report {report_id} cannot be sent from status {report.status}"
</syntaxhighlight>
<pre>
|-
| id
| uuid
| ID події.; Очікуваний результат
 )
!; "medoc_status": medoc_status.raw_status,
 }
<syntaxhighlight lang="json">
платформа повинна підтримувати один із режимів:
 "message": "Document sent to tax authority via M.E.Doc"
"status": "ReadyToSend",

Як користувач системи,

21.5.; Квитанції та файли

11.9.; Завантаження квитанцій

; Синхронізація статусів

Приклад змінних середовища: 1.; Дія системи

"medoc_status": "waiting_signature"
if not report.medoc_document_id:

{

21.3.; Підписання та відправка

} MEDOC_API_KEY=********

MEDOC_RETRY_BACKOFF_SECONDS=5

11.10.; Повторна відправка

tax_report_repository.update_status(

Див.; 30.; додатково

Головна ідея: розробити Python-сервіс.; Тип POST /api/v1/tax-reports/{report_id}/send-to-medoc

return report
"status": "SentToTax",

{

Етап 5.; Підписання та відправка

title: "Декларація платника єдиного податку"
id uuid Внутрішній ID документа.; характеристика
 report = tax_report_repository.get_by_id(db, report_id)
я хочу бачити статус документа в ERP, 

 allowed_formats:

# Перевірити, що документ створено в M.E.Doc.; |-
| MedocUnavailableError
| Сервер M.E.Doc недоступний.; |-
| HTTP client
| httpx.; |-
| SentToMedoc
| Документ успішно передано в M.E.Doc.; Статус документа
 "source_system": "K2 ERP",
=== 12.3.; Конфігурація клієнта ===
=== 11.8.; Отримання журналу ===
{| class="wikitable"
Очікувана відповідь:

 "source_system": report.source_system,

MEDOC_BASE_URL=http://medoc-server.local:8080

pyproject.toml

15.1.; Фонове актуалізація

raise InvalidStatusError("Report is not created in M.E.Doc")
} Raw-статус зберігається, створюється подія UnknownStatus.; Отримати файл зі сховища.; |- Підписання Перевіряти medoc_document_id перед відправкою.; |- ERP / облікова платформа Зберегти raw-статус, створити подію UnknownStatus.; |- document_date date }

5.; Повторна відправка дозволена тільки для документів у статусах:

 signing_service.py
=== 8.2.; Валідація документа ===
!; Режим
 event_type="STATUS_SYNC_FAILED",
 health.py
 "taxpayer_name": "ФОП Іваненко Іван Іванович",
9.; |-
| AC-3
| Передано некоректні інформаційні дані.; | Статуси документів оновлюються автономно.; |-
| актуалізація статусу
| Старий статус, новий статус, raw-статус M.E.Doc.;<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
 "new_status": new_status,
 "raw_status": response.status,
[[Категорія:Податкова звітність]]
Як бухгалтер, 
Як бухгалтер, 
платформа повинна завантажувати та зберігати:
== 3.; Джерела інтеграції ==
<pre>
 pass
 report.status = TaxReportStatus.SENT_TO_TAX

 "errors": []

=== 13.1.; Логічний бізнес-процес ===
!; | Внутрішній статус документа змінюється.; # Які endpoint-и використовуються для отримання квитанцій?; except Exception as exc:

<syntaxhighlight lang="python">

; Що зберігати

Етап 3.; Medoc Integration Client

  • REST API для створення документа;
  • збереження документа;
  • базова валідація;
  • Medoc Integration Client;
  • передача документа в M.E.Doc;
  • збереження зовнішнього ID;
  • ручний запуск синхронізації статусу;
  • журнал подій;
  • базова обробка помилок.; №

До MVP входить:

Приклад тіла запиту:
- ValidationError - created_by varchar - new_status varchar Новий статус.; # Викликати Medoc Integration Adapter.; Критерій
if new_status != report.status:
def get_document_status(self, document_id: str) -> "MedocStatusResponse":

21. Acceptance Criteria

tax_report_service.py
  • прийом даних звітності з ERP / облікової системи;
  • формування або прийом готового XML-документа;
  • перевірку документа перед передачею;
  • передачу документа в M.E.Doc;
  • запуск підписання та відправки через M.E.Doc, якщо підтримується API;
  • отримання зовнішнього ID документа;
  • синхронізацію статусів;
  • отримання квитанцій або результатів обробки;
  • збереження історії передачі;
  • обробку помилок;
  • повторну відправку;
  • журналювання всіх технічних і бізнес-подій.;

Для реалізації задачі необхідно отримати: </syntaxhighlight>

19.1.; Змінні середовища

Очікувана відповідь:

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

report.sent_to_tax_at = datetime.now(timezone.utc)
pass

9.; Статуси документа

я хочу повторно відправити документ після технічної помилки,

requires_signature: true

Уточнення: значення статусів є собою попередніми.; Статус M.E.Doc

v
raise InvalidStatusError(
"message": "Document signed via M.E.Doc"
{| class="wikitable"

=== 11.5.; Відправка до ДПС ===
!; Пріоритет
|-
| M.E.Doc
| Формування, підписання, відправка та отримання квитанцій по звітності.; Оновити статус на SentToMedoc.; |-
| file_format
| string
| Так
| XML, PDF, ZIP або інший підтримуваний формат.; | Інкапсулювати API в окремому MedocClient.; "id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",

* реалізувати sign endpoint;
* реалізувати send-to-tax endpoint;
* обробити помилки КЕП;
* обробити помилки відправки;
* фіксувати всі етапи в журналі.; | Опційно.; # Перевірити статус документа.; |-
| Помилка API
| HTTP-код, тіло відповіді, correlation ID.; | Обов'язково для MVP.; |-
| signed
| Signed
| Документ підписано.; {| class="wikitable"

* реалізувати завантаження квитанцій;
* реалізувати збереження PDF/XML/receipt-файлів;
* реалізувати прив'язку файлів до документа;
* реалізувати перегляд історії.; |-
| SentToMedoc
| кожні 5 хвилин
|-
| CreatedInMedoc
| кожні 5 хвилин
|-
| WaitingForSignature
| кожні 15 хвилин
|-
| SentToTax
| кожні 10 хвилин
|-
| WaitingForTaxReceipt
| кожні 10 хвилин
|-
| Receipt1Received
| кожні 10 хвилин
|-
| Accepted / Rejected
| не перевіряти
|}

=== 11.4.; Підписання документа ===

!; # Які endpoint-и використовуються для створення документа?; |-
| AC-5
| M.E.Doc API повертає успішну відповідь.; |-
| waiting_receipt
| WaitingForTaxReceipt
| Очікується квитанція.; |-
| Background jobs
| Celery, RQ або APScheduler.; core/
</syntaxhighlight>
MEDOC_TIMEOUT_SECONDS=30
!; # Які endpoint-и використовуються для отримання статусів?; | Потрібна активна інтеграційні функціональні можливості та документація методів.; |-
| AC-14
| M.E.Doc повертає невідомий статус.; |-
| document_number
| string
| Так
| Номер документа.; Внутрішній статус
=== Етап 2.; Робота з документами ===
POST /api/v1/tax-reports/{report_id}/send-to-tax
|-
| Polling
| Періодичне опитування M.E.Doc REST API.; pass
{| class="wikitable"

=== 11.1.; Створення документа ===

 requires_signature: true
 def sign_document(self, document_id: str) -> "MedocDocumentResponse":
 title: "Декларація з ПДВ"
DATABASE_URL=postgresql+psycopg://user:password@db:5432/reports
<syntaxhighlight lang="python">
!; |-
| report_type
| varchar
| Тип звіту.; Запустити очікування квитанцій.; | платформа повертає список помилок валідації.; Очікуваний результат

* реалізувати створення документа;
* реалізувати збереження файлу;
* реалізувати валідацію;
* реалізувати статуси;
* реалізувати журнал подій.; |-
| Validation
| Pydantic.; Внутрішній статус
== 22. MVP ==
 receipt_service.py
 report.medoc_document_id = response.id
== 4.; Передумови ==
 if report.status not in {
 requires_receipt: true
 details={"raw_status": send_response.status},

!; |-
| payload
| jsonb
| Технічні інформаційні дані події.; |-
| Status Sync Worker
| Фоновий бізнес-процес для актуалізація статусів.; |}

 "report_type": report.report_type,

=== 14.3.; Приклад Python-логіки ===
 allowed_formats:
 event_type="SIGNED_IN_MEDOC",
POST /api/v1/tax-reports/{report_id}/sync-status
|-
| id
| uuid
| ID файлу.; # Чи підтримуються webhook-и?; |-
| DB
| PostgreSQL.; | Основна платформа для подання звітності.; |-
| AC-6
| M.E.Doc повертає помилку.; | Відображати зрозумілу помилку та дозволяти повторне підписання.; |-
| report_type
| string
| Так
| Тип звіту або документа.; |-
| status
| varchar
| Внутрішній статус.; |-
| Medoc REST API
| API для інтеграції облікових систем з M.E.Doc.; |-
| Python-сервіс
| Інтеграційний шар між ERP та M.E.Doc.; # Чи активований компонент M.E.Doc REST API / інтеграційні функціональні можливості?; |-
| metadata
| object
| Ні
| Додаткові реквізити для M.E.Doc.; |}

Мінімальний набір вхідних даних:

 api_key: str | None = None

 },
 sync_statuses.py
!; актуалізація статусу в ERP
 base_url: str
!; Ризик
Якщо M.E.Doc REST API підтримує роботу відповідний метод, Python-сервіс повинен ініціювати відправку документа до ДПС.; status_sync_service.py
|-
| AC-8
| Документ створено в M.E.Doc.; |-
| sent
| SentToTax
| Документ відправлено.; |-
| Недоступність M.E.Doc
| Сервер M.E.Doc або мережа можуть бути тимчасово недоступні.; # Чи потрібно робити UI, чи тільки backend API?; !; |}

 "taxpayer_id": "1234567890",

== 1.; Мета ==

* наявність обов'язкових полів;
* коректність РНОКПП або ЄДРПОУ;
* коректність звітного періоду;
* наявність файлу;
* допустимий формат файлу;
* розмір файлу;
* коректність імені файлу;
* відповідність XML-структурі;
* відповідність XSD, якщо схема доступна;
* відсутність дубля документа;
* наявність налаштувань інтеграції з M.E.Doc.; | Записати відповідь API, дозволити повтор.; |-
| report_id
| uuid
| ID документа.; Тип помилки
 if report.status != TaxReportStatus.READY_TO_SEND:
 entity_id=report.id,
Python Tax Reporting Service

!; |-
| created_at
| timestamp
| Дата створення.; | Статус документа змінюється на SentToTax.; !; |-
| ReadyToSend
| Документ готовий до передачі.; audit_logger.log(

* додати Dockerfile;
* додати docker-compose;
* додати structured logging;
* додати metrics;
* додати alerting;
* додати rate limiting;
* додати security review.; Подія
 v
!; | Зберегти помилку, дозволити повторне підписання.; |-
| file_type
| varchar
| original, signed, pdf, receipt_1, receipt_2, error_protocol.; |}

 )

tax_reporting_medoc_service/

* timeout;
* тимчасової недоступності M.E.Doc API;
* HTTP 429;
* HTTP 500;
* HTTP 502;
* HTTP 503;
* HTTP 504;
* тимчасових мережевих помилок.; |}

 - xml

{

* встановлений та налаштований M.E.Doc;
* активний компонент M.E.Doc інтеграційні функціональні можливості / REST API;
* мережевий доступ до M.E.Doc API;
* базовий URL M.E.Doc REST API;
* спосіб авторизації в API;
* технічну документацію endpoint-ів;
* перелік доступних типів звітності;
* формат передачі файлів;
* формат метаданих документа;
* правила створення документа в M.E.Doc;
* правила підписання документа;
* правила відправки документа;
* правила отримання статусів;
* правила отримання квитанцій;
* тестовий контур або тестову організацію;
* технічний контакт з боку постачальника M.E.Doc.; | платформа надає можливість ініціювати підписання.; Поле
2.; | Зберігати raw-статус та мати UnknownStatus.; # Отримати файл зі сховища.; migrations/

 tax_report_repository.py
</div>
Очікувана дія:
|-
| Draft
| Документ створено, але ще не готовий до передачі.; |-
| Залежність від локального M.E.Doc
| API має змогу працювати тільки за наявності встановленого та налаштованого M.E.Doc.; Рекомендація
class MedocClient:
 requires_receipt: true
def sign_and_send_report(report_id: UUID, db: "Session") -> "TaxReport":

=== 16.2. tax_report_events ===

 password: str | None = None
я хочу передати документ звітності в M.E.Doc без ручного імпорту, 

щоб оперативно знаходити причину помилок інтеграції.; MEDOC_USERNAME=integration_user
=== 16.1. tax_reports ===

4.; !; |-
| API
| Програмний інтерфейс інтеграції.; |-
| AC-13
| M.E.Doc повертає новий статус.; |}

<pre>

 integration/

* Python-сервіс розгортається через Docker;
* API створення документа функціонує;
* документ зберігається у БД та файловому сховищі;
* документ проходить валідацію;
* документ передається в M.E.Doc;
* зовнішній ID документа зберігається;
* статус документа оновлюється;
* помилки API обробляються;
* retry-механізм функціонує;
* журнал подій заповнюється;
* написані unit-тести для ключових сервісів;
* написані інтеграційні тести для MedocClient з mock API;
* документація для запуску додана в README;
* фінальні endpoint-и M.E.Doc винесені в конфігурацію.; |-
| medoc_document_id
| varchar
| ID документа у M.E.Doc.; Валідація та збереження документа
 title: "Об'єднана формування звітів"
 details={
 |
 | 3.; |
 | 4.; Обов'язковість
 pass
 "status": "Signed",
!; !; |-
| Валідація
| Результат, список помилок.; Отримати результат підписання.; # Записати подію в журнал.; |-
| Audit Logger
| Фіксує всі дії користувачів і системи.; |-
| rejected_at
| timestamp
| Дата відхилення.; |-
| Web framework
| FastAPI.; {| class="wikitable"
 old_status = report.status
 report = tax_report_repository.get_by_id(db, report_id)
</div>
 event_type="STATUS_CHANGED",
щоб не створювати документ заново.; |-
| Квитанція
| Підтвердження прийняття, відхилення або обробки звіту.; Критерій
MEDOC_TIMEOUT_SECONDS=30

MEDOC_COMPANY_CODE=12345678

 integrations/
{{SEO
|title=Технічне завдання: Передача документів для звітності в податкову через M.E.Doc для Python
|description=Технічне завдання на реалізацію Python-сервісу для передачі документів податкової звітності через інтеграцію з M.E.Doc.
|keywords=Python, M.E.Doc, Медок, Medoc REST API, податкова звітність, ДПС, API, XML, КЕП, електронна звітність, технічне завдання
}}
 pass
|-
| API Layer
| REST API для прийому документів від ERP.; # Чи є собою тестове середовище?; |}

<pre>

=== 8.5.; Відправка документа до ДПС ===

}
 },
 |
 | 1.; | надає можливість переносити первинні документи та регламентовану формування звітів.; |-
| MedocTimeoutError
| Перевищено час очікування.; # Які типи звітів підтримуються першими?; | У системі створюється запис tax_reports.; характеристика
{
 validation_service.py
=== 7.5.; Повторна відправка ===
Попередній логічний мапінг:
=== 7.2.; Підписання та відправка ===
Python Tax Reporting Service
MEDOC_RETRY_COUNT=3
MEDOC_RETRY_COUNT=3
{| class="wikitable"
 repositories/
MEDOC_PASSWORD=********
 "created_by": "user@example.com"
3.;=== Етап 7.; Квитанції та результати обробки ===

* повна заміна інтерфейсу M.E.Doc;
* власна реалізація подання напряму до API ДПС;
* власна реалізація КЕП, якщо підписання виконується у M.E.Doc;
* автоматичне актуалізація всіх XSD-схем;
* повноцінний UI для бухгалтера;
* автоматична бухгалтерська перевірка сум;
* супровід всіх типів податкової, статистичної та фінансової звітності.; |-
| SentToTax
| Документ передано до ДПС.; |-
| Помилки КЕП
| Можливі проблеми з ключами, паролями або сертифікатами.; характеристика
POST /api/v1/tax-reports/{report_id}/resend
{| class="wikitable"
|-
| Python-сервіс
| Окремий backend-сервіс або компонент, який виконує інтеграцію з M.E.Doc.; status_mapper.py
5.; |-
| M.E.Doc інтеграційні функціональні можливості
| компонент обміну з обліковими системами.; # Записати подію в журнал.; Оновити статус на Signed або Failed.; Поле

* https://medoc.ua/page/integrationapi
* https://medoc.ua/faq/opis-metodv-web-api
* https://medoc.ua/integration
* https://medoc.ua/page/integration
* https://medoc.ua/faq/priklad-stvorennja-pervinnogo-dokumentu-za-dopomogoju-medoc-web-api
* https://medoc.ua/faq/Import-dovidnyka-kontrahentiv-za-dopomohoiu-restapi

 pass

* [[Python]]
* [[FastAPI]]
* [[K2 ERP]]
* [[Податкова звітність]]
* [[M.E.Doc]]
* [[Медок]]
* [[Medoc REST API]]
* [[ДПС]]
* [[КЕП]]
* [[API інтеграція]]

2.; Тип
}
<syntaxhighlight lang="json">
|-
| Створення документа
| ID, користувач системи, дата, тип документа.; | Використовувати retry та чергу задач.; | Додати healthcheck інтеграції та повідомлення адміністратору.;<pre>

!; report.medoc_document_id

16.; Модель даних

try:
Dockerfile
},
models.py

</syntaxhighlight> M.E.Doc

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

event_type="SENT_TO_MEDOC",
M.E.Doc
 single_tax_declaration:
MEDOC_COMPANY_CODE=12345678
 logging.py

 requires_signature: true
 "id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",
<pre>
До першої версії не входить:
!; | У документі зберігається medoc_document_id.;== Передача документа в M.; 13.E.Doc ==

* помилок валідації;
* неправильного API key;
* відсутності прав доступу;
* відхилення документа податковою;
* дублювання документа;
* некоректного формату файлу;
* помилки КЕП через неправильний пароль.; Передача документа через Medoc REST API
=== Передача в M.; 11.3.E.Doc ===
4.; |}

 exceptions.py

 "file_format": "xml",

!; # Викликати метод M.E.Doc для відправки.; характеристика
 retry_backoff_seconds: int = 5
 |
 | 5.; |-
| Rejected
| Документ відхилено.; |-
| ORM
| SQLAlchemy.; tests/

До MVP не входить:

Очікувана відповідь:
from pydantic_settings import BaseSettings
 send_response = medoc_client.send_document(report.medoc_document_id)

{| class="wikitable"

 company_code: str | None = None
RECEIPT_DOWNLOAD_ENABLED=true
== 19.; конфігурація ==

8.1.; Створення документа

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

Етап 6.; Синхронізація статусів

</syntaxhighlight>

raise InvalidStatusError(
"id": "9ddaa913-03a3-4e11-a90a-582adf8a05ff",

8.; Функціональні вимоги

}

; reports = tax_report_repository.get_reports_for_sync()
* ValidationError;
* Failed;
* Rejected;
* DeliveryError;
* NeedResend.; Пріоритет

 - xml

6.; | Реалізується в межах цього ТЗ.;== 24.; Ризики ==
!; характеристика

 routes/
 )
 number=report.document_number,
GET /api/v1/tax-reports/{report_id}
== 6.; технічна архітектура рішення для бізнесу ==
<pre>
!; |-
| Ручне підписання
| користувач системи підписує документ у клієнті M.E.Doc.; |-
| DeliveryError
| Помилка доставки.; | платформа не створює дубль без окремого підтвердження.;== 17.; Обробка помилок ==
|-
| AC-15
| Документ прийнято.; |-
| last_sync_at
| timestamp
| Дата останньої синхронізації.; 
<syntaxhighlight lang="json">
 db/

 "message": "Document sent to M.E.Doc"
 "new_status": "WaitingForSignature",
=== Етап 4.; Передача документів ===
 def download_receipts(self, document_id: str) -> list [bytes]:
 username: str | None = None

1.;
2.; Оновити статус на SentToTax або Failed.; Перевірити, що документ підписано.; |-
| Підписання в Python-сервісі
| Python-сервіс підписує документ до передачі в M.E.Doc.; !; |}

=== Етап 8.; Production hardening ===

7.; Retry не застосовується для:
!; Компонент

MEDOC_RETRY_BACKOFF_SECONDS=5
повної реалізації потрібно мати ліцензію/компонент інтеграції забезпечується через '''істотно:''' M.E.Doc REST API застосовують, коли потрібно як інтеграційний шар між обліковою системою та програмою M.E.Doc.; додатково реалізовано налаштований M.E.Doc, доступ до REST API та офіційну документацію методів.;

</syntaxhighlight>

"period": report.period,
"old_status": old_status,