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_ed25519→kep_diia). Водій-ФОП підписуєcarrierз мобільного (/api/v1/mobile/ettn/…, спільнийshipcore_auto/ettn_signing.py). Деталі — [[adr-2026-06-04-driver-fop-ettn-signing]].
ETTNDocument — ключові поля¶
- transport_invoice →
OneToOneField(TransportInvoice)— джерело даних документа - ettn_number — номер (тестовий формат
TEST-YYYYMMDD-XXXXXX) - status —
draft / submitted / carrier_signed / confirmed / rejected / cancelled - document_data —
JSONField, канонічний знімок ТТН на момент реєстрації (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_mode —
Trueдля Ed25519 тест-режиму
Документ не дублює рядки вантажу чи маршрут окремими полями — він заморожує знімок
TransportInvoiceуdocument_data. Будь-яка зміна знімку інвалідує хеш і всі підписи.
ETTNParty — ключові поля¶
- role —
sender(вантажовідправник) /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 (ProcessPanel → ETTNPage). 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: експортний клієнт