Документы, подписание, отлагательные условия, выдача (T21)¶
disbursement.py — этапы 10–12 SPEC §6: документы по выбранному предложению, подписание кодом подтверждения (ПЭП), проверка отлагательных условий и выдача. Статус меняется только через transition из workflow.py (WORKFLOW.md), поэтому каждый шаг попадает в журнал. Всё, что относится к этим этапам, хранится в одной колонке loan_applications.closing (миграция 0005_closing).
offered -> accepted -> documents клиент выбрал предложение; документы формируются сразу, в том же запросе
documents -> signed -> conditions клиент подписывает все документы одним кодом
conditions -> disbursed worker проверяет условия (мок) и выдаёт деньги (мок)
Отозвать заявку можно до documents включительно; после подписания нельзя (TRANSITIONS).
Документы¶
Список зависит от выбранного предложения (LoanApplication.selected_offer_id):
Документ (doc_id) |
Когда | Кто подписывает |
|---|---|---|
loan_agreement — кредитный договор |
Всегда | Заёмщик |
guarantee_agreement — договор поручительства |
Обеспечение owner_guarantee |
Основной собственник: учредитель с наибольшей долей из ЕГРЮЛ, иначе руководитель |
pledge_agreement — договор залога |
Обеспечение equipment_pledge |
Заёмщик |
msp_guarantee_application — заявка на гарантию Корпорации МСП |
Обеспечение msp_guarantee |
Заёмщик |
У документа есть номер (КД-…, ДП-…, ДЗ-…, МСП-…, из id заявки), подписант и текст с условиями: продукт, сумма, срок, ставка, платёж, обеспечение, порядок выдачи (на счёт клиента или поставщику). Текст — короткая выжимка условий для экрана, а не юридический договор.
Подписание кодом¶
issue_codeсоздаёт код из 6 цифр. Он действует 5 минут, на него есть 3 попытки. В базе хранится только хеш кода. Новый код отменяет прежний; на одну заявку выдаётся не больше 5 кодов.signпроверяет код и подписывает все документы одной подписью:documents → signed → conditions. Вclosing.signatureзаписываются время, кто подписал, способpep_codeи список документов.
Неверный код тратит попытку. Когда попытки закончились, код сгорает, и нужен новый. Неверный или просроченный код — это не исключение: sign возвращает текст для клиента, и потраченная попытка сохраняется.
Отлагательные условия¶
Список условий фиксируется вместе с документами. Worker (disbursement.tick(), тот же цикл, что и workflow.tick()) проверяет заявки в статусе conditions:
| Условие | Когда | Проверка (мок) |
|---|---|---|
guarantee_signed |
Поручительство | Договор поручительства подписан |
pledge_registered |
Залог оборудования | Номер уведомления в реестре уведомлений о залоге движимого имущества (выдуман из id заявки) |
supplier_invoice_checked |
Выдача поставщику (инвестиционный кредит) | Поставщик ≠ заёмщик; сумма кредита ≤ цена − собственный взнос. Номер счёта выдуман |
msp_guarantee_issued |
Гарантия Корпорации МСП | Номер гарантии (выдуман) |
Каждое условие пишет событие в журнал с результатом. Если все условия выполнены, следует выдача. Если какое-то условие не выполнено, заявка остаётся в conditions с отметкой failed и больше не проверяется: из conditions в таблице переходов есть только disbursed. Что делать с такой заявкой, пока не решено (docs/v2/NOTES.md, Unassigned).
Выдача¶
closing.payout:
| Продукт | Куда | Что |
|---|---|---|
Инвестиционный кредит (Offer.disbursement = supplier) |
Поставщику, supplier_inn |
Оплата оборудования по счёту |
| Оборотный кредит | Счёт клиента | Зачисление суммы |
| Овердрафт, кредитная линия | Счёт клиента | Установлен лимит, деньги не зачисляются (kind: limit) |
Номер счёта клиента и id платежа — мок. Текст выдачи — сообщение перехода в disbursed, его видит клиент.
API (/api/v2)¶
| Метод | Кто | Что |
|---|---|---|
POST /api/v2/applications/{id}/accept |
клиент | {"offer_id", "revision"}: offered → accepted → documents, в ответе closing.documents |
GET /api/v2/applications/{id}/documents/{doc_id} |
клиент, сотрудник | Документ: doc_id, kind, title, signer, text, signed_at |
POST /api/v2/applications/{id}/sign/code |
клиент | {"revision"} → {"demo_code", "expires_in", "application"}. 409 не в documents, 422 — лимит кодов |
POST /api/v2/applications/{id}/sign |
клиент | {"code", "revision"}: documents → signed → conditions. Неверный или просроченный код — 422 {"detail", "revision"}: попытка потрачена, версия заявки новая |
closing в GET /api/v2/applications/{id}: offer_id, documents, code (только expires_at и attempts_left, без хеша), codes_issued, signature, conditions, payout. Клиент видит у условий только code, title, status; подробности проверки видит сотрудник.
Упрощения¶
# MOCK:SMS-шлюза нет: код возвращается в ответе (demo_code), и интерфейс показывает его на экране. В банке код уходит на телефон клиента из договора ПЭП.# SIMPLIFICATION:один код клиента подписывает и договор поручительства. В банке поручитель (основной собственник) подписывает своей ПЭП или ЭП.# SIMPLIFICATION:срок кода, число попыток и лимит кодов — константы в коде, а не условия договора ПЭП.# MOCK:залог в реестре уведомлений, счёт поставщика и гарантия Корпорации МСП — проверки внутри проекта с выдуманными номерами; во внешние системы ничего не отправляется.# MOCK:выдача — запись вclosing.payoutи событие журнала, без проводок. Номер счёта клиента выводится из ИНН (40702… для ООО, 40802… для ИП).- Собственный взнос по инвестиционному кредиту считается оплаченным поставщику клиентом напрямую; проверяется только, что кредит его не покрывает.
- Срок на подписание не ограничен: документы можно подписать и после
valid_untilпредложения (docs/v2/NOTES.md, Unassigned).