diff --git a/components/contracts/cpp/capital/app/project_managment/create_project/createproj.cpp b/components/contracts/cpp/capital/app/project_managment/create_project/createproj.cpp
index c2658ca0941..1057a439c16 100644
--- a/components/contracts/cpp/capital/app/project_managment/create_project/createproj.cpp
+++ b/components/contracts/cpp/capital/app/project_managment/create_project/createproj.cpp
@@ -17,7 +17,7 @@
* @ingroup public_capital_actions
* @note Авторизация требуется от аккаунта: @p coopname
- * @note Для корневых проектов требуется отдельная инициализация через @ref capital::initprj
+ * @note Для всех проектов требуется отдельная инициализация через @ref capital::initprj
*/
void capital::createproj (
eosio::name coopname,
@@ -42,11 +42,10 @@ void capital::createproj (
// Валидируем parent_hash согласно правилам проектов
Capital::Projects::validate_parent_hash(coopname, parent_hash);
- // Если указан родительский проект, проверяем что он авторизован
+ // Если указан родительский проект, проверяем что он существует
if (parent_hash != checksum256()) {
auto parent_project = Capital::Projects::get_project(coopname, parent_hash);
eosio::check(parent_project.has_value(), "Родительский проект не найден");
- eosio::check(parent_project -> is_authorized, "Родительский проект не авторизован советом");
}
Capital::Projects::create_project(coopname, project_hash, parent_hash, title, description, invite, meta, data, can_convert_to_project);
diff --git a/components/contracts/cpp/capital/app/project_managment/create_project/project-creation-process.dox b/components/contracts/cpp/capital/app/project_managment/create_project/project-creation-process.dox
index a292a16396c..dc8bf211c31 100644
--- a/components/contracts/cpp/capital/app/project_managment/create_project/project-creation-process.dox
+++ b/components/contracts/cpp/capital/app/project_managment/create_project/project-creation-process.dox
@@ -8,8 +8,7 @@
реализации и генерации интеллектуального результата. Процесс вызывается тогда и только тогда, когда проект готов идти в планирование.
До этого идея проекта хранится в банке идей за пределами контракта.
- Дочерние проекты (компоненты мета-проекта) автоматически авторизованы при создании на авторизованном родительском проекте.
- Корневые проекты (без родителя) требуют отдельной инициализации через процесс @ref public_capital_project_initialization_process.
+ Все проекты (корневые и дочерние) требуют отдельной инициализации через процесс @ref public_capital_project_initialization_process.
\htmlonly
@@ -22,18 +21,11 @@
Note over БИ: Идея прошла отбор
БИ->>К: Идея готова к реализации
- alt Корневой проект
- К->>C: Создание проекта
- Note over C: Проверка уникальности хеша
- Note over C: Валидация родительского проекта
- C->>C: Создание записи проекта
- Note over C: Проект создан, требуется инициализация
- else Дочерний проект
- К->>C: Создание компонента
- Note over C: Проверка авторизации родителя
- C->>C: Создание записи проекта
- Note over C: Компонент автоматически авторизован
- end
+ К->>C: Создание проекта
+ Note over C: Проверка уникальности хеша
+ Note over C: Валидация родительского проекта
+ C->>C: Создание записи проекта
+ Note over C: Проект создан, требуется инициализация
\endhtmlonly
@@ -49,13 +41,11 @@
Система проверяет уникальность хеша проекта и валидирует родительский проект,
затем создает запись проекта.
-Дочерние проекты (компоненты) автоматически авторизованы при создании на авторизованном родительском проекте.
-Корневые проекты (без родителя) создаются без авторизации и требуют отдельной инициализации.
+Все проекты (корневые и дочерние) создаются без авторизации и требуют отдельной инициализации.
@post создается запись проекта в таблице projects
@post статус проекта устанавливается в PENDING
-@post для дочерних проектов: проект автоматически авторизован и готов к планированию
-@post для корневых проектов: проект создан и ожидает инициализации
+@post проект создан и ожидает инициализации
## Документы процесса
@include{doc} project-creation-docs.dox
diff --git a/components/contracts/cpp/capital/app/project_managment/init_project/initprj.cpp b/components/contracts/cpp/capital/app/project_managment/init_project/initprj.cpp
index 5ee1fb03aeb..5be5cb2c1f7 100644
--- a/components/contracts/cpp/capital/app/project_managment/init_project/initprj.cpp
+++ b/components/contracts/cpp/capital/app/project_managment/init_project/initprj.cpp
@@ -1,7 +1,7 @@
/**
* @brief Инициализирует проект для авторизации советом
- * Отправляет корневой проект на рассмотрение совета кооператива:
- * - Проверяет что проект существует и является корневым
+ * Отправляет проект на рассмотрение совета кооператива:
+ * - Проверяет что проект существует
* - Проверяет что проект еще не инициализирован
* - Отправляет проект на авторизацию с предоставленным документом
* @param coopname Наименование кооператива
@@ -11,7 +11,7 @@
* @ingroup public_capital_actions
* @note Авторизация требуется от аккаунта: @p coopname
- * @note Доступно только для корневых проектов (без родителя)
+ * @note Доступно для всех проектов (корневых и дочерних)
*/
void capital::initprj(eosio::name coopname, checksum256 project_hash, document2 document) {
require_auth(coopname);
@@ -22,9 +22,6 @@ void capital::initprj(eosio::name coopname, checksum256 project_hash, document2
// Получаем проект для проверки
auto project = Capital::Projects::get_project_or_fail(coopname, project_hash);
- // Проверяем что это корневой проект (без родителя)
- eosio::check(project->parent_hash == checksum256(), "Инициализация требуется только для корневых проектов");
-
// Проверяем что проект еще не инициализирован
eosio::check(!project->is_authorized, "Проект уже инициализирован");
diff --git a/components/contracts/cpp/capital/app/project_managment/init_project/project-init-process.dox b/components/contracts/cpp/capital/app/project_managment/init_project/project-init-process.dox
index c2173caaff6..852254efbfc 100644
--- a/components/contracts/cpp/capital/app/project_managment/init_project/project-init-process.dox
+++ b/components/contracts/cpp/capital/app/project_managment/init_project/project-init-process.dox
@@ -3,9 +3,8 @@
@defgroup public_capital_project_initialization_process Инициализировать проект
@ingroup public_capital_processes
@pre Проект создан через @ref public_capital_project_creation_process
- @pre Проект является корневым (без родителя)
- Процесс инициализации корневого проекта для получения авторизации совета кооператива.
+ Процесс инициализации проекта для получения авторизации совета кооператива.
Процесс включает отправку проекта на рассмотрение совета с предоставленным документом,
рассмотрение советом и принятие решения об авторизации или отклонении проекта.
@@ -18,7 +17,7 @@
participant С as Совет
К->>C: Инициализация проекта
- Note over C: Проверка что проект корневой
+ Note over C: Проверка что проект существует
Note over C: Проверка что проект не инициализирован
C->>С: Отправка на авторизацию с документом
Note over С: Рассмотрение проекта советом
@@ -37,8 +36,8 @@
### Шаг 1: Инициализация проекта
Действие: @ref capital::initprj "инициализация проекта"
-Кооператив отправляет корневой проект на рассмотрение совета кооператива с предоставленным документом.
-Система проверяет что проект существует, является корневым и еще не инициализирован,
+Кооператив отправляет проект на рассмотрение совета кооператива с предоставленным документом.
+Система проверяет что проект существует и еще не инициализирован,
затем отправляет проект на авторизацию в совет.
@post проект отправлен на рассмотрение совета
diff --git a/components/contracts/cpp/capital/app/project_managment/stop_project/stopproject.cpp b/components/contracts/cpp/capital/app/project_managment/stop_project/stopproject.cpp
index d5864bb24a7..a5136e4b5d5 100644
--- a/components/contracts/cpp/capital/app/project_managment/stop_project/stopproject.cpp
+++ b/components/contracts/cpp/capital/app/project_managment/stop_project/stopproject.cpp
@@ -4,6 +4,7 @@
* - Проверяет существование проекта
* - Валидирует что проект в статусе active
* - Обновляет статус проекта на pending
+ * - Сбрасывает авторизацию проекта (требуется повторная инициализация)
* @param coopname Наименование кооператива
* @param project_hash Хеш проекта для остановки
* @ingroup public_actions
@@ -25,4 +26,7 @@ void capital::stopproject(name coopname, checksum256 project_hash) {
// Обновляем статус проекта на "pending"
Capital::Projects::update_status(coopname, project_hash, Capital::Projects::Status::PENDING);
+
+ // Сбрасываем авторизацию проекта (требуется повторная инициализация)
+ Capital::Projects::revoke_authorization(coopname, project_hash);
}
diff --git a/components/contracts/cpp/capital/domain/entities/projects.hpp b/components/contracts/cpp/capital/domain/entities/projects.hpp
index 601bbe52954..b9effbe357d 100644
--- a/components/contracts/cpp/capital/domain/entities/projects.hpp
+++ b/components/contracts/cpp/capital/domain/entities/projects.hpp
@@ -171,7 +171,7 @@ namespace Capital::Projects {
row.data = data;
row.is_planed = false; // Изначально проект не запланирован
row.can_convert_to_project = can_convert_to_project; // Разрешена ли конвертация в кошелек проекта
- row.is_authorized = (parent_hash != checksum256()); // Дочерние проекты сразу авторизованы, корневые - нет
+ row.is_authorized = false; // Все проекты требуют инициализации
row.authorization = document2(); // Пустой документ авторизации
});
}
@@ -845,5 +845,24 @@ namespace Capital::Projects {
});
}
+ /**
+ * @brief Сбрасывает авторизацию проекта
+ * Устанавливает флаг авторизации в false и очищает документ авторизации
+ * @param coopname Наименование кооператива
+ * @param project_hash Хеш проекта
+ */
+ inline void revoke_authorization(eosio::name coopname, const checksum256 &project_hash) {
+ project_index projects(_capital, coopname.value);
+ auto project_hash_index = projects.get_index<"byhash"_n>();
+
+ auto project_itr = project_hash_index.find(project_hash);
+ eosio::check(project_itr != project_hash_index.end(), "Проект не найден");
+
+ project_hash_index.modify(project_itr, coopname, [&](auto& row) {
+ row.is_authorized = false;
+ row.authorization = document2(); // Пустой документ авторизации
+ });
+ }
+
}// namespace Project
\ No newline at end of file
diff --git a/components/cooptypes/src/cooperative/registry/1005.InitProjectStatement/index.ts b/components/cooptypes/src/cooperative/registry/1005.InitProjectStatement/index.ts
new file mode 100644
index 00000000000..359ddf55d5a
--- /dev/null
+++ b/components/cooptypes/src/cooperative/registry/1005.InitProjectStatement/index.ts
@@ -0,0 +1,113 @@
+import type { ICommonUser, ICooperativeData, IVars } from '../../model'
+import type { IGenerate, IMetaDocument } from '../../document'
+
+export const registry_id = 1005
+
+// Модель действия для генерации
+export interface Action extends IGenerate {
+ registry_id: number
+ project_name: string
+ project_id: string
+ component_name: string
+ component_id: string
+ is_component: boolean
+}
+
+export type Meta = IMetaDocument & Action
+
+// Модель данных документа
+export interface Model {
+ meta: IMetaDocument
+ coop: ICooperativeData
+ vars: IVars
+ user: ICommonUser
+ project_name: string
+ project_id: string
+ component_name: string
+ component_id: string
+ is_component: boolean
+}
+
+export const title = 'Заявление на инициализацию проекта'
+export const description = 'Заявление на инициализацию проекта или компонента'
+
+export const context = `
ЗАЯВЛЕНИЕ
на инициализацию проекта
{{ meta.created_at }}, {{ coop.city }}
{% trans 'parties_intro' %} "{{ vars.name }}" {% trans 'in_face_of_chairman' %} {{ coop.chairman.last_name }} {{ coop.chairman.first_name }} {{ coop.chairman.middle_name }}, {% trans 'acting_on_basis_of_charter' %}, {% trans 'hereinafter_referred_to_as' %} "{% trans 'society' %}", {% trans 'and_participant' %} {{ user.full_name_or_short_name }}, {% trans 'hereinafter_referred_to_as' %} "{% trans 'participant' %}", {% trans 'jointly_referred_to_as' %} "{% trans 'parties' %}", {% trans 'have_concluded_this_statement' %} {% trans 'hereinafter_referred_to_as' %} "{% trans 'statement' %}" {% trans 'of_the_following' %}:
{% if is_component %}{% trans 'participant_requests_component_init' %} "{{ component_name }}" (№{{ component_id }}) {% trans 'as_part_of_project' %} "{{ project_name }}" (№{{ project_id }}).{% else %}{% trans 'participant_requests_project_init' %} "{{ project_name }}" (№{{ project_id }}).{% endif %}
{% trans 'details_and_signatures_of_parties' %}
{% trans 'society' %}/{{ vars.full_abbr }} "{{ vars.name }}"/:
ИНН {{ coop.details.inn }}, КПП {{ coop.details.kpp }}, ОГРН {{ coop.details.ogrn }}
{% trans 'legal_address' %}: {{ coop.full_address }}
{% trans 'contact_phone' %}: {{ coop.phone }}
{% trans 'email' %}: {{ coop.email }}
{% trans 'bank_account' %}: {{ coop.defaultBankAccount.account_number }}
{% trans 'bank_name' %}: {{ coop.defaultBankAccount.bank_name }}
{% trans 'bik' %}: {{ coop.defaultBankAccount.details.bik }}
{% trans 'correspondent_account' %}: {{ coop.defaultBankAccount.details.corr }}
{% trans 'chairman' %} {{ vars.full_abbr_genitive }} "{{ vars.name }}"
{{ coop.chairman.last_name }} {{ coop.chairman.first_name }} {{ coop.chairman.middle_name }}
{% trans 'signed_by_digital_signature' %}
{% trans 'participant' %}:
{{ user.full_name_or_short_name }}
{% trans 'contact_phone' %}: {{ user.phone }}
{% trans 'email' %}: {{ user.email }}
{% trans 'signed_by_digital_signature' %}
`
+
+export const translations = {
+ ru: {
+ parties_intro: 'Потребительский Кооператив',
+ in_face_of_chairman: 'в лице Председателя Совета',
+ acting_on_basis_of_charter: 'действующего на основании Устава',
+ hereinafter_referred_to_as: 'далее именуемый(-ая)',
+ society: 'Общество',
+ and_participant: 'и',
+ participant: 'Пайщик',
+ jointly_referred_to_as: 'совместно именуемые',
+ parties: 'Стороны',
+ have_concluded_this_statement: 'составили настоящее Заявление',
+ statement: 'Заявление',
+ of_the_following: 'о нижеследующем',
+ participant_requests_component_init: 'Пайщик просит инициализировать Компонент',
+ participant_requests_project_init: 'Пайщик просит инициализировать Проект',
+ as_part_of_project: 'как составную часть Проекта',
+ details_and_signatures_of_parties: 'РЕКВИЗИТЫ И ПОДПИСИ СТОРОН',
+ legal_address: 'Юр. адрес',
+ contact_phone: 'Контактный тел.',
+ email: 'Электронная почта',
+ bank_account: 'Р/с',
+ bank_name: 'Банк',
+ bik: 'БИК',
+ correspondent_account: 'Корр/счет',
+ chairman: 'Председатель Совета',
+ signed_by_digital_signature: 'Подписано электронной подписью',
+ },
+}
+
+export const exampleData = {
+ meta: {
+ created_at: '11.04.2024 12:00',
+ },
+ project_name: 'Проект цифровой платформы',
+ project_id: 'B2C3D4E5F6789ABC',
+ component_name: 'Компонент разработки',
+ component_id: 'A1B2C3D4E5F6789A',
+ is_component: true,
+ vars: {
+ name: 'ВОСХОД',
+ full_abbr_genitive: 'Потребительского Кооператива',
+ full_abbr: 'Потребительский Кооператив',
+ },
+ user: {
+ full_name_or_short_name: 'Иванов Иван Иванович',
+ abbr_full_name: 'Иванов И.И.',
+ email: 'ivanov@example.com',
+ phone: '+7 999 123-45-67',
+ },
+ coop: {
+ short_name: 'ПК "ВОСХОД"',
+ details: {
+ inn: '9728130611',
+ kpp: '772801001',
+ ogrn: '1247700283346',
+ },
+ full_address: '117593, г. МОСКВА, ВН.ТЕР.Г. МУНИЦИПАЛЬНЫЙ ОКРУГ ЯСЕНЕВО, ПРОЕЗД СОЛОВЬИНЫЙ, Д. 1, ПОМЕЩ. 1/1',
+ phone: '+7 902 895-33-75',
+ email: 'chairman.voskhod@gmail.com',
+ defaultBankAccount: {
+ currency: 'RUB',
+ bank_name: 'ПАО Сбербанк',
+ account_number: '40703810038000110117',
+ details: {
+ bik: '044525225',
+ corr: '30101810400000000225',
+ kpp: '772801001',
+ },
+ },
+ chairman: {
+ first_name: 'Алексей',
+ last_name: 'Муравьев',
+ middle_name: 'Николаевич',
+ },
+ city: 'Москва',
+ },
+}
diff --git a/components/cooptypes/src/cooperative/registry/1006.InitProjectDecision/index.ts b/components/cooptypes/src/cooperative/registry/1006.InitProjectDecision/index.ts
new file mode 100644
index 00000000000..8e8773d3aef
--- /dev/null
+++ b/components/cooptypes/src/cooperative/registry/1006.InitProjectDecision/index.ts
@@ -0,0 +1,104 @@
+import type { IDecisionData, IGenerate, IMetaDocument } from '../../document'
+import type { ICooperativeData, IVars } from '../../model'
+
+export const registry_id = 1006
+
+/**
+ * Интерфейс генерации решения совета по инициализации проекта
+ */
+export interface Action extends IGenerate {
+ decision_id: number
+ project_name: string
+ project_id: string
+ component_name: string
+ component_id: string
+ is_component: boolean
+}
+
+export type Meta = IMetaDocument & Action
+
+// Модель данных
+export interface Model {
+ coop: ICooperativeData
+ meta: IMetaDocument
+ decision: IDecisionData
+ vars: IVars
+ project_name: string
+ project_id: string
+ component_name: string
+ component_id: string
+ is_component: boolean
+}
+
+export const title = 'Протокол решения совета об инициализации проекта'
+export const description = 'Форма протокола решения совета об инициализации проекта или компонента'
+export const context = '\n\n\n\n
{{ meta.created_at }}, {{ coop.city }}
\n
\n\n\n| {% trans \'meeting_format\' %} | \n{% trans \'meeting_format_value\' %} | \n
\n\n| {% trans \'meeting_place\' %} | \n{{ coop.full_address }} | \n
\n\n| {% trans \'meeting_date\' %} | \n{{ decision.date }} | \n
\n\n| {% trans \'opening_time\' %} | \n{{ decision.time }} | \n
\n\n
\n
{% trans \'council_members\' %}
\n
\n\n{% for member in coop.members %}\n\n| {% if member.is_chairman %}{% trans \'chairman_of_the_council\' %}{% else %}{% trans \'member_of_the_council\' %}{% endif %} | \n{{ member.last_name }} {{ member.first_name }} {{ member.middle_name }} | \n
\n{% endfor %}\n\n
\n
{% trans \'meeting_legality\' %}
\n
{% trans \'voting_results\', decision.voters_percent %} {% trans \'quorum\' %} {% trans \'chairman_of_the_meeting\', coop.chairman.last_name, coop.chairman.first_name, coop.chairman.middle_name %}.
\n
{% trans \'agenda\' %}
\n
\n\n\n| № | \n{% trans \'question\' %} | \n
\n\n| 1 | \n{% if is_component %}{% trans \'init_component_question\', component_name, component_id, project_name, project_id %}{% else %}{% trans \'init_project_question\', project_name, project_id %}{% endif %} | \n
\n\n
\n
{% trans \'voting\' %}
\n
{% trans \'vote_results\' %}
\n\n\n| {% trans \'votes_for\' %} | \n{{ decision.votes_for }} | \n
\n\n| {% trans \'votes_against\' %} | \n{{ decision.votes_against }} | \n
\n\n| {% trans \'votes_abstained\' %} | \n{{ decision.votes_abstained }} | \n
\n\n
\n
{% trans \'decision_made\' %}
\n
\n\n\n| № | \n{% trans \'decision\' %} | \n
\n\n| 1 | \n{% if is_component %}{% trans \'init_component_decision\', component_name, component_id, project_name, project_id %}{% else %}{% trans \'init_project_decision\', project_name, project_id %}{% endif %} | \n
\n\n
\n
\n
{% trans \'closing_time\', decision.time %}
\n
{% trans \'signature\' %}
{% trans \'chairman\' %} {{ coop.chairman.last_name }} {{ coop.chairman.first_name }} {{ coop.chairman.middle_name }}
\n'
+
+export const translations = {
+ ru: {
+ meeting_format: 'Форма',
+ meeting_date: 'Дата',
+ meeting_place: 'Место',
+ opening_time: 'Время открытия',
+ council_members: 'ЧЛЕНЫ СОВЕТА',
+ voting_results: 'Количество голосов составляет {0}% от общего числа членов Совета.',
+ meeting_legality: 'СОБРАНИЕ ПРАВОМОЧНО',
+ chairman_of_the_meeting: 'Председатель собрания совета: {0} {1} {2}',
+ agenda: 'ПОВЕСТКА ДНЯ',
+ vote_results: 'По первому вопросу повестки дня проголосовали:',
+ decision_made: 'РЕШИЛИ',
+ closing_time: 'Время закрытия собрания совета: {0}.',
+ protocol_number: 'ПРОТОКОЛ № {0}',
+ council_meeting_name: 'Собрания Совета',
+ chairman_of_the_council: 'Председатель совета',
+ signature: 'Документ подписан электронной подписью.',
+ chairman: 'Председатель',
+ quorum: 'Кворум для решения поставленных на повестку дня вопросов имеется.',
+ voting: 'ГОЛОСОВАНИЕ',
+ meeting_format_value: 'Заочная',
+ member_of_the_council: 'Член совета',
+ question: 'Вопрос',
+ votes_for: 'ЗА',
+ votes_against: 'ПРОТИВ',
+ votes_abstained: 'ВОЗДЕРЖАЛСЯ',
+ decision: 'Решение',
+ init_component_question: 'Об инициализации компонента "{0}" (№{1}) как составной части проекта "{2}" (№{3})',
+ init_project_question: 'Об инициализации проекта "{0}" (№{1})',
+ init_component_decision: 'Инициализировать компонент "{0}" (№{1}) как составную часть проекта "{2}" (№{3})',
+ init_project_decision: 'Инициализировать проект "{0}" (№{1})',
+ },
+ // ... другие переводы
+}
+
+export const exampleData = {
+ meta: {
+ created_at: '12.02.2024 00:01',
+ },
+ project_name: 'Проект цифровой платформы',
+ project_id: 'B2C3D4E5F6789ABC',
+ component_name: 'Компонент разработки',
+ component_id: 'A1B2C3D4E5F6789A',
+ is_component: true,
+ coop: {
+ city: 'Москва',
+ full_address: 'Смольная 3-84',
+ chairman: {
+ last_name: 'Муравьев',
+ first_name: 'Алексей',
+ middle_name: 'Николаевич',
+ },
+ },
+ decision: {
+ time: '00:01',
+ date: '12.02.2024',
+ votes_for: '3',
+ votes_against: '0',
+ votes_abstained: '0',
+ voters_percent: '100',
+ id: '1',
+ },
+ vars: {
+ full_abbr_genitive: 'потребительского кооператива',
+ name: 'ВОСХОД',
+ },
+}
diff --git a/components/cooptypes/src/cooperative/registry/index.ts b/components/cooptypes/src/cooperative/registry/index.ts
index 9c22f7c3021..67ceafca42c 100644
--- a/components/cooptypes/src/cooperative/registry/index.ts
+++ b/components/cooptypes/src/cooperative/registry/index.ts
@@ -29,6 +29,8 @@ export * as BlagorostOfferTemplate from './999.BlagorostOfferTemplate'
export * as GenerationAgreementTemplate from './997.GenerationAgreementTemplate'
export * as GenerationAgreement from './1001.GenerationAgreement'
export * as AppendixGenerationAgreement from './1002.AppendixGenerationAgreement'
+export * as InitProjectStatement from './1005.InitProjectStatement'
+export * as InitProjectDecision from './1006.InitProjectDecision'
export * as ExpenseStatement from './1010.ExpenseStatement'
export * as ExpenseDecision from './1011.ExpenseDecision'
diff --git a/components/factory/src/Actions/1005.InitProjectStatement.ts b/components/factory/src/Actions/1005.InitProjectStatement.ts
new file mode 100644
index 00000000000..a06815a60ba
--- /dev/null
+++ b/components/factory/src/Actions/1005.InitProjectStatement.ts
@@ -0,0 +1,50 @@
+import { DraftContract } from 'cooptypes'
+import { InitProjectStatement } from '../Templates'
+import { DocFactory } from '../Factory'
+import type { IGeneratedDocument, IGenerationOptions, IMetaDocument, ITemplate } from '../Interfaces'
+import type { MongoDBConnector } from '../Services/Databazor'
+
+export { InitProjectStatement as Template } from '../Templates'
+
+export class Factory extends DocFactory {
+ constructor(storage: MongoDBConnector) {
+ super(storage)
+ }
+
+ async generateDocument(data: InitProjectStatement.Action, options?: IGenerationOptions): Promise {
+ let template: ITemplate
+
+ if (process.env.SOURCE === 'local') {
+ template = InitProjectStatement.Template
+ }
+ else {
+ template = await this.getTemplate(DraftContract.contractName.production, InitProjectStatement.registry_id, data.block_num)
+ }
+
+ const meta: IMetaDocument = await this.getMeta({ title: template.title, ...data })
+ const coop = await super.getCooperative(data.coopname, data.block_num)
+ const vars = await super.getVars(data.coopname, data.block_num)
+
+ const userData = await super.getUser(data.username, data.block_num)
+ const user = super.getCommonUser(userData)
+
+ const combinedData: InitProjectStatement.Model = {
+ meta,
+ coop,
+ vars,
+ user,
+ project_name: data.project_name,
+ project_id: data.project_id,
+ component_name: data.component_name,
+ component_id: data.component_id,
+ is_component: data.is_component,
+ }
+
+ await this.validate(combinedData, template.model)
+
+ const translation = template.translations[meta.lang]
+ const document: IGeneratedDocument = await this.generatePDF('', template.context, combinedData, translation, meta, options?.skip_save)
+
+ return document
+ }
+}
diff --git a/components/factory/src/Actions/1006.InitProjectDecision.ts b/components/factory/src/Actions/1006.InitProjectDecision.ts
new file mode 100644
index 00000000000..b149c2abbee
--- /dev/null
+++ b/components/factory/src/Actions/1006.InitProjectDecision.ts
@@ -0,0 +1,88 @@
+import { type Cooperative, DraftContract } from 'cooptypes'
+import { DocFactory } from '../Factory'
+import type {
+ IGeneratedDocument,
+ IGenerationOptions,
+ IMetaDocument,
+ ITemplate,
+} from '../Interfaces'
+import type { MongoDBConnector } from '../Services/Databazor'
+
+import { InitProjectDecision } from '../Templates'
+
+export { InitProjectDecision as Template } from '../Templates'
+
+export class Factory extends DocFactory {
+ constructor(storage: MongoDBConnector) {
+ super(storage)
+ }
+
+ async generateDocument(
+ data: InitProjectDecision.Action,
+ options?: IGenerationOptions,
+ ): Promise {
+ let template: ITemplate
+
+ if (process.env.SOURCE === 'local') {
+ template = InitProjectDecision.Template
+ }
+ else {
+ template = await this.getTemplate(DraftContract.contractName.production, InitProjectDecision.registry_id, data.block_num)
+ }
+
+ const user = await this.getUser(data.username, data.block_num)
+
+ const userData = {
+ [user.type]: user.data,
+ }
+
+ const coop = await this.getCooperative(data.coopname, data.block_num)
+
+ // TODO необходимо строго типизировать мета-данные документов друг под друга!
+ const meta: IMetaDocument = await this.getMeta({
+ title: template.title,
+ ...data,
+ }) // Генерируем мета-данные
+
+ const decision: Cooperative.Document.IDecisionData = await this.getDecision(
+ coop,
+ data.coopname,
+ data.decision_id,
+ meta.created_at,
+ )
+
+ const vars = await super.getVars(data.coopname, data.block_num)
+
+ const combinedData: InitProjectDecision.Model = {
+ ...userData,
+ meta,
+ coop,
+ decision,
+ project_name: data.project_name,
+ project_id: data.project_id,
+ component_name: data.component_name,
+ component_id: data.component_id,
+ is_component: data.is_component,
+ vars,
+ }
+
+ // валидируем скомбинированные данные
+ await this.validate(combinedData, template.model)
+
+ // получаем комплекс перевода
+ const translation = template.translations[meta.lang]
+
+ // генерируем документ
+ const document: IGeneratedDocument = await this.generatePDF(
+ '',
+ template.context,
+ combinedData,
+ translation,
+ meta,
+ options?.skip_save,
+ )
+
+ // возвращаем
+ return document
+ }
+}
diff --git a/components/factory/src/Actions/index.ts b/components/factory/src/Actions/index.ts
index b11969e6239..6f973c1a689 100644
--- a/components/factory/src/Actions/index.ts
+++ b/components/factory/src/Actions/index.ts
@@ -25,6 +25,8 @@ export * as ReturnByMoneyDecision from './901.ReturnByMoneyDecision'
export * as BlagorostOffer from './1000.CapitalizationAgreement'
export * as GenerationAgreement from './1001.GenerationAgreement'
export * as AppendixGenerationAgreement from './1002.AppendixGenerationAgreement'
+export * as InitProjectStatement from './1005.InitProjectStatement'
+export * as InitProjectDecision from './1006.InitProjectDecision'
export * as ExpenseStatement from './1010.ExpenseStatement'
export * as ExpenseDecision from './1011.ExpenseDecision'
diff --git a/components/factory/src/Templates/1005.InitProjectStatement.ts b/components/factory/src/Templates/1005.InitProjectStatement.ts
new file mode 100644
index 00000000000..c70bd4817c1
--- /dev/null
+++ b/components/factory/src/Templates/1005.InitProjectStatement.ts
@@ -0,0 +1,41 @@
+import type { JSONSchemaType } from 'ajv'
+import { Cooperative } from 'cooptypes'
+import type { ITemplate } from '../Interfaces'
+import { CooperativeSchema } from '../Schema'
+import { IMetaJSONSchema } from '../Schema/MetaSchema'
+import { VarsSchema } from '../Schema/VarsSchema'
+import { CommonUserSchema } from '../Schema/CommonUserSchema'
+
+export const registry_id = Cooperative.Registry.InitProjectStatement.registry_id
+
+// Модель действия для генерации
+export type Action = Cooperative.Registry.InitProjectStatement.Action
+
+// Модель данных
+export type Model = Cooperative.Registry.InitProjectStatement.Model
+
+// Схема для сверки
+export const Schema: JSONSchemaType = {
+ type: 'object',
+ properties: {
+ meta: IMetaJSONSchema,
+ coop: CooperativeSchema,
+ vars: VarsSchema,
+ user: CommonUserSchema,
+ project_name: { type: 'string' },
+ project_id: { type: 'string' },
+ component_name: { type: 'string' },
+ component_id: { type: 'string' },
+ is_component: { type: 'boolean' },
+ },
+ required: ['meta', 'coop', 'vars', 'user', 'project_name', 'project_id', 'component_name', 'component_id', 'is_component'],
+ additionalProperties: true,
+}
+
+export const Template: ITemplate = {
+ title: Cooperative.Registry.InitProjectStatement.title,
+ description: Cooperative.Registry.InitProjectStatement.description,
+ model: Schema,
+ context: Cooperative.Registry.InitProjectStatement.context,
+ translations: Cooperative.Registry.InitProjectStatement.translations,
+}
diff --git a/components/factory/src/Templates/1006.InitProjectDecision.ts b/components/factory/src/Templates/1006.InitProjectDecision.ts
new file mode 100644
index 00000000000..c2d4b303e4b
--- /dev/null
+++ b/components/factory/src/Templates/1006.InitProjectDecision.ts
@@ -0,0 +1,64 @@
+import type { JSONSchemaType } from 'ajv'
+
+import { Cooperative } from 'cooptypes'
+import type { ITemplate } from '../Interfaces'
+import { IMetaJSONSchema } from '../Schema/MetaSchema'
+import { CooperativeSchema } from '../Schema/CooperativeSchema'
+import { decisionSchema } from '../Schema/DecisionSchema'
+import { VarsSchema } from '../Schema'
+
+export const registry_id = Cooperative.Registry.InitProjectDecision.registry_id
+
+/**
+ * Интерфейс генерации решения совета по инициализации проекта
+ */
+export type Action = Cooperative.Registry.InitProjectDecision.Action
+
+export type Model = Cooperative.Registry.InitProjectDecision.Model
+
+// Схема для сверки
+export const Schema: JSONSchemaType = {
+ type: 'object',
+ properties: {
+ coop: {
+ type: 'object',
+ properties: {
+ ...CooperativeSchema.properties,
+ },
+ required: [...CooperativeSchema.required],
+ additionalProperties: true,
+ },
+ decision: {
+ type: 'object',
+ properties: {
+ ...decisionSchema.properties,
+ },
+ required: [...decisionSchema.required],
+ additionalProperties: true,
+ },
+ meta: {
+ type: 'object',
+ properties: {
+ ...IMetaJSONSchema.properties,
+ },
+ required: [...IMetaJSONSchema.required],
+ additionalProperties: true,
+ },
+ vars: VarsSchema,
+ project_name: { type: 'string' },
+ project_id: { type: 'string' },
+ component_name: { type: 'string' },
+ component_id: { type: 'string' },
+ is_component: { type: 'boolean' },
+ },
+ required: ['meta', 'coop', 'decision', 'project_name', 'project_id', 'component_name', 'component_id', 'is_component'],
+ additionalProperties: true,
+}
+
+export const Template: ITemplate = {
+ title: Cooperative.Registry.InitProjectDecision.title,
+ description: Cooperative.Registry.InitProjectDecision.description,
+ model: Schema,
+ context: Cooperative.Registry.InitProjectDecision.context,
+ translations: Cooperative.Registry.InitProjectDecision.translations,
+}
diff --git a/components/factory/src/Templates/index.ts b/components/factory/src/Templates/index.ts
index 2f388a89c4f..888ae97aad4 100644
--- a/components/factory/src/Templates/index.ts
+++ b/components/factory/src/Templates/index.ts
@@ -27,6 +27,8 @@ export * as BlagorostOfferTemplate from './999.BlagorostOfferTemplate'
export * as BlagorostOffer from './1000.CapitalizationAgreement'
export * as GenerationAgreement from './1001.GenerationAgreement'
export * as AppendixGenerationAgreement from './1002.AppendixGenerationAgreement'
+export * as InitProjectStatement from './1005.InitProjectStatement'
+export * as InitProjectDecision from './1006.InitProjectDecision'
export * as ExpenseStatement from './1010.ExpenseStatement'
export * as ExpenseDecision from './1011.ExpenseDecision'
diff --git a/components/factory/src/Templates/registry.ts b/components/factory/src/Templates/registry.ts
index a2b9837389d..9db0e258b45 100644
--- a/components/factory/src/Templates/registry.ts
+++ b/components/factory/src/Templates/registry.ts
@@ -20,6 +20,8 @@ import * as ReturnByMoney from './900.returnByMoney'
import * as ReturnByMoneyDecision from './901.ReturnByMoneyDecision'
import * as GenerationAgreement from './1001.GenerationAgreement'
import * as AppendixGenerationAgreement from './1002.AppendixGenerationAgreement'
+import * as InitProjectStatement from './1005.InitProjectStatement'
+import * as InitProjectDecision from './1006.InitProjectDecision'
import * as ExpenseStatement from './1010.ExpenseStatement'
import * as ExpenseDecision from './1011.ExpenseDecision'
@@ -95,6 +97,8 @@ export const Registry = {
1000: BlagorostOffer,
1001: GenerationAgreement,
1002: AppendixGenerationAgreement,
+ 1005: InitProjectStatement,
+ 1006: InitProjectDecision,
1010: ExpenseStatement,
1011: ExpenseDecision,
1020: GenerationMoneyInvestStatement,
diff --git a/components/factory/src/index.ts b/components/factory/src/index.ts
index 62ccccbe70e..39176d66e79 100644
--- a/components/factory/src/index.ts
+++ b/components/factory/src/index.ts
@@ -110,6 +110,8 @@ export class Generator implements IGenerator {
[Actions.AssetContributionAct.Template.registry_id]: new Actions.AssetContributionAct.Factory(this.storage), // 702
[Actions.GenerationAgreement.Template.registry_id]: new Actions.GenerationAgreement.Factory(this.storage), // 1001
[Actions.AppendixGenerationAgreement.Template.registry_id]: new Actions.AppendixGenerationAgreement.Factory(this.storage), // 1002
+ [Actions.InitProjectStatement.Template.registry_id]: new Actions.InitProjectStatement.Factory(this.storage), // 1005
+ [Actions.InitProjectDecision.Template.registry_id]: new Actions.InitProjectDecision.Factory(this.storage), // 1006
[Actions.ExpenseStatement.Template.registry_id]: new Actions.ExpenseStatement.Factory(this.storage), // 1010
[Actions.ExpenseDecision.Template.registry_id]: new Actions.ExpenseDecision.Factory(this.storage), // 1011
diff --git a/components/factory/test/documents-1000-plus.test.ts b/components/factory/test/documents-1000-plus.test.ts
index 1d6a2895906..4ee518a44fb 100644
--- a/components/factory/test/documents-1000-plus.test.ts
+++ b/components/factory/test/documents-1000-plus.test.ts
@@ -55,6 +55,35 @@ describe('тест генератора документов с registry_id >= 1
})
})
+ it('генерируем заявление на инициализацию проекта', async () => {
+ await testDocumentGeneration({
+ registry_id: 1005,
+ coopname: 'voskhod',
+ username: 'ant',
+ project_name: 'Проект цифровой платформы',
+ project_id: 'B2C3D4E5F6789ABC',
+ component_name: 'Компонент разработки',
+ component_id: 'A1B2C3D4E5F6789A',
+ is_component: true,
+ lang: 'ru',
+ })
+ })
+
+ it('генерируем решение об инициализации проекта', async () => {
+ await testDocumentGeneration({
+ registry_id: 1006,
+ coopname: 'voskhod',
+ username: 'ant',
+ decision_id: 1,
+ project_name: 'Проект цифровой платформы',
+ project_id: 'B2C3D4E5F6789ABC',
+ component_name: 'Компонент разработки',
+ component_id: 'A1B2C3D4E5F6789A',
+ is_component: true,
+ lang: 'ru',
+ })
+ })
+
// Документы расходов
it('генерируем заявление о расходах', async () => {
await testDocumentGeneration({