From a745e798a41c6f3f928e27eef93235e97d4c974f Mon Sep 17 00:00:00 2001 From: coopops Date: Sat, 9 May 2026 12:12:10 +0000 Subject: [PATCH] =?UTF-8?q?[@ant]=20fix(controller+capital):=20event-drive?= =?UTF-8?q?n=20regshare=20+=20delete-row=20aware=20=D1=80=D0=B5=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=80=20=D0=BA=D0=BE=D1=88=D0=B5=D0=BB=D1=8C=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - controller: listener delta::ledger2::userwallets[w.cap.blago] синхронизирует regshare без ожидания scheduler-тика 1440 мин - typeorm-ledger2-state.repository: getWallets/getAccounts берут самую свежую row на ключ и при present=false обнуляют суммы (не выкидывают), чтобы удалённый L2-кошелёк остался раскрываемым в реестре с историей - capital: inline regshare после apprvappndx + whitelist auth в regshare - programs.hpp: is_participant_of_cpp_by_program_id через wallet::users.programs[], get_program_wallet → has_program_wallet - cooptypes/operations: human_name «Коммит РИД по программе Генератор», убрано «(перенос между кошельками)» --- components/cleos/scripts/cleos.sh | 2 +- .../generation/register_share/regshare.cpp | 7 +- .../invest_to_program/createpinv.cpp | 4 +- .../get_clearance/apprvappndx.cpp | 16 + .../register_contributor/regcontrib.cpp | 5 +- .../cpp/capital/domain/entities/wallets.hpp | 24 +- .../cpp/lib/core/ledger2/operations.hpp | 4 +- .../contracts/cpp/lib/core/programs.hpp | 86 +- .../cpp/soviet/src/wallet/addmemberfee.cpp | 6 +- .../cpp/soviet/src/wallet/openprogwall.cpp | 56 +- components/controller/schema.gql | 1088 +++-------------- ...istration-on-user-wallet-delta.listener.ts | 54 + .../program-share-registration.service.ts | 147 ++- .../capital/capital-extension.module.ts | 2 + .../typeorm-ledger2-state.repository.ts | 46 +- .../cooptypes/src/ledger2/operations.ts | 4 +- components/docs-harness/package-lock.json | 4 +- components/migrator/migration_state.json | 2 +- 18 files changed, 456 insertions(+), 1101 deletions(-) create mode 100644 components/controller/src/extensions/capital/application/listeners/program-share-registration-on-user-wallet-delta.listener.ts diff --git a/components/cleos/scripts/cleos.sh b/components/cleos/scripts/cleos.sh index 3617d96c42f..344de30eeaa 100755 --- a/components/cleos/scripts/cleos.sh +++ b/components/cleos/scripts/cleos.sh @@ -1,3 +1,3 @@ #!/bin/bash -cleos -u http://172.17.0.1:8888 "$@" +cleos -u http://172.17.0.1:8908 "$@" diff --git a/components/contracts/cpp/capital/app/generation/register_share/regshare.cpp b/components/contracts/cpp/capital/app/generation/register_share/regshare.cpp index 2c0031f26fc..e53d1c4199f 100644 --- a/components/contracts/cpp/capital/app/generation/register_share/regshare.cpp +++ b/components/contracts/cpp/capital/app/generation/register_share/regshare.cpp @@ -14,7 +14,12 @@ * @note Авторизация требуется от аккаунта кооператива: @p coopname (@c active) */ void capital::regshare(eosio::name coopname, checksum256 project_hash, eosio::name username, eosio::asset user_shares) { - require_auth(coopname); + // Прямой вызов от кооператива (планировщик контроллера) ИЛИ inline-вызов + // от системного контракта (например, capital::apprvappndx — авторегистрация + // доли при допуске участника к проекту). + if (!has_auth(coopname)) { + check_auth_and_get_payer_or_fail(contracts_whitelist); + } // Проверяем существование проекта auto project = Capital::Projects::get_project_or_fail(coopname, project_hash); diff --git a/components/contracts/cpp/capital/app/invests_managment/invest_in_program/invest_to_program/createpinv.cpp b/components/contracts/cpp/capital/app/invests_managment/invest_in_program/invest_to_program/createpinv.cpp index 3c07eba43c8..c2d59d2ae4d 100644 --- a/components/contracts/cpp/capital/app/invests_managment/invest_in_program/invest_to_program/createpinv.cpp +++ b/components/contracts/cpp/capital/app/invests_managment/invest_in_program/invest_to_program/createpinv.cpp @@ -26,8 +26,8 @@ void capital::createpinv(name coopname, name username, checksum256 invest_hash, auto contributor = Capital::Contributors::get_active_contributor_or_fail(coopname, username); // Проверяем наличие кошелька в программе благороста (_capital_wallet) - auto capital_wallet = Capital::Wallets::get_program_capital_wallet(coopname, username); - eosio::check(capital_wallet.has_value(), "У пайщика нет кошелька в программе благороста"); + eosio::check(Capital::Wallets::has_program_capital_wallet(coopname, username), + "У пайщика нет кошелька в программе благороста"); std::string memo = Capital::Memo::get_program_invest_memo(contributor -> id); diff --git a/components/contracts/cpp/capital/app/participation_management/get_clearance/apprvappndx.cpp b/components/contracts/cpp/capital/app/participation_management/get_clearance/apprvappndx.cpp index ef6fde32ae6..747e168f78c 100644 --- a/components/contracts/cpp/capital/app/participation_management/get_clearance/apprvappndx.cpp +++ b/components/contracts/cpp/capital/app/participation_management/get_clearance/apprvappndx.cpp @@ -41,6 +41,22 @@ void capital::apprvappndx(eosio::name coopname, eosio::name username, checksum25 // Фиксируем документ в реестре как принятый Soviet::make_complete_document(_capital, coopname, appendix->username, Names::Capital::APPROVE_APPENDIX, appendix_hash, approved_document); + // Авторегистрация доли по программе «Благорост» при допуске к проекту: + // если у пайщика уже есть баланс w.cap.blago — сразу заводим сегмент с + // user_shares = available + blocked. Без баланса regshare не вызываем — + // сегмент создастся при ближайшем тике scheduler'а, как только появится + // первая инвестиция в программу. + const auto user_shares = + Capital::Core::get_capital_program_user_share_balance(coopname, appendix->username); + if (user_shares.amount > 0) { + eosio::action( + eosio::permission_level{_capital, "active"_n}, + _capital, + "regshare"_n, + std::make_tuple(coopname, appendix->project_hash, appendix->username, user_shares) + ).send(); + } + // Удаляем приложение Capital::Appendix::delete_appendix(coopname, appendix->id); } \ No newline at end of file diff --git a/components/contracts/cpp/capital/app/participation_management/register_contributor/regcontrib.cpp b/components/contracts/cpp/capital/app/participation_management/register_contributor/regcontrib.cpp index 72a7e0f8808..562c8f62408 100644 --- a/components/contracts/cpp/capital/app/participation_management/register_contributor/regcontrib.cpp +++ b/components/contracts/cpp/capital/app/participation_management/register_contributor/regcontrib.cpp @@ -100,8 +100,7 @@ void capital::regcontrib(eosio::name coopname, eosio::name username, checksum256 } // Открываем кошельки для пайщика если необходимо - auto program_wallet = get_program_wallet(coopname, username, _source_program); - if (!program_wallet.has_value()) { + if (!has_program_wallet(coopname, username, _source_program)) { Action::send( _soviet, Names::External::OPEN_PROGRAM_WALLET, @@ -113,7 +112,7 @@ void capital::regcontrib(eosio::name coopname, eosio::name username, checksum256 ); } - if (!get_program_wallet(coopname, username, _capital_program).has_value()) { + if (!has_program_wallet(coopname, username, _capital_program)) { Action::send( _soviet, Names::External::OPEN_PROGRAM_WALLET, diff --git a/components/contracts/cpp/capital/domain/entities/wallets.hpp b/components/contracts/cpp/capital/domain/entities/wallets.hpp index 9d81203aa9a..ab1e0f7b503 100644 --- a/components/contracts/cpp/capital/domain/entities/wallets.hpp +++ b/components/contracts/cpp/capital/domain/entities/wallets.hpp @@ -25,21 +25,17 @@ namespace Capital { > capital_wallets_index; namespace Wallets { - - inline std::optional get_program_capital_wallet(eosio::name coopname, eosio::name username) { - + + /** + * Открыт ли у пайщика программный кошелёк ЦПП «Благорост» + * (есть подписанное программное соглашение в `wallet::users.programs[]`). + * Балансы читаются отдельно через ledger2::userwallets. + */ + inline bool has_program_capital_wallet(eosio::name coopname, eosio::name username) { auto program_id = get_program_id(_capital_program); - - auto program = get_program_or_fail(coopname, program_id); - - auto capital_wallet = get_program_wallet(coopname, username, _capital_program); - - if (!capital_wallet.has_value()) { - return std::nullopt; - } - - return capital_wallet.value(); - + // Программа должна существовать в реестре кооператива. + get_program_or_fail(coopname, program_id); + return has_program_wallet(coopname, username, _capital_program); } /** diff --git a/components/contracts/cpp/lib/core/ledger2/operations.hpp b/components/contracts/cpp/lib/core/ledger2/operations.hpp index 89c40b08d9b..b411f60f59f 100644 --- a/components/contracts/cpp/lib/core/ledger2/operations.hpp +++ b/components/contracts/cpp/lib/core/ledger2/operations.hpp @@ -196,12 +196,12 @@ static constexpr OperationRegistryEntry OPERATION_REGISTRY[] = { { operations::capital::INVEST, processes::capital::INVEST, WalletOp::TRANSFER, ledger2_wallets::SHARE_FUND_PAY, ledger2_wallets::BLAGOROST_FUND, 0, 0, - "Инвестиция в ЦПП «Благорост» (перенос между кошельками паевого фонда)" }, + "Инвестиция в ЦПП «Благорост»" }, // 7. Коммит РИД: Dr 08 / Cr 80, ISSUE GENERATOR_FUND (ADR-009: единый кошелёк программы Генератор) { operations::capital::COMMIT_RID, processes::capital::RID, WalletOp::ISSUE, eosio::name{}, ledger2_wallets::GENERATOR_FUND, ledger2_accounts::NON_CURRENT_INVESTMENTS, ledger2_accounts::SHARE_FUND, - "Коммит результата интеллектуальной деятельности по программе «Благорост»" }, + "Коммит результата интеллектуальной деятельности по программе «Генератор»" }, // 8. Приём РИД в НМА: Dr 04 / Cr 08, NONE — кошелёк остаётся на GENERATOR_FUND. // Семантика: подписан акт-2, РИД принят как НМА (закрылся 08-й). Перемещение diff --git a/components/contracts/cpp/lib/core/programs.hpp b/components/contracts/cpp/lib/core/programs.hpp index 5fbe3e48b70..5ca9e393552 100644 --- a/components/contracts/cpp/lib/core/programs.hpp +++ b/components/contracts/cpp/lib/core/programs.hpp @@ -9,8 +9,16 @@ using namespace eosio; /** - * Логика программ пайщика и кошелька (совет). - * Таблицы programs / progwallets / agreements — из domain/index.hpp (подключать раньше). + * Логика программ пайщика и кошелька. + * + * Источник правды по «участник ЦПП X» = `wallet::users[username].programs[]` + * (Эпик 2). signagree добавляет запись в этот вектор, revokeagree — удаляет; + * status="declined" в агриментах при ревоке не нужен — записи просто нет. + * + * Таблицы из domain/index.hpp: + * - soviet::programs — реестр программ кооператива. + * - soviet::coagreements — мапа program_type → program_id (per-coop). + * - wallet::users — подписанные программные соглашения пайщика. */ program get_program_or_fail(eosio::name coopname, uint64_t program_id) { @@ -22,57 +30,33 @@ program get_program_or_fail(eosio::name coopname, uint64_t program_id) { return program(*program_itr); } +inline bool has_signed_program_agreement(eosio::name coopname, eosio::name username, uint64_t program_id) { + WalletTables::users_index users(_wallet, coopname.value); + auto user_it = users.find(username.value); + if (user_it == users.end()) return false; + for (const auto &p : user_it->programs) { + if (p.program_id == program_id) return true; + } + return false; +} + bool is_participant_of_cpp_by_program_id(eosio::name coopname, eosio::name username, uint64_t program_id) { - progwallets_index progwallets(_soviet, coopname.value); - - auto wallets_by_username_and_program = progwallets.template get_index<"byuserprog"_n>(); - auto username_and_program_index = combine_ids(username.value, program_id); - auto wallet = wallets_by_username_and_program.find(username_and_program_index); - - if (wallet == wallets_by_username_and_program.end()) - return false; - - auto program_row = get_program_or_fail(coopname, program_id); - - agreements2_index agreements(_soviet, coopname.value); - auto agreement_row = agreements.find(wallet->agreement_id); - - if (agreement_row->status == "declined"_n) - return false; - - return true; + return has_signed_program_agreement(coopname, username, program_id); } bool is_valid_participant_of_program_by_type(eosio::name coopname, eosio::name username, eosio::name program_type) { - programs_index programs(_soviet, coopname.value); - progwallets_index progwallets(_soviet, coopname.value); - coagreements_index coagreements(_soviet, coopname.value); auto coagreement_row = coagreements.find(program_type.value); - if (coagreement_row == coagreements.end()) return false; + programs_index programs(_soviet, coopname.value); auto exist = programs.find(coagreement_row->program_id); - if (exist == programs.end()) return false; - auto wallets_by_username_and_program = progwallets.template get_index<"byuserprog"_n>(); - auto username_and_program_index = combine_ids(username.value, exist->id); - auto wallet = wallets_by_username_and_program.find(username_and_program_index); - - if (wallet == wallets_by_username_and_program.end()) - return false; - - agreements2_index agreements(_soviet, coopname.value); - auto agreement_row = agreements.find(wallet->agreement_id); - - if (agreement_row->status == "declined"_n) - return false; - - return true; + return has_signed_program_agreement(coopname, username, exist->id); } struct ProgramInfo { @@ -102,18 +86,14 @@ inline uint64_t get_draft_id(const eosio::name &type) { return it->second.draft_id; } -std::optional get_program_wallet(eosio::name coopname, eosio::name username, eosio::name type) { - auto program_id = get_program_id(type); - - progwallets_index progwallets(_soviet, coopname.value); - - auto balances_by_username_and_program = progwallets.template get_index<"byuserprog"_n>(); - auto username_and_program_index = combine_ids(username.value, program_id); - auto wallet = balances_by_username_and_program.find(username_and_program_index); - - if (wallet == balances_by_username_and_program.end()) { - return std::nullopt; - } - - return *wallet; +/** + * Открыт ли у пайщика программный кошелёк по типу программы. + * + * Источник — `wallet::users[username].programs[]`: пайщик считается «открывшим» + * программу, если у него есть подписанное программное соглашение нужного + * `program_id`. Балансы — отдельно через ledger2::userwallets, эта функция + * только про факт открытия. + */ +bool has_program_wallet(eosio::name coopname, eosio::name username, eosio::name type) { + return has_signed_program_agreement(coopname, username, get_program_id(type)); } diff --git a/components/contracts/cpp/soviet/src/wallet/addmemberfee.cpp b/components/contracts/cpp/soviet/src/wallet/addmemberfee.cpp index 64d7cdb7477..20710d047ca 100644 --- a/components/contracts/cpp/soviet/src/wallet/addmemberfee.cpp +++ b/components/contracts/cpp/soviet/src/wallet/addmemberfee.cpp @@ -23,11 +23,11 @@ void soviet::addmemberfee(eosio::name coopname, eosio::name username, uint64_t p auto participant = get_participant_or_fail(coopname, username); auto exist_wallet = get_user_program_wallet_or_fail(coopname, username, program_id); - + progwallets_index progwallets(_soviet, coopname.value); auto wallet = progwallets.find(exist_wallet.id); - - progwallets.modify(wallet, payer, [&](auto &p) { + + progwallets.modify(wallet, payer, [&](auto &p) { p.membership_contribution = p.membership_contribution.value_or(asset(0, quantity.symbol)) + quantity; }); diff --git a/components/contracts/cpp/soviet/src/wallet/openprogwall.cpp b/components/contracts/cpp/soviet/src/wallet/openprogwall.cpp index f8c81e93879..ccbc30c4ceb 100644 --- a/components/contracts/cpp/soviet/src/wallet/openprogwall.cpp +++ b/components/contracts/cpp/soviet/src/wallet/openprogwall.cpp @@ -13,32 +13,34 @@ */ void soviet::openprogwall(name coopname, name username, name program_type, uint64_t agreement_id) { name payer = check_auth_and_get_payer_or_fail(contracts_whitelist); - - auto program_wallet = get_program_wallet(coopname, username, program_type); - - if (!program_wallet.has_value()) { - auto program_id = get_program_id(program_type); - if (agreement_id > 0) { - agreements2_index agreements(_soviet, coopname.value); - auto agreement = agreements.find(agreement_id); - check(agreement != agreements.end(), "Соглашение не найдено"); - check(agreement -> username == username, "Неверный пользователь соглашения и кошелька"); - }; - - progwallets_index progwallets(_soviet, coopname.value); - - //TODO: make payer coopname - progwallets.emplace(_soviet, [&](auto &b) { - b.id = progwallets.available_primary_key(); - b.program_id = program_id; - b.coopname = coopname; - b.username = username; - b.agreement_id = agreement_id; - b.available = asset(0, _root_govern_symbol); - b.blocked = asset(0, _root_govern_symbol); - b.membership_contribution = asset(0, _root_govern_symbol); - }); - - }; + auto program_id = get_program_id(program_type); + + // Идемпотентность по самой таблице progwallets (легаси-учёт): не плодим + // дубликаты, если запись уже существует. Проверка по «byuserprog» оставлена + // здесь локально — фазаут progwallets ещё не завершён, общий помощник в + // lib/core/programs.hpp переехал на wallet::users (другая семантика). + progwallets_index progwallets(_soviet, coopname.value); + auto by_user_program = progwallets.template get_index<"byuserprog"_n>(); + auto wallet_idx_it = by_user_program.find(combine_ids(username.value, program_id)); + if (wallet_idx_it != by_user_program.end()) return; + + if (agreement_id > 0) { + agreements2_index agreements(_soviet, coopname.value); + auto agreement = agreements.find(agreement_id); + check(agreement != agreements.end(), "Соглашение не найдено"); + check(agreement->username == username, "Неверный пользователь соглашения и кошелька"); + } + + //TODO: make payer coopname + progwallets.emplace(_soviet, [&](auto &b) { + b.id = progwallets.available_primary_key(); + b.program_id = program_id; + b.coopname = coopname; + b.username = username; + b.agreement_id = agreement_id; + b.available = asset(0, _root_govern_symbol); + b.blocked = asset(0, _root_govern_symbol); + b.membership_contribution = asset(0, _root_govern_symbol); + }); }; \ No newline at end of file diff --git a/components/controller/schema.gql b/components/controller/schema.gql index a33484a3950..1257d32c700 100644 --- a/components/controller/schema.gql +++ b/components/controller/schema.gql @@ -1588,18 +1588,10 @@ type Branch { """Краткое название организации""" short_name: String! - """ - Доверенные аккаунты - - Требуемые роли: chairman, member. - """ + """Доверенные аккаунты""" trusted: [Individual!]! - """ - Председатель кооперативного участка - - Требуемые роли: chairman, member. - """ + """Председатель кооперативного участка""" trustee: Individual! """Тип организации""" @@ -6410,7 +6402,7 @@ input GetLedger2HistoryInput { page: Int = 1 """ - global_sequence родительского apply: фильтрует siblings (walletop/debit/credit) диапазоном до следующего apply того же processHash + global_sequence родительского apply: возвращает только inline-сибсов (walletop/debit/credit) этого apply через точечную связь parser2 (transaction_id + creator_action_ordinal=apply.action_ordinal). """ parentApplyGlobalSequence: String @@ -6779,7 +6771,7 @@ type Ledger2Operation { operationCode: String """ - global_sequence ближайшего предшествующего apply того же processHash (родитель) — для точечного cross-link на конкретную операцию. + global_sequence родительского apply (parser2: transaction_id + action_ordinal=this.creator_action_ordinal) — для точечного cross-link на конкретную операцию. """ parentApplyGlobalSequence: String @@ -7336,470 +7328,218 @@ type Mutation { """ Добавить активного пайщика, который вступил в кооператив, не используя платформу (заполнив заявление собственноручно, оплатив вступительный и минимальный паевый взносы, и получив протокол решения совета) - - Требуемые роли: chairman, member. """ addParticipant(data: AddParticipantInput!): Account! """Добавить метод оплаты (банковский счёт или СБП)""" addPaymentMethod(data: AddPaymentMethodInput!): PaymentMethod! - """ - Добавить доверенное лицо кооперативного участка - - Требуемые роли: chairman. - """ + """Добавить доверенное лицо кооперативного участка""" addTrustedAccount(data: AddTrustedAccountInput!): Branch! """Отменить заявку""" cancelRequest(data: CancelRequestInput!): Transaction! - """ - Добавление автора проекта в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Добавление автора проекта в CAPITAL контракте""" capitalAddAuthor(data: AddAuthorInput!): CapitalProject! - """ - Одобрение коммита в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Одобрение коммита в CAPITAL контракте""" capitalApproveCommit(data: CommitApproveInput!): CapitalCommit! - """ - Расчет голосов в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Расчет голосов в CAPITAL контракте""" capitalCalculateVotes(data: CalculateVotesInput!): CapitalSegment! - """ - Закрытие проекта от инвестиций в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Закрытие проекта от инвестиций в CAPITAL контракте""" capitalCloseProject(data: CloseProjectInput!): CapitalProject! - """ - Завершение шага процесса - - Требуемые роли: chairman, member, user. - """ + """Завершение шага процесса""" capitalCompleteProcessStep(data: CompleteProcessStepInput!): ProcessInstance! """ Завершение регистрации в Capital через отправку документов в блокчейн (regcontrib) - - Требуемые роли: chairman. """ capitalCompleteRegistration(data: CompleteCapitalRegistrationInputDTO!): Transaction! - """ - Завершение голосования в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Завершение голосования в CAPITAL контракте""" capitalCompleteVoting(data: CompleteVotingInput!): Transaction! - """ - Конвертация сегмента в CAPITAL контракте - - Требуемые роли: chairman, member. - """ + """Конвертация сегмента в CAPITAL контракте""" capitalConvertSegment(data: ConvertSegmentInput!): CapitalSegment! - """ - Создание коммита в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Создание коммита в CAPITAL контракте""" capitalCreateCommit(data: CreateCommitInput!): CapitalCommit! - """ - Создание цикла в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Создание цикла в CAPITAL контракте""" capitalCreateCycle(data: CreateCycleInput!): CapitalCycle! - """ - Получение ссуды в CAPITAL контракте - - Требуемые роли: participant. - """ + """Получение ссуды в CAPITAL контракте""" capitalCreateDebt(data: CreateDebtInput!): Transaction! - """ - Создание расхода в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Создание расхода в CAPITAL контракте""" capitalCreateExpense(data: CreateExpenseInput!): Transaction! - """ - Создание задачи в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Создание задачи в CAPITAL контракте""" capitalCreateIssue(data: CreateIssueInput!): CapitalIssue! - """ - Создание шаблона процесса - - Требуемые роли: chairman, member. - """ + """Создание шаблона процесса""" capitalCreateProcessTemplate(data: CreateProcessTemplateInput!): ProcessTemplate! - """ - Инвестирование в программу благорост (денежная программная инвестиция) - - Требуемые роли: participant. - """ + """Инвестирование в программу благорост (денежная программная инвестиция)""" capitalCreateProgramInvest(data: CreateProgramInvestInput!): Transaction! - """ - Создание программного имущественного взноса в CAPITAL контракте - - Требуемые роли: participant. - """ + """Создание программного имущественного взноса в CAPITAL контракте""" capitalCreateProgramProperty(data: CreateProgramPropertyInput!): Transaction! - """ - Создание проекта в CAPITAL контракте - - Требуемые роли: chairman, member. - """ + """Создание проекта в CAPITAL контракте""" capitalCreateProject(data: CreateProjectInput!): Transaction! - """ - Инвестирование в проект CAPITAL контракта - - Требуемые роли: participant. - """ + """Инвестирование в проект CAPITAL контракта""" capitalCreateProjectInvest(data: CreateProjectInvestInput!): Transaction! - """ - Создание проектного имущественного взноса в CAPITAL контракте - - Требуемые роли: participant. - """ + """Создание проектного имущественного взноса в CAPITAL контракте""" capitalCreateProjectProperty(data: CreateProjectPropertyInput!): Transaction! - """ - Создание истории в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Создание истории в CAPITAL контракте""" capitalCreateStory(data: CreateStoryInput!): CapitalStory! - """ - Отклонение коммита в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Отклонение коммита в CAPITAL контракте""" capitalDeclineCommit(data: CommitDeclineInput!): CapitalCommit! - """ - Удаление задачи по хэшу - - Требуемые роли: chairman. - """ + """Удаление задачи по хэшу""" capitalDeleteIssue(data: DeleteCapitalIssueByHashInput!): Boolean! - """ - Удаление шаблона процесса - - Требуемые роли: chairman, member. - """ + """Удаление шаблона процесса""" capitalDeleteProcessTemplate(id: String!): Boolean! - """ - Удаление проекта в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Удаление проекта в CAPITAL контракте""" capitalDeleteProject(data: DeleteProjectInput!): Transaction! - """ - Удаление истории по хэшу - - Требуемые роли: chairman, member, user. - """ + """Удаление истории по хэшу""" capitalDeleteStory(data: DeleteCapitalStoryByHashInput!): Boolean! - """ - Редактирование параметров участника в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Редактирование параметров участника в CAPITAL контракте""" capitalEditContributor(data: EditContributorInput!): CapitalContributor! - """ - Редактирование проекта в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Редактирование проекта в CAPITAL контракте""" capitalEditProject(data: EditProjectInput!): Transaction! """ Финализация проекта в CAPITAL контракте после завершения всех конвертаций участников - - Требуемые роли: chairman. """ capitalFinalizeProject(data: FinalizeProjectInput!): CapitalProject! - """ - Финансирование программы CAPITAL контракта - - Требуемые роли: chairman. - """ + """Финансирование программы CAPITAL контракта""" capitalFundProgram(data: FundProgramInput!): Transaction! - """ - Сгенерировать соглашение о благороста - - Требуемые роли: chairman, member. - """ + """Сгенерировать соглашение о благороста""" capitalGenerateCapitalizationAgreement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление об инвестировании в благорост - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление об инвестировании в благорост""" capitalGenerateCapitalizationMoneyInvestStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать акт об инвестировании имуществом в благорост - - Требуемые роли: chairman, member. - """ + """Сгенерировать акт об инвестировании имуществом в благорост""" capitalGenerateCapitalizationPropertyInvestAct(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать решение об инвестировании имуществом в благорост - - Требуемые роли: chairman, member. - """ + """Сгенерировать решение об инвестировании имуществом в благорост""" capitalGenerateCapitalizationPropertyInvestDecision(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление об инвестировании имуществом в благорост - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление об инвестировании имуществом в благорост""" capitalGenerateCapitalizationPropertyInvestStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о конвертации из благороста в основной кошелек - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о конвертации из благороста в основной кошелек""" capitalGenerateCapitalizationToMainWalletConvertStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ дополнения к приложению для компонента - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ дополнения к приложению для компонента""" capitalGenerateComponentGenerationContract(data: ComponentGenerationContractGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать решение о расходе - - Требуемые роли: chairman, member. - """ + """Сгенерировать решение о расходе""" capitalGenerateExpenseDecision(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о расходе - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о расходе""" capitalGenerateExpenseStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать генерационное соглашение - - Требуемые роли: chairman, member. - """ + """Сгенерировать генерационное соглашение""" capitalGenerateGenerationContract(data: GenerationContractGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление об инвестировании в генерацию - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление об инвестировании в генерацию""" capitalGenerateGenerationMoneyInvestStatement(data: GenerationMoneyInvestStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать акт об инвестировании имуществом в генерацию - - Требуемые роли: chairman, member. - """ + """Сгенерировать акт об инвестировании имуществом в генерацию""" capitalGenerateGenerationPropertyInvestAct(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать решение об инвестировании имуществом в генерацию - - Требуемые роли: chairman, member. - """ + """Сгенерировать решение об инвестировании имуществом в генерацию""" capitalGenerateGenerationPropertyInvestDecision(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление об инвестировании имуществом в генерацию - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление об инвестировании имуществом в генерацию""" capitalGenerateGenerationPropertyInvestStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о конвертации из генерации в благорост - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о конвертации из генерации в благорост""" capitalGenerateGenerationToCapitalizationConvertStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о конвертации из генерации в основной кошелек - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о конвертации из генерации в основной кошелек""" capitalGenerateGenerationToMainWalletConvertStatement(data: GenerationToMainWalletConvertStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о конвертации из генерации в проектный кошелек - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о конвертации из генерации в проектный кошелек""" capitalGenerateGenerationToProjectConvertStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать решение о получении займа - - Требуемые роли: chairman, member. - """ + """Сгенерировать решение о получении займа""" capitalGenerateGetLoanDecision(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о получении займа - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о получении займа""" capitalGenerateGetLoanStatement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Сгенерировать заявление об инвестировании в программу благороста (без привязки к проекту) - - Требуемые роли: chairman, member, user. """ capitalGenerateProgramMoneyInvestStatement(data: ProgramCapitalizationMoneyInvestStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ приложения к договору участия для проекта - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ приложения к договору участия для проекта""" capitalGenerateProjectGenerationContract(data: ProjectGenerationContractGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Генерация пачки документов для завершения регистрации в Capital (GenerationContract, StorageAgreement, BlagorostAgreement) - - Требуемые роли: chairman, member. """ capitalGenerateRegistrationDocuments(data: GenerateCapitalRegistrationDocumentsInputDTO!): GenerateCapitalRegistrationDocumentsOutputDTO! - """ - Сгенерировать акт о вкладе результатов - - Требуемые роли: chairman, member. - """ + """Сгенерировать акт о вкладе результатов""" capitalGenerateResultContributionAct(data: ResultContributionActGenerateInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать решение о вкладе результатов - - Требуемые роли: chairman, member. - """ + """Сгенерировать решение о вкладе результатов""" capitalGenerateResultContributionDecision(data: ResultContributionDecisionGenerateInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать заявление о вкладе результатов - - Требуемые роли: chairman, member. - """ + """Сгенерировать заявление о вкладе результатов""" capitalGenerateResultContributionStatement(data: ResultContributionStatementGenerateInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Импорт участника в CAPITAL контракт - - Требуемые роли: chairman. - """ + """Импорт участника в CAPITAL контракт""" capitalImportContributor(data: ImportContributorInput!): Transaction! - """ - Подписание приложения в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Подписание приложения в CAPITAL контракте""" capitalMakeClearance(data: MakeClearanceInput!): Transaction! """ Перенос задачи между компонентами одного проекта (без закоммиченного времени и использованных Git-привязок) - - Требуемые роли: chairman, member, user. """ capitalMoveIssueToComponent(data: MoveCapitalIssueToComponentInput!): CapitalIssue! - """ - Открытие проекта для инвестиций в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Открытие проекта для инвестиций в CAPITAL контракте""" capitalOpenProject(data: OpenProjectInput!): CapitalProject! - """ - Внесение результата в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Внесение результата в CAPITAL контракте""" capitalPushResult(data: PushResultInput!): CapitalSegment! - """ - Обновление CRPS пайщика в программе CAPITAL контракта - - Требуемые роли: chairman. - """ + """Обновление CRPS пайщика в программе CAPITAL контракта""" capitalRefreshProgram(data: RefreshProgramInput!): Transaction! - """ - Обновление сегмента в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Обновление сегмента в CAPITAL контракте""" capitalRefreshSegment(data: RefreshSegmentInput!): CapitalSegment - """ - Регистрация участника в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Регистрация участника в CAPITAL контракте""" capitalRegisterContributor(data: RegisterContributorInput!): Transaction! - """ - Установка конфигурации CAPITAL контракта - - Требуемые роли: chairman. - """ + """Установка конфигурации CAPITAL контракта""" capitalSetConfig(data: SetConfigInput!): Transaction! - """ - Установка мастера проекта в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Установка мастера проекта в CAPITAL контракте""" capitalSetMaster(data: SetMasterInput!): Transaction! """Установка плана проекта в CAPITAL контракте""" @@ -7808,161 +7548,75 @@ type Mutation { """Сохранение URL репозитория разработки проекта/компонента (только БД)""" capitalSetProjectDevelopmentRepositoryUrl(data: SetCapitalProjectDevelopmentRepositoryUrlInput!): CapitalProject! - """ - Подписание акта о вкладе результатов председателем - - Требуемые роли: chairman. - """ + """Подписание акта о вкладе результатов председателем""" capitalSignActAsChairman(data: SignActAsChairmanInput!): CapitalSegment! - """ - Подписание акта о вкладе результатов участником - - Требуемые роли: chairman, member, user. - """ + """Подписание акта о вкладе результатов участником""" capitalSignActAsContributor(data: SignActAsContributorInput!): CapitalSegment! - """ - Запуск экземпляра процесса - - Требуемые роли: chairman, member, user. - """ + """Запуск экземпляра процесса""" capitalStartProcess(data: StartProcessInput!): ProcessInstance! - """ - Запуск проекта в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Запуск проекта в CAPITAL контракте""" capitalStartProject(data: StartProjectInput!): CapitalProject! - """ - Запуск голосования в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Запуск голосования в CAPITAL контракте""" capitalStartVoting(data: StartVotingInput!): Transaction! - """ - Остановка проекта в CAPITAL контракте - - Требуемые роли: chairman. - """ + """Остановка проекта в CAPITAL контракте""" capitalStopProject(data: StopProjectInput!): CapitalProject! - """ - Голосование в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Голосование в CAPITAL контракте""" capitalSubmitVote(data: SubmitVoteInput!): Transaction! - """ - Обновление задачи в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Обновление задачи в CAPITAL контракте""" capitalUpdateIssue(data: UpdateIssueInput!): CapitalIssue! - """ - Обновление шаблона процесса (шаги, рёбра, статус) - - Требуемые роли: chairman, member. - """ + """Обновление шаблона процесса (шаги, рёбра, статус)""" capitalUpdateProcessTemplate(data: UpdateProcessTemplateInput!): ProcessTemplate! - """ - Обновление истории в CAPITAL контракте - - Требуемые роли: chairman, member, user. - """ + """Обновление истории в CAPITAL контракте""" capitalUpdateStory(data: UpdateStoryInput!): CapitalStory! - """ - Подтверждение одобрения документа председателем совета - - Требуемые роли: chairman. - """ + """Подтверждение одобрения документа председателем совета""" chairmanConfirmApprove(data: ConfirmApproveInput!): Approval! - """ - Отклонение одобрения документа председателем совета - - Требуемые роли: chairman. - """ + """Отклонение одобрения документа председателем совета""" chairmanDeclineApprove(data: DeclineApproveInput!): Approval! - """ - Создать Matrix аккаунт с именем пользователя и паролем - - Требуемые роли: chairman, member, user. - """ + """Создать Matrix аккаунт с именем пользователя и паролем""" chatcoopCreateAccount(data: CreateMatrixAccountInputDTO!): Boolean! - """ - Создать событие календаря - - Требуемые роли: chairman, member. - """ + """Создать событие календаря""" chatcoopCreateCalendarEvent(data: CreateChatCoopCalendarEventInput!): ChatCoopCalendarEvent! - """ - Выдать или обновить персональный URL подписки ICS (секрет в query) - - Требуемые роли: chairman, member, user. - """ + """Выдать или обновить персональный URL подписки ICS (секрет в query)""" chatcoopCreateCalendarIcsSubscription: ChatCoopCalendarIcsUrlResponse! - """ - Удалить событие календаря - - Требуемые роли: chairman, member. - """ + """Удалить событие календаря""" chatcoopDeleteCalendarEvent(id: String!): Boolean! - """ - Обновить событие календаря - - Требуемые роли: chairman, member. - """ + """Обновить событие календаря""" chatcoopUpdateCalendarEvent(data: UpdateChatCoopCalendarEventInput!): ChatCoopCalendarEvent! - """ - Обновить заметку (memo) к транскрипции звонка - - Требуемые роли: chairman, member, user. - """ + """Обновить заметку (memo) к транскрипции звонка""" chatcoopUpdateTranscriptionMemo(data: UpdateCallTranscriptionMemoInput!): CallTranscription! - """ - Выполнить шаг онбординга capital (создание предложения повестки) - - Требуемые роли: chairman. - """ + """Выполнить шаг онбординга capital (создание предложения повестки)""" completeCapitalOnboardingStep(data: CapitalOnboardingStepInput!): CapitalOnboardingState! - """ - Выполнить один из шагов онбординга (создание предложения повестки) - - Требуемые роли: chairman. - """ + """Выполнить один из шагов онбординга (создание предложения повестки)""" completeChairmanAgendaStep(data: ChairmanOnboardingAgendaInput!): ChairmanOnboardingState! """ Выполнить шаг онбординга по созданию общего собрания (сохранить hash повестки) - - Требуемые роли: chairman. """ completeChairmanGeneralMeetStep(data: ChairmanOnboardingGeneralMeetInput!): ChairmanOnboardingState! """Завершить заявку по истечению гарантийного срока""" completeRequest(data: CompleteRequestInput!): Transaction! - """ - Подтвердить соглашение пайщика администратором - - Требуемые роли: chairman, member. - """ + """Подтвердить соглашение пайщика администратором""" confirmAgreement(data: ConfirmAgreementInput!): Transaction! """ @@ -7977,16 +7631,10 @@ type Mutation { """ Сгенерировать документ предложения повестки очередного общего собрания пайщиков - - Требуемые роли: chairman, member. """ createAnnualGeneralMeet(data: CreateAnnualGeneralMeetInput!): MeetAggregate! - """ - Создать кооперативный участок - - Требуемые роли: chairman. - """ + """Создать кооперативный участок""" createBranch(data: CreateBranchInput!): Branch! """Создать заявку на поставку имущества по предложению Поставщика""" @@ -7994,15 +7642,11 @@ type Mutation { """ Создание объекта паевого платежа производится мутацией createDepositPayment. Выполнение мутации возвращает идентификатор платежа и данные для его совершения в зависимости от выбранного платежного провайдера. - - Требуемые роли: chairman, member. """ createDepositPayment(data: CreateDepositPaymentInput!): GatewayPayment! """ Создание объекта регистрационного платежа производится мутацией createInitialPayment. Выполнение мутации возвращает идентификатор платежа и данные для его совершения в зависимости от выбранного платежного провайдера. - - Требуемые роли: chairman, member. """ createInitialPayment(data: CreateInitialPaymentInput!): GatewayPayment! @@ -8011,64 +7655,34 @@ type Mutation { """ Создать повестку дня и проект решения, и сохранить в хранилище для дальнейшей генерации документа и его публикации - - Требуемые роли: chairman, member. """ createProjectOfFreeDecision(data: CreateProjectFreeDecisionInput!): CreatedProjectFreeDecision! - """ - Создать веб-пуш подписку для пользователя - - Требуемые роли: chairman, member. - """ + """Создать веб-пуш подписку для пользователя""" createWebPushSubscription(data: CreateSubscriptionInput!): CreateSubscriptionResponse! - """ - Создать заявку на вывод средств - - Требуемые роли: chairman, member. - """ + """Создать заявку на вывод средств""" createWithdraw(data: CreateWithdrawInput!): CreateWithdrawResponse! - """ - Деактивировать веб-пуш подписку по ID - - Требуемые роли: chairman, member. - """ + """Деактивировать веб-пуш подписку по ID""" deactivateWebPushSubscriptionById(data: DeactivateSubscriptionInput!): Boolean! - """ - Отклонить соглашение пайщика администратором - - Требуемые роли: chairman, member. - """ + """Отклонить соглашение пайщика администратором""" declineAgreement(data: DeclineAgreementInput!): Transaction! """Отклонить заявку""" declineRequest(data: DeclineRequestInput!): Transaction! - """ - Удалить кооперативный участок - - Требуемые роли: chairman. - """ + """Удалить кооперативный участок""" deleteBranch(data: DeleteBranchInput!): Boolean! """Удалить метод оплаты""" deletePaymentMethod(data: DeletePaymentMethodInput!): Boolean! - """ - Удалить черновик по id (только владелец) - - Требуемые роли: chairman. - """ + """Удалить черновик по id (только владелец)""" deleteReportDraft(id: String!): Boolean! - """ - Удалить доверенное лицо кооперативного участка - - Требуемые роли: chairman. - """ + """Удалить доверенное лицо кооперативного участка""" deleteTrustedAccount(data: DeleteTrustedAccountInput!): Branch! """Подтвердить доставку имущества Заказчику по заявке""" @@ -8077,67 +7691,33 @@ type Mutation { """Открыть спор по заявке""" disputeOnRequest(data: DisputeOnRequestInput!): Transaction! - """ - Изменить кооперативный участок - - Требуемые роли: chairman. - """ + """Изменить кооперативный участок""" editBranch(data: EditBranchInput!): Branch! - """ - Сгенерировать предложение повестки общего собрания пайщиков - - Требуемые роли: chairman, member. - """ + """Сгенерировать предложение повестки общего собрания пайщиков""" generateAnnualGeneralMeetAgendaDocument(data: AnnualGeneralMeetingAgendaGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ решения общего собрания пайщиков - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ решения общего собрания пайщиков""" generateAnnualGeneralMeetDecisionDocument(data: AnnualGeneralMeetingDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Сгенерировать документ уведомления о проведении общего собрания пайщиков - - Требуемые роли: chairman, member. """ generateAnnualGeneralMeetNotificationDocument(data: AnnualGeneralMeetingNotificationGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ акта приема-передачи. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ акта приема-передачи.""" generateAssetContributionAct(data: AssetContributionActGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ решения о вступлении в кооператив. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ решения о вступлении в кооператив.""" generateAssetContributionDecision(data: AssetContributionDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ заявления о вступлении в кооператив. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ заявления о вступлении в кооператив.""" generateAssetContributionStatement(data: AssetContributionStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать бюллетень для голосования на общем собрании пайщиков - - Требуемые роли: member. - """ + """Сгенерировать бюллетень для голосования на общем собрании пайщиков""" generateBallotForAnnualGeneralMeetDocument(data: AnnualGeneralMeetingVotingBallotGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Генерирует заявление на конвертацию паевого взноса в членский взнос - - Требуемые роли: member, chairman. - """ + """Генерирует заявление на конвертацию паевого взноса в членский взнос""" generateConvertToAxonStatement(data: ConvertToAxonStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ @@ -8145,122 +7725,64 @@ type Mutation { """ generateDocument(input: GenerateAnyDocumentInput!): GeneratedDocument! - """ - Сгенерировать протокол решения по предложенной повестке - - Требуемые роли: chairman, member. - """ + """Сгенерировать протокол решения по предложенной повестке""" generateFreeDecision(data: FreeDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ заявления о вступлении в кооператив. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ заявления о вступлении в кооператив.""" generateParticipantApplication(data: ParticipantApplicationGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ протокол решения собрания совета - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ протокол решения собрания совета""" generateParticipantApplicationDecision(data: ParticipantApplicationDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ согласия с политикой конфиденциальности. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ согласия с политикой конфиденциальности.""" generatePrivacyAgreement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ проекта свободного решения - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ проекта свободного решения""" generateProjectOfFreeDecision(data: ProjectFreeDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Генерирует пакет документов для регистрации пайщика. Возвращает список документов с метаданными для отображения на фронтенде. - - Требуемые роли: chairman, member. """ generateRegistrationDocuments(data: GenerateRegistrationDocumentsInput!): GenerateRegistrationDocumentsOutput! """ Сгенерировать XML отчёта из edits-состояния формы (результат редактора). Перед записью XML проходит XSD-валидацию; всё сохраняется в архив отчётов. - - Требуемые роли: chairman. """ generateReportFromEdits(editsJson: String!, period: Int, reportType: ReportType!, year: Int!): GeneratedReport! - """ - Сгенерировать документ акта возврата имущества. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ акта возврата имущества.""" generateReturnByAssetAct(data: ReturnByAssetActGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ решения о возврате имущества. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ решения о возврате имущества.""" generateReturnByAssetDecision(data: ReturnByAssetDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ заявления о возврате имущества. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ заявления о возврате имущества.""" generateReturnByAssetStatement(data: ReturnByAssetStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ решения совета о возврате паевого взноса - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ решения совета о возврате паевого взноса""" generateReturnByMoneyDecisionDocument(data: ReturnByMoneyDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ заявления на возврат паевого взноса - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ заявления на возврат паевого взноса""" generateReturnByMoneyStatementDocument(data: ReturnByMoneyGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ, подтверждающий выбор кооперативного участка - - Требуемые роли: chairman, member, user. - """ + """Сгенерировать документ, подтверждающий выбор кооперативного участка""" generateSelectBranchDocument(data: SelectBranchGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Сгенерировать документ соглашения о порядка и правилах использования простой электронной подписи. - - Требуемые роли: chairman, member. """ generateSignatureAgreement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Сгенерировать документ решения Совета по проведению общего собрания пайщиков - - Требуемые роли: chairman, member. """ generateSovietDecisionOnAnnualMeetDocument(data: AnnualGeneralMeetingSovietDecisionGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! - """ - Сгенерировать документ пользовательского соглашения. - - Требуемые роли: chairman, member. - """ + """Сгенерировать документ пользовательского соглашения.""" generateUserAgreement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ Сгенерировать документ соглашения о целевой потребительской программе "Цифровой Кошелёк" - - Требуемые роли: chairman, member. """ generateWalletAgreement(data: GenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! @@ -8269,11 +7791,7 @@ type Mutation { """ initSystem(data: Init!): SystemInfo! - """ - Установить расширение - - Требуемые роли: chairman. - """ + """Установить расширение""" installExtension(data: ExtensionInput!): Extension! """Произвести установку членов совета перед началом работы""" @@ -8289,25 +7807,17 @@ type Mutation { """ Поставить или снять отметку на ячейку календаря. mark=null — снять. Сейчас поддерживается только NOT_REQUIRED («не надо сдавать»). - - Требуемые роли: chairman. """ markReportPeriod(data: MarkReportPeriodInput!): Boolean! """Модерировать заявку""" moderateRequest(data: ModerateRequestInput!): Transaction! - """ - Уведомление о проведении общего собрания пайщиков - - Требуемые роли: chairman, member. - """ + """Уведомление о проведении общего собрания пайщиков""" notifyOnAnnualGeneralMeet(data: NotifyOnAnnualGeneralMeetInput!): MeetAggregate! """ Обрабатывает подписанное заявление на конвертацию и выполняет блокчейн-транзакцию - - Требуемые роли: member, chairman. """ processConvertToAxonStatement(data: ProcessConvertToAxonStatementInput!): Boolean! @@ -8316,8 +7826,6 @@ type Mutation { """ Опубликовать предложенную повестку и проект решения для дальнейшего голосования совета по нему - - Требуемые роли: chairman, member. """ publishProjectOfFreeDecision(data: PublishProjectFreeDecisionInput!): Boolean! @@ -8337,33 +7845,21 @@ type Mutation { """ Зарегистрировать заявление и подписанные положения, подготовив пакет документов к отправке в совет на голосование после поступления оплаты. - - Требуемые роли: chairman, member. """ registerParticipant(data: RegisterParticipantInput!): Account! """Заменить приватный ключ аккаунта""" resetKey(data: ResetKeyInput!): Boolean! - """ - Перезапуск общего собрания пайщиков - - Требуемые роли: chairman. - """ + """Перезапуск общего собрания пайщиков""" restartAnnualGeneralMeet(data: RestartAnnualGeneralMeetInput!): MeetAggregate! """ Сохранить/обновить черновик формы отчёта (upsert по owner+type+year+period) - - Требуемые роли: chairman. """ saveReportDraft(input: SaveReportDraftInput!): ReportDraft! - """ - Выбрать кооперативный участок - - Требуемые роли: chairman, member, user. - """ + """Выбрать кооперативный участок""" selectBranch(data: SelectBranchInput!): Boolean! """Отправить соглашение""" @@ -8371,26 +7867,16 @@ type Mutation { """ Управление статусом платежа осущствляется мутацией setPaymentStatus. При переходе платежа в статус PAID вызывается эффект в блокчейне, который завершает операцию автоматическим переводом платежа в статус COMPLETED. При установке статуса REFUNDED запускается процесс отмены платежа в блокчейне. Остальные статусы не приводят к эффектам в блокчейне. - - Требуемые роли: chairman, member. """ setPaymentStatus(data: SetPaymentStatusInput!): GatewayPayment! """Сохранить приватный ключ в зашифрованном серверном хранилище""" setWif(data: SetWifInput!): Boolean! - """ - Подписание решения председателем на общем собрании пайщиков - - Требуемые роли: chairman, member. - """ + """Подписание решения председателем на общем собрании пайщиков""" signByPresiderOnAnnualGeneralMeet(data: SignByPresiderOnAnnualGeneralMeetInput!): MeetAggregate! - """ - Подписание решения секретарём на общем собрании пайщиков - - Требуемые роли: chairman, member. - """ + """Подписание решения секретарём на общем собрании пайщиков""" signBySecretaryOnAnnualGeneralMeet(data: SignBySecretaryOnAnnualGeneralMeetInput!): MeetAggregate! """ @@ -8410,16 +7896,10 @@ type Mutation { """ Запустить воркфлоу уведомлений (только для председателя или server-secret) - - Требуемые роли: chairman. """ triggerNotificationWorkflow(data: TriggerNotificationWorkflowInput!): Boolean! - """ - Удалить расширение - - Требуемые роли: chairman. - """ + """Удалить расширение""" uninstallExtension(data: UninstallExtensionInput!): Boolean! """Снять с публикации заявку""" @@ -8427,59 +7907,37 @@ type Mutation { """ Обновить аккаунт в системе провайдера. Обновление аккаунта пользователя производится по username. Мутация позволяет изменить приватные данные пользователя, а также, адрес электронной почты в MONO. Использовать мутацию может только председатель совета. - - Требуемые роли: chairman. """ updateAccount(data: UpdateAccountInput!): Account! """Обновить банковский счёт""" updateBankAccount(data: UpdateBankAccountInput!): PaymentMethod! - """ - Обновить расширение - - Требуемые роли: chairman. - """ + """Обновить расширение""" updateExtension(data: ExtensionInput!): Extension! """ Обновить ручные реквизиты кооператива. ИНН/КПП/ОГРН игнорируются — это ончейн - - Требуемые роли: chairman. """ updateReportRequisites(input: UpdateReportRequisitesInput!): ReportRequisitesView! """Обновить заявку""" updateRequest(data: UpdateRequestInput!): Transaction! - """ - Обновить настройки системы (рабочие столы и маршруты по умолчанию) - - Требуемые роли: chairman. - """ + """Обновить настройки системы (рабочие столы и маршруты по умолчанию)""" updateSettings(data: UpdateSettingsInput!): Settings! - """ - Обновить параметры системы - - Требуемые роли: chairman. - """ + """Обновить параметры системы""" updateSystem(data: Update!): SystemInfo! """Подтвердить email адрес пользователя""" verifyEmail(data: VerifyEmailInputDTO!): Boolean! - """ - Голосование на общем собрании пайщиков - - Требуемые роли: member. - """ + """Голосование на общем собрании пайщиков""" voteOnAnnualGeneralMeet(data: VoteOnAnnualGeneralMeetInput!): MeetAggregate! """ Перевод между кошельками одного бух.счёта (operation o.adj.walmove). Только председатель. Backend проверяет связь wallet→account до подписания. - - Требуемые роли: chairman. """ walmoveWallets(input: WalmoveInput!): Ledger2AdjustmentResult! } @@ -9990,8 +9448,6 @@ type Query { """ Построить предзаполненные edits для формы: дефолты (ledger2 + реквизиты + корректировки), с наложением dirty-полей существующего черновика (если он есть). - - Требуемые роли: chairman. """ buildInitialReportEdits(period: Int, reportType: ReportType!, year: Int!): BuildInitialReportEdits! @@ -10003,18 +9459,10 @@ type Query { """Получение списка кандидатов расширения CAPITAL с обогащенными данными""" capitalCandidates(filter: CandidateFilterInput, options: PaginationInput): PaginatedCapitalCandidatesPaginationResult! - """ - Получение коммита по хэшу - - Требуемые роли: chairman, member, user. - """ + """Получение коммита по хэшу""" capitalCommit(data: GetCapitalCommitByHashInput!): CapitalCommit - """ - Получение списка коммитов кооператива с фильтрацией - - Требуемые роли: chairman, member, user. - """ + """Получение списка коммитов кооператива с фильтрацией""" capitalCommits(filter: CapitalCommitFilter, options: PaginationInput): PaginatedCapitalCommitsPaginationResult! """Получение участника по ID, имени пользователя или хешу участника""" @@ -10023,11 +9471,7 @@ type Query { """Получение списка участников кооператива с фильтрацией""" capitalContributors(filter: CapitalContributorFilter, options: PaginationInput): PaginatedCapitalContributorsPaginationResult! - """ - Получение списка циклов кооператива с фильтрацией - - Требуемые роли: chairman, member, user. - """ + """Получение списка циклов кооператива с фильтрацией""" capitalCycles(filter: CapitalCycleFilter, options: PaginationInput): PaginatedCapitalCyclesPaginationResult! """Получение долга по внутреннему ID базы данных""" @@ -10060,18 +9504,10 @@ type Query { """Получение списка инвестиций кооператива с фильтрацией""" capitalInvests(filter: CapitalInvestFilter, options: PaginationInput): PaginatedCapitalInvestsPaginationResult! - """ - Получение задачи по хэшу - - Требуемые роли: chairman, member, user. - """ + """Получение задачи по хэшу""" capitalIssue(data: GetCapitalIssueByHashInput!): CapitalIssue - """ - Получение списка задач кооператива с фильтрацией - - Требуемые роли: chairman, member, user. - """ + """Получение списка задач кооператива с фильтрацией""" capitalIssues(filter: CapitalIssueFilter, options: PaginationInput): PaginatedCapitalIssuesPaginationResult! """Получение проекта по хешу с компонентами""" @@ -10083,18 +9519,10 @@ type Query { """Получение списка проектов кооператива с фильтрацией и компонентами""" capitalProjects(filter: CapitalProjectFilter, options: PaginationInput): PaginatedCapitalProjectsPaginationResult! - """ - Получение результата по внутреннему ID базы данных - - Требуемые роли: chairman, member, user. - """ + """Получение результата по внутреннему ID базы данных""" capitalResult(data: GetResultInput!): CapitalResult - """ - Получение списка результатов кооператива с фильтрацией - - Требуемые роли: chairman, member, user. - """ + """Получение списка результатов кооператива с фильтрацией""" capitalResults(filter: ResultFilter, options: PaginationInput): PaginatedCapitalResultsPaginationResult! """Получение одного сегмента кооператива по фильтрам""" @@ -10106,39 +9534,21 @@ type Query { """Получение полного состояния CAPITAL контракта кооператива""" capitalState(data: GetCapitalConfigInput!): CapitalState - """ - Получение списка историй кооператива с фильтрацией - - Требуемые роли: chairman, member, user. - """ + """Получение списка историй кооператива с фильтрацией""" capitalStories(filter: CapitalStoryFilter, options: PaginationInput): PaginatedCapitalStoriesPaginationResult! - """ - Получение истории по хэшу - - Требуемые роли: chairman, member, user. - """ + """Получение истории по хэшу""" capitalStory(data: GetCapitalStoryByHashInput!): CapitalStory - """ - Получение пагинированного списка записей времени - - Требуемые роли: chairman, member, user. - """ + """Получение пагинированного списка записей времени""" capitalTimeEntries(filter: CapitalTimeEntriesFilter, options: PaginationInput): PaginatedCapitalTimeEntriesPaginationResult! """ Получение пагинированного списка агрегированных записей времени по задачам с информацией о задачах и участниках - - Требуемые роли: chairman, member, user. """ capitalTimeEntriesByIssues(filter: CapitalTimeEntriesFilter, options: PaginationInput): PaginatedCapitalTimeEntriesByIssuesPaginationResult! - """ - Гибкий запрос статистики времени участников по проектам с пагинацией - - Требуемые роли: chairman, member, user. Исключение: доступ разрешен, если `data.username` совпадает с `username` текущего пользователя. - """ + """Гибкий запрос статистики времени участников по проектам с пагинацией""" capitalTimeStats(data: CapitalTimeStatsInput, options: PaginationInput): CapitalTimeStats! """Получение голоса по внутреннему ID базы данных""" @@ -10153,81 +9563,43 @@ type Query { """Получение списка одобрений председателя совета с фильтрацией""" chairmanApprovals(filter: ApprovalFilter, options: PaginationInput): PaginatedChairmanApprovalsPaginationResult! - """ - Проверяет доступность Matrix username - - Требуемые роли: chairman, member, user. - """ + """Проверяет доступность Matrix username""" chatcoopCheckUsernameAvailability(data: CheckMatrixUsernameInput!): Boolean! - """ - Проверить статус Matrix аккаунта пользователя и получить iframe URL - - Требуемые роли: chairman, member, user. - """ + """Проверить статус Matrix аккаунта пользователя и получить iframe URL""" chatcoopGetAccountStatus: MatrixAccountStatusResponseDTO! """ Максимальный origin_server_ts в истории комнаты (мс), если есть сообщения - - Требуемые роли: chairman, member, user. """ chatcoopGetMaxOriginServerTsForRoom(data: GetMaxOriginServerTsForRoomInput!): Float - """ - Строки истории сообщений Matrix за календарные сутки UTC - - Требуемые роли: chairman, member, user. - """ + """Строки истории сообщений Matrix за календарные сутки UTC""" chatcoopGetRoomMessagesForUtcDate(data: GetRoomMessagesForUtcDateInput!): [ChatcoopRoomMessageLine!]! - """ - Получить детальную транскрипцию с сегментами - - Требуемые роли: chairman, member, user. - """ + """Получить детальную транскрипцию с сегментами""" chatcoopGetTranscription(data: GetTranscriptionInput!): CallTranscriptionWithSegments - """ - Получить список транскрипций звонков - - Требуемые роли: chairman, member, user. - """ + """Получить список транскрипций звонков""" chatcoopGetTranscriptions(data: GetTranscriptionsInput): [CallTranscription!]! - """ - Список событий календаря кооператива - - Требуемые роли: chairman, member, user. - """ + """Список событий календаря кооператива""" chatcoopListCalendarEvents: [ChatCoopCalendarEvent!]! """ Незашифрованные комнаты из реестра ChatCoop для привязки события календаря - - Требуемые роли: chairman, member. """ chatcoopListCalendarRooms: [ChatCoopCalendarRoomOption!]! - """ - Комнаты Matrix, привязанные к проекту Capital (реестр ChatCoop) - - Требуемые роли: chairman, member, user. - """ + """Комнаты Matrix, привязанные к проекту Capital (реестр ChatCoop)""" chatcoopListProjectCommunicationRooms(data: GetProjectCommunicationRoomsInput!): [ChatcoopProjectCommunicationRoom!]! """ UTC-даты (YYYY-MM-DD), в которых есть сообщения новее afterOriginServerTsExclusive, для комнаты Matrix - - Требуемые роли: chairman, member, user. """ chatcoopListUtcDatesWithNewRoomMessages(data: ListUtcDatesWithNewRoomMessagesInput!): [String!]! - """ - Проверить готовность реквизитов для генерации конкретной формы - - Требуемые роли: chairman. - """ + """Проверить готовность реквизитов для генерации конкретной формы""" checkReportReadiness(reportType: ReportType!): ReportReadinessView! """ @@ -10240,39 +9612,21 @@ type Query { """ cooperativePrograms(coopname: String!): [CooperativeProgram!]! - """ - Получить сводную информацию о аккаунте - - Требуемые роли: chairman, member. - """ + """Получить сводную информацию о аккаунте""" getAccount(data: GetAccountInput!): Account! - """ - Получить сводную информацию о аккаунтах системы - - Требуемые роли: chairman, member. - """ + """Получить сводную информацию о аккаунтах системы""" getAccounts(data: GetAccountsInput, options: PaginationInput): AccountsPaginationResult! """ Получить список действий блокчейна с возможностью фильтрации по аккаунту, имени действия, блоку и другим параметрам. - - Требуемые роли: chairman, member. """ getActions(filters: ActionFiltersInput, pagination: PaginationInput): PaginatedActionsPaginationResult! - """ - Получить список вопросов совета кооператива для голосования - - Требуемые роли: chairman, member. - """ + """Получить список вопросов совета кооператива для голосования""" getAgenda: [AgendaWithDocuments!]! - """ - Получить список доступных типов отчётов - - Требуемые роли: chairman. - """ + """Получить список доступных типов отчётов""" getAvailableReports: [AvailableReport!]! """Получить список кооперативных участков""" @@ -10281,62 +9635,36 @@ type Query { """Получить логи событий по задаче""" getCapitalIssueLogs(data: GetCapitalIssueLogsInput!, options: PaginationInput): PaginatedCapitalLogsPaginationResult! - """ - Получить состояние онбординга capital - - Требуемые роли: chairman, member, user. - """ + """Получить состояние онбординга capital""" getCapitalOnboardingState: CapitalOnboardingState! """Получить логи событий по проекту с фильтрацией и пагинацией""" getCapitalProjectLogs(data: GetCapitalLogsInput!): PaginatedCapitalLogsPaginationResult! - """ - Получить состояние онбординга председателя - - Требуемые роли: chairman. - """ + """Получить состояние онбординга председателя""" getChairmanOnboardingState: ChairmanOnboardingState! - """ - Получить текущий инстанс пользователя - - Требуемые роли: member, chairman, user. - """ + """Получить текущий инстанс пользователя""" getCurrentInstance: CurrentInstanceDTO """ Получить текущие состояния таблиц блокчейна с фильтрацией по контракту, области и таблице. - - Требуемые роли: chairman, member. """ getCurrentTableStates(filters: CurrentTableStatesFiltersInput, pagination: PaginationInput): PaginatedCurrentTableStatesPaginationResult! """ Получить список дельт блокчейна с возможностью фильтрации по контракту, таблице, блоку и другим параметрам. - - Требуемые роли: chairman, member. """ getDeltas(filters: DeltaFiltersInput, pagination: PaginationInput): PaginatedDeltasPaginationResult! """Получить состав приложений рабочего стола""" getDesktop: Desktop! - - "\n\nТребуемые роли: chairman, member. " getDocuments(data: GetDocumentsInput!): DocumentsAggregatePaginationResult! - """ - Получить логи расширений с фильтрацией и пагинацией - - Требуемые роли: chairman, member. - """ + """Получить логи расширений с фильтрацией и пагинацией""" getExtensionLogs(data: GetExtensionLogsInput, options: PaginationInput): ExtensionLogsPaginationResult! - """ - Получить список расширений - - Требуемые роли: chairman. - """ + """Получить список расширений""" getExtensions(data: GetExtensionsInput): [Extension!]! """Получить статус установки кооператива с приватными данными""" @@ -10344,168 +9672,98 @@ type Query { """ Получить полное состояние плана счетов кооператива. Возвращает все счета из стандартного плана счетов с актуальными данными из блокчейна. Если счет не активен в блокчейне, возвращает нулевые значения. - - Требуемые роли: chairman, member. """ getLedger(data: GetLedgerInput!): LedgerState! - """ - Актуальные балансы счетов кооператива из ledger2::accounts (id ×1000). - - Требуемые роли: chairman, member. - """ + """Актуальные балансы счетов кооператива из ledger2::accounts (id ×1000).""" getLedger2Accounts(coopname: String!): [Ledger2Account!]! """ История операций ledger2 с серверными фильтрами (action/accountId/username/date-range). - - Требуемые роли: chairman, member. """ getLedger2History(input: GetLedger2HistoryInput!): Ledger2HistoryResponse! """ Реестр проводок: пары debit+credit (Дт/Кт/Сумма), восстановленные из blockchain_actions по правилу «ближайший parent apply». Источник для фронт-страницы «Реестр проводок». - - Требуемые роли: chairman, member. """ getLedger2Postings(input: GetLedger2PostingsInput!): Ledger2PostingsResponse! """ Общекооперативные кошельки из ledger2::wallets (eosio::name w..). Кошельки пайщиков живут в контракте soviet — сюда не попадают. - - Требуемые роли: chairman, member. """ getLedger2Wallets(coopname: String!): [Ledger2Wallet!]! """ Получить историю операций по счетам кооператива. Возвращает список операций с возможностью фильтрации по account_id и пагинацией. Операции сортируются по дате создания (новые первыми). - - Требуемые роли: chairman, member. """ getLedgerHistory(data: GetLedgerHistoryInput!): LedgerHistoryResponse! - """ - Получить данные собрания по хешу - - Требуемые роли: chairman, member, user. - """ + """Получить данные собрания по хешу""" getMeet(data: GetMeetInput!): MeetAggregate! - """ - Получить список всех собраний кооператива - - Требуемые роли: chairman, member, user. - """ + """Получить список всех собраний кооператива""" getMeets(data: GetMeetsInput!): [MeetAggregate!]! - """ - Получить список методов оплаты - - Требуемые роли: chairman. Исключение: доступ разрешен, если `data.username` совпадает с `username` текущего пользователя. - """ + """Получить список методов оплаты""" getPaymentMethods(data: GetPaymentMethodsInput): PaymentMethodPaginationResult! """ Получить список платежей с возможностью фильтрации по типу, статусу и направлению. - - Требуемые роли: chairman, member. Исключение: доступ разрешен, если `data.username` совпадает с `username` текущего пользователя. """ getPayments(data: PaymentFiltersInput, options: PaginationInput): PaginatedGatewayPaymentsPaginationResult! - """ - Получить один программный кошелек по фильтру - - Требуемые роли: chairman, member. - """ + """Получить один программный кошелек по фильтру""" getProgramWallet(filter: ProgramWalletFilterInput!): ProgramWallet - """ - Получить список программных кошельков с фильтрацией и пагинацией - - Требуемые роли: chairman, member. - """ + """Получить список программных кошельков с фильтрацией и пагинацией""" getProgramWallets(filter: ProgramWalletFilterInput, options: PaginationInput): ProgramWalletsPaginationResult! - """ - Получить подписку провайдера по ID - - Требуемые роли: member, chairman. - """ + """Получить подписку провайдера по ID""" getProviderSubscriptionById(id: Float!): ProviderSubscription! - """ - Получить подписки пользователя у провайдера - - Требуемые роли: member, chairman, user. - """ + """Получить подписки пользователя у провайдера""" getProviderSubscriptions: [ProviderSubscription!]! """Получить конфигурацию программ регистрации для кооператива""" getRegistrationConfig(account_type: AccountType!, coopname: String!): RegistrationConfig! - """ - Получить сгенерированный отчёт по UUID — XML возвращается дословно - - Требуемые роли: chairman. - """ + """Получить сгенерированный отчёт по UUID — XML возвращается дословно""" getReport(id: String!): GeneratedReport! """ Матрица отчётов × периодов для календарного виджета. year = календарный год сдачи (когда приходит дедлайн). Для ячеек с dueYearOffset=1 (годовая БУХОТЧ, Q4 кварталок, декабрь ПСВ) reportYear = year - 1 — именно он возвращается в периоде. - - Требуемые роли: chairman. """ getReportCalendar(year: Int!): [ReportCalendarRow!]! """ Получить черновик формы отчёта по типу+году+периоду (null если не существует) - - Требуемые роли: chairman. """ getReportDraft(period: Int, reportType: ReportType!, year: Int!): ReportDraft - """ - История сгенерированных отчётов (постраничная, без XML) - - Требуемые роли: chairman. - """ + """История сгенерированных отчётов (постраничная, без XML)""" getReportHistory(filter: ReportHistoryFilterInput): ReportHistoryPage! """ Предрасчёт полей отчёта без XML — для отображения формы перед генерацией - - Требуемые роли: chairman. """ getReportPreview(input: ReportPreviewInput!): ReportPreview! """ Объединённый вид реквизитов кооператива (ончейн + ручные) с источником каждого поля - - Требуемые роли: chairman. """ getReportRequisites: ReportRequisitesView! """Получить сводную публичную информацию о системе""" getSystemInfo: SystemInfo! - """ - Получить веб-пуш подписки пользователя - - Требуемые роли: chairman, member. - """ + """Получить веб-пуш подписки пользователя""" getUserWebPushSubscriptions(data: GetUserSubscriptionsInput!): [WebPushSubscriptionDto!]! - """ - Получить статистику веб-пуш подписок (только для председателя) - - Требуемые роли: chairman. - """ + """Получить статистику веб-пуш подписок (только для председателя)""" getWebPushSubscriptionStats: SubscriptionStatsDto! """ Список черновиков форм отчётов текущего пользователя (с опциональной фильтрацией) - - Требуемые роли: chairman. """ listReportDrafts(filter: ListReportDraftsFilterInput): [ReportDraft!]! @@ -10514,18 +9772,10 @@ type Query { """ onecoopGetDocuments(data: GetOneCoopDocumentsInput!): OneCoopDocumentsResponse! - """ - Получить полную картину процесса ledger2 по process_hash - - Требуемые роли: chairman, member. - """ + """Получить полную картину процесса ledger2 по process_hash""" process(coopname: String!, hash: String!): ProcessView! - """ - Листинг процессов ledger2 с пагинацией и фильтрами - - Требуемые роли: chairman, member. - """ + """Листинг процессов ledger2 с пагинацией и фильтрами""" processes(filter: ProcessesFilter!, pagination: PaginationInput!): ProcessSummaryPaginationResult! """Полнотекстовый поиск по документам кооператива""" @@ -10533,15 +9783,11 @@ type Query { """ Поиск приватных данных аккаунтов по запросу. Поиск осуществляется по полям ФИО, ИНН, ОГРН, наименованию организации и другим приватным данным. - - Требуемые роли: chairman, member. """ searchPrivateAccounts(data: SearchPrivateAccountsInput!): [PrivateAccountSearchResult!]! """ Валидировать edits-состояние формы: возвращает список ошибок полей с JSONPath (совпадает с editedFields-путями на клиенте). - - Требуемые роли: chairman. """ validateReportEdits(editsJson: String!, reportType: ReportType!): [FieldError!]! } @@ -12771,4 +12017,4 @@ type ZeroReportSignerEdits { enum ZeroReportSignerType { CHAIRMAN REPRESENTATIVE -} +} \ No newline at end of file diff --git a/components/controller/src/extensions/capital/application/listeners/program-share-registration-on-user-wallet-delta.listener.ts b/components/controller/src/extensions/capital/application/listeners/program-share-registration-on-user-wallet-delta.listener.ts new file mode 100644 index 00000000000..314ce404cfc --- /dev/null +++ b/components/controller/src/extensions/capital/application/listeners/program-share-registration-on-user-wallet-delta.listener.ts @@ -0,0 +1,54 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; +import { Ledger2Contract } from 'cooptypes'; +import config from '~/config/config'; +import type { IDelta } from '~/types/common'; +import { ProgramShareRegistrationService } from '../services/program-share-registration.service'; + +const BLAGOROST_WALLET_NAME = 'w.cap.blago'; + +/** + * Слушатель дельт `ledger2::userwallets`. При изменении баланса пайщика на + * программном кошельке «Благорост» (`w.cap.blago`) запускает точечную + * синхронизацию долей по всем pending|active проектам пайщика. Это закрывает + * окно между поллингом scheduler'а (по умолчанию 1440 мин) и быстрыми + * пользовательскими сценариями: invest → commit → result. + * + * `present=false` (запись стёрта при обнулении баланса, Эпик 3 §6) пока не + * обрабатываем: scheduler в итоге сверит и обнулит долю; обработка отдельной + * action regshare с user_shares=0 — отдельная задача. + */ +@Injectable() +export class ProgramShareRegistrationOnUserWalletDeltaListener { + private readonly logger = new Logger(ProgramShareRegistrationOnUserWalletDeltaListener.name); + + constructor( + private readonly programShareRegistrationService: ProgramShareRegistrationService + ) {} + + @OnEvent(`delta::${Ledger2Contract.contractName.production}::${Ledger2Contract.Tables.UserWallets.tableName}`) + async handleUserWalletDelta(delta: IDelta): Promise { + if (!delta.present) return; + if (delta.scope !== config.coopname) return; + + const value = delta.value as Ledger2Contract.Tables.UserWallets.IUserWallet | undefined; + if (!value) return; + if (String(value.wallet_name) !== BLAGOROST_WALLET_NAME) return; + if (!value.username) return; + + const username = String(value.username); + try { + await this.programShareRegistrationService.syncProgramSharesForUser( + delta.scope, + username + ); + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + const stack = error instanceof Error ? error.stack : undefined; + this.logger.warn( + `regshare event-driven sync не выполнен: coop=${delta.scope} user=${username}: ${message}`, + stack + ); + } + } +} diff --git a/components/controller/src/extensions/capital/application/services/program-share-registration.service.ts b/components/controller/src/extensions/capital/application/services/program-share-registration.service.ts index 2b39d393360..60aab6ade40 100644 --- a/components/controller/src/extensions/capital/application/services/program-share-registration.service.ts +++ b/components/controller/src/extensions/capital/application/services/program-share-registration.service.ts @@ -13,7 +13,9 @@ import { } from '../../domain/repositories/project.repository'; import { ContributorStatus } from '../../domain/enums/contributor-status.enum'; import { ProjectStatus } from '../../domain/enums/project-status.enum'; -import { WALLET_BLOCKCHAIN_PORT, type WalletBlockchainPort } from '~/domain/wallet/ports/wallet-blockchain.port'; +import type { ContributorDomainEntity } from '../../domain/entities/contributor.entity'; +import type { ProjectDomainEntity } from '../../domain/entities/project.entity'; +import { WALLET_DOMAIN_PORT, type WalletDomainPort } from '~/domain/wallet/ports/wallet-domain.port'; import { getProgramId, ProgramType } from '~/domain/wallet/enums/program-type.enum'; import { AssetUtils } from '~/shared/utils/asset.utils'; import { HttpApiError } from '~/utils/httpApiError'; @@ -40,15 +42,19 @@ export class ProgramShareRegistrationService { private readonly projectRepository: ProjectRepository, @Inject(CAPITAL_BLOCKCHAIN_PORT) private readonly capitalBlockchainPort: CapitalBlockchainPort, - @Inject(WALLET_BLOCKCHAIN_PORT) - private readonly walletBlockchainPort: WalletBlockchainPort + @Inject(WALLET_DOMAIN_PORT) + private readonly walletDomainPort: WalletDomainPort ) {} /** * Обход участников в статусах active/import, проектов pending/active; при изменении user_shares относительно capital_contributor_shares — regshare. */ async syncProgramSharesForCoop(coopname: string): Promise { - const programId = getProgramId(ProgramType.BLAGOROST); + const projects = await this.findActiveProjects(coopname); + if (projects.length === 0) { + this.logger.debug(`Синхронизация regshare: нет проектов в статусах pending/active для ${coopname}`); + return; + } const contributors = (await this.contributorRepository.findAll()).filter( (c) => @@ -56,77 +62,98 @@ export class ProgramShareRegistrationService { (c.status === ContributorStatus.ACTIVE || c.status === ContributorStatus.IMPORT) ); - const projects = (await this.projectRepository.findAll()).filter( + for (const contributor of contributors) { + await this.syncContributor(coopname, contributor, projects); + } + } + + /** + * Точечная синхронизация regshare для одного пайщика — вызывается из listener'а + * на дельты `ledger2::userwallets[w.cap.blago]`. Не пишет лог, если у пайщика + * нет ни одного pending/active проекта. + */ + async syncProgramSharesForUser(coopname: string, username: string): Promise { + const projects = await this.findActiveProjects(coopname); + if (projects.length === 0) return; + + const contributor = (await this.contributorRepository.findAll()).find( + (c) => + c.coopname === coopname && + c.username === username && + (c.status === ContributorStatus.ACTIVE || c.status === ContributorStatus.IMPORT) + ); + if (!contributor) return; + + await this.syncContributor(coopname, contributor, projects); + } + + private async findActiveProjects(coopname: string): Promise { + return (await this.projectRepository.findAll()).filter( (p) => p.coopname === coopname && (p.status === ProjectStatus.PENDING || p.status === ProjectStatus.ACTIVE) ); + } - if (projects.length === 0) { - this.logger.debug(`Синхронизация regshare: нет проектов в статусах pending/active для ${coopname}`); + private async syncContributor( + coopname: string, + contributor: ContributorDomainEntity, + projects: ProjectDomainEntity[] + ): Promise { + const programId = getProgramId(ProgramType.BLAGOROST); + + const wallet = await this.walletDomainPort.getProgramWallet({ + coopname, + username: contributor.username, + program_id: programId, + }); + + if (!wallet || !wallet.available || !wallet.blocked) return; + + let targetShares: string; + try { + targetShares = AssetUtils.sumAssets([wallet.available, wallet.blocked]); + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + this.logger.warn( + `Синхронизация regshare: не удалось сложить балансы кошелька ${contributor.username}: ${message}` + ); return; } - for (const contributor of contributors) { - const wallet = await this.walletBlockchainPort.getProgramWallet( + const targetParsed = AssetUtils.parseAsset(targetShares); + if (!targetParsed.symbol) return; + + for (const project of projects) { + const segment = await this.capitalBlockchainPort.getSegmentByProjectUser( coopname, - contributor.username, - programId + project.project_hash, + contributor.username ); - if (!wallet) { - continue; - } + const registeredStr = + segment?.capital_contributor_shares ?? AssetUtils.formatAsset(0, targetParsed.symbol); + + if (this.sameAssetAmount(registeredStr, targetShares)) continue; - let targetShares: string; try { - targetShares = AssetUtils.sumAssets([wallet.available, wallet.blocked]); - } catch (error: unknown) { - const message = error instanceof Error ? error.message : String(error); - this.logger.warn( - `Синхронизация regshare: не удалось сложить балансы кошелька ${contributor.username}: ${message}` - ); - continue; - } - - const targetParsed = AssetUtils.parseAsset(targetShares); - if (!targetParsed.symbol) { - continue; - } - - for (const project of projects) { - const segment = await this.capitalBlockchainPort.getSegmentByProjectUser( + await this.capitalBlockchainPort.registerShare({ coopname, - project.project_hash, - contributor.username + project_hash: project.project_hash, + username: contributor.username, + user_shares: targetShares, + }); + this.logger.log( + `regshare: ${contributor.username} → проект ${project.project_hash}, user_shares=${targetShares} (было ${registeredStr})` + ); + await delay(REGSHARE_TX_GAP_MS); + } catch (error: unknown) { + const message = error instanceof HttpApiError ? error.message : error instanceof Error ? error.message : String(error); + const stack = error instanceof Error ? error.stack : undefined; + this.logger.warn( + `regshare не выполнен: coop=${coopname} project=${project.project_hash} user=${contributor.username}: ${message}`, + stack ); - - const registeredStr = - segment?.capital_contributor_shares ?? AssetUtils.formatAsset(0, targetParsed.symbol); - - if (this.sameAssetAmount(registeredStr, targetShares)) { - continue; - } - - try { - await this.capitalBlockchainPort.registerShare({ - coopname, - project_hash: project.project_hash, - username: contributor.username, - user_shares: targetShares, - }); - this.logger.log( - `regshare: ${contributor.username} → проект ${project.project_hash}, user_shares=${targetShares} (было ${registeredStr})` - ); - await delay(REGSHARE_TX_GAP_MS); - } catch (error: unknown) { - const message = error instanceof HttpApiError ? error.message : error instanceof Error ? error.message : String(error); - const stack = error instanceof Error ? error.stack : undefined; - this.logger.warn( - `regshare не выполнен: coop=${coopname} project=${project.project_hash} user=${contributor.username}: ${message}`, - stack - ); - } } } } diff --git a/components/controller/src/extensions/capital/capital-extension.module.ts b/components/controller/src/extensions/capital/capital-extension.module.ts index 9aa437aaa5f..7e2a0e2e236 100644 --- a/components/controller/src/extensions/capital/capital-extension.module.ts +++ b/components/controller/src/extensions/capital/capital-extension.module.ts @@ -300,6 +300,7 @@ import { GitHubService } from './infrastructure/services/github.service'; import { GitHubSyncSchedulerService } from './infrastructure/services/github-sync-scheduler.service'; import { ProgramShareRegistrationSchedulerService } from './infrastructure/services/program-share-registration-scheduler.service'; import { ProgramShareRegistrationService } from './application/services/program-share-registration.service'; +import { ProgramShareRegistrationOnUserWalletDeltaListener } from './application/listeners/program-share-registration-on-user-wallet-delta.listener'; import { CapitalDevelopmentRepositoryGitSyncService } from './application/services/capital-development-repository-git-sync.service'; import { CapitalGithubExtensionLifecycleListener } from './application/listeners/capital-github-extension-lifecycle.listener'; import { GitCommitMarkersSyncService } from './application/services/git-commit-markers-sync.service'; @@ -824,6 +825,7 @@ IssueIdGenerationService, GitHubSyncSchedulerService, ProgramShareRegistrationService, ProgramShareRegistrationSchedulerService, + ProgramShareRegistrationOnUserWalletDeltaListener, GitCommitMarkersSyncService, { provide: ISSUE_LINKED_GIT_COMMIT_REPOSITORY, diff --git a/components/controller/src/infrastructure/database/typeorm/repositories/typeorm-ledger2-state.repository.ts b/components/controller/src/infrastructure/database/typeorm/repositories/typeorm-ledger2-state.repository.ts index 3dfb05e12c6..a7a43fb0112 100644 --- a/components/controller/src/infrastructure/database/typeorm/repositories/typeorm-ledger2-state.repository.ts +++ b/components/controller/src/infrastructure/database/typeorm/repositories/typeorm-ledger2-state.repository.ts @@ -20,6 +20,20 @@ import type { const LEDGER2_CODE = Ledger2Contract.contractName.production; +/** + * Сохранить symbol/precision исходного актива, но занулить amount. + * Используется при present=false — запись удалена в чейне (`cleanup_l2_if_empty` + * / `cleanup_l3_if_empty`), но в реестре оставляем строку с нулями, чтобы + * пользователь мог раскрыть и посмотреть историю движений. + */ +function zeroAssetLike(s: unknown): string { + const str = typeof s === 'string' ? s : ''; + const [num = '0.0000', symbol = 'RUB'] = str.trim().split(/\s+/); + const dotIdx = num.indexOf('.'); + const decimals = dotIdx === -1 ? 4 : num.length - dotIdx - 1; + return `${(0).toFixed(decimals)} ${symbol}`; +} + /** * Чтение состояния ledger2 из Postgres-таблиц блокчейн-синка. * @@ -41,41 +55,55 @@ export class TypeOrmLedger2StateRepository implements Ledger2StatePort { ) {} async getAccounts(coopname: string): Promise { + // Берём самую свежую row на ключ (DISTINCT ON по block_num DESC) вместе + // с present-флагом. Удалённые в чейне записи (present=false) **не** + // отбрасываем: оставляем строку в реестре с обнулёнными суммами и + // именем/id из last_snapshot — у такой записи может быть история + // (debit/credit), которую пользователь хочет раскрыть. const rows = await this.deltaRepo.manager.query( - `SELECT DISTINCT ON (primary_key) value + `SELECT DISTINCT ON (primary_key) value, present FROM blockchain_deltas WHERE code = $1 AND "table" = '${Ledger2Contract.Tables.Accounts.tableName}' AND scope = $2 ORDER BY primary_key, block_num DESC, created_at DESC`, [LEDGER2_CODE, coopname], ); - return (rows as Array<{ value: Record }>).map((row) => { + return (rows as Array<{ value: Record; present: boolean }>).map((row) => { const v = row.value ?? {}; + const live = row.present === true; return { id: parseInt(String(v.id ?? 0), 10), name: String(v.name ?? ''), - balance: String(v.balance ?? '0.0000 RUB'), - debitBalance: String(v.debit_balance ?? '0.0000 RUB'), - creditBalance: String(v.credit_balance ?? '0.0000 RUB'), + balance: live ? String(v.balance ?? '0.0000 RUB') : zeroAssetLike(v.balance), + debitBalance: live ? String(v.debit_balance ?? '0.0000 RUB') : zeroAssetLike(v.debit_balance), + creditBalance: live ? String(v.credit_balance ?? '0.0000 RUB') : zeroAssetLike(v.credit_balance), accountType: typeof v.account_type === 'number' ? v.account_type : Number(v.account_type ?? 0), }; }); } async getWallets(coopname: string): Promise { + // Контракт удаляет L2-запись (`cleanup_l2_if_empty`) при обнулении баланса. + // Parser2 кладёт delete как row с present=false и value=last_snapshot. + // В реестре кошельков такую запись **оставляем** (с available=0/blocked=0 + // и id/name из snapshot), чтобы пользователь мог раскрыть и посмотреть + // историю движений по кошельку. WHERE present=true тут НЕЛЬЗЯ: фильтр + // выкинет delete-row, и DISTINCT ON выберет предыдущую present=true со + // старым снимком — кошелёк продолжал бы светиться с прежним балансом. const rows = await this.deltaRepo.manager.query( - `SELECT DISTINCT ON (primary_key) value + `SELECT DISTINCT ON (primary_key) value, present FROM blockchain_deltas WHERE code = $1 AND "table" = '${Ledger2Contract.Tables.Wallets.tableName}' AND scope = $2 ORDER BY primary_key, block_num DESC, created_at DESC`, [LEDGER2_CODE, coopname], ); - return (rows as Array<{ value: Record }>).map((row) => { + return (rows as Array<{ value: Record; present: boolean }>).map((row) => { const v = row.value ?? {}; + const live = row.present === true; return { id: String(v.id ?? ''), name: String(v.name ?? ''), - available: String(v.available ?? '0.0000 RUB'), - blocked: String(v.blocked ?? '0.0000 RUB'), + available: live ? String(v.available ?? '0.0000 RUB') : zeroAssetLike(v.available), + blocked: live ? String(v.blocked ?? '0.0000 RUB') : zeroAssetLike(v.blocked), }; }); } diff --git a/components/cooptypes/src/ledger2/operations.ts b/components/cooptypes/src/ledger2/operations.ts index 7bf54825488..4975a5f09fe 100644 --- a/components/cooptypes/src/ledger2/operations.ts +++ b/components/cooptypes/src/ledger2/operations.ts @@ -97,12 +97,12 @@ export const LEDGER2_OPERATION_REGISTRY: readonly OperationMeta[] = [ { code: 'o.cap.invest', process_type: 'p.cap.invest', contract: 'capital', name: 'INVEST', wallet_op: 'TRANSFER', wallet_from: 'w.wal.share', wallet_to: 'w.cap.blago', debit: null, credit: null, - human_name: 'Инвестиция в ЦПП «Благорост» (перенос между кошельками)' }, + human_name: 'Инвестиция в ЦПП «Благорост»' }, { code: 'o.cap.commit', process_type: 'p.cap.rid', contract: 'capital', name: 'COMMIT_RID', wallet_op: 'ISSUE', wallet_from: null, wallet_to: 'w.cap.gen', debit: 8, credit: 80, - human_name: 'Коммит РИД по программе «Благорост»' }, + human_name: 'Коммит РИД по программе «Генератор»' }, { code: 'o.cap.accept', process_type: 'p.cap.rid', contract: 'capital', name: 'ACCEPT_RID', wallet_op: 'NONE', wallet_from: null, wallet_to: null, diff --git a/components/docs-harness/package-lock.json b/components/docs-harness/package-lock.json index 874c8babeca..3bafa927235 100644 --- a/components/docs-harness/package-lock.json +++ b/components/docs-harness/package-lock.json @@ -1,11 +1,11 @@ { - "name": "browser-harness", + "name": "@coopenomics/docs-harness", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "browser-harness", + "name": "@coopenomics/docs-harness", "version": "1.0.0", "license": "ISC", "devDependencies": { diff --git a/components/migrator/migration_state.json b/components/migrator/migration_state.json index 818f21a65c4..f1a53fdf04e 100644 --- a/components/migrator/migration_state.json +++ b/components/migrator/migration_state.json @@ -1,5 +1,5 @@ { - "local": "046_create_drafts.ts", + "local": "049_migrate_phase2_progwallets.ts", "test": "046_create_drafts.ts", "prod": "046_create_drafts.ts" } \ No newline at end of file