From 2afc9b6fec230c7587e399eee1d4afda33b9e8f6 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Mon, 25 May 2026 21:46:11 +0500 Subject: [PATCH 01/15] =?UTF-8?q?feat(provider):=20=D1=80=D0=B5=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=80=20=D0=BA=D0=BE=D0=BE=D0=BF=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D0=B2=D0=BE=D0=B2=20=D0=B2=20=D0=92=D0=BE=D1=81?= =?UTF-8?q?=D1=85=D0=BE=D0=B4=D0=B5=20=D1=81=20=D0=B4=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=BC=D0=B8=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B0=D0=B9=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=20(Epic=208)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Прокидывает панель провайдера в страницу «Реестр кооперативов» оператора. coopback: - ProviderService.getCooperativesRegistry() — сводит on-chain список кооперативов (getAllRows registrator.coops) с подписками провайдера (getUserSubscriptions по coopname; провайдер недоступен/без подписки → пустой массив, реестр не падает). - GraphQL query getCooperativesRegistry (chairman/member) + CooperativeRegistryItemDTO. - BlockchainModule подключён в ProviderModule. - Регенерированы schema.gql + zeus (controller). sdk: - Queries.System.GetCooperativesRegistry (selector + query) + zeus. desktop: - Страница реестра грузится через бэкенд (GraphQL) вместо прямого fetchTable из блокчейна; раскрытие строки = подписки/инстанс/биллинг; сведение on-chain статуса (active/pending/blocked) и backend-статуса инстанса; колонка стоимость/мес. Мутации активации/блокировки пока on-chain с фронта. Проверено: controller tsc, sdk typecheck+build, desktop build:spa — зелёные. Co-Authored-By: Claude Opus 4.7 --- components/controller/schema.gql | 27 +++ .../dto/cooperative-registry-item.dto.ts | 33 ++++ .../application/provider/provider.module.ts | 3 +- .../provider/resolvers/provider.resolver.ts | 11 ++ .../provider/services/provider.service.ts | 47 ++++- components/controller/zeus/const.ts | 9 + components/controller/zeus/index.ts | 77 ++++++++ .../desktop/src/entities/Union/model/store.ts | 11 +- .../Union/LoadCooperatives/api/index.ts | 20 +- .../ui/UnionPageListOfCooperatives.vue | 171 ++++++++++++++---- .../queries/system/getCooperativesRegistry.ts | 21 +++ components/sdk/src/queries/system/index.ts | 3 + .../system/cooperativeRegistryItemSelector.ts | 17 ++ components/sdk/src/zeus/const.ts | 9 + components/sdk/src/zeus/index.ts | 77 ++++++++ 15 files changed, 488 insertions(+), 48 deletions(-) create mode 100644 components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts create mode 100644 components/sdk/src/queries/system/getCooperativesRegistry.ts create mode 100644 components/sdk/src/selectors/system/cooperativeRegistryItemSelector.ts diff --git a/components/controller/schema.gql b/components/controller/schema.gql index 7a9c419d8af..abbf938e942 100644 --- a/components/controller/schema.gql +++ b/components/controller/schema.gql @@ -4386,6 +4386,26 @@ type CooperativeProgram { program_type: String! } +type CooperativeRegistryItem { + """Анонсированный домен/сайт кооператива (registrator.coops.announce)""" + announce: String + + """Имя аккаунта кооператива (coopname)""" + coopname: String! + + """Дата регистрации заявки кооператива (on-chain)""" + created_at: String + + """Есть ли у кооператива данные провайдера (хотя бы одна подписка)""" + has_provider_data: Boolean! + + """Статус кооператива в блокчейне: pending | active | blocked""" + status: String! + + """Подписки кооператива у провайдера (с инстансом и биллингом)""" + subscriptions: [ProviderSubscription!]! +} + """Страна регистрации пользователя""" enum Country { Russia @@ -10436,6 +10456,13 @@ type Query { """ getChairmanOnboardingState: ChairmanOnboardingState! + """ + Реестр кооперативов оператора: список кооперативов из блокчейна с данными провайдера (подписки, инстанс, биллинг) + + Требуемые роли: member, chairman. + """ + getCooperativesRegistry: [CooperativeRegistryItem!]! + """ Получить текущий инстанс пользователя diff --git a/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts b/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts new file mode 100644 index 00000000000..d65eaf523da --- /dev/null +++ b/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts @@ -0,0 +1,33 @@ +import { Field, ObjectType } from '@nestjs/graphql'; +import { ProviderSubscriptionDTO } from './provider-subscription.dto'; + +/** + * Элемент реестра кооперативов для оператора (Восход). + * + * Сводит в одну запись: + * - on-chain данные кооператива из registrator.coops (статус pending|active|blocked, домен, дата); + * - данные провайдера (подписки/инстанс/биллинг) из provider-backend, привязанные по coopname. + * + * Источник on-chain: BlockchainPort.getAllRows(registrator, coops). + * Источник provider: ProviderService.getUserSubscriptions(coopname) (server-secret канал). + */ +@ObjectType('CooperativeRegistryItem') +export class CooperativeRegistryItemDTO { + @Field(() => String, { description: 'Имя аккаунта кооператива (coopname)' }) + coopname!: string; + + @Field(() => String, { nullable: true, description: 'Анонсированный домен/сайт кооператива (registrator.coops.announce)' }) + announce?: string; + + @Field(() => String, { description: 'Статус кооператива в блокчейне: pending | active | blocked' }) + status!: string; + + @Field(() => String, { nullable: true, description: 'Дата регистрации заявки кооператива (on-chain)' }) + created_at?: string; + + @Field(() => Boolean, { description: 'Есть ли у кооператива данные провайдера (хотя бы одна подписка)' }) + has_provider_data!: boolean; + + @Field(() => [ProviderSubscriptionDTO], { description: 'Подписки кооператива у провайдера (с инстансом и биллингом)' }) + subscriptions!: ProviderSubscriptionDTO[]; +} diff --git a/components/controller/src/application/provider/provider.module.ts b/components/controller/src/application/provider/provider.module.ts index c4a6162c582..58915335534 100644 --- a/components/controller/src/application/provider/provider.module.ts +++ b/components/controller/src/application/provider/provider.module.ts @@ -3,11 +3,12 @@ import { ProviderService } from './services/provider.service'; import { ProviderResolver } from './resolvers/provider.resolver'; import { ConfigModule } from '@nestjs/config'; import { DocumentDomainModule } from '~/domain/document/document.module'; +import { BlockchainModule } from '~/infrastructure/blockchain/blockchain.module'; // Импортируем для регистрации GraphQL enum import '~/domain/instance-status.enum'; @Module({ - imports: [ConfigModule, DocumentDomainModule], + imports: [ConfigModule, DocumentDomainModule, BlockchainModule], providers: [ProviderService, ProviderResolver], exports: [ProviderService], }) diff --git a/components/controller/src/application/provider/resolvers/provider.resolver.ts b/components/controller/src/application/provider/resolvers/provider.resolver.ts index d92cab1e893..41cf68f5d7a 100644 --- a/components/controller/src/application/provider/resolvers/provider.resolver.ts +++ b/components/controller/src/application/provider/resolvers/provider.resolver.ts @@ -3,6 +3,7 @@ import { UseGuards } from '@nestjs/common'; import { ProviderService } from '../services/provider.service'; import { ProviderSubscriptionDTO } from '../dto/provider-subscription.dto'; import { CurrentInstanceDTO } from '../dto/current-instance.dto'; +import { CooperativeRegistryItemDTO } from '../dto/cooperative-registry-item.dto'; import { GqlJwtAuthGuard } from '~/application/auth/guards/graphql-jwt-auth.guard'; import { RolesGuard } from '~/application/auth/guards/roles.guard'; import { AuthRoles } from '~/application/auth/decorators/auth.decorator'; @@ -18,6 +19,16 @@ import { Throttle } from '@nestjs/throttler'; export class ProviderResolver { constructor(private readonly providerService: ProviderService) {} + @Query(() => [CooperativeRegistryItemDTO], { + name: 'getCooperativesRegistry', + description: 'Реестр кооперативов оператора: список кооперативов из блокчейна с данными провайдера (подписки, инстанс, биллинг)', + }) + @UseGuards(GqlJwtAuthGuard, RolesGuard) + @AuthRoles(['member', 'chairman']) + async getCooperativesRegistry(): Promise { + return this.providerService.getCooperativesRegistry(); + } + @Query(() => [ProviderSubscriptionDTO], { name: 'getProviderSubscriptions', description: 'Получить подписки пользователя у провайдера', diff --git a/components/controller/src/application/provider/services/provider.service.ts b/components/controller/src/application/provider/services/provider.service.ts index 52893740ad0..f6c33c1ac89 100644 --- a/components/controller/src/application/provider/services/provider.service.ts +++ b/components/controller/src/application/provider/services/provider.service.ts @@ -1,9 +1,12 @@ import { Injectable, Logger, BadRequestException, Inject } from '@nestjs/common'; +import { RegistratorContract } from 'cooptypes'; import { ProviderSubscriptionDTO } from '../dto/provider-subscription.dto'; import { CurrentInstanceDTO } from '../dto/current-instance.dto'; +import { CooperativeRegistryItemDTO } from '../dto/cooperative-registry-item.dto'; import { InstanceStatus } from '~/domain/instance-status.enum'; import { Client, configureClient } from '@coopenomics/provider-client'; import { config } from '~/config'; +import { BLOCKCHAIN_PORT, type BlockchainPort } from '~/domain/common/ports/blockchain.port'; import { DocumentDomainService } from '~/domain/document/services/document-domain.service'; import { ConvertToAxonStatementGenerateDocumentInputDTO } from '~/application/document/documents-dto/convert-to-axon-statement-document.dto'; import { GenerateDocumentOptionsInputDTO } from '~/application/document/dto/generate-document-options-input.dto'; @@ -19,7 +22,8 @@ export class ProviderService { constructor( private readonly documentDomainService: DocumentDomainService, - @Inject(SYSTEM_BLOCKCHAIN_PORT) private readonly systemBlockchainPort: SystemBlockchainPort + @Inject(SYSTEM_BLOCKCHAIN_PORT) private readonly systemBlockchainPort: SystemBlockchainPort, + @Inject(BLOCKCHAIN_PORT) private readonly blockchainPort: BlockchainPort ) { // Проверяем наличие PROVIDER_BASE_URL const providerBaseUrl = config.provider_base_url; @@ -43,6 +47,47 @@ export class ProviderService { return config.provider_base_url !== ''; } + /** + * Реестр кооперативов для оператора: сводит on-chain список кооперативов + * (registrator.coops) с данными провайдера (подписки/инстанс/биллинг по coopname). + * + * On-chain — источник истины по статусу кооператива (pending|active|blocked). + * Provider — источник данных подписок; если провайдер не настроен или у кооператива + * нет подписки, поле subscriptions остаётся пустым (кооператив всё равно в списке). + */ + async getCooperativesRegistry(): Promise { + const coops = (await this.blockchainPort.getAllRows( + RegistratorContract.contractName.production, + RegistratorContract.contractName.production, + RegistratorContract.Tables.Cooperatives.tableName + )) as RegistratorContract.Tables.Cooperatives.ICooperative[]; + + const providerAvailable = this.isProviderAvailable(); + + return Promise.all( + coops.map(async (coop) => { + const item = new CooperativeRegistryItemDTO(); + item.coopname = coop.username; + item.announce = coop.announce; + item.status = coop.status; + item.created_at = coop.created_at; + item.subscriptions = []; + + if (providerAvailable) { + try { + item.subscriptions = await this.getUserSubscriptions(coop.username); + } catch (error: any) { + // Провайдер недоступен или у кооператива нет подписок — не роняем весь реестр. + this.logger.warn(`Не удалось получить подписки провайдера для ${coop.username}: ${error.message}`); + } + } + + item.has_provider_data = item.subscriptions.length > 0; + return item; + }) + ); + } + /** * Получить подписки пользователя по username */ diff --git a/components/controller/zeus/const.ts b/components/controller/zeus/const.ts index 565488008a6..31d5a11f549 100644 --- a/components/controller/zeus/const.ts +++ b/components/controller/zeus/const.ts @@ -3016,6 +3016,14 @@ export const ReturnTypes: Record = { is_active:"Boolean", program_type:"String" }, + CooperativeRegistryItem:{ + announce:"String", + coopname:"String", + created_at:"String", + has_provider_data:"Boolean", + status:"String", + subscriptions:"ProviderSubscription" + }, CreateSubscriptionResponse:{ message:"String", subscription:"WebPushSubscriptionDto", @@ -4174,6 +4182,7 @@ export const ReturnTypes: Record = { getCapitalOnboardingState:"CapitalOnboardingState", getCapitalProjectLogs:"PaginatedCapitalLogsPaginationResult", getChairmanOnboardingState:"ChairmanOnboardingState", + getCooperativesRegistry:"CooperativeRegistryItem", getCurrentInstance:"CurrentInstanceDTO", getCurrentTableStates:"PaginatedCurrentTableStatesPaginationResult", getDeltas:"PaginatedDeltasPaginationResult", diff --git a/components/controller/zeus/index.ts b/components/controller/zeus/index.ts index c841bfd09b8..328e8f8b4e9 100644 --- a/components/controller/zeus/index.ts +++ b/components/controller/zeus/index.ts @@ -4268,6 +4268,22 @@ export type ValueTypes = { program_type?:boolean | `@${string}`, __typename?: boolean | `@${string}`, ['...on CooperativeProgram']?: Omit +}>; + ["CooperativeRegistryItem"]: AliasType<{ + /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + announce?:boolean | `@${string}`, + /** Имя аккаунта кооператива (coopname) */ + coopname?:boolean | `@${string}`, + /** Дата регистрации заявки кооператива (on-chain) */ + created_at?:boolean | `@${string}`, + /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ + has_provider_data?:boolean | `@${string}`, + /** Статус кооператива в блокчейне: pending | active | blocked */ + status?:boolean | `@${string}`, + /** Подписки кооператива у провайдера (с инстансом и биллингом) */ + subscriptions?:ValueTypes["ProviderSubscription"], + __typename?: boolean | `@${string}`, + ['...on CooperativeRegistryItem']?: Omit }>; /** Страна регистрации пользователя */ ["Country"]:Country; @@ -7847,6 +7863,10 @@ getCapitalProjectLogs?: [{ data: ValueTypes["GetCapitalLogsInput"] | Variable; + ["CooperativeRegistryItem"]: AliasType<{ + /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + announce?:boolean | `@${string}`, + /** Имя аккаунта кооператива (coopname) */ + coopname?:boolean | `@${string}`, + /** Дата регистрации заявки кооператива (on-chain) */ + created_at?:boolean | `@${string}`, + /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ + has_provider_data?:boolean | `@${string}`, + /** Статус кооператива в блокчейне: pending | active | blocked */ + status?:boolean | `@${string}`, + /** Подписки кооператива у провайдера (с инстансом и биллингом) */ + subscriptions?:ResolverInputTypes["ProviderSubscription"], + __typename?: boolean | `@${string}` }>; /** Страна регистрации пользователя */ ["Country"]:Country; @@ -16123,6 +16158,10 @@ getCapitalProjectLogs?: [{ data: ResolverInputTypes["GetCapitalLogsInput"]},Reso Требуемые роли: chairman. */ getChairmanOnboardingState?:ResolverInputTypes["ChairmanOnboardingState"], + /** Реестр кооперативов оператора: список кооперативов из блокчейна с данными провайдера (подписки, инстанс, биллинг) + +Требуемые роли: member, chairman. */ + getCooperativesRegistry?:ResolverInputTypes["CooperativeRegistryItem"], /** Получить текущий инстанс пользователя Требуемые роли: member, chairman, user. */ @@ -20798,6 +20837,20 @@ export type ModelTypes = { is_active: boolean, /** Тип программы: wallet/generator/blagorost/marketplace и т.п. */ program_type: string +}; + ["CooperativeRegistryItem"]: { + /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + announce?: string | undefined | null, + /** Имя аккаунта кооператива (coopname) */ + coopname: string, + /** Дата регистрации заявки кооператива (on-chain) */ + created_at?: string | undefined | null, + /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ + has_provider_data: boolean, + /** Статус кооператива в блокчейне: pending | active | blocked */ + status: string, + /** Подписки кооператива у провайдера (с инстансом и биллингом) */ + subscriptions: Array }; ["Country"]:Country; ["CreateAnnualGeneralMeetInput"]: { @@ -24708,6 +24761,10 @@ export type ModelTypes = { Требуемые роли: chairman. */ getChairmanOnboardingState: ModelTypes["ChairmanOnboardingState"], + /** Реестр кооперативов оператора: список кооперативов из блокчейна с данными провайдера (подписки, инстанс, биллинг) + +Требуемые роли: member, chairman. */ + getCooperativesRegistry: Array, /** Получить текущий инстанс пользователя Требуемые роли: member, chairman, user. */ @@ -29595,6 +29652,22 @@ export type GraphQLTypes = { /** Тип программы: wallet/generator/blagorost/marketplace и т.п. */ program_type: string, ['...on CooperativeProgram']: Omit +}; + ["CooperativeRegistryItem"]: { + __typename: "CooperativeRegistryItem", + /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + announce?: string | undefined | null, + /** Имя аккаунта кооператива (coopname) */ + coopname: string, + /** Дата регистрации заявки кооператива (on-chain) */ + created_at?: string | undefined | null, + /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ + has_provider_data: boolean, + /** Статус кооператива в блокчейне: pending | active | blocked */ + status: string, + /** Подписки кооператива у провайдера (с инстансом и биллингом) */ + subscriptions: Array, + ['...on CooperativeRegistryItem']: Omit }; /** Страна регистрации пользователя */ ["Country"]: Country; @@ -33756,6 +33829,10 @@ export type GraphQLTypes = { Требуемые роли: chairman. */ getChairmanOnboardingState: GraphQLTypes["ChairmanOnboardingState"], + /** Реестр кооперативов оператора: список кооперативов из блокчейна с данными провайдера (подписки, инстанс, биллинг) + +Требуемые роли: member, chairman. */ + getCooperativesRegistry: Array, /** Получить текущий инстанс пользователя Требуемые роли: member, chairman, user. */ diff --git a/components/desktop/src/entities/Union/model/store.ts b/components/desktop/src/entities/Union/model/store.ts index e12cc3ef72d..851cdcbff15 100644 --- a/components/desktop/src/entities/Union/model/store.ts +++ b/components/desktop/src/entities/Union/model/store.ts @@ -1,13 +1,20 @@ -import { RegistratorContract } from 'cooptypes' +import { Queries } from '@coopenomics/sdk' import { defineStore } from 'pinia' const namespace = 'union' +/** + * Элемент реестра кооперативов: on-chain данные кооператива + данные провайдера + * (подписки/инстанс/биллинг), сведённые бэкендом (coopback) по coopname. + */ +export type ICooperativeRegistryItem = + Queries.System.GetCooperativesRegistry.IOutput['getCooperativesRegistry'][number] + export const useUnionStore = defineStore( namespace, () => { - const coops = [] as RegistratorContract.Tables.Cooperatives.ICooperative[] + const coops = [] as ICooperativeRegistryItem[] return { coops diff --git a/components/desktop/src/features/Union/LoadCooperatives/api/index.ts b/components/desktop/src/features/Union/LoadCooperatives/api/index.ts index 489f6663210..02ab95ac343 100644 --- a/components/desktop/src/features/Union/LoadCooperatives/api/index.ts +++ b/components/desktop/src/features/Union/LoadCooperatives/api/index.ts @@ -1,5 +1,7 @@ import { RegistratorContract } from 'cooptypes'; import { fetchTable } from 'src/shared/api'; +import { client } from 'src/shared/api/client'; +import { Queries } from '@coopenomics/sdk'; async function loadCoopByUsername(coopname: string): Promise { const coop = (await fetchTable( @@ -16,15 +18,17 @@ async function loadCoopByUsername(coopname: string): Promise { - const requests = (await fetchTable( - RegistratorContract.contractName.production, - RegistratorContract.contractName.production, - RegistratorContract.Tables.Cooperatives.tableName - )) as RegistratorContract.Tables.Cooperatives.ICooperative[]; +/** + * Реестр кооперативов оператора грузится через бэкенд (coopback GraphQL), + * а не напрямую из блокчейна: бэкенд сводит on-chain список кооперативов + * с данными провайдера (подписки / инстанс / биллинг по coopname). + */ +async function loadCoops(): Promise { + const { [Queries.System.GetCooperativesRegistry.name]: result } = await client.Query( + Queries.System.GetCooperativesRegistry.query + ); - - return requests; + return result; } export const api = { diff --git a/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue b/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue index 7775172c1a2..844bc609f70 100644 --- a/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue +++ b/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue @@ -7,7 +7,7 @@ :rows="coops" :columns="columns" :table-colspan="9" - row-key="username" + row-key="coopname" :pagination="pagination" virtual-scroll :virtual-scroll-item-size="48" @@ -30,47 +30,77 @@ ) {{ col.label }} template(#body="props") - q-tr(:key="`m_${props.row.username}`" :props="props") + q-tr(:key="`m_${props.row.coopname}`" :props="props") q-td(auto-width) q-btn(size="sm" color="primary" round dense :icon="props.expand ? 'remove' : 'add'" @click="props.expand = !props.expand") - q-td {{ props.row.username }} + q-td {{ props.row.coopname }} q-td {{ props.row.announce }} q-td q-badge(v-if="props.row.status === 'active'" color="teal") активен - q-badge(v-if="props.row.status === 'pending'" color="orange") на рассмотрении - q-badge(v-if="props.row.status === 'blocked'" color="red") заблокирован + q-badge(v-else-if="props.row.status === 'pending'" color="orange") на рассмотрении + q-badge(v-else-if="props.row.status === 'blocked'" color="red") заблокирован + q-badge(v-else color="grey") {{ props.row.status }} - q-td {{ moment(props.row.created_at).format('DD.MM.YY HH:mm:ss') }} + q-td + template(v-if="hostingStatus(props.row)") + q-badge(:color="instanceStatusColor(hostingStatus(props.row))") {{ instanceStatusLabel(hostingStatus(props.row)) }} + span.text-caption.q-ml-xs(v-if="installationProgress(props.row) != null") {{ installationProgress(props.row) }}% + span.text-grey(v-else-if="props.row.has_provider_data") — + span.text-grey(v-else) нет подписки + + q-td + span(v-if="monthlyCost(props.row) > 0") {{ formatMoney(monthlyCost(props.row)) }} ₽/мес + span.text-grey(v-else) — + + q-td {{ props.row.created_at ? moment(props.row.created_at).format('DD.MM.YY HH:mm:ss') : '—' }} q-td q-btn-dropdown( label="действия" flat size="sm") q-list - q-item(v-if="props.row.status !== 'active'" clickable v-close-popup @click="activate(props.row.username)") + q-item(v-if="props.row.status !== 'active'" clickable v-close-popup @click="activate(props.row.coopname)") q-item-section q-item-label Активировать - q-item(v-if="props.row.status !== 'blocked'" clickable v-close-popup @click="block(props.row.username)") + q-item(v-if="props.row.status !== 'blocked'" clickable v-close-popup @click="block(props.row.coopname)") q-item-section q-item-label Заблокировать - //- q-item(clickable v-close-popup @click="deleteCoop(props.row.username)") - //- q-item-section - //- q-item-label Удалить - q-tr(v-show="props.expand" :key="`e_${props.row.username}`" :props="props" class="q-virtual-scroll--with-prev") + q-tr(v-show="props.expand" :key="`e_${props.row.coopname}`" :props="props" class="q-virtual-scroll--with-prev") q-td(colspan="100%") - slot(:expand="props.expand" :receiver="props.row.username") - ListOfDocumentsWidget( - :username="props.row.username" - :filter="{data: getDataFilter(props.row.document.hash)}" - :expand="true" - :documentType="'newsubmitted'" - ) + div.q-pa-sm + div.text-subtitle2.q-mb-sm Подписки у провайдера + + q-markup-table(v-if="props.row.subscriptions && props.row.subscriptions.length" flat dense bordered) + thead + tr + th.text-left Тип + th.text-left Статус подписки + th.text-left Стоимость + th.text-left Действует до + th.text-left Инстанс + th.text-left Прогресс + tbody + tr(v-for="sub in props.row.subscriptions" :key="sub.id") + td.text-left + | {{ sub.subscription_type_name }} + q-badge.q-ml-xs(v-if="sub.is_trial" color="purple" outline) триал + td.text-left + q-badge(:color="subscriptionStatusColor(sub.status)") {{ subscriptionStatusLabel(sub.status) }} + td.text-left {{ formatMoney(sub.price) }} ₽ / {{ sub.period_days }} дн + td.text-left {{ sub.expires_at ? moment(sub.expires_at).format('DD.MM.YY') : '—' }} + td.text-left + q-badge(v-if="sub.instance_status" :color="instanceStatusColor(sub.instance_status)") {{ instanceStatusLabel(sub.instance_status) }} + span.text-grey(v-else) — + td.text-left {{ sub.installation_progress != null ? sub.installation_progress + '%' : '—' }} + + div.text-grey.q-pa-sm(v-else) У кооператива нет подписок у провайдера. diff --git a/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue b/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue new file mode 100644 index 00000000000..4609021cb01 --- /dev/null +++ b/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue @@ -0,0 +1,74 @@ + + + + diff --git a/components/desktop/src/features/Billing/PaySubscriptions/api/index.ts b/components/desktop/src/features/Billing/PaySubscriptions/api/index.ts new file mode 100644 index 00000000000..cd25f18a8f3 --- /dev/null +++ b/components/desktop/src/features/Billing/PaySubscriptions/api/index.ts @@ -0,0 +1,15 @@ +import { client } from 'src/shared/api/client' +import { Mutations } from '@coopenomics/sdk' +import type { IPaySubscriptionsInput } from '../model' + +async function paySubscriptions(input: IPaySubscriptionsInput) { + const { [Mutations.Billing.Pay.name]: result } = await client.Mutation( + Mutations.Billing.Pay.mutation, + { variables: { input } }, + ) + return result +} + +export const api = { + paySubscriptions, +} diff --git a/components/desktop/src/features/Billing/PaySubscriptions/index.ts b/components/desktop/src/features/Billing/PaySubscriptions/index.ts new file mode 100644 index 00000000000..0f16260e744 --- /dev/null +++ b/components/desktop/src/features/Billing/PaySubscriptions/index.ts @@ -0,0 +1,2 @@ +export { usePaySubscriptions } from './model' +export type { IPaySubscriptionsInput, IPaySubscriptionsOutput } from './model' diff --git a/components/desktop/src/features/Billing/PaySubscriptions/model/index.ts b/components/desktop/src/features/Billing/PaySubscriptions/model/index.ts new file mode 100644 index 00000000000..9f2706bead0 --- /dev/null +++ b/components/desktop/src/features/Billing/PaySubscriptions/model/index.ts @@ -0,0 +1,22 @@ +import type { Mutations } from '@coopenomics/sdk' +import { api } from '../api' + +// Типы строго из SDK +export type IPaySubscriptionsInput = Mutations.Billing.Pay.IInput['input'] +export type IPaySubscriptionsOutput = + Mutations.Billing.Pay.IOutput[typeof Mutations.Billing.Pay.name] + +/** + * Списание стоимости подписок с биллинг-кошелька пайщика (Epic 12, billing::pay). + * + * ОТКРЫТО: `username` — пайщик-плательщик, чей USER_SHARED-кошелёк `w.wal.bill` + * дебетуется. Реестр оператора не знает плательщика целевого коопа автоматически, + * поэтому он указывается явно (та же конфиг-точка, что BILLING_CRON_PAYER в coopback). + */ +export function usePaySubscriptions() { + const pay = async (input: IPaySubscriptionsInput): Promise => { + return await api.paySubscriptions(input) + } + + return { pay } +} diff --git a/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue b/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue index 7775172c1a2..60b99c61d43 100644 --- a/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue +++ b/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue @@ -59,6 +59,7 @@ q-tr(v-show="props.expand" :key="`e_${props.row.username}`" :props="props" class="q-virtual-scroll--with-prev") q-td(colspan="100%") slot(:expand="props.expand" :receiver="props.row.username") + CooperativeBillingPanel(v-if="props.expand" :coopname="props.row.username") ListOfDocumentsWidget( :username="props.row.username" :filter="{data: getDataFilter(props.row.document.hash)}" @@ -79,6 +80,7 @@ const union = useUnionStore() import { ListOfDocumentsWidget } from 'src/widgets/Cooperative/Documents/ListOfDocuments'; + import { CooperativeBillingPanel } from 'src/widgets/Billing/CooperativeBillingPanel'; const getDataFilter = (hash: string) => { return { document: { diff --git a/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue b/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue index b16c9cb593e..f14c4daf94b 100644 --- a/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue +++ b/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue @@ -3,12 +3,14 @@ .row .col-md-7.col-xs-12.q-pa-sm WalletProgramWidget + ConvertToBillingDialog -- 2.52.0 From cdf90e759a65cc1b05ba304220279ae266504c28 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:01:05 +0500 Subject: [PATCH 07/15] =?UTF-8?q?refactor(wallets):=20=D0=BA=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B8=D0=B5=20=D0=BB=D0=B5=D0=B9=D0=B1=D0=BB?= =?UTF-8?q?=D1=8B=20=D0=BA=D0=BE=D1=88=D0=B5=D0=BB=D1=8C=D0=BA=D0=BE=D0=B2?= =?UTF-8?q?=20'=D0=A6=D0=9A=20=E2=80=94=20=D0=BF=D0=B0=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B9/=D1=87=D0=BB=D0=B5=D0=BD=D1=81=D0=BA=D0=B8=D0=B9/=D0=B1?= =?UTF-8?q?=D0=B8=D0=BB=D0=BB=D0=B8=D0=BD=D0=B3'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Убирает «(Epic 12)» из инлайн-комментариев wallets.hpp и сокращает human_name + program_label кошельков w.wal.share/w.wal.member/w.wal.bill до коротких форм, пригодных для UI. wallets.generated.ts перегенерирован из C++. Co-Authored-By: Claude Opus 4.7 --- .../contracts/cpp/lib/core/ledger2/wallets.hpp | 14 +++++++------- .../cooptypes/src/ledger2/wallets.generated.ts | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/components/contracts/cpp/lib/core/ledger2/wallets.hpp b/components/contracts/cpp/lib/core/ledger2/wallets.hpp index 5fb9f6d7508..c15ebc2eca1 100644 --- a/components/contracts/cpp/lib/core/ledger2/wallets.hpp +++ b/components/contracts/cpp/lib/core/ledger2/wallets.hpp @@ -46,7 +46,7 @@ struct ledger2_wallets { // wallet — паевой фонд + возвраты + ЦК static constexpr eosio::name SHARE_FUND_PAY = "w.wal.share"_n; ///< Паевой взнос пайщика (USER_SHARED) static constexpr eosio::name CK_MEMBER = "w.wal.member"_n; ///< ЦК — членская часть пайщика (USER_SHARED) - static constexpr eosio::name BILLING_FUND_PAY = "w.wal.bill"_n; ///< Членские взносы пайщика на оплату подписок (биллинг-кошелёк; USER_SHARED). Источник для контракта `billing`: o.bil.fund зачисляет (паевой→членский), o.bil.pay списывает в w.sov.infra. (Epic 12) + static constexpr eosio::name BILLING_FUND_PAY = "w.wal.bill"_n; ///< ЦК — биллинг (USER_SHARED). Источник для контракта `billing`: o.bil.fund зачисляет (паевой→членский), o.bil.pay списывает в w.sov.infra. static constexpr eosio::name WITHDRAWALS_SINK = "w.wal.wthdrw"_n; ///< DEPRECATED 2026-05-21: исторический sink возвратов. Оставлен в реестре для исторических L2-балансов (накопленные возвраты до перехода). Не использовать в новых операциях. static constexpr eosio::name WITHDRAW_PENDING = "w.wal.wpend"_n; ///< Резерв паевого под заявку на возврат (COOPERATIVE-пул). o.wal.wthreq переводит сюда с w.wal.share, o.wal.wthdec возвращает обратно, o.wal.wthcpl сжигает отсюда. Заменил механику blocked/BLOCK/UNBLOCK 2026-05-24. @@ -99,9 +99,9 @@ struct Ledger2WalletMeta { inline constexpr std::array LEDGER2_WALLET_REGISTRY = {{ // USER_SHARED (6) — L3-разрез по пайщику { ledger2_wallets::MIN_SHARE_FUND, "Минимальный паевой взнос", WalletKind::USER_SHARED }, - { ledger2_wallets::SHARE_FUND_PAY, "Паевой взнос пайщика", WalletKind::USER_SHARED }, - { ledger2_wallets::CK_MEMBER, "ЦК — членская часть пайщика", WalletKind::USER_SHARED }, - { ledger2_wallets::BILLING_FUND_PAY, "Членские взносы пайщика на оплату подписок", WalletKind::USER_SHARED }, + { ledger2_wallets::SHARE_FUND_PAY, "ЦК — паевой", WalletKind::USER_SHARED }, + { ledger2_wallets::CK_MEMBER, "ЦК — членский", WalletKind::USER_SHARED }, + { ledger2_wallets::BILLING_FUND_PAY, "ЦК — биллинг", WalletKind::USER_SHARED }, { ledger2_wallets::BLAGOROST_FUND, "ЦПП «Благорост» — единый кошелёк программы у пайщика", WalletKind::USER_SHARED }, { ledger2_wallets::PREIMP_FUND, "Первичный учёт РИД-взносов до перехода на электронный учёт", WalletKind::USER_SHARED }, @@ -234,9 +234,9 @@ struct Ledger2WalletProgramMapping { inline constexpr std::array LEDGER2_USER_SHARED_PROGRAM_MAPPING = {{ { ledger2_wallets::MIN_SHARE_FUND, 0 /* w.reg.minshr — без проверки */ }, - { ledger2_wallets::SHARE_FUND_PAY, 1 /* ЦК */ }, - { ledger2_wallets::CK_MEMBER, 1 /* ЦК */ }, - { ledger2_wallets::BILLING_FUND_PAY, 1 /* ЦК — биллинг-кошелёк под ЦК-соглашением (Epic 12) */ }, + { ledger2_wallets::SHARE_FUND_PAY, 1 /* ЦК — паевой */ }, + { ledger2_wallets::CK_MEMBER, 1 /* ЦК — членский */ }, + { ledger2_wallets::BILLING_FUND_PAY, 1 /* ЦК — биллинг */ }, { ledger2_wallets::BLAGOROST_FUND, 4 /* Благорост */ }, { ledger2_wallets::GENERATOR_FUND, 3 /* Генератор */ }, { ledger2_wallets::PREIMP_FUND, 0 /* w.cap.preimp — РИД-учёт до перехода на электронный учёт, без проверки */ }, diff --git a/components/cooptypes/src/ledger2/wallets.generated.ts b/components/cooptypes/src/ledger2/wallets.generated.ts index 16a4387bbb9..52bfa24e67b 100644 --- a/components/cooptypes/src/ledger2/wallets.generated.ts +++ b/components/cooptypes/src/ledger2/wallets.generated.ts @@ -20,9 +20,9 @@ export interface WalletMeta { */ export const LEDGER2_WALLET_REGISTRY: readonly WalletMeta[] = [ { name: "w.reg.minshr", human_name: "Минимальный паевой взнос", kind: "USER_SHARED" }, - { name: "w.wal.share", human_name: "Паевой взнос пайщика", kind: "USER_SHARED" }, - { name: "w.wal.member", human_name: "ЦК — членская часть пайщика", kind: "USER_SHARED" }, - { name: "w.wal.bill", human_name: "Членские взносы пайщика на оплату подписок", kind: "USER_SHARED" }, + { name: "w.wal.share", human_name: "ЦК — паевой", kind: "USER_SHARED" }, + { name: "w.wal.member", human_name: "ЦК — членский", kind: "USER_SHARED" }, + { name: "w.wal.bill", human_name: "ЦК — биллинг", kind: "USER_SHARED" }, { name: "w.cap.blago", human_name: "ЦПП «Благорост» — единый кошелёк программы у пайщика", kind: "USER_SHARED" }, { name: "w.cap.preimp", human_name: "Первичный учёт РИД-взносов до перехода на электронный учёт", kind: "USER_SHARED" }, { name: "w.cap.gen", human_name: "ЦПП «Генератор» — единый кошелёк программы", kind: "COOPERATIVE" }, @@ -52,9 +52,9 @@ export interface ProgramWalletMapping { */ export const LEDGER2_USER_SHARED_PROGRAM_MAPPING: readonly ProgramWalletMapping[] = [ { wallet_name: "w.reg.minshr", required_program_id: 0, program_label: null }, - { wallet_name: "w.wal.share", required_program_id: 1, program_label: "ЦК" }, - { wallet_name: "w.wal.member", required_program_id: 1, program_label: "ЦК" }, - { wallet_name: "w.wal.bill", required_program_id: 1, program_label: "ЦК — биллинг-кошелёк под ЦК-соглашением (Epic 12)" }, + { wallet_name: "w.wal.share", required_program_id: 1, program_label: "ЦК — паевой" }, + { wallet_name: "w.wal.member", required_program_id: 1, program_label: "ЦК — членский" }, + { wallet_name: "w.wal.bill", required_program_id: 1, program_label: "ЦК — биллинг" }, { wallet_name: "w.cap.blago", required_program_id: 4, program_label: "Благорост" }, { wallet_name: "w.cap.gen", required_program_id: 3, program_label: "Генератор" }, { wallet_name: "w.cap.preimp", required_program_id: 0, program_label: null }, -- 2.52.0 From 3af38c6c42c9b281a2ab8da81d960ceb246e49f3 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:01:25 +0500 Subject: [PATCH 08/15] =?UTF-8?q?refactor(contract=20billing):=20=D0=BC?= =?UTF-8?q?=D0=B8=D0=BD=D0=B8=D0=BC=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=B0=D0=BA=D1=82=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=B7=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=20(Single-Hub=20v?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pay.cpp: убирает локальный payments_index (idempotency check + emplace); дедуп payment_hash переехал на provider (POST /billing/payment-confirmed идемпотентен по hash). Контракт billing своих таблиц больше не ведёт. - convert.cpp: после Ledger2::apply зовёт Soviet::make_complete_document (newsubmitted + newresolved в soviet) — подписанное заявление пайщика попадает в общий реестр документов кооператива, как в registrator::regcoop и capital::createpinv. - Удалён lib/domain/table_billing_payments.hpp + include в domain/index.hpp. Co-Authored-By: Claude Opus 4.7 --- .../contracts/cpp/billing/src/convert.cpp | 11 ++++ components/contracts/cpp/billing/src/pay.cpp | 24 ++------ components/contracts/cpp/lib/domain/index.hpp | 3 - .../cpp/lib/domain/table_billing_payments.hpp | 55 ------------------- 4 files changed, 15 insertions(+), 78 deletions(-) delete mode 100644 components/contracts/cpp/lib/domain/table_billing_payments.hpp diff --git a/components/contracts/cpp/billing/src/convert.cpp b/components/contracts/cpp/billing/src/convert.cpp index 37d213fdfb6..24dc32d2f85 100644 --- a/components/contracts/cpp/billing/src/convert.cpp +++ b/components/contracts/cpp/billing/src/convert.cpp @@ -45,4 +45,15 @@ void billing::convert(name coopname, name username, asset amount, document2 docu document.hash, memo ); + + // Фиксируем заявление в общем реестре документов кооператива (newsubmitted + newresolved + // в soviet — как в registrator::regcoop / capital::createpinv / soviet::converttoaxn). + Soviet::make_complete_document( + _billing, + coopname, + username, + "convert"_n, + document.hash, + document + ); } diff --git a/components/contracts/cpp/billing/src/pay.cpp b/components/contracts/cpp/billing/src/pay.cpp index 00c481a0fe7..b7c0bd1cf4f 100644 --- a/components/contracts/cpp/billing/src/pay.cpp +++ b/components/contracts/cpp/billing/src/pay.cpp @@ -10,8 +10,10 @@ using namespace eosio; * контракта в `contracts_whitelist` + фактом конвертации (`convert` = согласие). * * Состав подписок on-chain не раскрывается: контракт несёт только сумму, - * `payment_hash` (ссылка на запись в БД провайдера) и memo. Повторный вызов с - * тем же `payment_hash` — идемпотентный no-op (как `transaction_id` в Epic 3). + * `payment_hash` (ссылка на запись в БД провайдера) и memo. Дедуп по + * `payment_hash` — у provider'а (Single-Hub v5: парсер Восхода ловит pay-event, + * coopback Восхода дёргает provider `POST /billing/payment-confirmed`, provider + * сам отвечает на повторы). Контракт своих таблиц не ведёт. * * @param coopname Кооператив-плательщик. * @param username Пайщик, с чьего биллинг-кошелька списываем. @@ -34,12 +36,6 @@ void billing::pay(name coopname, name username, asset amount, check(payment_hash != checksum256{}, "payment_hash обязателен"); check(memo.size() < 256, "memo не должен превышать 255 символов"); - // Идемпотентность: повторный вызов с тем же payment_hash — no-op. - auto existing = Billing::get_payment(coopname, payment_hash); - if (existing.has_value()) { - return; - } - const std::string ledger_memo = memo.empty() ? std::string("Оплата подписки за инфраструктуру") : memo; @@ -55,16 +51,4 @@ void billing::pay(name coopname, name username, asset amount, payment_hash, ledger_memo ); - - // Фиксируем факт оплаты для дедупа последующих вызовов. - Billing::payments_index payments(_billing, coopname.value); - uint64_t new_id = get_global_id_in_scope(_billing, coopname, "payments"_n); - payments.emplace(coopname, [&](auto& p) { - p.id = new_id; - p.coopname = coopname; - p.username = username; - p.amount = amount; - p.payment_hash = payment_hash; - p.paid_at = time_point_sec(current_time_point()); - }); } diff --git a/components/contracts/cpp/lib/domain/index.hpp b/components/contracts/cpp/lib/domain/index.hpp index ab224e01072..020654ef016 100644 --- a/components/contracts/cpp/lib/domain/index.hpp +++ b/components/contracts/cpp/lib/domain/index.hpp @@ -77,6 +77,3 @@ #include "table_apps_pricings.hpp" #include "table_apps_globals.hpp" #include "table_apps_clients.hpp" - -// billing (Epic 12 — оплата подписок членскими взносами) -#include "table_billing_payments.hpp" diff --git a/components/contracts/cpp/lib/domain/table_billing_payments.hpp b/components/contracts/cpp/lib/domain/table_billing_payments.hpp deleted file mode 100644 index 2132bf85fc3..00000000000 --- a/components/contracts/cpp/lib/domain/table_billing_payments.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "../consts.hpp" - -/** - * @brief Дедуп-журнал оплат подписок контракта `billing` (Epic 12). - * - * Единственная таблица контракта `billing`. Хранит ТОЛЬКО факт проведённого - * списания по `payment_hash` — для идемпотентности повторных вызовов `pay` - * (по образцу `transaction_id`-идемпотентности платежей в провайдере, Epic 3). - * Состав подписок, цены и даты on-chain НЕ хранятся — это зона ответственности - * оператора (provider backend); `payment_hash` — ссылка на запись в его БД. - */ -namespace Billing { - -using namespace eosio; - -struct [[eosio::table, eosio::contract(BILLING)]] payment { - uint64_t id; - name coopname; - name username; - asset amount; - checksum256 payment_hash; - time_point_sec paid_at; - - uint64_t primary_key() const { return id; } - checksum256 by_payment_hash() const { return payment_hash; } - uint64_t by_username() const { return username.value; } -}; - -typedef multi_index< - "payments"_n, payment, - indexed_by<"bypayhash"_n, const_mem_fun>, - indexed_by<"byusername"_n, const_mem_fun>> - payments_index; - -/** - * @brief Возвращает запись об оплате по payment_hash (для дедупа), если есть. - */ -inline std::optional get_payment(name coopname, const checksum256 &payment_hash) { - payments_index payments(_billing, coopname.value); - auto by_hash = payments.get_index<"bypayhash"_n>(); - auto it = by_hash.find(payment_hash); - if (it == by_hash.end()) - return std::nullopt; - return *it; -} - -} // namespace Billing -- 2.52.0 From 67f9b60f5eb7761d4b61952be0df01b32a49e565 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:01:37 +0500 Subject: [PATCH 09/15] =?UTF-8?q?feat(coopback):=20BILLING=5FHUB=5FMODE=20?= =?UTF-8?q?=E2=80=94=20=D0=B5=D0=B4=D0=B8=D0=BD=D1=8B=D0=B9=20guard=20?= =?UTF-8?q?=D0=B1=D0=B8=D0=BB=D0=BB=D0=B8=D0=BD=D0=B3-=D0=BC=D0=BE=D0=B4?= =?UTF-8?q?=D1=83=D0=BB=D1=8F=20(Single-Hub=20v5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - config.ts: BILLING_CRON_ENABLED → BILLING_HUB_MODE. Этот же флаг включает весь BillingModule (cron, resolver, provider-client). Один источник истины включения биллинга. - app.module.ts: BillingModule условно регистрируется в imports только при BILLING_HUB_MODE=true. На спицах флаг false → модуль вообще не подключается, GraphQL Billing.*, крон и provider-client не появляются. - billing-cron.service.ts: убран локальный guard if(!cron_enabled) return — избыточен, модуль либо подключён целиком, либо вообще не существует. Co-Authored-By: Claude Opus 4.7 --- components/controller/src/app.module.ts | 5 ++++- components/controller/src/config/config.ts | 12 +++++++----- .../domain/billing/services/billing-cron.service.ts | 4 ---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/components/controller/src/app.module.ts b/components/controller/src/app.module.ts index e47d3be985f..40bfeabc8be 100644 --- a/components/controller/src/app.module.ts +++ b/components/controller/src/app.module.ts @@ -162,7 +162,10 @@ import { MutationLoggingInterceptor } from './application/common/interceptors/mu NotificationModule, LedgerModule, Ledger2Module, - BillingModule, + // Single-Hub v5: BillingModule подключается ТОЛЬКО на Восходе-хабе + // (BILLING_HUB_MODE=true). На спицах модуль не регистрируется — + // ни GraphQL Billing.*, ни крон-сервис, ни provider-client. + ...(process.env.BILLING_HUB_MODE === 'true' ? [BillingModule] : []), ProcessRegistryModule, BlockchainExplorerModule, ProviderModule, diff --git a/components/controller/src/config/config.ts b/components/controller/src/config/config.ts index 3259e29c5dd..d104c013f31 100644 --- a/components/controller/src/config/config.ts +++ b/components/controller/src/config/config.ts @@ -87,13 +87,15 @@ const envVarsSchema = z.object({ .describe('адрес сервиса GRAPHQL'), PROVIDER_BASE_URL: z.string().default('').describe('базовый URL сервиса провайдера'), - // Billing-cron (Epic 12): рекуррентное списание подписок (oracle-паттерн — - // Antelope не поддерживает deferred_trx, тик инициирует backend). - BILLING_CRON_ENABLED: z + // Billing Single-Hub v5: BillingModule подключается только на Восходе-хабе. + // На спицах флаг false → модуль вообще не регистрируется, endpoints/cron + // не появляются. Antelope не поддерживает deferred_trx — тик крона + // инициирует backend. + BILLING_HUB_MODE: z .string() .default('false') .transform((v) => v === 'true' || v === '1') - .describe('включить периодическое списание подписок (billing::pay)'), + .describe('узел работает как биллинг-хаб (только Восход): включает BillingModule, крон и GraphQL Billing.*'), BILLING_CRON_EXPRESSION: z .string() .default('0 * * * *') @@ -283,7 +285,7 @@ export default { graphql_service: envVars.data.GRAPHQL_SERVICE, provider_base_url: envVars.data.PROVIDER_BASE_URL, billing: { - cron_enabled: envVars.data.BILLING_CRON_ENABLED, + hub_mode: envVars.data.BILLING_HUB_MODE, cron_expression: envVars.data.BILLING_CRON_EXPRESSION, coopnames: envVars.data.BILLING_CRON_COOPNAMES.split(',') .map((s) => s.trim()) diff --git a/components/controller/src/domain/billing/services/billing-cron.service.ts b/components/controller/src/domain/billing/services/billing-cron.service.ts index 4c1d93b26b3..f879fb6023a 100644 --- a/components/controller/src/domain/billing/services/billing-cron.service.ts +++ b/components/controller/src/domain/billing/services/billing-cron.service.ts @@ -38,10 +38,6 @@ export class BillingCronService implements OnModuleInit, OnModuleDestroy { ) {} onModuleInit() { - if (!config.billing.cron_enabled) { - this.logger.log('BillingCronService отключён (BILLING_CRON_ENABLED=false)'); - return; - } if (!this.providerClient.isConfigured()) { this.logger.warn('BillingCronService: PROVIDER_BASE_URL не задан — тик не будет запущен'); return; -- 2.52.0 From a0c8b9d685ed509e6aa9e5cc2966e4de10f53731 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:06:44 +0500 Subject: [PATCH 10/15] =?UTF-8?q?refactor(contract=20billing):=20convert?= =?UTF-8?q?=5Fhash=20=D0=BA=D0=B0=D0=BA=20process-=D1=8F=D0=BA=D0=BE=D1=80?= =?UTF-8?q?=D1=8C=20=D0=B4=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8=D1=8F=20con?= =?UTF-8?q?vert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 5-й аргумент action billing::convert: вместо неявной привязки к document.hash вводим явный convert_hash — детерминированный sha256 от (coopname, username, amount, anchor). Он используется: - как process_hash ledger2-операции (3-й аргумент Ledger2::apply); - как package_hash в Soviet::make_complete_document — по нему документ находится в реестре кооператива и проверяется на повторное завершение (newresolved-идемпотентность). Это связывает «процесс конвертации» в единый якорь: и финансовая операция, и подписанное заявление пайщика, и поиск документа в реестре — все смотрят на один convert_hash. Контракт по-прежнему без своих таблиц (Single-Hub v5). Breaking: меняется сигнатура convert → перегенерация cooptypes/sdk/factory обязательна; mono coopback/desktop переходят на новый параметр следующим коммитом после ARM-сборки контракта. Co-Authored-By: Claude Opus 4.7 --- components/contracts/cpp/billing/billing.hpp | 8 ++++- .../contracts/cpp/billing/src/convert.cpp | 29 +++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/components/contracts/cpp/billing/billing.hpp b/components/contracts/cpp/billing/billing.hpp index ccd176fe7cd..037c7e91921 100644 --- a/components/contracts/cpp/billing/billing.hpp +++ b/components/contracts/cpp/billing/billing.hpp @@ -57,8 +57,14 @@ public: [[eosio::action]] void migrate(); // Конвертация паевого взноса в членский на биллинг-кошелёк пайщика. + // convert_hash — детерминированный sha256 от (coopname, username, amount, + // anchor) — служит process-якорем: используется как ключ операции ledger2 + // и как package_hash для Soviet::make_complete_document (документ в реестре + // ищется именно по convert_hash). Повтор с тем же convert_hash — + // идемпотентный no-op на уровне реестра soviet (newresolved уже зафиксирован). [[eosio::action]] void convert(eosio::name coopname, eosio::name username, - eosio::asset amount, document2 document); + eosio::asset amount, eosio::checksum256 convert_hash, + document2 document); // Списание с биллинг-кошелька стоимости подписок (оплата провайдеру). [[eosio::action]] void pay(eosio::name coopname, eosio::name username, diff --git a/components/contracts/cpp/billing/src/convert.cpp b/components/contracts/cpp/billing/src/convert.cpp index 24dc32d2f85..7dd7872765d 100644 --- a/components/contracts/cpp/billing/src/convert.cpp +++ b/components/contracts/cpp/billing/src/convert.cpp @@ -11,15 +11,22 @@ using namespace eosio; * зарезервированный под оплату подписок. Сам факт конвертации трактуется как * согласие пайщика на последующие рекуррентные списания (см. `pay`). * - * @param coopname Кооператив-плательщик (его подписью релеит бэкенд после JWT). - * @param username Пайщик, чей паевой конвертируется. - * @param amount Сумма конвертации (RUB, > 0). - * @param document Подписанное пайщиком заявление (обязательно, непустой hash). + * @param coopname Кооператив-плательщик (его подписью релеит бэкенд после JWT). + * @param username Пайщик, чей паевой конвертируется. + * @param amount Сумма конвертации (RUB, > 0). + * @param convert_hash Детерминированный sha256-якорь процесса конвертации + * (coopname, username, amount, anchor). Используется как + * process_hash ledger2-операции и как package_hash в + * Soviet::make_complete_document — по нему документ + * находится в реестре кооператива. Обеспечивает связность + * процесса и идемпотентность на уровне soviet-реестра. + * @param document Подписанное пайщиком заявление (обязательно, непустой hash). * * @ingroup public_billing_actions * @note Авторизация требуется от аккаунта: @p coopname */ -void billing::convert(name coopname, name username, asset amount, document2 document) { +void billing::convert(name coopname, name username, asset amount, + checksum256 convert_hash, document2 document) { require_auth(coopname); // Плательщик должен быть кооперативом (presence-only, без статуса). @@ -27,6 +34,7 @@ void billing::convert(name coopname, name username, asset amount, document2 docu check(amount.is_valid() && amount.amount > 0, "Сумма конвертации должна быть положительной"); check(amount.symbol == _root_govern_symbol, "Неверный символ валюты для конвертации"); + check(convert_hash != checksum256{}, "convert_hash обязателен (детерминированный якорь процесса)"); // Заявление обязательно и должно быть подписано пайщиком. Ловушка: пустой // checksum256 ломает ABI-кодирование/верификацию — документ должен быть реальным. @@ -42,18 +50,21 @@ void billing::convert(name coopname, name username, asset amount, document2 docu operations::billing::CONVERT, amount, username, - document.hash, + convert_hash, memo ); - // Фиксируем заявление в общем реестре документов кооператива (newsubmitted + newresolved - // в soviet — как в registrator::regcoop / capital::createpinv / soviet::converttoaxn). + // Фиксируем заявление в общем реестре документов кооператива (newsubmitted + + // newresolved в soviet — как в registrator::regcoop / capital::createpinv / + // soviet::converttoaxn). package_hash = convert_hash — документ привязан к + // конкретному процессу конвертации; повтор с тем же convert_hash на уровне + // soviet-реестра идемпотентен. Soviet::make_complete_document( _billing, coopname, username, "convert"_n, - document.hash, + convert_hash, document ); } -- 2.52.0 From fbf9b5f07758c4b926173bf3d03725e7f3bf8374 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:08:08 +0500 Subject: [PATCH 11/15] =?UTF-8?q?fix(contract=20billing):=20action=5Fname?= =?UTF-8?q?=20=3D=20operations::billing::CONVERT=20(=D1=83=D0=BD=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4-й аргумент Soviet::make_complete_document — name бизнес-действия, по которой документ ищется в общем реестре кооператива. Generic '"convert"_n' пересекается с любыми другими 'convert' в системе (soviet::converttoaxn и т.п.). Используем готовое уникальное имя ledger2-операции operations::billing::CONVERT (= 'o.bil.fund'_n), как и в Ledger2::apply выше. Конвенция совпадает с capital (Names::Capital::REGISTER_CONTRIBUTOR), wallet (Names::WalletActions::SIGN_AGREEMENT) — namespaced unique action-name. Co-Authored-By: Claude Opus 4.7 --- components/contracts/cpp/billing/src/convert.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/contracts/cpp/billing/src/convert.cpp b/components/contracts/cpp/billing/src/convert.cpp index 7dd7872765d..49b1ac1ba33 100644 --- a/components/contracts/cpp/billing/src/convert.cpp +++ b/components/contracts/cpp/billing/src/convert.cpp @@ -56,14 +56,16 @@ void billing::convert(name coopname, name username, asset amount, // Фиксируем заявление в общем реестре документов кооператива (newsubmitted + // newresolved в soviet — как в registrator::regcoop / capital::createpinv / - // soviet::converttoaxn). package_hash = convert_hash — документ привязан к - // конкретному процессу конвертации; повтор с тем же convert_hash на уровне - // soviet-реестра идемпотентен. + // soviet::converttoaxn). action_name = operations::billing::CONVERT + // (= "o.bil.fund"_n) — уникальное имя ledger2-операции, не пересекается с + // generic "convert"_n из других контрактов. package_hash = convert_hash — + // документ привязан к конкретному процессу; повтор с тем же convert_hash на + // уровне soviet-реестра идемпотентен. Soviet::make_complete_document( _billing, coopname, username, - "convert"_n, + operations::billing::CONVERT, convert_hash, document ); -- 2.52.0 From 73d9c772a62bc5f614566a27284eb56e64ef2acd Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:21:45 +0500 Subject: [PATCH 12/15] =?UTF-8?q?fix(billing=20review):=20coopnames=20?= =?UTF-8?q?=D0=B8=D0=B7=20on-chain=20registrator=20+=20=D1=81=D0=BF=D0=B5?= =?UTF-8?q?=D1=86-DTO=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=201095?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ответ на review @ant PR #40: 1) BILLING_CRON_COOPNAMES выпилен — список коопов для тика биллинга всегда доступен в on-chain таблице registrator.coops. BillingCronService теперь запрашивает его через ProviderService.getCooperativesRegistry() с фильтром status === 'active'. Никаких CSV-списков в env. 2) Специализированный DTO документа 1095.BillingConversionStatement (канон documents-dto/*-document.dto.ts, как convert-to-axon-statement-document.dto): - Base/Generate/Signed three-class layout с типизированной meta.convert_amount; - billing-convert-input.dto: document — BillingConversionStatementSigned*, не generic SignedDigitalDocumentInputDTO; - billing.resolver: добавлена mutation generateBillingConversionStatement (аналог generateConvertToAxonStatement) с throttle 3/min, roles member/chairman; - billing.service.generateConversionStatement: устанавливает registry_id из Cooperative.Registry.BillingConversionStatement, форматирует convert_amount через AmountFormatterUtils, зовёт documentDomainService.generateDocument; - BillingModule подключает DocumentDomainModule. Co-Authored-By: Claude Opus 4.7 --- .../src/application/billing/billing.module.ts | 12 +++-- .../billing/dto/billing-convert-input.dto.ts | 12 ++--- .../billing/resolvers/billing.resolver.ts | 24 +++++++++- .../billing/services/billing.service.ts | 22 +++++++++ ...lling-conversion-statement-document.dto.ts | 45 +++++++++++++++++++ components/controller/src/config/config.ts | 9 +--- .../billing/services/billing-cron.service.ts | 20 ++++++--- 7 files changed, 123 insertions(+), 21 deletions(-) create mode 100644 components/controller/src/application/document/documents-dto/billing-conversion-statement-document.dto.ts diff --git a/components/controller/src/application/billing/billing.module.ts b/components/controller/src/application/billing/billing.module.ts index 0fe2dd91675..c4ebe577cd6 100644 --- a/components/controller/src/application/billing/billing.module.ts +++ b/components/controller/src/application/billing/billing.module.ts @@ -3,16 +3,22 @@ import { BillingService } from './services/billing.service'; import { BillingResolver } from './resolvers/billing.resolver'; import { BillingProviderClient } from '~/infrastructure/billing/billing-provider.client'; import { BillingCronService } from '~/domain/billing/services/billing-cron.service'; +import { ProviderModule } from '~/application/provider/provider.module'; +import { DocumentDomainModule } from '~/domain/document/document.module'; /** - * Модуль billing (Epic 12): + * Модуль billing (Epic 12 / Single-Hub v5): * - GraphQL-мутации оплаты подписок (convert/pay) — BillingResolver/BillingService; - * - периодическое списание (Story 12.6) — BillingCronService + HTTP-клиент провайдера. + * - периодическое списание — BillingCronService + HTTP-клиент провайдера; + * - список коопов для тика берётся из on-chain `registrator.coops` через + * ProviderService (никаких env-CSV). * * Blockchain-порт (`BILLING_BLOCKCHAIN_PORT`) предоставляется глобальным - * BlockchainModule. Подключается в корневой AppModule. + * BlockchainModule. Подключается в корневой AppModule только при + * BILLING_HUB_MODE=true. */ @Module({ + imports: [ProviderModule, DocumentDomainModule], providers: [BillingService, BillingResolver, BillingProviderClient, BillingCronService], exports: [BillingService], }) diff --git a/components/controller/src/application/billing/dto/billing-convert-input.dto.ts b/components/controller/src/application/billing/dto/billing-convert-input.dto.ts index 6ed2a079223..9b41f2e4b7f 100644 --- a/components/controller/src/application/billing/dto/billing-convert-input.dto.ts +++ b/components/controller/src/application/billing/dto/billing-convert-input.dto.ts @@ -1,7 +1,7 @@ import { Field, InputType } from '@nestjs/graphql'; import { IsString, Matches, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; -import { SignedDigitalDocumentInputDTO } from '~/application/document/dto/signed-digital-document-input.dto'; +import { BillingConversionStatementSignedDocumentInputDTO } from '~/application/document/documents-dto/billing-conversion-statement-document.dto'; /** * Input мутации `billingConvert` (действие `billing::convert`, operation `o.bil.fund`). @@ -25,10 +25,12 @@ export class BillingConvertInputDTO { @Matches(/^\d+(\.\d+)?\s+[A-Z]{1,7}$/, { message: 'Формат " ", например "1500.0000 RUB"' }) amount!: string; - @Field(() => SignedDigitalDocumentInputDTO, { - description: 'Подписанное пайщиком заявление на конвертацию (document2)', + @Field(() => BillingConversionStatementSignedDocumentInputDTO, { + description: + 'Подписанное пайщиком заявление 1095.BillingConversionStatement ' + + '(document2 с типизированной meta: convert_amount).', }) @ValidateNested() - @Type(() => SignedDigitalDocumentInputDTO) - document!: SignedDigitalDocumentInputDTO; + @Type(() => BillingConversionStatementSignedDocumentInputDTO) + document!: BillingConversionStatementSignedDocumentInputDTO; } diff --git a/components/controller/src/application/billing/resolvers/billing.resolver.ts b/components/controller/src/application/billing/resolvers/billing.resolver.ts index dcb8193f0e2..a8f554d6e36 100644 --- a/components/controller/src/application/billing/resolvers/billing.resolver.ts +++ b/components/controller/src/application/billing/resolvers/billing.resolver.ts @@ -1,5 +1,6 @@ import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; import { UseGuards } from '@nestjs/common'; +import { Throttle } from '@nestjs/throttler'; import { GqlJwtAuthGuard } from '~/application/auth/guards/graphql-jwt-auth.guard'; import { RolesGuard } from '~/application/auth/guards/roles.guard'; import { AuthRoles } from '~/application/auth/decorators/auth.decorator'; @@ -8,6 +9,9 @@ import { BillingConvertInputDTO } from '../dto/billing-convert-input.dto'; import { BillingPayInputDTO } from '../dto/billing-pay-input.dto'; import { BillingResultDTO } from '../dto/billing-result.dto'; import { BillingSummaryDTO } from '../dto/billing-summary.dto'; +import { BillingConversionStatementGenerateDocumentInputDTO } from '~/application/document/documents-dto/billing-conversion-statement-document.dto'; +import { GenerateDocumentOptionsInputDTO } from '~/application/document/dto/generate-document-options-input.dto'; +import { GeneratedDocumentDTO } from '~/application/document/dto/generated-document.dto'; /** * GraphQL фасад billing (Epic 12 — оплата инфраструктурных подписок). @@ -39,11 +43,29 @@ export class BillingResolver { return this.service.getBillingSummary(coopname, period ?? 30); } + @Mutation(() => GeneratedDocumentDTO, { + name: 'generateBillingConversionStatement', + description: + 'Генерирует заявление 1095.BillingConversionStatement (перед подписью пайщиком) — ' + + 'аналог generateConvertToAxonStatement, канон documents-dto.', + }) + @Throttle({ default: { limit: 3, ttl: 60000 } }) + @UseGuards(GqlJwtAuthGuard, RolesGuard) + @AuthRoles(['member', 'chairman']) + generateBillingConversionStatement( + @Args('data', { type: () => BillingConversionStatementGenerateDocumentInputDTO }) + data: BillingConversionStatementGenerateDocumentInputDTO, + @Args('options', { type: () => GenerateDocumentOptionsInputDTO, nullable: true }) + options: GenerateDocumentOptionsInputDTO, + ): Promise { + return this.service.generateConversionStatement(data, options); + } + @Mutation(() => BillingResultDTO, { name: 'billingConvert', description: 'Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). ' + - 'Требует подписанное пайщиком заявление (document2).', + 'Принимает подписанное пайщиком заявление 1095.BillingConversionStatement.', }) @UseGuards(GqlJwtAuthGuard, RolesGuard) @AuthRoles(['user', 'member', 'chairman']) diff --git a/components/controller/src/application/billing/services/billing.service.ts b/components/controller/src/application/billing/services/billing.service.ts index ff6180679b2..af62cb0f352 100644 --- a/components/controller/src/application/billing/services/billing.service.ts +++ b/components/controller/src/application/billing/services/billing.service.ts @@ -4,6 +4,12 @@ import { type BillingBlockchainPort, } from '~/domain/billing/ports/billing-blockchain.port'; import { BillingProviderClient } from '~/infrastructure/billing/billing-provider.client'; +import { DocumentDomainService } from '~/domain/document/services/document-domain.service'; +import { AmountFormatterUtils } from '~/shared/utils/amount-formatter.utils'; +import { Cooperative } from 'cooptypes'; +import { BillingConversionStatementGenerateDocumentInputDTO } from '~/application/document/documents-dto/billing-conversion-statement-document.dto'; +import { GenerateDocumentOptionsInputDTO } from '~/application/document/dto/generate-document-options-input.dto'; +import { GeneratedDocumentDTO } from '~/application/document/dto/generated-document.dto'; import type { BillingConvertInputDTO } from '../dto/billing-convert-input.dto'; import type { BillingPayInputDTO } from '../dto/billing-pay-input.dto'; import type { BillingResultDTO } from '../dto/billing-result.dto'; @@ -20,8 +26,24 @@ export class BillingService { constructor( @Inject(BILLING_BLOCKCHAIN_PORT) private readonly blockchainPort: BillingBlockchainPort, private readonly providerClient: BillingProviderClient, + private readonly documentDomainService: DocumentDomainService, ) {} + /** + * Генерирует заявление 1095.BillingConversionStatement — подписывает пайщик + * на стороне desktop перед `billingConvert`. Канон: provider.service → + * generateConvertToAxonStatement. + */ + async generateConversionStatement( + data: BillingConversionStatementGenerateDocumentInputDTO, + options: GenerateDocumentOptionsInputDTO, + ): Promise { + data.registry_id = Cooperative.Registry.BillingConversionStatement.registry_id; + data.convert_amount = AmountFormatterUtils.formatAmount(data.convert_amount); + const document = await this.documentDomainService.generateDocument({ data, options }); + return document as unknown as GeneratedDocumentDTO; + } + /** * Сумма к оплате кооператива за период — проекция provider getBillingSummary * для реестра кооперативов (сумма/дата след. платежа/free-метки/payment_hash). diff --git a/components/controller/src/application/document/documents-dto/billing-conversion-statement-document.dto.ts b/components/controller/src/application/document/documents-dto/billing-conversion-statement-document.dto.ts new file mode 100644 index 00000000000..7e3aedd6a18 --- /dev/null +++ b/components/controller/src/application/document/documents-dto/billing-conversion-statement-document.dto.ts @@ -0,0 +1,45 @@ +import { InputType, Field, IntersectionType, OmitType } from '@nestjs/graphql'; +import { IsString } from 'class-validator'; +import { Cooperative } from 'cooptypes'; +import { GenerateMetaDocumentInputDTO } from '~/application/document/dto/generate-meta-document-input.dto'; +import { MetaDocumentInputDTO } from '~/application/document/dto/meta-document-input.dto'; +import { SignedDigitalDocumentInputDTO } from '~/application/document/dto/signed-digital-document-input.dto'; +import type { ExcludeCommonProps } from '~/application/document/types'; + +// интерфейс параметров для генерации (registry_id = 1095) +type action = Cooperative.Registry.BillingConversionStatement.Action; + +@InputType(`BaseBillingConversionStatementMetaDocumentInput`) +class BaseBillingConversionStatementMetaDocumentInputDTO implements ExcludeCommonProps { + @Field({ description: 'Сумма к конвертации паевого в членский на биллинг-кошелёк' }) + @IsString() + convert_amount!: string; +} + +@InputType(`BillingConversionStatementGenerateDocumentInput`) +export class BillingConversionStatementGenerateDocumentInputDTO + extends IntersectionType( + BaseBillingConversionStatementMetaDocumentInputDTO, + OmitType(GenerateMetaDocumentInputDTO, ['registry_id'] as const) + ) + implements action +{ + registry_id!: number; + + constructor() { + super(); + } +} + +@InputType(`BillingConversionStatementSignedMetaDocumentInput`) +export class BillingConversionStatementSignedMetaDocumentInputDTO + extends IntersectionType(BaseBillingConversionStatementMetaDocumentInputDTO, MetaDocumentInputDTO) + implements action {} + +@InputType(`BillingConversionStatementSignedDocumentInput`) +export class BillingConversionStatementSignedDocumentInputDTO extends SignedDigitalDocumentInputDTO { + @Field(() => BillingConversionStatementSignedMetaDocumentInputDTO, { + description: 'Метаинформация заявления на конвертацию паевого в биллинг-кошелёк', + }) + public readonly meta!: BillingConversionStatementSignedMetaDocumentInputDTO; +} diff --git a/components/controller/src/config/config.ts b/components/controller/src/config/config.ts index d104c013f31..2d3ca8cde28 100644 --- a/components/controller/src/config/config.ts +++ b/components/controller/src/config/config.ts @@ -100,10 +100,6 @@ const envVarsSchema = z.object({ .string() .default('0 * * * *') .describe('cron-выражение тика биллинга (по умолчанию ежечасно)'), - BILLING_CRON_COOPNAMES: z - .string() - .default('') - .describe('CSV список коопов для списания; пусто — берётся COOPNAME узла'), BILLING_CRON_PAYER: z .string() .default('') @@ -287,9 +283,8 @@ export default { billing: { hub_mode: envVars.data.BILLING_HUB_MODE, cron_expression: envVars.data.BILLING_CRON_EXPRESSION, - coopnames: envVars.data.BILLING_CRON_COOPNAMES.split(',') - .map((s) => s.trim()) - .filter((s) => s.length > 0), + // Список коопов — из on-chain `registrator.coops` через ProviderService + // (см. BillingCronService.activeCoopnames). Env-override отсутствует. payer: envVars.data.BILLING_CRON_PAYER, }, union: { diff --git a/components/controller/src/domain/billing/services/billing-cron.service.ts b/components/controller/src/domain/billing/services/billing-cron.service.ts index f879fb6023a..b88f8499bc2 100644 --- a/components/controller/src/domain/billing/services/billing-cron.service.ts +++ b/components/controller/src/domain/billing/services/billing-cron.service.ts @@ -6,6 +6,7 @@ import { type BillingBlockchainPort, } from '~/domain/billing/ports/billing-blockchain.port'; import { BillingProviderClient } from '~/infrastructure/billing/billing-provider.client'; +import { ProviderService } from '~/application/provider/services/provider.service'; /** * Периодическое списание подписок (Epic 12, Story 12.6) — oracle-паттерн. @@ -35,6 +36,7 @@ export class BillingCronService implements OnModuleInit, OnModuleDestroy { constructor( @Inject(BILLING_BLOCKCHAIN_PORT) private readonly blockchainPort: BillingBlockchainPort, private readonly providerClient: BillingProviderClient, + private readonly providerService: ProviderService, ) {} onModuleInit() { @@ -59,13 +61,20 @@ export class BillingCronService implements OnModuleInit, OnModuleDestroy { } } - private coopnames(): string[] { - return config.billing.coopnames.length > 0 ? config.billing.coopnames : [config.coopname]; + /** + * Список коопов для тика берётся ИЗ on-chain `registrator.coops` + * (через ProviderService), отфильтрованный по `status === 'active'`. + * Никаких env-CSV — кооперативы всегда есть в блокчейне. + */ + private async activeCoopnames(): Promise { + const registry = await this.providerService.getCooperativesRegistry(); + return registry.filter((c) => c.status === 'active').map((c) => c.coopname); } /** - * Один тик: обходит коопы, списывает подошедшие к оплате. - * Защита от наложения тиков (`running`) — если предыдущий ещё идёт, пропускаем. + * Один тик: обходит активные коопы из on-chain реестра, списывает подошедшие + * к оплате. Защита от наложения тиков (`running`) — если предыдущий ещё идёт, + * пропускаем. */ async tick(): Promise { if (this.running) { @@ -79,7 +88,8 @@ export class BillingCronService implements OnModuleInit, OnModuleDestroy { } this.running = true; try { - for (const coopname of this.coopnames()) { + const coopnames = await this.activeCoopnames(); + for (const coopname of coopnames) { await this.processCoop(coopname, payer); } } finally { -- 2.52.0 From 4d585bb91dddf71d47d426eca92f469582a382f6 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Thu, 28 May 2026 17:28:04 +0500 Subject: [PATCH 13/15] =?UTF-8?q?refactor(shared):=20TransactionUtils.extr?= =?UTF-8?q?actTransactionId=20=E2=80=94=20DRY?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Дубль метода был в billing.service и ledger2.service. По правилу mono — 2-кратное повторение → shared. Один источник истины: `~/shared/utils/transaction.utils.ts` с TransactionUtils.extractTransactionId. Co-Authored-By: Claude Opus 4.7 --- .../billing/services/billing.service.ts | 17 +++---------- .../ledger2/services/ledger2.service.ts | 15 ++---------- .../src/shared/utils/transaction.utils.ts | 24 +++++++++++++++++++ 3 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 components/controller/src/shared/utils/transaction.utils.ts diff --git a/components/controller/src/application/billing/services/billing.service.ts b/components/controller/src/application/billing/services/billing.service.ts index af62cb0f352..22f76c028fe 100644 --- a/components/controller/src/application/billing/services/billing.service.ts +++ b/components/controller/src/application/billing/services/billing.service.ts @@ -6,6 +6,7 @@ import { import { BillingProviderClient } from '~/infrastructure/billing/billing-provider.client'; import { DocumentDomainService } from '~/domain/document/services/document-domain.service'; import { AmountFormatterUtils } from '~/shared/utils/amount-formatter.utils'; +import { TransactionUtils } from '~/shared/utils/transaction.utils'; import { Cooperative } from 'cooptypes'; import { BillingConversionStatementGenerateDocumentInputDTO } from '~/application/document/documents-dto/billing-conversion-statement-document.dto'; import { GenerateDocumentOptionsInputDTO } from '~/application/document/dto/generate-document-options-input.dto'; @@ -75,7 +76,7 @@ export class BillingService { quantity: input.amount, document: input.document.toDocument(), }); - return { transactionId: this.extractTransactionId(result) }; + return { transactionId: TransactionUtils.extractTransactionId(result) }; } async pay(input: BillingPayInputDTO): Promise { @@ -87,20 +88,8 @@ export class BillingService { memo: input.memo, }); return { - transactionId: this.extractTransactionId(result), + transactionId: TransactionUtils.extractTransactionId(result), paymentHash: input.paymentHash, }; } - - private extractTransactionId(result: unknown): string { - if (result && typeof result === 'object' && 'transaction_id' in result) { - const tx = (result as { transaction_id?: unknown }).transaction_id; - if (typeof tx === 'string') return tx; - } - if (result && typeof result === 'object' && 'response' in result) { - const resp = (result as { response?: { transaction_id?: unknown } }).response; - if (resp && typeof resp.transaction_id === 'string') return resp.transaction_id; - } - return ''; - } } diff --git a/components/controller/src/application/ledger2/services/ledger2.service.ts b/components/controller/src/application/ledger2/services/ledger2.service.ts index 77203d5969d..b45f04cea5f 100644 --- a/components/controller/src/application/ledger2/services/ledger2.service.ts +++ b/components/controller/src/application/ledger2/services/ledger2.service.ts @@ -1,6 +1,7 @@ import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { createHash, randomBytes } from 'node:crypto'; import { Ledger2 } from 'cooptypes'; +import { TransactionUtils } from '~/shared/utils/transaction.utils'; import { LEDGER2_STATE_PORT, type Ledger2StatePort, @@ -136,7 +137,7 @@ export class Ledger2Service { return { processHash, - transactionId: this.extractTransactionId(result), + transactionId: TransactionUtils.extractTransactionId(result), }; } @@ -185,16 +186,4 @@ export class Ledger2Service { private generateProcessHash(): string { return createHash('sha256').update(randomBytes(32)).digest('hex'); } - - private extractTransactionId(result: unknown): string { - if (result && typeof result === 'object' && 'transaction_id' in result) { - const tx = (result as { transaction_id?: unknown }).transaction_id; - if (typeof tx === 'string') return tx; - } - if (result && typeof result === 'object' && 'response' in result) { - const resp = (result as { response?: { transaction_id?: unknown } }).response; - if (resp && typeof resp.transaction_id === 'string') return resp.transaction_id; - } - return ''; - } } diff --git a/components/controller/src/shared/utils/transaction.utils.ts b/components/controller/src/shared/utils/transaction.utils.ts new file mode 100644 index 00000000000..4665283c890 --- /dev/null +++ b/components/controller/src/shared/utils/transaction.utils.ts @@ -0,0 +1,24 @@ +/** + * Утилиты для работы с результатом on-chain транзакции, который возвращают + * blockchain-порты (`BillingBlockchainPort`, `Ledger2BlockchainPort` и т.п.). + * Форма ответа Wharfkit/Antelope разная: иногда `{ transaction_id }` прямо + * в корне, иногда `{ response: { transaction_id } }`. Выносим разбор в одно + * место, чтобы сервисы не дублировали. + */ +export class TransactionUtils { + /** + * Извлекает on-chain `transaction_id` из произвольного объекта-результата + * подписи/отправки. Возвращает пустую строку, если поле не найдено. + */ + static extractTransactionId(result: unknown): string { + if (result && typeof result === 'object' && 'transaction_id' in result) { + const tx = (result as { transaction_id?: unknown }).transaction_id; + if (typeof tx === 'string') return tx; + } + if (result && typeof result === 'object' && 'response' in result) { + const resp = (result as { response?: { transaction_id?: unknown } }).response; + if (resp && typeof resp.transaction_id === 'string') return resp.transaction_id; + } + return ''; + } +} -- 2.52.0 From 021557c2c6f3615ff0d9c21654b48bf49ff83ef2 Mon Sep 17 00:00:00 2001 From: claude <4+claude@noreply.git.coopenomics.world> Date: Sat, 30 May 2026 10:23:50 +0500 Subject: [PATCH 14/15] =?UTF-8?q?[B2D-14][@ant]=20feat:=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20Single-Hub?= =?UTF-8?q?=20v5=20=E2=80=94=20FSD-=D1=80=D0=B0=D0=B7=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=B7=D0=BA=D0=B0=20=D1=81=D1=82=D0=B5=D0=BF=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B0,=20=D1=80=D0=B5=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20SDK,=20MembershipWallet=20=E2=80=94=20?= =?UTF-8?q?=D1=87=D1=82=D0=BE=D0=B1=D1=8B=20=D1=81=D0=B2=D0=B5=D1=80=D0=BD?= =?UTF-8?q?=D1=83=D1=82=D1=8C=20Epic=2012=20=D0=B4=D0=BE=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B1=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=81?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D1=8F=20=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=B2=D0=B5=D1=81=D1=82=D0=B8=20=D0=B5=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=81=20Epic=2013?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - controller/sdk Zeus: регенерация schema.gql + zeus/{const,index}.ts под актуальный coopback (DTO 1095.BillingConversionStatement, registrator, billing-invoice). - controller billing.service / provider.service / cooperative-registry-item DTO: правки под Single-Hub. - boot init/booter+infra: подгон под новые BILLING_HUB_MODE-зависимости и init-порядок. - desktop ConnectionAgreementStepper: FSD-разгрузка ConnectionAgreementPage — FormStep удалён, выделены DomainStep + FinancialParamsStep, UnionMembershipStep/AgreementStep/ApprovalWaitingStep/InstallationStep/DomainValidationStep сокращены до канона BaseCard/BaseButton/BaseInput. - desktop entities/Wallet: новый composable useCooperativeMainWallet — единая точка для w.wal.bill COOPERATIVE. - desktop widgets/ConnectionDashboard: новый MembershipWallet поверх useCooperativeMainWallet, AxonWallet/DomainCard/SubscriptionsCard перевод на канон. - desktop pages/Union: новый CooperativeDetail; ListOfCooperatives рефакторинг. - desktop features/Billing/ConvertToBillingDialog: правки под убранный auto-setup на onboarding. - удалён мёртвый CooperativeBillingPanel widget + CooperativeDataForm feature (заменены каноном). --- components/boot/src/init/booter.ts | 14 +- components/boot/src/init/infra.ts | 133 +- components/controller/schema.gql | 1199 ++++------------- .../billing/services/billing.service.ts | 4 +- .../dto/cooperative-registry-item.dto.ts | 5 +- .../provider/services/provider.service.ts | 21 +- components/controller/zeus/const.ts | 18 +- components/controller/zeus/index.ts | 305 ++++- .../desktop/extensions/soviet/install.ts | 13 + .../src/entities/Wallet/model/index.ts | 1 + .../Wallet/model/useCooperativeMainWallet.ts | 96 ++ .../ui/ConvertToBillingDialog.vue | 89 +- .../Union/CooperativeDataForm/index.ts | 1 - .../ui/CooperativeDataForm.vue | 240 ---- .../Union/CooperativeDataForm/ui/index.ts | 1 - .../ConnectionAgreementPage.vue | 75 +- .../pages/Union/CooperativeDetail/index.ts | 1 + .../ui/UnionPageCooperativeDetail.vue | 346 +++++ .../pages/Union/CooperativeDetail/ui/index.ts | 1 + .../ui/UnionPageListOfCooperatives.vue | 461 ++++--- .../pages/User/WalletPage/ui/WalletPage.vue | 3 - .../VerticalStepper/VerticalStepper.vue | 2 +- .../Billing/CooperativeBillingPanel/index.ts | 1 - .../ui/CooperativeBillingPanel.vue | 112 -- .../Steps/AgreementStep.vue | 129 +- .../Steps/ApprovalWaitingStep.vue | 249 +--- .../Steps/DomainStep.vue | 77 ++ .../Steps/DomainValidationStep.vue | 382 +----- .../Steps/FinancialParamsStep.vue | 122 ++ .../Steps/FormStep.vue | 83 -- .../Steps/InstallationStep.vue | 409 +----- .../Steps/IntroStep.vue | 75 +- .../Steps/UnionMembershipStep.vue | 475 ++----- .../ConnectionAgreementStepper/Steps/index.ts | 9 +- .../Tariffs/TariffCard.vue | 345 ++--- .../Tariffs/TariffSelector.vue | 92 +- .../ui/ConnectionAgreementStepper.vue | 164 ++- .../ConnectionDashboard/ui/AxonWallet.vue | 253 ++-- .../ui/ConnectionDashboard.vue | 18 +- .../ConnectionDashboard/ui/DomainCard.vue | 271 ++-- .../ui/MembershipWallet.vue | 83 ++ .../ui/SubscriptionsCard.vue | 211 ++- .../widgets/ConnectionDashboard/ui/index.ts | 1 + .../system/cooperativeRegistryItemSelector.ts | 1 + components/sdk/src/zeus/const.ts | 18 +- components/sdk/src/zeus/index.ts | 305 ++++- 46 files changed, 2973 insertions(+), 3941 deletions(-) create mode 100644 components/desktop/src/entities/Wallet/model/useCooperativeMainWallet.ts delete mode 100644 components/desktop/src/features/Union/CooperativeDataForm/index.ts delete mode 100644 components/desktop/src/features/Union/CooperativeDataForm/ui/CooperativeDataForm.vue delete mode 100644 components/desktop/src/features/Union/CooperativeDataForm/ui/index.ts create mode 100644 components/desktop/src/pages/Union/CooperativeDetail/index.ts create mode 100644 components/desktop/src/pages/Union/CooperativeDetail/ui/UnionPageCooperativeDetail.vue create mode 100644 components/desktop/src/pages/Union/CooperativeDetail/ui/index.ts delete mode 100644 components/desktop/src/widgets/Billing/CooperativeBillingPanel/index.ts delete mode 100644 components/desktop/src/widgets/Billing/CooperativeBillingPanel/ui/CooperativeBillingPanel.vue create mode 100644 components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainStep.vue create mode 100644 components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FinancialParamsStep.vue delete mode 100644 components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FormStep.vue create mode 100644 components/desktop/src/widgets/ConnectionDashboard/ui/MembershipWallet.vue diff --git a/components/boot/src/init/booter.ts b/components/boot/src/init/booter.ts index 8a6e0648de2..6884c67daa6 100644 --- a/components/boot/src/init/booter.ts +++ b/components/boot/src/init/booter.ts @@ -29,12 +29,22 @@ export async function bootExtra() { // провайдере (PENDING→RENT). boot:extra используется НЕ только для аренды // сервера (например, просто пересев совета/чейна для других задач), поэтому // провижининг partner1 включается ТОЛЬКО под флагом EXTRA_RENT=1. + // + // EXTRA_SEED=1 (взаимоисключающее с EXTRA_RENT) — сидит partner1 как + // пайщика-organization Восхода (newaccount + reguser + wallet-signagree + + // засев coopback) БЕЗ regcoop+preInit. Pre-state для ручного прохода + // ConnectionAgreement: signin под WIF из фикстуры → UI выбора тарифа / + // подписания / активации руками. EXTRA_RENT приоритетен. if (process.env.EXTRA_RENT === '1') { console.log('EXTRA_RENT=1 → installExtraData: провижининг partner1 (триггер аренды)') - await installExtraData(blockchain) // Регистрируем partner1 как coop (active) + await installExtraData(blockchain, 'full') + } + else if (process.env.EXTRA_SEED === '1') { + console.log('EXTRA_SEED=1 → installExtraData (candidate): partner1 — пайщик-organization, готов к UI Connect') + await installExtraData(blockchain, 'candidate') } else { - console.log('EXTRA_RENT не задан → пропускаем провижининг partner1 (аренда не запускается)') + console.log('EXTRA_RENT/EXTRA_SEED не заданы → пропускаем провижининг partner1') } console.log('Инициализируем статус системы в PostgreSQL') diff --git a/components/boot/src/init/infra.ts b/components/boot/src/init/infra.ts index 2c66a362b7e..ed0e923c036 100644 --- a/components/boot/src/init/infra.ts +++ b/components/boot/src/init/infra.ts @@ -580,7 +580,10 @@ export async function installInitialData(blockchain: Blockchain, isExtended = fa console.log('Начальные данные установлены') } -export async function installExtraData(blockchain: Blockchain) { +export async function installExtraData( + blockchain: Blockchain, + mode: 'full' | 'candidate' = 'full', +) { // Регистрируем partner1 как coop с авто-approve от провайдера (Восхода). // Без этого реальный UI flow требует ручной активации председателем — // провайдер не подтянет partner1 в свою DB пока в registrator.coops его @@ -592,33 +595,58 @@ export async function installExtraData(blockchain: Blockchain) { // program_id > 0 с проверкой «подписывается через wallet::signagree»). // Минимум для попадания в registrator.coops со status=active: // newaccount → reguser(type=organization) → regcoop → stcoopstatus(active) - console.log('\n=== installExtraData: регистрируем partner1 как coop (active) ===') + // + // mode='candidate' — пропускает regcoop+preInit. partner1 остаётся + // пайщиком-organization Восхода: можно signin под WIF из фикстуры и пройти + // UI «Connect / выбор тарифа / подписание / активация» руками. Используется + // для отладки UX подключения без авто-провижининга. + console.log(`\n=== installExtraData (${mode}): partner1 ===`) const username = 'partner1' - // Берём WIF из docs-harness/state/cooperatives/partner1.json, если он там есть. - // Без этого boot:extra на каждом запуске генерирует случайный privateKey, - // а harness 08 (chairman install wizard /partner1/install) подаёт WIF из - // фикстуры на шаге 1 — они расходятся, startInstall mutation не принимает - // ключ, wizard зависает на шаге 1 без видимой ошибки. На репозиторий - // фикстура коммит'ится разработчиком вручную; здесь только читаем. + // Источники WIF (по приоритету): env PARTNER1_WIF → фикстура + // docs-harness/state/cooperatives/partner1.json → DEFAULT_PARTNER1_WIF. + // + // DEFAULT_PARTNER1_WIF — общеизвестный test-ключ EOSIO (тот же, что у root + // системного eosio в boot/configs/config.ini). На dev-стенде использовать + // безопасно: контур закрытый, на проде partner1 не существует. Стабильный + // дефолт удобнее env-override'ов и фикстур — каждый reboot:extra даёт тот + // же signin, без записи в .env. + const DEFAULT_PARTNER1_WIF = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3' let seededKeys: { privateKey: string; publicKey: string } | undefined - try { - const fixturePath = resolve( - __dirname, - '../../../docs-harness/state/cooperatives/partner1.json', - ) - if (existsSync(fixturePath)) { - const fx = JSON.parse(readFileSync(fixturePath, 'utf-8')) - if (fx?.wif) { - // publicKey не хранится в фикстуре — деривим из приватного. - const pub = fx.publicKey || await ecc.privateToPublic(fx.wif) - seededKeys = { privateKey: fx.wif, publicKey: pub } - console.log(`✓ partner1: используем seeded WIF из фикстуры (pub=${pub.slice(0, 12)}…)`) - } + const envWif = process.env.PARTNER1_WIF?.trim() + if (envWif) { + try { + const pub = await ecc.privateToPublic(envWif) + seededKeys = { privateKey: envWif, publicKey: pub } + console.log(`✓ partner1: используем PARTNER1_WIF из env (pub=${pub.slice(0, 12)}…)`) + } catch (e: any) { + console.warn(`⚠ PARTNER1_WIF недопустим (${e.message}) — пробуем фикстуру`) } - } catch (e: any) { - console.warn(`⚠ partner1 fixture read failed (${e.message}) — генерируем новый ключ`) + } + if (!seededKeys) { + try { + const fixturePath = resolve( + __dirname, + '../../../docs-harness/state/cooperatives/partner1.json', + ) + if (existsSync(fixturePath)) { + const fx = JSON.parse(readFileSync(fixturePath, 'utf-8')) + if (fx?.wif) { + // publicKey не хранится в фикстуре — деривим из приватного. + const pub = fx.publicKey || await ecc.privateToPublic(fx.wif) + seededKeys = { privateKey: fx.wif, publicKey: pub } + console.log(`✓ partner1: используем seeded WIF из фикстуры (pub=${pub.slice(0, 12)}…)`) + } + } + } catch (e: any) { + console.warn(`⚠ partner1 fixture read failed (${e.message}) — пробуем дефолт`) + } + } + if (!seededKeys) { + const pub = await ecc.privateToPublic(DEFAULT_PARTNER1_WIF) + seededKeys = { privateKey: DEFAULT_PARTNER1_WIF, publicKey: pub } + console.log(`✓ partner1: используем DEFAULT_PARTNER1_WIF (pub=${pub.slice(0, 12)}…)`) } const account = await blockchain.generateKeypair(username, seededKeys, 'Аккаунт partner1') @@ -648,34 +676,39 @@ export async function installExtraData(blockchain: Blockchain) { registration_hash, }) - await blockchain.registerCooperative({ - username: account.username, - coopname: account.username, - params: { - is_cooperative: true, - coop_type: 'conscoop', - announce: 'partner-dev.coopenomics.world', - description: 'Партнёрский кооператив (тестовый dev-стенд)', - initial: `100.0000 ${config.token.govern_symbol}`, - minimum: `300.0000 ${config.token.govern_symbol}`, - org_initial: `1000.0000 ${config.token.govern_symbol}`, - org_minimum: `3000.0000 ${config.token.govern_symbol}`, - }, - document: { - hash: registration_hash, - signatures: [], - meta: '{}', - version: '1.0.0', - doc_hash: registration_hash, - meta_hash: registration_hash, - } as any, - }) + if (mode === 'full') { + await blockchain.registerCooperative({ + username: account.username, + coopname: account.username, + params: { + is_cooperative: true, + coop_type: 'conscoop', + announce: 'partner-dev.coopenomics.world', + description: 'Партнёрский кооператив (тестовый dev-стенд)', + initial: `100.0000 ${config.token.govern_symbol}`, + minimum: `300.0000 ${config.token.govern_symbol}`, + org_initial: `1000.0000 ${config.token.govern_symbol}`, + org_minimum: `3000.0000 ${config.token.govern_symbol}`, + }, + document: { + hash: registration_hash, + signatures: [], + meta: '{}', + version: '1.0.0', + doc_hash: registration_hash, + meta_hash: registration_hash, + } as any, + }) - await blockchain.preInit({ - coopname: account.username, - username: config.provider, - status: 'active', - }) + await blockchain.preInit({ + coopname: account.username, + username: config.provider, + status: 'active', + }) + } + else { + console.log('candidate-mode: пропускаем regcoop+preInit (UI Connect делает руками)') + } // Записываем partner1 в ЦПП Кошелька оператора (voskhod, program_id=1). // БЕЗ этого провайдерский performInitialTransfers (150 AXON на partner1 ДО diff --git a/components/controller/schema.gql b/components/controller/schema.gql index 5911b9befbd..94e9f574bc1 100644 --- a/components/controller/schema.gql +++ b/components/controller/schema.gql @@ -1359,6 +1359,99 @@ type BaseCapitalProject { voting: CapitalProjectVotingData! } +input BillingConversionStatementGenerateDocumentInput { + """Номер блока, на котором был создан документ""" + block_num: Int + + """Сумма к конвертации паевого в членский на биллинг-кошелёк""" + convert_amount: String! + + """Название кооператива, связанное с документом""" + coopname: String! + + """Дата и время создания документа""" + created_at: String + + """Имя генератора, использованного для создания документа""" + generator: String + + """Язык документа""" + lang: String + + """Ссылки, связанные с документом""" + links: [String!] + + """Часовой пояс, в котором был создан документ""" + timezone: String + + """Название документа""" + title: String + + """Имя пользователя, создавшего документ""" + username: String! + + """Версия генератора, использованного для создания документа""" + version: String +} + +input BillingConversionStatementSignedDocumentInput { + """Хэш содержимого документа""" + doc_hash: String! + + """Общий хэш (doc_hash + meta_hash)""" + hash: String! + + """Метаинформация заявления на конвертацию паевого в биллинг-кошелёк""" + meta: BillingConversionStatementSignedMetaDocumentInput! + + """Хэш мета-данных""" + meta_hash: String! + + """Вектор подписей""" + signatures: [SignatureInfoInput!]! + + """Версия стандарта документа""" + version: String! +} + +input BillingConversionStatementSignedMetaDocumentInput { + """Номер блока, на котором был создан документ""" + block_num: Int! + + """Сумма к конвертации паевого в членский на биллинг-кошелёк""" + convert_amount: String! + + """Название кооператива, связанное с документом""" + coopname: String! + + """Дата и время создания документа""" + created_at: String! + + """Имя генератора, использованного для создания документа""" + generator: String! + + """Язык документа""" + lang: String! + + """Ссылки, связанные с документом""" + links: [String!]! + + """ID документа в реестре""" + registry_id: Int! + + """Часовой пояс, в котором был создан документ""" + timezone: String! + + """Название документа""" + title: String! + + """Имя пользователя, создавшего документ""" + username: String! + + """Версия генератора, использованного для создания документа""" + version: String! +} + input BillingConvertInput { """ Сумма с символом, например "1500.0000 RUB" @@ -1368,8 +1461,10 @@ input BillingConvertInput { """Имя аккаунта кооператива""" coopname: String! - """Подписанное пайщиком заявление на конвертацию (document2)""" - document: SignedDigitalDocumentInput! + """ + Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). + """ + document: BillingConversionStatementSignedDocumentInput! """Имя аккаунта пайщика — владельца биллинг-кошелька""" username: String! @@ -1649,18 +1744,10 @@ type Branch { """Краткое название организации""" short_name: String! - """ - Доверенные аккаунты - - Требуемые роли: chairman, member. - """ + """Доверенные аккаунты""" trusted: [Individual!]! - """ - Председатель кооперативного участка - - Требуемые роли: chairman, member. - """ + """Председатель кооперативного участка""" trustee: Individual! """Тип организации""" @@ -4451,7 +4538,7 @@ type CooperativeProgram { } type CooperativeRegistryItem { - """Анонсированный домен/сайт кооператива (registrator.coops.announce)""" + """Анонсированный домен/сайт кооператива""" announce: String """Имя аккаунта кооператива (coopname)""" @@ -4463,6 +4550,9 @@ type CooperativeRegistryItem { """Есть ли у кооператива данные провайдера (хотя бы одна подписка)""" has_provider_data: Boolean! + """Наименование организации кооператива""" + name: String + """Статус кооператива в блокчейне: pending | active | blocked""" status: String! @@ -7532,470 +7622,224 @@ type Mutation { """ Добавить активного пайщика, который вступил в кооператив, не используя платформу (заполнив заявление собственноручно, оплатив вступительный и минимальный паевый взносы, и получив протокол решения совета) - - Требуемые роли: chairman, member. """ addParticipant(data: AddParticipantInput!): Account! """Добавить метод оплаты (банковский счёт или СБП)""" addPaymentMethod(data: AddPaymentMethodInput!): PaymentMethod! - """ - Добавить доверенное лицо кооперативного участка - - Требуемые роли: chairman. - """ + """Добавить доверенное лицо кооперативного участка""" addTrustedAccount(data: AddTrustedAccountInput!): Branch! """ - Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Требует подписанное пайщиком заявление (document2). - - Требуемые роли: user, member, chairman. + Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Принимает подписанное пайщиком заявление 1095.BillingConversionStatement. """ billingConvert(input: BillingConvertInput!): BillingResult! """ Списание стоимости подписок с биллинг-кошелька пайщика в инфраструктурный кошелёк кооператива (operation o.bil.pay). Идемпотентно по payment_hash. - - Требуемые роли: chairman. """ billingPay(input: BillingPayInput!): BillingResult! """Отменить заявку""" 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. """ capitalGenerateGenerationConvertStatement(data: GenerationConvertStatementGenerateDocumentInput!, 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. - """ + """Сгенерировать решение о получении займа""" 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 контракте""" @@ -8004,182 +7848,90 @@ 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. """ chatcoopCreateSecretaryRoom(data: CreateSecretaryRoomInput!): ChatcoopSecretaryRoom! - """ - Удалить событие календаря - - Требуемые роли: chairman, member. - """ + """Удалить событие календаря""" chatcoopDeleteCalendarEvent(id: String!): Boolean! """ Удалить комнату секретаря: вывести секретаря и снять комнату с синхронизации (возвращает идентификатор комнаты в реестре) - - Требуемые роли: chairman, member. """ chatcoopRemoveSecretaryRoom(data: RemoveSecretaryRoomInput!): String! - """ - Обновить событие календаря - - Требуемые роли: chairman, member. - """ + """Обновить событие календаря""" chatcoopUpdateCalendarEvent(data: UpdateChatCoopCalendarEventInput!): ChatCoopCalendarEvent! - """ - Обновить заметку (memo) к транскрипции звонка - - Требуемые роли: chairman, member. - """ + """Обновить заметку (memo) к транскрипции звонка""" chatcoopUpdateTranscriptionMemo(data: UpdateCallTranscriptionMemoInput!): CallTranscription! - """ - Выполнить шаг онбординга capital (создание предложения повестки) - - Требуемые роли: chairman. - """ + """Выполнить шаг онбординга capital (создание предложения повестки)""" completeCapitalOnboardingStep(data: CapitalOnboardingStepInput!): CapitalOnboardingState! - """ - Выполнить один из шагов онбординга (создание предложения повестки) - - Требуемые роли: chairman. - """ + """Выполнить один из шагов онбординга (создание предложения повестки)""" completeChairmanAgendaStep(data: ChairmanOnboardingAgendaInput!): ChairmanOnboardingState! """ Выполнить шаг онбординга по созданию общего собрания (сохранить hash повестки) - - Требуемые роли: chairman. """ completeChairmanGeneralMeetStep(data: ChairmanOnboardingGeneralMeetInput!): ChairmanOnboardingState! """ Выполнить шаг онбординга кооператива на расширение (решение совета или общее собрание) - - Требуемые роли: chairman. """ completeExtensionOnboardingStep(data: CompleteExtensionOnboardingStepInput!): ExtensionOnboardingState! """Завершить заявку по истечению гарантийного срока""" completeRequest(data: CompleteRequestInput!): Transaction! - """ - Подтвердить соглашение пайщика администратором - - Требуемые роли: chairman, member. - """ + """Подтвердить соглашение пайщика администратором""" confirmAgreement(data: ConfirmAgreementInput!): Transaction! """ @@ -8194,16 +7946,10 @@ type Mutation { """ Сгенерировать документ предложения повестки очередного общего собрания пайщиков - - Требуемые роли: chairman, member. """ createAnnualGeneralMeet(data: CreateAnnualGeneralMeetInput!): MeetAggregate! - """ - Создать кооперативный участок - - Требуемые роли: chairman. - """ + """Создать кооперативный участок""" createBranch(data: CreateBranchInput!): Branch! """Создать заявку на поставку имущества по предложению Поставщика""" @@ -8211,15 +7957,11 @@ type Mutation { """ Создание объекта паевого платежа производится мутацией createDepositPayment. Выполнение мутации возвращает идентификатор платежа и данные для его совершения в зависимости от выбранного платежного провайдера. - - Требуемые роли: chairman, member. """ createDepositPayment(data: CreateDepositPaymentInput!): GatewayPayment! """ Создание объекта регистрационного платежа производится мутацией createInitialPayment. Выполнение мутации возвращает идентификатор платежа и данные для его совершения в зависимости от выбранного платежного провайдера. - - Требуемые роли: chairman, member. """ createInitialPayment(data: CreateInitialPaymentInput!): GatewayPayment! @@ -8228,64 +7970,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! """Подтвердить доставку имущества Заказчику по заявке""" @@ -8294,67 +8006,38 @@ 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. + Генерирует заявление 1095.BillingConversionStatement (перед подписью пайщиком) — аналог generateConvertToAxonStatement, канон documents-dto. """ + generateBillingConversionStatement(data: BillingConversionStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! + + """Генерирует заявление на конвертацию паевого взноса в членский взнос""" generateConvertToAxonStatement(data: ConvertToAxonStatementGenerateDocumentInput!, options: GenerateDocumentOptionsInput): GeneratedDocument! """ @@ -8362,122 +8045,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! @@ -8486,11 +8111,7 @@ type Mutation { """ initSystem(data: Init!): SystemInfo! - """ - Установить расширение - - Требуемые роли: chairman. - """ + """Установить расширение""" installExtension(data: ExtensionInput!): Extension! """Произвести установку членов совета перед началом работы""" @@ -8506,25 +8127,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! @@ -8533,8 +8146,6 @@ type Mutation { """ Опубликовать предложенную повестку и проект решения для дальнейшего голосования совета по нему - - Требуемые роли: chairman, member. """ publishProjectOfFreeDecision(data: PublishProjectFreeDecisionInput!): Boolean! @@ -8554,33 +8165,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! """Отправить соглашение""" @@ -8588,26 +8187,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! """ @@ -8627,16 +8216,10 @@ type Mutation { """ Запустить воркфлоу уведомлений (только для председателя или server-secret) - - Требуемые роли: chairman. """ triggerNotificationWorkflow(data: TriggerNotificationWorkflowInput!): Boolean! - """ - Удалить расширение - - Требуемые роли: chairman. - """ + """Удалить расширение""" uninstallExtension(data: UninstallExtensionInput!): Boolean! """Снять с публикации заявку""" @@ -8644,59 +8227,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! } @@ -10212,8 +9773,6 @@ type Query { """ Построить предзаполненные edits для формы: дефолты (ledger2 + реквизиты + корректировки), с наложением dirty-полей существующего черновика (если он есть). - - Требуемые роли: chairman. """ buildInitialReportEdits(period: Int, reportType: ReportType!, year: Int!): BuildInitialReportEdits! @@ -10225,18 +9784,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, имени пользователя или хешу участника""" @@ -10245,11 +9796,7 @@ type Query { """Получение списка участников кооператива с фильтрацией""" capitalContributors(filter: CapitalContributorFilter, options: PaginationInput): PaginatedCapitalContributorsPaginationResult! - """ - Получение списка циклов кооператива с фильтрацией - - Требуемые роли: chairman, member, user. - """ + """Получение списка циклов кооператива с фильтрацией""" capitalCycles(filter: CapitalCycleFilter, options: PaginationInput): PaginatedCapitalCyclesPaginationResult! """Получение долга по внутреннему ID базы данных""" @@ -10282,18 +9829,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! """Получение проекта по хешу с компонентами""" @@ -10305,18 +9844,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! """Получение одного сегмента кооператива по фильтрам""" @@ -10328,39 +9859,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 базы данных""" @@ -10375,95 +9888,53 @@ 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 (пайщики/совет/секретарь) — для синхронизации в blago - - Требуемые роли: chairman, member, user. """ chatcoopListNonProjectCommunicationRooms: [ChatcoopNonProjectCommunicationRoom!]! - """ - Комнаты Matrix, привязанные к проекту Capital (реестр ChatCoop) - - Требуемые роли: chairman, member, user. - """ + """Комнаты Matrix, привязанные к проекту Capital (реестр ChatCoop)""" chatcoopListProjectCommunicationRooms(data: GetProjectCommunicationRoomsInput!): [ChatcoopProjectCommunicationRoom!]! """ Все комнаты реестра ChatCoop (системные/проектные — read-only, комнаты секретаря — удаляемые) - - Требуемые роли: chairman, member. """ chatcoopListSecretaryRooms: [ChatcoopSecretaryRoom!]! """ UTC-даты (YYYY-MM-DD), в которых есть сообщения новее afterOriginServerTsExclusive, для комнаты Matrix - - Требуемые роли: chairman, member, user. """ chatcoopListUtcDatesWithNewRoomMessages(data: ListUtcDatesWithNewRoomMessagesInput!): [String!]! - """ - Проверить готовность реквизитов для генерации конкретной формы - - Требуемые роли: chairman. - """ + """Проверить готовность реквизитов для генерации конкретной формы""" checkReportReadiness(reportType: ReportType!): ReportReadinessView! """ @@ -10476,45 +9947,25 @@ 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!]! """ Сумма к оплате кооператива за период (стоимость платных подписок, разбивка, дата следующего платежа, payment_hash). Источник — provider backend оператора. Для реестра кооперативов Восхода. - - Требуемые роли: chairman, member. """ getBillingSummary(coopname: String!, period: Float): BillingSummary! @@ -10524,76 +9975,44 @@ type Query { """Получить логи событий по задаче""" getCapitalIssueLogs(data: GetCapitalIssueLogsInput!, options: PaginationInput): PaginatedCapitalLogsPaginationResult! - """ - Получить состояние онбординга capital - - Требуемые роли: chairman, member, user. - """ + """Получить состояние онбординга capital""" getCapitalOnboardingState: CapitalOnboardingState! """Получить логи событий по проекту с фильтрацией и пагинацией""" getCapitalProjectLogs(data: GetCapitalLogsInput!): PaginatedCapitalLogsPaginationResult! - """ - Получить состояние онбординга председателя - - Требуемые роли: chairman. - """ + """Получить состояние онбординга председателя""" getChairmanOnboardingState: ChairmanOnboardingState! """ Реестр кооперативов оператора: список кооперативов из блокчейна с данными провайдера (подписки, инстанс, биллинг) - - Требуемые роли: member, chairman. """ getCooperativesRegistry: [CooperativeRegistryItem!]! - """ - Получить текущий инстанс пользователя - - Требуемые роли: 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, member, user. - """ + """Получить состояние онбординга кооператива на расширение""" getExtensionOnboardingState(extension_name: String!): ExtensionOnboardingState! - """ - Получить список расширений - - Требуемые роли: chairman. - """ + """Получить список расширений""" getExtensions(data: GetExtensionsInput): [Extension!]! """Получить статус установки кооператива с приватными данными""" @@ -10601,100 +10020,56 @@ 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!]! """ @@ -10705,69 +10080,43 @@ type Query { """Получить конфигурацию программ регистрации для кооператива""" 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!]! @@ -10776,18 +10125,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! """Полнотекстовый поиск по документам кооператива""" @@ -10795,15 +10136,11 @@ type Query { """ Поиск приватных данных аккаунтов по запросу. Поиск осуществляется по полям ФИО, ИНН, ОГРН, наименованию организации и другим приватным данным. - - Требуемые роли: chairman, member. """ searchPrivateAccounts(data: SearchPrivateAccountsInput!): [PrivateAccountSearchResult!]! """ Валидировать edits-состояние формы: возвращает список ошибок полей с JSONPath (совпадает с editedFields-путями на клиенте). - - Требуемые роли: chairman. """ validateReportEdits(editsJson: String!, reportType: ReportType!): [FieldError!]! } @@ -13071,4 +12408,4 @@ type ZeroReportSignerEdits { enum ZeroReportSignerType { CHAIRMAN REPRESENTATIVE -} +} \ No newline at end of file diff --git a/components/controller/src/application/billing/services/billing.service.ts b/components/controller/src/application/billing/services/billing.service.ts index 22f76c028fe..bb5d0ed6a61 100644 --- a/components/controller/src/application/billing/services/billing.service.ts +++ b/components/controller/src/application/billing/services/billing.service.ts @@ -6,6 +6,7 @@ import { import { BillingProviderClient } from '~/infrastructure/billing/billing-provider.client'; import { DocumentDomainService } from '~/domain/document/services/document-domain.service'; import { AmountFormatterUtils } from '~/shared/utils/amount-formatter.utils'; +import { DomainToBlockchainUtils } from '~/shared/utils/domain-to-blockchain.utils'; import { TransactionUtils } from '~/shared/utils/transaction.utils'; import { Cooperative } from 'cooptypes'; import { BillingConversionStatementGenerateDocumentInputDTO } from '~/application/document/documents-dto/billing-conversion-statement-document.dto'; @@ -28,6 +29,7 @@ export class BillingService { @Inject(BILLING_BLOCKCHAIN_PORT) private readonly blockchainPort: BillingBlockchainPort, private readonly providerClient: BillingProviderClient, private readonly documentDomainService: DocumentDomainService, + private readonly domainToBlockchainUtils: DomainToBlockchainUtils, ) {} /** @@ -74,7 +76,7 @@ export class BillingService { coopname: input.coopname, username: input.username, quantity: input.amount, - document: input.document.toDocument(), + document: this.domainToBlockchainUtils.convertSignedDocumentToBlockchainFormat(input.document), }); return { transactionId: TransactionUtils.extractTransactionId(result) }; } diff --git a/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts b/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts index d65eaf523da..871f76037ae 100644 --- a/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts +++ b/components/controller/src/application/provider/dto/cooperative-registry-item.dto.ts @@ -16,7 +16,10 @@ export class CooperativeRegistryItemDTO { @Field(() => String, { description: 'Имя аккаунта кооператива (coopname)' }) coopname!: string; - @Field(() => String, { nullable: true, description: 'Анонсированный домен/сайт кооператива (registrator.coops.announce)' }) + @Field(() => String, { nullable: true, description: 'Наименование организации кооператива' }) + name?: string; + + @Field(() => String, { nullable: true, description: 'Анонсированный домен/сайт кооператива' }) announce?: string; @Field(() => String, { description: 'Статус кооператива в блокчейне: pending | active | blocked' }) diff --git a/components/controller/src/application/provider/services/provider.service.ts b/components/controller/src/application/provider/services/provider.service.ts index f6c33c1ac89..9da80773425 100644 --- a/components/controller/src/application/provider/services/provider.service.ts +++ b/components/controller/src/application/provider/services/provider.service.ts @@ -7,6 +7,7 @@ import { InstanceStatus } from '~/domain/instance-status.enum'; import { Client, configureClient } from '@coopenomics/provider-client'; import { config } from '~/config'; import { BLOCKCHAIN_PORT, type BlockchainPort } from '~/domain/common/ports/blockchain.port'; +import { ORGANIZATION_REPOSITORY, type OrganizationRepository } from '~/domain/common/repositories/organization.repository'; import { DocumentDomainService } from '~/domain/document/services/document-domain.service'; import { ConvertToAxonStatementGenerateDocumentInputDTO } from '~/application/document/documents-dto/convert-to-axon-statement-document.dto'; import { GenerateDocumentOptionsInputDTO } from '~/application/document/dto/generate-document-options-input.dto'; @@ -23,7 +24,8 @@ export class ProviderService { constructor( private readonly documentDomainService: DocumentDomainService, @Inject(SYSTEM_BLOCKCHAIN_PORT) private readonly systemBlockchainPort: SystemBlockchainPort, - @Inject(BLOCKCHAIN_PORT) private readonly blockchainPort: BlockchainPort + @Inject(BLOCKCHAIN_PORT) private readonly blockchainPort: BlockchainPort, + @Inject(ORGANIZATION_REPOSITORY) private readonly organizationRepository: OrganizationRepository ) { // Проверяем наличие PROVIDER_BASE_URL const providerBaseUrl = config.provider_base_url; @@ -68,6 +70,7 @@ export class ProviderService { coops.map(async (coop) => { const item = new CooperativeRegistryItemDTO(); item.coopname = coop.username; + item.name = await this.resolveOrganizationName(coop.username, coop.description); item.announce = coop.announce; item.status = coop.status; item.created_at = coop.created_at; @@ -88,6 +91,22 @@ export class ProviderService { ); } + /** + * Извлечь человеко-читаемое наименование кооператива. Сначала пробуем + * organization-запись в Mongo (short_name → full_name), потом on-chain + * description; если и его нет — null, фронт сам отрисует coopname. + */ + private async resolveOrganizationName(username: string, onChainDescription: string): Promise { + try { + const organization = await this.organizationRepository.findByUsername(username); + const name = organization?.short_name || organization?.full_name; + if (name) return name; + } catch { + // organization ещё не зарегистрирована — fallback на on-chain + } + return onChainDescription || undefined; + } + /** * Получить подписки пользователя по username */ diff --git a/components/controller/zeus/const.ts b/components/controller/zeus/const.ts index 0280e229794..f78b36cabeb 100644 --- a/components/controller/zeus/const.ts +++ b/components/controller/zeus/const.ts @@ -127,9 +127,19 @@ export const AllTypesProps: Record = { }, BankAccountInput:{ details:"BankAccountDetailsInput" + }, + BillingConversionStatementGenerateDocumentInput:{ + + }, + BillingConversionStatementSignedDocumentInput:{ + meta:"BillingConversionStatementSignedMetaDocumentInput", + signatures:"SignatureInfoInput" + }, + BillingConversionStatementSignedMetaDocumentInput:{ + }, BillingConvertInput:{ - document:"SignedDigitalDocumentInput" + document:"BillingConversionStatementSignedDocumentInput" }, BillingPayInput:{ @@ -1039,6 +1049,10 @@ export const AllTypesProps: Record = { data:"AnnualGeneralMeetingVotingBallotGenerateDocumentInput", options:"GenerateDocumentOptionsInput" }, + generateBillingConversionStatement:{ + data:"BillingConversionStatementGenerateDocumentInput", + options:"GenerateDocumentOptionsInput" + }, generateConvertToAxonStatement:{ data:"ConvertToAxonStatementGenerateDocumentInput", options:"GenerateDocumentOptionsInput" @@ -3056,6 +3070,7 @@ export const ReturnTypes: Record = { coopname:"String", created_at:"String", has_provider_data:"Boolean", + name:"String", status:"String", subscriptions:"ProviderSubscription" }, @@ -3670,6 +3685,7 @@ export const ReturnTypes: Record = { generateAssetContributionDecision:"GeneratedDocument", generateAssetContributionStatement:"GeneratedDocument", generateBallotForAnnualGeneralMeetDocument:"GeneratedDocument", + generateBillingConversionStatement:"GeneratedDocument", generateConvertToAxonStatement:"GeneratedDocument", generateDocument:"GeneratedDocument", generateFreeDecision:"GeneratedDocument", diff --git a/components/controller/zeus/index.ts b/components/controller/zeus/index.ts index 5ce0271a0c3..2d4ca7a63e6 100644 --- a/components/controller/zeus/index.ts +++ b/components/controller/zeus/index.ts @@ -2079,13 +2079,77 @@ export type ValueTypes = { __typename?: boolean | `@${string}`, ['...on BaseCapitalProject']?: Omit }>; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null | Variable, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string | Variable, + /** Название кооператива, связанное с документом */ + coopname: string | Variable, + /** Дата и время создания документа */ + created_at?: string | undefined | null | Variable, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null | Variable, + /** Язык документа */ + lang?: string | undefined | null | Variable, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null | Variable, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null | Variable, + /** Название документа */ + title?: string | undefined | null | Variable, + /** Имя пользователя, создавшего документ */ + username: string | Variable, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null | Variable +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string | Variable, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string | Variable, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: ValueTypes["BillingConversionStatementSignedMetaDocumentInput"] | Variable, + /** Хэш мета-данных */ + meta_hash: string | Variable, + /** Вектор подписей */ + signatures: Array | Variable, + /** Версия стандарта документа */ + version: string | Variable +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number | Variable, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string | Variable, + /** Название кооператива, связанное с документом */ + coopname: string | Variable, + /** Дата и время создания документа */ + created_at: string | Variable, + /** Имя генератора, использованного для создания документа */ + generator: string | Variable, + /** Язык документа */ + lang: string | Variable, + /** Ссылки, связанные с документом */ + links: Array | Variable, + /** ID документа в реестре */ + registry_id: number | Variable, + /** Часовой пояс, в котором был создан документ */ + timezone: string | Variable, + /** Название документа */ + title: string | Variable, + /** Имя пользователя, создавшего документ */ + username: string | Variable, + /** Версия генератора, использованного для создания документа */ + version: string | Variable +}; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string | Variable, /** Имя аккаунта кооператива */ coopname: string | Variable, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: ValueTypes["SignedDigitalDocumentInput"] | Variable, + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: ValueTypes["BillingConversionStatementSignedDocumentInput"] | Variable, /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string | Variable }; @@ -4319,7 +4383,7 @@ export type ValueTypes = { ['...on CooperativeProgram']?: Omit }>; ["CooperativeRegistryItem"]: AliasType<{ - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?:boolean | `@${string}`, /** Имя аккаунта кооператива (coopname) */ coopname?:boolean | `@${string}`, @@ -4327,6 +4391,8 @@ export type ValueTypes = { created_at?:boolean | `@${string}`, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data?:boolean | `@${string}`, + /** Наименование организации кооператива */ + name?:boolean | `@${string}`, /** Статус кооператива в блокчейне: pending | active | blocked */ status?:boolean | `@${string}`, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -6606,6 +6672,7 @@ generateAssetContributionAct?: [{ data: ValueTypes["AssetContributionActGenerate generateAssetContributionDecision?: [{ data: ValueTypes["AssetContributionDecisionGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateAssetContributionStatement?: [{ data: ValueTypes["AssetContributionStatementGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateBallotForAnnualGeneralMeetDocument?: [{ data: ValueTypes["AnnualGeneralMeetingVotingBallotGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], +generateBillingConversionStatement?: [{ data: ValueTypes["BillingConversionStatementGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateConvertToAxonStatement?: [{ data: ValueTypes["ConvertToAxonStatementGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateDocument?: [{ input: ValueTypes["GenerateAnyDocumentInput"] | Variable},ValueTypes["GeneratedDocument"]], generateFreeDecision?: [{ data: ValueTypes["FreeDecisionGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], @@ -10597,13 +10664,77 @@ export type ResolverInputTypes = { voting?:ResolverInputTypes["CapitalProjectVotingData"], __typename?: boolean | `@${string}` }>; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at?: string | undefined | null, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null, + /** Язык документа */ + lang?: string | undefined | null, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null, + /** Название документа */ + title?: string | undefined | null, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: ResolverInputTypes["BillingConversionStatementSignedMetaDocumentInput"], + /** Хэш мета-данных */ + meta_hash: string, + /** Вектор подписей */ + signatures: Array, + /** Версия стандарта документа */ + version: string +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at: string, + /** Имя генератора, использованного для создания документа */ + generator: string, + /** Язык документа */ + lang: string, + /** Ссылки, связанные с документом */ + links: Array, + /** ID документа в реестре */ + registry_id: number, + /** Часовой пояс, в котором был создан документ */ + timezone: string, + /** Название документа */ + title: string, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version: string +}; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string, /** Имя аккаунта кооператива */ coopname: string, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: ResolverInputTypes["SignedDigitalDocumentInput"], + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: ResolverInputTypes["BillingConversionStatementSignedDocumentInput"], /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string }; @@ -12772,7 +12903,7 @@ export type ResolverInputTypes = { __typename?: boolean | `@${string}` }>; ["CooperativeRegistryItem"]: AliasType<{ - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?:boolean | `@${string}`, /** Имя аккаунта кооператива (coopname) */ coopname?:boolean | `@${string}`, @@ -12780,6 +12911,8 @@ export type ResolverInputTypes = { created_at?:boolean | `@${string}`, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data?:boolean | `@${string}`, + /** Наименование организации кооператива */ + name?:boolean | `@${string}`, /** Статус кооператива в блокчейне: pending | active | blocked */ status?:boolean | `@${string}`, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -15005,6 +15138,7 @@ generateAssetContributionAct?: [{ data: ResolverInputTypes["AssetContributionAct generateAssetContributionDecision?: [{ data: ResolverInputTypes["AssetContributionDecisionGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateAssetContributionStatement?: [{ data: ResolverInputTypes["AssetContributionStatementGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateBallotForAnnualGeneralMeetDocument?: [{ data: ResolverInputTypes["AnnualGeneralMeetingVotingBallotGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], +generateBillingConversionStatement?: [{ data: ResolverInputTypes["BillingConversionStatementGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateConvertToAxonStatement?: [{ data: ResolverInputTypes["ConvertToAxonStatementGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateDocument?: [{ input: ResolverInputTypes["GenerateAnyDocumentInput"]},ResolverInputTypes["GeneratedDocument"]], generateFreeDecision?: [{ data: ResolverInputTypes["FreeDecisionGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], @@ -18877,14 +19011,78 @@ export type ModelTypes = { title: string, /** Данные голосования по методу Водянова */ voting: ModelTypes["CapitalProjectVotingData"] +}; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at?: string | undefined | null, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null, + /** Язык документа */ + lang?: string | undefined | null, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null, + /** Название документа */ + title?: string | undefined | null, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: ModelTypes["BillingConversionStatementSignedMetaDocumentInput"], + /** Хэш мета-данных */ + meta_hash: string, + /** Вектор подписей */ + signatures: Array, + /** Версия стандарта документа */ + version: string +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at: string, + /** Имя генератора, использованного для создания документа */ + generator: string, + /** Язык документа */ + lang: string, + /** Ссылки, связанные с документом */ + links: Array, + /** ID документа в реестре */ + registry_id: number, + /** Часовой пояс, в котором был создан документ */ + timezone: string, + /** Название документа */ + title: string, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version: string }; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string, /** Имя аккаунта кооператива */ coopname: string, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: ModelTypes["SignedDigitalDocumentInput"], + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: ModelTypes["BillingConversionStatementSignedDocumentInput"], /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string }; @@ -20983,7 +21181,7 @@ export type ModelTypes = { program_type: string }; ["CooperativeRegistryItem"]: { - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?: string | undefined | null, /** Имя аккаунта кооператива (coopname) */ coopname: string, @@ -20991,6 +21189,8 @@ export type ModelTypes = { created_at?: string | undefined | null, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data: boolean, + /** Наименование организации кооператива */ + name?: string | undefined | null, /** Статус кооператива в блокчейне: pending | active | blocked */ status: string, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -23033,7 +23233,7 @@ export type ModelTypes = { Требуемые роли: chairman. */ addTrustedAccount: ModelTypes["Branch"], - /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Требует подписанное пайщиком заявление (document2). + /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Принимает подписанное пайщиком заявление 1095.BillingConversionStatement. Требуемые роли: user, member, chairman. */ billingConvert: ModelTypes["BillingResult"], @@ -23493,6 +23693,10 @@ export type ModelTypes = { Требуемые роли: member. */ generateBallotForAnnualGeneralMeetDocument: ModelTypes["GeneratedDocument"], + /** Генерирует заявление 1095.BillingConversionStatement (перед подписью пайщиком) — аналог generateConvertToAxonStatement, канон documents-dto. + +Требуемые роли: member, chairman. */ + generateBillingConversionStatement: ModelTypes["GeneratedDocument"], /** Генерирует заявление на конвертацию паевого взноса в членский взнос Требуемые роли: member, chairman. */ @@ -27618,14 +27822,78 @@ export type GraphQLTypes = { /** Данные голосования по методу Водянова */ voting: GraphQLTypes["CapitalProjectVotingData"], ['...on BaseCapitalProject']: Omit +}; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at?: string | undefined | null, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null, + /** Язык документа */ + lang?: string | undefined | null, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null, + /** Название документа */ + title?: string | undefined | null, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: GraphQLTypes["BillingConversionStatementSignedMetaDocumentInput"], + /** Хэш мета-данных */ + meta_hash: string, + /** Вектор подписей */ + signatures: Array, + /** Версия стандарта документа */ + version: string +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at: string, + /** Имя генератора, использованного для создания документа */ + generator: string, + /** Язык документа */ + lang: string, + /** Ссылки, связанные с документом */ + links: Array, + /** ID документа в реестре */ + registry_id: number, + /** Часовой пояс, в котором был создан документ */ + timezone: string, + /** Название документа */ + title: string, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version: string }; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string, /** Имя аккаунта кооператива */ coopname: string, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: GraphQLTypes["SignedDigitalDocumentInput"], + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: GraphQLTypes["BillingConversionStatementSignedDocumentInput"], /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string }; @@ -29860,7 +30128,7 @@ export type GraphQLTypes = { }; ["CooperativeRegistryItem"]: { __typename: "CooperativeRegistryItem", - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?: string | undefined | null, /** Имя аккаунта кооператива (coopname) */ coopname: string, @@ -29868,6 +30136,8 @@ export type GraphQLTypes = { created_at?: string | undefined | null, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data: boolean, + /** Наименование организации кооператива */ + name?: string | undefined | null, /** Статус кооператива в блокчейне: pending | active | blocked */ status: string, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -32031,7 +32301,7 @@ export type GraphQLTypes = { Требуемые роли: chairman. */ addTrustedAccount: GraphQLTypes["Branch"], - /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Требует подписанное пайщиком заявление (document2). + /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Принимает подписанное пайщиком заявление 1095.BillingConversionStatement. Требуемые роли: user, member, chairman. */ billingConvert: GraphQLTypes["BillingResult"], @@ -32491,6 +32761,10 @@ export type GraphQLTypes = { Требуемые роли: member. */ generateBallotForAnnualGeneralMeetDocument: GraphQLTypes["GeneratedDocument"], + /** Генерирует заявление 1095.BillingConversionStatement (перед подписью пайщиком) — аналог generateConvertToAxonStatement, канон documents-dto. + +Требуемые роли: member, chairman. */ + generateBillingConversionStatement: GraphQLTypes["GeneratedDocument"], /** Генерирует заявление на конвертацию паевого взноса в членский взнос Требуемые роли: member, chairman. */ @@ -36297,6 +36571,9 @@ type ZEUS_VARIABLES = { ["AssetContributionStatementSignedMetaDocumentInput"]: ValueTypes["AssetContributionStatementSignedMetaDocumentInput"]; ["BankAccountDetailsInput"]: ValueTypes["BankAccountDetailsInput"]; ["BankAccountInput"]: ValueTypes["BankAccountInput"]; + ["BillingConversionStatementGenerateDocumentInput"]: ValueTypes["BillingConversionStatementGenerateDocumentInput"]; + ["BillingConversionStatementSignedDocumentInput"]: ValueTypes["BillingConversionStatementSignedDocumentInput"]; + ["BillingConversionStatementSignedMetaDocumentInput"]: ValueTypes["BillingConversionStatementSignedMetaDocumentInput"]; ["BillingConvertInput"]: ValueTypes["BillingConvertInput"]; ["BillingPayInput"]: ValueTypes["BillingPayInput"]; ["BuhotchSignerType"]: ValueTypes["BuhotchSignerType"]; diff --git a/components/desktop/extensions/soviet/install.ts b/components/desktop/extensions/soviet/install.ts index 2e30347ee74..ac0226dc446 100644 --- a/components/desktop/extensions/soviet/install.ts +++ b/components/desktop/extensions/soviet/install.ts @@ -6,6 +6,7 @@ import { PaymentsPage } from 'src/pages/Cooperative/Payments'; import { ListOfMeetsPage } from 'src/pages/Cooperative/ListOfMeets'; import { MeetDetailsPage } from 'src/pages/Cooperative/MeetDetails'; import { UnionPageListOfCooperatives } from 'src/pages/Union/ListOfCooperatives'; +import { UnionPageCooperativeDetail } from 'src/pages/Union/CooperativeDetail'; import type { IWorkspaceConfig } from 'src/shared/lib/types/workspace'; export default async function (): Promise { @@ -94,6 +95,18 @@ export default async function (): Promise { requiresAuth: true, }, }, + { + path: 'union/cooperatives/:detailCoopname', + name: 'union-cooperative-detail', + component: markRaw(UnionPageCooperativeDetail), + meta: { + title: 'Кооператив', + icon: 'fa-solid fa-handshake', + roles: ['chairman', 'member'], + conditions: 'coopname === "voskhod"', + requiresAuth: true, + }, + }, ], }, ], diff --git a/components/desktop/src/entities/Wallet/model/index.ts b/components/desktop/src/entities/Wallet/model/index.ts index a2825076662..d3780656f8a 100644 --- a/components/desktop/src/entities/Wallet/model/index.ts +++ b/components/desktop/src/entities/Wallet/model/index.ts @@ -1,2 +1,3 @@ export * from './types' export * from './stores' +export * from './useCooperativeMainWallet' diff --git a/components/desktop/src/entities/Wallet/model/useCooperativeMainWallet.ts b/components/desktop/src/entities/Wallet/model/useCooperativeMainWallet.ts new file mode 100644 index 00000000000..535ecb276b0 --- /dev/null +++ b/components/desktop/src/entities/Wallet/model/useCooperativeMainWallet.ts @@ -0,0 +1,96 @@ +import { ref, watchEffect, type Ref } from 'vue' +import { Queries, Zeus } from '@coopenomics/sdk' +import { client } from 'src/shared/api/client' + +/** + * Балансы MAIN-программы (split-кошелёк): `available` — паевой взнос + * (w.wal.share), `membership_contribution` — кошелёк членских/инфраструктурных + * взносов (w.wal.member/w.wal.bill). Backend отдаёт оба поля одной записью + * MAIN-программы, отдельных запросов для каждого waltype не требуется. + * + * coopname/username реактивны: смена → перезапрос. + */ +export function useCooperativeMainWallet( + coopname: Ref | (() => string), + username: Ref | (() => string), +) { + const loading = ref(false) + // initialLoading — true ТОЛЬКО до первого успешного ответа. UI должен + // ориентироваться на него (а не на loading), иначе при тихих рефрешах + // (закрытие диалога конвертации, реактивная смена coopname в две фазы) + // плашка моргает «загрузка → значение → загрузка → значение». + const initialLoading = ref(true) + const error = ref('') + const available = ref('0') + const membership = ref('0') + const symbol = ref('') + + const getCoopname = () => + typeof coopname === 'function' ? coopname() : coopname.value + const getUsername = () => + typeof username === 'function' ? username() : username.value + + const splitAsset = (asset?: string | null) => { + if (!asset) return { amount: '0', symbol: '' } + const [amount, sym = ''] = String(asset).split(' ') + return { amount: amount || '0', symbol: sym } + } + + let inFlight = 0 + let lastKey = '' + + const refresh = async () => { + const c = getCoopname() + const u = getUsername() + if (!c || !u) return + // Дедуп параллельных вызовов: если уже летит запрос на тот же ключ — пропустить. + const key = `${c}/${u}` + if (inFlight > 0 && lastKey === key) return + lastKey = key + inFlight++ + loading.value = true + error.value = '' + try { + const { [Queries.Wallet.GetProgramWallet.name]: wallet } = await client.Query( + Queries.Wallet.GetProgramWallet.query, + { + variables: { + filter: { + coopname: c, + username: u, + program_type: Zeus.ProgramType.MAIN, + }, + }, + }, + ) + const av = splitAsset(wallet?.available) + const mb = splitAsset(wallet?.membership_contribution) + available.value = av.amount + membership.value = mb.amount + symbol.value = av.symbol || mb.symbol + } catch (e: any) { + // У пайщика может ещё не быть MAIN-кошелька (новый coop) — + // показываем нули, а не ошибку. + const msg = e?.message ?? String(e) + if (/not found|null/i.test(msg)) { + available.value = '0' + membership.value = '0' + symbol.value = '' + } else { + error.value = msg + } + } finally { + inFlight = Math.max(0, inFlight - 1) + loading.value = false + initialLoading.value = false + } + } + + watchEffect(() => { + void getCoopname() + void getUsername() + void refresh() + }) + + return { available, membership, symbol, loading, initialLoading, error, refresh } +} diff --git a/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue b/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue index 4609021cb01..e2c26954dc9 100644 --- a/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue +++ b/components/desktop/src/features/Billing/ConvertToBilling/ui/ConvertToBillingDialog.vue @@ -1,54 +1,65 @@ diff --git a/components/desktop/src/features/Union/CooperativeDataForm/ui/index.ts b/components/desktop/src/features/Union/CooperativeDataForm/ui/index.ts deleted file mode 100644 index d4819bb0252..00000000000 --- a/components/desktop/src/features/Union/CooperativeDataForm/ui/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as CooperativeDataForm } from './CooperativeDataForm.vue' diff --git a/components/desktop/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue b/components/desktop/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue index 732814fe93e..2e51c450490 100644 --- a/components/desktop/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue +++ b/components/desktop/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue @@ -140,44 +140,50 @@ const init = async () => { connectionAgreement.setHasMatrixAccount(accountStatus.hasAccount); } + // Подтягиваем on-chain запись кооператива — её наличие означает, что + // соглашение о подключении уже подписано (regcoop проходит только после + // signagree). Используем как маркёр прохождения шагов 0–4. + try { + await connectionAgreement.reloadCooperative(); + } catch { + // coop ещё не зарегистрирован — это валидное состояние, не падаем + } + const instance = connectionAgreement.currentInstance; - const hasInstanceError = connectionAgreement.currentInstanceError; + const coop = connectionAgreement.coop; - // Определяем шаг на основе текущего прогресса установки (при каждом заходе) - - // Сначала проверяем, была ли установка уже завершена (даже при ошибке загрузки) + // Сначала проверяем, была ли установка уже завершена const isAlreadyCompleted = instance?.progress === 100 && instance?.status === Zeus.InstanceStatus.ACTIVE; if (isAlreadyCompleted) { console.log('✅ Установка уже завершена ранее, показываем дашборд'); - // Не меняем шаг, оставляем текущий (или устанавливаем специальный шаг для завершенной установки) isLoading.value = false; return; } - // Определяем шаг на основе текущего состояния + // Восстанавливаем фактический шаг по состоянию on-chain + provider. + // Идея: каждый шаг имеет хорошо различимый внешний маркёр; при перезагрузке + // не должно требоваться localStorage. let targetStep: number; - if (hasInstanceError) { - // Если есть ошибка загрузки инстанса, определяем шаг на основе членства в союзе - targetStep = system.info.is_unioned ? 0 : 1; - } else if (instance && typeof instance.progress === 'number' && instance.progress > 0) { - // Если установка уже идет (прогресс > 0), переходим к шагу установки - targetStep = 6; - } else { - // Если инстанса нет ИЛИ его прогресс = 0, определяем шаг на основе членства в союзе - if (system.info.is_unioned) { - // Если кооператив не является членом союза, начинаем с нулевого шага - targetStep = 0; + if (coop) { + // Соглашение точно подписано (coop появился в registrator.coops). + if (instance && typeof instance.progress === 'number' && instance.progress > 0) { + targetStep = 7; // установка идёт + } else if (instance?.blockchain_status === 'active') { + targetStep = 7; // союз подтвердил, провайдер вот-вот стартует + } else if (instance?.is_delegated) { + targetStep = 6; // домен делегирован, ждём подтверждения союза } else { - // Если кооператив уже член союза, начинаем с первого шага - targetStep = 1; + targetStep = 5; // DNS-шаг: ждём делегирования или провайдер ещё не подхватил coop } + } else if (system.info.is_unioned) { + targetStep = 0; // нужна регистрация в мессенджере союза + } else { + targetStep = 1; // онбординг от выбора тарифа } - // Устанавливаем определенный шаг connectionAgreement.setCurrentStep(targetStep); - // Скрываем лоадер после загрузки данных isLoading.value = false; }; @@ -203,27 +209,24 @@ watch( status: instance.status, }); - // Логика автоматических переходов (только для шагов 4, 5, 6) - // Шаги 0, 1, 2, 3 не имеют автоматических переходов - if (currentStep === 4) { - // Шаг 4: Проверка домена + // Автопереходы только для шагов 5 (dns), 6 (approval), 7 (installation). + // Шаги 0..4 (union/intro/domain/financial/agreement) — пользовательский ввод. + if (currentStep === 5) { + // Шаг 5: Проверка делегирования домена. if (instance.is_valid && instance.is_delegated) { - // Домен валиден и делегирован if (instance.blockchain_status === 'active') { - // Можно переходить сразу к установке - console.log('✅ Домен готов и blockchain_status активен → переход к шагу 6'); - connectionAgreement.setCurrentStep(6); + console.log('✅ Домен готов и blockchain_status активен → переход к шагу 7 (installation)'); + connectionAgreement.setCurrentStep(7); } else { - // Ожидаем подтверждения от союза - console.log('⏳ Домен готов, но ожидаем подтверждения → переход к шагу 5'); - connectionAgreement.setCurrentStep(5); + console.log('⏳ Домен готов, ждём подтверждения союза → переход к шагу 6 (approval)'); + connectionAgreement.setCurrentStep(6); } } - } else if (currentStep === 5) { - // Шаг 5: Ожидание подтверждения от союза + } else if (currentStep === 6) { + // Шаг 6: Ожидание подтверждения от союза. if (instance.blockchain_status === 'active') { - console.log('✅ Подтверждение получено → переход к шагу 6'); - connectionAgreement.setCurrentStep(6); + console.log('✅ Подтверждение получено → переход к шагу 7 (installation)'); + connectionAgreement.setCurrentStep(7); } } // Редирект на страницу завершения теперь делает только InstallationStep.vue diff --git a/components/desktop/src/pages/Union/CooperativeDetail/index.ts b/components/desktop/src/pages/Union/CooperativeDetail/index.ts new file mode 100644 index 00000000000..ed584959d76 --- /dev/null +++ b/components/desktop/src/pages/Union/CooperativeDetail/index.ts @@ -0,0 +1 @@ +export * from './ui' diff --git a/components/desktop/src/pages/Union/CooperativeDetail/ui/UnionPageCooperativeDetail.vue b/components/desktop/src/pages/Union/CooperativeDetail/ui/UnionPageCooperativeDetail.vue new file mode 100644 index 00000000000..f43085c67f1 --- /dev/null +++ b/components/desktop/src/pages/Union/CooperativeDetail/ui/UnionPageCooperativeDetail.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/components/desktop/src/pages/Union/CooperativeDetail/ui/index.ts b/components/desktop/src/pages/Union/CooperativeDetail/ui/index.ts new file mode 100644 index 00000000000..92030e91f18 --- /dev/null +++ b/components/desktop/src/pages/Union/CooperativeDetail/ui/index.ts @@ -0,0 +1 @@ +export { default as UnionPageCooperativeDetail } from './UnionPageCooperativeDetail.vue' diff --git a/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue b/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue index ce6a1679dd2..151ecf2d00a 100644 --- a/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue +++ b/components/desktop/src/pages/Union/ListOfCooperatives/ui/UnionPageListOfCooperatives.vue @@ -1,243 +1,274 @@ - template(#body="props") - q-tr(:key="`m_${props.row.coopname}`" :props="props") - q-td(auto-width) - q-btn(size="sm" color="primary" round dense :icon="props.expand ? 'remove' : 'add'" @click="props.expand = !props.expand") - q-td {{ props.row.coopname }} - q-td {{ props.row.announce }} + - const block = async (coopname: string) => { - const {blockCooperative} = useBlockCooperative() - - try { - await blockCooperative(coopname) - await load() - SuccessAlert('Кооператив заблокирован') - } catch(e: any) { - FailAlert(e) - } - } - - const columns = [ - { name: 'coopname', align: 'left', label: 'Аккаунт', field: 'coopname', sortable: true }, - { name: 'announce', align: 'left', label: 'Сайт', field: 'announce', sortable: false }, - { name: 'status', align: 'left', label: 'Статус в реестре', field: 'status', sortable: true }, - { name: 'hosting', align: 'left', label: 'Хостинг', field: 'hosting', sortable: false }, - { name: 'cost', align: 'left', label: 'Стоимость', field: 'cost', sortable: false }, - { - name: 'created_at', - align: 'left', - label: 'Дата заявки', - field: 'created_at', - sortable: true, - }, - { name: 'actions', align: 'center', label: '', field: 'actions', sortable: false }, - ] as any - - const expanded = ref([]) - const tableRef = ref(null) - const pagination = ref({ rowsPerPage: 0 }) - - - + diff --git a/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue b/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue index 2b89b0b1fa7..cfc88494c58 100644 --- a/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue +++ b/components/desktop/src/pages/User/WalletPage/ui/WalletPage.vue @@ -1,7 +1,6 @@ diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/AgreementStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/AgreementStep.vue index d71b9bb1369..6668093dc58 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/AgreementStep.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/AgreementStep.vue @@ -1,46 +1,31 @@ + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/ApprovalWaitingStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/ApprovalWaitingStep.vue index 740a3cbf03b..71d46755bf3 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/ApprovalWaitingStep.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/ApprovalWaitingStep.vue @@ -1,70 +1,17 @@ - - + + - diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainStep.vue new file mode 100644 index 00000000000..e8a38e94458 --- /dev/null +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainStep.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainValidationStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainValidationStep.vue index 40a92c1ee4d..452556c9f10 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainValidationStep.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/DomainValidationStep.vue @@ -1,92 +1,24 @@ - - + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FinancialParamsStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FinancialParamsStep.vue new file mode 100644 index 00000000000..9c69fc10d2d --- /dev/null +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FinancialParamsStep.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FormStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FormStep.vue deleted file mode 100644 index 2118c579af0..00000000000 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/FormStep.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - - - diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/InstallationStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/InstallationStep.vue index 2169d179a0f..b2ecffde748 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/InstallationStep.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/InstallationStep.vue @@ -1,368 +1,97 @@ - - + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/IntroStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/IntroStep.vue index bb4ace889e8..9be2c95d0de 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/IntroStep.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/IntroStep.vue @@ -1,23 +1,20 @@ + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/UnionMembershipStep.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/UnionMembershipStep.vue index 43abffa4640..855dd6f8d0c 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/UnionMembershipStep.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/UnionMembershipStep.vue @@ -1,436 +1,127 @@ - - + + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/index.ts b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/index.ts index f3a28a45cec..2e2cab160a9 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/index.ts +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Steps/index.ts @@ -1,11 +1,12 @@ -// Этот файл больше не используется -// Компоненты импортируются напрямую в ConnectionAgreementStepper.vue -// Оставлен для обратной совместимости, если нужен где-то ещё +// Реестр шагов ConnectionAgreement (не используется напрямую — шаги +// импортируются по имени в ConnectionAgreementStepper.vue). Оставлен как +// барель-экспорт на случай переиспользования отдельных шагов. export { default as UnionMembershipStep } from './UnionMembershipStep.vue' export { default as IntroStep } from './IntroStep.vue' +export { default as DomainStep } from './DomainStep.vue' +export { default as FinancialParamsStep } from './FinancialParamsStep.vue' export { default as AgreementStep } from './AgreementStep.vue' -export { default as FormStep } from './FormStep.vue' export { default as DomainValidationStep } from './DomainValidationStep.vue' export { default as ApprovalWaitingStep } from './ApprovalWaitingStep.vue' export { default as InstallationStep } from './InstallationStep.vue' diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffCard.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffCard.vue index 1516b61573c..aabb4a41c2b 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffCard.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffCard.vue @@ -6,6 +6,7 @@ const props = defineProps<{ tariff: ITariff selected?: boolean disabled?: boolean + groupName?: string }>() const emits = defineEmits<{ @@ -13,256 +14,166 @@ const emits = defineEmits<{ deselect: [tariffId: string] }>() -const isSelected = computed(() => props.selected) -const isDisabled = computed(() => props.disabled) +const isSelected = computed(() => !!props.selected) +const isDisabled = computed(() => !!props.disabled) +const isFree = computed(() => props.tariff.price === 'Бесплатно') -const cardClasses = computed(() => { - const classes = ['tariff-card', 'cursor-pointer', 'transition-all', 'duration-200'] +const onChange = () => { + if (isDisabled.value) return + emits('select', props.tariff.id) +} - if (isSelected.value) { - classes.push('tariff-selected') - } - - if (isDisabled.value) { - classes.push('tariff-disabled') - } - - return classes.join(' ') -}) - -const handleSelect = () => { - if (!isDisabled.value) { - // Если тариф уже выбран, снимаем выбор, иначе выбираем - if (isSelected.value) { - emits('deselect', props.tariff.id) - } else { - emits('select', props.tariff.id) - } - } +const onClick = () => { + if (isDisabled.value) return + if (isSelected.value) emits('deselect', props.tariff.id) } diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffSelector.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffSelector.vue index 86ba91a8976..a7430bfca50 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffSelector.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/Tariffs/TariffSelector.vue @@ -1,27 +1,20 @@ +.tariff-selector + .tariff-selector__list + TariffCard( + v-for="tariff in availableTariffs" + :key="tariff.id" + :tariff="tariff" + :selected="selectedTariffId === tariff.id" + :disabled="disabled" + group-name="connection-tariff" + @select="handleTariffSelect" + @deselect="handleTariffDeselect" + ) + diff --git a/components/desktop/src/widgets/ConnectionAgreementStepper/ui/ConnectionAgreementStepper.vue b/components/desktop/src/widgets/ConnectionAgreementStepper/ui/ConnectionAgreementStepper.vue index e2511ce1588..fbb35b0c41c 100644 --- a/components/desktop/src/widgets/ConnectionAgreementStepper/ui/ConnectionAgreementStepper.vue +++ b/components/desktop/src/widgets/ConnectionAgreementStepper/ui/ConnectionAgreementStepper.vue @@ -1,70 +1,12 @@ - - - + + + + diff --git a/components/desktop/src/widgets/ConnectionDashboard/ui/AxonWallet.vue b/components/desktop/src/widgets/ConnectionDashboard/ui/AxonWallet.vue index ef1e0b5edbb..31f5e2157b8 100644 --- a/components/desktop/src/widgets/ConnectionDashboard/ui/AxonWallet.vue +++ b/components/desktop/src/widgets/ConnectionDashboard/ui/AxonWallet.vue @@ -1,87 +1,78 @@ - diff --git a/components/desktop/src/widgets/ConnectionDashboard/ui/ConnectionDashboard.vue b/components/desktop/src/widgets/ConnectionDashboard/ui/ConnectionDashboard.vue index e10d4f3b581..2aae689d370 100644 --- a/components/desktop/src/widgets/ConnectionDashboard/ui/ConnectionDashboard.vue +++ b/components/desktop/src/widgets/ConnectionDashboard/ui/ConnectionDashboard.vue @@ -1,24 +1,17 @@ - diff --git a/components/desktop/src/widgets/ConnectionDashboard/ui/DomainCard.vue b/components/desktop/src/widgets/ConnectionDashboard/ui/DomainCard.vue index 8ac36745fc7..7570082c6df 100644 --- a/components/desktop/src/widgets/ConnectionDashboard/ui/DomainCard.vue +++ b/components/desktop/src/widgets/ConnectionDashboard/ui/DomainCard.vue @@ -1,95 +1,61 @@ - diff --git a/components/desktop/src/widgets/ConnectionDashboard/ui/MembershipWallet.vue b/components/desktop/src/widgets/ConnectionDashboard/ui/MembershipWallet.vue new file mode 100644 index 00000000000..c68ae6b47ba --- /dev/null +++ b/components/desktop/src/widgets/ConnectionDashboard/ui/MembershipWallet.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/components/desktop/src/widgets/ConnectionDashboard/ui/SubscriptionsCard.vue b/components/desktop/src/widgets/ConnectionDashboard/ui/SubscriptionsCard.vue index c39133a1ffb..82ae54d1e79 100644 --- a/components/desktop/src/widgets/ConnectionDashboard/ui/SubscriptionsCard.vue +++ b/components/desktop/src/widgets/ConnectionDashboard/ui/SubscriptionsCard.vue @@ -1,97 +1,68 @@ - diff --git a/components/desktop/src/widgets/ConnectionDashboard/ui/index.ts b/components/desktop/src/widgets/ConnectionDashboard/ui/index.ts index e57281f39a0..ceab783a7bb 100644 --- a/components/desktop/src/widgets/ConnectionDashboard/ui/index.ts +++ b/components/desktop/src/widgets/ConnectionDashboard/ui/index.ts @@ -1,5 +1,6 @@ export { default as ConnectionDashboard } from './ConnectionDashboard.vue' export { default as AxonWallet } from './AxonWallet.vue' +export { default as MembershipWallet } from './MembershipWallet.vue' export { default as DomainCard } from './DomainCard.vue' export { default as SubscriptionsCard } from './SubscriptionsCard.vue' diff --git a/components/sdk/src/selectors/system/cooperativeRegistryItemSelector.ts b/components/sdk/src/selectors/system/cooperativeRegistryItemSelector.ts index d330325dbf4..85f53427237 100644 --- a/components/sdk/src/selectors/system/cooperativeRegistryItemSelector.ts +++ b/components/sdk/src/selectors/system/cooperativeRegistryItemSelector.ts @@ -4,6 +4,7 @@ import { rawProviderSubscriptionSelector } from './providerSubscriptionSelector' export const rawCooperativeRegistryItemSelector = { coopname: true, + name: true, announce: true, status: true, created_at: true, diff --git a/components/sdk/src/zeus/const.ts b/components/sdk/src/zeus/const.ts index 0280e229794..f78b36cabeb 100644 --- a/components/sdk/src/zeus/const.ts +++ b/components/sdk/src/zeus/const.ts @@ -127,9 +127,19 @@ export const AllTypesProps: Record = { }, BankAccountInput:{ details:"BankAccountDetailsInput" + }, + BillingConversionStatementGenerateDocumentInput:{ + + }, + BillingConversionStatementSignedDocumentInput:{ + meta:"BillingConversionStatementSignedMetaDocumentInput", + signatures:"SignatureInfoInput" + }, + BillingConversionStatementSignedMetaDocumentInput:{ + }, BillingConvertInput:{ - document:"SignedDigitalDocumentInput" + document:"BillingConversionStatementSignedDocumentInput" }, BillingPayInput:{ @@ -1039,6 +1049,10 @@ export const AllTypesProps: Record = { data:"AnnualGeneralMeetingVotingBallotGenerateDocumentInput", options:"GenerateDocumentOptionsInput" }, + generateBillingConversionStatement:{ + data:"BillingConversionStatementGenerateDocumentInput", + options:"GenerateDocumentOptionsInput" + }, generateConvertToAxonStatement:{ data:"ConvertToAxonStatementGenerateDocumentInput", options:"GenerateDocumentOptionsInput" @@ -3056,6 +3070,7 @@ export const ReturnTypes: Record = { coopname:"String", created_at:"String", has_provider_data:"Boolean", + name:"String", status:"String", subscriptions:"ProviderSubscription" }, @@ -3670,6 +3685,7 @@ export const ReturnTypes: Record = { generateAssetContributionDecision:"GeneratedDocument", generateAssetContributionStatement:"GeneratedDocument", generateBallotForAnnualGeneralMeetDocument:"GeneratedDocument", + generateBillingConversionStatement:"GeneratedDocument", generateConvertToAxonStatement:"GeneratedDocument", generateDocument:"GeneratedDocument", generateFreeDecision:"GeneratedDocument", diff --git a/components/sdk/src/zeus/index.ts b/components/sdk/src/zeus/index.ts index 5ce0271a0c3..2d4ca7a63e6 100644 --- a/components/sdk/src/zeus/index.ts +++ b/components/sdk/src/zeus/index.ts @@ -2079,13 +2079,77 @@ export type ValueTypes = { __typename?: boolean | `@${string}`, ['...on BaseCapitalProject']?: Omit }>; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null | Variable, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string | Variable, + /** Название кооператива, связанное с документом */ + coopname: string | Variable, + /** Дата и время создания документа */ + created_at?: string | undefined | null | Variable, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null | Variable, + /** Язык документа */ + lang?: string | undefined | null | Variable, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null | Variable, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null | Variable, + /** Название документа */ + title?: string | undefined | null | Variable, + /** Имя пользователя, создавшего документ */ + username: string | Variable, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null | Variable +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string | Variable, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string | Variable, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: ValueTypes["BillingConversionStatementSignedMetaDocumentInput"] | Variable, + /** Хэш мета-данных */ + meta_hash: string | Variable, + /** Вектор подписей */ + signatures: Array | Variable, + /** Версия стандарта документа */ + version: string | Variable +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number | Variable, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string | Variable, + /** Название кооператива, связанное с документом */ + coopname: string | Variable, + /** Дата и время создания документа */ + created_at: string | Variable, + /** Имя генератора, использованного для создания документа */ + generator: string | Variable, + /** Язык документа */ + lang: string | Variable, + /** Ссылки, связанные с документом */ + links: Array | Variable, + /** ID документа в реестре */ + registry_id: number | Variable, + /** Часовой пояс, в котором был создан документ */ + timezone: string | Variable, + /** Название документа */ + title: string | Variable, + /** Имя пользователя, создавшего документ */ + username: string | Variable, + /** Версия генератора, использованного для создания документа */ + version: string | Variable +}; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string | Variable, /** Имя аккаунта кооператива */ coopname: string | Variable, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: ValueTypes["SignedDigitalDocumentInput"] | Variable, + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: ValueTypes["BillingConversionStatementSignedDocumentInput"] | Variable, /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string | Variable }; @@ -4319,7 +4383,7 @@ export type ValueTypes = { ['...on CooperativeProgram']?: Omit }>; ["CooperativeRegistryItem"]: AliasType<{ - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?:boolean | `@${string}`, /** Имя аккаунта кооператива (coopname) */ coopname?:boolean | `@${string}`, @@ -4327,6 +4391,8 @@ export type ValueTypes = { created_at?:boolean | `@${string}`, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data?:boolean | `@${string}`, + /** Наименование организации кооператива */ + name?:boolean | `@${string}`, /** Статус кооператива в блокчейне: pending | active | blocked */ status?:boolean | `@${string}`, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -6606,6 +6672,7 @@ generateAssetContributionAct?: [{ data: ValueTypes["AssetContributionActGenerate generateAssetContributionDecision?: [{ data: ValueTypes["AssetContributionDecisionGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateAssetContributionStatement?: [{ data: ValueTypes["AssetContributionStatementGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateBallotForAnnualGeneralMeetDocument?: [{ data: ValueTypes["AnnualGeneralMeetingVotingBallotGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], +generateBillingConversionStatement?: [{ data: ValueTypes["BillingConversionStatementGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateConvertToAxonStatement?: [{ data: ValueTypes["ConvertToAxonStatementGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], generateDocument?: [{ input: ValueTypes["GenerateAnyDocumentInput"] | Variable},ValueTypes["GeneratedDocument"]], generateFreeDecision?: [{ data: ValueTypes["FreeDecisionGenerateDocumentInput"] | Variable, options?: ValueTypes["GenerateDocumentOptionsInput"] | undefined | null | Variable},ValueTypes["GeneratedDocument"]], @@ -10597,13 +10664,77 @@ export type ResolverInputTypes = { voting?:ResolverInputTypes["CapitalProjectVotingData"], __typename?: boolean | `@${string}` }>; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at?: string | undefined | null, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null, + /** Язык документа */ + lang?: string | undefined | null, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null, + /** Название документа */ + title?: string | undefined | null, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: ResolverInputTypes["BillingConversionStatementSignedMetaDocumentInput"], + /** Хэш мета-данных */ + meta_hash: string, + /** Вектор подписей */ + signatures: Array, + /** Версия стандарта документа */ + version: string +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at: string, + /** Имя генератора, использованного для создания документа */ + generator: string, + /** Язык документа */ + lang: string, + /** Ссылки, связанные с документом */ + links: Array, + /** ID документа в реестре */ + registry_id: number, + /** Часовой пояс, в котором был создан документ */ + timezone: string, + /** Название документа */ + title: string, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version: string +}; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string, /** Имя аккаунта кооператива */ coopname: string, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: ResolverInputTypes["SignedDigitalDocumentInput"], + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: ResolverInputTypes["BillingConversionStatementSignedDocumentInput"], /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string }; @@ -12772,7 +12903,7 @@ export type ResolverInputTypes = { __typename?: boolean | `@${string}` }>; ["CooperativeRegistryItem"]: AliasType<{ - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?:boolean | `@${string}`, /** Имя аккаунта кооператива (coopname) */ coopname?:boolean | `@${string}`, @@ -12780,6 +12911,8 @@ export type ResolverInputTypes = { created_at?:boolean | `@${string}`, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data?:boolean | `@${string}`, + /** Наименование организации кооператива */ + name?:boolean | `@${string}`, /** Статус кооператива в блокчейне: pending | active | blocked */ status?:boolean | `@${string}`, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -15005,6 +15138,7 @@ generateAssetContributionAct?: [{ data: ResolverInputTypes["AssetContributionAct generateAssetContributionDecision?: [{ data: ResolverInputTypes["AssetContributionDecisionGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateAssetContributionStatement?: [{ data: ResolverInputTypes["AssetContributionStatementGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateBallotForAnnualGeneralMeetDocument?: [{ data: ResolverInputTypes["AnnualGeneralMeetingVotingBallotGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], +generateBillingConversionStatement?: [{ data: ResolverInputTypes["BillingConversionStatementGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateConvertToAxonStatement?: [{ data: ResolverInputTypes["ConvertToAxonStatementGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], generateDocument?: [{ input: ResolverInputTypes["GenerateAnyDocumentInput"]},ResolverInputTypes["GeneratedDocument"]], generateFreeDecision?: [{ data: ResolverInputTypes["FreeDecisionGenerateDocumentInput"], options?: ResolverInputTypes["GenerateDocumentOptionsInput"] | undefined | null},ResolverInputTypes["GeneratedDocument"]], @@ -18877,14 +19011,78 @@ export type ModelTypes = { title: string, /** Данные голосования по методу Водянова */ voting: ModelTypes["CapitalProjectVotingData"] +}; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at?: string | undefined | null, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null, + /** Язык документа */ + lang?: string | undefined | null, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null, + /** Название документа */ + title?: string | undefined | null, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: ModelTypes["BillingConversionStatementSignedMetaDocumentInput"], + /** Хэш мета-данных */ + meta_hash: string, + /** Вектор подписей */ + signatures: Array, + /** Версия стандарта документа */ + version: string +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at: string, + /** Имя генератора, использованного для создания документа */ + generator: string, + /** Язык документа */ + lang: string, + /** Ссылки, связанные с документом */ + links: Array, + /** ID документа в реестре */ + registry_id: number, + /** Часовой пояс, в котором был создан документ */ + timezone: string, + /** Название документа */ + title: string, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version: string }; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string, /** Имя аккаунта кооператива */ coopname: string, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: ModelTypes["SignedDigitalDocumentInput"], + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: ModelTypes["BillingConversionStatementSignedDocumentInput"], /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string }; @@ -20983,7 +21181,7 @@ export type ModelTypes = { program_type: string }; ["CooperativeRegistryItem"]: { - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?: string | undefined | null, /** Имя аккаунта кооператива (coopname) */ coopname: string, @@ -20991,6 +21189,8 @@ export type ModelTypes = { created_at?: string | undefined | null, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data: boolean, + /** Наименование организации кооператива */ + name?: string | undefined | null, /** Статус кооператива в блокчейне: pending | active | blocked */ status: string, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -23033,7 +23233,7 @@ export type ModelTypes = { Требуемые роли: chairman. */ addTrustedAccount: ModelTypes["Branch"], - /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Требует подписанное пайщиком заявление (document2). + /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Принимает подписанное пайщиком заявление 1095.BillingConversionStatement. Требуемые роли: user, member, chairman. */ billingConvert: ModelTypes["BillingResult"], @@ -23493,6 +23693,10 @@ export type ModelTypes = { Требуемые роли: member. */ generateBallotForAnnualGeneralMeetDocument: ModelTypes["GeneratedDocument"], + /** Генерирует заявление 1095.BillingConversionStatement (перед подписью пайщиком) — аналог generateConvertToAxonStatement, канон documents-dto. + +Требуемые роли: member, chairman. */ + generateBillingConversionStatement: ModelTypes["GeneratedDocument"], /** Генерирует заявление на конвертацию паевого взноса в членский взнос Требуемые роли: member, chairman. */ @@ -27618,14 +27822,78 @@ export type GraphQLTypes = { /** Данные голосования по методу Водянова */ voting: GraphQLTypes["CapitalProjectVotingData"], ['...on BaseCapitalProject']: Omit +}; + ["BillingConversionStatementGenerateDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num?: number | undefined | null, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at?: string | undefined | null, + /** Имя генератора, использованного для создания документа */ + generator?: string | undefined | null, + /** Язык документа */ + lang?: string | undefined | null, + /** Ссылки, связанные с документом */ + links?: Array | undefined | null, + /** Часовой пояс, в котором был создан документ */ + timezone?: string | undefined | null, + /** Название документа */ + title?: string | undefined | null, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version?: string | undefined | null +}; + ["BillingConversionStatementSignedDocumentInput"]: { + /** Хэш содержимого документа */ + doc_hash: string, + /** Общий хэш (doc_hash + meta_hash) */ + hash: string, + /** Метаинформация заявления на конвертацию паевого в биллинг-кошелёк */ + meta: GraphQLTypes["BillingConversionStatementSignedMetaDocumentInput"], + /** Хэш мета-данных */ + meta_hash: string, + /** Вектор подписей */ + signatures: Array, + /** Версия стандарта документа */ + version: string +}; + ["BillingConversionStatementSignedMetaDocumentInput"]: { + /** Номер блока, на котором был создан документ */ + block_num: number, + /** Сумма к конвертации паевого в членский на биллинг-кошелёк */ + convert_amount: string, + /** Название кооператива, связанное с документом */ + coopname: string, + /** Дата и время создания документа */ + created_at: string, + /** Имя генератора, использованного для создания документа */ + generator: string, + /** Язык документа */ + lang: string, + /** Ссылки, связанные с документом */ + links: Array, + /** ID документа в реестре */ + registry_id: number, + /** Часовой пояс, в котором был создан документ */ + timezone: string, + /** Название документа */ + title: string, + /** Имя пользователя, создавшего документ */ + username: string, + /** Версия генератора, использованного для создания документа */ + version: string }; ["BillingConvertInput"]: { /** Сумма с символом, например "1500.0000 RUB" */ amount: string, /** Имя аккаунта кооператива */ coopname: string, - /** Подписанное пайщиком заявление на конвертацию (document2) */ - document: GraphQLTypes["SignedDigitalDocumentInput"], + /** Подписанное пайщиком заявление 1095.BillingConversionStatement (document2 с типизированной meta: convert_amount). */ + document: GraphQLTypes["BillingConversionStatementSignedDocumentInput"], /** Имя аккаунта пайщика — владельца биллинг-кошелька */ username: string }; @@ -29860,7 +30128,7 @@ export type GraphQLTypes = { }; ["CooperativeRegistryItem"]: { __typename: "CooperativeRegistryItem", - /** Анонсированный домен/сайт кооператива (registrator.coops.announce) */ + /** Анонсированный домен/сайт кооператива */ announce?: string | undefined | null, /** Имя аккаунта кооператива (coopname) */ coopname: string, @@ -29868,6 +30136,8 @@ export type GraphQLTypes = { created_at?: string | undefined | null, /** Есть ли у кооператива данные провайдера (хотя бы одна подписка) */ has_provider_data: boolean, + /** Наименование организации кооператива */ + name?: string | undefined | null, /** Статус кооператива в блокчейне: pending | active | blocked */ status: string, /** Подписки кооператива у провайдера (с инстансом и биллингом) */ @@ -32031,7 +32301,7 @@ export type GraphQLTypes = { Требуемые роли: chairman. */ addTrustedAccount: GraphQLTypes["Branch"], - /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Требует подписанное пайщиком заявление (document2). + /** Конвертация паевого взноса пайщика в членский на биллинг-кошелёк (operation o.bil.fund). Принимает подписанное пайщиком заявление 1095.BillingConversionStatement. Требуемые роли: user, member, chairman. */ billingConvert: GraphQLTypes["BillingResult"], @@ -32491,6 +32761,10 @@ export type GraphQLTypes = { Требуемые роли: member. */ generateBallotForAnnualGeneralMeetDocument: GraphQLTypes["GeneratedDocument"], + /** Генерирует заявление 1095.BillingConversionStatement (перед подписью пайщиком) — аналог generateConvertToAxonStatement, канон documents-dto. + +Требуемые роли: member, chairman. */ + generateBillingConversionStatement: GraphQLTypes["GeneratedDocument"], /** Генерирует заявление на конвертацию паевого взноса в членский взнос Требуемые роли: member, chairman. */ @@ -36297,6 +36571,9 @@ type ZEUS_VARIABLES = { ["AssetContributionStatementSignedMetaDocumentInput"]: ValueTypes["AssetContributionStatementSignedMetaDocumentInput"]; ["BankAccountDetailsInput"]: ValueTypes["BankAccountDetailsInput"]; ["BankAccountInput"]: ValueTypes["BankAccountInput"]; + ["BillingConversionStatementGenerateDocumentInput"]: ValueTypes["BillingConversionStatementGenerateDocumentInput"]; + ["BillingConversionStatementSignedDocumentInput"]: ValueTypes["BillingConversionStatementSignedDocumentInput"]; + ["BillingConversionStatementSignedMetaDocumentInput"]: ValueTypes["BillingConversionStatementSignedMetaDocumentInput"]; ["BillingConvertInput"]: ValueTypes["BillingConvertInput"]; ["BillingPayInput"]: ValueTypes["BillingPayInput"]; ["BuhotchSignerType"]: ValueTypes["BuhotchSignerType"]; -- 2.52.0 From e69ba7090972f55789ddf2beb01837adf491417c Mon Sep 17 00:00:00 2001 From: coopops Date: Sat, 30 May 2026 07:22:36 +0000 Subject: [PATCH 15/15] fix gitgnore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 4053ce389f1..93526847de4 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ components/contracts/cpp/ledger2/scripts/out/ .env.testnet .pnpm-store +schema.gql +.claude -- 2.52.0