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

eTTN — електронна товарно-транспортна накладна

Реалізація електронної ТТН відповідно до законодавства України. Замість паперової накладної — цифровий документ з підписом Ed25519, що передається між учасниками.


1. Призначення

Електронна ТТН (eTTN) замінює паперову форму ТТН-1, яка раніше супроводжувала вантаж при перевезенні. Переваги: - Швидке формування (без ручного заповнення формуляра) - Цифровий підпис → юридична сила без друку - Передача між учасниками online (відправник → перевізник → отримувач) - Архівація + швидкий пошук - Інтеграція з податковою системою


2. Учасники документа

Сторона Роль
Відправник (Shipper) Хто відвантажує товар (звичайно — продавець)
Перевізник (Carrier) Транспортна компанія / водій
Отримувач (Consignee) Хто отримує товар (покупець)
Замовник перевезення Хто платить за перевезення (може = відправник або отримувач)

3. Backend моделі

backend/shipcore_auto/models/ettn.py (Phase 4 Day-7; legacy шлях backend/fleet/ — re-export shim, що вказує сюди):

Модель Призначення
ETTNDocument Документ eTTN — 1:1 до TransportInvoice (ТТН)
ETTNParty Сторона підписання (sender / carrier / recipient)

⚠️ Оновлено 2026-05-31: ETTNTestKey (per-user OneToOne) видалено. Авторитет підпису тепер org-bound: essentials.OrgMembership(user, org, can_sign) + спільний на ЄДРПОУ ключ edo.SigningKey ([[adr-2026-05-31-org-membership]]).

Оновлено 2026-06-04: підпис диспатчиться через SignatureProvider (edo/signing_providers.py), перемикач EdoExchangeSettings.signature_mode (test_ed25519kep_diia). Водій-ФОП підписує carrier з мобільного (/api/v1/mobile/ettn/…, спільний shipcore_auto/ettn_signing.py). Деталі — [[adr-2026-06-04-driver-fop-ettn-signing]].

ETTNDocument — ключові поля

  • transport_invoiceOneToOneField(TransportInvoice) — джерело даних документа
  • ettn_number — номер (тестовий формат TEST-YYYYMMDD-XXXXXX)
  • statusdraft / submitted / carrier_signed / confirmed / rejected / cancelled
  • document_dataJSONField, канонічний знімок ТТН на момент реєстрації (sender / receiver / carrier / vehicle / driver / cargo / weight / …)
  • document_hash — SHA-256 hex від канонічного JSON (база для підписів)
  • rejection_reason, submitted_at / confirmed_at / cancelled_at, created_by
  • is_test_modeTrue для Ed25519 тест-режиму

Документ не дублює рядки вантажу чи маршрут окремими полями — він заморожує знімок TransportInvoice у document_data. Будь-яка зміна знімку інвалідує хеш і всі підписи.

ETTNParty — ключові поля

  • rolesender (вантажовідправник) / carrier (перевізник) / recipient (вантажоодержувач)
  • name, edrpou — реквізити сторони
  • signed / signed_at / signed_by — стан підпису
  • signature — Base64 Ed25519-підпис над document_data
  • signed_hash — SHA-256 на момент підпису (виявлення підробки)
  • key_fingerprint — перші 16 hex SHA-256 публічного ключа (для відображення)

Криптографія (shipcore_auto/ettn_service.py)

  • Алгоритм: Ed25519 (RFC 8032, швидкий, підпис 64 байти)
  • Бібліотека: cryptography
  • Канонічний JSON: json.dumps(..., sort_keys=True, ensure_ascii=False) → детермінований байт-рядок
  • Кожен учасник має свій ключ (приватний → у нього, публічний → у системі для верифікації)
  • Зміна будь-якого поля знімку інвалідує підпис

4. Frontend (ERP)

Сторінка: ETTNPage.tsx — процес-айтем ettn у Fleet (ProcessPanelETTNPage). API-клієнт frontend/dop/fleet/api/ettn.ts б'є канонічний /api/v1/shipcore-auto/….

Функції: - Список транспортних накладних зі статусом eTTN, фільтр за статусом + пошук, плитки-лічильники - Lifecycle: register → submit → cancel - Підписання Ed25519 за роллю (sender / carrier / recipient) з тестового ключа користувача - Панель «Мій ключ»: згенерувати / переглянути / видалити пару Ed25519 - Верифікація підписів усіх сторін + перегляд хешу документа


5. Workflow (фактичний)

1. register — створити eTTN на базі TransportInvoice:
   └── document_data ← знімок ТТН, document_hash ← SHA-256
   └── автоствворюються ETTNParty зі sender/carrier/receiver накладної
   └── Status: draft

2. submit — подати до реєстру:
   └── Status: submitted

3. sign (по кожній стороні) — Ed25519 підпис над document_data:
   └── перша підпис перевізника:       Status: carrier_signed
   └── коли підписали ВСІ сторони:      Status: confirmed (+ confirmed_at)

   reject — відхилити (з submitted / carrier_signed): Status: rejected
   cancel — скасувати (поки не confirmed/cancelled):  Status: cancelled

4. verify — будь-коли перевірити підписи всіх сторін (повертає valid per-role)

Перехід статусів автоматичний у ETTNDocument._update_status_from_signatures() після кожного підпису. GPS-трек і архівація — поза поточним обсягом.


5a. API endpoints

Канонічний префікс — /api/v1/shipcore-auto/ (legacy alias /api/v1/fleet/ ще працює):

GET    /transport-invoices/                      — список ТТН з полями ettn_status / ettn_number
GET    /transport-invoices/{id}/ettn/status/     — статус eTTN для накладної
POST   /transport-invoices/{id}/ettn/register/   — зареєструвати eTTN (→ draft)
POST   /transport-invoices/{id}/ettn/submit/     — подати (→ submitted)
POST   /transport-invoices/{id}/ettn/cancel/     — скасувати

GET    /ettn/                                    — список eTTN тенанту
GET    /ettn/{id}/                               — деталь
POST   /ettn/{id}/sign/    { role }              — підписати за роллю (Ed25519)
POST   /ettn/{id}/reject/  { reason }            — відхилити
POST   /ettn/{id}/verify/                        — верифікувати підписи всіх сторін

GET    /ettn-keys/me/                            — мій тестовий ключ (без приватного)
POST   /ettn-keys/generate/                      — згенерувати / перегенерувати пару Ed25519
DELETE /ettn-keys/me/                            — видалити тест-ключ

6. Інтеграція з документами

Поточне джерело — TransportInvoice (ТТН)

eTTN реєструється з транспортної накладної (TransportInvoice): сторони (sender / carrier / recipient) і реквізити вантажу автозаповнюються зі знімка накладної у document_data. Інших точок створення наразі немає.

🔮 Майбутнє — auto-create з GoodsShipment / Waybill

Кнопка «Створити eTTN» на видатковій накладній або авто-створення при формуванні Waybill з вантажним замовленням — ще не реалізовано (ідея). Триґер активації — клієнт із наскрізним потоком відвантаження → eTTN.


7. Тестове середовище

ETTNTestKey — таблиця тестових ключів для dev/QA: - Зручно для тестування підписів без реальних USB-токенів - В production — приватні ключі не зберігаються у системі (в ідеалі — на ключовому носії)


8. Регуляторні питання

  • Поточна реалізація — proof-of-concept з Ed25519. У production-edition потрібна:
  • Інтеграція з УЦСК (КЕП) — вимога українського законодавства для юридично значущих підписів
  • Передача документів через офіційні шлюзи (M.E.Doc, Vchasno, тощо)
  • Для внутрішнього використання (B2B, де сторони довіряють один одному) — Ed25519 достатньо

🔮 Deferred / Ideas

КЕП-інтеграція через УЦСК

Мотивація: обов'язкова вимога для юридично значущого документообігу в Україні Чому відкладено: потрібна сертифікація + інтеграція з токенами (Diia.Signature, IIT) Trigger: клієнт з вимогою юридично значущих eTTN

Інтеграція з ЦБД ТТН (НДЛБ)

Мотивація: Україна планує єдину базу електронних накладних Чому відкладено: API ще не релізнутий державою Trigger: запуск державного реєстру

QR-код для миттєвої передачі

Мотивація: на дорозі — водій показує QR, інспектор сканує → бачить eTTN Чому відкладено: UI для генерації + перевірки QR Trigger: дорожні перевірки + вимога ДПС

Mass-signing для пачок документів

Мотивація: оптові відвантаження — 50+ накладних/день Чому відкладено: потрібен batch-sign UI + safety Trigger: клієнт з великим обсягом

Multi-language eTTN (export)

Мотивація: експортні перевезення — потрібен документ російською/англійською Чому відкладено: необхідні шаблони для перекладу Trigger: експортний клієнт


Пов'язане