Cash Transfer — Перекази коштів між своїми рахунками¶
Тип: horizontal, в складі essentials (не окремий модуль)
Backend: backend/essentials/models/cash_transfer.py
Frontend: frontend/erp/src/components/Essentials/CashTransfer/
API: /api/v1/essentials/cash-transfers/
Доданий: 2026-04-23, Phase F-6
Призначення¶
Уніфікований документ для переказу коштів між власними рахунками організації. Покриває всі 4 напрями:
- Каса → Банк
- Банк → Каса
- Банк → Банк
- Каса → Каса
Архітектурне рішення¶
Згідно з project-memory western_accounting_approach: каса і банк — не окремі типи документів, а типи рахунків (Cashbox vs SettlementAccount). UA-вимоги (РКО/ПКО, Касова книга, ліміт готівки 50 000 грн/день) — шарами над цим уніфікованим документом, не окремі сутності.
Модель¶
class CashTransfer(TransactionModel):
organization # FK → Organization
amount, currency
from_cashbox # FK (null) ┐ exactly one of
from_settlement_account # FK (null) ┘
to_cashbox # FK (null) ┐ exactly one of
to_settlement_account # FK (null) ┘
business_operation # FK → BusinessOperation (для головної проводки)
fee_amount # комісія банку (опційно)
fee_business_operation # FK → BusinessOperation (для комісії, required якщо fee>0)
State від TransactionModel: draft → posted → (опц.) marked.
Посту-логіка¶
Service: backend/essentials/services/cash_transfer_service.py
post_cash_transfer(transfer):
1. validate_before_post() # див. нижче
2. reverse_accounting_entries(transfer) # rule: re-post має очищувати
3. post_accounting_entry(..., business_operation=main) # Dt/Ct з BO
4. if fee > 0:
post_accounting_entry(..., business_operation=fee_bo)
5. state = 'posted'
Все під @transaction.atomic — частковий результат неможливий.
Типові Дт/Кт (через pre-configured BusinessOperation):
| Напрям | Dt | Ct |
|---|---|---|
| Каса → Банк | 311 (Banking) | 301 (Cashbox) |
| Банк → Каса | 301 | 311 |
| Банк → Банк | 311 (target) | 311 (source) |
| Каса → Каса | 301 (target) | 301 (source) |
| Комісія (fee>0) | 92 або 949 (expense) | 311 (source) |
Валідація (validate_before_post)¶
- Рівно один source-FK (cashbox або settlement_account)
- Рівно один dest-FK
- Source != Destination
amount > 0- Валюта source / dest збігається з
currencyдокумента (різна валюта → використатиBankExchangeProcess) business_operationмає обидваdebit_accountіcredit_account- Якщо
fee_amount > 0→fee_business_operationобов'язкове і має обидва рахунки date > posting_lock_date(якщо налаштовано)
Endpoints¶
Стандартний ModelViewSet з двома custom actions:
| Endpoint | Method | Призначення |
|---|---|---|
/cash-transfers/ |
GET, POST | Список / створити |
/cash-transfers/{id}/ |
GET, PUT, PATCH, DELETE | Деталь / edit / видалити |
/cash-transfers/{id}/form-data/ |
GET | Запис + refs для форми |
/cash-transfers/form-refs/ |
GET | Refs для нового запису |
/cash-transfers/{id}/post_document/ |
POST | Провести документ |
/cash-transfers/{id}/unpost_document/ |
POST | Скасувати проведення |
Відповідність правилам¶
Слідує .claude/rules/document-posting.md:
- ✅ state у read_only_fields серіалізатора
- ✅ validate() блокує edit коли state='posted' (якщо context не має allow_posted_edit)
- ✅ Re-post видаляє старі PostingGroup через reverse_accounting_entries перед створенням нових
- ✅ Unpost видаляє всі PostingGroup
- ✅ Записи регістру створюються тільки через post_accounting_entry, не прямою вставкою
- ✅ Post/unpost обгорнуті в @transaction.atomic
- ✅ validate_before_post перевіряє posting_lock_date
MVP обмеження (Phase 1)¶
- Тільки одна організація per документ (intercompany — пізніше)
- Однакова валюта source=dest (різна валюта →
BankExchangeProcess) - Immediate transfer — без «грошей в дорозі» (рах. 333)
- Single transfer — без масових операцій
🔮 Deferred¶
- Money in transit (333) — опціональний двоетапний флоу: списання сьогодні, зарахування через N днів
- Cross-currency transfer — інтеграція з
BankExchangeProcessяк source+destination - Bulk transfer — масове перерахування зарплат на різні банки одним документом
- UA print forms: РКО (КО-1) для касових напрямів, платіжне доручення для банківських
- UA cash limit validation — блокувати касові перекази понад 50 000 грн/день між юр.особами
- AI: anomaly detection — попередження про нетиповий за розміром переказ (розглянуто під A.6 checkpoint, відкладено)
- Bank Reconciliation integration — matching bank statement rows до posted CashTransfers
Status¶
MVP Phase 1 — завершено 2026-04-23. Бекенд + фронтенд + docs. Smoke-тести ручні. Unit-тести — TODO.