fix(capital): restore CPP templates from RTF sources and improve parameter constructor
Typecheck / desktop (pull_request) Failing after 18m32s
Typecheck / controller (pull_request) Failing after 6m52s

Align cooptypes/factory templates 994–1000 with original document wording,
correct doc_data substitution points, update voskhod backfill values, and
add onboarding UI with descriptive field labels and doc data hash saving.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alex Ant
2026-07-14 14:27:27 +03:00
parent 45feef2676
commit 33f1ac1a15
39 changed files with 744 additions and 644 deletions
@@ -14,17 +14,8 @@ const TARGET_COOPNAME = 'voskhod';
const COLLECTION_NAME = 'doc_private_data';
const capitalProgramPrivateData = {
approval_protocol_number: '1',
approval_protocol_day: '15',
approval_protocol_month: 'января',
approval_protocol_year: '26',
cooperative_name: 'ВОСХОД',
cooperative_short_name: 'ПК',
cooperative_quoted_name: '«ВОСХОД»',
website: 'https://цифровой-кооператив.рф',
chairman_full_name: 'Муравьев Алексей Николаевич',
generator_program_purpose:
'развитию информационной экосистемы взаимодействия физических и юридических лиц, на основе международных кооперативных принципов и законодательства Российской Федерации в отношении потребительских обществ (кооперативов) под названием “Кооперативная Экономика”',
'развитию информационной экосистемы взаимодействия физических и юридических лиц, на основе международных кооперативных принципов и законодательства Российской Федерации в отношении потребительских обществ (кооперативов) под названием “Кооперативная Экономика”, с целью самоорганизации и интеграции в социально-экономическую среду Российской Федерации., на основе международных кооперативных принципов и законодательства Российской Федерации',
eoap_definition:
'информационная экосистема, интегрируемая в социально-экономическую среду Российской Федерации, состоящая из комплекса программных продуктов на базе технологии распределенного реестра, обеспечивающих широкое экономическое и социальное взаимодействие физических и юридических лиц, включая нерезидентов различных юрисдикций и организационно-правовых форм, на основе международных кооперативных принципов и законодательства Российской Федерации в отношении потребительских кооперативов (обществ) под названием “Кооперативная Экономика”',
generator_task_goal:
@@ -38,10 +29,9 @@ const capitalProgramPrivateData = {
blagorost_task_development:
'развитие ЕОАП как центра привлечения и интеграции инновационных цифровых разработок, а также экономических и социальных методов и решений',
return_source_description:
'аппаратно-программная сеть узлов распределенного реестра в формате «СМЭВ+SWIFT», построенная на принципах самоорганизации и самофинансирования деятельности технологической инфраструктуры ЕОАП, обеспечивающей консенсус ее распределенных узлов по формированию базового продукта ЕОАП - полного цикла документооборота по синхронному взаимодействию пайщиков и кооперативов - участников экосистемы ЕОАП - через использование цифровых контрактов, с одновременным выполнением функций нотариата и учета финансовых и юридических событий',
'аппаратно-программная сеть узлов распределенного реестра в формате «СМЭВ+SWIFT», построенная на принципах самоорганизации и самофинансирования деятельности технологической инфраструктуры ЕОАП, обеспечивающей консенсус ее распределенных узлов по формированию базового продукта ЕОАП - полного цикла документооборота по синхронному взаимодействию пайщиков и кооперативов - участников экосистемы ЕАОП - через использование цифровых контрактов, с одновременным выполнением функций нотариата и учета финансовых и юридических событий (подробнее на Сайте)',
return_additional_source:
'взносы пользователей ЕОАП, его отдельных программных продуктов и приложений, переданных Обществу или создаваемых в рамках Общества, которые интегрируются в ЕОАП',
offer_template_number: '______',
};
function stableStringify(value: unknown): string {
@@ -14,6 +14,7 @@ const { spawnSync } = require('child_process');
const controllerRoot = path.resolve(__dirname, '..');
const schemaPath = path.join(controllerRoot, 'schema.gql');
const zeusConfigPath = path.join(controllerRoot, 'graphql-zeus.json');
const sdkSrc = path.resolve(controllerRoot, '..', 'sdk', 'src');
const localZeusDir = path.join(controllerRoot, 'zeus');
const sdkZeusDir = path.join(sdkSrc, 'zeus');
@@ -40,6 +41,12 @@ if (!fs.existsSync(sdkSrc)) {
process.exit(1);
}
// graphql-zeus 7.x: yargs кладёт path в argv.path, а CLIClass читает args._[0].
// Без graphql-zeus.json config-maker уходит в inquirer и «зависает» без TTY.
if (!fs.existsSync(zeusConfigPath)) {
fs.writeFileSync(zeusConfigPath, `${JSON.stringify({ urlOrPath: './schema.gql' }, null, 2)}\n`, 'utf8');
}
let zeusBin;
let zeusIsWin;
try {
@@ -51,6 +58,7 @@ try {
const zeusArgs = ['./schema.gql', '../sdk/src', '--subscriptions', 'graphql-ws'];
const startedAt = Date.now();
console.log('generate-client: graphql-zeus… (530 с без вывода — норма, не прерывайте)');
const result = spawnSync(zeusBin, zeusArgs, {
stdio: 'inherit',
cwd: controllerRoot,
@@ -4,15 +4,11 @@ import type { GetDocumentsInputDTO } from '../dto/get-documents-input.dto';
import type { PaginationResultDomainInterface } from '~/domain/common/interfaces/pagination.interface';
import type { DocumentPackageAggregateDomainInterface } from '~/domain/document/interfaces/document-package-aggregate-domain.interface';
import type { GenerateAnyDocumentInputDTO } from '../dto/generate-any-document-input.dto';
import { GeneratorInfrastructureService } from '~/infrastructure/generator/generator.service';
import { DocumentDomainEntity } from '~/domain/document/entity/document-domain.entity';
@Injectable()
export class DocumentService {
constructor(
private readonly documentInteractor: DocumentInteractor,
private readonly generatorService: GeneratorInfrastructureService
) {}
constructor(private readonly documentInteractor: DocumentInteractor) {}
async getDocumentsAggregate(
data: GetDocumentsInputDTO
@@ -34,7 +30,7 @@ export class DocumentService {
}
async generateAnyDocument(input: GenerateAnyDocumentInputDTO): Promise<DocumentDomainEntity> {
return this.generatorService.generateDocument({
return this.documentInteractor.generateDocument({
data: input.data as any,
options: input.options,
});
@@ -36,6 +36,14 @@ export class CapitalOnboardingStepInputDTO {
decision!: string;
}
@InputType('SaveCapitalProgramDocDataInput')
export class SaveCapitalProgramDocDataInputDTO {
@Field(() => String)
@IsString()
@IsNotEmpty()
doc_data_hash!: string;
}
@ObjectType('CapitalOnboardingState')
export class CapitalOnboardingStateDTO {
@Field(() => Boolean)
@@ -3,7 +3,11 @@ import { UseGuards } from '@nestjs/common';
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';
import { CapitalOnboardingStepInputDTO, CapitalOnboardingStateDTO } from '../dto/onboarding.dto';
import {
CapitalOnboardingStepInputDTO,
CapitalOnboardingStateDTO,
SaveCapitalProgramDocDataInputDTO,
} from '../dto/onboarding.dto';
import { CapitalOnboardingService } from '../services/onboarding.service';
import { CurrentUser } from '~/application/auth/decorators/current-user.decorator';
import type { MonoAccountDomainInterface } from '~/domain/account/interfaces/mono-account-domain.interface';
@@ -34,4 +38,16 @@ export class CapitalOnboardingResolver {
): Promise<CapitalOnboardingStateDTO> {
return this.onboardingService.completeStep(data, currentUser?.username);
}
@Mutation(() => CapitalOnboardingStateDTO, {
name: 'saveCapitalProgramDocDataHash',
description: 'Сохранить hash PrivateData параметров документов ЦПП',
})
@UseGuards(GqlJwtAuthGuard, RolesGuard)
@AuthRoles(['chairman'])
async saveProgramDocDataHash(
@Args('data', { type: () => SaveCapitalProgramDocDataInputDTO }) data: SaveCapitalProgramDocDataInputDTO,
): Promise<CapitalOnboardingStateDTO> {
return this.onboardingService.saveProgramDocDataHash(data.doc_data_hash);
}
}
@@ -170,6 +170,23 @@ export class CapitalOnboardingService {
return this.buildState(plugin.config);
}
public async saveProgramDocDataHash(docDataHash: string): Promise<CapitalOnboardingStateDTO> {
const plugin = await this.loadPlugin();
const normalizedHash = docDataHash.trim();
if (!normalizedHash) {
throw new Error('Hash PrivateData документов ЦПП не может быть пустым');
}
const updatedConfig = {
...plugin.config,
capital_program_doc_data_hash: normalizedHash,
};
await this.extensionRepository.update({ ...plugin, config: updatedConfig });
return this.buildState(updatedConfig);
}
public async completeStep(data: CapitalOnboardingStepInputDTO, username: string): Promise<CapitalOnboardingStateDTO> {
const plugin = await this.loadPlugin();
const flagKey = this.mapStepToFlag(data.step);
+1
View File
@@ -2791,6 +2791,7 @@ export const ReturnTypes: Record<string,any> = {
CapitalOnboardingState:{
blagorost_offer_template_done:"Boolean",
blagorost_provision_done:"Boolean",
capital_program_doc_data_hash:"String",
generation_contract_template_done:"Boolean",
generator_offer_template_done:"Boolean",
generator_program_template_done:"Boolean",
+10 -3
View File
@@ -3009,6 +3009,7 @@ export type ValueTypes = {
["CapitalOnboardingState"]: AliasType<{
blagorost_offer_template_done?:boolean | `@${string}`,
blagorost_provision_done?:boolean | `@${string}`,
capital_program_doc_data_hash?:boolean | `@${string}`,
generation_contract_template_done?:boolean | `@${string}`,
generator_offer_template_done?:boolean | `@${string}`,
generator_program_template_done?:boolean | `@${string}`,
@@ -12342,6 +12343,7 @@ export type ResolverInputTypes = {
["CapitalOnboardingState"]: AliasType<{
blagorost_offer_template_done?:boolean | `@${string}`,
blagorost_provision_done?:boolean | `@${string}`,
capital_program_doc_data_hash?:boolean | `@${string}`,
generation_contract_template_done?:boolean | `@${string}`,
generator_offer_template_done?:boolean | `@${string}`,
generator_program_template_done?:boolean | `@${string}`,
@@ -21418,6 +21420,7 @@ export type ModelTypes = {
["CapitalOnboardingState"]: {
blagorost_offer_template_done: boolean,
blagorost_provision_done: boolean,
capital_program_doc_data_hash?: string | undefined | null,
generation_contract_template_done: boolean,
generator_offer_template_done: boolean,
generator_program_template_done: boolean,
@@ -25716,7 +25719,7 @@ export type ModelTypes = {
Требуемые роли: chairman, member. */
generateExpenseProposalStatementDocument: ModelTypes["GeneratedDocument"],
/** Сгенерировать протокол решения по предложенно повестке
/** Сгенерировать протокол решения по предложенной повестке
Требуемые роли: chairman, member. */
generateFreeDecision: ModelTypes["GeneratedDocument"],
@@ -29210,7 +29213,10 @@ export type ModelTypes = {
}
export type GraphQLTypes = {
["AcceptChildOrderInput"]: {
// ------------------------------------------------------;
// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY);
// ------------------------------------------------------;
["AcceptChildOrderInput"]: {
/** Имя аккаунта кооператива */
coopname: string,
/** Подписанное заявление на имущественный паевый взнос */
@@ -31113,6 +31119,7 @@ export type GraphQLTypes = {
__typename: "CapitalOnboardingState",
blagorost_offer_template_done: boolean,
blagorost_provision_done: boolean,
capital_program_doc_data_hash?: string | undefined | null,
generation_contract_template_done: boolean,
generator_offer_template_done: boolean,
generator_program_template_done: boolean,
@@ -35632,7 +35639,7 @@ export type GraphQLTypes = {
Требуемые роли: chairman, member. */
generateExpenseProposalStatementDocument: GraphQLTypes["GeneratedDocument"],
/** Сгенерировать протокол решения по предложенно повестке
/** Сгенерировать протокол решения по предложенной повестке
Требуемые роли: chairman, member. */
generateFreeDecision: GraphQLTypes["GeneratedDocument"],
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,13 +1,4 @@
export interface CapitalProgramPrivateData {
approval_protocol_number: string
approval_protocol_day: string
approval_protocol_month: string
approval_protocol_year: string
cooperative_name: string
cooperative_short_name: string
cooperative_quoted_name: string
website: string
chairman_full_name: string
generator_program_purpose: string
eoap_definition: string
generator_task_goal: string
@@ -18,19 +9,19 @@ export interface CapitalProgramPrivateData {
blagorost_task_development: string
return_source_description: string
return_additional_source: string
offer_template_number: string
}
export interface CapitalApprovalHeader {
protocol_number: string
protocol_day_month_year: string
}
export const CAPITAL_APPROVAL_PLACEHOLDER: CapitalApprovalHeader = {
protocol_number: '______',
protocol_day_month_year: '«___» __________ 20__ г.',
}
export const capitalProgramPrivateDataRequiredFields = [
'approval_protocol_number',
'approval_protocol_day',
'approval_protocol_month',
'approval_protocol_year',
'cooperative_name',
'cooperative_short_name',
'cooperative_quoted_name',
'website',
'chairman_full_name',
'generator_program_purpose',
'eoap_definition',
'generator_task_goal',
@@ -41,9 +32,20 @@ export const capitalProgramPrivateDataRequiredFields = [
'blagorost_task_development',
'return_source_description',
'return_additional_source',
'offer_template_number',
] as const
export function resolveCapitalApprovalHeader(
decision?: { protocol_number?: string; protocol_day_month_year?: string } | null,
): CapitalApprovalHeader {
const protocol_number = decision?.protocol_number?.trim()
const protocol_day_month_year = decision?.protocol_day_month_year?.trim()
return {
protocol_number: protocol_number || CAPITAL_APPROVAL_PLACEHOLDER.protocol_number,
protocol_day_month_year: protocol_day_month_year || CAPITAL_APPROVAL_PLACEHOLDER.protocol_day_month_year,
}
}
export function requireCapitalProgramPrivateData(
payload: CapitalProgramPrivateData | null | undefined,
registry_id: number,
@@ -22,7 +22,18 @@ const completeStep = async (
return state;
};
const saveProgramDocDataHash = async (doc_data_hash: string) => {
const { [Mutations.Capital.SaveCapitalProgramDocDataHash.name]: state } = await client.Mutation(
Mutations.Capital.SaveCapitalProgramDocDataHash.mutation,
{
variables: { data: { doc_data_hash } },
},
);
return state;
};
export const api = {
loadOnboardingState,
completeStep,
saveProgramDocDataHash,
};
@@ -0,0 +1,61 @@
export type EditableFieldKey =
| 'generator_program_purpose'
| 'eoap_definition'
| 'generator_task_goal'
| 'idea_unit_cost'
| 'idea_unit_cost_words'
| 'blagorost_goal_expansion'
| 'blagorost_task_expansion'
| 'blagorost_task_development'
| 'return_source_description'
| 'return_additional_source';
export const PREVIEW_PLACEHOLDER = '______';
export const FIELD_LABELS: Record<EditableFieldKey, string> = {
generator_program_purpose: 'Направление самореализации после слов «по …»',
eoap_definition: 'Определение ЕОАП после слов «а именно:»',
generator_task_goal: 'Характеристика ЕОАП после слов «развитие ЕОАП как …»',
idea_unit_cost: 'Стоимость единицы идеи (цифрами)',
idea_unit_cost_words: 'Стоимость единицы идеи (прописью)',
blagorost_goal_expansion: 'Потребность участников в развитии ЕОАП',
blagorost_task_expansion: 'Задача расширения участников ЕОАП',
blagorost_task_development: 'Задача развития ЕОАП',
return_source_description: 'Описание экономического эффекта ЕОАП',
return_additional_source: 'Дополнительный источник возврата паевых взносов',
};
export const GENERATOR_DOC_FIELDS: EditableFieldKey[] = [
'generator_program_purpose',
'eoap_definition',
'generator_task_goal',
'idea_unit_cost',
'idea_unit_cost_words',
];
export const BLAGOROST_DOC_FIELDS: EditableFieldKey[] = [
'blagorost_goal_expansion',
'blagorost_task_expansion',
'blagorost_task_development',
'return_source_description',
'return_additional_source',
'eoap_definition',
];
export const ALL_DOC_FIELDS: EditableFieldKey[] = [
...GENERATOR_DOC_FIELDS,
...BLAGOROST_DOC_FIELDS.filter((key) => !GENERATOR_DOC_FIELDS.includes(key)),
];
export const DOCUMENT_SECTIONS = [
{
registryId: 994,
tabLabel: 'Положение ГЕНЕРАТОР',
hint: 'Параметры подставляются в положение о программе «ГЕНЕРАТОР». Пустые поля отображаются прочерками — заполните их прямо в тексте документа.',
},
{
registryId: 998,
tabLabel: 'Положение БЛАГОРОСТ',
hint: 'Параметры подставляются в положение о программе «БЛАГОРОСТ», включая источники возврата. Заполните поля inline в тексте документа.',
},
] as const;
@@ -50,7 +50,7 @@ export const useCapitalOnboarding = () => {
const registry_id = stepToRegistryId[step.id];
const docDataHash = onboardingState.value?.capital_program_doc_data_hash;
if (capitalProgramDocDataRegistryIds.has(registry_id) && !docDataHash) {
throw new Error('Параметры документов ЦПП не заполнены: переустановите или обновите настройки расширения capital');
throw new Error('Сначала заполните параметры документов ЦПП и сформируйте предпросмотр');
}
const generateDocInput: Mutations.Documents.GenerateDocument.IInput = {
@@ -158,10 +158,12 @@ export const useCapitalOnboarding = () => {
});
const isOnboardingCompleted = computed(() => {
console.log(stepsConfig.value);
return stepsConfig.value.every(step => step.status === 'completed');
});
const docDataHash = computed(() => onboardingState.value?.capital_program_doc_data_hash || null);
const isDocParamsReady = computed(() => Boolean(docDataHash.value));
const config = computed<ICouncilOnboardingConfig>(() => ({
steps: stepsConfig.value,
expireAt: expireAt.value,
@@ -225,6 +227,10 @@ export const useCapitalOnboarding = () => {
}
};
const handleDocParamsSaved = async () => {
onboardingState.value = await api.loadOnboardingState();
};
return {
config,
loading,
@@ -232,8 +238,11 @@ export const useCapitalOnboarding = () => {
generatingDocument,
currentGeneratedDoc,
isOnboardingCompleted,
docDataHash,
isDocParamsReady,
loadState,
handleStepClick,
handleStepSubmit,
handleDocParamsSaved,
};
};
@@ -1,46 +1,50 @@
<template lang="pug">
div
// Показываем лоадер пока данные загружаются
WindowLoader(
v-if="loading"
text="Загрузка данных онбординга..."
)
// Показываем шаги если онбординг не завершен и данные загружены
q-card(v-else-if="!isOnboardingCompleted" flat)
q-card-section.row.items-center.justify-between
div
div.text-h5 Адаптация к работе с программой "Благорост"
template(v-else-if="!isOnboardingCompleted")
CapitalProgramDocumentParametersWidget(
:doc-data-hash='docDataHash'
@saved='handleDocParamsSaved'
)
q-separator
q-card-section
q-list(separator)
q-item(v-for="(step, index) in config?.steps || []" :key="step.id")
q-item-section
div.row.items-center.q-gutter-sm
q-icon(
:name="getIcon(step)"
:color="getIconColor(step)"
size="22px"
q-card(v-if='isDocParamsReady' flat class='q-mt-md')
q-card-section.row.items-center.justify-between
div
div.text-h5 Адаптация к работе с программой "Благорост"
q-separator
q-card-section
q-list(separator)
q-item(v-for="(step, index) in config?.steps || []" :key="step.id")
q-item-section
div.row.items-center.q-gutter-sm
q-icon(
:name="getIcon(step)"
:color="getIconColor(step)"
size="22px"
)
div.text-subtitle1 {{ index + 1 }}. {{ step.title }}
div.text-caption.text-grey-7 {{ step.description }}
q-chip(
v-if="step.status === 'in_progress'"
dense
color="amber"
text-color="black"
icon="hourglass_top"
class="q-mt-xs"
) Ожидаем решение совета
q-item-section(side)
q-btn(
v-if="showAction(index)"
:disable="submitting || generatingDocument"
:loading="generatingDocument && currentStepId === step.id"
color="primary"
label="Объявить собрание совета"
@click="() => openDialog(step)"
)
div.text-subtitle1 {{ index + 1 }}. {{ step.title }}
div.text-caption.text-grey-7 {{ step.description }}
q-chip(
v-if="step.status === 'in_progress'"
dense
color="amber"
text-color="black"
icon="hourglass_top"
class="q-mt-xs"
) Ожидаем решение совета
q-item-section(side)
q-btn(
v-if="showAction(index)"
:disable="submitting || generatingDocument"
:loading="generatingDocument && currentStepId === step.id"
color="primary"
label="Объявить собрание совета"
@click="() => openDialog(step)"
)
BaseDialog(
v-model="dialogOpen",
@@ -87,6 +91,7 @@ import { DocumentHtmlReader } from 'src/shared/ui/DocumentHtmlReader';
import { BaseDialog } from 'src/shared/ui/base/BaseDialog';
import { WindowLoader, Loader } from 'src/shared/ui/Loader';
import type { ICouncilOnboardingStep } from 'src/shared/ui/CouncilOnboarding';
import CapitalProgramDocumentParametersWidget from './CapitalProgramDocumentParametersWidget.vue';
import { useCapitalOnboarding } from '../model';
const {
@@ -96,9 +101,12 @@ const {
generatingDocument,
currentGeneratedDoc,
isOnboardingCompleted,
docDataHash,
isDocParamsReady,
loadState,
handleStepClick,
handleStepSubmit,
handleDocParamsSaved,
} = useCapitalOnboarding();
const dialogOpen = ref(false);
@@ -1,387 +1,261 @@
<template lang="pug">
BaseCard(title='Параметры документов ЦПП')
p.capital-doc-params__intro.t-body2
| Заполните поля, которые будут подставлены в положения и оферты программ «ГЕНЕРАТОР» и «БЛАГОРОСТ».
| Перед установкой расширения сформируйте предпросмотр документов: так параметры сохранятся в PrivateData, а в config попадёт только hash.
BaseCard.capital-doc-params(title='Параметры документов ЦПП')
p.t-body-sm.capital-doc-params__intro
| Заполните параметры положений «ГЕНЕРАТОР» и «БЛАГОРОСТ» прямо в тексте документа.
| Пустые поля подсвечиваются оранжевым подсвеченные области можно редактировать inline.
BaseInput(
:model-value='config?.capital_program_doc_data_hash || ""'
label='Hash PrivateData документов'
hint='Появится после формирования предпросмотра'
readonly
mono
)
BaseBanner(v-if='savedHash' type='success' class='q-mb-md')
| Параметры сохранены. Хеш: {{ savedHash }}
BaseBanner(v-if='config?.capital_program_doc_data_hash' variant='pos')
| Параметры сохранены. Hash: {{ config.capital_program_doc_data_hash }}
q-tabs(v-model='activeTab' dense align='left' class='capital-doc-params__tabs')
q-tab(
v-for='section in DOCUMENT_SECTIONS'
:key='section.registryId'
:name='section.registryId'
:label='section.tabLabel'
)
q-badge(v-if='getMissingCount(section.registryId)' color='warning' floating) {{ getMissingCount(section.registryId) }}
q-expansion-item(default-opened label='Протокол и кооператив' icon='description')
.row.q-col-gutter-md.q-mt-sm
.col-12.col-md-3(v-for='field in protocolFields' :key='field.key')
BaseInput(
v-model='form[field.key]'
:label='field.label'
:error='fieldErrors[field.key]'
)
.col-12.col-md-6(v-for='field in cooperativeFields' :key='field.key')
BaseInput(
v-model='form[field.key]'
:label='field.label'
:error='fieldErrors[field.key]'
q-tab-panels(v-model='activeTab' animated class='capital-doc-params__panels')
q-tab-panel(
v-for='section in DOCUMENT_SECTIONS'
:key='section.registryId'
:name='section.registryId'
)
p.t-caption.text-grey-7.q-mb-md {{ section.hint }}
.capital-doc-params__toolbar
BaseButton(
color='primary'
outline
:loading='loadingRegistryId === section.registryId'
:disable='!!loadingRegistryId'
@click='loadPreview(section.registryId)'
)
q-icon(name='refresh' class='q-mr-xs')
| {{ previews[section.registryId] ? 'Обновить предпросмотр' : 'Сформировать предпросмотр' }}
q-expansion-item(label='Программа ГЕНЕРАТОР' icon='bolt')
.capital-doc-params__section
BaseInput(
v-for='field in generatorFields'
:key='field.key'
v-model='form[field.key]'
:label='field.label'
:type='field.type || "textarea"'
:autogrow='field.type !== "text"'
:error='fieldErrors[field.key]'
q-inner-loading(:showing='loadingRegistryId === section.registryId')
CapitalProgramInlineDocumentPreview(
v-if='previews[section.registryId]'
v-model='form'
:html='getPreviewHtml(section.registryId)'
:field-labels='FIELD_LABELS'
class='q-mt-md'
)
q-expansion-item(label='Программа БЛАГОРОСТ' icon='eco')
.capital-doc-params__section
BaseInput(
v-for='field in blagorostFields'
:key='field.key'
v-model='form[field.key]'
:label='field.label'
type='textarea'
autogrow
:error='fieldErrors[field.key]'
)
q-expansion-item(label='Возврат, источники и оферты' icon='article')
.capital-doc-params__section
BaseInput(
v-for='field in returnFields'
:key='field.key'
v-model='form[field.key]'
:label='field.label'
:type='field.type || "textarea"'
:autogrow='field.type !== "text"'
:error='fieldErrors[field.key]'
)
p.t-caption.text-grey-6.q-mt-md(v-else)
| Нажмите «Сформировать предпросмотр», чтобы увидеть документ с редактируемыми полями.
.capital-doc-params__footer
p.capital-doc-params__hint.t-caption
| Предпросмотр генерирует документы без публикации и сохраняет PrivateData по hash.
BaseButton(:loading='isGenerating' @click='generatePreview')
| Сформировать предпросмотр
BaseDialog(v-model='previewOpen' title='Предпросмотр положений ЦПП' size='xl')
.capital-doc-params__preview(v-if='previewDocuments.length')
q-tabs(v-model='activePreviewTab' dense align='left' class='capital-doc-params__tabs')
q-tab(
v-for='doc in previewDocuments'
:key='doc.registry_id'
:name='String(doc.registry_id)'
:label='doc.title'
)
q-separator
q-tab-panels(v-model='activePreviewTab' animated)
q-tab-panel(
v-for='doc in previewDocuments'
:key='doc.registry_id'
:name='String(doc.registry_id)'
)
.doc-preview
DocumentHtmlReader(:html='doc.html' :sanitize='false')
template(#footer)
BaseButton(variant='ghost' @click='previewOpen = false')
| Закрыть
BaseButton(
color='primary'
:loading='saving'
:disable='!!loadingRegistryId'
@click='saveParams'
)
| Сохранить параметры
</template>
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import { Mutations } from '@coopenomics/sdk';
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { useQuasar } from 'quasar';
import type { CapitalProgramPrivateData } from 'cooptypes';
import { useSystemStore } from 'src/entities/System/model';
import { useSessionStore } from 'src/entities/Session';
import { client } from 'src/shared/api/client';
import { FailAlert, SuccessAlert } from 'src/shared/api';
import { BaseBanner, BaseButton, BaseCard, BaseDialog, BaseInput } from 'src/shared/ui/base';
import { DocumentHtmlReader } from 'src/shared/ui/DocumentHtmlReader';
import { BaseBanner, BaseButton, BaseCard } from 'src/shared/ui/base';
import { api as documentApi } from 'src/shared/lib/document/api';
import { api } from '../api';
import CapitalProgramInlineDocumentPreview from './CapitalProgramInlineDocumentPreview.vue';
import {
ALL_DOC_FIELDS,
BLAGOROST_DOC_FIELDS,
DOCUMENT_SECTIONS,
FIELD_LABELS,
GENERATOR_DOC_FIELDS,
PREVIEW_PLACEHOLDER,
type EditableFieldKey,
} from '../model/capitalProgramDocFields';
type CapitalProgramPrivateData = {
approval_protocol_number: string;
approval_protocol_day: string;
approval_protocol_month: string;
approval_protocol_year: string;
cooperative_name: string;
cooperative_short_name: string;
cooperative_quoted_name: string;
website: string;
chairman_full_name: string;
generator_program_purpose: string;
eoap_definition: string;
generator_task_goal: string;
idea_unit_cost: string;
idea_unit_cost_words: string;
blagorost_goal_expansion: string;
blagorost_task_expansion: string;
blagorost_task_development: string;
return_source_description: string;
return_additional_source: string;
offer_template_number: string;
};
type FieldDefinition = {
key: keyof CapitalProgramPrivateData;
label: string;
type?: 'text' | 'textarea';
};
type CapitalProgramConfig = Record<string, unknown> & {
capital_program_doc_data_hash?: string | null;
};
type GeneratedPreviewDocument = NonNullable<
Mutations.Documents.GenerateDocument.IOutput[typeof Mutations.Documents.GenerateDocument.name]
>;
interface Props {
config: CapitalProgramConfig;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(event: 'update:config', value: CapitalProgramConfig): void;
saved: [hash: string];
}>();
const system = useSystemStore();
const session = useSessionStore();
const isGenerating = ref(false);
const previewOpen = ref(false);
const activePreviewTab = ref('994');
const previewDocuments = ref<Array<{ registry_id: number; title: string; html: string; hash: string }>>([]);
const fieldErrors = reactive<Partial<Record<keyof CapitalProgramPrivateData, string>>>({});
const $q = useQuasar();
const systemStore = useSystemStore();
const sessionStore = useSessionStore();
const form = reactive<Omit<CapitalProgramPrivateData, 'cooperative_quoted_name'>>({
approval_protocol_number: '',
approval_protocol_day: '',
approval_protocol_month: '',
approval_protocol_year: '',
cooperative_name: '',
cooperative_short_name: '',
website: '',
chairman_full_name: '',
generator_program_purpose: '',
eoap_definition: '',
generator_task_goal: '',
idea_unit_cost: '',
idea_unit_cost_words: '',
blagorost_goal_expansion: '',
blagorost_task_expansion: '',
blagorost_task_development: '',
return_source_description: '',
return_additional_source: '',
offer_template_number: '______',
});
const activeTab = ref<number>(994);
const saving = ref(false);
const savedHash = ref('');
const loadingRegistryId = ref<number | null>(null);
const protocolFields: FieldDefinition[] = [
{ key: 'approval_protocol_number', label: 'Номер протокола' },
{ key: 'approval_protocol_day', label: 'День протокола' },
{ key: 'approval_protocol_month', label: 'Месяц протокола' },
{ key: 'approval_protocol_year', label: 'Год протокола' },
];
type PreviewState = {
html: string;
docDataHash: string;
};
const cooperativeFields: FieldDefinition[] = [
{ key: 'cooperative_name', label: 'Наименование кооператива' },
{ key: 'cooperative_short_name', label: 'Краткое наименование (ПК)' },
{ key: 'website', label: 'Сайт' },
{ key: 'chairman_full_name', label: 'ФИО председателя' },
];
const previews = reactive<Partial<Record<number, PreviewState>>>({});
const generatorFields: FieldDefinition[] = [
{ key: 'generator_program_purpose', label: 'Назначение программы ГЕНЕРАТОР' },
{ key: 'eoap_definition', label: 'Определение ЕОАП' },
{ key: 'generator_task_goal', label: 'Цель задач ГЕНЕРАТОР' },
{ key: 'idea_unit_cost', label: 'Стоимость единицы идеи', type: 'text' },
{ key: 'idea_unit_cost_words', label: 'Стоимость единицы идеи прописью', type: 'text' },
];
const DOC_FIELDS_BY_REGISTRY: Record<number, EditableFieldKey[]> = {
994: GENERATOR_DOC_FIELDS,
998: BLAGOROST_DOC_FIELDS,
};
const blagorostFields: FieldDefinition[] = [
{ key: 'blagorost_goal_expansion', label: 'Расширение цели БЛАГОРОСТ' },
{ key: 'blagorost_task_expansion', label: 'Задача расширения БЛАГОРОСТ' },
{ key: 'blagorost_task_development', label: 'Задача развития БЛАГОРОСТ' },
];
function createEmptyForm(): Record<EditableFieldKey, string> {
return Object.fromEntries(ALL_DOC_FIELDS.map((key) => [key, ''])) as Record<EditableFieldKey, string>;
}
const returnFields: FieldDefinition[] = [
{ key: 'return_source_description', label: 'Источник возврата' },
{ key: 'return_additional_source', label: 'Дополнительный источник возврата' },
{ key: 'offer_template_number', label: 'Номер шаблона оферты', type: 'text' },
];
const form = reactive<Record<EditableFieldKey, string>>(createEmptyForm());
const allFields = computed(() => [
...protocolFields,
...cooperativeFields,
...generatorFields,
...blagorostFields,
...returnFields,
]);
watch(
() => system.info,
(info) => {
if (!info) return;
form.cooperative_name ||= String(info.coopname || '').toUpperCase();
form.cooperative_short_name ||= 'ПК';
form.website ||= info.website || info.contacts?.website || '';
form.chairman_full_name ||= info.chairman?.full_name || info.chairman_full_name || '';
},
{ immediate: true }
const editableFields = computed(() =>
ALL_DOC_FIELDS.map((key) => ({
key,
label: FIELD_LABELS[key],
})),
);
function getPayload(): CapitalProgramPrivateData {
const cooperativeName = String(form.cooperative_name || '').trim();
return {
...Object.fromEntries(
allFields.value.map(({ key }) => [key, String(form[key] || '').trim()])
) as Omit<CapitalProgramPrivateData, 'cooperative_quoted_name'>,
cooperative_quoted_name: cooperativeName ? `«${cooperativeName}»` : '',
};
function getPreviewHtml(registryId: number): string {
return previews[registryId]?.html ?? '';
}
function validatePayload(payload: CapitalProgramPrivateData): string[] {
return allFields.value
.filter(({ key }) => !payload[key])
function getMissingCount(registryId: number): number {
const fields = DOC_FIELDS_BY_REGISTRY[registryId] ?? [];
return fields.filter((key) => !String(form[key] ?? '').trim()).length;
}
function getPreviewPayload(): CapitalProgramPrivateData {
return Object.fromEntries(
ALL_DOC_FIELDS.map((key) => [key, String(form[key] ?? '').trim() || PREVIEW_PLACEHOLDER]),
) as CapitalProgramPrivateData;
}
function getDocDataHashFromResult(result: Awaited<ReturnType<typeof documentApi.generateDocument>>): string {
const meta = result.meta as { doc_data_hash?: string } | undefined;
return meta?.doc_data_hash ?? '';
}
function validatePayload(): string | null {
const missing = editableFields.value
.filter(({ key }) => !String(form[key] ?? '').trim())
.map(({ label }) => label);
}
function clearFieldErrors(): void {
for (const key of Object.keys(fieldErrors) as Array<keyof CapitalProgramPrivateData>) {
delete fieldErrors[key];
}
}
function setFieldErrors(missingLabels: string[]): void {
clearFieldErrors();
for (const { key, label } of allFields.value) {
if (missingLabels.includes(label)) {
fieldErrors[key] = 'Заполните поле';
}
}
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}
function getDocDataHash(doc: GeneratedPreviewDocument): string | null {
if (!isRecord(doc.meta)) return null;
const hash = doc.meta.doc_data_hash;
return typeof hash === 'string' && hash.length > 0 ? hash : null;
}
async function generateDocument(registry_id: number, payload: CapitalProgramPrivateData): Promise<GeneratedPreviewDocument> {
const { [Mutations.Documents.GenerateDocument.name]: result } = await client.Mutation(
Mutations.Documents.GenerateDocument.mutation,
{
variables: {
input: {
data: {
coopname: system.info?.coopname || '',
username: session.username,
lang: 'ru',
registry_id,
doc_data: payload,
},
options: { skip_save: true },
},
},
}
);
if (!result) {
throw new Error('Документ не был сгенерирован');
}
return result;
}
async function generatePreview() {
const payload = getPayload();
const missing = validatePayload(payload);
if (missing.length) {
setFieldErrors(missing);
FailAlert(`Заполните параметры документов: ${missing.join(', ')}`);
return `Заполните все параметры в документах: ${missing.join(', ')}`;
}
return null;
}
async function loadPreview(registryId: number, options?: { silent?: boolean }) {
if (!options?.silent) {
loadingRegistryId.value = registryId;
}
try {
const result = await documentApi.generateDocument({
coopname: systemStore.info?.coopname ?? '',
username: sessionStore.username ?? '',
registry_id: registryId,
doc_data: getPreviewPayload(),
});
previews[registryId] = {
html: result.html,
docDataHash: getDocDataHashFromResult(result),
};
return result;
} catch (error) {
if (!options?.silent) {
$q.notify({
type: 'negative',
message: error instanceof Error ? error.message : 'Не удалось сформировать предпросмотр',
});
}
throw error;
} finally {
if (!options?.silent) {
loadingRegistryId.value = null;
}
}
}
async function saveParams() {
const validationError = validatePayload();
if (validationError) {
$q.notify({ type: 'warning', message: validationError });
return;
}
clearFieldErrors();
saving.value = true;
try {
isGenerating.value = true;
const docs = await Promise.all([
generateDocument(994, payload),
generateDocument(998, payload),
]);
const docDataHash = docs
.map(getDocDataHash)
.find((hash: unknown): hash is string => typeof hash === 'string' && hash.length > 0);
if (!docDataHash) {
throw new Error('Генератор не вернул doc_data_hash');
for (const section of DOCUMENT_SECTIONS) {
await loadPreview(section.registryId, { silent: true });
}
previewDocuments.value = docs.map((doc, index) => ({
registry_id: index === 0 ? 994 : 998,
title: doc.full_title,
html: doc.html,
hash: doc.hash,
}));
activePreviewTab.value = '994';
previewOpen.value = true;
emit('update:config', {
...props.config,
capital_program_doc_data_hash: docDataHash,
const hash = previews[994]?.docDataHash ?? previews[998]?.docDataHash;
if (!hash) {
throw new Error('Не удалось получить хеш параметров документов');
}
await api.saveProgramDocDataHash(hash);
savedHash.value = hash;
emit('saved', hash);
$q.notify({
type: 'positive',
message: 'Параметры документов ЦПП сохранены',
});
SuccessAlert('Параметры документов сохранены в PrivateData');
} catch (error) {
FailAlert(error);
$q.notify({
type: 'negative',
message: error instanceof Error ? error.message : 'Не удалось сохранить параметры',
});
} finally {
isGenerating.value = false;
saving.value = false;
}
}
watch(activeTab, (registryId) => {
if (!previews[registryId]) {
void loadPreview(registryId);
}
});
onMounted(() => {
void loadPreview(activeTab.value);
});
</script>
<style scoped lang="scss">
.capital-doc-params__intro {
margin: 0 0 var(--p-4);
color: var(--p-ink-secondary);
color: var(--p-ink-muted);
}
.capital-doc-params__section {
.capital-doc-params__tabs {
margin-bottom: var(--p-2);
}
.capital-doc-params__panels {
background: transparent;
}
.capital-doc-params__toolbar {
display: flex;
flex-direction: column;
gap: var(--p-3);
margin-top: var(--p-2);
align-items: center;
gap: var(--p-2);
}
.capital-doc-params__footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--p-4);
margin-top: var(--p-6);
}
.capital-doc-params__hint {
margin: 0;
color: var(--p-ink-secondary);
}
.capital-doc-params__tabs {
color: var(--p-primary);
}
.doc-preview :deep([data-doc-param]) {
background: var(--p-warn-soft);
border-radius: var(--p-r-sm);
padding: 0 2px;
justify-content: flex-end;
margin-top: var(--p-4);
padding-top: var(--p-4);
border-top: 1px solid var(--p-line);
}
</style>
@@ -0,0 +1,201 @@
<template lang="pug">
.capital-inline-doc.statement(ref='containerRef')
</template>
<script setup lang="ts">
import DOMPurify from 'dompurify';
import { nextTick, onBeforeUnmount, ref, watch } from 'vue';
import type { EditableFieldKey } from '../model/capitalProgramDocFields';
const props = defineProps<{
html: string;
fieldLabels: Partial<Record<EditableFieldKey, string>>;
}>();
const form = defineModel<Record<EditableFieldKey, string>>({ required: true });
const containerRef = ref<HTMLElement | null>(null);
const listeners = new WeakMap<HTMLTextAreaElement, () => void>();
type FocusSnapshot = {
key: EditableFieldKey;
selectionStart: number;
selectionEnd: number;
};
let focusSnapshot: FocusSnapshot | null = null;
function isFieldEmpty(key: EditableFieldKey): boolean {
return !String(form.value[key] ?? '').trim();
}
function applyFieldStyle(textarea: HTMLTextAreaElement, key: EditableFieldKey) {
textarea.classList.toggle('capital-doc-param-inline--empty', isFieldEmpty(key));
}
function captureFocus() {
const active = document.activeElement;
if (!(active instanceof HTMLTextAreaElement) || !active.classList.contains('capital-doc-param-inline')) {
focusSnapshot = null;
return;
}
const key = active.getAttribute('data-field') as EditableFieldKey | null;
if (!key) {
focusSnapshot = null;
return;
}
focusSnapshot = {
key,
selectionStart: active.selectionStart,
selectionEnd: active.selectionEnd,
};
}
function restoreFocus(root: HTMLElement) {
if (!focusSnapshot) return;
const textarea = root.querySelector(`textarea[data-field="${focusSnapshot.key}"]`) as HTMLTextAreaElement | null;
if (!textarea) return;
textarea.focus();
textarea.setSelectionRange(focusSnapshot.selectionStart, focusSnapshot.selectionEnd);
}
function cleanupEditors(root: HTMLElement) {
root.querySelectorAll('textarea.capital-doc-param-inline').forEach((textarea) => {
const handler = listeners.get(textarea);
if (handler) {
textarea.removeEventListener('input', handler);
listeners.delete(textarea);
}
});
}
function mountInlineEditors(root: HTMLElement) {
root.querySelectorAll('[data-doc-param]').forEach((node) => {
const key = node.getAttribute('data-doc-param') as EditableFieldKey | null;
if (!key) return;
const textarea = document.createElement('textarea');
textarea.className = 'capital-doc-param-inline';
textarea.setAttribute('data-field', key);
textarea.rows =
key.includes('description') ||
key.includes('expansion') ||
key.includes('development') ||
key.includes('goal') ||
key.includes('purpose')
? 3
: 2;
textarea.value = form.value[key] ?? '';
textarea.placeholder = props.fieldLabels[key] ?? key;
applyFieldStyle(textarea, key);
const onInput = () => {
form.value[key] = textarea.value;
applyFieldStyle(textarea, key);
};
textarea.addEventListener('input', onInput);
listeners.set(textarea, onInput);
node.replaceWith(textarea);
});
}
function syncInlineEditors(root: HTMLElement) {
root.querySelectorAll('textarea.capital-doc-param-inline').forEach((node) => {
const textarea = node as HTMLTextAreaElement;
const key = textarea.getAttribute('data-field') as EditableFieldKey | null;
if (!key) return;
if (textarea !== document.activeElement && textarea.value !== (form.value[key] ?? '')) {
textarea.value = form.value[key] ?? '';
}
applyFieldStyle(textarea, key);
});
}
async function renderDocument(html: string) {
await nextTick();
const root = containerRef.value;
if (!root) return;
captureFocus();
cleanupEditors(root);
root.innerHTML = DOMPurify.sanitize(html);
mountInlineEditors(root);
restoreFocus(root);
}
watch(
() => props.html,
(html) => {
if (html) void renderDocument(html);
},
{ immediate: true },
);
watch(
form,
() => {
if (containerRef.value) syncInlineEditors(containerRef.value);
},
{ deep: true },
);
onBeforeUnmount(() => {
if (containerRef.value) cleanupEditors(containerRef.value);
});
</script>
<style scoped lang="scss">
.capital-inline-doc {
max-height: 60vh;
overflow: auto;
padding: var(--p-4);
border: 1px solid var(--p-line);
border-radius: var(--p-r-md);
background: var(--p-surface);
}
.capital-inline-doc :deep(.capital-doc-param-inline) {
display: block;
width: 100%;
max-width: 100%;
margin: var(--p-1) 0;
padding: var(--p-2) var(--p-3);
font: inherit;
line-height: inherit;
color: var(--p-ink);
background: color-mix(in srgb, var(--p-primary) 8%, var(--p-surface));
border: 1px dashed var(--p-primary);
border-radius: var(--p-r-sm);
resize: vertical;
box-sizing: border-box;
white-space: pre-wrap;
&:focus {
outline: none;
border-style: solid;
background: color-mix(in srgb, var(--p-primary) 12%, var(--p-surface));
}
&::placeholder {
color: var(--p-ink-muted);
font-size: 0.85em;
}
}
.capital-inline-doc :deep(.capital-doc-param-inline--empty) {
border-color: var(--p-warn);
background: color-mix(in srgb, var(--p-warn) 12%, var(--p-surface));
&:focus {
background: color-mix(in srgb, var(--p-warn) 16%, var(--p-surface));
}
}
</style>
@@ -1,2 +1,3 @@
export { default as CapitalOnboardingCard } from './CapitalOnboardingCard.vue';
export { default as CapitalProgramDocumentParametersWidget } from './CapitalProgramDocumentParametersWidget.vue';
export { default as CapitalProgramInlineDocumentPreview } from './CapitalProgramInlineDocumentPreview.vue';
@@ -1,11 +1,6 @@
<template lang="pug">
.extension-install
q-form(:ref='setFormRef')
CapitalProgramDocumentParametersWidget(
v-if='extensionName === "capital"'
:config='config'
@update:config='$emit("update:config", $event)'
)
q-form(ref='formRef')
BaseCard(v-if='schema && !isEmpty', title='Настройки')
ZodForm(
:schema='schema',
@@ -23,7 +18,6 @@ import type { ComponentPublicInstance } from 'vue';
import { ZodForm } from 'src/shared/ui/ZodForm';
import { BaseCard } from 'src/shared/ui/base/BaseCard';
import { isExtensionSchemaEmpty } from 'src/shared/lib/utils';
import { CapitalProgramDocumentParametersWidget } from 'app/extensions/capital/features/Onboarding';
type ExtensionInstallConfig = Record<string, unknown>;
type ExtensionInstallFormRef = {
@@ -40,12 +34,6 @@ interface Props {
const props = defineProps<Props>();
const isEmpty = computed(() => isExtensionSchemaEmpty(props.schema));
const setFormRef = (element: Element | ComponentPublicInstance | null) => {
if (props.formRef && 'value' in props.formRef) {
props.formRef.value = element;
}
};
</script>
<style scoped lang="scss">
@@ -29,6 +29,7 @@ export class Factory extends DocFactory<GeneratorProgramTemplate.Action> {
coop,
vars,
doc_data,
approval: Cooperative.Registry.resolveCapitalApprovalHeader(vars.generator_program),
}
await this.validate(combinedData, template.model)
@@ -37,6 +37,7 @@ export class Factory extends DocFactory<GeneratorOfferTemplate.Action> {
vars,
common_user,
doc_data,
approval: Cooperative.Registry.resolveCapitalApprovalHeader(vars.generator_offer_template),
}
await this.validate(combinedData, template.model)
@@ -12,18 +12,25 @@ export class Factory extends DocFactory<BlagorostProgramTemplate.Action> {
}
async generateDocument(data: BlagorostProgramTemplate.Action, options?: IGenerationOptions): Promise<IGeneratedDocument> {
const { template, vars, docData } = await this.resolveParallel({
const { template, vars, coop, docData } = await this.resolveParallel({
template: () => process.env.SOURCE === 'local'
? Promise.resolve(BlagorostProgramTemplate.Template as ITemplate<BlagorostProgramTemplate.Model>)
: this.getTemplate<BlagorostProgramTemplate.Model>(DraftContract.contractName.production, BlagorostProgramTemplate.registry_id, data.block_num),
vars: () => this.getVars(data.coopname),
coop: () => this.getCooperative(data.coopname),
docData: () => this.loadDocData<BlagorostProgramTemplate.Model['doc_data']>(data),
})
const meta: IMetaDocument = await this.getMeta({ title: template.title, ...data })
const doc_data = Cooperative.Registry.requireCapitalProgramPrivateData(docData, BlagorostProgramTemplate.registry_id)
const combinedData: BlagorostProgramTemplate.Model = { meta, vars, doc_data }
const combinedData: BlagorostProgramTemplate.Model = {
meta,
coop,
vars,
doc_data,
approval: Cooperative.Registry.resolveCapitalApprovalHeader(vars.blagorost_program),
}
await this.validate(combinedData, template.model)
@@ -34,6 +34,7 @@ export class Factory extends DocFactory<BlagorostOfferTemplate.Action> {
coop,
vars,
doc_data,
approval: Cooperative.Registry.resolveCapitalApprovalHeader(vars.blagorost_offer_template),
}
await this.validate(combinedData, template.model)
@@ -0,0 +1,30 @@
import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
export const CapitalApprovalHeaderSchema: JSONSchemaType<Cooperative.Registry.CapitalApprovalHeader> = {
type: 'object',
properties: {
protocol_number: { type: 'string' },
protocol_day_month_year: { type: 'string' },
},
required: ['protocol_number', 'protocol_day_month_year'],
additionalProperties: false,
}
export const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
},
required: [...Cooperative.Registry.capitalProgramPrivateDataRequiredFields],
additionalProperties: false,
}
@@ -1,46 +1,16 @@
import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
import type { IMetaDocument, ITemplate } from '../Interfaces'
import type { ITemplate } from '../Interfaces'
import { IMetaJSONSchema } from '../Schema/MetaSchema'
import { CapitalProgramPrivateDataSchema } from '../Schema/CapitalProgramPrivateDataSchema'
import { CommonUserSchema, CooperativeSchema, VarsSchema } from '../Schema'
export const registry_id = Cooperative.Registry.BlagorostOffer.registry_id
// Модель действия для генерации
export type Action = Cooperative.Registry.BlagorostOffer.Action
// Модель данных - используем полную модель с дополнительными полями
export type Model = Cooperative.Registry.BlagorostOffer.Model
const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
approval_protocol_number: { type: 'string' },
approval_protocol_day: { type: 'string' },
approval_protocol_month: { type: 'string' },
approval_protocol_year: { type: 'string' },
cooperative_name: { type: 'string' },
cooperative_short_name: { type: 'string' },
cooperative_quoted_name: { type: 'string' },
website: { type: 'string' },
chairman_full_name: { type: 'string' },
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
offer_template_number: { type: 'string' },
},
required: Cooperative.Registry.capitalProgramPrivateDataRequiredFields,
additionalProperties: false,
}
// Схема для сверки - используем расширенную схему для дополнительных данных
export const Schema: JSONSchemaType<Model> = {
type: 'object',
properties: {
@@ -2,6 +2,7 @@ import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
import type { ITemplate } from '../Interfaces'
import { IMetaJSONSchema } from '../Schema/MetaSchema'
import { CapitalApprovalHeaderSchema, CapitalProgramPrivateDataSchema } from '../Schema/CapitalProgramPrivateDataSchema'
import { CommonUserSchema, CooperativeSchema, VarsSchema } from '../Schema'
export const registry_id = Cooperative.Registry.GeneratorProgramTemplate.registry_id
@@ -12,34 +13,6 @@ export type Action = Cooperative.Registry.GeneratorProgramTemplate.Action
// Модель данных
export type Model = Cooperative.Registry.GeneratorProgramTemplate.Model
const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
approval_protocol_number: { type: 'string' },
approval_protocol_day: { type: 'string' },
approval_protocol_month: { type: 'string' },
approval_protocol_year: { type: 'string' },
cooperative_name: { type: 'string' },
cooperative_short_name: { type: 'string' },
cooperative_quoted_name: { type: 'string' },
website: { type: 'string' },
chairman_full_name: { type: 'string' },
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
offer_template_number: { type: 'string' },
},
required: Cooperative.Registry.capitalProgramPrivateDataRequiredFields,
additionalProperties: false,
}
// Схема для сверки
export const Schema: JSONSchemaType<Model> = {
type: 'object',
@@ -48,8 +21,9 @@ export const Schema: JSONSchemaType<Model> = {
coop: CooperativeSchema,
vars: VarsSchema,
doc_data: CapitalProgramPrivateDataSchema,
approval: CapitalApprovalHeaderSchema,
},
required: ['meta', 'coop', 'vars', 'doc_data'],
required: ['meta', 'coop', 'vars', 'doc_data', 'approval'],
additionalProperties: true,
}
@@ -2,45 +2,15 @@ import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
import type { ITemplate } from '../Interfaces'
import { IMetaJSONSchema } from '../Schema/MetaSchema'
import { CapitalApprovalHeaderSchema, CapitalProgramPrivateDataSchema } from '../Schema/CapitalProgramPrivateDataSchema'
import { CommonUserSchema, CooperativeSchema, VarsSchema } from '../Schema'
export const registry_id = Cooperative.Registry.GeneratorOfferTemplate.registry_id
// Модель действия для генерации
export type Action = Cooperative.Registry.GeneratorOfferTemplate.Action
// Модель данных
export type Model = Cooperative.Registry.GeneratorOfferTemplate.Model
const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
approval_protocol_number: { type: 'string' },
approval_protocol_day: { type: 'string' },
approval_protocol_month: { type: 'string' },
approval_protocol_year: { type: 'string' },
cooperative_name: { type: 'string' },
cooperative_short_name: { type: 'string' },
cooperative_quoted_name: { type: 'string' },
website: { type: 'string' },
chairman_full_name: { type: 'string' },
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
offer_template_number: { type: 'string' },
},
required: Cooperative.Registry.capitalProgramPrivateDataRequiredFields,
additionalProperties: false,
}
// Схема для сверки
export const Schema: JSONSchemaType<Model> = {
type: 'object',
properties: {
@@ -49,8 +19,9 @@ export const Schema: JSONSchemaType<Model> = {
vars: VarsSchema,
doc_data: CapitalProgramPrivateDataSchema,
common_user: CommonUserSchema,
approval: CapitalApprovalHeaderSchema,
},
required: ['meta', 'coop', 'vars', 'common_user', 'doc_data'],
required: ['meta', 'coop', 'vars', 'common_user', 'doc_data', 'approval'],
additionalProperties: true,
}
@@ -2,45 +2,15 @@ import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
import type { ITemplate } from '../Interfaces'
import { IMetaJSONSchema } from '../Schema/MetaSchema'
import { CapitalProgramPrivateDataSchema } from '../Schema/CapitalProgramPrivateDataSchema'
import { CommonUserSchema, CooperativeSchema, VarsSchema } from '../Schema'
export const registry_id = Cooperative.Registry.GeneratorOffer.registry_id
// Модель действия для генерации
export type Action = Cooperative.Registry.GeneratorOffer.Action
// Модель данных
export type Model = Cooperative.Registry.GeneratorOffer.Model
const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
approval_protocol_number: { type: 'string' },
approval_protocol_day: { type: 'string' },
approval_protocol_month: { type: 'string' },
approval_protocol_year: { type: 'string' },
cooperative_name: { type: 'string' },
cooperative_short_name: { type: 'string' },
cooperative_quoted_name: { type: 'string' },
website: { type: 'string' },
chairman_full_name: { type: 'string' },
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
offer_template_number: { type: 'string' },
},
required: Cooperative.Registry.capitalProgramPrivateDataRequiredFields,
additionalProperties: false,
}
// Схема для сверки
export const Schema: JSONSchemaType<Model> = {
type: 'object',
properties: {
@@ -1,60 +1,26 @@
import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
import type { IGenerate, IMetaDocument, ITemplate } from '../Interfaces'
import type { IVars } from '../Models'
import type { ITemplate } from '../Interfaces'
import { IMetaJSONSchema } from '../Schema/MetaSchema'
import { VarsSchema } from '../Schema'
import { CapitalApprovalHeaderSchema, CapitalProgramPrivateDataSchema } from '../Schema/CapitalProgramPrivateDataSchema'
import { CooperativeSchema, VarsSchema } from '../Schema'
export const registry_id = Cooperative.Registry.BlagorostProgramTemplate.registry_id
// Модель действия для генерации
export interface Action extends IGenerate {
registry_id: number
}
export type Action = Cooperative.Registry.BlagorostProgramTemplate.Action
// Модель данных
export interface Model {
meta: IMetaDocument
vars: IVars
}
export type Model = Cooperative.Registry.BlagorostProgramTemplate.Model
const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
approval_protocol_number: { type: 'string' },
approval_protocol_day: { type: 'string' },
approval_protocol_month: { type: 'string' },
approval_protocol_year: { type: 'string' },
cooperative_name: { type: 'string' },
cooperative_short_name: { type: 'string' },
cooperative_quoted_name: { type: 'string' },
website: { type: 'string' },
chairman_full_name: { type: 'string' },
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
offer_template_number: { type: 'string' },
},
required: Cooperative.Registry.capitalProgramPrivateDataRequiredFields,
additionalProperties: false,
}
// Схема для сверки
export const Schema: JSONSchemaType<Model> = {
type: 'object',
properties: {
meta: IMetaJSONSchema,
coop: CooperativeSchema,
vars: VarsSchema,
doc_data: CapitalProgramPrivateDataSchema,
approval: CapitalApprovalHeaderSchema,
},
required: ['meta', 'vars', 'doc_data'],
required: ['meta', 'coop', 'vars', 'doc_data', 'approval'],
additionalProperties: true,
}
@@ -2,45 +2,15 @@ import type { JSONSchemaType } from 'ajv'
import { Cooperative } from 'cooptypes'
import type { ITemplate } from '../Interfaces'
import { IMetaJSONSchema } from '../Schema/MetaSchema'
import { CapitalApprovalHeaderSchema, CapitalProgramPrivateDataSchema } from '../Schema/CapitalProgramPrivateDataSchema'
import { CooperativeSchema, VarsSchema } from '../Schema'
export const registry_id = Cooperative.Registry.BlagorostOfferTemplate.registry_id
// Модель действия для генерации
export type Action = Cooperative.Registry.BlagorostOfferTemplate.Action
// Модель данных
export type Model = Cooperative.Registry.BlagorostOfferTemplate.Model
const CapitalProgramPrivateDataSchema: JSONSchemaType<Cooperative.Registry.CapitalProgramPrivateData> = {
type: 'object',
properties: {
approval_protocol_number: { type: 'string' },
approval_protocol_day: { type: 'string' },
approval_protocol_month: { type: 'string' },
approval_protocol_year: { type: 'string' },
cooperative_name: { type: 'string' },
cooperative_short_name: { type: 'string' },
cooperative_quoted_name: { type: 'string' },
website: { type: 'string' },
chairman_full_name: { type: 'string' },
generator_program_purpose: { type: 'string' },
eoap_definition: { type: 'string' },
generator_task_goal: { type: 'string' },
idea_unit_cost: { type: 'string' },
idea_unit_cost_words: { type: 'string' },
blagorost_goal_expansion: { type: 'string' },
blagorost_task_expansion: { type: 'string' },
blagorost_task_development: { type: 'string' },
return_source_description: { type: 'string' },
return_additional_source: { type: 'string' },
offer_template_number: { type: 'string' },
},
required: Cooperative.Registry.capitalProgramPrivateDataRequiredFields,
additionalProperties: false,
}
// Схема для сверки
export const Schema: JSONSchemaType<Model> = {
type: 'object',
properties: {
@@ -48,8 +18,9 @@ export const Schema: JSONSchemaType<Model> = {
coop: CooperativeSchema,
vars: VarsSchema,
doc_data: CapitalProgramPrivateDataSchema,
approval: CapitalApprovalHeaderSchema,
},
required: ['meta', 'coop', 'vars', 'doc_data'],
required: ['meta', 'coop', 'vars', 'doc_data', 'approval'],
additionalProperties: true,
}
@@ -49,15 +49,6 @@ beforeAll(async () => {
}
const capitalProgramPrivateData = {
approval_protocol_number: '1',
approval_protocol_day: '15',
approval_protocol_month: 'января',
approval_protocol_year: '26',
cooperative_name: 'ВОСХОД',
cooperative_short_name: 'ПК',
cooperative_quoted_name: '«ВОСХОД»',
website: 'https://цифровой-кооператив.рф',
chairman_full_name: 'Муравьев Алексей Николаевич',
generator_program_purpose: 'развитию информационной экосистемы взаимодействия физических и юридических лиц, на основе международных кооперативных принципов и законодательства Российской Федерации в отношении потребительских обществ (кооперативов) под названием “Кооперативная Экономика”',
eoap_definition: 'информационная экосистема, интегрируемая в социально-экономическую среду Российской Федерации, состоящая из комплекса программных продуктов на базе технологии распределенного реестра, обеспечивающих широкое экономическое и социальное взаимодействие физических и юридических лиц, включая нерезидентов различных юрисдикций и организационно-правовых форм, на основе международных кооперативных принципов и законодательства Российской Федерации в отношении потребительских кооперативов (обществ) под названием “Кооперативная Экономика”',
generator_task_goal: 'центра привлечения и интеграции передовых инновационных цифровых разработок, а также экономических и социальных методов и решений',
@@ -68,7 +59,6 @@ beforeAll(async () => {
blagorost_task_development: 'развитие ЕОАП как центра привлечения и интеграции инновационных цифровых разработок, а также экономических и социальных методов и решений',
return_source_description: 'аппаратно-программная сеть узлов распределенного реестра в формате «СМЭВ+SWIFT», построенная на принципах самоорганизации и самофинансирования деятельности технологической инфраструктуры ЕОАП, обеспечивающей консенсус ее распределенных узлов по формированию базового продукта ЕОАП - полного цикла документооборота по синхронному взаимодействию пайщиков и кооперативов - участников экосистемы ЕОАП - через использование цифровых контрактов, с одновременным выполнением функций нотариата и учета финансовых и юридических событий',
return_additional_source: 'взносы пользователей ЕОАП, его отдельных программных продуктов и приложений, переданных Обществу или создаваемых в рамках Общества, которые интегрируются в ЕОАП',
offer_template_number: '______',
}
const { hash } = await generator.saveDocData(capitalProgramPrivateData, 994)
@@ -4,6 +4,7 @@ export * as CalculateVotes from './calculateVotes'
export * as CloseProject from './closeProject'
export * as CompleteCapitalRegistration from './completeCapitalRegistration'
export * as CompleteOnboardingStep from './completeOnboardingStep'
export * as SaveCapitalProgramDocDataHash from './saveCapitalProgramDocDataHash'
export * as CompleteVoting from './completeVoting'
export * as ConvertSegment from './convertSegment'
export * as CreateCommit from './createCommit'
@@ -0,0 +1,19 @@
import { capitalOnboardingStateSelector } from '../../selectors'
import { $, type GraphQLTypes, type InputType, type ModelTypes, Selector } from '../../zeus'
export const name = 'saveCapitalProgramDocDataHash'
export const mutation = Selector('Mutation')({
[name]: [{ data: $('data', 'SaveCapitalProgramDocDataInput!') }, capitalOnboardingStateSelector],
})
export interface IInput {
/**
* @private
*/
[key: string]: unknown
data: ModelTypes['SaveCapitalProgramDocDataInput']
}
export type IOutput = InputType<GraphQLTypes['Mutation'], typeof mutation>
+7
View File
@@ -169,6 +169,9 @@ export const AllTypesProps: Record<string,any> = {
event_types:"LogEventType"
},
CapitalOnboardingStep: "enum" as const,
SaveCapitalProgramDocDataInput:{
doc_data_hash:"String"
},
CapitalOnboardingStepInput:{
step:"CapitalOnboardingStep"
},
@@ -1019,6 +1022,9 @@ export const AllTypesProps: Record<string,any> = {
completeCapitalOnboardingStep:{
data:"CapitalOnboardingStepInput"
},
saveCapitalProgramDocDataHash:{
data:"SaveCapitalProgramDocDataInput"
},
completeChairmanAgendaStep:{
data:"ChairmanOnboardingAgendaInput"
},
@@ -2791,6 +2797,7 @@ export const ReturnTypes: Record<string,any> = {
CapitalOnboardingState:{
blagorost_offer_template_done:"Boolean",
blagorost_provision_done:"Boolean",
capital_program_doc_data_hash:"String",
generation_contract_template_done:"Boolean",
generator_offer_template_done:"Boolean",
generator_program_template_done:"Boolean",
+21 -3
View File
@@ -3009,6 +3009,7 @@ export type ValueTypes = {
["CapitalOnboardingState"]: AliasType<{
blagorost_offer_template_done?:boolean | `@${string}`,
blagorost_provision_done?:boolean | `@${string}`,
capital_program_doc_data_hash?:boolean | `@${string}`,
generation_contract_template_done?:boolean | `@${string}`,
generator_offer_template_done?:boolean | `@${string}`,
generator_program_template_done?:boolean | `@${string}`,
@@ -3023,6 +3024,9 @@ export type ValueTypes = {
['...on CapitalOnboardingState']?: Omit<ValueTypes["CapitalOnboardingState"], "...on CapitalOnboardingState">
}>;
["CapitalOnboardingStep"]:CapitalOnboardingStep;
["SaveCapitalProgramDocDataInput"]: {
doc_data_hash: string | Variable<any, string>
};
["CapitalOnboardingStepInput"]: {
decision: string | Variable<any, string>,
question: string | Variable<any, string>,
@@ -7117,6 +7121,7 @@ chatcoopRemoveSecretaryRoom?: [{ data: ValueTypes["RemoveSecretaryRoomInput"] |
chatcoopUpdateCalendarEvent?: [{ data: ValueTypes["UpdateChatCoopCalendarEventInput"] | Variable<any, string>},ValueTypes["ChatCoopCalendarEvent"]],
chatcoopUpdateTranscriptionMemo?: [{ data: ValueTypes["UpdateCallTranscriptionMemoInput"] | Variable<any, string>},ValueTypes["CallTranscription"]],
completeCapitalOnboardingStep?: [{ data: ValueTypes["CapitalOnboardingStepInput"] | Variable<any, string>},ValueTypes["CapitalOnboardingState"]],
saveCapitalProgramDocDataHash?: [{ data: ValueTypes["SaveCapitalProgramDocDataInput"] | Variable<any, string>},ValueTypes["CapitalOnboardingState"]],
completeChairmanAgendaStep?: [{ data: ValueTypes["ChairmanOnboardingAgendaInput"] | Variable<any, string>},ValueTypes["ChairmanOnboardingState"]],
completeChairmanGeneralMeetStep?: [{ data: ValueTypes["ChairmanOnboardingGeneralMeetInput"] | Variable<any, string>},ValueTypes["ChairmanOnboardingState"]],
completeExtensionOnboardingStep?: [{ data: ValueTypes["CompleteExtensionOnboardingStepInput"] | Variable<any, string>},ValueTypes["ExtensionOnboardingState"]],
@@ -12342,6 +12347,7 @@ export type ResolverInputTypes = {
["CapitalOnboardingState"]: AliasType<{
blagorost_offer_template_done?:boolean | `@${string}`,
blagorost_provision_done?:boolean | `@${string}`,
capital_program_doc_data_hash?:boolean | `@${string}`,
generation_contract_template_done?:boolean | `@${string}`,
generator_offer_template_done?:boolean | `@${string}`,
generator_program_template_done?:boolean | `@${string}`,
@@ -12355,6 +12361,9 @@ export type ResolverInputTypes = {
__typename?: boolean | `@${string}`
}>;
["CapitalOnboardingStep"]:CapitalOnboardingStep;
["SaveCapitalProgramDocDataInput"]: {
doc_data_hash: string | Variable<any, string>
};
["CapitalOnboardingStepInput"]: {
decision: string,
question: string,
@@ -16351,6 +16360,7 @@ chatcoopRemoveSecretaryRoom?: [{ data: ResolverInputTypes["RemoveSecretaryRoomIn
chatcoopUpdateCalendarEvent?: [{ data: ResolverInputTypes["UpdateChatCoopCalendarEventInput"]},ResolverInputTypes["ChatCoopCalendarEvent"]],
chatcoopUpdateTranscriptionMemo?: [{ data: ResolverInputTypes["UpdateCallTranscriptionMemoInput"]},ResolverInputTypes["CallTranscription"]],
completeCapitalOnboardingStep?: [{ data: ResolverInputTypes["CapitalOnboardingStepInput"]},ResolverInputTypes["CapitalOnboardingState"]],
saveCapitalProgramDocDataHash?: [{ data: ResolverInputTypes["SaveCapitalProgramDocDataInput"]},ResolverInputTypes["CapitalOnboardingState"]],
completeChairmanAgendaStep?: [{ data: ResolverInputTypes["ChairmanOnboardingAgendaInput"]},ResolverInputTypes["ChairmanOnboardingState"]],
completeChairmanGeneralMeetStep?: [{ data: ResolverInputTypes["ChairmanOnboardingGeneralMeetInput"]},ResolverInputTypes["ChairmanOnboardingState"]],
completeExtensionOnboardingStep?: [{ data: ResolverInputTypes["CompleteExtensionOnboardingStepInput"]},ResolverInputTypes["ExtensionOnboardingState"]],
@@ -21418,6 +21428,7 @@ export type ModelTypes = {
["CapitalOnboardingState"]: {
blagorost_offer_template_done: boolean,
blagorost_provision_done: boolean,
capital_program_doc_data_hash?: string | undefined | null,
generation_contract_template_done: boolean,
generator_offer_template_done: boolean,
generator_program_template_done: boolean,
@@ -21430,6 +21441,9 @@ export type ModelTypes = {
onboarding_init_at: string
};
["CapitalOnboardingStep"]:CapitalOnboardingStep;
["SaveCapitalProgramDocDataInput"]: {
doc_data_hash: string
};
["CapitalOnboardingStepInput"]: {
decision: string,
question: string,
@@ -25716,7 +25730,7 @@ export type ModelTypes = {
Требуемые роли: chairman, member. */
generateExpenseProposalStatementDocument: ModelTypes["GeneratedDocument"],
/** Сгенерировать протокол решения по предложенно повестке
/** Сгенерировать протокол решения по предложенной повестке
Требуемые роли: chairman, member. */
generateFreeDecision: ModelTypes["GeneratedDocument"],
@@ -29210,7 +29224,10 @@ export type ModelTypes = {
}
export type GraphQLTypes = {
["AcceptChildOrderInput"]: {
// ------------------------------------------------------;
// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY);
// ------------------------------------------------------;
["AcceptChildOrderInput"]: {
/** Имя аккаунта кооператива */
coopname: string,
/** Подписанное заявление на имущественный паевый взнос */
@@ -31113,6 +31130,7 @@ export type GraphQLTypes = {
__typename: "CapitalOnboardingState",
blagorost_offer_template_done: boolean,
blagorost_provision_done: boolean,
capital_program_doc_data_hash?: string | undefined | null,
generation_contract_template_done: boolean,
generator_offer_template_done: boolean,
generator_program_template_done: boolean,
@@ -35632,7 +35650,7 @@ export type GraphQLTypes = {
Требуемые роли: chairman, member. */
generateExpenseProposalStatementDocument: GraphQLTypes["GeneratedDocument"],
/** Сгенерировать протокол решения по предложенно повестке
/** Сгенерировать протокол решения по предложенной повестке
Требуемые роли: chairman, member. */
generateFreeDecision: GraphQLTypes["GeneratedDocument"],