Аналіз документа «Прихідна накладна» (Goods Receipt)¶
Дата аналізу: 2026-04-13 Мета: порівняти поточну реалізацію з SAP, D365, 1С, Odoo; визначити прогалини та план покращень.
1. Поточний стан реалізації¶
1.1 Бекенд¶
Моделі:
- GoodsReceipt (backend/essentials/models/goods_receipt.py) — заголовок документа
- Поля: supplier, organization, warehouse, contract, currency, business_operation, payment_type, total_amount
- Автоперерахунок total_amount при зміні рядків
- Стани: draft → posted → marked
GoodsReceiptLine— рядок документа- Поля: item, unit, quantity, price, amount, tax_rate/vat_rate/vat_amount/price_gross, batch_number, serial_number, expiry_date
- Автоматичний розрахунок amount, vat_amount, price_gross при save()
Проведення (backend/essentials/views/transactions.py, GoodsReceiptViewSet.post_document):
- Для кожного рядка:
1. Автогенерація batch_number якщо порожній ({doc.number}-{line.pk})
2. Конвертація ціни в облікову та презентаційну валюту (convert_to_dual())
3. Створення Batch + StockTransaction через receive_batch()
4. Створення запису InventoryJournal
5. Якщо є business_operation — бухгалтерські проводки (основна + ПДВ)
- Відміна: reverse_batch_receipt() з guard (не можна якщо партії вже видані)
Сервіси:
- batch_service.py — FIFO deduction, WAC calculation, receive/reverse batch, ItemWarehouseStock refresh
- currency_service.py — dual-currency conversion (документна → облікова/презентаційна)
- SELECT FOR UPDATE на Batch rows для race-condition safety
API endpoints:
GET/POST /essentials/goods-receipts/
GET/PUT /essentials/goods-receipts/{id}/
GET /essentials/goods-receipts/{id}/form-data/ — документ + refs
GET /essentials/goods-receipts/form-refs/ — refs + next_number
POST /essentials/goods-receipts/{id}/post_document/
POST /essentials/goods-receipts/{id}/unpost_document/
CRUD /essentials/goods-receipt-lines/
1.2 Фронтенд¶
Компоненти (frontend/erp/src/components/Essentials/GoodsReceipt/):
| Файл | Призначення |
|---|---|
GoodsReceiptPage.tsx |
Роутер: list / form / print |
GoodsReceiptList.tsx |
Таблиця документів з фільтрами |
GoodsReceiptForm.tsx |
Форма створення/редагування |
GoodsReceiptFields.tsx |
Основні поля (2 fieldset: Контрагенти + Надходження) |
GoodsReceiptSubtables.tsx |
Таблиця рядків з inline editing + modal |
GoodsReceiptFormToolbar.tsx |
Панель дій |
GoodsReceiptListToolbar.tsx |
Панель фільтрів списку |
Поля заголовка: - Fieldset «Контрагенти»: Organization, Supplier, Contract - Fieldset «Надходження»: Warehouse, Currency, Business Operation, Payment Type
Рядки (SubtablePanel):
- Inline edit: item, unit, quantity, price, vat_rate, batch_number
- Modal edit: + sequence, tax_rate, serial_number, expiry_date
- Автоматичне підтягування ціни/одиниці при виборі товару (/essentials/pricing/lookup/)
- Footer: Amount | VAT | Total (з акцентним Total на синьому тлі)
Особливості: - Draft lines — локальні рядки до першого збереження (~115 рядків коду) - Custom post flow: create doc → flush draft lines → post - Автозаповнення валюти та payment_type з контракту - Фільтрація контрактів по supplier + organization
2. Порівняння з провідними DOP¶
2.1 SAP S/4HANA (MIGO)¶
| Функція | SAP | ESWF | Висновок |
|---|---|---|---|
| Зв'язок з Purchase Order | GR прив'язується до PO | Немає PO | Відсутнє |
| 3-way matching (PO ↔ GR ↔ Invoice) | Автоматичний | Відсутній | Відсутнє |
| Tolerance check (допуски кількість/ціна) | Configurable ±% | Немає | Відсутнє |
| Storage Location (зона/бін) | Склад → Зона → Бін | Тільки warehouse | Часткове |
| Quality Inspection | QM auto-trigger | Відсутній | Відсутнє |
| Return to Vendor | Movement Type 122 | Немає окремого документу | Відсутнє |
| Batch Split (1 рядок → кілька партій) | Так | 1 рядок = 1 партія | Часткове |
| Movement Types (200+) | Так | Тільки receipt | Мінімальне |
| Freight / Landed Cost | Так | Відсутній | Відсутнє |
| Dual-currency | doc + local + group | doc + accounting + presentation | На рівні |
2.2 Microsoft Dynamics 365 F&SCM¶
| Функція | D365 | ESWF | Висновок |
|---|---|---|---|
| Product Receipt (packing slip) | Окремий етап | Немає | Відсутнє |
| PO workflow (PO → Receipt → Invoice) | Так | Тільки GR | Відсутнє |
| Charges (фрахт, митні збори) | На заголовку/рядках | Відсутній | Відсутнє |
| Inventory Dimensions | Site → WH → Location → Batch → Serial | WH + Batch + Serial | Часткове |
| Financial dimensions on lines | Cost center, department per line | Тільки business_operation на заголовку | Часткове |
| Over/under delivery | Configurable per item | Немає | Відсутнє |
| Discount handling (рядкова/документна) | Так | Відсутній | Відсутнє |
2.3 1С:Підприємство¶
| Функція | 1С | ESWF | Висновок |
|---|---|---|---|
| Документ-підстава (Замовлення → Надходження) | Так | Немає замовлення постачальнику | Відсутнє |
| Кілька складів в одному документі | Так (warehouse per line) | Один склад на заголовку | Обмеження |
| Характеристики номенклатури | Розмір, колір, конфігурація | Відсутні | Відсутнє |
| Додаткові витрати з розподілом | Пропорційно сумі/кількості | Відсутній | Відсутнє |
| Друковані форми (М-4, ТОРГ-12) | Так | PrintEngine (Fortune Sheet) | На рівні |
| Штрихкод-сканер | Пошук по штрихкоду | Відсутній | Відсутнє |
| Курсові різниці | Автоматичний розрахунок | Тільки конвертація на дату | Часткове |
2.4 Odoo 17¶
| Функція | Odoo | ESWF | Висновок |
|---|---|---|---|
| Multi-step receipt (Input → Quality → Stock) | 1/2/3-step | Тільки 1-step | Часткове |
| Backorders | Автоматичне створення | Відсутнє | Відсутнє |
| Landed Costs | Окремий документ | Відсутнє | Відсутнє |
| Lot/Serial tracking rules per product | Configurable | Все однаково | Часткове |
| UoM conversion (коробки → штуки) | Автоматичний | Одна одиниця | Відсутнє |
3. Виявлені прогалини¶
3.1 Критичні (відсутній базовий функціонал)¶
3.1.1 Знижки (Discounts)¶
- Немає рядкових знижок (
discount_percent) - Немає документних знижок
- Формула:
amount = qty × price × (1 - discount% / 100)
3.1.2 Додаткові витрати (Charges / Landed Cost)¶
- Фрахт, страхування, митні збори — не враховуються у собівартості
- Потрібна окрема таблиця витрат з розподілом по рядках (пропорційно сумі або кількості)
3.1.3 Purchase Order → Goods Receipt linkage¶
- Не можна створити GR «на основі» замовлення постачальнику
- Немає контролю «що замовлено vs. що отримано»
- Немає backorder tracking
3.1.4 Конвертація одиниць виміру¶
- Одна одиниця per line без конвертації
- Постачальник продає в коробках, облік — у штуках → зараз неможливо
3.1.5 Warehouse per line¶
- Один склад на весь документ
- Одна накладна не може розподілити товар по кількох складах
3.2 Важливі (UX та якість)¶
3.2.1 Валідація при проведенні — мінімальна¶
- Перевіряється лише:
lines.exists()таline.item_id - НЕ перевіряється: warehouse, currency, organization ≠ null; quantity > 0; price >= 0
3.2.2 Ліміт 200 записів у refs¶
_build_refs()→qs[:200]для всіх довідників- Якщо 500+ товарів — частина не потрапить у select
- Потрібен server-side search (typeahead)
3.2.3 Немає optimistic locking¶
- Два користувачі можуть одночасно редагувати — останній перезаписує зміни першого (lost update)
3.2.4 Post logic у ViewSet (anti-pattern)¶
post_document— 170+ рядків бізнес-логіки в HTTP handler- Неможливо перевикористати з management commands / Celery / tests
3.2.5 Draft lines дублювання¶
- ~115 рядків складної логіки в GoodsReceiptForm.tsx для draft lines + custom post
- Дублюється в кожній кастомній формі документа
4. Рекомендації по UI/UX¶
4.1 Sticky header документа¶
Зараз: Номер і дата ховаються при скролі рядків. Рекомендація: Зафіксований header з: - Номер + дата (великий шрифт) - Статус як кольоровий badge (draft=сірий, posted=зелений) - Постачальник (quick-view) - Загальна сума (завжди видима)
4.2 Розширений summary panel¶
Зараз: Amount | VAT | Total — тільки 3 числа. Додати: - Кількість позицій / загальна кількість одиниць - Розбивка по ставках ПДВ (20%: ₴X, 7%: ₴Y, 0%: ₴Z) - Вага брутто/нетто (якщо є на товарі)
4.3 Paste з Excel¶
Ctrl+V→ розпарсити clipboard → створити рядки- Drag-and-drop зона для Excel/CSV файлів
- Критично для масового введення
4.4 Покращений пошук товару¶
Зараз: Select з пошуком по назві. Додати: - Пошук по штрихкоду / артикулу / коду - Recent items (останні вибрані) вгорі списку - Quick-add «+ Створити» прямо з select'у - Показувати залишок на складі при виборі (inline підказка)
4.5 Візуальний status flow¶
4.6 Attachment'и¶
- Скан накладної, сертифікат якості, фото вантажу
- Прив'язка до заголовка або окремого рядка
4.7 Audit trail UI¶
- Хто створив / змінив / провів / відмінив
- Часові мітки всіх операцій
- Порівняння версій (diff)
4.8 Multi-row operations в таблиці рядків¶
- Multi-select (checkbox або Shift+Click) для bulk delete
- Drag-and-drop reorder рядків
- Auto-fill (drag cell value down)
5. Рекомендації по архітектурі¶
5.1 Винести post/unpost у сервіс¶
backend/essentials/services/goods_receipt_service.py
def post_goods_receipt(receipt: GoodsReceipt) -> PostResult:
"""Повна логіка проведення — batch, journal, accounting."""
def unpost_goods_receipt(receipt: GoodsReceipt) -> None:
"""Відміна проведення з guard-перевірками."""
@action(detail=True, methods=['post'], url_path='post_document')
def post_document(self, request, pk=None):
obj = self.get_object()
result = post_goods_receipt(obj)
if result.errors:
return Response({'detail': ..., 'errors': result.errors}, status=400)
return Response(self.get_serializer(obj).data)
5.2 Pre-posting validation¶
def validate_before_post(receipt: GoodsReceipt) -> list[str]:
errors = []
if not receipt.warehouse_id:
errors.append("Warehouse is required")
if not receipt.currency_id:
errors.append("Currency is required")
if not receipt.organization_id:
errors.append("Organization is required")
for line in receipt.lines.all():
if line.quantity <= 0:
errors.append(f"Line {line.pk}: quantity must be positive")
if line.price < 0:
errors.append(f"Line {line.pk}: price cannot be negative")
return errors
5.3 Server-side search для refs¶
Замість завантаження всіх 200 записів — typeahead endpoint:
На фронтенді:useRefSelect з debounced пошуком.
5.4 Optimistic locking¶
Додати version або використати updated_at для перевірки:
if obj.updated_at != payload.get('_updated_at'):
raise ConflictError("Document was modified by another user")
5.5 Draft lines у useDocumentForm¶
Перенести draft-lines логіку з GoodsReceiptForm у useDocumentForm hook — прибере ~100 рядків з кожної кастомної форми.
6. Зведена оцінка¶
| Аспект | Оцінка | Коментар |
|---|---|---|
| Базова функціональність | 7/10 | CRUD + проведення працює |
| Batch/Lot tracking | 8/10 | FIFO + WAC, dual-currency — на рівні |
| Accounting integration | 7/10 | PostingGroup + InventoryJournal |
| UI/UX форми | 6/10 | Функціональна, але базова |
| UI/UX списку | 6/10 | Стандартна таблиця, page_size=50 |
| Валідація | 5/10 | Мінімальна перед проведенням |
| Повнота vs SAP/D365 | 4/10 | Немає PO, charges, discounts |
| Повнота vs 1С | 5/10 | Немає замовлення, додаткових витрат |
| Архітектура | 6/10 | Post logic у ViewSet, ліміт refs |
| Data integrity | 8/10 | SELECT FOR UPDATE, guard on unpost |
7. План імплементації покращень¶
Фаза 1 — Quick wins (1-2 дні кожне)¶
| # | Задача | Тип | Файли |
|---|---|---|---|
| 1.1 | Pre-posting validation (warehouse, currency, org, qty>0, price>=0) | Backend | views/transactions.py або новий services/goods_receipt_service.py |
| 1.2 | Знижка рядка (discount_percent на GoodsReceiptLine) |
Backend + Frontend | models/goods_receipt.py, serializers/transactions.py, GoodsReceiptSubtables.tsx |
| 1.3 | Server-side search для items (замість ліміту 200) | Backend + Frontend | views/transactions.py, GoodsReceiptSubtables.tsx → typeahead |
| 1.4 | Розширений summary panel (к-сть позицій, розбивка ПДВ) | Frontend | GoodsReceiptForm.tsx footer |
| 1.5 | Sticky document header (номер, дата, статус, сума) | Frontend | DocumentFormShell.tsx або GoodsReceiptForm.tsx |
Фаза 2 — Середня складність (3-5 днів кожне)¶
| # | Задача | Тип | Файли |
|---|---|---|---|
| 2.1 | Витяг post/unpost у goods_receipt_service.py |
Backend refactoring | Новий services/goods_receipt_service.py, спрощення views/transactions.py |
| 2.2 | Warehouse per line (fallback на header) | Backend + Frontend | models/goods_receipt.py, GoodsReceiptSubtables.tsx |
| 2.3 | Paste з Excel (clipboard → lines) | Frontend | GoodsReceiptSubtables.tsx або SubtablePanel.tsx |
| 2.4 | Attached files (скан накладної, сертифікати) | Backend + Frontend | Нова модель DocumentAttachment, UI компонент |
| 2.5 | Audit trail UI | Backend + Frontend | Використати AuditLog, новий UI компонент |
| 2.6 | Optimistic locking | Backend + Frontend | TransactionModel, serializer validation |
| 2.7 | Draft lines → useDocumentForm | Frontend refactoring | useDocumentForm.ts, спрощення всіх кастомних форм |
Фаза 3 — Стратегічні (1-2 тижні кожне)¶
| # | Задача | Тип | Файли |
|---|---|---|---|
| 3.1 | Purchase Order документ | Backend + Frontend | Нові models, serializers, views, компоненти |
| 3.2 | GR «на основі PO» (linkage + заповнення) | Backend + Frontend | goods_receipt.py → FK до PO, auto-fill logic |
| 3.3 | Landed Cost (додаткові витрати з розподілом) | Backend + Frontend | Нова модель GoodsReceiptCharge, розподіл по рядках |
| 3.4 | UoM conversion (коробки → штуки) | Backend + Frontend | Unit модель + conversion table, line-level calc |
| 3.5 | Multi-step receipt (вхідний контроль → якість → склад) | Backend + Frontend | Workflow engine, нові стани документа |
| 3.6 | 3-way matching (PO ↔ GR ↔ Vendor Invoice) | Backend + Frontend | Matching service, звітність розбіжностей |
8. Ключові файли для імплементації¶
Backend¶
backend/essentials/models/goods_receipt.py — модель документа і рядків
backend/essentials/serializers/transactions.py — серіалізатори
backend/essentials/views/transactions.py — GoodsReceiptViewSet (рядки 367-644)
backend/essentials/services/batch_service.py — receive_batch, reverse_batch_receipt
backend/essentials/services/currency_service.py — dual-currency conversion
backend/essentials/models/batch.py — Batch, ItemWarehouseStock
backend/essentials/models/stock_transaction.py — StockTransaction
backend/essentials/models/inventory_journal.py — InventoryJournal
backend/registers/models/inventory_journal.py — Register-level InventoryJournal
Frontend¶
frontend/erp/src/components/Essentials/GoodsReceipt/ — всі 7 компонентів
frontend/erp/src/hooks/useDocumentForm.ts — хук документної форми
frontend/erp/src/components/shared/DocumentFormShell.tsx — shell-обгортка
frontend/erp/src/components/shared/SubtablePanel.tsx — табличний редактор рядків
frontend/erp/src/api/inventory.ts — API виклики
frontend/erp/src/config/essentials.ts — конфігурація (goodsReceipts item)