Compare commits
220 Commits
main
...
notifications
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a450e2ac6 | |||
| 9fc87a705f | |||
| 305864c1ed | |||
| ad83d9cc77 | |||
| 226c7f9473 | |||
| 137d1ca8a4 | |||
| 59744e9d23 | |||
| ac8836628e | |||
| 1f649c8951 | |||
| 310468fb69 | |||
| 7f782e0a92 | |||
| d0c9f8bffc | |||
| 60a35f6f76 | |||
| a3a2923751 | |||
| 32e6a45f05 | |||
| 59665c6df4 | |||
| d23b4e3aac | |||
| 20897cf199 | |||
| 0b57232606 | |||
| 1bd8f003f7 | |||
| fcb614cd90 | |||
| 1c376c003a | |||
| a433ceaf1d | |||
| 850478b7f7 | |||
| 11a891392e | |||
| 7930ef8ef6 | |||
| 8484a14905 | |||
| e7a0968b94 | |||
| 87241b2de0 | |||
| 4a5fb2af8b | |||
| b9acc67818 | |||
| 5be9fa6ae8 | |||
| e0f8d6a64c | |||
| 2276ab396e | |||
| 9de84afc29 | |||
| 747e567666 | |||
| 675376079e | |||
| 1fa0cee816 | |||
| 6a7f71eb5a | |||
| 6bda6948bf | |||
| abb43b4221 | |||
| 4193c45205 | |||
| 36eb50fef9 | |||
| ad0ebf82ee | |||
| 54d55e288f | |||
| 9fb51b00bd | |||
| d56dcc153a | |||
| d9f421acbd | |||
| 01ec687ba0 | |||
| 0ee1efac4e | |||
| fbf9d514a0 | |||
| be7a9e9e3a | |||
| bc3b3f701f | |||
| 0d8be7a489 | |||
| 2fdeaed3a0 | |||
| 13481d8f95 | |||
| f4b87baa2b | |||
| a337dbceb8 | |||
| 04592a9908 | |||
| 9d204ba496 | |||
| 64dd48b408 | |||
| 515a374f86 | |||
| ddae8d6a53 | |||
| 6e87047e1d | |||
| 62e13853c5 | |||
| a09959d751 | |||
| e2678df443 | |||
| fedec69e44 | |||
| 4ccf2c743c | |||
| 418d43af58 | |||
| 869a75f080 | |||
| c7bc2d1a20 | |||
| 3ea4cd6d73 | |||
| 6a955737e0 | |||
| 51bf49b063 | |||
| 12468b16c8 | |||
| 5ebd28d181 | |||
| defe482ccd | |||
| e99d141f28 | |||
| aa0a6731de | |||
| 46f7f10dce | |||
| 552333faf6 | |||
| e23589d4d3 | |||
| 104b08e1ba | |||
| 1b81cfc0a9 | |||
| 6e51433ae9 | |||
| 421f356987 | |||
| abd9f1931d | |||
| 2b87034abb | |||
| 8d7c919332 | |||
| 4785ea2886 | |||
| 4daa06dac1 | |||
| abc253f47d | |||
| 5fea2f8f34 | |||
| c29e224f2f | |||
| b930543c2b | |||
| 2768d72e90 | |||
| 8ccefe8fac | |||
| c93e59908d | |||
| 22f0fd8a10 | |||
| 8e17d96529 | |||
| 494a164ee8 | |||
| ee28ae1719 | |||
| 3266061359 | |||
| f69d849c4f | |||
| 2628120e35 | |||
| edf7d9ab62 | |||
| 2095e448e5 | |||
| beff507f4a | |||
| bf4fbfabac | |||
| 2f1d88a74c | |||
| b444004f4a | |||
| 6862f2881a | |||
| 73afcabee2 | |||
| b4168a4053 | |||
| 1fe14d5811 | |||
| 89e5c97ef8 | |||
| 258b8304ff | |||
| 69fe9c1348 | |||
| fa4af94fa0 | |||
| 2ac84a6910 | |||
| 3f79cf9a1b | |||
| c155605ca8 | |||
| 80a94f79da | |||
| 89ba6cb356 | |||
| c7bd0326ba | |||
| 2c551a0d9e | |||
| ba103a969e | |||
| 0d9177f98f | |||
| 60c32be299 | |||
| 83c107b8b2 | |||
| b6d582fb2c | |||
| a5818bdc53 | |||
| de0fe5465f | |||
| d43b188a30 | |||
| bfb2be2a72 | |||
| 73c2cd9cb3 | |||
| 61cfc442ef | |||
| 0ed04c2c27 | |||
| 6773509ede | |||
| acd86df785 | |||
| c554b167b3 | |||
| 18cf7b61e3 | |||
| e42b396a68 | |||
| c47e61d42a | |||
| 92559370fa | |||
| c3a2ec46b3 | |||
| fe55d23e65 | |||
| b0d4f5d542 | |||
| be48f7a158 | |||
| 83bd744100 | |||
| ff1615f7b1 | |||
| 696e1a0d2c | |||
| 397670473a | |||
| cab8061bc3 | |||
| 3c2b9bcb4c | |||
| 7a274b7ab1 | |||
| e524244bab | |||
| 14ecaf259a | |||
| 749c13dc91 | |||
| ab2ee4cc92 | |||
| 2907352d61 | |||
| 390b995eb6 | |||
| 24b3dd3c60 | |||
| 55444a4b72 | |||
| 76854207a7 | |||
| 4fcd700e39 | |||
| 05dfcced1b | |||
| 931c366907 | |||
| 71d35b74d7 | |||
| 21fac5c7df | |||
| 0ba9d55081 | |||
| b5b388e95d | |||
| 9c643395b3 | |||
| b989074170 | |||
| 261f010a49 | |||
| af46867939 | |||
| be2355e5c5 | |||
| 8b4a20ed3f | |||
| 1ab1e1d3c5 | |||
| c9aab02aab | |||
| 0643604778 | |||
| fe79f3ff98 | |||
| f919a14927 | |||
| dda389ad75 | |||
| aa42864029 | |||
| 41bb17224a | |||
| fd6f628c43 | |||
| 28ca615d96 | |||
| 76203a88d8 | |||
| aa891adddf | |||
| ecdac6fff9 | |||
| bcba24ea5e | |||
| 44b1f423cc | |||
| 85cc7361d7 | |||
| e5e28ff652 | |||
| 4957182480 | |||
| 84927e943a | |||
| 0d06114f00 | |||
| 2654760e16 | |||
| d02e7ba2be | |||
| e18fd94336 | |||
| 03e2410556 | |||
| 0f1f34f621 | |||
| c08473618f | |||
| 3b4fb195bb | |||
| 827eb10cc2 | |||
| 6e7c60de6e | |||
| 54a4449e0b | |||
| 08c31171a0 | |||
| a6011f5d46 | |||
| a1300e2b3c | |||
| 8f58672403 | |||
| b8d048bf3c | |||
| bb7b650ebc | |||
| 5253de9279 | |||
| 094945e350 | |||
| eb6b58e6db | |||
| 7bcb6e30a7 | |||
| 44ab386835 |
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"agentCanUpdateSnapshot": true
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
description:
|
||||
globs: components/controller/**
|
||||
alwaysApply: false
|
||||
---
|
||||
# NestJS Controller и Чистая архитектура
|
||||
|
||||
## Основные принципы
|
||||
1. Чистая архитектура - главный архитектурный подход. Пиши код с комментариями.
|
||||
2. Типы IName, IChecksum256, ITimePointSec - это просто строки.
|
||||
3. Домен должен быть полностью изолирован от инфраструктурных деталей.
|
||||
4. Направление зависимостей - внутрь (к ядру, домену).
|
||||
5. Домен, инфраструктура и приложение связаны через App.module, НЕ НУЖНО импортировать их друг в друга, а достаточно просто импортировать домен на уровне приложения чтобы использовать все экспорты домена.
|
||||
|
||||
## Структура проекта
|
||||
- `domain/` - доменный слой (бизнес-логика, независимая от инфраструктуры)
|
||||
- `infrastructure/` - инфраструктурный слой (адаптеры к внешним системам)
|
||||
- `modules/` - слой приложения (DTO, резолверы, сервисы)
|
||||
|
||||
## Слои и их взаимодействие
|
||||
1. **Домен**:
|
||||
- Содержит чистые доменные интерфейсы и реализованные на них сущности
|
||||
- НЕ должен зависеть от `cooptypes` (инфраструктурный контракт)
|
||||
- Использует собственные доменные типы (например, Date вместо строковых timestamp)
|
||||
- Интерфейсы портов описывают взаимодействие с внешними системами
|
||||
|
||||
2. **Инфраструктура**:
|
||||
- Содержит адаптеры к внешним системам (блокчейн, БД и т.д.)
|
||||
- Осуществляет преобразование между доменными и инфраструктурными типами
|
||||
- Общая логика преобразования выносится в утилитарные классы (например, `DomainToBlockchainUtils`)
|
||||
|
||||
3. **Модули (приложение)**:
|
||||
- DTO имплементируют доменные интерфейсы напрямую
|
||||
- Резолвер вызывает сервис, который принимает DTO
|
||||
- Сервис передает объекты DTO в интерактор домена
|
||||
|
||||
## Поток данных
|
||||
1. Резолвер принимает входные данные и передает их в сервис
|
||||
2. Сервис вызывает интерактор домена, передавая ему объекты DTO (имплементирующие доменный интерфейс)
|
||||
3. Интерактор выполняет бизнес-логику и взаимодействует с портами домена
|
||||
4. Адаптеры (инфраструктурный слой) преобразуют доменные объекты в формат внешних систем (JSON для хранения мета-данных, ISO для дат и т.д.)
|
||||
5. Адаптеры возвращают результаты в домен, домен возвращает данные в сервис, который возвращает их в резолвер
|
||||
|
||||
## Правила преобразования данных
|
||||
1. Преобразование DTO → доменный объект: не требуется, если DTO имплементирует доменный интерфейс
|
||||
2. Преобразование доменный объект → инфраструктурный тип: происходит в адаптерах
|
||||
3. Преобразование документов, дат и других сложных объектов: используются утилитарные классы уровня инфраструктуры
|
||||
|
||||
## Работа с типами данных
|
||||
1. **Даты**:
|
||||
- В доменных интерфейсах используется тип `Date`
|
||||
- В DTO используется тип `Date` с декораторами `@IsDate()` и `@Type(() => Date)`
|
||||
- В инфраструктурном слое происходит преобразование `Date` → `string` (ISO формат)
|
||||
```typescript
|
||||
// Доменный интерфейс
|
||||
interface MeetDomainInterface {
|
||||
open_at: Date;
|
||||
}
|
||||
|
||||
// DTO
|
||||
@Field(() => Date)
|
||||
@IsDate()
|
||||
@Type(() => Date)
|
||||
open_at!: Date;
|
||||
|
||||
// Адаптер
|
||||
const blockchainData = {
|
||||
open_at: domainToBlockchainUtils.convertDateToBlockchainFormat(data.open_at)
|
||||
};
|
||||
```
|
||||
|
||||
2. **Документы**:
|
||||
- В доменных интерфейсах используется собственный тип `SignedDocumentDomainInterface<T>`
|
||||
- В DTO используется соответствующий DTO-класс (например, `SignedDigitalDocumentInputDTO`)
|
||||
- В инфраструктурном слое происходит преобразование между форматами (meta-поля в JSON и т.д.)
|
||||
|
||||
## Типовые ошибки
|
||||
1. **Нарушение изоляции домена**: домен должен быть изолирован от инфраструктуры. Не используйте импорты из `cooptypes` в доменных интерфейсах.
|
||||
```typescript
|
||||
// Неправильно
|
||||
import { MeetContract } from 'cooptypes';
|
||||
export type VoteDomainInterface = MeetContract.Actions.Vote.IInput;
|
||||
|
||||
// Правильно
|
||||
export interface VoteDomainInterface {
|
||||
coopname: string;
|
||||
hash: string;
|
||||
// ... доменные поля
|
||||
}
|
||||
```
|
||||
|
||||
2. **Преобразование в неправильном слое**: преобразование доменных объектов в инфраструктурные типы должно происходить в адаптерах, а не в доменном слое или сервисе.
|
||||
```typescript
|
||||
// Неправильно (в доменном интеракторе)
|
||||
async vote(data: VoteDomainInterface) {
|
||||
const blockchainData = { ...data, meta: JSON.stringify(data.meta) };
|
||||
// ...
|
||||
}
|
||||
|
||||
// Правильно (в адаптере)
|
||||
async vote(data: VoteDomainInterface) {
|
||||
const blockchainData = this.convertToBlockchainFormat(data);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
3. **Дублирование логики преобразования**: общая логика преобразования должна быть вынесена в утилитарные классы.
|
||||
```typescript
|
||||
// Неправильно (дублирование в разных адаптерах)
|
||||
// В MeetAdapter
|
||||
private convertDoc(doc) { return { ...doc, meta: JSON.stringify(doc.meta) }; }
|
||||
// В BranchAdapter
|
||||
private convertDoc(doc) { return { ...doc, meta: JSON.stringify(doc.meta) }; }
|
||||
|
||||
// Правильно (общий утилитарный класс)
|
||||
// DomainToBlockchainUtils
|
||||
convertSignedDocumentToBlockchainFormat(doc) {
|
||||
return { ...doc, meta: JSON.stringify(doc.meta) };
|
||||
}
|
||||
```
|
||||
|
||||
## Примеры
|
||||
```typescript
|
||||
// Доменный интерфейс - чистый, без зависимостей от инфраструктуры
|
||||
export interface VoteOnAnnualGeneralMeetInputDomainInterface {
|
||||
coopname: string;
|
||||
hash: string;
|
||||
member: string;
|
||||
ballot: VoteItemInputDomainInterface[];
|
||||
}
|
||||
|
||||
// DTO имплементирует доменный интерфейс напрямую
|
||||
@InputType('VoteOnAnnualGeneralMeetInput')
|
||||
export class VoteOnAnnualGeneralMeetInputDTO implements VoteOnAnnualGeneralMeetInputDomainInterface {
|
||||
@Field(() => String)
|
||||
@IsString()
|
||||
coopname!: string;
|
||||
// ... остальные поля
|
||||
}
|
||||
|
||||
// Адаптер преобразует доменный объект в инфраструктурный тип
|
||||
async vote(data: VoteOnAnnualGeneralMeetInputDomainInterface): Promise<TransactionResult> {
|
||||
// Преобразуем доменный объект в инфраструктурный тип
|
||||
const blockchainData: MeetContract.Actions.Vote.IInput = {
|
||||
coopname: data.coopname,
|
||||
hash: data.hash,
|
||||
// ... преобразование других полей
|
||||
};
|
||||
// ... отправка данных во внешнюю систему
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
description: SDK мутации и запросы для подключения на рабочем столе
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
Бэкенд реализован здесь components/controller, sdk здесь components/sdk.
|
||||
|
||||
Пример создания Query к API через SDK:
|
||||
|
||||
``` ts
|
||||
async function loadBranches(data: IGetBranchesInput): Promise<IBranch[]> {
|
||||
const { [Queries.Branches.GetBranches.name]: output } = await client.Query(
|
||||
Queries.Branches.GetBranches.query,
|
||||
{
|
||||
variables: {
|
||||
data
|
||||
}
|
||||
}
|
||||
);
|
||||
return output;
|
||||
}
|
||||
```
|
||||
|
||||
Такие запросы обычно хранятся в папке Entities и вызываются из его store.
|
||||
|
||||
Пример мутации:
|
||||
|
||||
``` ts
|
||||
async function selectBranch(data: ISelectBranchInput): Promise<boolean>{
|
||||
const {[Mutations.Branches.SelectBranch.name]: result} = await client.Mutation(Mutations.Branches.SelectBranch.mutation, {variables: {
|
||||
data
|
||||
}})
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
Мутации обычно храним в папке features.
|
||||
|
||||
Как можешь обратить внимание, все мутации и запросы строятся по одному шаблону. Вся необходимая информация уже есть в SDK.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# DESKTOP
|
||||
|
||||
- Пишем код фронтенда в архитектуре Feature Sliced Design (FSD).
|
||||
- Стиль шаблонов PUG на composite API.
|
||||
- Всегда создаём index.ts файлы для vue компонент.
|
||||
- Создавай индексные файлы для vue через export {default as NAME} from './where', а на уровне выше, если это необходимо, делай export * from './ui'
|
||||
- Всегда удаляем неиспользуемые импорты.
|
||||
- Не используем emit избыточно. Вместо них используем композабл функции моделей фич, если необходимо. Emit только в крайнем случае.
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Структура файлов шаблонов документов и алгоритм правки
|
||||
|
||||
## Основные директории и файлы
|
||||
|
||||
### 1. Определение типов и интерфейсов (cooptypes)
|
||||
**Путь:** `/cooptypes/src/cooperative/registry/[ID.DocumentName]/index.ts`
|
||||
|
||||
В этих файлах определяются:
|
||||
- Интерфейсы данных (`IAgendaMeet`, etc.)
|
||||
- Основная модель данных документа (`Model`)
|
||||
- HTML шаблон документа (`context`)
|
||||
- Переводы строк (`translations`)
|
||||
- Пример данных для тестирования (`exampleData`)
|
||||
|
||||
**Для изменения шаблона нужно править:**
|
||||
- Интерфейсы модели данных при изменении структуры
|
||||
- HTML в переменной `context` для изменения внешнего вида
|
||||
- Строки переводов в `translations.ru`
|
||||
|
||||
### 2. Схемы валидации (factory)
|
||||
**Путь:** `/factory/src/Schema/[SchemaName].ts`
|
||||
|
||||
Содержат:
|
||||
- JSON схемы для валидации данных
|
||||
- Определение обязательных полей
|
||||
|
||||
**При изменении структуры данных:**
|
||||
- Обновите соответствующую схему валидации
|
||||
- Обновите список обязательных полей в `required`
|
||||
|
||||
### 3. Фабрики документов (factory)
|
||||
**Путь:** `/factory/src/Actions/[ID.DocumentName].ts`
|
||||
|
||||
Обрабатывают:
|
||||
- Получение данных из разных источников
|
||||
- Сборку модели для шаблонизатора
|
||||
- Валидацию данных по схеме
|
||||
- Генерацию PDF
|
||||
|
||||
**При изменении логики сборки документа:**
|
||||
- Обновите метод `generateDocument()`
|
||||
- Добавьте новые источники данных
|
||||
|
||||
### 4. Шаблоны (factory)
|
||||
**Путь:** `/factory/src/Templates/[ID.DocumentName].ts`
|
||||
|
||||
Связывают:
|
||||
- Шаблон из cooptypes
|
||||
- Схему валидации
|
||||
- Метаданные документа
|
||||
|
||||
**После изменения в cooptypes:**
|
||||
- Убедитесь, что схема в Templates соответствует новой модели
|
||||
|
||||
### 5. Тесты (factory)
|
||||
**Путь:** `/factory/test/[category].test.ts`
|
||||
|
||||
Содержат:
|
||||
- Тестовые данные для генерации документов
|
||||
- Вызовы функции `testDocumentGeneration`
|
||||
|
||||
**После внесения изменений:**
|
||||
- Обновите тестовые данные в соответствии с новой структурой
|
||||
- Запустите тесты командой `pnpm test`
|
||||
|
||||
## Алгоритм внесения изменений
|
||||
|
||||
1. **Модификация типов**
|
||||
- Изменить файл в `/cooptypes/src/cooperative/registry/[ID.DocumentName]/index.ts`
|
||||
- Обновить интерфейсы, шаблон HTML и переводы
|
||||
|
||||
2. **Обновление схемы валидации**
|
||||
- Изменить соответствующую схему в `/factory/src/Schema/`
|
||||
- Убедиться, что обязательные поля совпадают с интерфейсом
|
||||
|
||||
3. **Компиляция библиотеки типов**
|
||||
- Выполнить `cd /cooptypes && pnpm build`
|
||||
|
||||
4. **Обновление тестовых данных**
|
||||
- Привести тестовые данные в соответствие с новой структурой
|
||||
|
||||
5. **Запуск тестов**
|
||||
- Выполнить `cd /factory && pnpm test [filename].test.ts`
|
||||
|
||||
## Особенности шаблонизации
|
||||
|
||||
- Используется Nunjucks для шаблонов
|
||||
- Поддерживаются конструкции: `{% if %}`, `{% for %}`, `{% trans %}`
|
||||
- Переменные вставляются через `{{ variable }}`
|
||||
- Переводы через `{% trans 'KEY' %}`
|
||||
@@ -0,0 +1,225 @@
|
||||
# Архитектура расширений в MonoCoop
|
||||
|
||||
## Основные принципы
|
||||
1. Расширения построены на модулях NestJS с использованием шаблона "Порты и адаптеры"
|
||||
2. Каждое расширение наследуется от `BaseExtModule` и реализует интерфейс `OnModuleInit`
|
||||
3. Расширения могут взаимодействовать с блокчейном через соответствующие порты
|
||||
4. Конфигурации расширений хранятся в БД и описываются с помощью Zod-схем
|
||||
5. Расширения регистрируются в глобальном реестре `AppRegistry`
|
||||
|
||||
## Структура расширения
|
||||
Минимальная структура расширения включает:
|
||||
- `XXX-extension.module.ts` - основной модуль расширения
|
||||
- `package.json` - информация о пакете
|
||||
- `README.md` - документация
|
||||
- `INSTALL.md` - инструкции по установке
|
||||
- `CHANGELOG.md` - история изменений
|
||||
|
||||
## Создание нового расширения
|
||||
1. Создайте директорию для расширения в `components/controller/src/extensions/`
|
||||
2. Создайте основной класс расширения, наследующийся от `BaseExtModule`
|
||||
3. Определите Zod-схему для конфигурации
|
||||
4. Реализуйте метод `initialize()`
|
||||
5. Зарегистрируйте расширение в `extensions.registry.ts`
|
||||
6. Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`
|
||||
|
||||
## Пример структуры модуля расширения
|
||||
```typescript
|
||||
// XXX-extension.module.ts
|
||||
export class XXXPlugin extends BaseExtModule {
|
||||
constructor(...) {
|
||||
super();
|
||||
}
|
||||
|
||||
name = 'xxx';
|
||||
plugin!: ExtensionDomainEntity<IConfig>;
|
||||
public configSchemas = Schema;
|
||||
|
||||
async initialize() {
|
||||
// Инициализация расширения
|
||||
// Настройка cron-задач
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [XXXPlugin],
|
||||
})
|
||||
export class XXXPluginModule {
|
||||
constructor(private readonly xxxPlugin: XXXPlugin) {}
|
||||
|
||||
async initialize() {
|
||||
await this.xxxPlugin.initialize();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Управление отображением конфигурации
|
||||
Zod-схемы используются для автоматического отображения формы настроек в интерфейсе пользователя.
|
||||
Через интерфейс `DeserializedDescriptionOfExtension` из `components/controller/src/types/shared/extension.types.ts`
|
||||
можно управлять отображением полей формы:
|
||||
|
||||
```typescript
|
||||
export const Schema = z.object({
|
||||
// Базовое поле с меткой
|
||||
simpleField: z.string().describe(
|
||||
describeField({
|
||||
label: 'Название поля',
|
||||
note: 'Подсказка под полем'
|
||||
})
|
||||
),
|
||||
|
||||
// Скрытое поле для служебного использования
|
||||
hiddenField: z.string().describe(
|
||||
describeField({
|
||||
label: 'Скрытое поле',
|
||||
visible: false
|
||||
})
|
||||
),
|
||||
|
||||
// Поле с проверкой значения
|
||||
validatedField: z.number().describe(
|
||||
describeField({
|
||||
label: 'Поле с валидацией',
|
||||
rules: ['val >= 5', 'val <= 100'],
|
||||
})
|
||||
),
|
||||
|
||||
// Форматированное поле с префиксом и суффиксом
|
||||
formattedField: z.number().describe(
|
||||
describeField({
|
||||
label: 'Форматированное поле',
|
||||
prepend: '$',
|
||||
append: 'USD',
|
||||
})
|
||||
),
|
||||
|
||||
// Многострочное текстовое поле
|
||||
multilineField: z.string().describe(
|
||||
describeField({
|
||||
label: 'Многострочное поле',
|
||||
maxRows: 5,
|
||||
minLength: 10,
|
||||
maxLength: 1000
|
||||
})
|
||||
),
|
||||
});
|
||||
```
|
||||
|
||||
Доступные поля для управления отображением:
|
||||
- `label` - название поля (обязательное)
|
||||
- `note` - пояснение или подсказка
|
||||
- `visible` - видимость поля (по умолчанию true)
|
||||
- `rules` - правила валидации в виде строковых выражений
|
||||
- `mask` - маска для ввода
|
||||
- `fillMask` - автозаполнение маски
|
||||
- `minLength` / `maxLength` - ограничения длины для текстовых полей
|
||||
- `maxRows` - количество строк для многострочного ввода
|
||||
- `append` / `prepend` - текст до/после значения поля
|
||||
|
||||
## Взаимодействие с блокчейном
|
||||
Для взаимодействия с блокчейном:
|
||||
1. Определите порт в доменном слое (например, `SovietBlockchainPort`)
|
||||
2. Инжектируйте порт в конструкторе расширения через DI
|
||||
3. Используйте методы порта для взаимодействия с блокчейном
|
||||
|
||||
```typescript
|
||||
@Inject(SOVIET_BLOCKCHAIN_PORT) private readonly sovietBlockchainPort: SovietBlockchainPort
|
||||
// ...
|
||||
const decisions = await this.sovietBlockchainPort.getDecisions(coopname);
|
||||
```
|
||||
|
||||
## Настройка планировщика задач
|
||||
Расширения могут использовать cron-задачи для периодического выполнения операций:
|
||||
|
||||
```typescript
|
||||
import cron from 'node-cron';
|
||||
|
||||
// Регистрация cron-задачи (каждые N минут)
|
||||
const cronExpression = `*/${this.plugin.config.checkInterval} * * * *`;
|
||||
cron.schedule(cronExpression, () => {
|
||||
this.logger.info('Запуск запланированной задачи');
|
||||
this.runTask();
|
||||
});
|
||||
```
|
||||
|
||||
## Работа с конфигурацией
|
||||
1. Определите Zod-схему для конфигурации
|
||||
2. Используйте `describeField` для добавления UI-метаданных к полям
|
||||
3. Получайте и обновляйте конфигурацию через репозиторий `extensionRepository`
|
||||
|
||||
```typescript
|
||||
export const Schema = z.object({
|
||||
checkInterval: z.number().describe(
|
||||
describeField({
|
||||
label: 'Интервал проверки (в минутах)',
|
||||
note: 'Минимум: 5 минут',
|
||||
rules: ['val >= 5'],
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
// Обновление конфигурации
|
||||
this.plugin.config.lastCheckDate = new Date().toISOString();
|
||||
await this.extensionRepository.update(this.plugin);
|
||||
```
|
||||
|
||||
## Логирование действий
|
||||
Расширения должны логировать свои действия:
|
||||
1. Используйте `WinstonLoggerService` для системного логирования
|
||||
2. Используйте `LogExtensionDomainRepository` для хранения логов в БД
|
||||
|
||||
```typescript
|
||||
// Системное логирование
|
||||
this.logger.info(`Выполнение операции для ${id}`);
|
||||
|
||||
// Сохранение лога в БД
|
||||
await this.logExtensionRepository.push(this.name, {
|
||||
type: 'operation',
|
||||
timestamp: new Date().toISOString(),
|
||||
data: { ... },
|
||||
});
|
||||
```
|
||||
|
||||
## Регистрация расширения
|
||||
После создания расширения, добавьте его в `extensions.registry.ts`:
|
||||
|
||||
```typescript
|
||||
export const AppRegistry: INamedExtension = {
|
||||
myExtension: {
|
||||
is_builtin: false,
|
||||
is_internal: true,
|
||||
is_available: true,
|
||||
is_desktop: false,
|
||||
title: 'Моё расширение',
|
||||
description: 'Описание функциональности.',
|
||||
image: 'https://example.com/image.png',
|
||||
class: MyExtensionPluginModule,
|
||||
schema: MyExtensionSchema,
|
||||
tags: ['тег1', 'тег2'],
|
||||
readme: getReadmeContent('./myExtension'),
|
||||
instructions: getInstructionsContent('./myExtension'),
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Дефолтные настройки
|
||||
Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`:
|
||||
|
||||
```typescript
|
||||
getDefaultApps(): Partial<ExtensionDomainEntity>[] {
|
||||
return [
|
||||
// ...
|
||||
{
|
||||
name: 'myExtension',
|
||||
enabled: true,
|
||||
config: {
|
||||
// Дефолтные значения конфигурации
|
||||
parameter1: 'value1',
|
||||
parameter2: 42,
|
||||
},
|
||||
},
|
||||
// ...
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
---
|
||||
description:
|
||||
globs: **/controller/src/extensions/**
|
||||
alwaysApply: false
|
||||
---
|
||||
# Архитектура расширений в MonoCoop
|
||||
|
||||
## Основные принципы
|
||||
1. Расширения построены на модулях NestJS с использованием шаблона "Порты и адаптеры"
|
||||
2. Каждое расширение наследуется от `BaseExtModule` и реализует интерфейс `OnModuleInit`
|
||||
3. Расширения могут взаимодействовать с блокчейном через соответствующие порты
|
||||
4. Конфигурации расширений хранятся в БД и описываются с помощью Zod-схем
|
||||
5. Расширения регистрируются в глобальном реестре `AppRegistry`
|
||||
|
||||
## Структура расширения
|
||||
Минимальная структура расширения включает:
|
||||
- `XXX-extension.module.ts` - основной модуль расширения
|
||||
- `package.json` - информация о пакете
|
||||
- `README.md` - документация
|
||||
- `INSTALL.md` - инструкции по установке
|
||||
- `CHANGELOG.md` - история изменений
|
||||
|
||||
## Создание нового расширения
|
||||
1. Создайте директорию для расширения в `components/controller/src/extensions/`
|
||||
2. Создайте основной класс расширения, наследующийся от `BaseExtModule`
|
||||
3. Определите Zod-схему для конфигурации
|
||||
4. Реализуйте метод `initialize()`
|
||||
5. Зарегистрируйте расширение в `extensions.registry.ts`
|
||||
6. Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`
|
||||
|
||||
## Пример структуры модуля расширения
|
||||
```typescript
|
||||
// XXX-extension.module.ts
|
||||
export class XXXPlugin extends BaseExtModule {
|
||||
constructor(...) {
|
||||
super();
|
||||
}
|
||||
|
||||
name = 'xxx';
|
||||
plugin!: ExtensionDomainEntity<IConfig>;
|
||||
public configSchemas = Schema;
|
||||
|
||||
async initialize() {
|
||||
// Инициализация расширения
|
||||
// Настройка cron-задач
|
||||
}
|
||||
|
||||
// Дополнительные методы расширения
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [XXXPlugin],
|
||||
})
|
||||
export class XXXPluginModule {
|
||||
constructor(private readonly xxxPlugin: XXXPlugin) {}
|
||||
|
||||
async initialize() {
|
||||
await this.xxxPlugin.initialize();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Взаимодействие с блокчейном
|
||||
Для взаимодействия с блокчейном:
|
||||
1. Определите порт в доменном слое (например, `SovietBlockchainPort`)
|
||||
2. Инжектируйте порт в конструкторе расширения через DI
|
||||
3. Используйте методы порта для взаимодействия с блокчейном
|
||||
|
||||
```typescript
|
||||
@Inject(SOVIET_BLOCKCHAIN_PORT) private readonly sovietBlockchainPort: SovietBlockchainPort
|
||||
// ...
|
||||
const decisions = await this.sovietBlockchainPort.getDecisions(coopname);
|
||||
```
|
||||
|
||||
## Настройка планировщика задач
|
||||
Расширения могут использовать cron-задачи для периодического выполнения операций:
|
||||
|
||||
```typescript
|
||||
import cron from 'node-cron';
|
||||
|
||||
// Регистрация cron-задачи (каждые N минут)
|
||||
const cronExpression = `*/${this.plugin.config.checkInterval} * * * *`;
|
||||
cron.schedule(cronExpression, () => {
|
||||
this.logger.info('Запуск запланированной задачи');
|
||||
this.runTask();
|
||||
});
|
||||
```
|
||||
|
||||
## Работа с конфигурацией
|
||||
1. Определите Zod-схему для конфигурации
|
||||
2. Используйте `describeField` для добавления UI-метаданных к полям
|
||||
3. Получайте и обновляйте конфигурацию через репозиторий `extensionRepository`
|
||||
|
||||
```typescript
|
||||
export const Schema = z.object({
|
||||
checkInterval: z.number().describe(
|
||||
describeField({
|
||||
label: 'Интервал проверки (в минутах)',
|
||||
note: 'Минимум: 5 минут',
|
||||
rules: ['val >= 5'],
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
// Обновление конфигурации
|
||||
this.plugin.config.lastCheckDate = new Date().toISOString();
|
||||
await this.extensionRepository.update(this.plugin);
|
||||
```
|
||||
|
||||
## Логирование действий
|
||||
Расширения должны логировать свои действия:
|
||||
1. Используйте `WinstonLoggerService` для системного логирования
|
||||
2. Используйте `LogExtensionDomainRepository` для хранения логов в БД
|
||||
|
||||
```typescript
|
||||
// Системное логирование
|
||||
this.logger.info(`Выполнение операции для ${id}`);
|
||||
|
||||
// Сохранение лога в БД
|
||||
await this.logExtensionRepository.push(this.name, {
|
||||
type: 'operation',
|
||||
timestamp: new Date().toISOString(),
|
||||
data: { ... },
|
||||
});
|
||||
```
|
||||
|
||||
## Регистрация расширения
|
||||
После создания расширения, добавьте его в `extensions.registry.ts`:
|
||||
|
||||
```typescript
|
||||
export const AppRegistry: INamedExtension = {
|
||||
myExtension: {
|
||||
is_builtin: false,
|
||||
is_internal: true,
|
||||
is_available: true,
|
||||
is_desktop: false,
|
||||
title: 'Моё расширение',
|
||||
description: 'Описание функциональности.',
|
||||
image: 'https://example.com/image.png',
|
||||
class: MyExtensionPluginModule,
|
||||
schema: MyExtensionSchema,
|
||||
tags: ['тег1', 'тег2'],
|
||||
readme: getReadmeContent('./myExtension'),
|
||||
instructions: getInstructionsContent('./myExtension'),
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Дефолтные настройки
|
||||
Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`:
|
||||
|
||||
```typescript
|
||||
getDefaultApps(): Partial<ExtensionDomainEntity>[] {
|
||||
return [
|
||||
// ...
|
||||
{
|
||||
name: 'myExtension',
|
||||
enabled: true,
|
||||
config: {
|
||||
// Дефолтные значения конфигурации
|
||||
parameter1: 'value1',
|
||||
parameter2: 42,
|
||||
},
|
||||
},
|
||||
// ...
|
||||
];
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,261 @@
|
||||
---
|
||||
description:
|
||||
globs: src/**/*.ts
|
||||
alwaysApply: false
|
||||
---
|
||||
# Фабрика Документов Кооперативов
|
||||
|
||||
## Общая Архитектура
|
||||
|
||||
Фабрика документов — это система генерации PDF документов для кооперативов, построенная на TypeScript с использованием MongoDB для хранения данных. Система состоит из трех основных частей:
|
||||
|
||||
1. **registry/** — JSON-шаблоны документов (статические данные)
|
||||
2. **factory/** — основная фабрика с логикой генерации
|
||||
3. **cooptypes/** — типы данных и интерфейсы
|
||||
|
||||
## Структура Registry
|
||||
|
||||
В корневой папке `registry/` находятся JSON файлы с номерными названиями, представляющие шаблоны документов:
|
||||
|
||||
### Основные документы:
|
||||
- `1.walletProgramAgreement.json` — соглашение о кошельке
|
||||
- `2.regulationElectronicSignature.json` — регламент электронной подписи
|
||||
- `3.privacyPolicy.json` — политика конфиденциальности
|
||||
- `4.userAgreement.json` — пользовательское соглашение
|
||||
- `50.CoopenomicsAgreement.json` — соглашение с партнерами
|
||||
- `100.participantApplication.json` — заявление участника
|
||||
- `101.selectBranchStatement.json` — заявление о выборе филиала
|
||||
|
||||
### Документы общих собраний (300-304):
|
||||
- `300.annualGeneralMeetingAgenda.json` — предложение повестки дня
|
||||
- `301.annualGeneralMeetingSovietDecision.json` — протокол заседания совета
|
||||
- `302.annualGeneralMeetingNotification.json` — уведомление о собрании
|
||||
- `303.annualGeneralMeetingVotingBallot.json` — бюллетень для голосования
|
||||
- `304.annualGeneralMeetingDecision.json` — протокол общего собрания
|
||||
|
||||
### Инвестиционные документы (1000+):
|
||||
- `1000.investAgreement.json` — инвестиционное соглашение
|
||||
- `1001.investByResultStatement.json` — заявление о зачете по результатам
|
||||
- `1002.investByResultAct.json` — акт зачета по результатам
|
||||
- `1005.investByMoneyStatement.json` — заявление о зачете денежных средств
|
||||
|
||||
### Структура JSON-шаблона:
|
||||
```json
|
||||
{
|
||||
"context": "<div>...HTML шаблон с переменными...</div>",
|
||||
"model": {...данные для примера...},
|
||||
"translation": {...переводы ключей...},
|
||||
"object_model": {...схема объектной модели...}
|
||||
}
|
||||
```
|
||||
|
||||
## Фабрика (factory/)
|
||||
|
||||
### Основные компоненты:
|
||||
|
||||
#### src/index.ts — Главный класс Generator
|
||||
```typescript
|
||||
export class Generator implements IGenerator {
|
||||
// Хранилище фабрик для каждого типа документа
|
||||
factories: { [K in Numbers]: DocFactory<IGenerate> }
|
||||
|
||||
// MongoDB коннектор
|
||||
public storage: MongoDBConnector
|
||||
|
||||
// Основной метод генерации
|
||||
async generate(data: IGenerate, options?: IGenerationOptions): Promise<IGeneratedDocument>
|
||||
}
|
||||
```
|
||||
|
||||
#### Архитектура Factory Pattern:
|
||||
- Базовый класс `DocFactory<T>` в `src/Factory/index.ts`
|
||||
- Каждый документ имеет свою фабрику в `src/Actions/`
|
||||
- Фабрики наследуются от `DocFactory` и реализуют метод `generateDocument()`
|
||||
|
||||
### Сервисы:
|
||||
|
||||
#### Services/Generator/ — PDF генерация
|
||||
- `PDFService` — конвертирует HTML в PDF через WeasyPrint
|
||||
- Использует шрифт Arial (base64)
|
||||
- Добавляет метаданные в PDF
|
||||
- Вычисляет SHA-256 хеш документа
|
||||
|
||||
#### Services/Templator/ — Шаблонизация
|
||||
- Основан на Nunjucks
|
||||
- Поддерживает кастомное расширение `{% trans %}` для переводов
|
||||
- Рендерит HTML из шаблона с подстановкой переменных
|
||||
|
||||
#### Services/Validator/ — Валидация
|
||||
- Использует AJV для JSON Schema валидации
|
||||
- Поддерживает кастомные форматы (телефон)
|
||||
- Локализация ошибок на русском языке
|
||||
|
||||
#### Services/Databazor/ — База данных
|
||||
- `MongoDBConnector` — работа с MongoDB
|
||||
- `DataService` — абстракция над данными
|
||||
- Коллекции: `deltas`, `actions`, `documents`, и другие
|
||||
|
||||
### Модели данных (src/Models/):
|
||||
|
||||
#### Основные типы пользователей:
|
||||
- `Individual` — физические лица (ФИО, паспорт, адрес)
|
||||
- `Organization` — организации (ИНН, ОГРН, представитель)
|
||||
- `Entrepreneur` — ИП (ФИО + ИНН/ОГРН)
|
||||
|
||||
#### Кооперативные данные:
|
||||
- `Cooperative` — данные кооператива
|
||||
- `PaymentMethod` — платежные методы
|
||||
- `Vars` — переменные кооператива
|
||||
- `Project` — проекты
|
||||
|
||||
### Система Action-ов:
|
||||
|
||||
Каждый документ имеет Action класс в `src/Actions/` с методом `generateDocument()`:
|
||||
|
||||
1. **Получение шаблона** — из локального Registry или MongoDB
|
||||
2. **Сбор данных** — пользователь, кооператив, переменные, специфичные данные
|
||||
3. **Валидация** — проверка по JSON схеме
|
||||
4. **Рендеринг** — HTML из шаблона + данные
|
||||
5. **PDF генерация** — HTML → PDF с метаданными
|
||||
6. **Сохранение** — в MongoDB (если не skip_save)
|
||||
|
||||
## Система типов (cooptypes/)
|
||||
|
||||
### cooperative/registry/ — Типы документов
|
||||
Каждый документ имеет папку с интерфейсами:
|
||||
- `Action` — входные данные для генерации
|
||||
- `Model` — модель данных для шаблона
|
||||
- `Template` — структура шаблона
|
||||
|
||||
### contracts/ — Блокчейн контракты
|
||||
- `registrator/` — регистрация кооперативов
|
||||
- `soviet/` — управление советом
|
||||
- `meet/` — общие собрания
|
||||
- `wallet/`, `capital/`, `fund/` — финансовые операции
|
||||
|
||||
## База данных MongoDB
|
||||
|
||||
### Основные коллекции:
|
||||
|
||||
#### deltas — Состояние блокчейна
|
||||
```javascript
|
||||
{
|
||||
block_num: number,
|
||||
present: boolean,
|
||||
code: string, // название контракта
|
||||
scope: string, // область действия
|
||||
table: string, // имя таблицы
|
||||
primary_key: string,
|
||||
value: {...} // данные записи
|
||||
}
|
||||
```
|
||||
|
||||
#### actions — Действия блокчейна
|
||||
```javascript
|
||||
{
|
||||
block_num: number,
|
||||
account: string,
|
||||
name: string, // имя действия
|
||||
receiver: string,
|
||||
data: {...} // данные действия
|
||||
}
|
||||
```
|
||||
|
||||
#### documents — Сгенерированные документы
|
||||
```javascript
|
||||
{
|
||||
hash: string, // SHA-256 хеш
|
||||
binary: Uint8Array, // PDF данные
|
||||
html: string, // HTML исходник
|
||||
meta: { // метаданные
|
||||
title: string,
|
||||
created_at: string,
|
||||
lang: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Таблицы данных:
|
||||
- `coops` — кооперативы
|
||||
- `meets` — собрания
|
||||
- `questions` — вопросы собраний
|
||||
- `decisions` — решения совета
|
||||
- `individuals` — физические лица
|
||||
- `organizations` — организации
|
||||
- `entrepreneurs` — ИП
|
||||
- `paymentMethods` — платежные методы
|
||||
- `vars` — переменные кооперативов
|
||||
|
||||
## Генерация документов
|
||||
|
||||
### Процесс генерации:
|
||||
1. **Вызов** `generator.generate(action, options)`
|
||||
2. **Поиск фабрики** по `registry_id`
|
||||
3. **Загрузка шаблона** (локально или из БД)
|
||||
4. **Сбор данных** из MongoDB по `coopname`, `username`, `block_num`
|
||||
5. **Создание модели** — объединение всех данных
|
||||
6. **Валидация** модели по JSON схеме
|
||||
7. **Рендеринг HTML** через Nunjucks
|
||||
8. **Генерация PDF** через WeasyPrint
|
||||
9. **Добавление метаданных** в PDF
|
||||
10. **Вычисление хеша** SHA-256
|
||||
11. **Сохранение** в MongoDB
|
||||
|
||||
### Пример использования:
|
||||
```typescript
|
||||
const generator = new Generator()
|
||||
await generator.connect(mongoUri)
|
||||
|
||||
const document = await generator.generate({
|
||||
registry_id: '300',
|
||||
coopname: 'voskhod',
|
||||
username: 'ant',
|
||||
block_num: 0,
|
||||
meet: {...},
|
||||
questions: [...]
|
||||
})
|
||||
```
|
||||
|
||||
## Особенности реализации
|
||||
|
||||
### Шаблонизация:
|
||||
- HTML шаблоны с CSS стилями
|
||||
- Переменные в формате `{{variable.field}}`
|
||||
- Условная логика `{% if condition %}`
|
||||
- Циклы `{% for item in array %}`
|
||||
- Переводы `{% trans 'KEY', var1, var2 %}`
|
||||
|
||||
### Подписи:
|
||||
- Цифровые подписи вместо физических
|
||||
- Текст "Подписано электронной подписью"
|
||||
- Убраны подчеркивания для подписей
|
||||
|
||||
### Типы собраний:
|
||||
- `regular` — очередное
|
||||
- `extraordinary` — внеочередное
|
||||
- Условная логика в шаблонах
|
||||
|
||||
### Филиалы:
|
||||
- `coop.is_branched` — проверка на наличие филиалов
|
||||
- "пайщиков" vs "уполномоченных" в зависимости от типа
|
||||
|
||||
### Форматирование дат:
|
||||
- Формат: "г. Москва, 15 декабря 2024 г."
|
||||
- Без кавычек вокруг дат
|
||||
- Запятая после города
|
||||
|
||||
## Тестирование
|
||||
|
||||
### test/utils/index.ts — Тестовые утилиты:
|
||||
- `preLoading()` — инициализация тестовых данных
|
||||
- Создание кооператива, пользователей, платежных методов
|
||||
- Настройка данных собраний и решений
|
||||
- Очистка временных файлов
|
||||
|
||||
### Тестовые данные:
|
||||
- Кооператив "ВОСХОД"
|
||||
- Пользователи: ant, individual, entrepreneur
|
||||
- Организации: voskhod, branch, exampleorg
|
||||
- Собрания с вопросами и решениями
|
||||
|
||||
Фабрика поддерживает полный цикл создания документов кооператива от заявлений до протоколов собраний с возможностью кастомизации под разные типы кооперативов и требования.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
description:
|
||||
globs: components/sdk/**
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Руководство по работе с GraphQL Zeus в SDK
|
||||
|
||||
## Основной процесс
|
||||
|
||||
1. **Анализ DTO бэкенда**:
|
||||
- Изучите структуру DTO классов (`@ObjectType`) в бэкенде
|
||||
- Обратите внимание на имена типов в декораторах `@ObjectType('ИмяТипа')`
|
||||
- Отметьте поля, связи и вложенные объекты
|
||||
|
||||
2. **Создание селекторов**:
|
||||
- Для каждого DTO создайте соответствующий селектор с именем `raw<ИмяТипа>Selector`
|
||||
- Селектор - это объект, где ключи соответствуют полям DTO, а значения - `true`
|
||||
- Для вложенных объектов используйте вложенные селекторы: `field: nestedSelector`
|
||||
- Для списков используйте один селектор без массива: `items: itemSelector`
|
||||
|
||||
3. **Валидация селекторов**:
|
||||
- Для каждого селектора создайте проверку типа:
|
||||
```typescript
|
||||
const _validate: MakeAllFieldsRequired<ValueTypes['ТочноеИмяГрафКьЭлТипа']> = rawSelector
|
||||
```
|
||||
- Имя типа должно точно совпадать с именем в декораторе `@ObjectType`
|
||||
|
||||
4. **Экспорт селекторов**:
|
||||
- Создайте финальный селектор с помощью функции `Selector`:
|
||||
```typescript
|
||||
export const typeSelector = Selector('ТочноеИмяГрафКьЭлТипа')(rawTypeSelector)
|
||||
```
|
||||
- Экспортируйте сырой селектор для переиспользования
|
||||
- Экспортируйте тип модели: `export type modelType = ModelTypes['ТочноеИмяГрафКьЭлТипа']`
|
||||
|
||||
5. **Создание запросов/мутаций**:
|
||||
- Используйте селекторы в запросах и мутациях:
|
||||
```typescript
|
||||
export const query = Selector('Query')({
|
||||
queryName: [{ data: $('data', 'ТочноеИмяВходногоТипа!') }, exportedSelector]
|
||||
})
|
||||
```
|
||||
- Для параметров используйте оператор `$` с точным именем входного типа
|
||||
- Создайте интерфейс входных данных:
|
||||
```typescript
|
||||
export interface IInput {
|
||||
data: ModelTypes['ТочноеИмяВходногоТипа']
|
||||
}
|
||||
```
|
||||
|
||||
## Особенности работы
|
||||
|
||||
- **Документы**: всегда сохраняйте структуру `{ hash, signatures, rawDocument }`
|
||||
- **Сложные DTO**: разбивайте на атомарные селекторы и комбинируйте их
|
||||
- **Типы в Zeus**: часто отличаются от имен классов в бэкенде, всегда проверяйте в `schema.gql`
|
||||
- **Массивы**: Zeus автоматически обрабатывает массивы, не используйте `[selector]`
|
||||
|
||||
Это руководство поможет правильно структурировать работу с SDK и избежать типичных ошибок при работе с Zeus.
|
||||
@@ -0,0 +1,99 @@
|
||||
name: Build Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- testnet
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Debug info
|
||||
run: |
|
||||
echo "Текущая ветка:"
|
||||
git branch --show-current
|
||||
echo "Последние коммиты:"
|
||||
git log -n 3 --oneline
|
||||
echo "Проверяем файлы в директории components/desktop/src-ssr:"
|
||||
ls -la components/desktop/src-ssr/ || echo "Директория не найдена!"
|
||||
echo "Проверяем файлы в middlewares:"
|
||||
ls -la components/desktop/src-ssr/middlewares/ || echo "Директория middlewares не найдена!"
|
||||
|
||||
- name: Set docker tag
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
echo "DOCKER_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "DOCKER_TAG=latest" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Сначала собираем базовый образ с runtime
|
||||
- name: Build base image
|
||||
run: |
|
||||
docker build --target runtime -t dicoop/mono-base:${{ env.DOCKER_TAG }} .
|
||||
docker push dicoop/mono-base:${{ env.DOCKER_TAG }}
|
||||
|
||||
# Создаем сервисные образы на основе базового
|
||||
- name: Build desktop image
|
||||
run: |
|
||||
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.desktop
|
||||
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/desktop\", \"run\", \"start\"]" >> Dockerfile.desktop
|
||||
docker build -t dicoop/desktop:${{ env.DOCKER_TAG }} -f Dockerfile.desktop .
|
||||
docker push dicoop/desktop:${{ env.DOCKER_TAG }}
|
||||
|
||||
- name: Build controller image
|
||||
run: |
|
||||
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.coopback
|
||||
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/controller\", \"run\", \"start\"]" >> Dockerfile.coopback
|
||||
docker build -t dicoop/coopback:${{ env.DOCKER_TAG }} -f Dockerfile.coopback .
|
||||
docker push dicoop/coopback:${{ env.DOCKER_TAG }}
|
||||
|
||||
- name: Build parser image
|
||||
run: |
|
||||
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.cooparser
|
||||
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/parser\", \"run\", \"start\"]" >> Dockerfile.cooparser
|
||||
docker build -t dicoop/cooparser:${{ env.DOCKER_TAG }} -f Dockerfile.cooparser .
|
||||
docker push dicoop/cooparser:${{ env.DOCKER_TAG }}
|
||||
|
||||
- name: Build notificator image
|
||||
run: |
|
||||
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.notificator
|
||||
echo "CMD [\"pnpm\", \"-F\", \"coop-notificator\", \"run\", \"start\"]" >> Dockerfile.notificator
|
||||
docker build -t dicoop/notificator:${{ env.DOCKER_TAG }} -f Dockerfile.notificator .
|
||||
docker push dicoop/notificator:${{ env.DOCKER_TAG }}
|
||||
|
||||
# Отправка хука для деплоя
|
||||
- name: Trigger deployment webhook
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/latest ]]; then
|
||||
# Хук для тестнета
|
||||
curl -X POST ${{ vars.TESTNET_WEBHOOK_URL }} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '${{ env.DOCKER_TAG }}'
|
||||
elif [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
# Хук для продакшена
|
||||
curl -X POST ${{ vars.PRODUCTION_WEBHOOK_URL }} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '${{ env.DOCKER_TAG }}'
|
||||
else
|
||||
# Хук для тестнета (обычная ветка)
|
||||
curl -X POST ${{ vars.TESTNET_WEBHOOK_URL }} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '${{ env.DOCKER_TAG }}'
|
||||
fi
|
||||
@@ -0,0 +1,93 @@
|
||||
name: Publish Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
build-and-publish-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
- name: Install Python requirements
|
||||
run: |
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install mkdocs-material mkdocs-macros-plugin mkdocs-section-index pymdown-extensions
|
||||
working-directory: ./components/docs
|
||||
|
||||
- name: Install Node.js dependencies
|
||||
run: pnpm install
|
||||
working-directory: ./components/docs
|
||||
|
||||
- name: Patch spectaql-config.yml for CI
|
||||
run: |
|
||||
sed -i.bak "0,/url:.*/s|url:.*|url: 'https://testnet.coopenomics.world/backend/v1/graphql'|" spectaql-config.yml
|
||||
working-directory: ./components/controller
|
||||
|
||||
- name: Show patched spectaql-config.yml
|
||||
run: cat spectaql-config.yml
|
||||
working-directory: ./components/controller
|
||||
|
||||
- name: Build cooptypes
|
||||
run: pnpm run build
|
||||
working-directory: ./components/cooptypes
|
||||
|
||||
- name: Generate controller docs
|
||||
run: pnpm run docs
|
||||
working-directory: ./components/controller
|
||||
|
||||
- name: Copy controller docs
|
||||
run: |
|
||||
mkdir -p ./components/docs/docs/graphql
|
||||
cp -r ./components/controller/docs/* ./components/docs/docs/graphql/
|
||||
|
||||
- name: Generate sdk docs
|
||||
run: pnpm run docs
|
||||
working-directory: ./components/sdk
|
||||
|
||||
- name: Copy sdk docs
|
||||
run: |
|
||||
mkdir -p ./components/docs/docs/sdk
|
||||
cp -r ./components/sdk/docs/* ./components/docs/docs/sdk/
|
||||
|
||||
- name: Generate cooptypes docs
|
||||
run: pnpm run docs
|
||||
working-directory: ./components/cooptypes
|
||||
|
||||
- name: Copy cooptypes docs
|
||||
run: |
|
||||
mkdir -p ./components/docs/docs/cooptypes
|
||||
cp -r ./components/cooptypes/docs/* ./components/docs/docs/cooptypes/
|
||||
|
||||
- name: Build docs (mkdocs)
|
||||
run: |
|
||||
source venv/bin/activate
|
||||
mkdocs build
|
||||
working-directory: ./components/docs
|
||||
|
||||
- name: Publish to GitHub Pages
|
||||
run: npx gh-pages --nojekyll -d site --repo https://x-access-token:${GITHUB_TOKEN}@github.com/coopenomics/mono.git
|
||||
working-directory: ./components/docs
|
||||
env:
|
||||
GIT_AUTHOR_NAME: github-actions
|
||||
GIT_AUTHOR_EMAIL: github-actions@github.com
|
||||
GIT_COMMITTER_NAME: github-actions
|
||||
GIT_COMMITTER_EMAIL: github-actions@github.com
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Publish Packages
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build all packages
|
||||
run: pnpm lerna run build
|
||||
|
||||
- name: Publish to npm
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: pnpm lerna publish from-package --yes --no-verify-access
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
node_modules/
|
||||
lerna-debug.log
|
||||
components/controller/graph.png
|
||||
wallet-data/
|
||||
blockchain-data/
|
||||
blockchain-data/
|
||||
scripts/changelog-prompt.md
|
||||
scripts/changelog-release.md
|
||||
scripts/release-info.md
|
||||
|
||||
Vendored
+8
-3
@@ -1,14 +1,19 @@
|
||||
{
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.guides.bracketPairs": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||
// "editor.formatOnSave": true,
|
||||
// "editor.codeActionsOnSave": {
|
||||
// "source.addMissingImports.ts": "explicit",
|
||||
// "source.fixAll.ts": "explicit",
|
||||
// "source.fixAll.eslint": "explicit"
|
||||
// },
|
||||
"eslint.run": "onType",
|
||||
"eslint.validate": ["javascript", "typescript", "vue"],
|
||||
// "typescript.tsdk": "node_modules/typescript/lib",
|
||||
"i18n-ally.localesPaths": ["src/i18n"],
|
||||
"typescript.format.enable": true,
|
||||
"typescript.format.indentSwitchCase": false,
|
||||
"typescript.validate.enable": true,
|
||||
"notebook.defaultFormatter": "Vue.volar"
|
||||
}
|
||||
|
||||
+139
@@ -1,8 +1,147 @@
|
||||
# v2025.7.1-1
|
||||
|
||||
В этом релизе реализованы механизмы возврата паевого взноса пайщика и инструменты управления этим процессом для членов совета. Также внесены визуальные доработки интерфейсов для улучшения восприятия информации.
|
||||
|
||||
✨ Новые функции
|
||||
- [#276](https://github.com/coopenomics/mono/issues/276): Реализовать путь возврата паевого взноса из кошелька пайщика
|
||||
- [#281](https://github.com/coopenomics/mono/issues/281): Генерация заявления на возврат паевого взноса
|
||||
- [#282](https://github.com/coopenomics/mono/issues/282): Генерация решения совета на возврат паевого взноса
|
||||
- [#278](https://github.com/coopenomics/mono/issues/278): Введение методов управления возвратами паевых взносов в контроллере
|
||||
- [#279](https://github.com/coopenomics/mono/issues/279): Отобразить исходящие платежи с кнопками управления в реестре платежей для совета
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#286](https://github.com/coopenomics/mono/issues/286): Поправить ошибки склонений времени
|
||||
- [#262](https://github.com/coopenomics/mono/issues/262): Баг: рабочий стол совета включается, однако, страница всегда открывается со стола пайщика
|
||||
- [#261](https://github.com/coopenomics/mono/issues/261): Баг: первая загрузка переадресует на главную страницу всегда - прямой переход на собрание становится недоступен.
|
||||
|
||||
🔧 Улучшения
|
||||
- [#285](https://github.com/coopenomics/mono/issues/285): Корректировка дизайна кошелька, профиля, повестки совета, реестра документов, реестра платежей
|
||||
- [#284](https://github.com/coopenomics/mono/issues/284): Разместить кошелек на главную вместо профиля
|
||||
- [#283](https://github.com/coopenomics/mono/issues/283): Ввести лоадер на переходе между рабочими столами
|
||||
- [#280](https://github.com/coopenomics/mono/issues/280): Мигрировать имеющиеся данные о входящих платежах в новую модель
|
||||
- [#277](https://github.com/coopenomics/mono/issues/277): Рефакторинг модуля платежей: переход на унифицированную модель входящего и исходящего платежа
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# v2025.6.14
|
||||
|
||||
Разработан модуль для проведения очередных общих собраний пайщиков. Исправлены баги, внесены улучшения пользовательского интерфейса.
|
||||
|
||||
✨ Новые функции
|
||||
- [#264](https://github.com/coopenomics/mono/issues/264): Разработан смарт-контракт общего собрания пайщиков (meet)
|
||||
- [#263](https://github.com/coopenomics/mono/issues/263): Реализован модуль оповещений на электронные почты по жизненному циклу общего собрания пайщиков
|
||||
- [#273](https://github.com/coopenomics/mono/issues/273): Встроены реальные шаблоны документов общего собрания
|
||||
- [#268](https://github.com/coopenomics/mono/issues/268): Добавлена страница результатов общего собрания
|
||||
- [#267](https://github.com/coopenomics/mono/issues/267): Добавлена страница просмотра и скачивания бюллетеней и уведомлений по собранию
|
||||
- [#270](https://github.com/coopenomics/mono/issues/270): Ссылка в оповещении ведет на страницу собрания с документом-уведомлением для подписи
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#262](https://github.com/coopenomics/mono/issues/262): Исправлено некорректное открытие рабочего стола совета
|
||||
- [#261](https://github.com/coopenomics/mono/issues/261): Исправлена ошибка с редиректом при первой загрузке и прямом переходе на собрание
|
||||
- [#259](https://github.com/coopenomics/mono/issues/259): Исправлены отступы в мобильной карточке пайщика
|
||||
- [#258](https://github.com/coopenomics/mono/issues/258): Убран hover-эффект на документе и пайщике в таблице
|
||||
|
||||
🔧 Улучшения
|
||||
- [#274](https://github.com/coopenomics/mono/issues/274): Настроена рассылка оповещений на почту при получении решения о проведении собрания
|
||||
- [#272](https://github.com/coopenomics/mono/issues/272): Подписанные уведомления сохраняются и извлекаются из реестра по Graph-QL
|
||||
- [#271](https://github.com/coopenomics/mono/issues/271): Ведется подсчет количества пайщиков в каждом кооперативе при добавлении и удалении
|
||||
- [#260](https://github.com/coopenomics/mono/issues/260): Введен счетчик количества пайщиков в кооперативе на контракте регистратора
|
||||
- [#256](https://github.com/coopenomics/mono/issues/256): Отображается статус членства каждого пайщика
|
||||
- [#255](https://github.com/coopenomics/mono/issues/255): В разделе Платежи отображается ФИО/Наименование плательщика
|
||||
- [#269](https://github.com/coopenomics/mono/issues/269): Реализована рассылка уведомлений перед началом собрания
|
||||
- [#265](https://github.com/coopenomics/mono/issues/265): Проведена отладка и тестирование процесса общего собрания пайщиков
|
||||
- [#266](https://github.com/coopenomics/mono/issues/266): Протестированы все процессы общего собрания
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# v2025.5.14
|
||||
|
||||
В этом релизе реализован новый стандарт передачи и хранения документов по блокчейну с поддержкой неограниченного количества подписей и их валидацией. Также внесены улучшения в интерфейс и исправлены ошибки.
|
||||
|
||||
✨ Новые функции
|
||||
- [#252](https://github.com/coopenomics/mono/issues/252): Внедрение обновленного стандарта хранения и передачи документов по блокчейну
|
||||
- [#251](https://github.com/coopenomics/mono/issues/251): Реализация версионированного мигратора данных для контроллера кооператива
|
||||
- [#244](https://github.com/coopenomics/mono/issues/244): Обновление стандарта сборки документов и переход на хэш-идентификаторы
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#249](https://github.com/coopenomics/mono/issues/249): Исправлена спутанная маршрутизация между рабочими столами кооперативов
|
||||
- [#253](https://github.com/coopenomics/mono/issues/253): Исправлена избыточная точность суммы оплаты в заявлении на вступление
|
||||
|
||||
🔧 Улучшения
|
||||
- [#259](https://github.com/coopenomics/mono/issues/259): Исправлены отступы в мобильной карточке пайщика на странице пайщиков
|
||||
- [#258](https://github.com/coopenomics/mono/issues/258): Удалён hover-эффект для документов и пайщиков в таблице
|
||||
- [#257](https://github.com/coopenomics/mono/issues/257): Добавлено сохранение светлой/тёмной темы в localStorage и восстановление при загрузке страницы
|
||||
- [#256](https://github.com/coopenomics/mono/issues/256): Отображение статуса членства каждого пайщика в разделе "Пайщики"
|
||||
- [#255](https://github.com/coopenomics/mono/issues/255): Отображение ФИО/Наименования плательщика в разделе "Платежи"
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# v2025.5.2
|
||||
|
||||
В этом релизе рабочие столы переведены на серверный рендеринг, что улучшает стабильность развертывания и упрощает автоматизацию поставки ПО. Данный релиз является подготовительным к переходу на новый стандарт цифровых документов на платформе.
|
||||
|
||||
✨ Новые функции
|
||||
- [#245](https://github.com/coopenomics/mono/issues/245): Перевод десктопа на серверный рендеринг с поддержкой динамических переменных окружения
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#247](https://github.com/coopenomics/mono/issues/247): Исправлен баг с повторной поставкой ПО при обрывах соединения между серверами
|
||||
|
||||
🔧 Улучшения
|
||||
- [#246](https://github.com/coopenomics/mono/issues/246): Перевод CI/CD на сборку и поставку предсобранных докер-контейнеров
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# MONO v2025.4.29
|
||||
|
||||
В этом релизе реализована новая архитектура рабочих столов с установкой через маркетплейс. Добавлены стол пайщика и стол совета, переработаны разделы документов и подписей, улучшено разделение кошелька и профиля для повышения удобства пользователей.
|
||||
|
||||
✨ Новые функции
|
||||
- [#234](https://github.com/coopenomics/mono/issues/234): Маркетплейс рабочих столов с поддержкой разных ролей и микросервисной архитектурой
|
||||
- [#238](https://github.com/coopenomics/mono/issues/238): Контроллер общего собрания пайщиков с поддержкой документооборота и подписей
|
||||
- [#233](https://github.com/coopenomics/mono/issues/233): Минимальный смарт-контракт общих собраний пайщиков
|
||||
- [#232](https://github.com/coopenomics/mono/issues/232): Бэкенд полного обозревателя блоков
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#231](https://github.com/coopenomics/mono/issues/231): Исправления ошибок регистрации, выхода из системы, отображения платежей и редактирования организации
|
||||
|
||||
🔧 Улучшения
|
||||
- [#243](https://github.com/coopenomics/mono/issues/243): Контроль прав доступа на получении документов пайщика
|
||||
- [#242](https://github.com/coopenomics/mono/issues/242): Бесконечный скролл на документах пайщика и кооператива
|
||||
- [#241](https://github.com/coopenomics/mono/issues/241): Раздел "Документы" для пайщика
|
||||
- [#240](https://github.com/coopenomics/mono/issues/240): Множественные подписи на одном документе
|
||||
- [#239](https://github.com/coopenomics/mono/issues/239): Последовательные методы подписи протокола общего собрания
|
||||
- [#237](https://github.com/coopenomics/mono/issues/237): Мобильная вёрстка на страницах стола совета
|
||||
- [#236](https://github.com/coopenomics/mono/issues/236): Пересобран лендинг для MONO
|
||||
- [#235](https://github.com/coopenomics/mono/issues/235): Настроен флоу гитхаб-релизов с описаниями
|
||||
- [#226](https://github.com/coopenomics/mono/issues/226): Встроено редактирование пайщиков
|
||||
- [#224](https://github.com/coopenomics/mono/issues/224): Добавлено ТЗ по контракту капитализации
|
||||
|
||||
---
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add Zeus type ([7bcb6e3](https://github.com/coopenomics/mono/commit/7bcb6e30a77b0ab89c5293188b58f08f19c8761e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
+34
-1
@@ -1,10 +1,43 @@
|
||||
FROM node:18-alpine
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Сразу копируем все файлы
|
||||
COPY . .
|
||||
|
||||
# Устанавливаем инструменты
|
||||
RUN npm install -g pnpm lerna
|
||||
|
||||
# Установка зависимостей
|
||||
# Используем версию pnpm, совместимую с существующим lock-файлом
|
||||
RUN pnpm install
|
||||
|
||||
# Установка системных зависимостей для WeasyPrint
|
||||
RUN apk add --no-cache \
|
||||
python3 \
|
||||
py3-pip \
|
||||
gcc \
|
||||
musl-dev \
|
||||
python3-dev \
|
||||
pango \
|
||||
zlib-dev \
|
||||
jpeg-dev \
|
||||
openjpeg-dev \
|
||||
g++ \
|
||||
libffi-dev \
|
||||
harfbuzz-subset \
|
||||
&& python3 -m venv /venv \
|
||||
&& /venv/bin/pip install WeasyPrint==62.3 \
|
||||
&& rm -rf /var/cache/*
|
||||
|
||||
# Сборка всех компонентов
|
||||
RUN lerna run build
|
||||
|
||||
# Финальный образ
|
||||
FROM builder AS runtime
|
||||
|
||||
# Настройка переменных окружения
|
||||
ENV PATH="/venv/bin:$PATH"
|
||||
|
||||
# Проверка WeasyPrint
|
||||
RUN weasyprint --version
|
||||
@@ -1,55 +1,135 @@
|
||||
# MONO
|
||||
|
||||
Система управления взаимоотношениями в кооперативе. Включает в себя полный комплект программного обеспечения для подключения к платформе "Кооперативная Экономика" и управления взаимоотношениями с пайщиками в кооперативе и самим кооперативом на основе смарт-контрактов и простой электронной подписи.
|
||||
|
||||
## Ветки
|
||||
- Для разработки используется ветка `dev`.
|
||||
|
||||
- Для разработки используется ветка `dev`.
|
||||
- Для стейджа используется ветка `testnet`.
|
||||
- Для продакшена используется ветка `main`.
|
||||
|
||||
## Установка
|
||||
```
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
Также для работы потребуется установленная фабрика документов `weasyprint` для вашей операционной системы: <https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation>
|
||||
|
||||
## Конфигурация
|
||||
|
||||
Для конфигурации потребуетcя установленный `docker` и `docker-compose`. Выполните команду и следуйте инструкциям:
|
||||
|
||||
```
|
||||
```sh
|
||||
pnpm run setup
|
||||
```
|
||||
|
||||
## Запуск
|
||||
|
||||
### Инфраструктура
|
||||
Для работы системы необходимы базы `mongo`, `postgres` и `redis`.
|
||||
|
||||
Для работы системы необходимы базы `mongo`, `postgres` и `redis`.
|
||||
|
||||
Команда запуска баз данных в контейнерах для работы в фоновом режиме:
|
||||
```
|
||||
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Блокчейн и контракты
|
||||
```
|
||||
|
||||
```sh
|
||||
pnpm boot
|
||||
```
|
||||
Команда запустит блокчейн и установит все смарт-контракты, подготовив систему к локальной разработке или применению.
|
||||
|
||||
Команда запустит блокчейн и установит все смарт-контракты, подготовив систему к локальной разработке или применению.
|
||||
|
||||
### Бэкенд
|
||||
```
|
||||
|
||||
```sh
|
||||
pnpm run dev:backend
|
||||
```
|
||||
|
||||
Команда запустит набор сервисов бэкенда и точку доступа GraphQL-API на 2998 порту.
|
||||
|
||||
### Фронтенд
|
||||
|
||||
Команда запустит рабочий стол кооператива на 3005 порту:
|
||||
|
||||
```
|
||||
```sh
|
||||
pnpm run dev:desktop
|
||||
```
|
||||
|
||||
### Очистка базы
|
||||
|
||||
Команда очистит базу mongodb и начнет производство блоков с начала:
|
||||
|
||||
```sh
|
||||
pnpm run clear
|
||||
```
|
||||
|
||||
Правильная последовательность команд при переустановке проекта "с нуля":
|
||||
|
||||
```sh
|
||||
git pull
|
||||
pnpm install
|
||||
pnpm run setup
|
||||
pnpm run clear
|
||||
pnpm run boot
|
||||
pnpm run dev:backend
|
||||
pnpm run dev:desktop
|
||||
```
|
||||
|
||||
### Кошелёк
|
||||
Для работы с кошельком блокчейна используется утилита cleos, которая позволяет извлекать таблицы смарт-контрактов и отправлять транзакции в блокчейн если это требуется.
|
||||
|
||||
Для работы с командным кошельком `cleos` локально необходимо чтобы инфраструктура была поднята:
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Запускаем контейнер с кошельком и входим в него командой:
|
||||
|
||||
```
|
||||
pnpm run cleos
|
||||
```
|
||||
|
||||
В кошельке уже находится дефолтный ключ для работы с локальной средой. Этот ключ зашифрован паролем. Пароль хранится в файле `password` и используется автоматически при разблокировке. Для разблокировки кошелька, находясь в контейнере выполняем:
|
||||
|
||||
```
|
||||
./unlock.sh
|
||||
```
|
||||
|
||||
Для использования кошелька выполняем:
|
||||
```
|
||||
./cleos.sh <command>
|
||||
```
|
||||
|
||||
Для получения полного списка команд вызываем кошелек без команд:
|
||||
```
|
||||
./cleos.sh
|
||||
```
|
||||
|
||||
Например, для получения информации о текущем состоянии блокчейна:
|
||||
```
|
||||
./cleos.sh get info
|
||||
```
|
||||
|
||||
### Возможные проблемы
|
||||
В случае, если при выполнении ./unlock.sh возникает проблема:
|
||||
`Unable to connect to keosd, if keosd is running please kill the process and try again`, то выполните команду:
|
||||
|
||||
```
|
||||
./reset.sh
|
||||
```
|
||||
|
||||
Данная команда удалит созданный ранее сокет кошелька, после чего, выполните ./unlock.sh повторно.
|
||||
|
||||
## Лицензия
|
||||
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
|
||||
|
||||
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
|
||||
|
||||
Разрешено делиться, копировать и распространять материал на любом носителе и форме, адаптировать, делать ремиксы, видоизменять и создавать новое, опираясь на этот материал. При использовании, Вы должны обеспечить указание авторства, предоставить ссылку, и обозначить изменения, если таковые были сделаны. Если вы перерабатываете, преобразовываете материал или берёте его за основу для производного произведения, вы должны распространять переделанные вами части материала на условиях той же лицензии , в соответствии с которой распространяется оригинал. Запрещено коммерческое использование материала. Использование в коммерческих целях – это использование, в первую очередь направленное на получение коммерческого преимущества или денежного вознаграждения.
|
||||
|
||||
Юридический текст лицензии: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru
|
||||
Юридический текст лицензии: <https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
@@ -2,7 +2,7 @@ EOSIO_PUB_KEY=EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
|
||||
EOSIO_PRV_KEY=5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
|
||||
DATADIR=blockchain-data
|
||||
BPACCOUNT=eosio
|
||||
PASSWORD=PASSWORD
|
||||
PASSWORD=PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
|
||||
SERVER_SECRET=SECRET
|
||||
SERVER_URL=http://127.0.0.1:2998
|
||||
MONGO_URI=mongodb://127.0.0.1:27017/cooperative-x
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/boot
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/boot
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/boot",
|
||||
"type": "module",
|
||||
"version": "2.2.9",
|
||||
"version": "2025.7.2",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "",
|
||||
@@ -11,6 +11,9 @@
|
||||
"scripts": {
|
||||
"enter": "./scripts/enter.sh",
|
||||
"cli": "esno src/index.ts",
|
||||
"deploy": "esno src/index.ts deploy",
|
||||
"cleos": "esno src/index.ts cleos",
|
||||
"unlock": "esno src/index.ts unlock",
|
||||
"boot": "esno src/index.ts boot",
|
||||
"clear": "esno src/index.ts clear",
|
||||
"start": "./scripts/restart.sh",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'
|
||||
import { Api, JsonRpc, Serialize } from 'eosjs'
|
||||
import {
|
||||
DraftContract,
|
||||
GatewayContract,
|
||||
RegistratorContract,
|
||||
SovietContract,
|
||||
SystemContract,
|
||||
@@ -513,8 +514,8 @@ export default class Blockchain {
|
||||
console.log('Новый кооператив пре-иниализирован: ', params)
|
||||
}
|
||||
|
||||
// TODO change registerOrganization to registerCooperative
|
||||
async registerOrganization(
|
||||
// TODO change registerCooperative to registerCooperative
|
||||
async registerCooperative(
|
||||
params: RegistratorContract.Actions.RegisterCooperative.IRegisterCooperative,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
@@ -573,7 +574,7 @@ export default class Blockchain {
|
||||
)
|
||||
}
|
||||
|
||||
async registerAccount2(
|
||||
async createAccount(
|
||||
params: RegistratorContract.Actions.CreateAccount.ICreateAccount,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
@@ -586,7 +587,7 @@ export default class Blockchain {
|
||||
name: RegistratorContract.Actions.CreateAccount.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.registrator,
|
||||
actor: params.coopname,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
@@ -606,10 +607,10 @@ export default class Blockchain {
|
||||
}
|
||||
|
||||
async registerUser(
|
||||
params: RegistratorContract.Actions.RegisterUser.IRegistrerUser,
|
||||
params: RegistratorContract.Actions.RegisterUser.IRegisterUser,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
console.dir(params, { depth: null })
|
||||
await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
@@ -618,13 +619,11 @@ export default class Blockchain {
|
||||
name: RegistratorContract.Actions.RegisterUser.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.registrator,
|
||||
actor: params.coopname,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: {
|
||||
...params,
|
||||
},
|
||||
data: params,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -639,7 +638,7 @@ export default class Blockchain {
|
||||
|
||||
async transfer(params: TokenContract.Actions.Transfer.ITransfer) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
console.dir(params, { depth: null })
|
||||
const result = await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
@@ -747,7 +746,7 @@ export default class Blockchain {
|
||||
name: SovietContract.Actions.Decisions.VoteFor.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.member,
|
||||
actor: params.username,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
@@ -800,36 +799,39 @@ export default class Blockchain {
|
||||
|
||||
async exec(params: SovietContract.Actions.Decisions.Exec.IExec) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Decisions.Exec.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.executer,
|
||||
permission: 'active',
|
||||
try {
|
||||
await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Decisions.Exec.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.executer,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: {
|
||||
...params,
|
||||
},
|
||||
],
|
||||
data: {
|
||||
...params,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
}
|
||||
catch (e) {
|
||||
console.dir(e, { depth: null })
|
||||
}
|
||||
console.log('Решение исполнено: ', params)
|
||||
}
|
||||
|
||||
async joinCoop(
|
||||
params: RegistratorContract.Actions.JoinCooperative.IJoinCooperative,
|
||||
async ConfirmPayment(
|
||||
params: GatewayContract.Actions.CompleteIncome.ICompleteIncome,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
@@ -837,11 +839,11 @@ export default class Blockchain {
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: RegistratorContract.contractName.production,
|
||||
name: RegistratorContract.Actions.JoinCooperative.actionName,
|
||||
account: GatewayContract.contractName.production,
|
||||
name: GatewayContract.Actions.CompleteIncome.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.registrator,
|
||||
actor: params.coopname,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
@@ -919,7 +921,7 @@ export default class Blockchain {
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Шаблон создан: ', params)
|
||||
console.log('Шаблон создан: ', params.registry_id)
|
||||
}
|
||||
|
||||
async createTranslation(
|
||||
@@ -951,7 +953,7 @@ export default class Blockchain {
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Перевод создан: ', params)
|
||||
console.log('Перевод создан: ', params.registry_id)
|
||||
}
|
||||
|
||||
async createProgram(
|
||||
@@ -985,36 +987,4 @@ export default class Blockchain {
|
||||
|
||||
console.log('Программа установлена: ', params)
|
||||
}
|
||||
|
||||
async makeCoagreement(
|
||||
params: SovietContract.Actions.Agreements.MakeCoagreement.IMakeCoagreement,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Agreements.MakeCoagreement.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.administrator,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: {
|
||||
...params,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Программа установлена: ', params)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ max-block-net-usage-threshold-bytes = 1024
|
||||
verbose-http-errors = true
|
||||
chain-state-history = true
|
||||
trace-history = true
|
||||
state-history-endpoint = 0.0.0.0:8080
|
||||
state-history-endpoint = 0.0.0.0:8070
|
||||
resource-monitor-space-threshold = 99
|
||||
resource-monitor-not-shutdown-on-threshold-exceeded = true
|
||||
wasm-runtime = eos-vm
|
||||
|
||||
@@ -75,4 +75,19 @@ export default [
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/capital'),
|
||||
target: 'capital',
|
||||
},
|
||||
{
|
||||
name: 'wallet',
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/wallet'),
|
||||
target: 'wallet',
|
||||
},
|
||||
{
|
||||
name: 'loan',
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/loan'),
|
||||
target: 'loan',
|
||||
},
|
||||
{
|
||||
name: 'meet',
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/meet'),
|
||||
target: 'meet',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -87,6 +87,18 @@ export default {
|
||||
name: 'capital',
|
||||
code_permissions_to: ['capital'],
|
||||
},
|
||||
{
|
||||
name: 'loan',
|
||||
code_permissions_to: ['loan'],
|
||||
},
|
||||
{
|
||||
name: 'meet',
|
||||
code_permissions_to: ['meet'],
|
||||
},
|
||||
{
|
||||
name: 'wallet',
|
||||
code_permissions_to: ['wallet'],
|
||||
},
|
||||
{
|
||||
name: 'soviet',
|
||||
code_permissions_to: ['soviet'],
|
||||
|
||||
@@ -1,38 +1,25 @@
|
||||
import type { Container } from "dockerode"
|
||||
import { findContainerByName } from "./find"
|
||||
import { runContainer } from "./run"
|
||||
import { exec } from 'node:child_process'
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
export async function execCommand(command: string[]): Promise<string> {
|
||||
const container = await runContainer(true)
|
||||
const execAsync = promisify(exec)
|
||||
|
||||
const exec = await container.exec({
|
||||
Cmd: command,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
})
|
||||
export async function execCommand(command: string[]): Promise<void> {
|
||||
const fullCmd = ['docker', 'compose', 'exec', 'node', ...command].join(' ')
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
exec.start({}, (err: any, stream: any) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
let output = ""
|
||||
|
||||
// eslint-disable-next-line node/prefer-global/buffer
|
||||
stream.on("data", (data: Buffer) => {
|
||||
output += data.toString()
|
||||
})
|
||||
|
||||
stream.on("end", () => {
|
||||
output = output.replace(/^\d+\s*/, "")
|
||||
console.log(output)
|
||||
resolve(output)
|
||||
})
|
||||
|
||||
stream.on("error", (err: any) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
try {
|
||||
// eslint-disable-next-line node/prefer-global/process
|
||||
const { stdout, stderr } = await execAsync(fullCmd, { env: process.env })
|
||||
if (stdout)
|
||||
console.log(stdout.trim())
|
||||
if (stderr)
|
||||
console.error(stderr.trim())
|
||||
}
|
||||
catch (err: any) {
|
||||
if (err.stdout)
|
||||
console.log(err.stdout.trim())
|
||||
if (err.stderr)
|
||||
console.error(err.stderr.trim())
|
||||
// опционально:
|
||||
// console.error(`Command failed with code ${err.code}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@ export async function clearDB(): Promise<void> {
|
||||
// eslint-disable-next-line node/prefer-global/process
|
||||
await mongoose.connect(process.env.MONGO_URI as string)
|
||||
|
||||
try {
|
||||
await mongoose.connection.collection('users').deleteMany({})
|
||||
console.log('Все документы удалены из коллекции users')
|
||||
}
|
||||
catch (e) {
|
||||
console.error('Ошибка при удалении:', e)
|
||||
}
|
||||
|
||||
try {
|
||||
await mongoose.connection.collection('sync').deleteMany({})
|
||||
console.log('Все документы удалены из коллекции sync')
|
||||
|
||||
@@ -31,17 +31,11 @@ program.version('0.1.0')
|
||||
|
||||
// Команда для запуска команды в контейнере
|
||||
program
|
||||
.command('cleos <cmd...>')
|
||||
.command('cleos [cmd...]')
|
||||
.description('Execute a cleos command in a Node container')
|
||||
.allowUnknownOption()
|
||||
.action(async (cmd: string[]) => {
|
||||
try {
|
||||
console.log(cmd)
|
||||
await execCommand(['cleos', ...cmd])
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Command execution failed:', error)
|
||||
}
|
||||
.action(async (cmd: string[] = []) => {
|
||||
await execCommand(['cleos', ...cmd])
|
||||
})
|
||||
|
||||
// Команда для запуска команды в контейнере
|
||||
@@ -54,14 +48,8 @@ program
|
||||
.action(async (cmd: string, options: any) => {
|
||||
try {
|
||||
const { target, network } = options
|
||||
await deleteFile(keosdPath)
|
||||
|
||||
await execCommand([
|
||||
'cleos',
|
||||
'wallet',
|
||||
'unlock',
|
||||
'--password',
|
||||
process.env.PASSWORD!,
|
||||
])
|
||||
await deployCommand(cmd, target, network)
|
||||
}
|
||||
catch (error) {
|
||||
@@ -126,6 +114,12 @@ program
|
||||
.action(async () => {
|
||||
try {
|
||||
await stopContainerByName('node')
|
||||
}
|
||||
catch (e) {
|
||||
console.log('Нет контейнера для остановки. Стартуем новый..')
|
||||
}
|
||||
|
||||
try {
|
||||
await clearDirectory(basePath)
|
||||
await clearDB()
|
||||
await runContainer()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { startInfra } from "./infra"
|
||||
import { startCoop } from "./cooperative"
|
||||
import { startInfra } from './infra'
|
||||
import { startCoop } from './cooperative'
|
||||
|
||||
export async function boot() {
|
||||
await startInfra()
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import axios from 'axios'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Registry } from '@coopenomics/factory'
|
||||
import { Cooperative as TCooperative } from 'cooptypes'
|
||||
import type { Account, Contract, Keys } from '../types'
|
||||
import type { Cooperative } from 'cooptypes'
|
||||
import type { Keys } from '../types'
|
||||
import config, { GOVERN_SYMBOL, SYMBOL } from '../configs'
|
||||
import Blockchain from '../blockchain'
|
||||
import { sendPostToCoopbackWithSecret, sleep } from '../utils'
|
||||
import { generateRandomSHA256 } from '../utils/randomHash'
|
||||
|
||||
const test_hash
|
||||
= '157192b276da23cc84ab078fc8755c051c5f0430bf4802e55718221e6b76c777'
|
||||
@@ -14,11 +11,23 @@ const test_sign
|
||||
const test_pkey = 'EOS5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzxrLg3J'
|
||||
const test_meta = JSON.stringify({})
|
||||
|
||||
const document = {
|
||||
const document: Cooperative.Document.ISignedDocument2 = {
|
||||
hash: test_hash,
|
||||
signature: test_sign,
|
||||
public_key: test_pkey,
|
||||
signatures: [
|
||||
{
|
||||
id: 1,
|
||||
signed_hash: test_hash,
|
||||
public_key: test_pkey,
|
||||
signed_at: '2025-05-14T12:22:26',
|
||||
meta: test_meta,
|
||||
signer: 'cooperative1',
|
||||
signature: test_sign,
|
||||
},
|
||||
],
|
||||
meta: test_meta,
|
||||
version: '1.0.0',
|
||||
doc_hash: test_hash,
|
||||
meta_hash: test_hash,
|
||||
}
|
||||
|
||||
export class CooperativeClass {
|
||||
@@ -46,48 +55,6 @@ export class CooperativeClass {
|
||||
})
|
||||
}
|
||||
|
||||
async createAgreements(coopname: string) {
|
||||
// console.log('создаём кооперативное соглашение/положение по кошельку')
|
||||
await this.blockchain.makeCoagreement({
|
||||
coopname,
|
||||
administrator: coopname,
|
||||
type: 'wallet',
|
||||
draft_id: TCooperative.Registry.WalletAgreement.registry_id,
|
||||
program_id: 1,
|
||||
})
|
||||
|
||||
await this.blockchain.makeCoagreement({
|
||||
coopname,
|
||||
administrator: coopname,
|
||||
type: 'signature',
|
||||
draft_id: TCooperative.Registry.RegulationElectronicSignature.registry_id,
|
||||
program_id: 0,
|
||||
})
|
||||
await this.blockchain.makeCoagreement({
|
||||
coopname,
|
||||
administrator: coopname,
|
||||
type: 'user',
|
||||
draft_id: TCooperative.Registry.UserAgreement.registry_id,
|
||||
program_id: 0,
|
||||
})
|
||||
|
||||
await this.blockchain.makeCoagreement({
|
||||
coopname,
|
||||
administrator: coopname,
|
||||
type: 'privacy',
|
||||
draft_id: TCooperative.Registry.PrivacyPolicy.registry_id,
|
||||
program_id: 0,
|
||||
})
|
||||
|
||||
await this.blockchain.makeCoagreement({
|
||||
coopname,
|
||||
administrator: coopname,
|
||||
type: 'coopenomics',
|
||||
draft_id: TCooperative.Registry.CoopenomicsAgreement.registry_id,
|
||||
program_id: 0,
|
||||
})
|
||||
}
|
||||
|
||||
async createCooperative(username: string, keys?: Keys) {
|
||||
const account = await this.blockchain.generateKeypair(
|
||||
username,
|
||||
@@ -96,8 +63,7 @@ export class CooperativeClass {
|
||||
)
|
||||
console.log('Регистрируем аккаунт')
|
||||
|
||||
await this.blockchain.registerAccount2({
|
||||
registrator: config.provider,
|
||||
await this.blockchain.createAccount({
|
||||
coopname: config.provider,
|
||||
referer: '',
|
||||
username: account.username,
|
||||
@@ -106,47 +72,34 @@ export class CooperativeClass {
|
||||
})
|
||||
|
||||
console.log('Регистрируем аккаунт как пользователя')
|
||||
const registration_hash = generateRandomSHA256()
|
||||
|
||||
await this.blockchain.registerUser({
|
||||
registrator: config.provider,
|
||||
coopname: config.provider,
|
||||
braname: '',
|
||||
username: account.username,
|
||||
type: 'organization',
|
||||
})
|
||||
|
||||
console.log('Переводим аккаунт в организации')
|
||||
|
||||
await this.blockchain.registerOrganization({
|
||||
username: account.username,
|
||||
coopname: account.username,
|
||||
params: {
|
||||
is_cooperative: true,
|
||||
coop_type: 'conscoop',
|
||||
announce: 'Тестовый кооператив',
|
||||
description: 'Тестовое описание',
|
||||
initial: `100.0000 ${config.token.govern_symbol}`,
|
||||
minimum: `300.0000 ${config.token.govern_symbol}`,
|
||||
org_initial: `1000.0000 ${config.token.govern_symbol}`,
|
||||
org_minimum: `3000.0000 ${config.token.govern_symbol}`,
|
||||
},
|
||||
document,
|
||||
statement: document,
|
||||
registration_hash,
|
||||
})
|
||||
|
||||
console.log('Отправляем заявление на вступление')
|
||||
|
||||
await this.blockchain.joinCoop({
|
||||
registrator: config.provider_chairman,
|
||||
await this.blockchain.ConfirmPayment({
|
||||
coopname: config.provider,
|
||||
username: account.username,
|
||||
document,
|
||||
braname: '',
|
||||
income_hash: registration_hash,
|
||||
})
|
||||
|
||||
console.log('Голосуем по решению в провайдере')
|
||||
|
||||
await this.blockchain.votefor({
|
||||
version: '1.0.0',
|
||||
signed_at: '2025-05-14T12:22:26',
|
||||
signed_hash: test_hash,
|
||||
signature: test_sign,
|
||||
public_key: test_pkey,
|
||||
coopname: config.provider,
|
||||
member: config.provider_chairman,
|
||||
username: config.provider_chairman,
|
||||
decision_id: 1,
|
||||
})
|
||||
|
||||
@@ -174,20 +127,29 @@ export class CooperativeClass {
|
||||
administrator: config.provider,
|
||||
username: username!,
|
||||
agreement_type: 'wallet',
|
||||
document: { // отправляем произвольный документ с валидной подписью
|
||||
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
|
||||
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
|
||||
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
|
||||
meta: '{}',
|
||||
},
|
||||
document,
|
||||
})
|
||||
|
||||
console.log('создаём программы и соглашения новому кооперативу')
|
||||
// await this.createPrograms(username)
|
||||
await this.createAgreements(username)
|
||||
console.log('Переводим аккаунт в кооператив')
|
||||
|
||||
await this.blockchain.registerCooperative({
|
||||
username: account.username,
|
||||
coopname: account.username,
|
||||
params: {
|
||||
is_cooperative: true,
|
||||
coop_type: 'conscoop',
|
||||
announce: 'Тестовый кооператив',
|
||||
description: 'Тестовое описание',
|
||||
initial: `100.0000 ${config.token.govern_symbol}`,
|
||||
minimum: `300.0000 ${config.token.govern_symbol}`,
|
||||
org_initial: `1000.0000 ${config.token.govern_symbol}`,
|
||||
org_minimum: `3000.0000 ${config.token.govern_symbol}`,
|
||||
},
|
||||
document,
|
||||
})
|
||||
|
||||
console.log('Переводим инициализационные токены')
|
||||
await this.blockchain.transfer({ from: 'eosio', to: username, quantity: `100.0000 ${SYMBOL}`, memo: '' })
|
||||
await this.blockchain.transfer({ from: 'eosio', to: account.username, quantity: `100.0000 ${SYMBOL}`, memo: '' })
|
||||
|
||||
console.log(`Арендуем ресурсы кооперативу`)
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ export async function startInfra() {
|
||||
position: 'Председатель',
|
||||
based_on: 'Решение общего собрания №1',
|
||||
},
|
||||
country: 'Russia',
|
||||
country: 'Российская Федерация',
|
||||
city: 'Москва',
|
||||
fact_address: '117593 г. Москва, муниципальный округ Ясенево, проезд Соловьиный, дом 1, помещение 1/1',
|
||||
full_address:
|
||||
@@ -202,7 +202,7 @@ export async function startInfra() {
|
||||
first_name: 'Иван',
|
||||
last_name: 'Иванов',
|
||||
middle_name: 'Иванович',
|
||||
birthdate: '2023-04-01',
|
||||
birthdate: '1990/04/01',
|
||||
phone: '+71234567890',
|
||||
email: 'ivanov@example.com',
|
||||
full_address: 'Переулок Правды д. 1',
|
||||
@@ -210,7 +210,7 @@ export async function startInfra() {
|
||||
series: 7122,
|
||||
number: 112233,
|
||||
issued_by: 'отделом УФМС по г. Москва',
|
||||
issued_at: '22.04.2010',
|
||||
issued_at: '2010/05/10',
|
||||
code: '111-232',
|
||||
},
|
||||
}
|
||||
@@ -316,7 +316,6 @@ export async function startInfra() {
|
||||
|
||||
const cooperative = new CooperativeClass(blockchain)
|
||||
|
||||
await cooperative.createAgreements(config.provider)
|
||||
await cooperative.createPrograms(config.provider)
|
||||
|
||||
console.log(`Арендуем ресурсы провайдеру`)
|
||||
|
||||
@@ -28,7 +28,7 @@ export class CooperativeClass {
|
||||
this.blockchain = blockchain
|
||||
}
|
||||
|
||||
async createParticipant(username: string, keys?: Keys) {
|
||||
async addUser(username: string, keys?: Keys) {
|
||||
const account = await this.blockchain.generateKeypair(
|
||||
username,
|
||||
keys,
|
||||
@@ -37,7 +37,6 @@ export class CooperativeClass {
|
||||
console.log('Регистрируем аккаунт')
|
||||
|
||||
const data: RegistratorContract.Actions.AddUser.IAddUser = {
|
||||
registrator: config.provider,
|
||||
coopname: config.provider,
|
||||
referer: '',
|
||||
username: account.username,
|
||||
@@ -115,12 +114,12 @@ export class CooperativeClass {
|
||||
}
|
||||
}
|
||||
|
||||
export async function createParticipant(username: string) {
|
||||
export async function addUser(username: string) {
|
||||
// инициализируем инстанс с ключами
|
||||
const blockchain = new Blockchain(config.network, config.private_keys)
|
||||
const cooperative = new CooperativeClass(blockchain)
|
||||
|
||||
await cooperative.createParticipant(username, {
|
||||
await cooperative.addUser(username, {
|
||||
// eslint-disable-next-line node/prefer-global/process
|
||||
privateKey: process.env.EOSIO_PRV_KEY!,
|
||||
// eslint-disable-next-line node/prefer-global/process
|
||||
|
||||
@@ -4,7 +4,7 @@ import Blockchain from '../blockchain'
|
||||
import config from '../configs'
|
||||
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
|
||||
import { generateRandomSHA256 } from '../utils/randomHash'
|
||||
import { createParticipant } from '../init/participant'
|
||||
import { addUser } from '../init/participant'
|
||||
import { generateRandomUsername } from '../utils/randomUsername'
|
||||
import { sleep } from '../utils'
|
||||
import { processDecision } from './soviet/processDecision'
|
||||
@@ -17,7 +17,7 @@ import { getCoopProgramWallet, getUserProgramWallet } from './wallet/walletUtils
|
||||
import { investInProject } from './capital/investInProject'
|
||||
import { allocateFundsToResult } from './capital/allocateFundsToResult'
|
||||
import { commitToResult } from './capital/commitToResult'
|
||||
import { capitalProgramId, ratePerHour, walletProgramId } from './capital/consts'
|
||||
import { capitalProgramId, ratePerHour, sourceProgramId, walletProgramId } from './capital/consts'
|
||||
import { withdrawContribution } from './capital/withdrawContribution'
|
||||
import { registerExpense } from './capital/registerExpense'
|
||||
|
||||
@@ -55,19 +55,19 @@ beforeAll(async () => {
|
||||
|
||||
investor1 = generateRandomUsername()
|
||||
console.log('investor1: ', investor1)
|
||||
await createParticipant(investor1)
|
||||
await addUser(investor1)
|
||||
|
||||
tester1 = generateRandomUsername()
|
||||
console.log('tester1: ', tester1)
|
||||
await createParticipant(tester1)
|
||||
await addUser(tester1)
|
||||
|
||||
tester2 = generateRandomUsername()
|
||||
console.log('tester2: ', tester2)
|
||||
await createParticipant(tester2)
|
||||
await addUser(tester2)
|
||||
|
||||
tester3 = generateRandomUsername()
|
||||
console.log('tester3: ', tester3)
|
||||
await createParticipant(tester3)
|
||||
await addUser(tester3)
|
||||
|
||||
// const { stdout } = await execa('esno', [CLI_PATH, 'boot'], { stdio: 'inherit' })
|
||||
// expect(stdout).toContain('Boot process completed')
|
||||
@@ -87,8 +87,8 @@ afterAll(() => {
|
||||
})
|
||||
|
||||
describe('тест контракта CAPITAL', () => {
|
||||
it('создаём целевую потребительскую программу', async () => {
|
||||
const program = await getCoopProgramWallet(blockchain, 'voskhod', capitalProgramId)
|
||||
it('создаём программу генерации', async () => {
|
||||
const program = await getCoopProgramWallet(blockchain, 'voskhod', sourceProgramId)
|
||||
if (!program) {
|
||||
const data: SovietContract.Actions.Programs.CreateProgram.ICreateProgram = {
|
||||
coopname: 'voskhod',
|
||||
@@ -103,7 +103,53 @@ describe('тест контракта CAPITAL', () => {
|
||||
fixed_membership_contribution: '0.0000 RUB',
|
||||
membership_percent_fee: '0',
|
||||
meta: '',
|
||||
type: 'cofund',
|
||||
type: 'source',
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Programs.CreateProgram.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'ant',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
getTotalRamUsage(result)
|
||||
expect(result.transaction_id).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('создаём программу капитализации', async () => {
|
||||
const program = await getCoopProgramWallet(blockchain, 'voskhod', capitalProgramId)
|
||||
|
||||
if (!program) {
|
||||
const data: SovietContract.Actions.Programs.CreateProgram.ICreateProgram = {
|
||||
coopname: 'voskhod',
|
||||
is_can_coop_spend_share_contributions: false,
|
||||
username: 'ant',
|
||||
title: 'Капитализация',
|
||||
announce: '',
|
||||
description: '',
|
||||
preview: '',
|
||||
images: '',
|
||||
calculation_type: 'free',
|
||||
fixed_membership_contribution: '0.0000 RUB',
|
||||
membership_percent_fee: '0',
|
||||
meta: '',
|
||||
type: 'capital',
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact(
|
||||
@@ -180,7 +226,7 @@ describe('тест контракта CAPITAL', () => {
|
||||
|
||||
it('создаём проект', async () => {
|
||||
const hash = generateRandomSHA256()
|
||||
const parehtHash = '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
const parentHash = '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
|
||||
const data: CapitalContract.Actions.CreateProject.ICreateProject = {
|
||||
coopname: 'voskhod',
|
||||
@@ -188,7 +234,7 @@ describe('тест контракта CAPITAL', () => {
|
||||
title: `Идея ${hash.slice(0, 10)}`,
|
||||
description: `Описание ${hash.slice(0, 10)}`,
|
||||
project_hash: hash,
|
||||
parent_project_hash: parehtHash,
|
||||
parent_project_hash: parentHash,
|
||||
parent_distribution_ratio: 0,
|
||||
terms: '',
|
||||
subject: '',
|
||||
@@ -351,6 +397,8 @@ describe('тест контракта CAPITAL', () => {
|
||||
application: 'voskhod',
|
||||
project_hash: project1.project_hash,
|
||||
result_hash: generateRandomSHA256(),
|
||||
assignee: 'ant',
|
||||
assignment: 'Задание #1: тут описание',
|
||||
}
|
||||
|
||||
result1 = data
|
||||
@@ -403,7 +451,7 @@ describe('тест контракта CAPITAL', () => {
|
||||
console.log('wallet investor1: ', wallet)
|
||||
}
|
||||
{
|
||||
const { depositId, program, userWallet } = await depositToWallet(blockchain, 'voskhod', investor1, 10000)
|
||||
const { depositId, program, userWallet } = await depositToWallet(blockchain, 'voskhod', investor1, 100000)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -431,105 +479,56 @@ describe('тест контракта CAPITAL', () => {
|
||||
const { finalResult, commitHash } = await commitToResult(blockchain, 'voskhod', result1.result_hash, result1.project_hash, tester1, tester1CommitHours)
|
||||
commits.push(commitHash)
|
||||
|
||||
expect(finalResult.creators_amount).toBe('10000.0000 RUB')
|
||||
expect(finalResult.creators_base).toBe('10000.0000 RUB')
|
||||
expect(finalResult.creators_bonus).toBe('3820.0000 RUB')
|
||||
expect(finalResult.authors_bonus).toBe('16180.0000 RUB')
|
||||
expect(finalResult.generated_amount).toBe('30000.0000 RUB')
|
||||
expect(finalResult.participants_bonus).toBe('48540.0000 RUB')
|
||||
expect(finalResult.total_amount).toBe('78540.0000 RUB')
|
||||
expect(finalResult.generated).toBe('30000.0000 RUB')
|
||||
expect(finalResult.capitalists_bonus).toBe('48540.0000 RUB')
|
||||
expect(finalResult.total).toBe('78540.0000 RUB')
|
||||
})
|
||||
|
||||
it('добавить коммит создателя tester2 на 10 часов по 1000 RUB', async () => {
|
||||
const { finalResult, commitHash } = await commitToResult(blockchain, 'voskhod', result1.result_hash, result1.project_hash, tester2, tester2CommitHours)
|
||||
commits.push(commitHash)
|
||||
|
||||
expect(finalResult.creators_amount).toBe('20000.0000 RUB')
|
||||
expect(finalResult.creators_base).toBe('20000.0000 RUB')
|
||||
expect(finalResult.creators_bonus).toBe('7640.0000 RUB')
|
||||
expect(finalResult.authors_bonus).toBe('32360.0000 RUB')
|
||||
expect(finalResult.generated_amount).toBe('60000.0000 RUB')
|
||||
expect(finalResult.participants_bonus).toBe('97080.0000 RUB')
|
||||
expect(finalResult.total_amount).toBe('157080.0000 RUB')
|
||||
expect(finalResult.generated).toBe('60000.0000 RUB')
|
||||
expect(finalResult.capitalists_bonus).toBe('97080.0000 RUB')
|
||||
expect(finalResult.total).toBe('157080.0000 RUB')
|
||||
})
|
||||
|
||||
// it('завершаем цикл и стартуем распределение', async () => {
|
||||
// const data: CapitalContract.Actions.StartDistribution.IStart = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// result_hash: result1.result_hash,
|
||||
// }
|
||||
|
||||
// const result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.StartDistribution.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
|
||||
// const blockchainResult = (await blockchain.getTableRows(
|
||||
// CapitalContract.contractName.production,
|
||||
// TODO: заменить на получение ссуды, а возврат перенести ниже
|
||||
// it('пишем заявление на возврат в кошелёк от tester1 на 10000 RUB', async () => {
|
||||
// const withdrawAmount = `${(tester1CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
|
||||
// console.log('commits: ', commits)
|
||||
// const { withdrawHash, transactionId } = await withdrawContribution(
|
||||
// blockchain,
|
||||
// 'voskhod',
|
||||
// 'results',
|
||||
// 1,
|
||||
// tester1,
|
||||
// result1.result_hash,
|
||||
// result1.result_hash,
|
||||
// 2,
|
||||
// 'sha256',
|
||||
// ))[0]
|
||||
|
||||
// expect(blockchainResult).toBeDefined()
|
||||
// expect(blockchainResult.result_hash).toBe(result1.result_hash)
|
||||
// expect(blockchainResult.project_hash).toBe(project1.project_hash)
|
||||
// expect(blockchainResult.coopname).toBe('voskhod')
|
||||
// expect(blockchainResult.status).toBe('started')
|
||||
// result1.project_hash,
|
||||
// [commits[0]],
|
||||
// withdrawAmount,
|
||||
// fakeDocument,
|
||||
// )
|
||||
// })
|
||||
|
||||
it('пишем заявление на возврат в кошелёк от tester1 на 10000 RUB', async () => {
|
||||
const withdrawAmount = `${(tester1CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
|
||||
console.log('commits: ', commits)
|
||||
const { withdrawHash, transactionId } = await withdrawContribution(
|
||||
blockchain,
|
||||
'voskhod',
|
||||
tester1,
|
||||
result1.result_hash,
|
||||
result1.project_hash,
|
||||
[commits[0]],
|
||||
withdrawAmount,
|
||||
fakeDocument,
|
||||
)
|
||||
})
|
||||
// it('пишем заявление на возврат в кошелёк от tester2 на 10000 RUB', async () => {
|
||||
// const withdrawAmount = `${(tester2CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
|
||||
|
||||
it('пишем заявление на возврат в кошелёк от tester2 на 10000 RUB', async () => {
|
||||
const withdrawAmount = `${(tester2CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
|
||||
|
||||
const { withdrawHash, transactionId } = await withdrawContribution(
|
||||
blockchain,
|
||||
'voskhod',
|
||||
tester2,
|
||||
result1.result_hash,
|
||||
result1.project_hash,
|
||||
[commits[1]],
|
||||
withdrawAmount,
|
||||
fakeDocument,
|
||||
)
|
||||
})
|
||||
// const { withdrawHash, transactionId } = await withdrawContribution(
|
||||
// blockchain,
|
||||
// 'voskhod',
|
||||
// tester2,
|
||||
// result1.result_hash,
|
||||
// result1.project_hash,
|
||||
// [commits[1]],
|
||||
// withdrawAmount,
|
||||
// fakeDocument,
|
||||
// )
|
||||
// })
|
||||
|
||||
it('регистрируем расход на 1000 RUB', async () => {
|
||||
const expenseAmount = '1000.0000 RUB'
|
||||
@@ -560,276 +559,295 @@ describe('тест контракта CAPITAL', () => {
|
||||
fakeDocument, // fakeDocument
|
||||
)
|
||||
})
|
||||
// it('добавляем второго автора tester2', async () => {
|
||||
// const data: CapitalContract.Actions.AddAuthor.IAddAuthor = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// project_hash: project1.project_hash,
|
||||
// author: tester2,
|
||||
// shares: '100',
|
||||
// }
|
||||
|
||||
// const result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.AddAuthor.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
/// ____________
|
||||
it('завершаем цикл и стартуем распределение', async () => {
|
||||
const data: CapitalContract.Actions.StartDistribution.IStart = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
}
|
||||
|
||||
// const project = (await blockchain.getTableRows(
|
||||
// CapitalContract.contractName.production,
|
||||
// 'voskhod',
|
||||
// 'projects',
|
||||
// 1,
|
||||
// project1.project_hash,
|
||||
// project1.project_hash,
|
||||
// 3,
|
||||
// 'sha256',
|
||||
// ))[0]
|
||||
const result = await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.StartDistribution.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'voskhod',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
|
||||
// expect(project).toBeDefined()
|
||||
// expect(project.authors_count).toBe(2)
|
||||
// expect(project.authors_shares).toBe(200)
|
||||
// })
|
||||
getTotalRamUsage(result)
|
||||
expect(result.transaction_id).toBeDefined()
|
||||
|
||||
// it('добавляем коммиты создателей tester2 и tester3', async () => {
|
||||
// // Добавляем второго создателя
|
||||
// let data: CapitalContract.Actions.AddCreator.IAddCreator = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// result_hash: result1.result_hash,
|
||||
// creator: tester2,
|
||||
// used: '100.0000 RUB',
|
||||
// }
|
||||
const blockchainResult = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
'voskhod',
|
||||
'results',
|
||||
1,
|
||||
result1.result_hash,
|
||||
result1.result_hash,
|
||||
2,
|
||||
'sha256',
|
||||
))[0]
|
||||
|
||||
// let result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.AddCreator.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
expect(blockchainResult).toBeDefined()
|
||||
expect(blockchainResult.result_hash).toBe(result1.result_hash)
|
||||
expect(blockchainResult.project_hash).toBe(project1.project_hash)
|
||||
expect(blockchainResult.coopname).toBe('voskhod')
|
||||
expect(blockchainResult.status).toBe('closed')
|
||||
|
||||
// // Добавляем третьего создателя
|
||||
// data = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// result_hash: result1.result_hash,
|
||||
// creator: tester3,
|
||||
// used: '100.0000 RUB',
|
||||
// }
|
||||
expect(blockchainResult.creators_amount_remain).toBe(blockchainResult.creators_amount)
|
||||
expect(blockchainResult.creators_bonus_remain).toBe(blockchainResult.creators_bonus)
|
||||
expect(blockchainResult.authors_bonus_remain).toBe(blockchainResult.authors_bonus)
|
||||
expect(blockchainResult.capitalists_bonus_remain).toBe(blockchainResult.capitalists_bonus)
|
||||
console.log('Результат после старта приёма: ', blockchainResult)
|
||||
})
|
||||
|
||||
// result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.AddCreator.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
it('обновляем капитал первого создателя в результате', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
// // Проверяем финальные значения
|
||||
// const blockchainResult = (await blockchain.getTableRows(
|
||||
// CapitalContract.contractName.production,
|
||||
// 'voskhod',
|
||||
// 'results',
|
||||
// 1,
|
||||
// result1.result_hash,
|
||||
// result1.result_hash,
|
||||
// 2,
|
||||
// 'sha256',
|
||||
// ))[0]
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: tester1,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
// expect(blockchainResult).toBeDefined()
|
||||
// expect(blockchainResult.creators_count).toBe(3)
|
||||
// expect(blockchainResult.creators_amount).toBe('300.0000 RUB')
|
||||
// // Ниже – пример ожидаемого роста, исходя из логики контракта
|
||||
// expect(blockchainResult.creators_bonus).toBe('114.6000 RUB')
|
||||
// expect(blockchainResult.authors_bonus).toBe('485.4000 RUB')
|
||||
// expect(blockchainResult.generated_amount).toBe('900.0000 RUB')
|
||||
// expect(blockchainResult.participants_bonus).toBe('1456.2000 RUB')
|
||||
// expect(blockchainResult.total_amount).toBe('2356.2000 RUB')
|
||||
// })
|
||||
const result = await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.CreateClaim.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'voskhod',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
getTotalRamUsage(result)
|
||||
expect(result.transaction_id).toBeDefined()
|
||||
|
||||
// it('удаляем создателя tester3', async () => {
|
||||
// const data: CapitalContract.Actions.DelCreator.IDelCreator = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// result_hash: result1.result_hash,
|
||||
// creator: tester3,
|
||||
// }
|
||||
const blockchainResult = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
'voskhod',
|
||||
'results',
|
||||
1,
|
||||
result1.result_hash,
|
||||
result1.result_hash,
|
||||
2,
|
||||
'sha256',
|
||||
))[0]
|
||||
|
||||
// const result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.DelCreator.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
expect(blockchainResult).toBeDefined()
|
||||
console.log('blockchainResult: ', blockchainResult)
|
||||
})
|
||||
|
||||
// // Проверяем обновленные значения после удаления
|
||||
// const blockchainResult = (await blockchain.getTableRows(
|
||||
// CapitalContract.contractName.production,
|
||||
// 'voskhod',
|
||||
// 'results',
|
||||
// 1,
|
||||
// result1.result_hash,
|
||||
// result1.result_hash,
|
||||
// 2,
|
||||
// 'sha256',
|
||||
// ))[0]
|
||||
it('обновляем капитал второго создателя в результате', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
// expect(blockchainResult).toBeDefined()
|
||||
// expect(blockchainResult.creators_count).toBe(2)
|
||||
// expect(blockchainResult.creators_amount).toBe('200.0000 RUB')
|
||||
// // Уменьшаем все показатели ровно на величину последнего добавленного создателя
|
||||
// expect(blockchainResult.creators_bonus).toBe('76.4000 RUB') // 114.6000 - 38.2000
|
||||
// expect(blockchainResult.authors_bonus).toBe('323.6000 RUB') // 485.4000 - 161.8000
|
||||
// expect(blockchainResult.generated_amount).toBe('600.0000 RUB') // 900.0000 - 300.0000
|
||||
// expect(blockchainResult.participants_bonus).toBe('970.8000 RUB') // 1456.2000 - 485.4000
|
||||
// expect(blockchainResult.total_amount).toBe('1570.8000 RUB') // 2356.2000 - 785.4000
|
||||
// })
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: tester2,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
// it('стартуем распределение долей результата', async () => {
|
||||
// const data: CapitalContract.Actions.Start.IStart = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// result_hash: result1.result_hash,
|
||||
// }
|
||||
const result = await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.CreateClaim.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'voskhod',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
getTotalRamUsage(result)
|
||||
expect(result.transaction_id).toBeDefined()
|
||||
|
||||
// const result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.Start.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
const blockchainResult = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
'voskhod',
|
||||
'results',
|
||||
1,
|
||||
result1.result_hash,
|
||||
result1.result_hash,
|
||||
2,
|
||||
'sha256',
|
||||
))[0]
|
||||
|
||||
// const blockchainResult = (await blockchain.getTableRows(
|
||||
// CapitalContract.contractName.production,
|
||||
// 'voskhod',
|
||||
// 'results',
|
||||
// 1,
|
||||
// result1.result_hash,
|
||||
// result1.result_hash,
|
||||
// 2,
|
||||
// 'sha256',
|
||||
// ))[0]
|
||||
expect(blockchainResult).toBeDefined()
|
||||
console.log('blockchainResult: ', blockchainResult)
|
||||
})
|
||||
|
||||
// expect(blockchainResult).toBeDefined()
|
||||
// expect(blockchainResult.status).toBe('started')
|
||||
// })
|
||||
it('повторно обновляем капитал второго создателя в результате и ожидаем ошибку', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
// it('пишем заявления и получаем NFT', async () => {
|
||||
// const data: CapitalContract.Actions.SetStatement.ISetStatement = {
|
||||
// coopname: 'voskhod',
|
||||
// application: 'voskhod',
|
||||
// statement: fakeDocument,
|
||||
// nft_hash: generateRandomSHA256(),
|
||||
// }
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: tester2,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
// const result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.SetStatement.actionName,
|
||||
// authorization: [
|
||||
// {
|
||||
// actor: 'voskhod',
|
||||
// permission: 'active',
|
||||
// },
|
||||
// ],
|
||||
// data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
// getTotalRamUsage(result)
|
||||
// expect(result.transaction_id).toBeDefined()
|
||||
// })
|
||||
try {
|
||||
await sleep(1000)
|
||||
await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.CreateClaim.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'voskhod',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
throw new Error('Ожидалась ошибка, но транзакция прошла успешно')
|
||||
}
|
||||
catch (error: any) {
|
||||
const message = error.json?.error?.details?.[0]?.message
|
||||
expect(message).toMatch(/Клайм уже существует/i)
|
||||
}
|
||||
})
|
||||
|
||||
it('обновляем капитал инвестора в результате', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: investor1,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.CreateClaim.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'voskhod',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
getTotalRamUsage(result)
|
||||
expect(result.transaction_id).toBeDefined()
|
||||
|
||||
const blockchainResult = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
'voskhod',
|
||||
'results',
|
||||
1,
|
||||
result1.result_hash,
|
||||
result1.result_hash,
|
||||
2,
|
||||
'sha256',
|
||||
))[0]
|
||||
|
||||
expect(blockchainResult).toBeDefined()
|
||||
console.log('investorResult: ', blockchainResult)
|
||||
})
|
||||
|
||||
it('повторно обновляем капитал инвестора в результате и ожидаем ошибку', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: investor1,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
try {
|
||||
await sleep(1000)
|
||||
await blockchain.api.transact(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.CreateClaim.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: 'voskhod',
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blocksBehind: 3,
|
||||
expireSeconds: 30,
|
||||
},
|
||||
)
|
||||
throw new Error('Ожидалась ошибка, но транзакция прошла успешно')
|
||||
}
|
||||
catch (error: any) {
|
||||
const message = error.json?.error?.details?.[0]?.message
|
||||
expect(message).toMatch(/Клайм уже существует/i)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { expect } from 'vitest'
|
||||
import { CapitalContract } from 'cooptypes'
|
||||
import { CapitalContract, SovietContract } from 'cooptypes'
|
||||
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
|
||||
import { generateRandomSHA256 } from '../../utils/randomHash'
|
||||
import { fakeDocument } from '../soviet/fakeDocument'
|
||||
import { processDecision } from '../soviet/processDecision'
|
||||
import { ratePerHour } from './consts'
|
||||
|
||||
export async function commitToResult(
|
||||
@@ -27,7 +28,7 @@ export async function commitToResult(
|
||||
resultHash,
|
||||
2,
|
||||
'sha256',
|
||||
))[0] || { spend: '0.0000 RUB', commits_count: 0 }
|
||||
))[0] || { spended: '0.0000 RUB', commits_count: 0 }
|
||||
|
||||
const prevProject = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
@@ -38,7 +39,7 @@ export async function commitToResult(
|
||||
projectHash,
|
||||
3,
|
||||
'sha256',
|
||||
))[0] || { spend: '0.0000 RUB' }
|
||||
))[0] || { spended: '0.0000 RUB' }
|
||||
|
||||
const prevContributor = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
@@ -61,10 +62,9 @@ export async function commitToResult(
|
||||
coopname,
|
||||
application: coopname,
|
||||
result_hash: resultHash,
|
||||
creator,
|
||||
commit_hash: commitHash,
|
||||
specification: fakeDocument,
|
||||
contributed_hours: spendHours,
|
||||
username: creator,
|
||||
}
|
||||
|
||||
console.log(`\n🚀 Отправка транзакции CreateCommit для результата ${resultHash}`)
|
||||
@@ -103,16 +103,14 @@ export async function commitToResult(
|
||||
console.log('🔍 Коммит после создания:', blockchainCommit)
|
||||
expect(blockchainCommit).toBeDefined()
|
||||
expect(blockchainCommit.commit_hash).toBe(commitHash)
|
||||
expect(blockchainCommit.spend).toBe(totalSpended)
|
||||
expect(blockchainCommit.spended).toBe(totalSpended)
|
||||
expect(blockchainCommit.status).toBe('created')
|
||||
|
||||
// Утверждение коммита
|
||||
const approveCommitData: CapitalContract.Actions.ApproveCommit.IApproveCommit = {
|
||||
const approveCommitData: SovietContract.Actions.Approves.ConfirmApprove.IConfirmApprove = {
|
||||
coopname,
|
||||
application: coopname,
|
||||
commit_hash: commitHash,
|
||||
approver: 'ant',
|
||||
approved_specification: fakeDocument,
|
||||
approval_hash: commitHash,
|
||||
approved_document: fakeDocument,
|
||||
}
|
||||
|
||||
console.log(`\n✅ Подтверждение коммита ${commitHash}`)
|
||||
@@ -120,8 +118,8 @@ export async function commitToResult(
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.ApproveCommit.actionName,
|
||||
account: SovietContract.contractName.production,
|
||||
name: SovietContract.Actions.Approves.ConfirmApprove.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data: approveCommitData,
|
||||
},
|
||||
@@ -148,10 +146,84 @@ export async function commitToResult(
|
||||
'sha256',
|
||||
))[0]
|
||||
|
||||
console.log('🔍 Коммит после утверждения:', blockchainCommit)
|
||||
expect(blockchainCommit).toBeDefined()
|
||||
expect(blockchainCommit.commit_hash).toBe(commitHash)
|
||||
expect(blockchainCommit.status).toBe('approved')
|
||||
// Коммит удаляем после утверждения
|
||||
expect(blockchainCommit).toBeUndefined()
|
||||
|
||||
// // Получение всех решений и выполнение последнего
|
||||
// const decisions = await blockchain.getTableRows(
|
||||
// SovietContract.contractName.production,
|
||||
// coopname,
|
||||
// 'decisions',
|
||||
// 1000,
|
||||
// )
|
||||
// const lastDecision = decisions[decisions.length - 1]
|
||||
|
||||
// console.log(`\n📜 Выполнение последнего решения: ${lastDecision.id}`)
|
||||
// await processDecision(blockchain, lastDecision.id)
|
||||
|
||||
// {
|
||||
// // Утверждение коммита
|
||||
// const act1Data: CapitalContract.Actions.SetAct1.ISetAct1 = {
|
||||
// coopname,
|
||||
// application: coopname,
|
||||
// username: creator,
|
||||
// commit_hash: commitHash,
|
||||
// act: fakeDocument,
|
||||
// }
|
||||
|
||||
// console.log(`\n✅ Установка акта1 по коммиту ${commitHash}`)
|
||||
// const act1Result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.SetAct1.actionName,
|
||||
// authorization: [{ actor: coopname, permission: 'active' }],
|
||||
// data: act1Data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
|
||||
// getTotalRamUsage(act1Result)
|
||||
// expect(act1Result.transaction_id).toBeDefined()
|
||||
// }
|
||||
|
||||
// {
|
||||
// // Утверждение коммита
|
||||
// const act2Data: CapitalContract.Actions.SetAct2.ISetAct2 = {
|
||||
// coopname,
|
||||
// application: coopname,
|
||||
// username: creator,
|
||||
// commit_hash: commitHash,
|
||||
// act: fakeDocument,
|
||||
// }
|
||||
|
||||
// console.log(`\n✅ Установка акта2 по коммиту ${commitHash}`)
|
||||
// const act2Result = await blockchain.api.transact(
|
||||
// {
|
||||
// actions: [
|
||||
// {
|
||||
// account: CapitalContract.contractName.production,
|
||||
// name: CapitalContract.Actions.SetAct2.actionName,
|
||||
// authorization: [{ actor: coopname, permission: 'active' }],
|
||||
// data: act2Data,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// blocksBehind: 3,
|
||||
// expireSeconds: 30,
|
||||
// },
|
||||
// )
|
||||
|
||||
// getTotalRamUsage(act2Result)
|
||||
// expect(act2Result.transaction_id).toBeDefined()
|
||||
// }
|
||||
|
||||
// Проверка результата после утверждения коммита
|
||||
const finalResult = (await blockchain.getTableRows(
|
||||
@@ -192,12 +264,12 @@ export async function commitToResult(
|
||||
console.log('▶ Проект:', finalProject)
|
||||
console.log('▶ Контрибьютор:', finalContributor)
|
||||
|
||||
expect(parseFloat(finalResult.spend)).toBe(parseFloat(prevResult.spend) + parseFloat(totalSpended))
|
||||
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
|
||||
// expect(parseFloat(finalResult.spended)).toBe(parseFloat(prevResult.spended) + parseFloat(totalSpended))
|
||||
// expect(parseFloat(finalProject.spended)).toBe(parseFloat(prevProject.spended))
|
||||
|
||||
// Проверка, что у контрибьютора увеличились contributed_hours и available
|
||||
expect(parseFloat(finalContributor.contributed_hours)).toBe(parseFloat(prevContributor.contributed_hours) + spendHours)
|
||||
expect(parseFloat(finalContributor.available)).toBe(parseFloat(prevContributor.available) + parseFloat(totalSpended))
|
||||
// expect(parseFloat(finalContributor.contributed_hours)).toBe(parseFloat(prevContributor.contributed_hours) + spendHours)
|
||||
// expect(parseFloat(finalContributor.available)).toBe(parseFloat(prevContributor.available) + parseFloat(totalSpended))
|
||||
|
||||
console.log(`\n✅ Коммит ${commitHash} завершен успешно!`)
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
export const capitalProgramId = 3
|
||||
export const sourceProgramId = 3
|
||||
export const capitalProgramId = 4
|
||||
export const walletProgramId = 1
|
||||
export const ratePerHour = '1000.0000 RUB'
|
||||
export const sourceProgramName = 'source'
|
||||
export const capitalProgramName = 'capital'
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
|
||||
import { generateRandomSHA256 } from '../../utils/randomHash'
|
||||
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
|
||||
import { processDecision } from '../soviet/processDecision'
|
||||
import { capitalProgramId } from './consts'
|
||||
import { capitalProgramId, sourceProgramId } from './consts'
|
||||
|
||||
export async function investInProject(
|
||||
blockchain: any,
|
||||
|
||||
@@ -174,26 +174,24 @@ export async function registerExpense(
|
||||
const blockchainWithdraw = (await blockchain.getTableRows(
|
||||
GatewayContract.contractName.production,
|
||||
coopname,
|
||||
GatewayContract.Tables.Withdraws.tableName,
|
||||
GatewayContract.Tables.Outcomes.tableName,
|
||||
1,
|
||||
expenseHash,
|
||||
expenseHash,
|
||||
3,
|
||||
2,
|
||||
'sha256',
|
||||
))[0]
|
||||
|
||||
console.log('🔍 Вывод средств:', blockchainWithdraw)
|
||||
expect(blockchainWithdraw).toBeDefined()
|
||||
expect(blockchainWithdraw.withdraw_hash).toBe(expenseHash)
|
||||
expect(blockchainWithdraw.outcome_hash).toBe(expenseHash)
|
||||
expect(blockchainWithdraw.quantity).toBe(expenseAmount)
|
||||
expect(blockchainWithdraw.status).toBe('authorized')
|
||||
expect(blockchainWithdraw.status).toBe('pending')
|
||||
|
||||
// Завершение вывода
|
||||
const completeWithdrawData: GatewayContract.Actions.CompleteWithdraw.ICompleteWithdraw = {
|
||||
const completeWithdrawData: GatewayContract.Actions.CompleteOutcome.ICompleteOutcome = {
|
||||
coopname,
|
||||
application: '',
|
||||
memo: '',
|
||||
withdraw_hash: expenseHash,
|
||||
outcome_hash: expenseHash,
|
||||
}
|
||||
|
||||
console.log(`\n✅ Завершение вывода ${expenseHash}`)
|
||||
@@ -202,7 +200,7 @@ export async function registerExpense(
|
||||
actions: [
|
||||
{
|
||||
account: GatewayContract.contractName.production,
|
||||
name: GatewayContract.Actions.CompleteWithdraw.actionName,
|
||||
name: GatewayContract.Actions.CompleteOutcome.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data: completeWithdrawData,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect } from 'vitest'
|
||||
import { signAgreement } from '../soviet/signAgreement'
|
||||
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
|
||||
import { capitalProgramId } from './consts'
|
||||
import { capitalProgramName, sourceProgramId } from './consts'
|
||||
|
||||
export async function signCapitalAgreement(
|
||||
blockchain: any,
|
||||
@@ -9,20 +9,20 @@ export async function signCapitalAgreement(
|
||||
username: string,
|
||||
fakeDocument: any,
|
||||
) {
|
||||
const txId = await signAgreement(blockchain, coopname, username, 'cofund', fakeDocument)
|
||||
const txId = await signAgreement(blockchain, coopname, username, capitalProgramName, fakeDocument)
|
||||
|
||||
const wallet = await getUserProgramWallet(blockchain, coopname, username, capitalProgramId)
|
||||
const wallet = await getUserProgramWallet(blockchain, coopname, username, sourceProgramId)
|
||||
|
||||
expect(wallet).toEqual(expect.objectContaining({
|
||||
coopname,
|
||||
username,
|
||||
available: expect.any(String),
|
||||
blocked: expect.any(String),
|
||||
program_id: capitalProgramId,
|
||||
program_id: sourceProgramId,
|
||||
membership_contribution: expect.any(String),
|
||||
}))
|
||||
|
||||
const program = await getCoopProgramWallet(blockchain, coopname, capitalProgramId)
|
||||
const program = await getCoopProgramWallet(blockchain, coopname, sourceProgramId)
|
||||
|
||||
return { wallet, program, txId }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { expect } from 'vitest'
|
||||
import { signAgreement } from '../soviet/signAgreement'
|
||||
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
|
||||
import { sourceProgramId, sourceProgramName } from './consts'
|
||||
|
||||
export async function signGenerationAgreement(
|
||||
blockchain: any,
|
||||
coopname: string,
|
||||
username: string,
|
||||
fakeDocument: any,
|
||||
) {
|
||||
const txId = await signAgreement(blockchain, coopname, username, sourceProgramName, fakeDocument)
|
||||
|
||||
const wallet = await getUserProgramWallet(blockchain, coopname, username, sourceProgramId)
|
||||
|
||||
expect(wallet).toEqual(expect.objectContaining({
|
||||
coopname,
|
||||
username,
|
||||
available: expect.any(String),
|
||||
blocked: expect.any(String),
|
||||
program_id: sourceProgramId,
|
||||
membership_contribution: expect.any(String),
|
||||
}))
|
||||
|
||||
const program = await getCoopProgramWallet(blockchain, coopname, sourceProgramId)
|
||||
|
||||
return { wallet, program, txId }
|
||||
}
|
||||
@@ -44,15 +44,14 @@ export async function withdrawContribution(
|
||||
console.log('▶ Проект:', prevProject)
|
||||
|
||||
// Создание заявления на возврат
|
||||
const createWithdrawData: CapitalContract.Actions.CreateWithdraw1.ICreateWithdraw = {
|
||||
const createWithdrawData: CapitalContract.Actions.WithdrawResult.IWithdrawFromResult = {
|
||||
coopname,
|
||||
application: coopname,
|
||||
username,
|
||||
result_hash: resultHash,
|
||||
withdraw_hash: withdrawHash,
|
||||
commit_hashes: commitHashes,
|
||||
contribution_statement: fakeDocument,
|
||||
return_statement: fakeDocument,
|
||||
amount: withdrawAmount,
|
||||
}
|
||||
|
||||
console.log(`\n🚀 Отправка транзакции CreateWithdraw для ${username} на сумму ${withdrawAmount}`)
|
||||
@@ -61,7 +60,7 @@ export async function withdrawContribution(
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.CreateWithdraw1.actionName,
|
||||
name: CapitalContract.Actions.WithdrawResult.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data: createWithdrawData,
|
||||
},
|
||||
@@ -79,7 +78,7 @@ export async function withdrawContribution(
|
||||
let blockchainWithdraw = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
coopname,
|
||||
'withdraws',
|
||||
CapitalContract.Tables.ResultWithdraws.tableName,
|
||||
1,
|
||||
withdrawHash,
|
||||
withdrawHash,
|
||||
@@ -93,12 +92,11 @@ export async function withdrawContribution(
|
||||
expect(blockchainWithdraw.amount).toBe(withdrawAmount)
|
||||
|
||||
// Подтверждение возврата
|
||||
const approveWithdrawData: CapitalContract.Actions.ApproveWithdraw.IApproveWithdraw = {
|
||||
const approveWithdrawData: CapitalContract.Actions.ApproveWithdrawResult.IApproveWithdrawResult = {
|
||||
coopname,
|
||||
application: coopname,
|
||||
approver: 'ant',
|
||||
withdraw_hash: withdrawHash,
|
||||
approved_contribution_statement: fakeDocument,
|
||||
approved_return_statement: fakeDocument,
|
||||
}
|
||||
|
||||
@@ -108,7 +106,7 @@ export async function withdrawContribution(
|
||||
actions: [
|
||||
{
|
||||
account: CapitalContract.contractName.production,
|
||||
name: CapitalContract.Actions.ApproveWithdraw.actionName,
|
||||
name: CapitalContract.Actions.ApproveWithdrawResult.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data: approveWithdrawData,
|
||||
},
|
||||
@@ -126,7 +124,7 @@ export async function withdrawContribution(
|
||||
blockchainWithdraw = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
coopname,
|
||||
'withdraws',
|
||||
CapitalContract.Tables.ResultWithdraws.tableName,
|
||||
1,
|
||||
withdrawHash,
|
||||
withdrawHash,
|
||||
@@ -146,17 +144,15 @@ export async function withdrawContribution(
|
||||
1000,
|
||||
)
|
||||
const lastDecision = decisions[decisions.length - 1]
|
||||
const prevLastDecision = decisions[decisions.length - 2]
|
||||
|
||||
console.log(`\n📜 Выполнение решений: ${prevLastDecision.id}, ${lastDecision.id}`)
|
||||
console.log(`\n📜 Выполнение решения: ${lastDecision.id}`)
|
||||
|
||||
await processDecision(blockchain, prevLastDecision.id)
|
||||
await processDecision(blockchain, lastDecision.id)
|
||||
|
||||
blockchainWithdraw = (await blockchain.getTableRows(
|
||||
CapitalContract.contractName.production,
|
||||
coopname,
|
||||
'withdraws',
|
||||
CapitalContract.Tables.ResultWithdraws.tableName,
|
||||
1,
|
||||
withdrawHash,
|
||||
withdrawHash,
|
||||
@@ -203,7 +199,9 @@ export async function withdrawContribution(
|
||||
expect(parseFloat(programWallet.blocked)).toBe(parseFloat(prevProgramWallet.blocked))
|
||||
|
||||
// Проверка изменения spend в проекте
|
||||
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend) + parseFloat(withdrawAmount))
|
||||
expect(parseFloat(finalProject.withdrawed)).toBe(parseFloat(prevProject.withdrawed) + parseFloat(withdrawAmount))
|
||||
|
||||
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
|
||||
|
||||
console.log(`\n✅ Возврат на ${withdrawAmount} завершен успешно!`)
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||
import { GatewayContract, RegistratorContract, SovietContract } from 'cooptypes'
|
||||
import { sha256 } from 'eosjs/dist/eosjs-key-conversions'
|
||||
import Blockchain from '../blockchain'
|
||||
import config from '../configs'
|
||||
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
|
||||
import { addUser } from '../init/participant'
|
||||
import { generateRandomUsername } from '../utils/randomUsername'
|
||||
import { generateRandomSHA256 } from '../utils/randomHash'
|
||||
import { signWalletAgreement } from './wallet/signWalletAgreement'
|
||||
import { depositToWallet } from './wallet/depositToWallet'
|
||||
import { processDecision } from './soviet/processDecision'
|
||||
import { getParticipant } from './registrator/getParticipant'
|
||||
import { registerUser } from './registrator/registerUser'
|
||||
|
||||
const blockchain = new Blockchain(config.network, config.private_keys)
|
||||
let tester1: string
|
||||
const walletProgramStates1: any[] = []
|
||||
|
||||
const fakeDocument = {
|
||||
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
|
||||
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
|
||||
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
|
||||
meta: '{}',
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
await blockchain.update_pass_instance()
|
||||
}, 500_000)
|
||||
|
||||
afterAll(() => {
|
||||
console.log('\n📊 **RAM USAGE SUMMARY** 📊')
|
||||
let totalGlobalRam = 0
|
||||
|
||||
for (const [key, ramUsed] of Object.entries(globalRamStats)) {
|
||||
console.log(` ${key} = ${(ramUsed / 1024).toFixed(2)} kb`)
|
||||
totalGlobalRam += ramUsed
|
||||
}
|
||||
|
||||
console.log(`\n💾 **TOTAL RAM USED IN TESTS**: ${(totalGlobalRam / 1024).toFixed(2)} kb\n`)
|
||||
})
|
||||
|
||||
describe('тест Registrator', () => {
|
||||
it('регистируем пайщика 1', async () => {
|
||||
const coopname = 'voskhod'
|
||||
const tester1 = generateRandomUsername()
|
||||
|
||||
await registerUser(blockchain, coopname, tester1)
|
||||
})
|
||||
|
||||
it('регистируем пайщика 2', async () => {
|
||||
const coopname = 'voskhod'
|
||||
const tester2 = generateRandomUsername()
|
||||
|
||||
await registerUser(blockchain, coopname, tester2)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
import { SovietContract } from 'cooptypes'
|
||||
import type Blockchain from '../../blockchain'
|
||||
|
||||
export async function getParticipant(
|
||||
blockchain: Blockchain,
|
||||
coopname: string,
|
||||
username: string,
|
||||
) {
|
||||
const participant = (await blockchain.getTableRows(
|
||||
SovietContract.contractName.production,
|
||||
'voskhod',
|
||||
'participants',
|
||||
1,
|
||||
username,
|
||||
username,
|
||||
))[0]
|
||||
|
||||
return participant
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { GatewayContract, RegistratorContract, SovietContract } from 'cooptypes'
|
||||
import { expect } from 'vitest'
|
||||
import { generateRandomSHA256 } from '../../utils/randomHash'
|
||||
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
|
||||
import { processDecision } from '../soviet/processDecision'
|
||||
import { getParticipant } from '../registrator/getParticipant'
|
||||
import { fakeDocument } from '../soviet/fakeDocument'
|
||||
import { compareTokenAmounts, getCoopWallet } from '../wallet/walletUtils'
|
||||
|
||||
export async function registerUser(blockchain: any, coopname: string, username: string) {
|
||||
const registration_hash = generateRandomSHA256()
|
||||
|
||||
const account = await blockchain.generateKeypair(username, undefined, 'Аккаунт кооператива')
|
||||
|
||||
// 🔹 Получаем балансы до регистрации
|
||||
const prevCoopWallet = await getCoopWallet(blockchain, coopname)
|
||||
const prevAvailable = prevCoopWallet?.circulating_account?.available || '0.0000 RUB'
|
||||
const prevInitial = prevCoopWallet?.initial_account?.available || '0.0000 RUB'
|
||||
console.log('📦 CoopWallet BEFORE:', prevCoopWallet)
|
||||
|
||||
// 🔹 1. Создание аккаунта
|
||||
{
|
||||
const data: RegistratorContract.Actions.CreateAccount.ICreateAccount = {
|
||||
coopname,
|
||||
referer: '',
|
||||
username,
|
||||
public_key: account.publicKey,
|
||||
meta: '',
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact({
|
||||
actions: [{
|
||||
account: RegistratorContract.contractName.production,
|
||||
name: RegistratorContract.Actions.CreateAccount.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data,
|
||||
}],
|
||||
}, { blocksBehind: 3, expireSeconds: 30 })
|
||||
|
||||
getTotalRamUsage(result)
|
||||
console.log('✅ Аккаунт создан')
|
||||
}
|
||||
|
||||
// 🔹 2. Регистрация пайщика
|
||||
{
|
||||
const data: RegistratorContract.Actions.RegisterUser.IRegisterUser = {
|
||||
coopname,
|
||||
braname: '',
|
||||
username,
|
||||
type: 'individual',
|
||||
statement: fakeDocument,
|
||||
registration_hash,
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact({
|
||||
actions: [{
|
||||
account: RegistratorContract.contractName.production,
|
||||
name: RegistratorContract.Actions.RegisterUser.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data,
|
||||
}],
|
||||
}, { blocksBehind: 3, expireSeconds: 30 })
|
||||
|
||||
getTotalRamUsage(result)
|
||||
console.log('✅ Пайщик зарегистрирован')
|
||||
}
|
||||
|
||||
// 🔹 3. Подтверждение прихода
|
||||
{
|
||||
const data: GatewayContract.Actions.CompleteIncome.ICompleteIncome = {
|
||||
coopname,
|
||||
income_hash: registration_hash,
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact({
|
||||
actions: [{
|
||||
account: GatewayContract.contractName.production,
|
||||
name: GatewayContract.Actions.CompleteIncome.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data,
|
||||
}],
|
||||
}, { blocksBehind: 3, expireSeconds: 30 })
|
||||
|
||||
getTotalRamUsage(result)
|
||||
console.log('✅ Приход подтвержден')
|
||||
}
|
||||
|
||||
// 🔹 4. Исполнение решения
|
||||
const decisions = await blockchain.getTableRows(
|
||||
SovietContract.contractName.production,
|
||||
coopname,
|
||||
'decisions',
|
||||
1000,
|
||||
)
|
||||
const lastDecision = decisions.at(-1)
|
||||
console.log('📜 Последнее решение:', lastDecision)
|
||||
await processDecision(blockchain, lastDecision.id)
|
||||
console.log('✅ Решение выполнено')
|
||||
|
||||
// 🔹 5. Проверка участника
|
||||
const participant = await getParticipant(blockchain, coopname, username)
|
||||
console.log('🙋 Участник:', participant)
|
||||
|
||||
expect(participant).toBeDefined()
|
||||
expect(participant.has_vote).toBe(1)
|
||||
expect(participant.status).toBe('accepted')
|
||||
expect(participant.username).toBe(username)
|
||||
|
||||
// 🔹 6. Проверка балансов после регистрации
|
||||
const coopWalletAfter = await getCoopWallet(blockchain, coopname)
|
||||
const newAvailable = coopWalletAfter?.circulating_account?.available || '0.0000 RUB'
|
||||
const newInitial = coopWalletAfter?.initial_account?.available || '0.0000 RUB'
|
||||
|
||||
console.log('💰 CoopWallet AFTER:', coopWalletAfter)
|
||||
|
||||
const minAmount = parseFloat(participant.minimum_amount.split(' ')[0])
|
||||
const initAmount = parseFloat(participant.initial_amount.split(' ')[0])
|
||||
|
||||
compareTokenAmounts(prevAvailable, newAvailable, minAmount)
|
||||
compareTokenAmounts(prevInitial, newInitial, initAmount)
|
||||
|
||||
return participant
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||
import Blockchain from '../blockchain'
|
||||
import config from '../configs'
|
||||
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
|
||||
import { createParticipant } from '../init/participant'
|
||||
import { addUser } from '../init/participant'
|
||||
import { generateRandomUsername } from '../utils/randomUsername'
|
||||
import { signWalletAgreement } from './wallet/signWalletAgreement'
|
||||
import { depositToWallet } from './wallet/depositToWallet'
|
||||
@@ -23,7 +23,7 @@ beforeAll(async () => {
|
||||
|
||||
tester1 = generateRandomUsername()
|
||||
console.log('tester1: ', tester1)
|
||||
await createParticipant(tester1)
|
||||
await addUser(tester1)
|
||||
}, 500_000)
|
||||
|
||||
afterAll(() => {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { randomInt } from 'node:crypto'
|
||||
import { GatewayContract } from 'cooptypes'
|
||||
import { GatewayContract, WalletContract } from 'cooptypes'
|
||||
import { expect } from 'vitest'
|
||||
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
|
||||
import { generateRandomSHA256 } from '../../utils/randomHash'
|
||||
import { compareTokenAmounts, getCoopProgramWallet, getCoopWallet, getDeposit, getUserProgramWallet } from './walletUtils'
|
||||
|
||||
export async function depositToWallet(blockchain: any, coopname: string, username: string, amount: number) {
|
||||
const depositId = randomInt(100000)
|
||||
|
||||
const data: GatewayContract.Actions.CreateDeposit.ICreateDeposit = {
|
||||
const data: WalletContract.Actions.CreateDeposit.ICreateDeposit = {
|
||||
coopname,
|
||||
username,
|
||||
deposit_id: depositId,
|
||||
type: 'deposit',
|
||||
deposit_hash: generateRandomSHA256(),
|
||||
quantity: `${amount.toFixed(4)} RUB`,
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
|
||||
{
|
||||
actions: [
|
||||
{
|
||||
account: GatewayContract.contractName.production,
|
||||
name: GatewayContract.Actions.CreateDeposit.actionName,
|
||||
authorization: [{ actor: username, permission: 'active' }],
|
||||
account: WalletContract.contractName.production,
|
||||
name: WalletContract.Actions.CreateDeposit.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data,
|
||||
},
|
||||
],
|
||||
@@ -35,16 +35,15 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
|
||||
getTotalRamUsage(result)
|
||||
expect(result.transaction_id).toBeDefined()
|
||||
|
||||
const deposit = await getDeposit(blockchain, coopname, depositId)
|
||||
const deposit = await getDeposit(blockchain, coopname, data.deposit_hash)
|
||||
|
||||
expect(deposit).toEqual(expect.objectContaining({
|
||||
id: depositId,
|
||||
expect(deposit).toMatchObject({
|
||||
deposit_hash: data.deposit_hash,
|
||||
username,
|
||||
coopname,
|
||||
type: 'deposit',
|
||||
quantity: `${amount.toFixed(4)} RUB`,
|
||||
status: 'pending',
|
||||
}))
|
||||
})
|
||||
|
||||
const prevUserWallet = await getUserProgramWallet(blockchain, coopname, username, 1)
|
||||
const prevUserWalletAvailable = prevUserWallet?.available || '0.0000 RUB'
|
||||
@@ -52,11 +51,9 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
|
||||
const prevCoopWallet = await getCoopWallet(blockchain, coopname)
|
||||
const prevCoopWalletAvailable = prevCoopWallet?.circulating_account?.available || '0.0000 RUB'
|
||||
|
||||
const data2: GatewayContract.Actions.CompleteDeposit.ICompleteDeposit = {
|
||||
const data2: GatewayContract.Actions.CompleteIncome.ICompleteIncome = {
|
||||
coopname,
|
||||
admin: coopname,
|
||||
deposit_id: depositId,
|
||||
memo: '',
|
||||
income_hash: data.deposit_hash,
|
||||
}
|
||||
|
||||
const result2 = await blockchain.api.transact(
|
||||
@@ -64,7 +61,7 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
|
||||
actions: [
|
||||
{
|
||||
account: GatewayContract.contractName.production,
|
||||
name: GatewayContract.Actions.CompleteDeposit.actionName,
|
||||
name: GatewayContract.Actions.CompleteIncome.actionName,
|
||||
authorization: [{ actor: coopname, permission: 'active' }],
|
||||
data: data2,
|
||||
},
|
||||
@@ -77,12 +74,14 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
|
||||
)
|
||||
|
||||
getTotalRamUsage(result2)
|
||||
const deposit2 = await getDeposit(blockchain, coopname, depositId)
|
||||
expect(deposit2.status).toBe('completed')
|
||||
|
||||
const deposit2 = await getDeposit(blockchain, coopname, data.deposit_hash)
|
||||
expect(deposit2).toBeUndefined()
|
||||
|
||||
const program = await getCoopProgramWallet(blockchain, coopname, 1)
|
||||
|
||||
const userWallet = await getUserProgramWallet(blockchain, coopname, username, 1)
|
||||
console.log('▶ Кошелёк пользователя после пополнения: ', userWallet)
|
||||
|
||||
// Проверяем изменение балансов
|
||||
compareTokenAmounts(prevUserWalletAvailable, userWallet.available, amount)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { FundContract, GatewayContract, SovietContract } from 'cooptypes'
|
||||
import { FundContract, SovietContract, WalletContract } from 'cooptypes'
|
||||
import { expect } from 'vitest'
|
||||
import type Blockchain from '../../blockchain'
|
||||
|
||||
export async function getUserProgramWallet(blockchain: any, coopname: string, username: string, program_id: number) {
|
||||
const wallets = await blockchain.getTableRows(
|
||||
@@ -24,7 +25,7 @@ export async function getCoopProgramWallet(blockchain: any, coopname: string, pr
|
||||
program_id.toString(),
|
||||
program_id.toString(),
|
||||
)
|
||||
console.log('PROGRAMS:', program)
|
||||
|
||||
return program[0]
|
||||
}
|
||||
|
||||
@@ -37,14 +38,16 @@ export async function getCoopWallet(blockchain: any, coopname: string) {
|
||||
))[0]
|
||||
}
|
||||
|
||||
export async function getDeposit(blockchain: any, coopname: string, deposit_id: number) {
|
||||
export async function getDeposit(blockchain: Blockchain, coopname: string, deposit_hash: string) {
|
||||
return (await blockchain.getTableRows(
|
||||
GatewayContract.contractName.production,
|
||||
WalletContract.contractName.production,
|
||||
coopname,
|
||||
'deposits',
|
||||
WalletContract.Tables.Deposits.tableName,
|
||||
1,
|
||||
deposit_id.toString(),
|
||||
deposit_id.toString(),
|
||||
deposit_hash,
|
||||
deposit_hash,
|
||||
2,
|
||||
'sha256',
|
||||
))[0]
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
eosio-wallet/wallet.lock
|
||||
eosio-wallet/keosd.sock
|
||||
@@ -0,0 +1,8 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/cleos
|
||||
@@ -0,0 +1,54 @@
|
||||
# The filename (relative to data-dir) to create a unix socket for HTTP RPC; set blank to disable. (eosio::http_plugin)
|
||||
# unix-socket-path = keosd.sock
|
||||
|
||||
# The local IP and port to listen for incoming http connections; setting to http-category-address to enable http-category-address option. leave blank to disable. (eosio::http_plugin)
|
||||
# http-server-address =
|
||||
|
||||
# Specify the Access-Control-Allow-Origin to be returned on each request (eosio::http_plugin)
|
||||
# access-control-allow-origin =
|
||||
|
||||
# Specify the Access-Control-Allow-Headers to be returned on each request (eosio::http_plugin)
|
||||
# access-control-allow-headers =
|
||||
|
||||
# Specify the Access-Control-Max-Age to be returned on each request. (eosio::http_plugin)
|
||||
# access-control-max-age =
|
||||
|
||||
# Specify if Access-Control-Allow-Credentials: true should be returned on each request. (eosio::http_plugin)
|
||||
# access-control-allow-credentials = false
|
||||
|
||||
# The maximum body size in bytes allowed for incoming RPC requests (eosio::http_plugin)
|
||||
# max-body-size = 2097152
|
||||
|
||||
# Maximum size in megabytes http_plugin should use for processing http requests. -1 for unlimited. 503 error response when exceeded. (eosio::http_plugin)
|
||||
# http-max-bytes-in-flight-mb = 500
|
||||
|
||||
# Maximum number of requests http_plugin should use for processing http requests. 503 error response when exceeded. (eosio::http_plugin)
|
||||
# http-max-in-flight-requests = -1
|
||||
|
||||
# Maximum time on main thread for processing a request, -1 for unlimited (eosio::http_plugin)
|
||||
# http-max-response-time-ms = 15
|
||||
|
||||
# Append the error log to HTTP responses (eosio::http_plugin)
|
||||
# verbose-http-errors = false
|
||||
|
||||
# If set to false, then any incoming "Host" header is considered valid (eosio::http_plugin)
|
||||
# http-validate-host = true
|
||||
|
||||
# Additionally acceptable values for the "Host" header of incoming HTTP requests, can be specified multiple times. Includes http/s_server_address by default. (eosio::http_plugin)
|
||||
# http-alias =
|
||||
|
||||
# Number of worker threads in http thread pool (eosio::http_plugin)
|
||||
# http-threads = 2
|
||||
|
||||
# If set to false, do not keep HTTP connections alive, even if client requests. (eosio::http_plugin)
|
||||
# http-keep-alive = true
|
||||
|
||||
# The path of the wallet files (absolute path or relative to application data dir) (eosio::wallet_plugin)
|
||||
# wallet-dir = "."
|
||||
|
||||
# Timeout for unlocked wallet in seconds (default 900 (15 minutes)). Wallets will automatically lock after specified number of seconds of inactivity. Activity is defined as any wallet command e.g. list-wallets. (eosio::wallet_plugin)
|
||||
# unlock-timeout = 900
|
||||
|
||||
# Plugin(s) to enable, may be specified multiple times
|
||||
# plugin =
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cipher_keys": "710a43f09ece89ed7baf387cc1ae3127cb90d9fc16cffda660c71c75678d1fe4d8b22e1fd0476e232581a37e3c3beda3e25b873ae0a9d43c274f30b4d9ea394f4c583234a6d0715540163edc28db22de98b0aa7e9431ebfc6f28b1eaf665326d7456b55f1fa776e7eac61d90264871e6a58b3ebbd8dec377e05ef7fec64b348aef02459329f49d1384bf2af32fd02ce1"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@coopenomics/cleos",
|
||||
"version": "2025.7.2",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"run": "./run.sh"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
docker run --rm -it --name cleos \
|
||||
--network dicoop \
|
||||
--volume ./eosio-wallet:/root/eosio-wallet \
|
||||
--volume ./scripts:/root/scripts \
|
||||
-w /root/scripts \
|
||||
dicoop/blockchain_v5.1.1:dev /bin/bash
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
ls
|
||||
exit
|
||||
ls
|
||||
./cleos.sh
|
||||
exit
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cleos -u http://node:8888 "$@"
|
||||
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
rm ../eosio-wallet/keosd.sock
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cleos wallet unlock --name default < ../eosio-wallet/password
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/contracts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/contracts
|
||||
|
||||
@@ -30,6 +30,9 @@ macro(add_contract_build name)
|
||||
endmacro()
|
||||
|
||||
# Добавляем все контракты
|
||||
add_contract_build(meet)
|
||||
add_contract_build(loan)
|
||||
add_contract_build(wallet)
|
||||
add_contract_build(capital)
|
||||
add_contract_build(branch)
|
||||
add_contract_build(contributor)
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -1,18 +1,15 @@
|
||||
#include "branch.hpp"
|
||||
|
||||
#include "src/addtrusted.cpp"
|
||||
#include "src/createbranch.cpp"
|
||||
#include "src/deletebranch.cpp"
|
||||
#include "src/deltrusted.cpp"
|
||||
#include "src/editbranch.cpp"
|
||||
|
||||
using namespace eosio;
|
||||
|
||||
[[eosio::action]] void branch::migrate() {
|
||||
require_auth(_branch);
|
||||
|
||||
branchstat_index stat(_branch, _branch.value);
|
||||
auto st = stat.find("nzpzufzhcfab"_n.value);
|
||||
|
||||
if (st != stat.end()){
|
||||
stat.modify(st, _branch, [&](auto &s){
|
||||
s.count = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,121 +18,3 @@ using namespace eosio;
|
||||
require_auth(_system);
|
||||
};
|
||||
|
||||
|
||||
[[eosio::action]] void branch::addtrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "addtrusted"_n);
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
auto trusted_account = get_account_or_fail(trusted);
|
||||
eosio::check(trusted_account.type == "individual"_n, "Только физическое лицо может быть назначено доверенным кооперативного участка");
|
||||
|
||||
branches.modify(branch, coopname, [&](auto &b) {
|
||||
eosio::check(std::find(b.trusted.begin(), b.trusted.end(), trusted) == b.trusted.end(),
|
||||
"Доверенный уже добавлен в кооперативный участок");
|
||||
eosio::check(b.trusted.size() < 3, "Не больше трех доверенных на одном кооперативном участке");
|
||||
b.trusted.push_back(trusted);
|
||||
});
|
||||
}
|
||||
|
||||
[[eosio::action]] void branch::deltrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "deltrusted"_n);
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
branches.modify(branch, coopname, [&](auto &b) {
|
||||
auto it = std::find(b.trusted.begin(), b.trusted.end(), trusted);
|
||||
eosio::check(it != b.trusted.end(), "Доверенный не найден в кооперативном участке");
|
||||
b.trusted.erase(it);
|
||||
});
|
||||
}
|
||||
|
||||
[[eosio::action]] void branch::createbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "createbranch"_n);
|
||||
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto coop = get_cooperative_or_fail(coopname);
|
||||
|
||||
auto authorizer_account = get_account_or_fail(trustee);
|
||||
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
|
||||
|
||||
branches.emplace(coopname, [&](auto &row) {
|
||||
row.braname = braname;
|
||||
row.trustee = trustee;
|
||||
});
|
||||
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_registrator,
|
||||
"createbranch"_n,
|
||||
std::make_tuple(coopname, braname)
|
||||
).send();
|
||||
|
||||
uint64_t branch_count = add_branch_count(coopname);
|
||||
|
||||
if (!coop.is_branched && branch_count >= 3) { //регистрируем переход на кооперативные участки
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_registrator,
|
||||
"enabranches"_n,
|
||||
std::make_tuple(coopname)
|
||||
).send();
|
||||
}
|
||||
|
||||
//TODO create subfunds and subwallets
|
||||
|
||||
}
|
||||
|
||||
[[eosio::action]] void branch::editbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "editbranch"_n);
|
||||
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
auto authorizer_account = get_account_or_fail(trustee);
|
||||
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
|
||||
|
||||
branches.modify(branch, coopname, [&](auto &b) {
|
||||
b.trustee = trustee;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
[[eosio::action]] void branch::deletebranch(eosio::name coopname, eosio::name braname) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "deletebranch"_n);
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
auto coop = get_cooperative_or_fail(coopname);
|
||||
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
branches.erase(branch);
|
||||
|
||||
// отключаем участников кооператива от кооперативного участка
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_soviet,
|
||||
"deletebranch"_n,
|
||||
std::make_tuple(coopname, braname)
|
||||
).send();
|
||||
|
||||
uint64_t new_count = sub_branch_count(coopname);
|
||||
|
||||
if (coop.is_branched && new_count < 3) { //отключаем систему КУ, если их меньше 3
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_registrator,
|
||||
"disbranches"_n,
|
||||
std::make_tuple(coopname)
|
||||
).send();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[[eosio::action]] void branch::addtrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "addtrusted"_n);
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
auto trusted_account = get_account_or_fail(trusted);
|
||||
eosio::check(trusted_account.type == "individual"_n, "Только физическое лицо может быть назначено доверенным кооперативного участка");
|
||||
|
||||
branches.modify(branch, coopname, [&](auto &b) {
|
||||
eosio::check(std::find(b.trusted.begin(), b.trusted.end(), trusted) == b.trusted.end(),
|
||||
"Доверенный уже добавлен в кооперативный участок");
|
||||
eosio::check(b.trusted.size() < 3, "Не больше трех доверенных на одном кооперативном участке");
|
||||
b.trusted.push_back(trusted);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
[[eosio::action]] void branch::createbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "createbranch"_n);
|
||||
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto coop = get_cooperative_or_fail(coopname);
|
||||
|
||||
auto authorizer_account = get_account_or_fail(trustee);
|
||||
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
|
||||
|
||||
branches.emplace(coopname, [&](auto &row) {
|
||||
row.braname = braname;
|
||||
row.trustee = trustee;
|
||||
});
|
||||
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_registrator,
|
||||
"createbranch"_n,
|
||||
std::make_tuple(coopname, braname)
|
||||
).send();
|
||||
|
||||
uint64_t branch_count = add_branch_count(coopname);
|
||||
|
||||
if (!coop.is_branched && branch_count >= 3) { //регистрируем переход на кооперативные участки
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_registrator,
|
||||
"enabranches"_n,
|
||||
std::make_tuple(coopname)
|
||||
).send();
|
||||
}
|
||||
|
||||
//TODO create subfunds and subwallets
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
[[eosio::action]] void branch::deletebranch(eosio::name coopname, eosio::name braname) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "deletebranch"_n);
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
auto coop = get_cooperative_or_fail(coopname);
|
||||
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
branches.erase(branch);
|
||||
|
||||
// отключаем участников кооператива от кооперативного участка
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_soviet,
|
||||
"deletebranch"_n,
|
||||
std::make_tuple(coopname, braname)
|
||||
).send();
|
||||
|
||||
uint64_t new_count = sub_branch_count(coopname);
|
||||
|
||||
if (coop.is_branched && new_count < 3) { //отключаем систему КУ, если их меньше 3
|
||||
action(
|
||||
permission_level{ _branch, "active"_n},
|
||||
_registrator,
|
||||
"disbranches"_n,
|
||||
std::make_tuple(coopname)
|
||||
).send();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
[[eosio::action]] void branch::deltrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "deltrusted"_n);
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
branches.modify(branch, coopname, [&](auto &b) {
|
||||
auto it = std::find(b.trusted.begin(), b.trusted.end(), trusted);
|
||||
eosio::check(it != b.trusted.end(), "Доверенный не найден в кооперативном участке");
|
||||
b.trusted.erase(it);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
[[eosio::action]] void branch::editbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
|
||||
check_auth_or_fail(_branch, coopname, coopname, "editbranch"_n);
|
||||
|
||||
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch = branches.find(braname.value);
|
||||
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
|
||||
|
||||
auto authorizer_account = get_account_or_fail(trustee);
|
||||
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
|
||||
|
||||
branches.modify(branch, coopname, [&](auto &b) {
|
||||
b.trustee = trustee;
|
||||
});
|
||||
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -1,97 +1,93 @@
|
||||
// capital.cpp
|
||||
#include "capital.hpp"
|
||||
|
||||
#include "src/result/createresult.cpp"
|
||||
#include "src/result/startdistrbn.cpp"
|
||||
#include "src/assignment/createassign.cpp"
|
||||
#include "src/assignment/startdistrbn.cpp"
|
||||
|
||||
#include "src/investment/createinvest.cpp"
|
||||
#include "src/investment/approveinvst.cpp"
|
||||
#include "src/investment/capauthinvst.cpp"
|
||||
|
||||
#include "src/managment/init.cpp"
|
||||
#include "src/commit/createcmmt.cpp"
|
||||
#include "src/commit/approvecmmt.cpp"
|
||||
#include "src/commit/declinecmmt.cpp"
|
||||
#include "src/commit/delcmmt.cpp"
|
||||
|
||||
#include "src/claim/setact1.cpp"
|
||||
#include "src/claim/setact2.cpp"
|
||||
#include "src/claim/createclaim.cpp"
|
||||
#include "src/claim/setstatement.cpp"
|
||||
#include "src/claim/authorize.cpp"
|
||||
#include "src/debt/createdebt.cpp"
|
||||
#include "src/debt/approvedebt.cpp"
|
||||
|
||||
#include "src/debt/debtauthcnfr.cpp"
|
||||
#include "src/debt/debtpaycnfrm.cpp"
|
||||
#include "src/debt/debtpaydcln.cpp"
|
||||
#include "src/debt/declinedebt.cpp"
|
||||
#include "src/debt/settledebt.cpp"
|
||||
|
||||
#include "src/result/approverslt.cpp"
|
||||
#include "src/result/updaterslt.cpp"
|
||||
#include "src/result/pushrslt.cpp"
|
||||
#include "src/result/authrslt.cpp"
|
||||
#include "src/result/setact1.cpp"
|
||||
#include "src/result/setact2.cpp"
|
||||
|
||||
#include "src/registration/capregcontr.cpp"
|
||||
#include "src/registration/approvereg.cpp"
|
||||
#include "src/registration/regcontrib.cpp"
|
||||
|
||||
#include "src/managment/init.cpp"
|
||||
#include "src/managment/createproj.cpp"
|
||||
#include "src/managment/addauthor.cpp"
|
||||
#include "src/managment/allocate.cpp"
|
||||
#include "src/managment/wthdrcallbck.cpp"
|
||||
#include "src/managment/diallocate.cpp"
|
||||
|
||||
#include "src/commit/createcmmt.cpp"
|
||||
#include "src/commit/approvecmmt.cpp"
|
||||
|
||||
#include "src/withdraw_from_result/createwthd1.cpp"
|
||||
#include "src/withdraw_from_result/capauthwthdc.cpp"
|
||||
#include "src/withdraw_from_result/capauthwthdr.cpp"
|
||||
#include "src/withdraw_from_result/authwithdrw1.cpp"
|
||||
#include "src/withdraw_from_result/capauthwthd1.cpp"
|
||||
#include "src/withdraw_from_result/approvewthd1.cpp"
|
||||
|
||||
#include "src/withdraw_from_project/createwthd2.cpp"
|
||||
#include "src/withdraw_from_project/capauthwthd2.cpp"
|
||||
#include "src/withdraw_from_project/approvewthd2.cpp"
|
||||
|
||||
#include "src/withdraw_from_program/createwthd3.cpp"
|
||||
#include "src/withdraw_from_program/capauthwthd3.cpp"
|
||||
#include "src/withdraw_from_program/approvewthd3.cpp"
|
||||
|
||||
#include "src/convert/approvecnvrt.cpp"
|
||||
#include "src/convert/createcnvrt.cpp"
|
||||
|
||||
#include "src/expense/approveexpns.cpp"
|
||||
#include "src/expense/capauthexpns.cpp"
|
||||
// #include "src/expense/capdeclexpns.cpp"
|
||||
#include "src/expense/createexpnse.cpp"
|
||||
#include "src/expense/expense_withdraw_callback.cpp"
|
||||
#include "src/expense/exppaycnfrm.cpp"
|
||||
|
||||
#include "src/fund/fund.cpp"
|
||||
#include "src/fund/refresh.cpp"
|
||||
|
||||
|
||||
#include "src/fundproj/fundproj.cpp"
|
||||
#include "src/fundproj/refreshproj.cpp"
|
||||
|
||||
#include "src/fundprog/fundprog.cpp"
|
||||
#include "src/fundprog/refreshprog.cpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
// TODO: внедрить коррекцию долей при выходе пайщика из проекта / программы
|
||||
// void capital::reduce_shares(name coopname, checksum256 project_hash, name username, asset amount) {
|
||||
// require_auth(_capital);
|
||||
|
||||
// auto exist_project = get_project(coopname, project_hash);
|
||||
// eosio::check(exist_project.has_value(), "Проект не найден");
|
||||
void capital::validate_project_hierarchy_depth(eosio::name coopname, checksum256 project_hash) {
|
||||
uint8_t level = 0;
|
||||
project_index projects(_capital, coopname.value);
|
||||
|
||||
auto current_project = get_project(coopname, project_hash);
|
||||
eosio::check(current_project.has_value(), "Проект не найден");
|
||||
|
||||
// project_index projects(_capital, coopname.value);
|
||||
// auto project = projects.find(exist_project->id);
|
||||
while (current_project -> parent_project_hash != checksum256()) {
|
||||
eosio::check(level < 12, "Превышено максимальное количество уровней родительских проектов (12)");
|
||||
|
||||
// contributor_index contributors(_capital, coopname.value);
|
||||
// auto idx = contributors.get_index<"byusername"_n>();
|
||||
// auto itr = idx.find(username.value);
|
||||
// eosio::check(itr != idx.end(), "Contributor not found");
|
||||
current_project = get_project(coopname, current_project->parent_project_hash);
|
||||
eosio::check(current_project.has_value(), "Родительский проект не найден");
|
||||
|
||||
// eosio::check(itr->share_balance >= amount, "Недостаточно долей для уменьшения");
|
||||
|
||||
// int64_t prev_total_shares = project->membership_total_shares.amount;
|
||||
// int64_t new_total_shares = prev_total_shares - amount.amount;
|
||||
|
||||
// eosio::check(new_total_shares >= 0, "Нельзя уменьшить total_shares ниже 0");
|
||||
|
||||
// // Пересчёт cumulative_reward_per_share для корректного распределения будущих выплат
|
||||
// if (new_total_shares > 0) {
|
||||
// projects.modify(project, coopname, [&](auto &p) {
|
||||
// p.membership_cumulative_reward_per_share =
|
||||
// (p.membership_cumulative_reward_per_share * prev_total_shares) / new_total_shares;
|
||||
// p.membership_total_shares -= amount;
|
||||
// });
|
||||
// } else {
|
||||
// // Если все доли исчезли, просто обнуляем
|
||||
// projects.modify(project, coopname, [&](auto &p) {
|
||||
// p.membership_cumulative_reward_per_share = 0;
|
||||
// p.membership_total_shares = asset(0, _root_govern_symbol);
|
||||
// });
|
||||
// }
|
||||
|
||||
// // Уменьшаем долю пользователя
|
||||
// auto primary_itr = contributors.find(itr->id);
|
||||
// contributors.modify(primary_itr, same_payer, [&](auto &c) {
|
||||
// c.share_balance -= amount;
|
||||
// });
|
||||
// }
|
||||
level++;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@@ -152,7 +148,7 @@ eosio::asset capital::get_amount_for_withdraw_from_commit(eosio::name coopname,
|
||||
c.status = "withdrawed"_n;
|
||||
});
|
||||
|
||||
return itr -> spend;
|
||||
return itr -> spended;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,6 +197,20 @@ std::optional<contributor> capital::get_active_contributor_or_fail(eosio::name c
|
||||
return contributor;
|
||||
}
|
||||
|
||||
|
||||
std::optional<capital_tables::capitalist> capital::get_capitalist(eosio::name coopname, eosio::name username) {
|
||||
capital_tables::capitalist_index capitalists(_capital, coopname.value);
|
||||
|
||||
auto itr = capitalists.find(username.value);
|
||||
if (itr == capitalists.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
program capital::get_capital_program_or_fail(eosio::name coopname) {
|
||||
auto program_id = get_program_id(_capital_program);
|
||||
|
||||
@@ -209,21 +219,34 @@ program capital::get_capital_program_or_fail(eosio::name coopname) {
|
||||
}
|
||||
|
||||
|
||||
program capital::get_cofund_program_or_fail(eosio::name coopname) {
|
||||
auto program_id = get_program_id(_cofund_program);
|
||||
program capital::get_source_program_or_fail(eosio::name coopname) {
|
||||
auto program_id = get_program_id(_source_program);
|
||||
|
||||
auto program = get_program_or_fail(coopname, program_id);
|
||||
return program;
|
||||
};
|
||||
|
||||
int64_t capital::get_capital_program_share_balance(eosio::name coopname) {
|
||||
auto capital_program = get_capital_program_or_fail(coopname);
|
||||
|
||||
return capital_program.available -> amount + capital_program.blocked -> amount;
|
||||
};
|
||||
|
||||
int64_t capital::get_capital_user_share_balance(eosio::name coopname, eosio::name username) {
|
||||
auto wallet = get_capital_wallet(coopname, username);
|
||||
eosio::check(wallet.has_value(), "Кошелёк пайщика в программе не найден");
|
||||
|
||||
return wallet -> available.amount + wallet -> blocked -> amount;
|
||||
}
|
||||
|
||||
std::optional<progwallet> capital::get_capital_wallet(eosio::name coopname, eosio::name username) {
|
||||
auto state = get_global_state(coopname);
|
||||
|
||||
programs_index programs(_soviet, coopname.value);
|
||||
auto program = programs.find(state.program_id);
|
||||
eosio::check(program != programs.end(), "Программа капитализации не найдена");
|
||||
auto program_id = get_program_id(_capital_program);
|
||||
|
||||
auto capital_wallet = get_program_wallet(coopname, username, state.program_id);
|
||||
auto program = get_program_or_fail(coopname, program_id);
|
||||
|
||||
auto capital_wallet = get_program_wallet(coopname, username, _capital_program);
|
||||
|
||||
if (!capital_wallet.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -233,21 +256,6 @@ std::optional<progwallet> capital::get_capital_wallet(eosio::name coopname, eosi
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::optional<result_author> capital::get_result_author(eosio::name coopname, eosio::name username, const checksum256 &result_hash) {
|
||||
result_authors_index result_authors(_capital, coopname.value);
|
||||
auto result_author_index = result_authors.get_index<"byresauthor"_n>();
|
||||
|
||||
uint128_t combined_id = combine_checksum_ids(result_hash, username);
|
||||
auto result_author_itr = result_author_index.find(combined_id);
|
||||
|
||||
if (result_author_itr == result_author_index.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *result_author_itr;
|
||||
}
|
||||
|
||||
std::optional<author> capital::get_author(eosio::name coopname, eosio::name username, const checksum256 &project_hash) {
|
||||
authors_index authors(_capital, coopname.value);
|
||||
auto project_author_index = authors.get_index<"byprojauthor"_n>();
|
||||
@@ -262,32 +270,52 @@ std::optional<author> capital::get_author(eosio::name coopname, eosio::name user
|
||||
return *author_itr;
|
||||
}
|
||||
|
||||
std::optional<creator> capital::get_creator(eosio::name coopname, eosio::name username, const checksum256 &result_hash) {
|
||||
std::optional<creator> capital::get_creator(eosio::name coopname, eosio::name username, const checksum256 &assignment_hash) {
|
||||
creators_index creators(_capital, coopname.value);
|
||||
auto result_creator_index = creators.get_index<"byresultcrtr"_n>();
|
||||
auto assignment_creator_index = creators.get_index<"byassigncrtr"_n>();
|
||||
|
||||
uint128_t combined_id = combine_checksum_ids(result_hash, username);
|
||||
auto creator_itr = result_creator_index.find(combined_id);
|
||||
uint128_t combined_id = combine_checksum_ids(assignment_hash, username);
|
||||
auto creator_itr = assignment_creator_index.find(combined_id);
|
||||
|
||||
if (creator_itr == result_creator_index.end()) {
|
||||
if (creator_itr == assignment_creator_index.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *creator_itr;
|
||||
}
|
||||
|
||||
std::optional<result> capital::get_result(eosio::name coopname, const checksum256 &result_hash) {
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_hash_index = results.get_index<"byhash"_n>();
|
||||
std::optional<assignment> capital::get_assignment(eosio::name coopname, const checksum256 &assignment_hash) {
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment_hash_index = assignments.get_index<"byhash"_n>();
|
||||
|
||||
auto result_itr = result_hash_index.find(result_hash);
|
||||
if (result_itr == result_hash_index.end()) {
|
||||
auto assignment_itr = assignment_hash_index.find(assignment_hash);
|
||||
if (assignment_itr == assignment_hash_index.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *result_itr;
|
||||
return *assignment_itr;
|
||||
}
|
||||
|
||||
|
||||
std::optional<debt> capital::get_debt(eosio::name coopname, const checksum256 &debt_hash) {
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto hash_index = debts.get_index<"bydebthash"_n>();
|
||||
|
||||
auto itr = hash_index.find(debt_hash);
|
||||
if (itr == hash_index.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
assignment capital::get_assignment_or_fail(eosio::name coopname, const checksum256 &assignment_hash, const char* msg) {
|
||||
auto maybe_assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(maybe_assignment.has_value(), msg);
|
||||
return *maybe_assignment;
|
||||
}
|
||||
|
||||
|
||||
std::optional<project> capital::get_project(eosio::name coopname, const checksum256 &project_hash) {
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project_hash_index = projects.get_index<"byhash"_n>();
|
||||
@@ -328,6 +356,20 @@ std::optional<capital_tables::result_withdraw> capital::get_result_withdraw(eosi
|
||||
}
|
||||
|
||||
|
||||
std::optional<capital_tables::program_withdraw> capital::get_program_withdraw(eosio::name coopname, const checksum256 &hash) {
|
||||
capital_tables::program_withdraws_index program_withdraws(_capital, coopname.value);
|
||||
auto index = program_withdraws.get_index<"byhash"_n>();
|
||||
|
||||
auto itr = index.find(hash);
|
||||
|
||||
if (itr == index.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
|
||||
std::optional<capital_tables::project_withdraw> capital::get_project_withdraw(eosio::name coopname, const checksum256 &hash) {
|
||||
capital_tables::project_withdraws_index project_withdraws(_capital, coopname.value);
|
||||
auto index = project_withdraws.get_index<"byhash"_n>();
|
||||
@@ -342,17 +384,66 @@ std::optional<capital_tables::project_withdraw> capital::get_project_withdraw(eo
|
||||
}
|
||||
|
||||
|
||||
std::optional<claim> capital::get_claim(eosio::name coopname, const checksum256 &claim_hash) {
|
||||
claim_index claims(_capital, coopname.value);
|
||||
auto claim_hash_index = claims.get_index<"byhash"_n>();
|
||||
std::optional<result> capital::get_result(eosio::name coopname, const checksum256 &result_hash) {
|
||||
result_index results(_capital, coopname.value);
|
||||
auto idx = results.get_index<"byhash"_n>();
|
||||
|
||||
auto it = idx.find(result_hash);
|
||||
if (it == idx.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
auto claim_itr = claim_hash_index.find(claim_hash);
|
||||
std::optional<result> capital::get_result_by_assignment_and_username(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username) {
|
||||
result_index results(_capital, coopname.value);
|
||||
auto idx = results.get_index<"byresuser"_n>();
|
||||
auto rkey = combine_checksum_ids(assignment_hash, username);
|
||||
|
||||
if (claim_itr == claim_hash_index.end()) {
|
||||
auto it = idx.find(rkey);
|
||||
if (it == idx.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
std::optional<convert> capital::get_convert(eosio::name coopname, const checksum256 &hash) {
|
||||
convert_index converts(_capital, coopname.value);
|
||||
auto index = converts.get_index<"byhash"_n>();
|
||||
|
||||
auto itr = index.find(hash);
|
||||
|
||||
if (itr == index.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *claim_itr;
|
||||
return *itr;
|
||||
}
|
||||
|
||||
|
||||
result capital::get_result_by_assignment_and_username_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg) {
|
||||
auto c = get_result_by_assignment_and_username(coopname, assignment_hash, username);
|
||||
eosio::check(c.has_value(), msg);
|
||||
return *c;
|
||||
}
|
||||
|
||||
|
||||
std::optional<creauthor> capital::get_creauthor(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username) {
|
||||
creauthor_index creathors(_capital, coopname.value);
|
||||
auto idx = creathors.get_index<"byresuser"_n>();
|
||||
auto rkey = combine_checksum_ids(assignment_hash, username);
|
||||
|
||||
auto it = idx.find(rkey);
|
||||
if (it == idx.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
creauthor capital::get_creauthor_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg) {
|
||||
auto maybe_creauthor = get_creauthor(coopname, assignment_hash, username);
|
||||
eosio::check(maybe_creauthor.has_value(), msg);
|
||||
return *maybe_creauthor;
|
||||
}
|
||||
|
||||
|
||||
@@ -384,40 +475,29 @@ global_state capital::get_global_state(name coopname) {
|
||||
}
|
||||
|
||||
|
||||
void capital::ensure_contributor(name coopname, name username) {
|
||||
// Получаем глобальное состояние для установки reward_per_share_last
|
||||
auto gs = get_global_state(coopname);
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// calculcate_capital_amounts: для расчёта премий по формулам:
|
||||
// - creators_bonus = spend * 0.382
|
||||
// - authors_bonus = spend * 1.618
|
||||
// - generated = spend + creators_bonus + authors_bonus
|
||||
// - participants_bonus = generated * 1.618
|
||||
// - total = generated + participants_bonus
|
||||
// - creators_bonus = spended * 0.382
|
||||
// - authors_bonus = spended * 0.618
|
||||
// - generated = spended + creators_bonus + authors_bonus
|
||||
// - capitalists_bonus = generated * 1.618
|
||||
// - total = generated + capitalists_bonus
|
||||
//----------------------------------------------------------------------------
|
||||
bonus_result capital::calculcate_capital_amounts(int64_t spend_amount) {
|
||||
bonus_result br{};
|
||||
bonus_result capital::calculcate_capital_amounts(const eosio::asset& spended) {
|
||||
bonus_result br;
|
||||
|
||||
// Преобразуем spend_amount в double для дальнейших расчетов
|
||||
double spend = double(spend_amount);
|
||||
|
||||
// 1) creators_bonus = spend_amount * 0.382
|
||||
br.creators_bonus = int64_t(spend * 0.382);
|
||||
|
||||
// 2) authors_bonus = spend_amount * 1.618
|
||||
br.authors_bonus = int64_t(spend * 1.618);
|
||||
|
||||
// 3) generated = spend + creators_bonus + authors_bonus
|
||||
br.generated = int64_t(spend + br.creators_bonus + br.authors_bonus);
|
||||
|
||||
// 4) participants_bonus = generated * 1.618
|
||||
br.participants_bonus = int64_t(double(br.generated) * 1.618);
|
||||
|
||||
// 5) total = generated + participants_bonus
|
||||
br.total = int64_t(br.generated + br.participants_bonus);
|
||||
double amount = static_cast<double>(spended.amount);
|
||||
eosio::symbol sym = spended.symbol;
|
||||
|
||||
br.creator_base = spended;
|
||||
br.author_base = spended;
|
||||
|
||||
br.creators_bonus = eosio::asset(int64_t(amount * 0.382), sym);
|
||||
br.authors_bonus = eosio::asset(int64_t(amount * 0.618), sym);
|
||||
br.generated = eosio::asset(br.creator_base.amount + br.creators_bonus.amount + br.authors_bonus.amount + br.author_base.amount, sym);
|
||||
br.capitalists_bonus = eosio::asset( int64_t(static_cast<double>(br.generated.amount) * 1.618), sym);
|
||||
br.total = eosio::asset(br.generated.amount + br.capitalists_bonus.amount, sym);
|
||||
|
||||
return br;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,33 +28,34 @@ public:
|
||||
void init(name coopname, name initiator);
|
||||
|
||||
[[eosio::action]]
|
||||
void createresult(name coopname, name application, checksum256 project_hash, checksum256 result_hash);
|
||||
void createassign(name coopname, name application, checksum256 project_hash, checksum256 assignment_hash, eosio::name assignee, std::string description);
|
||||
|
||||
//Возврат из задания
|
||||
[[eosio::action]]
|
||||
void createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 withdraw_hash, asset amount, document2 return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void wthdrcallbck(eosio::name coopname, eosio::name callback_type, checksum256 withdraw_hash);
|
||||
|
||||
//Возврат из результата
|
||||
[[eosio::action]]
|
||||
void createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, std::vector<checksum256> commit_hashes, document contribution_statement, document return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthdc(eosio::name coopname, uint64_t withdraw_id, document authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthdr(eosio::name coopname, uint64_t withdraw_id, document authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void authwithdrw1(eosio::name coopname, checksum256 withdraw_hash);
|
||||
void capauthwthd1(eosio::name coopname, checksum256 withdraw_hash, document2 authorization);
|
||||
|
||||
// Возврат из проекта
|
||||
[[eosio::action]]
|
||||
void createwthd2(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement);
|
||||
void createwthd2(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document2 return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthd2(eosio::name coopname, uint64_t withdraw_id, document authorization);
|
||||
void capauthwthd2(eosio::name coopname, checksum256 withdraw_hash, document2 authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvewthd2(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
|
||||
void approvewthd2(name coopname, name application, name approver, checksum256 withdraw_hash, document2 approved_return_statement);
|
||||
|
||||
// Возврат из программы
|
||||
[[eosio::action]]
|
||||
void createwthd3(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document2 return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthd3(eosio::name coopname, checksum256 withdraw_hash, document2 authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvewthd3(name coopname, name application, name approver, checksum256 withdraw_hash, document2 approved_return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void createproj (
|
||||
@@ -69,67 +70,129 @@ public:
|
||||
std::string subject
|
||||
);
|
||||
|
||||
// results
|
||||
[[eosio::action]]
|
||||
void createclaim(name coopname, name application, name owner, checksum256 result_hash, checksum256 claim_hash);
|
||||
void updaterslt(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 result_hash
|
||||
);
|
||||
|
||||
[[eosio::action]]
|
||||
void setstatement(name coopname, name application, name owner, checksum256 result_hash, document statement);
|
||||
void pushrslt(name coopname, name application, checksum256 result_hash, document2 statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void authorize(eosio::name coopname, uint64_t claim_id, document decision);
|
||||
void authrslt(eosio::name coopname, checksum256 result_hash, document2 decision);
|
||||
|
||||
[[eosio::action]]
|
||||
void setact1(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 claim_hash, document act);
|
||||
void approverslt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 result_hash, document2 approved_statement);
|
||||
|
||||
// конвертация
|
||||
[[eosio::action]]
|
||||
void approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document2 approved_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void setact2(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 result_hash, document act);
|
||||
|
||||
void createcnvrt(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 convert_hash,
|
||||
document2 convert_statement
|
||||
);
|
||||
|
||||
[[eosio::action]]
|
||||
void startdistrbn(name coopname, name application, checksum256 result_hash);
|
||||
|
||||
void startdistrbn(name coopname, name application, checksum256 assignment_hash);
|
||||
|
||||
[[eosio::action]]
|
||||
void addauthor(name coopname, name application, checksum256 project_hash, name author, uint64_t shares);
|
||||
|
||||
// Коммиты
|
||||
[[eosio::action]]
|
||||
void approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_specification);
|
||||
void createcmmt(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 commit_hash, uint64_t contributed_hours);
|
||||
[[eosio::action]]
|
||||
void createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document specification);
|
||||
void approvecmmt(eosio::name coopname, checksum256 commit_hash, document2 empty_document);
|
||||
[[eosio::action]]
|
||||
void declinecmmt(eosio::name coopname, checksum256 commit_hash, std::string reason);
|
||||
[[eosio::action]]
|
||||
void delcmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash);
|
||||
|
||||
// Долги
|
||||
[[eosio::action]]
|
||||
void createdebt(name coopname, name username, checksum256 assignment_hash, checksum256 debt_hash, asset amount, time_point_sec repaid_at, document2 statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvedebt(eosio::name coopname, checksum256 debt_hash, document2 approved_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void debtauthcnfr(eosio::name coopname, checksum256 debt_hash, document2 decision);
|
||||
|
||||
[[eosio::action]]
|
||||
void debtpaycnfrm(name coopname, checksum256 debt_hash);
|
||||
|
||||
[[eosio::action]]
|
||||
void debtpaydcln(name coopname, checksum256 debt_hash, std::string reason);
|
||||
|
||||
[[eosio::action]]
|
||||
void declinedebt(name coopname, checksum256 debt_hash, std::string reason);
|
||||
|
||||
[[eosio::action]]
|
||||
void settledebt(name coopname);
|
||||
|
||||
|
||||
[[eosio::action]]
|
||||
void setact1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document2 act);
|
||||
[[eosio::action]]
|
||||
void setact2(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document2 act);
|
||||
|
||||
// Регистрация
|
||||
[[eosio::action]]
|
||||
void regcontrib(eosio::name coopname, eosio::name application, eosio::name username, checksum256 project_hash, uint64_t convert_percent, eosio::asset rate_per_hour, time_point_sec created_at, document agreement);
|
||||
void regcontrib(eosio::name coopname, eosio::name application, eosio::name username, checksum256 project_hash, uint64_t convert_percent, eosio::asset rate_per_hour, time_point_sec created_at, document2 agreement);
|
||||
[[eosio::action]]
|
||||
void capregcontr(eosio::name coopname, uint64_t contributor_id, document authorization);
|
||||
void capregcontr(eosio::name coopname, uint64_t contributor_id, document2 authorization);
|
||||
[[eosio::action]]
|
||||
void approvereg(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 project_hash, eosio::name username, document approved_agreement);
|
||||
void approvereg(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 project_hash, eosio::name username, document2 approved_agreement);
|
||||
|
||||
// Инвестиции
|
||||
[[eosio::action]]
|
||||
void createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document statement);
|
||||
[[eosio::action]]
|
||||
void capauthinvst(eosio::name coopname, uint64_t invest_id, document authorization);
|
||||
[[eosio::action]]
|
||||
void approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document approved_statement);
|
||||
void createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document2 statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount);
|
||||
void capauthinvst(eosio::name coopname, checksum256 invest_hash, document2 authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_contribution_statement, document approved_return_statement);
|
||||
void approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document2 approved_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount);
|
||||
|
||||
[[eosio::action]]
|
||||
void diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document2 approved_return_statement);
|
||||
|
||||
// Расходы
|
||||
[[eosio::action]]
|
||||
void createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 result_hash, name creator, uint64_t fund_id, asset amount, std::string description, document statement);
|
||||
[[eosio::action]]
|
||||
void approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document approved_statement);
|
||||
[[eosio::action]]
|
||||
void capauthexpns(eosio::name coopname, uint64_t expense_id, document authorization);
|
||||
void createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 assignment_hash, name creator, uint64_t fund_id, asset amount, std::string description, document2 statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document2 approved_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthexpns(eosio::name coopname, checksum256 expense_hash, document2 authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void exppaycnfrm(eosio::name coopname, checksum256 expense_hash);
|
||||
|
||||
|
||||
// Членские взносы
|
||||
void fund(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo);
|
||||
void refresh(name coopname, name application, checksum256 project_hash, name username);
|
||||
[[eosio::action]] void fundproj(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo);
|
||||
[[eosio::action]] void refreshproj(name coopname, name application, checksum256 project_hash, name username);
|
||||
[[eosio::action]] void fundprog(eosio::name coopname, asset amount, std::string memo);
|
||||
[[eosio::action]] void refreshprog(name coopname, name application, name username);
|
||||
|
||||
private:
|
||||
|
||||
@@ -155,51 +218,56 @@ private:
|
||||
* @return Текущее глобальное состояние.
|
||||
*/
|
||||
global_state get_global_state(name coopname);
|
||||
|
||||
void ensure_contributor(name coopname, name username);
|
||||
|
||||
static bonus_result calculcate_capital_amounts(int64_t spend_amount);
|
||||
|
||||
static bonus_result calculcate_capital_amounts(const eosio::asset& spended);
|
||||
|
||||
std::optional<author> get_author(eosio::name coopname, eosio::name username, const checksum256 &project_hash);
|
||||
std::optional<creator> get_creator(eosio::name coopname, eosio::name username, const checksum256 &result_hash);
|
||||
std::optional<result> get_result(eosio::name coopname, const checksum256 &result_hash);
|
||||
std::optional<creator> get_creator(eosio::name coopname, eosio::name username, const checksum256 &assignment_hash);
|
||||
std::optional<assignment> get_assignment(eosio::name coopname, const checksum256 &assignment_hash);
|
||||
std::optional<debt> get_debt(eosio::name coopname, const checksum256 &debt_hash);
|
||||
|
||||
|
||||
std::optional<project> get_project(eosio::name coopname, const checksum256 &project_hash);
|
||||
std::optional<claim> get_claim(eosio::name coopname, const checksum256 &result_hash);
|
||||
std::optional<result_author> get_result_author(eosio::name coopname, eosio::name username, const checksum256 &result_hash);
|
||||
std::optional<project> get_master_project(eosio::name coopname);
|
||||
void validate_project_hierarchy_depth(eosio::name coopname, checksum256 project_hash);
|
||||
|
||||
void distribute_project_membership_funds(eosio::name coopname, uint64_t project_id, asset amount, uint8_t level);
|
||||
|
||||
int64_t get_capital_user_share_balance(eosio::name coopname, eosio::name username);
|
||||
|
||||
std::optional<result> get_result_by_assignment_and_username(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username);
|
||||
std::optional<result> get_result(eosio::name coopname, const checksum256 &result_hash);
|
||||
|
||||
std::optional<convert> get_convert(eosio::name coopname, const checksum256 &hash);
|
||||
|
||||
std::optional<commit> get_commit(eosio::name coopname, const checksum256 &hash);
|
||||
std::optional<invest> get_invest(eosio::name coopname, const checksum256 &invest_hash);
|
||||
std::optional<capital_tables::result_withdraw> get_result_withdraw(eosio::name coopname, const checksum256 &hash);
|
||||
std::optional<capital_tables::project_withdraw> get_project_withdraw(eosio::name coopname, const checksum256 &hash);
|
||||
std::optional<capital_tables::program_withdraw> get_program_withdraw(eosio::name coopname, const checksum256 &hash);
|
||||
|
||||
|
||||
std::optional<expense> get_expense(eosio::name coopname, const checksum256 &hash);
|
||||
|
||||
program get_capital_program_or_fail(eosio::name coopname);
|
||||
program get_cofund_program_or_fail(eosio::name coopname);
|
||||
program get_source_program_or_fail(eosio::name coopname);
|
||||
std::optional<progwallet> get_capital_wallet(eosio::name coopname, eosio::name username);
|
||||
|
||||
|
||||
std::optional<contributor> get_contributor(eosio::name coopname, const checksum256 &project_hash, eosio::name username);
|
||||
std::optional<contributor> get_active_contributor_or_fail(eosio::name coopname, const checksum256 &project_hash, eosio::name username);
|
||||
|
||||
std::optional<capital_tables::capitalist> get_capitalist(eosio::name coopname, eosio::name username);
|
||||
|
||||
int64_t get_capital_program_share_balance(eosio::name coopname);
|
||||
|
||||
uint64_t count_authors_by_project(eosio::name coopname, const checksum256 &project_hash);
|
||||
|
||||
eosio::asset get_amount_for_withdraw_from_commit(eosio::name coopname, eosio::name username, const checksum256 &hash);
|
||||
|
||||
void expense_withdraw_callback(name coopname, checksum256 withdraw_hash);
|
||||
creauthor get_creauthor_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg);
|
||||
std::optional<creauthor> get_creauthor(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username);
|
||||
result get_result_by_assignment_and_username_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg);
|
||||
assignment get_assignment_or_fail(eosio::name coopname, const checksum256 &assignment_hash, const char* msg);
|
||||
|
||||
void try_finalize_withdrawal(eosio::name coopname, const capital_tables::result_withdraws_index::const_iterator &withdraw) {
|
||||
if (!is_document_empty(withdraw->authorized_return_statement) &&
|
||||
!is_document_empty(withdraw->authorized_contribution_statement)) {
|
||||
|
||||
Wallet::add_blocked_funds(_capital, coopname, withdraw->username, withdraw->amount, _cofund_program);
|
||||
|
||||
action(
|
||||
permission_level{_capital, "active"_n},
|
||||
_capital,
|
||||
"authwithdrw1"_n,
|
||||
std::make_tuple(coopname, withdraw->withdraw_hash)
|
||||
).send();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -6,13 +6,55 @@
|
||||
using namespace eosio;
|
||||
|
||||
struct bonus_result {
|
||||
int64_t creators_bonus;
|
||||
int64_t authors_bonus;
|
||||
int64_t generated;
|
||||
int64_t participants_bonus;
|
||||
int64_t total;
|
||||
asset author_base;
|
||||
asset creator_base;
|
||||
asset creators_bonus;
|
||||
asset authors_bonus;
|
||||
asset generated;
|
||||
asset capitalists_bonus;
|
||||
asset total;
|
||||
};
|
||||
|
||||
// creauthors.hpp (или в capital.hpp)
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] creauthor {
|
||||
uint64_t id;
|
||||
checksum256 project_hash; // С каким результатом связана запись
|
||||
checksum256 assignment_hash; // С каким результатом связана запись
|
||||
eosio::name username; //
|
||||
eosio::asset provisional_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset debt_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset spended = asset(0, _root_govern_symbol);
|
||||
eosio::asset available = asset(0, _root_govern_symbol);
|
||||
eosio::asset for_convert = asset(0, _root_govern_symbol);
|
||||
|
||||
// Сколько пользователь имеет «авторских долей» в этом результате
|
||||
uint64_t author_shares = 0;
|
||||
|
||||
// Сколько пользователь имеет «создательских долей» в creators_bonus
|
||||
uint64_t creator_bonus_shares = 0;
|
||||
|
||||
// Сколько часов вложено в задание
|
||||
uint64_t contributed_hours = 0;
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
|
||||
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу задания
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
|
||||
|
||||
// Индекс по (assignment_hash + username)
|
||||
uint128_t by_resuser() const {
|
||||
return combine_checksum_ids(assignment_hash, username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"creauthors"_n, creauthor,
|
||||
indexed_by<"byproject"_n, const_mem_fun<creauthor, checksum256, &creauthor::by_project_hash>>,
|
||||
indexed_by<"byassignment"_n, const_mem_fun<creauthor, checksum256, &creauthor::by_assignment_hash>>,
|
||||
indexed_by<"byresuser"_n, const_mem_fun<creauthor, uint128_t, &creauthor::by_resuser>>
|
||||
> creauthor_index;
|
||||
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
|
||||
uint64_t id; ///< Уникальный идентификатор действия.
|
||||
@@ -22,22 +64,22 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
|
||||
|
||||
name status = "created"_n; ///< Статус расхода (created | approved | authorized)
|
||||
checksum256 project_hash; ///< Хэш проекта, связанного с расходом.
|
||||
checksum256 result_hash; ///< Хэш результата, связанного с расходом.
|
||||
checksum256 assignment_hash; ///< Хэш задания, связанного с расходом.
|
||||
checksum256 expense_hash; ///< Хэш расхода.
|
||||
uint64_t fund_id; ///< Идентификатор фонда списания (expfunds в контакте fund)
|
||||
eosio::asset amount; ///< Сумма расхода.
|
||||
std::string description; ///< Публичное описание расхода.
|
||||
|
||||
document statement; ///< Служебная записка
|
||||
document approved_statement; ///< принятая записка председателем или доверенным
|
||||
document authorization; ///< утвержденная записка советом
|
||||
document2 expense_statement; ///< Служебная записка
|
||||
document2 approved_statement; ///< принятая записка председателем или доверенным
|
||||
document2 authorization; ///< утвержденная записка советом
|
||||
|
||||
time_point_sec spend_at = current_time_point(); ///< Дата и время создания расхода.
|
||||
time_point_sec spended_at = current_time_point(); ///< Дата и время создания расхода.
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_username() const { return username.value; } ///< По имени пользователя.
|
||||
checksum256 by_expense_hash() const { return expense_hash; } ///< Индекс по хэшу задачи.
|
||||
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу результата.
|
||||
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу задания.
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта.
|
||||
|
||||
};
|
||||
@@ -46,7 +88,7 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
|
||||
"expenses"_n, expense,
|
||||
indexed_by<"byusername"_n, const_mem_fun<expense, uint64_t, &expense::by_username>>,
|
||||
indexed_by<"byhash"_n, const_mem_fun<expense, checksum256, &expense::by_expense_hash>>,
|
||||
indexed_by<"byresulthash"_n, const_mem_fun<expense, checksum256, &expense::by_result_hash>>,
|
||||
indexed_by<"byassignment"_n, const_mem_fun<expense, checksum256, &expense::by_assignment_hash>>,
|
||||
indexed_by<"byprojhash"_n, const_mem_fun<expense, checksum256, &expense::by_project_hash>>
|
||||
> expense_index;
|
||||
|
||||
@@ -60,23 +102,26 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] commit {
|
||||
name coopname; ///< Имя кооператива.
|
||||
name application; ///< Приложение, инициировавшее действие.
|
||||
name username; ///< Имя пользователя, совершившего действие.
|
||||
name status = "created"_n; ///< Статус коммита (created | withdrawed | converted)
|
||||
name status; ///< Статус коммита (created | approved | authorized | act1 | act2 )
|
||||
checksum256 project_hash; ///< Хэш проекта, связанного с действием.
|
||||
checksum256 result_hash; ///< Хэш результата, связанного с действием.
|
||||
checksum256 assignment_hash; ///< Хэш задания, связанного с действием.
|
||||
checksum256 commit_hash; ///< Хэш действия.
|
||||
uint64_t contributed_hours; ///< Сумма временных затрат, связанная с действием.
|
||||
eosio::asset spend; ///< Сумма затрат, связанная с действием.
|
||||
|
||||
document specification; ///< Техническое задание (спецификация) как приложение к договору УХД
|
||||
document approved_specification; ///< Одобрение председателя или доверенного лица
|
||||
document authorization; ///< Решение совета
|
||||
eosio::asset rate_per_hour = asset(0, _root_govern_symbol); ///< Стоимость часа
|
||||
eosio::asset spended = asset(0, _root_govern_symbol); ///< Сумма затрат, связанная с действием.
|
||||
eosio::asset generated = asset(0, _root_govern_symbol); ///< Сумма генерации, связанная с действием.
|
||||
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< Сумма затрат, связанная с действием.
|
||||
eosio::asset authors_bonus = asset(0, _root_govern_symbol);///< Сумма затрат, связанная с действием.
|
||||
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol); ///< Сумма затрат, связанная с действием.
|
||||
eosio::asset total = asset(0, _root_govern_symbol); ///< Суммарная стоимость коммита на будущем приёме задания с учетом капитализации и генерации
|
||||
|
||||
std::string decline_comment;
|
||||
time_point_sec created_at; ///< Дата и время создания действия.
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_username() const { return username.value; } ///< По имени пользователя.
|
||||
checksum256 by_commit_hash() const { return commit_hash; } ///< Индекс по хэшу задачи.
|
||||
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу результата.
|
||||
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу задания.
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта.
|
||||
};
|
||||
|
||||
@@ -84,7 +129,7 @@ typedef eosio::multi_index<
|
||||
"commits"_n, commit,
|
||||
indexed_by<"byusername"_n, const_mem_fun<commit, uint64_t, &commit::by_username>>,
|
||||
indexed_by<"byhash"_n, const_mem_fun<commit, checksum256, &commit::by_commit_hash>>,
|
||||
indexed_by<"byresulthash"_n, const_mem_fun<commit, checksum256, &commit::by_result_hash>>,
|
||||
indexed_by<"byassignment"_n, const_mem_fun<commit, checksum256, &commit::by_assignment_hash>>,
|
||||
indexed_by<"byprojhash"_n, const_mem_fun<commit, checksum256, &commit::by_project_hash>>
|
||||
> commit_index;
|
||||
|
||||
@@ -103,8 +148,8 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] invest {
|
||||
eosio::asset amount = asset(0, _root_govern_symbol); ///< Сумма инвестиции.
|
||||
name status; ///< created | signed | authorized | blocked
|
||||
time_point_sec invested_at; ///< Дата приёма инвестиции.
|
||||
document statement; ///< Заявление на зачёт из кошелька.
|
||||
document approved_statement; ///< Подпись председателя на принятом заявлении.
|
||||
document2 invest_statement; ///< Заявление на зачёт из кошелька.
|
||||
document2 approved_statement; ///< Подпись председателя на принятом заявлении.
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_username() const { return username.value; } ///< Индекс по имени аккаунта.
|
||||
@@ -132,28 +177,28 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] contributor {
|
||||
checksum256 project_hash;
|
||||
name status;
|
||||
time_point_sec created_at;
|
||||
document agreement;
|
||||
document approved_agreement;
|
||||
document authorization;
|
||||
document2 agreement;
|
||||
document2 approved_agreement;
|
||||
document2 authorization;
|
||||
|
||||
eosio::asset invested = asset(0, _root_govern_symbol);
|
||||
|
||||
uint64_t contributed_hours;
|
||||
eosio::asset rate_per_hour;
|
||||
eosio::asset spend = asset(0, _root_govern_symbol);
|
||||
|
||||
uint64_t convert_percent;
|
||||
eosio::asset for_convert = asset(0, _root_govern_symbol);
|
||||
uint64_t contributed_hours;
|
||||
|
||||
eosio::asset rate_per_hour = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset spended = asset(0, _root_govern_symbol);
|
||||
eosio::asset debt_amount = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset available = asset(0, _root_govern_symbol);
|
||||
eosio::asset withdrawed = asset(0, _root_govern_symbol);
|
||||
eosio::asset converted = asset(0, _root_govern_symbol);
|
||||
eosio::asset expensed = asset(0, _root_govern_symbol);
|
||||
eosio::asset returned = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset share_balance = asset(0, _root_govern_symbol); ///< Баланс долей вкладчика
|
||||
eosio::asset share_balance = asset(0, _root_govern_symbol); ///< Баланс долей пайщика
|
||||
eosio::asset pending_rewards = asset(0, _root_govern_symbol); ///< Накопленные награды
|
||||
int64_t reward_per_share_last = 0; ///< Последний зафиксированный cumulative_reward_per_share
|
||||
int64_t reward_per_share_last = 0; ///< Последний зафиксированный cumulative_reward_per_share по проекту
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
uint64_t by_username() const { return username.value; }
|
||||
@@ -170,7 +215,7 @@ typedef eosio::multi_index<
|
||||
|
||||
|
||||
/**
|
||||
* @brief Таблица идей (проектов)
|
||||
* @brief Таблица проектов
|
||||
*
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] project {
|
||||
@@ -188,20 +233,31 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] project {
|
||||
|
||||
uint64_t authors_count;
|
||||
uint64_t authors_shares;
|
||||
uint64_t commits_count;
|
||||
|
||||
std::vector<uint64_t> expense_funds = {4};
|
||||
|
||||
eosio::asset target = asset(0, _root_govern_symbol);
|
||||
eosio::asset invested = asset(0, _root_govern_symbol);
|
||||
eosio::asset available = asset(0, _root_govern_symbol);
|
||||
eosio::asset allocated = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset creators_base = asset(0, _root_govern_symbol);
|
||||
eosio::asset creators_bonus = asset(0, _root_govern_symbol);
|
||||
eosio::asset authors_bonus = asset(0, _root_govern_symbol);
|
||||
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol);
|
||||
eosio::asset total = asset(0, _root_govern_symbol); // стоимость проекта с учетом генерации и капитализации
|
||||
|
||||
eosio::asset expensed = asset(0, _root_govern_symbol);
|
||||
eosio::asset spend = asset(0, _root_govern_symbol);
|
||||
eosio::asset spended = asset(0, _root_govern_symbol);
|
||||
eosio::asset generated = asset(0, _root_govern_symbol);
|
||||
|
||||
double membership_parent_distribution_ratio = 1;
|
||||
eosio::asset converted = asset(0, _root_govern_symbol);
|
||||
eosio::asset withdrawed = asset(0, _root_govern_symbol);
|
||||
|
||||
double parent_distribution_ratio = 1;
|
||||
int64_t membership_cumulative_reward_per_share = 0;
|
||||
|
||||
eosio::asset membership_total_shares = asset(0, _root_govern_symbol); ///< Общее количество долей пайщиков в проекте
|
||||
eosio::asset total_share_balance = asset(0, _root_govern_symbol); ///< Общее количество долей пайщиков в проекте
|
||||
eosio::asset membership_funded = asset(0, _root_govern_symbol); ///< Общее количество поступивших членских взносов
|
||||
eosio::asset membership_available = asset(0, _root_govern_symbol); ///< Доступное количество членских взносов для участников проекта согласно долям
|
||||
eosio::asset membership_distributed = asset(0, _root_govern_symbol); ///< Распределенное количество членских взносов на участников проекта
|
||||
@@ -219,84 +275,145 @@ typedef eosio::multi_index<"projects"_n, project,
|
||||
> project_index;
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] result {
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] assignment {
|
||||
uint64_t id;
|
||||
checksum256 result_hash;
|
||||
checksum256 assignment_hash;
|
||||
checksum256 project_hash;
|
||||
eosio::name status = "created"_n; ///< created | started | expired?
|
||||
|
||||
eosio::name status = "opened"_n; ///< opened | closed
|
||||
|
||||
eosio::name coopname;
|
||||
eosio::name assignee;
|
||||
std::string description;
|
||||
|
||||
uint64_t authors_shares;
|
||||
uint64_t total_creators_bonus_shares;
|
||||
|
||||
uint64_t authors_count;
|
||||
uint64_t commits_count;
|
||||
time_point_sec created_at = current_time_point();
|
||||
time_point_sec expired_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + 365 * 86400);
|
||||
uint64_t authors_shares;
|
||||
uint64_t authors_count;
|
||||
|
||||
uint64_t commits_count;
|
||||
eosio::asset allocated = asset(0, _root_govern_symbol); ///< аллоцированные на создание результата средства
|
||||
eosio::asset available = asset(0, _root_govern_symbol); ///< зарезерированные на создание результата средства
|
||||
eosio::asset spend = asset(0, _root_govern_symbol); ///< фактически потраченные ресурсы на создание результат в виде времени (паевые взносы-возвраты)
|
||||
eosio::asset expensed = asset(0, _root_govern_symbol); ///< фактически потраченные на создание результата средства в виде расходов (подписки, прочее)
|
||||
eosio::asset allocated = asset(0, _root_govern_symbol); ///< аллоцированные на создание задания средства
|
||||
eosio::asset available = asset(0, _root_govern_symbol); ///< зарезерированные на создание задания средства
|
||||
eosio::asset spended = asset(0, _root_govern_symbol); ///< фактически потраченные ресурсы на создание задание в виде времени (паевые взносы-возвраты)
|
||||
eosio::asset generated = asset(0, _root_govern_symbol); ///< стоимость РИД с учётом премий авторов и создателей
|
||||
eosio::asset expensed = asset(0, _root_govern_symbol); ///< фактически потраченные на создание задания средства в виде расходов (подписки, прочее)
|
||||
eosio::asset withdrawed = asset(0, _root_govern_symbol); ///< фактически возвращенные средства из задания
|
||||
|
||||
eosio::asset creators_amount = asset(0, _root_govern_symbol); ///< себестоимость РИД
|
||||
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< премии создателей - 0.382 от себестоимости (creators_amount)
|
||||
eosio::asset authors_bonus = asset(0, _root_govern_symbol); ///< премии авторов - 1.618 от себестоимости (creators_amount)
|
||||
eosio::asset generated_amount = asset(0, _root_govern_symbol); ///< стоимость РИД с учётом премий авторов и создателей
|
||||
eosio::asset participants_bonus = asset(0, _root_govern_symbol); ///< премии пайщиков кооператива - 1.618 от generated_amount
|
||||
eosio::asset creators_base = asset(0, _root_govern_symbol); ///< себестоимость РИД
|
||||
|
||||
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< премии создателей - 0.382 от себестоимости (creators_base)
|
||||
eosio::asset authors_bonus = asset(0, _root_govern_symbol); ///< премии авторов - 1.618 от себестоимости (creators_base)
|
||||
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol); ///< премии пайщиков кооператива - 1.618 от generated_amount
|
||||
|
||||
eosio::asset total = asset(0, _root_govern_symbol); ///< Стоимость РИД с учетом генерации и капитализации (стоимость РИД в spended + authors_bonus + creators_bonus + capitalists_bonus)
|
||||
|
||||
eosio::asset authors_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
|
||||
eosio::asset creators_base_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
|
||||
|
||||
eosio::asset creators_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
|
||||
|
||||
eosio::asset capitalists_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты пайщикам
|
||||
|
||||
eosio::asset total_amount = asset(0, _root_govern_symbol); ///< Капитализация РИД (стоимость РИД в generated_amount + participants_bonus)
|
||||
|
||||
eosio::asset participants_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты пайщикам
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
checksum256 by_hash() const { return result_hash; } ///< Индекс по хэшу результата.
|
||||
checksum256 by_hash() const { return assignment_hash; } ///< Индекс по хэшу задания.
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"results"_n, result,
|
||||
indexed_by<"byhash"_n, const_mem_fun<result, checksum256, &result::by_hash>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<result, checksum256, &result::by_project_hash>>
|
||||
> result_index;
|
||||
typedef eosio::multi_index<"assignments"_n, assignment,
|
||||
indexed_by<"byhash"_n, const_mem_fun<assignment, checksum256, &assignment::by_hash>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<assignment, checksum256, &assignment::by_project_hash>>
|
||||
> assignment_index;
|
||||
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] claim {
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] result {
|
||||
uint64_t id;
|
||||
checksum256 claim_hash;
|
||||
checksum256 project_hash;
|
||||
checksum256 assignment_hash;
|
||||
checksum256 result_hash;
|
||||
|
||||
eosio::name coopname;
|
||||
eosio::name owner;
|
||||
eosio::name username;
|
||||
|
||||
eosio::name type; ///< intellectual | property
|
||||
eosio::name status = "created"_n; ///< created | statement | decision | act1 | act2 | completed
|
||||
time_point_sec created_at = current_time_point();
|
||||
|
||||
eosio::asset amount = asset(0, _root_govern_symbol);
|
||||
|
||||
document statement; ///< Заявление
|
||||
document decision; ///< Решение
|
||||
document act1; ///< Акт передачи
|
||||
document act2; ///< Акт приёма
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_owner() const { return owner.value; } ///< Индекс по владельцу
|
||||
checksum256 by_hash() const { return claim_hash; } ///< Индекс по хэшу
|
||||
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
|
||||
eosio::asset creator_base_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset debt_amount = asset(0, _root_govern_symbol);
|
||||
|
||||
uint128_t by_result_user() const {
|
||||
return combine_checksum_ids(result_hash, owner);
|
||||
eosio::asset creator_bonus_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset author_bonus_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset generation_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset capitalist_bonus_amount = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset total_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset available_for_return = asset(0, _root_govern_symbol);
|
||||
eosio::asset available_for_convert = asset(0, _root_govern_symbol);
|
||||
|
||||
document2 result_statement; ///< Заявление
|
||||
document2 approved_statement; ///< Принятое заявление
|
||||
document2 authorization; ///< Решение совета
|
||||
document2 act1; ///< Акт1
|
||||
document2 act2; ///< Акт2
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
|
||||
checksum256 by_hash() const { return result_hash; } ///< Индекс по хэшу проекта
|
||||
|
||||
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
|
||||
|
||||
uint128_t by_assignment_user() const {
|
||||
return combine_checksum_ids(assignment_hash, username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"claims"_n, claim,
|
||||
indexed_by<"byowner"_n, const_mem_fun<claim, uint64_t, &claim::by_owner>>,
|
||||
indexed_by<"byhash"_n, const_mem_fun<claim, checksum256, &claim::by_hash>>,
|
||||
indexed_by<"byresulthash"_n, const_mem_fun<claim, checksum256, &claim::by_result_hash>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<claim, checksum256, &claim::by_project_hash>>,
|
||||
indexed_by<"byresuser"_n, const_mem_fun<claim, uint128_t, &claim::by_result_user>>
|
||||
> claim_index;
|
||||
typedef eosio::multi_index<"results"_n, result,
|
||||
indexed_by<"byusername"_n, const_mem_fun<result, uint64_t, &result::by_username>>,
|
||||
indexed_by<"byhash"_n, const_mem_fun<result, checksum256, &result::by_hash>>,
|
||||
indexed_by<"byassignment"_n, const_mem_fun<result, checksum256, &result::by_assignment_hash>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<result, checksum256, &result::by_project_hash>>,
|
||||
indexed_by<"byresuser"_n, const_mem_fun<result, uint128_t, &result::by_assignment_user>>
|
||||
> result_index;
|
||||
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] convert {
|
||||
uint64_t id;
|
||||
checksum256 project_hash;
|
||||
checksum256 assignment_hash;
|
||||
checksum256 convert_hash;
|
||||
|
||||
eosio::name coopname;
|
||||
eosio::name username;
|
||||
|
||||
eosio::name status = "created"_n; ///< created
|
||||
|
||||
eosio::asset convert_amount = asset(0, _root_govern_symbol);
|
||||
|
||||
document2 convert_statement; ///< Заявление
|
||||
|
||||
time_point_sec created_at = current_time_point();
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
|
||||
checksum256 by_convert_hash() const { return convert_hash; } ///< Индекс по хэшу
|
||||
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
|
||||
|
||||
uint128_t by_assignment_user() const {
|
||||
return combine_checksum_ids(assignment_hash, username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"converts"_n, convert,
|
||||
indexed_by<"byusername"_n, const_mem_fun<convert, uint64_t, &convert::by_username>>,
|
||||
indexed_by<"byhash"_n, const_mem_fun<convert, checksum256, &convert::by_convert_hash>>,
|
||||
indexed_by<"byassignment"_n, const_mem_fun<convert, checksum256, &convert::by_assignment_hash>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<convert, checksum256, &convert::by_project_hash>>
|
||||
> convert_index;
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] author {
|
||||
@@ -321,60 +438,32 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] author {
|
||||
> authors_index;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Таблица для учёта авторства на результатах
|
||||
* Принимает в себя копии объектов авторов из проекта. И используется для распределения премий по конкретному результату.
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] result_author {
|
||||
uint64_t id;
|
||||
checksum256 project_hash;
|
||||
checksum256 result_hash;
|
||||
|
||||
eosio::name username;
|
||||
|
||||
uint64_t shares;
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ
|
||||
uint64_t by_username() const { return username.value; } ///< Индекс по имени пользователя
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
|
||||
|
||||
uint128_t by_result_author() const {
|
||||
return combine_checksum_ids(project_hash, username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"resauthors"_n, result_author,
|
||||
indexed_by<"byusername"_n, const_mem_fun<result_author, uint64_t, &result_author::by_username>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<result_author, checksum256, &result_author::by_project_hash>>,
|
||||
indexed_by<"byresauthor"_n, const_mem_fun<result_author, uint128_t, &result_author::by_result_author>>
|
||||
> result_authors_index;
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] creator {
|
||||
uint64_t id; ///< id и primary_key
|
||||
|
||||
checksum256 project_hash; ///< Хэш идеи
|
||||
checksum256 result_hash; ///< Хэш результата интеллектуальной деятельности
|
||||
checksum256 assignment_hash; ///< Хэш задания интеллектуальной деятельности
|
||||
|
||||
eosio::name username; ///< Имя пользователя
|
||||
eosio::asset spend = asset(0, _root_govern_symbol); ///< Стоимость использованных ресурсов
|
||||
eosio::asset spended = asset(0, _root_govern_symbol); ///< Стоимость использованных ресурсов
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
checksum256 by_result_hash() const { return result_hash; }
|
||||
checksum256 by_assignment_hash() const { return assignment_hash; }
|
||||
checksum256 by_project_hash() const { return project_hash; }
|
||||
|
||||
uint128_t by_result_creator() const {
|
||||
return combine_checksum_ids(result_hash, username);
|
||||
uint128_t by_assignment_creator() const {
|
||||
return combine_checksum_ids(assignment_hash, username);
|
||||
}
|
||||
|
||||
uint64_t by_username() const { return username.value; }
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"creators"_n, creator,
|
||||
indexed_by<"byresulthash"_n, const_mem_fun<creator, checksum256, &creator::by_result_hash>>,
|
||||
indexed_by<"byassignment"_n, const_mem_fun<creator, checksum256, &creator::by_assignment_hash>>,
|
||||
indexed_by<"byprojecthash"_n, const_mem_fun<creator, checksum256, &creator::by_project_hash>>,
|
||||
indexed_by<"byusername"_n, const_mem_fun<creator, uint64_t, &creator::by_username>>,
|
||||
indexed_by<"byresultcrtr"_n, const_mem_fun<creator, uint128_t, &creator::by_result_creator>>
|
||||
indexed_by<"byassigncrtr"_n, const_mem_fun<creator, uint128_t, &creator::by_assignment_creator>>
|
||||
> creators_index;
|
||||
|
||||
/**
|
||||
@@ -384,6 +473,13 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] creator {
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] global_state {
|
||||
eosio::name coopname; ///< Имя кооператива глобального состояния.
|
||||
uint64_t program_id; ///< Идентификатор целевой программы.
|
||||
|
||||
asset program_membership_funded = asset(0, _root_govern_symbol); ///< Общая сумма членских взносов по программе
|
||||
asset program_membership_available = asset(0, _root_govern_symbol); ///< Доступная сумма членских взносов по программе
|
||||
asset program_membership_distributed = asset(0, _root_govern_symbol); ///< Распределенная сумма членских взносов по программе
|
||||
int64_t program_membership_cumulative_reward_per_share; ///< Накопительное вознаграждение на долю в членских взносах
|
||||
|
||||
|
||||
asset total_shares = asset(0, _root_govern_symbol); ///< Общая сумма долей всех участников.
|
||||
asset total_contributions = asset(0, _root_govern_symbol); ///< Общая сумма всех вкладов.
|
||||
asset total_rewards_distributed = asset(0, _root_symbol); ///< Общая сумма распределенных вознаграждений.
|
||||
@@ -400,25 +496,36 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] global_state {
|
||||
|
||||
|
||||
namespace capital_tables {
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] capitalist {
|
||||
name username; ///< Имя пользователя
|
||||
name coopname; ///< Имя кооператива
|
||||
asset pending_rewards = asset(0, _root_govern_symbol); ///< Вознаграждения ожидающие получения
|
||||
asset returned_rewards = asset(0, _root_govern_symbol); ///< Полученные вознаграждения
|
||||
int64_t reward_per_share_last; ///< Крайнее вознаграждение за долю
|
||||
|
||||
uint64_t primary_key() const { return username.value; } ///< Основной ключ.
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"capitalists"_n, capitalist> capitalist_index; ///< Таблица для хранения участников программы капитализации
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] result_withdraw {
|
||||
uint64_t id; ///< Уникальный ID запроса на возврат.
|
||||
name coopname; ///< Имя аккаунта кооператива
|
||||
checksum256 project_hash; ///< Хэш проекта
|
||||
checksum256 result_hash; ///< Хэш результата
|
||||
checksum256 assignment_hash; ///< Хэш задания
|
||||
checksum256 withdraw_hash; ///< Уникальный внешний ключ
|
||||
name username; ///< Имя аккаунта участника, запрашивающего возврат.
|
||||
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
|
||||
std::vector<checksum256> commit_hashes; ///< Погашаемые коммиты
|
||||
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
|
||||
document contribution_statement; ///< Заявление на паевой взнос авторскими правами
|
||||
document return_statement; ///< Заявление на возврат паевого взноса деньгами
|
||||
document2 contribution_statement; ///< Заявление на паевой взнос авторскими правами
|
||||
document2 return_statement; ///< Заявление на возврат паевого взноса деньгами
|
||||
|
||||
document approved_contribution_statement; ///< Принятое председателем заявление на взнос
|
||||
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
|
||||
document2 approved_contribution_statement; ///< Принятое председателем заявление на взнос
|
||||
document2 approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
|
||||
|
||||
document authorized_contribution_statement; ///< Решение совета на приём взноса
|
||||
document authorized_return_statement; ///< Решение совета на возврат взноса
|
||||
document2 authorized_contribution_statement; ///< Решение совета на приём взноса
|
||||
document2 authorized_return_statement; ///< Решение совета на возврат взноса
|
||||
|
||||
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
|
||||
|
||||
@@ -428,11 +535,11 @@ namespace capital_tables {
|
||||
checksum256 by_hash() const { return withdraw_hash; } ///< Индекс по хэшу
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"rwithdraws"_n, result_withdraw,
|
||||
typedef eosio::multi_index<"reswithdraws"_n, result_withdraw,
|
||||
indexed_by<"byhash"_n, const_mem_fun<result_withdraw, checksum256, &result_withdraw::by_hash>>,
|
||||
indexed_by<"byusername"_n, const_mem_fun<result_withdraw, uint64_t, &result_withdraw::by_account>>,
|
||||
indexed_by<"bycreated"_n, const_mem_fun<result_withdraw, uint64_t, &result_withdraw::by_created>>
|
||||
> result_withdraws_index; ///< Таблица для хранения запросов на возврат из результата.
|
||||
> result_withdraws_index; ///< Таблица для хранения запросов на возврат из задания.
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] project_withdraw {
|
||||
@@ -443,11 +550,9 @@ namespace capital_tables {
|
||||
name username; ///< Имя аккаунта участника, запрашивающего возврат.
|
||||
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
|
||||
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
|
||||
document return_statement; ///< Заявление на возврат паевого взноса деньгами
|
||||
document2 return_statement; ///< Заявление на возврат паевого взноса деньгами
|
||||
|
||||
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
|
||||
|
||||
document authorized_return_statement; ///< Решение совета на возврат взноса
|
||||
document2 approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
|
||||
|
||||
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
|
||||
|
||||
@@ -458,11 +563,37 @@ namespace capital_tables {
|
||||
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"pwithdraws"_n, project_withdraw,
|
||||
typedef eosio::multi_index<"prjwithdraws"_n, project_withdraw,
|
||||
indexed_by<"byhash"_n, const_mem_fun<project_withdraw, checksum256, &project_withdraw::by_hash>>,
|
||||
indexed_by<"byprojhash"_n, const_mem_fun<project_withdraw, checksum256, &project_withdraw::by_project_hash>>,
|
||||
indexed_by<"byusername"_n, const_mem_fun<project_withdraw, uint64_t, &project_withdraw::by_account>>,
|
||||
indexed_by<"bycreated"_n, const_mem_fun<project_withdraw, uint64_t, &project_withdraw::by_created>>
|
||||
> project_withdraws_index; ///< Таблица для хранения запросов на возврат из проекта.
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] program_withdraw {
|
||||
uint64_t id; ///< Уникальный ID запроса на возврат.
|
||||
name coopname; ///< Имя аккаунта кооператива
|
||||
checksum256 withdraw_hash; ///< Уникальный внешний ключ
|
||||
name username; ///< Имя аккаунта участника, запрашивающего возврат.
|
||||
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
|
||||
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
|
||||
document2 return_statement; ///< Заявление на возврат паевого взноса деньгами
|
||||
|
||||
document2 approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
|
||||
|
||||
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_account() const { return username.value; } ///< Вторичный индекс по аккаунту.
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch(); }
|
||||
checksum256 by_hash() const { return withdraw_hash; } ///< Индекс по хэшу
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"prgwithdraws"_n, program_withdraw,
|
||||
indexed_by<"byhash"_n, const_mem_fun<program_withdraw, checksum256, &program_withdraw::by_hash>>,
|
||||
indexed_by<"byusername"_n, const_mem_fun<program_withdraw, uint64_t, &program_withdraw::by_account>>,
|
||||
indexed_by<"bycreated"_n, const_mem_fun<program_withdraw, uint64_t, &program_withdraw::by_created>>
|
||||
> program_withdraws_index; ///< Таблица для хранения запросов на возврат из проекта.
|
||||
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,50 @@
|
||||
void capital::createassign(name coopname, name application, checksum256 project_hash, checksum256 assignment_hash, eosio::name assignee, std::string description) {
|
||||
require_auth(coopname);
|
||||
|
||||
auto project = get_project(coopname, project_hash);
|
||||
eosio::check(project.has_value(), "проект не найден");
|
||||
|
||||
// Проверяем, существует ли уже assignment
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(!assignment.has_value(), "Объект задания уже существует");
|
||||
|
||||
get_participant_or_fail(coopname, assignee);
|
||||
|
||||
// Создаём assignment
|
||||
assignments.emplace(coopname, [&](auto &n) {
|
||||
n.id = get_global_id_in_scope(_capital, coopname, "assignments"_n);
|
||||
n.coopname = coopname;
|
||||
n.assignee = assignee;
|
||||
n.description = description;
|
||||
n.project_hash = project_hash;
|
||||
n.assignment_hash = assignment_hash;
|
||||
n.authors_shares = project -> authors_shares;
|
||||
n.authors_count = project -> authors_count;
|
||||
});
|
||||
|
||||
authors_index authors(_capital, coopname.value);
|
||||
auto authors_hash_index = authors.get_index<"byprojecthash"_n>();
|
||||
|
||||
// Перебираем всех авторов с данным project_hash
|
||||
auto author_itr = authors_hash_index.lower_bound(project_hash);
|
||||
|
||||
uint64_t authors_count = 0;
|
||||
|
||||
creauthor_index creathors(_capital, coopname.value);
|
||||
|
||||
// Копируем запись автора идеи в assignment_authors
|
||||
while(author_itr != authors_hash_index.end() && author_itr->project_hash == project_hash) {
|
||||
creathors.emplace(coopname, [&](auto &ra){
|
||||
ra.id = creathors.available_primary_key();
|
||||
ra.assignment_hash = assignment_hash;
|
||||
ra.project_hash = project_hash;
|
||||
ra.username = author_itr->username;
|
||||
ra.author_shares = author_itr -> shares;
|
||||
});
|
||||
authors_count++;
|
||||
author_itr++;
|
||||
}
|
||||
|
||||
eosio::check(authors_count > 0, "Нельзя создать задание без установленных авторов в проекте");
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
void capital::startdistrbn(name coopname, name application, checksum256 assignment_hash) {
|
||||
check_auth_or_fail(_capital, coopname, application, "start"_n);
|
||||
|
||||
auto assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Задание не найдено");
|
||||
eosio::check(assignment -> status == "opened"_n, "Только задание в статусе opened может быть запущен в распределение");
|
||||
|
||||
auto project = get_project(coopname, assignment -> project_hash);
|
||||
eosio::check(project.has_value(), "проект не найден");
|
||||
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment_for_modify = assignments.find(assignment -> id);
|
||||
|
||||
//заносим доступные средства к распределению
|
||||
assignments.modify(assignment_for_modify, coopname, [&](auto& row) {
|
||||
row.status = "closed"_n;
|
||||
row.authors_bonus_remain = row.authors_bonus;
|
||||
row.creators_base_remain = row.creators_base;
|
||||
row.creators_bonus_remain = row.creators_bonus;
|
||||
row.capitalists_bonus_remain = row.capitalists_bonus;
|
||||
});
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
void capital::authorize(eosio::name coopname, uint64_t claim_id, document decision) {
|
||||
require_auth(_soviet);
|
||||
|
||||
claim_index claims(_capital, coopname.value);
|
||||
auto claim = claims.find(claim_id);
|
||||
|
||||
eosio::check(claim != claims.end(), "Объект запроса доли не найден");
|
||||
|
||||
// Проверяем статус.
|
||||
eosio::check(claim -> status == "statement"_n, "Неверный статус");
|
||||
|
||||
claims.modify(claim, coopname, [&](auto &n){
|
||||
n.status = "decision"_n;
|
||||
n.decision = decision;
|
||||
});
|
||||
};
|
||||
@@ -1,91 +0,0 @@
|
||||
void capital::createclaim(name coopname, name application, name owner, checksum256 result_hash, checksum256 claim_hash) {
|
||||
check_auth_or_fail(_capital, coopname, application, "createclaim"_n);
|
||||
|
||||
// извлекаем программу и кошелек пайщика в программе
|
||||
auto capital_program = get_capital_program_or_fail(coopname);
|
||||
auto capital_wallet = get_capital_wallet(coopname, owner);
|
||||
eosio::check(!capital_wallet.has_value(), "Для участия необходимо подписать соглашение целевой потребительской программы!");
|
||||
|
||||
// извлекаем результат
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
|
||||
// извлекаем проект
|
||||
auto project = get_project(coopname, result -> project_hash);
|
||||
eosio::check(project.has_value(), "Проект не найден");
|
||||
|
||||
// извлекаем клайм, и падаем, если он уже есть
|
||||
auto existing_claim = get_claim(coopname, claim_hash);
|
||||
eosio::check(!existing_claim.has_value(), "Объект запроса доли уже существует");
|
||||
|
||||
uint64_t author_amount = 0;
|
||||
uint64_t creator_amount = 0;
|
||||
uint64_t creator_bonus_amount = 0;
|
||||
uint64_t participant_amount = 0;
|
||||
|
||||
// считаем авторское вознаграждение
|
||||
auto author = get_result_author(coopname, owner, result_hash);
|
||||
if (author.has_value()) {
|
||||
author_amount = uint64_t(double(author->shares) * double(result->authors_bonus.amount) / double(result->authors_shares));
|
||||
}
|
||||
|
||||
// считаем вознаграждение создателя
|
||||
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, owner);
|
||||
|
||||
if (result -> creators_amount.amount > 0) {
|
||||
/**
|
||||
- for_convert - это то, что гарантированно готовится стать share_balance,
|
||||
- available - это то, что может быть выведено до момента claim.
|
||||
*/
|
||||
|
||||
creator_amount = contributor -> available.amount + contributor -> for_convert.amount;
|
||||
double creator_bonus_share = double(creator_amount) / double(result -> creators_amount.amount);
|
||||
creator_bonus_amount = uint64_t(creator_bonus_share * double(result -> creators_bonus.amount));
|
||||
};
|
||||
|
||||
// считаем премию пайщика
|
||||
if (
|
||||
capital_program.available -> amount > 0 &&
|
||||
capital_wallet -> available.amount > 0 &&
|
||||
result -> participants_bonus_remain.amount > 0)
|
||||
{
|
||||
double participant_share = double(capital_wallet -> available.amount) / double(capital_program.available -> amount);
|
||||
participant_amount = uint64_t(participant_share * double(result -> participants_bonus.amount));
|
||||
|
||||
if (participant_amount > result -> participants_bonus_remain.amount) {
|
||||
participant_amount = result -> participants_bonus_remain.amount;
|
||||
}
|
||||
}
|
||||
|
||||
//DEBUG
|
||||
print("author_amount: ", author_amount);
|
||||
print("creator_amount: ", creator_amount);
|
||||
print("creator_bonus_amount: ", creator_bonus_amount);
|
||||
print("participant_amount:", participant_amount);
|
||||
|
||||
eosio::asset amount = eosio::asset(author_amount + creator_amount + creator_bonus_amount + participant_amount, _root_govern_symbol);
|
||||
|
||||
// создаём объект запроса доли
|
||||
claim_index claims(_capital, coopname.value);
|
||||
uint64_t claim_id = get_global_id_in_scope(_capital, coopname, "claims"_n);
|
||||
|
||||
claims.emplace(coopname, [&](auto &n) {
|
||||
n.id = claim_id;
|
||||
n.claim_hash = claim_hash;
|
||||
n.owner = owner;
|
||||
n.result_hash = result_hash;
|
||||
n.coopname = coopname;
|
||||
n.status = "pending"_n;
|
||||
n.amount = amount;
|
||||
});
|
||||
|
||||
// обновляем оставшиеся выплаты пайщикам
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_for_modify = results.find(result -> id);
|
||||
eosio::check(result_for_modify -> participants_bonus_remain.amount >= participant_amount, "Недостаточно средств в результате для оплаты премии пайщика");
|
||||
|
||||
results.modify(result_for_modify, coopname, [&](auto &r){
|
||||
r.participants_bonus_remain -= asset(participant_amount, _root_govern_symbol);
|
||||
});
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
void capital::setact1(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 claim_hash, document act) {
|
||||
check_auth_or_fail(_capital, coopname, application, "setact1"_n);
|
||||
|
||||
verify_document_or_fail(act);
|
||||
|
||||
// claims
|
||||
auto claim = get_claim(coopname, claim_hash);
|
||||
eosio::check(claim.has_value(), "Объект запроса доли не найден");
|
||||
eosio::check(claim -> owner == owner, "Неверно указано имя пользователя владельца результата");
|
||||
|
||||
auto result = get_result(coopname, claim -> result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
|
||||
claim_index claims(_capital, coopname.value);
|
||||
auto claim_for_modify = claims.find(claim -> id);
|
||||
|
||||
// Проверяем статус.
|
||||
eosio::check(result -> status == "decision"_n, "Неверный статус для поставки акта приёма-передачи");
|
||||
|
||||
claims.modify(claim_for_modify, coopname, [&](auto &n){
|
||||
n.status = "act1"_n;
|
||||
n.act1 = act;
|
||||
});
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
void capital::setact2(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 claim_hash, document act) {
|
||||
check_auth_or_fail(_capital, coopname, application, "setact2"_n);
|
||||
|
||||
verify_document_or_fail(act);
|
||||
|
||||
auto exist_claim = get_claim(coopname, claim_hash);
|
||||
|
||||
eosio::check(exist_claim.has_value(), "Объект запроса доли не найден");
|
||||
eosio::check(exist_claim -> owner == owner, "Неверно указано имя пользователя владельца результата");
|
||||
|
||||
auto result = get_result(coopname, exist_claim -> result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
|
||||
auto project = get_project(coopname, result -> project_hash);
|
||||
eosio::check(project.has_value(), "Проект не найден");
|
||||
|
||||
// Проверяем статус
|
||||
eosio::check(exist_claim -> status == "act1"_n, "Неверный статус для поставки акта");
|
||||
|
||||
claim_index claims(coopname, coopname.value);
|
||||
auto claim = claims.find(exist_claim -> id);
|
||||
|
||||
claims.modify(claim, coopname, [&](auto &n) {
|
||||
n.status = "act2"_n;
|
||||
n.act2 = act;
|
||||
});
|
||||
|
||||
auto contributor = capital::get_active_contributor_or_fail(coopname, result -> project_hash, exist_claim -> owner);
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
|
||||
auto contributor_for_modify = contributors.find(contributor -> id);
|
||||
|
||||
// Увеличиваем share_balance на сумму остатка создательского баланса
|
||||
contributors.modify(contributor_for_modify, coopname, [&](auto &c) {
|
||||
c.share_balance += claim -> amount;
|
||||
});
|
||||
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project_for_modify = projects.find(project -> id);
|
||||
|
||||
// учитываем увеличение долей в проекте
|
||||
projects.modify(project_for_modify, coopname, [&](auto &p){
|
||||
p.membership_total_shares += claim -> amount;
|
||||
});
|
||||
|
||||
// списание с УХД
|
||||
Wallet::sub_blocked_funds(_capital, coopname, claim -> owner, claim -> amount, _cofund_program);
|
||||
|
||||
// добавление на капитализацию
|
||||
Wallet::add_blocked_funds(_capital, coopname, claim -> owner, claim -> amount, _capital_program);
|
||||
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
void capital::setstatement(name coopname, name application, name owner, checksum256 claim_hash, document statement) {
|
||||
check_auth_or_fail(_capital, coopname, application, "setstatement"_n);
|
||||
|
||||
// проверяем заявление
|
||||
verify_document_or_fail(statement);
|
||||
|
||||
// извлекаем клайм
|
||||
auto claim = get_claim(coopname, claim_hash);
|
||||
eosio::check(claim.has_value(), "Объект запроса доли не найден");
|
||||
eosio::check(claim->status == "pending"_n, "Нельзя изменить статус клайма");
|
||||
eosio::check(claim -> owner == owner, "Неверно указано имя пользователя владельца результата");
|
||||
|
||||
// обновляем клайм, добавляя заявление
|
||||
claim_index claims(_capital, coopname.value);
|
||||
auto claim_for_modify = claims.find(claim->id);
|
||||
|
||||
claims.modify(claim_for_modify, coopname, [&](auto &c){
|
||||
c.status = "statement"_n;
|
||||
c.statement = statement;
|
||||
});
|
||||
|
||||
// Отправляем заявление в совет
|
||||
action(permission_level{_capital, "active"_n}, _soviet, "claim"_n,
|
||||
std::make_tuple(coopname, owner, claim->id, statement))
|
||||
.send();
|
||||
}
|
||||
@@ -1,80 +1,85 @@
|
||||
void capital::approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_specification){
|
||||
check_auth_or_fail(_capital, coopname, application, "approvecmmt"_n);
|
||||
|
||||
verify_document_or_fail(approved_specification);
|
||||
void capital::approvecmmt(eosio::name coopname, checksum256 commit_hash, document2 empty_document) {
|
||||
require_auth(_soviet);
|
||||
|
||||
auto exist_commit = get_commit(coopname, commit_hash);
|
||||
eosio::check(exist_commit.has_value(), "Действие с указанным хэшем не существует");
|
||||
|
||||
auto result = get_result(coopname, exist_commit -> result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
|
||||
eosio::check(result -> status == "created"_n, "Нельзя добавить действие в уже закрытый результат");
|
||||
eosio::check(exist_commit.has_value(), "Коммит не найден");
|
||||
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit = commits.find(exist_commit -> id);
|
||||
|
||||
commits.modify(commit, coopname, [&](auto &a){
|
||||
a.status = "approved"_n;
|
||||
a.approved_specification = approved_specification;
|
||||
});
|
||||
auto exist_assignment = get_assignment(coopname, commit -> assignment_hash);
|
||||
eosio::check(exist_assignment.has_value(), "Задание не найдено");
|
||||
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, result -> project_hash, commit -> username);
|
||||
eosio::check(exist_assignment -> status == "opened"_n, "Нельзя добавить коммит в уже закрытое задание");
|
||||
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor -> id);
|
||||
// Обновляем assignment
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment -> id);
|
||||
|
||||
// Рассчитываем долю, которая идет в for_convert
|
||||
double convert_ratio = static_cast<double>(contributor->convert_percent) / HUNDR_PERCENTS;
|
||||
asset for_convert = asset(static_cast<int64_t>(commit->spend.amount * convert_ratio), commit->spend.symbol);
|
||||
|
||||
// Остаток идет в available
|
||||
asset available = commit -> spend - for_convert;
|
||||
|
||||
contributors.modify(contributor, coopname, [&](auto &c){
|
||||
c.available += available;
|
||||
c.for_convert += for_convert;
|
||||
c.contributed_hours = commit -> contributed_hours;
|
||||
c.spend += commit -> spend;
|
||||
});
|
||||
|
||||
auto br = capital::calculcate_capital_amounts(commit -> spend.amount);
|
||||
|
||||
// Формируем eosio::asset из результатов
|
||||
eosio::asset creators_bonus(br.creators_bonus, commit -> spend.symbol);
|
||||
eosio::asset authors_bonus(br.authors_bonus, commit -> spend.symbol);
|
||||
eosio::asset generated(br.generated, commit -> spend.symbol);
|
||||
eosio::asset participants_bonus(br.participants_bonus, commit -> spend.symbol);
|
||||
eosio::asset total(br.total, commit -> spend.symbol);
|
||||
|
||||
// Обновляем запись в таблице results
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_for_modyfy = results.find(result -> id);
|
||||
|
||||
eosio::check(result -> available >= commit -> spend, "Недостаточно средств в результате для приёма действия");
|
||||
|
||||
results.modify(result_for_modyfy, coopname, [&](auto& row) {
|
||||
row.available -= commit -> spend;
|
||||
row.spend += commit -> spend;
|
||||
|
||||
row.creators_amount += commit -> spend;
|
||||
row.creators_bonus += creators_bonus;
|
||||
row.authors_bonus += authors_bonus;
|
||||
row.generated_amount += generated;
|
||||
row.participants_bonus += participants_bonus;
|
||||
row.participants_bonus_remain += participants_bonus;
|
||||
row.total_amount += total;
|
||||
assignments.modify(assignment, _capital, [&](auto &row) {
|
||||
row.spended += commit -> spended;
|
||||
row.creators_base += commit -> spended;
|
||||
row.generated += commit -> generated;
|
||||
row.creators_bonus += commit -> creators_bonus;
|
||||
row.authors_bonus += commit -> authors_bonus;
|
||||
row.capitalists_bonus += commit -> capitalists_bonus;
|
||||
row.total += commit -> total;
|
||||
row.total_creators_bonus_shares += commit-> spended.amount;
|
||||
row.commits_count++;
|
||||
});
|
||||
|
||||
|
||||
//обновить сгенерированную сумму по проекту
|
||||
auto exist_project = get_project(coopname, result -> project_hash);
|
||||
|
||||
// Обновляем проект
|
||||
auto exist_project = get_project(coopname, commit -> project_hash);
|
||||
eosio::check(exist_project.has_value(),"Проект не найден");
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist_project->id);
|
||||
auto project = projects.find(exist_project -> id);
|
||||
|
||||
projects.modify(project, _capital, [&](auto &p) {
|
||||
p.generated += generated;
|
||||
p.spended += commit -> spended;
|
||||
p.generated += commit -> generated;
|
||||
p.creators_base += commit -> spended;
|
||||
p.creators_bonus += commit -> creators_bonus;
|
||||
p.authors_bonus += commit -> authors_bonus;
|
||||
p.capitalists_bonus += commit -> capitalists_bonus;
|
||||
p.total += commit -> total;
|
||||
|
||||
p.commits_count++;
|
||||
});
|
||||
|
||||
|
||||
// Обновляем актора и проект
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, commit -> project_hash, commit -> username);
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor -> id);
|
||||
contributors.modify(contributor, coopname, [&](auto &c){
|
||||
c.spended += commit->spended;
|
||||
c.contributed_hours += commit->contributed_hours;
|
||||
});
|
||||
|
||||
// Обновляем запись в creauthors (создательские доли)
|
||||
auto exist_creauthor = get_creauthor(coopname, commit->assignment_hash, commit->username);
|
||||
creauthor_index creathors(_capital, coopname.value);
|
||||
|
||||
if (!exist_creauthor.has_value()) {
|
||||
creathors.emplace(_capital, [&](auto &ra){
|
||||
ra.id = creathors.available_primary_key();
|
||||
ra.project_hash = commit->project_hash;
|
||||
ra.assignment_hash = commit->assignment_hash;
|
||||
ra.username = commit->username;
|
||||
ra.spended = commit->spended;
|
||||
ra.contributed_hours = commit->contributed_hours;
|
||||
// сумма, которая доступна для получения ссуды и используется в качества залога
|
||||
ra.provisional_amount = commit->spended;
|
||||
ra.creator_bonus_shares = commit->spended.amount;
|
||||
});
|
||||
} else {
|
||||
auto creauthor = creathors.find(exist_creauthor->id);
|
||||
creathors.modify(creauthor, _capital, [&](auto &ra) {
|
||||
ra.spended += commit->spended;
|
||||
ra.contributed_hours += commit->contributed_hours;
|
||||
ra.provisional_amount += commit->spended;
|
||||
ra.creator_bonus_shares += commit->spended.amount;
|
||||
});
|
||||
}
|
||||
|
||||
commits.erase(commit);
|
||||
};
|
||||
@@ -1,33 +1,63 @@
|
||||
void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document specification){
|
||||
check_auth_or_fail(_capital, coopname, application, "createcmmt"_n);
|
||||
void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 commit_hash, uint64_t contributed_hours){
|
||||
require_auth(coopname);
|
||||
|
||||
verify_document_or_fail(specification);
|
||||
auto assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Задание не найдено");
|
||||
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, creator);
|
||||
auto contributor = get_active_contributor_or_fail(coopname, assignment -> project_hash, username);
|
||||
|
||||
auto exist_commit = get_commit(coopname, commit_hash);
|
||||
|
||||
eosio::check(!exist_commit.has_value(), "Действие с указанным хэшем уже существует");
|
||||
|
||||
eosio::check(contributed_hours > 0, "Только положительная сумма");
|
||||
eosio::check(contributed_hours > 0, "Только положительная сумма часов");
|
||||
|
||||
eosio::asset spend = contributor -> rate_per_hour * contributed_hours;
|
||||
// считаем сумму фактических затрат создателя на основе ставки в час и потраченного времени
|
||||
eosio::asset spended = contributor -> rate_per_hour * contributed_hours;
|
||||
|
||||
// Вычисляем премии на основе суммы фактических затрат
|
||||
auto amounts = capital::calculcate_capital_amounts(spended);
|
||||
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit_id = get_global_id_in_scope(_capital, coopname, "commits"_n);
|
||||
|
||||
//TODO: надо смотреть надо ли здесь добавлять creator_base и author_base
|
||||
commits.emplace(coopname, [&](auto &a) {
|
||||
a.id = get_global_id_in_scope(_capital, coopname, "commits"_n);
|
||||
a.id = commit_id;
|
||||
a.status = "created"_n;
|
||||
a.coopname = coopname;
|
||||
a.application = application;
|
||||
a.username = creator;
|
||||
a.project_hash = result -> project_hash;
|
||||
a.result_hash = result_hash;
|
||||
a.username = username;
|
||||
a.project_hash = assignment -> project_hash;
|
||||
a.assignment_hash = assignment_hash;
|
||||
a.commit_hash = commit_hash;
|
||||
a.contributed_hours = contributed_hours;
|
||||
a.spend = spend;
|
||||
a.rate_per_hour = contributor -> rate_per_hour;
|
||||
a.spended = spended;
|
||||
a.generated = amounts.generated;
|
||||
a.creators_bonus = amounts.creators_bonus;
|
||||
a.authors_bonus = amounts.authors_bonus;
|
||||
a.capitalists_bonus = amounts.capitalists_bonus;
|
||||
a.total = amounts.total;
|
||||
a.created_at = current_time_point();
|
||||
a.specification = specification;
|
||||
});
|
||||
|
||||
auto empty_doc = document2{};
|
||||
|
||||
//отправить на approve председателю
|
||||
Action::send<createapprv_interface>(
|
||||
_soviet,
|
||||
"createapprv"_n,
|
||||
_capital,
|
||||
coopname,
|
||||
username,
|
||||
empty_doc,
|
||||
commit_hash,
|
||||
_capital,
|
||||
"approvecmmt"_n,
|
||||
"declinecmmt"_n,
|
||||
std::string("")
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
void capital::declinecmmt(eosio::name coopname, checksum256 commit_hash, std::string reason) {
|
||||
require_auth(_soviet);
|
||||
|
||||
auto exist_commit = get_commit(coopname, commit_hash);
|
||||
eosio::check(exist_commit.has_value(), "Коммит не найден");
|
||||
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit = commits.find(exist_commit -> id);
|
||||
|
||||
commits.modify(commit, coopname, [&](auto &c) {
|
||||
c.status = "declined"_n;
|
||||
c.decline_comment = reason;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
void capital::delcmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash) {
|
||||
require_auth(coopname);
|
||||
|
||||
auto exist_commit = get_commit(coopname, commit_hash);
|
||||
eosio::check(exist_commit.has_value(), "Коммит с указанным хэшем не существует");
|
||||
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit = commits.find(exist_commit->id);
|
||||
eosio::check(commit != commits.end(), "Коммит не найден");
|
||||
|
||||
eosio::check(commit->status == "declined"_n, "Удалять можно только отклонённые коммиты");
|
||||
|
||||
commits.erase(commit);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document2 approved_statement){
|
||||
check_auth_or_fail(_capital, coopname, application, "approvecnvrt"_n);
|
||||
|
||||
verify_document_or_fail(approved_statement);
|
||||
|
||||
auto exist_convert = get_convert(coopname, convert_hash);
|
||||
eosio::check(exist_convert.has_value(), "Конвертация пользователя для задананиеа не найдена");
|
||||
convert_index converts(_capital, coopname.value);
|
||||
|
||||
auto convert = converts.find(exist_convert -> id);
|
||||
|
||||
auto assignment = get_assignment(coopname, convert -> assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Задание не найдено");
|
||||
|
||||
// добавляем доли актору и отмечаем статистику сконвертированных сумм
|
||||
auto contributor = get_active_contributor_or_fail(coopname, convert -> project_hash, convert -> username);
|
||||
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor_for_modify = contributors.find(contributor -> id);
|
||||
|
||||
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
|
||||
c.converted += convert -> convert_amount;
|
||||
c.share_balance += convert -> convert_amount;
|
||||
});
|
||||
|
||||
// добавляем доли в проект
|
||||
auto exist = get_project(coopname, convert -> project_hash);
|
||||
eosio::check(exist.has_value(),"Проект не найден");
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist -> id);
|
||||
|
||||
projects.modify(project, coopname, [&](auto &p) {
|
||||
p.converted += convert -> convert_amount;
|
||||
p.total_share_balance += convert -> convert_amount;
|
||||
});
|
||||
|
||||
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Капитализация' с ID: " + std::to_string(convert -> id);
|
||||
|
||||
//Списываем баланс средств с УХД только при наличии convert_amount в result
|
||||
Wallet::sub_blocked_funds(_capital, coopname, convert -> username, convert -> convert_amount, _source_program, memo);
|
||||
|
||||
//Увеличиваем баланс средств в капитализации
|
||||
Wallet::add_blocked_funds(_capital, coopname, convert -> username, convert -> convert_amount, _capital_program, memo);
|
||||
|
||||
// удаляем объект конвертации
|
||||
converts.erase(convert);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void capital::createcnvrt(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 convert_hash,
|
||||
document2 convert_statement
|
||||
) {
|
||||
// Авторизация
|
||||
require_auth(coopname);
|
||||
|
||||
// Получаем задание (или кидаем ошибку)
|
||||
auto exist_assignment = get_assignment_or_fail(coopname, assignment_hash, "Задание не найдено");
|
||||
eosio::check(exist_assignment.status == "closed"_n, "Распределение стоимости задания еще не начато");
|
||||
|
||||
// Проверяем, нет ли уже такой конвертации
|
||||
auto existing_convert = get_convert(coopname, convert_hash);
|
||||
eosio::check(!existing_convert.has_value(), "Объект конвертации с указанным хэшем уже существует");
|
||||
|
||||
// Находим запись в таблице assignments
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment.id);
|
||||
|
||||
// Получаем контрибьютора
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_assignment.project_hash, username);
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor->id);
|
||||
|
||||
// Находим creauthor
|
||||
auto exist_creauthor = get_creauthor_or_fail(coopname, assignment_hash, username, "Объект актора в результате не найден");
|
||||
|
||||
//=== Сумма к конвертации ===
|
||||
asset convert_amount = exist_creauthor.available + exist_creauthor.for_convert;
|
||||
eosio::check(convert_amount.amount > 0, "Нет доступных средств для конвертации");
|
||||
|
||||
//=== Создаём запись в converts ===
|
||||
convert_index converts(_capital, coopname.value);
|
||||
uint64_t convert_id = get_global_id_in_scope(_capital, coopname, "converts"_n);
|
||||
|
||||
converts.emplace(coopname, [&](auto &n) {
|
||||
n.id = convert_id;
|
||||
n.username = username;
|
||||
n.project_hash = exist_assignment.project_hash;
|
||||
n.assignment_hash = assignment_hash;
|
||||
n.convert_hash = convert_hash;
|
||||
n.coopname = coopname;
|
||||
n.status = "created"_n;
|
||||
n.convert_amount = convert_amount;
|
||||
n.convert_statement = convert_statement;
|
||||
});
|
||||
|
||||
eosio::check(assignment -> creators_base_remain >= convert_amount, "Недостаточно средств в assignment.creators_base_remain для конвертации");
|
||||
|
||||
assignments.modify(assignment, coopname, [&](auto &r) {
|
||||
r.creators_base_remain -= convert_amount;
|
||||
});
|
||||
|
||||
creauthor_index creathors(_capital, coopname.value);
|
||||
|
||||
auto creauthor = creathors.find(exist_creauthor.id);
|
||||
|
||||
//обнуляем доступные средства к выводу или конвертации
|
||||
creathors.modify(creauthor, coopname, [&](auto &ra) {
|
||||
ra.for_convert = asset(0, _root_govern_symbol);
|
||||
ra.available = asset(0, _root_govern_symbol);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
void capital::approvedebt(eosio::name coopname, checksum256 debt_hash, document2 approved_statement)
|
||||
{
|
||||
require_auth(_soviet);
|
||||
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto exist_debt = get_debt(coopname, debt_hash);
|
||||
eosio::check(exist_debt.has_value(), "Долг не найден");
|
||||
|
||||
auto debt = debts.find(exist_debt -> id);
|
||||
|
||||
debts.modify(debt, coopname, [&](auto& d) {
|
||||
d.status = "approved"_n;
|
||||
d.approved_statement = approved_statement;
|
||||
});
|
||||
|
||||
//отправляем в совет
|
||||
Action::send<createagenda_interface>(
|
||||
_soviet,
|
||||
"createagenda"_n,
|
||||
_capital,
|
||||
coopname,
|
||||
debt -> username,
|
||||
get_valid_soviet_action("createdebt"_n),
|
||||
debt_hash,
|
||||
_capital,
|
||||
"debtauthcnfr"_n,
|
||||
"declinedebt"_n,
|
||||
debt -> statement,
|
||||
std::string("")
|
||||
);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
void capital::createdebt(name coopname, name username, checksum256 assignment_hash, checksum256 debt_hash, asset amount, time_point_sec repaid_at, document2 statement) {
|
||||
require_auth(coopname);
|
||||
|
||||
verify_document_or_fail(statement);
|
||||
|
||||
Wallet::validate_asset(amount);
|
||||
|
||||
auto exist_assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(exist_assignment.has_value(), "Задание не найдено");
|
||||
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment -> id);
|
||||
|
||||
eosio::check(assignment -> status == "opened"_n, "Только результаты в статусе opened могут быть основанием для выдачи ссуды");
|
||||
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, assignment -> project_hash, username);
|
||||
eosio::check(exist_contributor.has_value(), "Договор УХД с пайщиком не найден");
|
||||
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor -> id);
|
||||
|
||||
contributors.modify(contributor, coopname, [&](auto &c){
|
||||
c.debt_amount += amount;
|
||||
});
|
||||
|
||||
auto exist_creauthor = get_creauthor(coopname, assignment_hash, username);
|
||||
eosio::check(exist_creauthor.has_value(), "Резактор не найден");
|
||||
|
||||
creauthor_index creauthors(_capital, coopname.value);
|
||||
|
||||
auto creauthor = creauthors.find(exist_creauthor->id);
|
||||
eosio::check(creauthor -> provisional_amount >= amount, "Недостаточно доступных средств для получения ссуды");
|
||||
|
||||
creauthors.modify(creauthor, coopname, [&](auto &ra) {
|
||||
ra.debt_amount += amount;
|
||||
ra.provisional_amount -= amount;
|
||||
});
|
||||
|
||||
auto exist_debt = get_debt(coopname, debt_hash);
|
||||
eosio::check(!exist_debt.has_value(), "Ссуда с указанным hash уже существует");
|
||||
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto debt_id = get_global_id_in_scope(_soviet, coopname, "debts"_n);
|
||||
|
||||
debts.emplace(coopname, [&](auto &d){
|
||||
d.id = debt_id;
|
||||
d.coopname = coopname;
|
||||
d.username = username;
|
||||
d.debt_hash = debt_hash;
|
||||
d.assignment_hash = assignment_hash;
|
||||
d.project_hash = assignment -> project_hash;
|
||||
d.amount = amount;
|
||||
d.statement = statement;
|
||||
d.repaid_at = repaid_at;
|
||||
});
|
||||
|
||||
|
||||
// Отправляем в совет approve-запрос
|
||||
action(
|
||||
permission_level{_capital, "active"_n}, // кто вызывает
|
||||
_soviet,
|
||||
"createapprv"_n,
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
username,
|
||||
statement,
|
||||
debt_hash, // внешний ID
|
||||
_capital, // callback_contract (текущий контракт)
|
||||
"approvedebt"_n, // callback_action_approve
|
||||
"declinedebt"_n, // callback_action_decline
|
||||
std::string("")
|
||||
)
|
||||
).send();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//действие вызывается советом как коллбэк при положительном решении по вопросу выдачи ссуд
|
||||
//вызывает контракт шлюза для регистрации исходящего платежа
|
||||
void capital::debtauthcnfr(eosio::name coopname, checksum256 debt_hash, document2 decision) {
|
||||
require_auth(_soviet);
|
||||
|
||||
auto exist_debt = get_debt(coopname, debt_hash);
|
||||
eosio::check(exist_debt.has_value(), "Долг не найден");
|
||||
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto debt = debts.find(exist_debt -> id);
|
||||
debts.modify(debt, _capital, [&](auto &d){
|
||||
d.status = "authorized"_n;
|
||||
d.authorization = decision;
|
||||
});
|
||||
|
||||
//Создаём объект долга в контракте loan
|
||||
Action::send<createdebt_interface>(
|
||||
_loan,
|
||||
"createdebt"_n,
|
||||
_capital,
|
||||
coopname,
|
||||
debt -> username,
|
||||
debt -> debt_hash,
|
||||
debt -> repaid_at,
|
||||
debt -> amount
|
||||
);
|
||||
|
||||
// создаём объект исходящего платежа в gateway с коллбэком после обработки
|
||||
Action::send<createoutpay_interface>(
|
||||
_gateway,
|
||||
"createoutpay"_n,
|
||||
_capital,
|
||||
coopname,
|
||||
debt -> username,
|
||||
debt -> debt_hash,
|
||||
debt -> amount,
|
||||
_capital,
|
||||
"debtpaycnfrm"_n,
|
||||
"dclnauthdebt"_n
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
void capital::debtpaycnfrm(name coopname, checksum256 debt_hash) {
|
||||
require_auth(_gateway);
|
||||
|
||||
auto exist_debt = get_debt(coopname, debt_hash);
|
||||
eosio::check(exist_debt.has_value(), "Долг не найден");
|
||||
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto debt = debts.find(exist_debt -> id);
|
||||
|
||||
debts.erase(debt);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
void capital::debtpaydcln(name coopname, checksum256 debt_hash, std::string reason) {
|
||||
require_auth(_gateway);
|
||||
|
||||
auto exist_debt = get_debt(coopname, debt_hash);
|
||||
eosio::check(exist_debt.has_value(), "Долг не найден");
|
||||
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto debt = debts.find(exist_debt -> id);
|
||||
|
||||
//Удаляем объект долга в контракте loan
|
||||
Action::send<settledebt_interface>(
|
||||
_loan,
|
||||
"settledebt"_n,
|
||||
_capital,
|
||||
coopname,
|
||||
debt -> username,
|
||||
debt -> debt_hash,
|
||||
debt -> amount
|
||||
);
|
||||
|
||||
debts.erase(debt);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
void capital::declinedebt(name coopname, checksum256 debt_hash, std::string reason) {
|
||||
//вызывается при отклонении советом или председателем из контракта совета
|
||||
require_auth(_gateway);
|
||||
|
||||
auto exist_debt = get_debt(coopname, debt_hash);
|
||||
eosio::check(exist_debt.has_value(), "Долг не найден");
|
||||
|
||||
debts_index debts(_capital, coopname.value);
|
||||
auto debt = debts.find(exist_debt -> id);
|
||||
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, debt -> project_hash, debt -> username);
|
||||
eosio::check(exist_contributor.has_value(), "Договор УХД с пайщиком не найден");
|
||||
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor -> id);
|
||||
|
||||
eosio::check(contributor -> debt_amount >= debt -> amount, "Возникла какая-то чудовищная ошибка: у пайщика недостаточно средств в долговом кошельке для того, чтобы принять возврат долга. Такого вообще не должно было быть, но если произошло, пожалуйста, срочно обратитесь в поддержку.");
|
||||
|
||||
contributors.modify(contributor, coopname, [&](auto &c) {
|
||||
c.debt_amount -= debt -> amount;
|
||||
});
|
||||
|
||||
auto exist_creauthor = get_creauthor(coopname, debt -> assignment_hash, debt -> username);
|
||||
eosio::check(exist_creauthor.has_value(), "Резактор не найден");
|
||||
|
||||
creauthor_index creauthors(_capital, coopname.value);
|
||||
auto creauthor = creauthors.find(exist_creauthor->id);
|
||||
|
||||
eosio::check(creauthor -> provisional_amount >= debt -> amount, "Недостаточно доступных средств для получения ссуды");
|
||||
eosio::check(creauthor -> debt_amount >= debt -> amount, "Возникла какая-то чудовищная ошибка: у пайщика недостаточно средств в долговом кошельке для того, чтобы принять возврат долга. Такого вообще не должно было быть, но если произошло, пожалуйста, срочно обратитесь в поддержку.");
|
||||
|
||||
creauthors.modify(creauthor, coopname, [&](auto &ra) {
|
||||
ra.debt_amount -= debt -> amount;
|
||||
ra.provisional_amount += debt -> amount;
|
||||
});
|
||||
|
||||
debts.erase(debt);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
void capital::settledebt(name coopname){
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
void capital::approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document approved_statement) {
|
||||
void capital::approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document2 approved_statement) {
|
||||
check_auth_or_fail(_capital, coopname, application, "approveinvst"_n);
|
||||
|
||||
verify_document_or_fail(approved_statement);
|
||||
@@ -16,20 +16,30 @@ void capital::approveexpns(name coopname, name application, name approver, check
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, expense -> project_hash, expense -> username);
|
||||
|
||||
auto exist_result = get_result(coopname, expense -> result_hash);
|
||||
eosio::check(exist_result.has_value(),"Результат не найден");
|
||||
eosio::check(exist_result -> available >= expense -> amount, "Недостаточно средств в результате для списания расходов");
|
||||
auto exist_assignment = get_assignment(coopname, expense -> assignment_hash);
|
||||
eosio::check(exist_assignment.has_value(),"Задание не найдено");
|
||||
eosio::check(exist_assignment -> available >= expense -> amount, "Недостаточно средств в результате для списания расходов");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result -> id);
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment -> id);
|
||||
|
||||
results.modify(result, coopname, [&](auto &r){
|
||||
assignments.modify(assignment, coopname, [&](auto &r){
|
||||
r.available -= expense -> amount;
|
||||
});
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(coopname, expense -> username, _capital, _capital_expense_authorize_action, expense -> id, expense -> statement, std::string("")))
|
||||
.send();
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
expense -> username,
|
||||
get_valid_soviet_action("capresexpns"_n),
|
||||
expense_hash,
|
||||
_capital,
|
||||
"capauthexpns"_n,
|
||||
"capdeclexpns"_n,
|
||||
expense -> expense_statement,
|
||||
std::string("")
|
||||
)
|
||||
).send();
|
||||
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
void capital::capauthexpns(eosio::name coopname, uint64_t expense_id, document authorization) {
|
||||
void capital::capauthexpns(eosio::name coopname, checksum256 expense_hash, document2 authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
expense_index expenses(_capital, coopname.value);
|
||||
auto expense = expenses.find(expense_id);
|
||||
auto exist_expense = get_expense(coopname, expense_hash);
|
||||
eosio::check(exist_expense.has_value(), "Расход не найден");
|
||||
|
||||
eosio::check(expense != expenses.end(), "Расход не найден");
|
||||
expense_index expenses(_capital, coopname.value);
|
||||
auto expense = expenses.find(exist_expense -> id);
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, expense -> project_hash, expense -> username);
|
||||
eosio::check(contributor.has_value(), "Договор УХД с пайщиком по проекту не найден");
|
||||
@@ -16,8 +17,16 @@ void capital::capauthexpns(eosio::name coopname, uint64_t expense_id, document a
|
||||
});
|
||||
|
||||
// создаём объект исходящего платежа в gateway с коллбэком после обработки
|
||||
action(permission_level{ _capital, "active"_n}, _gateway, _gateway_create_expense_withdraw_action,
|
||||
std::make_tuple(coopname, ""_n, expense -> username, expense -> expense_hash, expense -> amount, expense -> statement, _capital, _gateway_to_capital_expense_callback_type, std::string("")))
|
||||
.send();
|
||||
action(permission_level{ _capital, "active"_n}, _gateway, "createoutpay"_n,
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
expense -> username,
|
||||
expense -> expense_hash,
|
||||
expense -> amount,
|
||||
_capital,
|
||||
"exppaycnfrm"_n,
|
||||
"capdeclexpns"_n
|
||||
)
|
||||
).send();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
void capital::capdeclexpns(name coopname) {
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
void capital::createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 result_hash, name creator, uint64_t fund_id, asset amount, std::string description, document statement){
|
||||
void capital::createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 assignment_hash, name creator, uint64_t fund_id, asset amount, std::string description, document2 statement){
|
||||
check_auth_or_fail(_capital, coopname, application, "createexpns"_n);
|
||||
|
||||
verify_document_or_fail(statement);
|
||||
@@ -7,11 +7,11 @@ void capital::createexpnse(eosio::name coopname, eosio::name application, checks
|
||||
check(amount.is_valid(), "Invalid asset");
|
||||
check(amount.amount > 0, "Amount must be positive");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Объект результата не существует");
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Объект задананиеа не существует");
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, creator);
|
||||
auto contributor = get_active_contributor_or_fail(coopname, assignment -> project_hash, creator);
|
||||
|
||||
auto exist_expense = get_expense(coopname, expense_hash);
|
||||
eosio::check(!exist_expense.has_value(), "Расход с указанным хэшем уже существует");
|
||||
@@ -25,15 +25,15 @@ void capital::createexpnse(eosio::name coopname, eosio::name application, checks
|
||||
i.coopname = coopname;
|
||||
i.application = application;
|
||||
i.username = creator;
|
||||
i.project_hash = result -> project_hash;
|
||||
i.result_hash = result_hash;
|
||||
i.project_hash = assignment -> project_hash;
|
||||
i.assignment_hash = assignment_hash;
|
||||
i.expense_hash = expense_hash;
|
||||
i.fund_id = fund_id;
|
||||
i.status = "created"_n;
|
||||
i.spend_at = current_time_point();
|
||||
i.statement = statement;
|
||||
i.amount = amount;
|
||||
i.description = description;
|
||||
i.spended_at = current_time_point();
|
||||
i.expense_statement = statement;
|
||||
i.amount = amount;
|
||||
i.description = description;
|
||||
});
|
||||
|
||||
}
|
||||
+11
-10
@@ -1,6 +1,6 @@
|
||||
void capital::expense_withdraw_callback(name coopname, checksum256 expense_hash){
|
||||
auto payer = check_auth_and_get_payer_or_fail({_gateway});
|
||||
|
||||
void capital::exppaycnfrm(eosio::name coopname, checksum256 expense_hash) {
|
||||
auto payer = check_auth_and_get_payer_or_fail({ _gateway });
|
||||
|
||||
auto expense = get_expense(coopname, expense_hash);
|
||||
eosio::check(expense.has_value(), "Объект расходов не найден");
|
||||
|
||||
@@ -8,17 +8,18 @@ void capital::expense_withdraw_callback(name coopname, checksum256 expense_hash)
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor_for_modify = contributors.find(contributor -> id);
|
||||
|
||||
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
|
||||
contributors.modify(contributor_for_modify, payer, [&](auto &c){
|
||||
c.expensed += expense -> amount;
|
||||
});
|
||||
|
||||
auto exist_result = get_result(coopname, expense -> result_hash);
|
||||
eosio::check(exist_result.has_value(),"Результат не найден");
|
||||
auto exist_assignment = get_assignment(coopname, expense -> assignment_hash);
|
||||
eosio::check(exist_assignment.has_value(),"Задание не найдено");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result -> id);
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment -> id);
|
||||
|
||||
results.modify(result, coopname, [&](auto &r){
|
||||
//TODO: make coopname payer
|
||||
assignments.modify(assignment, payer, [&](auto &r){
|
||||
r.expensed += expense -> amount;
|
||||
});
|
||||
|
||||
@@ -37,4 +38,4 @@ void capital::expense_withdraw_callback(name coopname, checksum256 expense_hash)
|
||||
expenses.erase(expense_for_delete);
|
||||
|
||||
//TODO: здесь должна быть проводка по фонду
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user