Фабрика документов
Электронные документы в кооперативе — это юридически-значимые действия. Для них важны одинаковая форма, повторяемость и проверяемость. Фабрика автоматизирует процесс и делает его повторяемым: каждый документ создаётся по одному маршруту, на основе шаблона, версии шаблона и исходных данных, которые можно перепроверить. Это защищает от расхождений между версиями, гарантирует, что контрольная сумма и подпись относятся к тому же содержимому, и самое главное - позволяет автоматизировать работу документами в стандартизированных бизнес-процессах кооператива.
Электронный документ¶
Электронный документ — файл, который содержит юридически-значимое действие пайщика. Он создан по общему кооперативному стандарту, может быть подписан и передан.
Электронный документ в кооперативной экономике может находится в двух математически-связанных между собой состояниями: полная форма и подписанная форма.
Полная форма документа включает в себя "сырые" данные, доступные для отображения или скачивания в виде PDF-файла. Это тот вид документа, который мы привыкли видеть, и который содержит все данные, которые в нем должны быть - все заполненные поля, доступные для чтения, и т.д..
Интерфейс данных полного документа:
⚠️ Интерфейс GeneratedDocument не найден в typedoc_data
Подписанная форма документа включает в себя контрольную сумму полной формы, следовательно, они математически-взаимосвязаны - из полной формы всегда можно получить контрольную сумму подписанной формы и произвести сверку. В подписанной форме всегда есть контрольная сумма полного документа и мета-данные, которых достаточно для того, чтобы установить того, кто сгенерировал документ, и того, кто его подписал, и сделать это математически-точно и без публичного раскрытия персональных данных.
Интерфейс данных подписанного документа:
⚠️ Интерфейс SignedBlockchainDocument не найден в typedoc_data
Обратное же, т.е. получить полную форму из подписанной может только тот, у кого есть доступ к закрытой информации в базе данных кооператива - обычно это или пайщик, кому принадлежит документ, или член совета.
Для передачи подписей в документах используется следующий интерфейс:
⚠️ Интерфейс SignatureInfoInput не найден в typedoc_data
Он позволяет накладывать на документ и поверх предыдущих подписей неограниченное количество новых подписей. Обычно, нам в наших бизнес-процессах не требуется больше двух подписей на одном документе (например, на акте приёма-передачи требуется две подписи). Но для исключительных случаев мы не ограничены в количестве подписей на одном документе.
Проверка подписей осуществляется на уровне смарт-контрактов блокчейна, требуя наличия подписи от конкретного аккаунта-участника бизнес-действия. Кроме этого, проверку подписей документов осуществляет бэкенд программного комплекса цифрового кооператива каждый раз при запросе документов пайщиком или членом совета.
Подпись документа¶
Как мы ранее могли обратить внимание, внизу каждого электронного документа на платформе есть блок подписи, давайте взглянем на него еще раз:

Мы видим контрольную сумму документа, а также блок с указанием количества подписей, где каждая подпись указывает на сертификат подписанта. Сертификаты выдаются пайщикам при регистрации и хранятся в базе данных кооператива. Мы извлекли сертификат пайщика на основании имени аккаунта подписанта, которое мы безопасно хранили в блокчейне.
Далее мы видим цифровую подпись. Как мы ранее говорили, она накладывается на контрольную сумму документа с помощью приватного ключа пайщика. А поскольку мы обладаем именем аккаунта пайщика, то мы всегда можем извлечь публичный ключ и произвести математическую сверку корректности подписи и ее принадлежности к указанному аккаунту. Что мы и делаем, когда показываем идентификатор статуса подписи - "Верифицирована".
Глубокая сверка¶
При необходимости из базы данных кооператива могут быть извлечены исходные данные, которые использовались для генерации полного документа, и использованы для того, чтобы на основании публичных мета-данных произвести глубокую сверку.
При глубокой сверке фабрика документов произведет полную регенерацию документа из исходных данных, заполнив ими шаблон электронного документа заново, и если все в порядке - то получит тот же самый результат в виде полностью идентичной контрольной суммы документа, который и был подписан. Глубокую сверку документов рекомендуется производить у всех документов пайщиков до принятия решений по ним.
Фабрика документов¶
Итак, что же такое фабрика документов?
Фабрика документов - это архитектурный паттерн, который позволяет производить одинаковым образом разные документы за счет использования шаблонов и общих стандартов генерации.
Фабрика предоставляет конвейеры по производству электронных документов, которые работают в целом одинаково: извлекают шаблон документа из блокчейна, подставляют данные пайщиков, формируют полный документ и возвращает его пайщику. Т.е. фабрика отвечает за генерацию и глубокую сверку документов, а также за резервное хранение полных документов и сертификатов пайщиков с их личными данными с полной историей изменений, на основании которых эти полные документы генерировались.
Таким образом, фабрика способна в любой момент предоставить или полный документ или произвести глубокую сверку документа на основании своих исторических данных.
Мы не будем в данном разделе подробно останавливаться на принципах генерации документов из шаблов, т.к. это продукт стандартов кооперативной экономики и данный материал будет описан на соответствующих страницах сайта https://coopenomics.world.
Реестр шаблонов¶
| id | Название | SDK | GraphQL |
|---|---|---|---|
| 1 | Согласие с условиями ЦПП «ЦИФРОВОЙ КОШЕЛЕК» | ⚠️ 🛠️ SDK: Mutations.Agreements.GenerateWalletAgreement не найден | Mutation.generateWalletAgreement |
| 2 | Согласие с условиями положения о простой электронной подписи | ⚠️ 🛠️ SDK: Mutations.Agreements.GenerateSignatureAgreement не найден | Mutation.generateSignatureAgreement |
| 3 | Согласие с условиями политики обработки конфиденциальных данных | ⚠️ 🛠️ SDK: Mutations.Agreements.GeneratePrivacyAgreement не найден | Mutation.generatePrivacyAgreement |
| 4 | Согласие с условиями пользовательского соглашения | ⚠️ 🛠️ SDK: Mutations.Agreements.GenerateUserAgreement не найден | Mutation.generateUserAgreement |
| 50 | Пользовательское соглашение (оферта) о присоединении к платформе "Кооперативная Экономика" | — | — |
| 51 | Заявление о конвертации паевого взноса в членский взнос | ⚠️ 🛠️ SDK: Mutations.Provider.GenerateConvertToAxonStatement не найден | Mutation.generateConvertToAxonStatement |
| 100 | Заявление на вступление в кооператив | ⚠️ 🛠️ SDK: Mutations.Participants.GenerateParticipantApplication не найден | Mutation.generateParticipantApplication |
| 101 | Заявление пайщика о выборе кооперативного участка | ⚠️ 🛠️ SDK: Mutations.Branches.GenerateSelectBranchDocument не найден | Mutation.generateSelectBranchDocument |
| 300 | Предложение повестки дня общего собрания | ⚠️ 🛠️ SDK: Mutations.Meet.GenerateAnnualGeneralMeetAgendaDocument не найден | Mutation.generateAnnualGeneralMeetAgendaDocument |
| 301 | Решение совета о созыве общего собрания | ⚠️ 🛠️ SDK: Mutations.Meet.GenerateSovietDecisionOnAnnualMeetDocument не найден | Mutation.generateSovietDecisionOnAnnualMeetDocument |
| 302 | Уведомление о проведении общего собрания | ⚠️ 🛠️ SDK: Mutations.Meet.GenerateAnnualGeneralMeetNotificationDocument не найден | Mutation.generateAnnualGeneralMeetNotificationDocument |
| 303 | Заявление с бюллетенем для голосования на общем собрании | ⚠️ 🛠️ SDK: Mutations.Meet.GenerateBallotForAnnualGeneralMeetDocument не найден | Mutation.generateBallotForAnnualGeneralMeetDocument |
| 304 | Протокол решения общего собрания | ⚠️ 🛠️ SDK: Mutations.Meet.GenerateAnnualGeneralMeetDecisionDocument не найден | Mutation.generateAnnualGeneralMeetDecisionDocument |
| 501 | Решение совета о приёме пайщика в кооператив | ⚠️ 🛠️ SDK: Mutations.Participants.GenerateParticipantApplicationDecision не найден | Mutation.generateParticipantApplicationDecision |
| 599 | Предложение повестки дня собрания совета | ⚠️ 🛠️ SDK: Mutations.FreeDecisions.GenerateProjectOfFreeDecision не найден | Mutation.generateProjectOfFreeDecision |
| 600 | Протокола решения совета | ⚠️ 🛠️ SDK: Mutations.FreeDecisions.GenerateFreeDecision не найден | Mutation.generateFreeDecision |
| 699 | Согласие с условиями ЦПП «СОСЕДИ» | — | — |
| 700 | Заявление на паевый взнос имуществом | ⚠️ 🛠️ SDK: Mutations.Cooplace.GenerateAssetContributionStatement не найден | Mutation.generateAssetContributionStatement |
| 701 | Протокол решения совета о форме и стоимости имущества | ⚠️ 🛠️ SDK: Mutations.Cooplace.GenerateAssetContributionDecision не найден | Mutation.generateAssetContributionDecision |
| 702 | Акт приёма-передачи имущества | ⚠️ 🛠️ SDK: Mutations.Cooplace.GenerateAssetContributionAct не найден | Mutation.generateAssetContributionAct |
| 800 | Заявление на возврат паевого взноса имуществом | ⚠️ 🛠️ SDK: Mutations.Cooplace.GenerateReturnByAssetStatement не найден | Mutation.generateReturnByAssetStatement |
| 801 | Протокол решения совета о возврате паевого взноса имуществом по соглашению новации | ⚠️ 🛠️ SDK: Mutations.Cooplace.GenerateReturnByAssetDecision не найден | Mutation.generateReturnByAssetDecision |
| 802 | Акт приёмки-передачи имущества | ⚠️ 🛠️ SDK: Mutations.Cooplace.GenerateReturnByAssetAct не найден | Mutation.generateReturnByAssetAct |
| 900 | Заявление на возврат паевого взноса денежными средствами | ⚠️ 🛠️ SDK: Mutations.Wallet.GenerateReturnByMoneyStatementDocument не найден | Mutation.generateReturnByMoneyStatementDocument |
| 901 | Решение совета о возврате паевого взноса | ⚠️ 🛠️ SDK: Mutations.Wallet.GenerateReturnByMoneyDecisionDocument не найден | Mutation.generateReturnByMoneyDecisionDocument |
| 1000 | Оферта по благороста | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateCapitalizationAgreement не найден | Mutation.capitalGenerateCapitalizationAgreement |
| 1001 | Договор участия в хозяйственной деятельности | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationContract не найден | Mutation.capitalGenerateGenerationContract |
| 1002 | Приложение к договору участия | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateProjectGenerationContract не найден | Mutation.capitalGenerateProjectGenerationContract |
| 1010 | Заявление о расходах | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateExpenseStatement не найден | Mutation.capitalGenerateExpenseStatement |
| 1011 | Решение совета о расходах | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateExpenseDecision не найден | Mutation.capitalGenerateExpenseDecision |
| 1020 | Заявление об инвестировании денежных средств в генерацию | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationMoneyInvestStatement не найден | Mutation.capitalGenerateGenerationMoneyInvestStatement |
| 1025 | Заявление о возврате неиспользованных средств генерации | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationMoneyReturnUnusedStatement не найден | Mutation.capitalGenerateGenerationMoneyReturnUnusedStatement |
| 1030 | Заявление об инвестировании средств в благорост | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateCapitalizationMoneyInvestStatement не найден | Mutation.capitalGenerateCapitalizationMoneyInvestStatement |
| 1040 | Заявление на внесение результата интеллектуальной деятельности | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateResultContributionStatement не найден | Mutation.capitalGenerateResultContributionStatement |
| 1041 | Решение совета об инвестициях по результатам | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateResultContributionDecision не найден | Mutation.capitalGenerateResultContributionDecision |
| 1042 | Акт приема-передачи результата интеллектуальной деятельности | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateResultContributionAct не найден | Mutation.capitalGenerateResultContributionAct |
| 1050 | Заявление на получение займа | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGetLoanStatement не найден | Mutation.capitalGenerateGetLoanStatement |
| 1051 | Решение совета о предоставлении займа | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGetLoanDecision не найден | Mutation.capitalGenerateGetLoanDecision |
| 1060 | Заявление об инвестировании имущества в генерацию | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationPropertyInvestStatement не найден | Mutation.capitalGenerateGenerationPropertyInvestStatement |
| 1061 | Решение совета об инвестировании имущества в генерацию | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationPropertyInvestDecision не найден | Mutation.capitalGenerateGenerationPropertyInvestDecision |
| 1062 | Акт приема-передачи имущества в генерацию | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationPropertyInvestAct не найден | Mutation.capitalGenerateGenerationPropertyInvestAct |
| 1070 | Заявление об инвестировании имущества в благорост | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateCapitalizationPropertyInvestStatement не найден | Mutation.capitalGenerateCapitalizationPropertyInvestStatement |
| 1071 | Решение совета об инвестировании имущества в благорост | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateCapitalizationPropertyInvestDecision не найден | Mutation.capitalGenerateCapitalizationPropertyInvestDecision |
| 1072 | Акт приема-передачи имущества в благорост | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateCapitalizationPropertyInvestAct не найден | Mutation.capitalGenerateCapitalizationPropertyInvestAct |
| 1080 | Заявление о конвертации средств генерации в основной кошелек | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationToMainWalletConvertStatement не найден | Mutation.capitalGenerateGenerationToMainWalletConvertStatement |
| 1081 | Заявление о конвертации средств генерации в проект | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationToProjectConvertStatement не найден | Mutation.capitalGenerateGenerationToProjectConvertStatement |
| 1082 | Заявление о конвертации средств генерации в благорост | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateGenerationToCapitalizationConvertStatement не найден | Mutation.capitalGenerateGenerationToCapitalizationConvertStatement |
| 1090 | Заявление о конвертации средств благороста в основной кошелек | ⚠️ 🛠️ SDK: Mutations.Capital.GenerateCapitalizationToMainWalletConvertStatement не найден | Mutation.capitalGenerateCapitalizationToMainWalletConvertStatement |
Для разработчиков¶
Генерация и подпись¶
Для того, чтобы сгенерировать документ, необходимо передать ему набор обязательных параметров из интерфейса IInput. Обязательные параметры являются частью процесса генерации документа, а не обязательные параметры обычно являются мета-данными документа.
Т.е. в результате генерации документа будет получен объект мета-данных, который можно использовать для глубокой сверки, передав их в качестве опциональных параметров.
Пример: заявление на вступление¶
⚠️ 🛠️ SDK: Mutations.Participants.GenerateParticipantApplication не найден | Mutation.generateParticipantApplication
⚠️ Описание для Mutations.Participants.GenerateParticipantApplication не найдено
⚠️ Mutations.Participants.GenerateParticipantApplication не найден
Результат:
⚠️ Mutations.Participants.GenerateParticipantApplication не найден
Используем полученный документ в result для создания подписи:
import { Mutations, Classes } from '@coopenomics/sdk'
// 2. Подписываем документ с помощью SDK-класса Document
const signer = new Classes.Document('WIF_PRIVATE_KEY')
const signed = await signer.signDocument(document, 'user1', 1) //1 - это порядковый номер подписи
Тип подписанного документа¶
⚠️ Описание для SignedBlockchainDocument не найдено
Результат (тип signed):
⚠️ Интерфейс SignedBlockchainDocument не найден в typedoc_data
Полученный signed документ может быть использован для отправки в мутацией согласно бизнес-процессам, которые мы далее рассматриваем по документации.
Важно
Приватный ключ (WIF) должен соответствовать имени пользователя (username), иначе процесс валидации подписи не будет завершен с успехом.
Мультиподпись¶
Когда необходимо создать дополнительную подпись на документе, то мы это делаем на основе подписанного документа, который уже опубликован в блокчейне. Мы берем его, и создаем еще одну подпись, накладывая её поверх ранее подписанного другим пайщиком документа, указывая порядковый номер подписи следующим.
const signed = await signer.signDocument(document, 'user2', 2)