Merge branch 'testnet'
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
---
|
||||
description:
|
||||
globs: components/controller/**
|
||||
alwaysApply: false
|
||||
---
|
||||
# NestJS Controller и Чистая архитектура
|
||||
|
||||
## Основные принципы
|
||||
1. Чистая архитектура - главный архитектурный подход. Пиши код с комментариями.
|
||||
2. Типы IName, IChecksum256, ITimePointSec - это просто строки.
|
||||
3. Домен должен быть полностью изолирован от инфраструктурных деталей.
|
||||
4. Направление зависимостей - внутрь (к ядру, домену).
|
||||
|
||||
## Структура проекта
|
||||
- `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:
|
||||
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,12 @@
|
||||
---
|
||||
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'
|
||||
@@ -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.
|
||||
@@ -2,3 +2,6 @@ node_modules/
|
||||
lerna-debug.log
|
||||
components/controller/graph.png
|
||||
blockchain-data/
|
||||
scripts/changelog-prompt.md
|
||||
scripts/changelog-release.md
|
||||
scripts/release-info.md
|
||||
|
||||
Vendored
+5
-3
@@ -4,11 +4,13 @@
|
||||
"editor.formatOnSave": true,
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||
"editor.codeActionsOnSave": {
|
||||
"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,
|
||||
"typescript.validate.enable": true
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
@@ -11,6 +11,7 @@
|
||||
"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",
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
],
|
||||
@@ -618,7 +619,7 @@ export default class Blockchain {
|
||||
name: RegistratorContract.Actions.RegisterUser.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.registrator,
|
||||
actor: params.coopname,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
@@ -800,36 +801,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.ICompeteIncome,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
@@ -837,11 +841,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',
|
||||
},
|
||||
],
|
||||
@@ -985,36 +989,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'],
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { Account, Contract, 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'
|
||||
@@ -46,48 +47,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 +55,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,40 +64,22 @@ 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('Голосуем по решению в провайдере')
|
||||
@@ -182,9 +122,23 @@ export class CooperativeClass {
|
||||
},
|
||||
})
|
||||
|
||||
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: '' })
|
||||
|
||||
@@ -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'
|
||||
@@ -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')
|
||||
@@ -397,6 +397,8 @@ describe('тест контракта CAPITAL', () => {
|
||||
application: 'voskhod',
|
||||
project_hash: project1.project_hash,
|
||||
result_hash: generateRandomSHA256(),
|
||||
assignee: 'ant',
|
||||
assignment: 'Задание #1: тут описание',
|
||||
}
|
||||
|
||||
result1 = data
|
||||
@@ -477,55 +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.generated).toBe('30000.0000 RUB')
|
||||
expect(finalResult.capitalists_bonus).toBe('48540.0000 RUB')
|
||||
expect(finalResult.total_amount).toBe('78540.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.generated).toBe('60000.0000 RUB')
|
||||
expect(finalResult.capitalists_bonus).toBe('97080.0000 RUB')
|
||||
expect(finalResult.total_amount).toBe('157080.0000 RUB')
|
||||
expect(finalResult.total).toBe('157080.0000 RUB')
|
||||
})
|
||||
|
||||
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,
|
||||
)
|
||||
})
|
||||
// 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',
|
||||
// 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'
|
||||
@@ -605,15 +608,24 @@ describe('тест контракта CAPITAL', () => {
|
||||
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('opened')
|
||||
expect(blockchainResult.status).toBe('closed')
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
it('обновляем капитал первого создателя в результате', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: tester1,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
const result = await blockchain.api.transact(
|
||||
@@ -656,11 +668,14 @@ describe('тест контракта CAPITAL', () => {
|
||||
})
|
||||
|
||||
it('обновляем капитал второго создателя в результате', async () => {
|
||||
const claim_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(
|
||||
@@ -703,11 +718,14 @@ describe('тест контракта CAPITAL', () => {
|
||||
})
|
||||
|
||||
it('повторно обновляем капитал второго создателя в результате и ожидаем ошибку', async () => {
|
||||
const claim_hash = generateRandomSHA256()
|
||||
|
||||
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
|
||||
coopname: 'voskhod',
|
||||
application: 'voskhod',
|
||||
result_hash: result1.result_hash,
|
||||
username: tester2,
|
||||
claim_hash,
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -742,11 +760,14 @@ describe('тест контракта CAPITAL', () => {
|
||||
})
|
||||
|
||||
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(
|
||||
@@ -789,11 +810,14 @@ describe('тест контракта CAPITAL', () => {
|
||||
})
|
||||
|
||||
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 {
|
||||
|
||||
@@ -28,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,
|
||||
@@ -39,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,
|
||||
@@ -62,10 +62,9 @@ export async function commitToResult(
|
||||
coopname,
|
||||
application: coopname,
|
||||
result_hash: resultHash,
|
||||
creator,
|
||||
commit_hash: commitHash,
|
||||
contribution_statement: fakeDocument,
|
||||
contributed_hours: spendHours,
|
||||
username: creator,
|
||||
}
|
||||
|
||||
console.log(`\n🚀 Отправка транзакции CreateCommit для результата ${resultHash}`)
|
||||
@@ -104,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_statement: fakeDocument,
|
||||
approval_hash: commitHash,
|
||||
approved_document: fakeDocument,
|
||||
}
|
||||
|
||||
console.log(`\n✅ Подтверждение коммита ${commitHash}`)
|
||||
@@ -121,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,
|
||||
},
|
||||
@@ -149,86 +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]
|
||||
// // Получение всех решений и выполнение последнего
|
||||
// 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)
|
||||
// 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,
|
||||
}
|
||||
// {
|
||||
// // Утверждение коммита
|
||||
// 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,
|
||||
},
|
||||
)
|
||||
// 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()
|
||||
}
|
||||
// getTotalRamUsage(act1Result)
|
||||
// expect(act1Result.transaction_id).toBeDefined()
|
||||
// }
|
||||
|
||||
{
|
||||
// Утверждение коммита
|
||||
const act2Data: CapitalContract.Actions.SetAct2.ISetAct2 = {
|
||||
coopname,
|
||||
application: coopname,
|
||||
username: creator,
|
||||
commit_hash: commitHash,
|
||||
act: fakeDocument,
|
||||
}
|
||||
// {
|
||||
// // Утверждение коммита
|
||||
// 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,
|
||||
},
|
||||
)
|
||||
// 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()
|
||||
}
|
||||
// getTotalRamUsage(act2Result)
|
||||
// expect(act2Result.transaction_id).toBeDefined()
|
||||
// }
|
||||
|
||||
// Проверка результата после утверждения коммита
|
||||
const finalResult = (await blockchain.getTableRows(
|
||||
@@ -269,8 +264,8 @@ 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)
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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,8 +74,9 @@ 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)
|
||||
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
}
|
||||
@@ -1,17 +1,33 @@
|
||||
// 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/claim/approveclaim.cpp"
|
||||
#include "src/claim/createclaim.cpp"
|
||||
#include "src/claim/claimnow.cpp"
|
||||
#include "src/claim/capauthclaim.cpp"
|
||||
#include "src/commit/createcmmt.cpp"
|
||||
#include "src/commit/approvecmmt.cpp"
|
||||
#include "src/commit/declinecmmt.cpp"
|
||||
#include "src/commit/delcmmt.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"
|
||||
@@ -22,13 +38,6 @@
|
||||
#include "src/managment/addauthor.cpp"
|
||||
#include "src/managment/allocate.cpp"
|
||||
#include "src/managment/diallocate.cpp"
|
||||
#include "src/managment/wthdrcallbck.cpp"
|
||||
|
||||
#include "src/commit/createcmmt.cpp"
|
||||
#include "src/commit/approvecmmt.cpp"
|
||||
#include "src/commit/capauthcmmt.cpp"
|
||||
#include "src/commit/setact1.cpp"
|
||||
#include "src/commit/setact2.cpp"
|
||||
|
||||
|
||||
#include "src/withdraw_from_result/createwthd1.cpp"
|
||||
@@ -48,8 +57,11 @@
|
||||
|
||||
#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/fundproj/fundproj.cpp"
|
||||
#include "src/fundproj/refreshproj.cpp"
|
||||
@@ -59,18 +71,6 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
// TODO: внедрить коррекцию долей при выходе пайщика из проекта / программы
|
||||
// void capital::reduce_shares(name coopname, checksum256 project_hash, name username, asset amount) {
|
||||
// require_auth(_capital);
|
||||
|
||||
|
||||
// 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");
|
||||
|
||||
// }
|
||||
|
||||
|
||||
void capital::validate_project_hierarchy_depth(eosio::name coopname, checksum256 project_hash) {
|
||||
uint8_t level = 0;
|
||||
@@ -148,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -256,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>();
|
||||
@@ -285,36 +270,49 @@ 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;
|
||||
}
|
||||
|
||||
result capital::get_result_or_fail(eosio::name coopname, const checksum256 &result_hash, const char* msg) {
|
||||
auto maybe_result = get_result(coopname, result_hash);
|
||||
eosio::check(maybe_result.has_value(), msg);
|
||||
return *maybe_result;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -386,10 +384,21 @@ std::optional<capital_tables::project_withdraw> capital::get_project_withdraw(eo
|
||||
}
|
||||
|
||||
|
||||
std::optional<claim> capital::get_claim(eosio::name coopname, const checksum256 &result_hash, eosio::name username) {
|
||||
claim_index claims(_capital, coopname.value);
|
||||
auto idx = claims.get_index<"byresuser"_n>();
|
||||
auto rkey = combine_checksum_ids(result_hash, username);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
auto it = idx.find(rkey);
|
||||
if (it == idx.end()) {
|
||||
@@ -412,17 +421,17 @@ std::optional<convert> capital::get_convert(eosio::name coopname, const checksum
|
||||
}
|
||||
|
||||
|
||||
claim capital::get_claim_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg) {
|
||||
auto c = get_claim(coopname, result_hash, username);
|
||||
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<resactor> capital::get_resactor(eosio::name coopname, const checksum256 &result_hash, eosio::name username) {
|
||||
resactor_index ractors(_capital, coopname.value);
|
||||
auto idx = ractors.get_index<"byresuser"_n>();
|
||||
auto rkey = combine_checksum_ids(result_hash, username);
|
||||
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()) {
|
||||
@@ -431,10 +440,10 @@ std::optional<resactor> capital::get_resactor(eosio::name coopname, const checks
|
||||
return *it;
|
||||
}
|
||||
|
||||
resactor capital::get_resactor_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg) {
|
||||
auto maybe_resactor = get_resactor(coopname, result_hash, username);
|
||||
eosio::check(maybe_resactor.has_value(), msg);
|
||||
return *maybe_resactor;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -466,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
|
||||
// - 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) capitalists_bonus = generated * 1.618
|
||||
br.capitalists_bonus = int64_t(double(br.generated) * 1.618);
|
||||
|
||||
// 5) total = generated + capitalists_bonus
|
||||
br.total = int64_t(br.generated + br.capitalists_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,24 +28,21 @@ 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, document 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, asset amount, document return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthd1(eosio::name coopname, uint64_t withdraw_id, document authorization);
|
||||
void capauthwthd1(eosio::name coopname, checksum256 withdraw_hash, document authorization);
|
||||
|
||||
// Возврат из проекта
|
||||
[[eosio::action]]
|
||||
void createwthd2(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthd2(eosio::name coopname, uint64_t withdraw_id, document authorization);
|
||||
void capauthwthd2(eosio::name coopname, checksum256 withdraw_hash, document authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvewthd2(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
|
||||
@@ -55,12 +52,11 @@ public:
|
||||
void createwthd3(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthwthd3(eosio::name coopname, uint64_t withdraw_id, document authorization);
|
||||
void capauthwthd3(eosio::name coopname, checksum256 withdraw_hash, document authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvewthd3(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
|
||||
|
||||
|
||||
[[eosio::action]]
|
||||
void createproj (
|
||||
checksum256 project_hash,
|
||||
@@ -74,23 +70,24 @@ public:
|
||||
std::string subject
|
||||
);
|
||||
|
||||
// claims
|
||||
// results
|
||||
[[eosio::action]]
|
||||
void createclaim(
|
||||
void updaterslt(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 result_hash
|
||||
);
|
||||
|
||||
[[eosio::action]]
|
||||
void claimnow(name coopname, name application, name username, checksum256 result_hash, document statement);
|
||||
void pushrslt(name coopname, name application, checksum256 result_hash, document statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void capauthclaim(eosio::name coopname, uint64_t claim_id, document decision);
|
||||
void authrslt(eosio::name coopname, checksum256 result_hash, document decision);
|
||||
|
||||
[[eosio::action]]
|
||||
void approveclaim(eosio::name coopname, eosio::name application, eosio::name approver, eosio::name username, checksum256 result_hash, document approved_statement);
|
||||
void approverslt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 result_hash, document approved_statement);
|
||||
|
||||
// конвертация
|
||||
[[eosio::action]]
|
||||
@@ -101,28 +98,54 @@ public:
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 result_hash,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 convert_hash,
|
||||
document 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_statement);
|
||||
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 contribution_statement);
|
||||
void approvecmmt(eosio::name coopname, checksum256 commit_hash, document 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, document statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void approvedebt(eosio::name coopname, checksum256 debt_hash, document approved_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void debtauthcnfr(eosio::name coopname, checksum256 debt_hash, document 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, document act);
|
||||
[[eosio::action]]
|
||||
void setact2(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document act);
|
||||
[[eosio::action]]
|
||||
void capauthcmmt(eosio::name coopname, uint64_t commit_id, document authorization);
|
||||
|
||||
// Регистрация
|
||||
[[eosio::action]]
|
||||
@@ -137,30 +160,34 @@ public:
|
||||
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);
|
||||
void capauthinvst(eosio::name coopname, checksum256 invest_hash, document authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document approved_statement);
|
||||
|
||||
[[eosio::action]]
|
||||
void allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount);
|
||||
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 result_hash, eosio::asset amount);
|
||||
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, document 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);
|
||||
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, 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 capauthexpns(eosio::name coopname, checksum256 expense_hash, document authorization);
|
||||
|
||||
[[eosio::action]]
|
||||
void exppaycnfrm(eosio::name coopname, checksum256 expense_hash);
|
||||
|
||||
|
||||
// Членские взносы
|
||||
[[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);
|
||||
@@ -191,14 +218,14 @@ 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<project> get_master_project(eosio::name coopname);
|
||||
@@ -208,14 +235,17 @@ private:
|
||||
|
||||
int64_t get_capital_user_share_balance(eosio::name coopname, eosio::name username);
|
||||
|
||||
std::optional<claim> get_claim(eosio::name coopname, const checksum256 &result_hash, 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<result_author> get_result_author(eosio::name coopname, eosio::name username, const checksum256 &result_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);
|
||||
|
||||
@@ -231,17 +261,13 @@ private:
|
||||
|
||||
int64_t get_capital_program_share_balance(eosio::name coopname);
|
||||
|
||||
std::optional<capital_tables::program_withdraw> get_program_withdraw(eosio::name coopname, const checksum256 &hash);
|
||||
|
||||
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);
|
||||
|
||||
resactor get_resactor_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg);
|
||||
std::optional<resactor> get_resactor(eosio::name coopname, const checksum256 &result_hash, eosio::name username);
|
||||
claim get_claim_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg);
|
||||
result get_result_or_fail(eosio::name coopname, const checksum256 &result_hash, const char* msg);
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
@@ -6,50 +6,53 @@
|
||||
using namespace eosio;
|
||||
|
||||
struct bonus_result {
|
||||
int64_t creators_bonus;
|
||||
int64_t authors_bonus;
|
||||
int64_t generated;
|
||||
int64_t capitalists_bonus;
|
||||
int64_t total;
|
||||
asset author_base;
|
||||
asset creator_base;
|
||||
asset creators_bonus;
|
||||
asset authors_bonus;
|
||||
asset generated;
|
||||
asset capitalists_bonus;
|
||||
asset total;
|
||||
};
|
||||
|
||||
// resactors.hpp (или в capital.hpp)
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] resactor {
|
||||
// creauthors.hpp (или в capital.hpp)
|
||||
struct [[eosio::table, eosio::contract(CAPITAL)]] creauthor {
|
||||
uint64_t id;
|
||||
checksum256 project_hash; // С каким результатом связана запись
|
||||
checksum256 result_hash; // С каким результатом связана запись
|
||||
eosio::name username; // Чей это учёт
|
||||
|
||||
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);
|
||||
eosio::asset spend = asset(0, _root_govern_symbol);
|
||||
|
||||
// Сколько пользователь имеет «авторских долей» в этом результате
|
||||
uint64_t authors_shares = 0;
|
||||
uint64_t author_shares = 0;
|
||||
|
||||
// Сколько пользователь имеет «создательских долей» в creators_bonus
|
||||
uint64_t creators_bonus_shares = 0;
|
||||
uint64_t creator_bonus_shares = 0;
|
||||
|
||||
// Сколько часов вложено в результат
|
||||
// Сколько часов вложено в задание
|
||||
uint64_t contributed_hours = 0;
|
||||
|
||||
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; } ///< Индекс по хэшу проекта
|
||||
|
||||
// Индекс по (result_hash + username)
|
||||
// Индекс по (assignment_hash + username)
|
||||
uint128_t by_resuser() const {
|
||||
return combine_checksum_ids(result_hash, username);
|
||||
return combine_checksum_ids(assignment_hash, username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"resactors"_n, resactor,
|
||||
indexed_by<"byproject"_n, const_mem_fun<resactor, checksum256, &resactor::by_project_hash>>,
|
||||
indexed_by<"byresult"_n, const_mem_fun<resactor, checksum256, &resactor::by_result_hash>>,
|
||||
indexed_by<"byresuser"_n, const_mem_fun<resactor, uint128_t, &resactor::by_resuser>>
|
||||
> resactor_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;
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +64,7 @@ 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; ///< Сумма расхода.
|
||||
@@ -71,12 +74,12 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
|
||||
document approved_statement; ///< принятая записка председателем или доверенным
|
||||
document 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; } ///< Индекс по хэшу проекта.
|
||||
|
||||
};
|
||||
@@ -85,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;
|
||||
|
||||
@@ -101,22 +104,24 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] commit {
|
||||
name username; ///< Имя пользователя, совершившего действие.
|
||||
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; ///< Сумма затрат, связанная с действием.
|
||||
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); ///< Суммарная стоимость коммита на будущем приёме задания с учетом капитализации и генерации
|
||||
|
||||
document contribution_statement; ///< Техническое задание (спецификация) как приложение к договору УХД
|
||||
document approved_statement; ///< Одобрение председателя или доверенного лица
|
||||
document authorization; ///< Решение совета
|
||||
document act1; ///< акт приема-передачи (1)
|
||||
document act2; ///< акт приема-передачи (2)
|
||||
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; } ///< Индекс по хэшу проекта.
|
||||
};
|
||||
|
||||
@@ -124,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;
|
||||
|
||||
@@ -183,12 +188,13 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] contributor {
|
||||
|
||||
eosio::asset rate_per_hour = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset spend = asset(0, _root_govern_symbol);
|
||||
eosio::asset spended = asset(0, _root_govern_symbol);
|
||||
eosio::asset debt_amount = 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 claimed = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset share_balance = asset(0, _root_govern_symbol); ///< Баланс долей пайщика
|
||||
eosio::asset pending_rewards = asset(0, _root_govern_symbol); ///< Накопленные награды
|
||||
@@ -227,19 +233,27 @@ 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);
|
||||
eosio::asset converted = asset(0, _root_govern_symbol);
|
||||
eosio::asset claimed = 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;
|
||||
|
||||
@@ -261,59 +275,62 @@ 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
|
||||
|
||||
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 total_creators_bonus_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 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 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 withdrawed = asset(0, _root_govern_symbol); ///< фактически возвращенные средства из результата
|
||||
eosio::asset creators_base = asset(0, _root_govern_symbol); ///< себестоимость РИД
|
||||
|
||||
eosio::asset creators_amount = asset(0, _root_govern_symbol); ///< себестоимость РИД
|
||||
eosio::asset generated_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 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_amount = asset(0, _root_govern_symbol); ///< Капитализация РИД (стоимость РИД в generated_amount + capitalists_bonus)
|
||||
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_amount_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); ///< сумма остатка для выплаты пайщикам
|
||||
|
||||
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 project_hash;
|
||||
checksum256 assignment_hash;
|
||||
checksum256 result_hash;
|
||||
|
||||
eosio::name coopname;
|
||||
@@ -323,39 +340,50 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] claim {
|
||||
eosio::name status = "created"_n; ///< created | statement | decision | act1 | act2 | completed
|
||||
time_point_sec created_at = current_time_point();
|
||||
|
||||
eosio::asset author_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset creator_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset capitalist_amount = asset(0, _root_govern_symbol);
|
||||
|
||||
eosio::asset creator_base_amount = asset(0, _root_govern_symbol);
|
||||
eosio::asset debt_amount = asset(0, _root_govern_symbol);
|
||||
|
||||
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);
|
||||
|
||||
document claim_statement; ///< Заявление
|
||||
document result_statement; ///< Заявление
|
||||
document approved_statement; ///< Принятое заявление
|
||||
document authorization; ///< Решение
|
||||
document authorization; ///< Решение совета
|
||||
document act1; ///< Акт1
|
||||
document act2; ///< Акт2
|
||||
|
||||
uint64_t primary_key() const { return id; } ///< Основной ключ.
|
||||
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
|
||||
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу
|
||||
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_result_user() const {
|
||||
return combine_checksum_ids(result_hash, username);
|
||||
uint128_t by_assignment_user() const {
|
||||
return combine_checksum_ids(assignment_hash, username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"claims"_n, claim,
|
||||
indexed_by<"byusername"_n, const_mem_fun<claim, uint64_t, &claim::by_username>>,
|
||||
indexed_by<"byresult"_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 result_hash;
|
||||
checksum256 assignment_hash;
|
||||
checksum256 convert_hash;
|
||||
|
||||
eosio::name coopname;
|
||||
@@ -372,18 +400,18 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] convert {
|
||||
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_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_user() const {
|
||||
return combine_checksum_ids(result_hash, username);
|
||||
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<"byresult"_n, const_mem_fun<convert, checksum256, &convert::by_result_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;
|
||||
|
||||
@@ -410,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;
|
||||
|
||||
/**
|
||||
@@ -513,7 +513,7 @@ namespace capital_tables {
|
||||
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 | )
|
||||
@@ -539,7 +539,7 @@ namespace capital_tables {
|
||||
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 {
|
||||
|
||||
@@ -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,25 +0,0 @@
|
||||
void capital::approveclaim(eosio::name coopname, eosio::name application, eosio::name approver, eosio::name username, checksum256 result_hash, document approved_statement){
|
||||
check_auth_or_fail(_capital, coopname, application, "approveclaim"_n);
|
||||
|
||||
verify_document_or_fail(approved_statement);
|
||||
|
||||
auto exist_claim = get_claim(coopname, result_hash, username);
|
||||
eosio::check(exist_claim.has_value(), "Клайм пользователя для результата не существует");
|
||||
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
|
||||
claim_index claims(_capital, coopname.value);
|
||||
auto claim = claims.find(exist_claim -> id);
|
||||
|
||||
claims.modify(claim, coopname, [&](auto &a) {
|
||||
a.status = "approved"_n;
|
||||
a.approved_statement = approved_statement;
|
||||
});
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(coopname, claim -> username, _capital, _capital_claim_authorize_action, claim -> id, claim -> claim_statement, std::string("")))
|
||||
.send();
|
||||
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
void capital::capauthclaim(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, "Неверный статус");
|
||||
|
||||
auto exist = get_project(coopname, claim -> project_hash);
|
||||
eosio::check(exist.has_value(),"Проект не найден");
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist -> id);
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, claim -> project_hash, claim -> username);
|
||||
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor_for_modify = contributors.find(contributor -> id);
|
||||
|
||||
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
|
||||
c.claimed += claim -> total_amount;
|
||||
c.share_balance += claim -> total_amount;
|
||||
});
|
||||
|
||||
projects.modify(project, coopname, [&](auto &p) {
|
||||
p.claimed += claim -> total_amount;
|
||||
p.total_share_balance += claim -> total_amount;
|
||||
});
|
||||
|
||||
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(claim_id);
|
||||
|
||||
//Увеличиваем баланс средств в капитализации
|
||||
Wallet::add_blocked_funds(_capital, coopname, claim -> username, claim -> total_amount, _capital_program, memo);
|
||||
|
||||
//Удаляем объект claim за ненадобностью
|
||||
claims.erase(claim);
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
void capital::claimnow(name coopname, name application, name username, checksum256 result_hash, document statement) {
|
||||
check_auth_or_fail(_capital, coopname, application, "claimnow"_n);
|
||||
|
||||
// проверяем заявление
|
||||
verify_document_or_fail(statement);
|
||||
|
||||
// извлекаем клайм
|
||||
auto claim = get_claim(coopname, result_hash, username);
|
||||
eosio::check(claim.has_value(), "Объект запроса доли не найден");
|
||||
eosio::check(claim->status == "pending"_n, "Нельзя изменить статус клайма");
|
||||
eosio::check(claim -> username == username, "Неверно указано имя пользователя владельца результата");
|
||||
|
||||
// обновляем клайм, добавляя заявление
|
||||
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.claim_statement = statement;
|
||||
});
|
||||
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
void capital::createclaim(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 result_hash
|
||||
) {
|
||||
// Авторизация
|
||||
check_auth_or_fail(_capital, coopname, application, "createclaim"_n);
|
||||
|
||||
// Получаем результат (или кидаем ошибку)
|
||||
auto exist_result = get_result_or_fail(coopname, result_hash, "Результат не найден");
|
||||
eosio::check(exist_result.status == "opened"_n, "Распределение стоимости результата еще не начато или уже завершено");
|
||||
|
||||
// Проверяем, нет ли уже такого клайма
|
||||
auto existing_claim = get_claim(coopname, result_hash, username);
|
||||
eosio::check(!existing_claim.has_value(), "Клайм уже существует");
|
||||
|
||||
// Находим запись в таблице results
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result.id);
|
||||
|
||||
// Получаем контрибьютора
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, username);
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor->id);
|
||||
|
||||
// Попробуем найти resactor
|
||||
auto optional_resactor = get_resactor(coopname, result_hash, username);
|
||||
|
||||
//=== (A) Авторская часть ===
|
||||
uint64_t author_amount = 0;
|
||||
{
|
||||
|
||||
// Если resactor есть, считаем долю.
|
||||
if (optional_resactor.has_value()) {
|
||||
auto resactor = *optional_resactor;
|
||||
|
||||
// Исходная сумма (просто authors_bonus.amount)
|
||||
uint64_t authors_total = result -> authors_bonus.amount;
|
||||
// Доля пользователя
|
||||
uint64_t user_auth_shares = resactor.authors_shares;
|
||||
// Всего долей авторов
|
||||
uint64_t total_auth_shares = result -> authors_shares;
|
||||
|
||||
if (authors_total > 0 && total_auth_shares > 0 && user_auth_shares > 0) {
|
||||
uint128_t tmp = (uint128_t)authors_total * (uint128_t)user_auth_shares;
|
||||
author_amount = (uint64_t)(tmp / (uint128_t)total_auth_shares);
|
||||
print(result->authors_bonus_remain.amount, ", ", author_amount);
|
||||
|
||||
eosio::check(result->authors_bonus_remain.amount >= author_amount,
|
||||
"Недостаточно средств для авторов");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=== (B) Создательская часть бонусов ===
|
||||
uint64_t creator_amount = 0;
|
||||
{
|
||||
if (optional_resactor.has_value()) {
|
||||
auto resactor = *optional_resactor;
|
||||
|
||||
uint64_t creators_bonus_total = result->creators_bonus.amount; // вся сумма создателей
|
||||
uint64_t user_creator_bonus_shares = resactor.creators_bonus_shares;
|
||||
uint64_t total_creators_bonus_shares= result->total_creators_bonus_shares;
|
||||
|
||||
if (creators_bonus_total > 0 && total_creators_bonus_shares > 0 && user_creator_bonus_shares > 0) {
|
||||
uint128_t tmp = (uint128_t)creators_bonus_total * (uint128_t)user_creator_bonus_shares;
|
||||
creator_amount = (uint64_t)(tmp / (uint128_t)total_creators_bonus_shares);
|
||||
|
||||
eosio::check(result->creators_bonus_remain.amount >= creator_amount, "Недостаточно средств для создателей");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=== (C) Капиталисты ===
|
||||
// здесь resactor НЕ обязателен, доли берём из глобальных методов
|
||||
uint64_t capitalist_amount = 0;
|
||||
{
|
||||
// Полная сумма для капиталистов
|
||||
uint64_t capitals_total = result->capitalists_bonus.amount;
|
||||
|
||||
// Пользовательские доли берем из кошелька программы
|
||||
uint64_t user_cap_shares = get_capital_user_share_balance(coopname, username);
|
||||
// Общее число долей капиталистов во всей программе
|
||||
uint64_t total_cap_shares = get_capital_program_share_balance(coopname);
|
||||
|
||||
if (capitals_total > 0 && total_cap_shares > 0 && user_cap_shares > 0) {
|
||||
uint128_t tmp = (uint128_t)capitals_total * (uint128_t)user_cap_shares;
|
||||
capitalist_amount = (uint64_t)(tmp / (uint128_t)total_cap_shares);
|
||||
|
||||
eosio::check(result->capitalists_bonus_remain.amount >= capitalist_amount,
|
||||
"Недостаточно средств для пайщиков");
|
||||
}
|
||||
}
|
||||
|
||||
//=== Складываем всё ===
|
||||
uint64_t total_claim_amount = author_amount + creator_amount + capitalist_amount;
|
||||
eosio::asset total_amount(total_claim_amount, _root_govern_symbol);
|
||||
|
||||
//=== Создаём запись в claims ===
|
||||
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.username = username;
|
||||
n.result_hash = result_hash;
|
||||
n.coopname = coopname;
|
||||
n.status = "created"_n;
|
||||
n.author_amount = asset(author_amount, _root_govern_symbol);
|
||||
n.creator_amount = asset(creator_amount, _root_govern_symbol);
|
||||
n.capitalist_amount = asset(capitalist_amount, _root_govern_symbol);
|
||||
n.total_amount = total_amount;
|
||||
});
|
||||
|
||||
//=== Уменьшаем остаток bonus_remain ===
|
||||
results.modify(result, coopname, [&](auto &r){
|
||||
// авторы
|
||||
if (author_amount > 0) {
|
||||
r.authors_bonus_remain -= eosio::asset(author_amount, _root_govern_symbol);
|
||||
}
|
||||
// создатели
|
||||
if (creator_amount > 0) {
|
||||
r.creators_bonus_remain -= eosio::asset(creator_amount, _root_govern_symbol);
|
||||
}
|
||||
// капиталисты
|
||||
if (capitalist_amount > 0) {
|
||||
r.capitalists_bonus_remain -= eosio::asset(capitalist_amount, _root_govern_symbol);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,27 +1,85 @@
|
||||
void capital::approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_statement){
|
||||
check_auth_or_fail(_capital, coopname, application, "approvecmmt"_n);
|
||||
|
||||
verify_document_or_fail(approved_statement);
|
||||
void capital::approvecmmt(eosio::name coopname, checksum256 commit_hash, document 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_statement = approved_statement;
|
||||
auto exist_assignment = get_assignment(coopname, commit -> assignment_hash);
|
||||
eosio::check(exist_assignment.has_value(), "Задание не найдено");
|
||||
|
||||
eosio::check(exist_assignment -> status == "opened"_n, "Нельзя добавить коммит в уже закрытое задание");
|
||||
|
||||
// Обновляем assignment
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment -> id);
|
||||
|
||||
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, commit -> project_hash);
|
||||
eosio::check(exist_project.has_value(),"Проект не найден");
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist_project -> id);
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(coopname, commit -> username, _capital, _capital_commit_authorize_action, commit -> id, commit -> contribution_statement, std::string("")))
|
||||
.send();
|
||||
|
||||
projects.modify(project, _capital, [&](auto &p) {
|
||||
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,16 +0,0 @@
|
||||
void capital::capauthcmmt(eosio::name coopname, uint64_t commit_id, document authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit = commits.find(commit_id);
|
||||
eosio::check(commit != commits.end(), "Коммит не найден");
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, commit->project_hash, commit->username);
|
||||
|
||||
//TODO: change to coopname
|
||||
commits.modify(commit, _soviet, [&](auto &n) {
|
||||
n.status = "authorized"_n;
|
||||
n.authorization = authorization;
|
||||
});
|
||||
|
||||
};
|
||||
@@ -1,35 +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 contribution_statement){
|
||||
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(contribution_statement);
|
||||
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.contribution_statement = contribution_statement;
|
||||
});
|
||||
|
||||
auto empty_doc = document{};
|
||||
|
||||
//отправить на 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);
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/**
|
||||
* @brief Принятие второго акта (act2). Убираем любой CRPS, просто плюсуем бонусы.
|
||||
*/
|
||||
void capital::setact2(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 commit_hash,
|
||||
document act
|
||||
) {
|
||||
check_auth_or_fail(_capital, coopname, application, "setact2"_n);
|
||||
verify_document_or_fail(act);
|
||||
|
||||
// Ищем коммит
|
||||
auto exist_commit = get_commit(coopname, commit_hash);
|
||||
eosio::check(exist_commit.has_value(), "Коммит не найден");
|
||||
|
||||
eosio::check(exist_commit -> username == username, "Неверно указано имя пользователя владельца результата");
|
||||
eosio::check(exist_commit -> status == "act1"_n, "Неверный статус для поставки акта");
|
||||
|
||||
// Обновляем коммит
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit = commits.find(exist_commit->id);
|
||||
commits.modify(commit, coopname, [&](auto &c) {
|
||||
c.status = "act2"_n;
|
||||
c.act2 = act;
|
||||
});
|
||||
|
||||
// Ищем результат и проект
|
||||
auto exist_result = get_result_or_fail(coopname, commit->result_hash, "Результат не найден");
|
||||
auto exist_project = get_project(coopname, exist_result.project_hash);
|
||||
eosio::check(exist_project.has_value(), "Проект не найден");
|
||||
|
||||
// Ищем вкладчика
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, commit->username);
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor->id);
|
||||
|
||||
// Распределяем spend на available / for_convert
|
||||
// convert_percent — целое число от 0 до HUNDR_PERCENTS
|
||||
int64_t for_convert_amount = (commit->spend.amount * contributor->convert_percent) / HUNDR_PERCENTS;
|
||||
eosio::asset for_convert(for_convert_amount, commit->spend.symbol);
|
||||
eosio::asset available = commit->spend - for_convert;
|
||||
|
||||
// Вычисляем bonus
|
||||
auto br = capital::calculcate_capital_amounts(commit->spend.amount);
|
||||
|
||||
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 capitalists_bonus (br.capitalists_bonus, commit->spend.symbol);
|
||||
eosio::asset total (br.total, commit->spend.symbol);
|
||||
|
||||
// Обновляем result
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result.id);
|
||||
eosio::check(result->available >= commit->spend, "Недостаточно средств в результате для приёма коммита");
|
||||
|
||||
results.modify(result, coopname, [&](auto &row) {
|
||||
row.available -= commit->spend;
|
||||
row.spend += commit->spend;
|
||||
row.creators_amount += commit->spend;
|
||||
row.total_creators_bonus_shares += commit->spend.amount;
|
||||
row.creators_bonus += creators_bonus;
|
||||
row.authors_bonus += authors_bonus;
|
||||
row.generated_amount += generated;
|
||||
row.capitalists_bonus += capitalists_bonus;
|
||||
row.total_amount += total;
|
||||
row.commits_count++;
|
||||
});
|
||||
|
||||
// Обновляем проект
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist_project->id);
|
||||
|
||||
// Обновляем актора и проект
|
||||
contributors.modify(contributor, coopname, [&](auto &c){
|
||||
c.spend += commit->spend;
|
||||
c.share_balance += commit->spend;
|
||||
c.contributed_hours += commit->contributed_hours;
|
||||
});
|
||||
|
||||
projects.modify(project, coopname, [&](auto &p) {
|
||||
p.generated += generated;
|
||||
p.spend += commit->spend;
|
||||
p.available += commit->spend;
|
||||
p.total_share_balance += commit->spend;
|
||||
});
|
||||
|
||||
// Обновляем запись в resactors (создательские доли)
|
||||
auto exist_resactor = get_resactor(coopname, commit->result_hash, commit->username);
|
||||
resactor_index ractors(_capital, coopname.value);
|
||||
|
||||
if (!exist_resactor.has_value()) {
|
||||
|
||||
ractors.emplace(coopname, [&](auto &ra){
|
||||
ra.id = ractors.available_primary_key();
|
||||
ra.project_hash = commit->project_hash;
|
||||
ra.result_hash = commit->result_hash;
|
||||
ra.username = commit->username;
|
||||
ra.creators_bonus_shares = commit->spend.amount;
|
||||
ra.spend = commit->spend;
|
||||
ra.for_convert = for_convert;
|
||||
ra.available = available;
|
||||
ra.contributed_hours = commit->contributed_hours;
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
auto resactor = ractors.find(exist_resactor->id);
|
||||
ractors.modify(resactor, coopname, [&](auto &ra) {
|
||||
ra.creators_bonus_shares += commit -> spend.amount;
|
||||
ra.for_convert += for_convert;
|
||||
ra.available += available;
|
||||
ra.spend += commit->spend;
|
||||
ra.contributed_hours += commit->contributed_hours;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// 10) Добавляем заблокированные средства на договор УХД
|
||||
std::string memo = "Приём паевого взноса по договору УХД с contributor_id: " + std::to_string(contributor->id);
|
||||
Wallet::add_blocked_funds(_capital, coopname, contributor->username, commit->spend, _source_program, memo);
|
||||
}
|
||||
@@ -4,13 +4,13 @@ void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio:
|
||||
verify_document_or_fail(approved_statement);
|
||||
|
||||
auto exist_convert = get_convert(coopname, convert_hash);
|
||||
eosio::check(exist_convert.has_value(), "Конвертация пользователя для результата не найдена");
|
||||
eosio::check(exist_convert.has_value(), "Конвертация пользователя для задананиеа не найдена");
|
||||
convert_index converts(_capital, coopname.value);
|
||||
|
||||
auto convert = converts.find(exist_convert -> id);
|
||||
|
||||
auto result = get_result(coopname, convert -> result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
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);
|
||||
@@ -36,7 +36,7 @@ void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio:
|
||||
|
||||
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Капитализация' с ID: " + std::to_string(convert -> id);
|
||||
|
||||
//Списываем баланс средств с УХД только при наличии convert_amount в claim
|
||||
//Списываем баланс средств с УХД только при наличии convert_amount в result
|
||||
Wallet::sub_blocked_funds(_capital, coopname, convert -> username, convert -> convert_amount, _source_program, memo);
|
||||
|
||||
//Увеличиваем баланс средств в капитализации
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void capital::createcnvrt(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 result_hash,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 convert_hash,
|
||||
document convert_statement
|
||||
) {
|
||||
// Авторизация
|
||||
check_auth_or_fail(_capital, coopname, application, "createcnvrt"_n);
|
||||
require_auth(coopname);
|
||||
|
||||
// Получаем результат (или кидаем ошибку)
|
||||
auto exist_result = get_result_or_fail(coopname, result_hash, "Результат не найден");
|
||||
eosio::check(exist_result.status == "opened"_n || exist_result.status == "created"_n, "Распределение стоимости результата еще не начато или уже завершено");
|
||||
// Получаем задание (или кидаем ошибку)
|
||||
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(), "Объект конвертации с указанным хэшем уже существует");
|
||||
|
||||
// Находим запись в таблице results
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result.id);
|
||||
// Находим запись в таблице assignments
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment = assignments.find(exist_assignment.id);
|
||||
|
||||
// Получаем контрибьютора
|
||||
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, username);
|
||||
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);
|
||||
|
||||
// Попробуем найти resactor
|
||||
auto exist_resactor = get_resactor_or_fail(coopname, result_hash, username, "Объект актора в результате не найден");
|
||||
// Находим creauthor
|
||||
auto exist_creauthor = get_creauthor_or_fail(coopname, assignment_hash, username, "Объект актора в результате не найден");
|
||||
|
||||
//=== Сумма к конвертации ===
|
||||
asset convert_amount = exist_resactor.available + exist_resactor.for_convert;
|
||||
asset convert_amount = exist_creauthor.available + exist_creauthor.for_convert;
|
||||
eosio::check(convert_amount.amount > 0, "Нет доступных средств для конвертации");
|
||||
|
||||
//=== Создаём запись в converts ===
|
||||
@@ -40,8 +44,8 @@ void capital::createcnvrt(
|
||||
converts.emplace(coopname, [&](auto &n) {
|
||||
n.id = convert_id;
|
||||
n.username = username;
|
||||
n.project_hash = exist_result.project_hash;
|
||||
n.result_hash = result_hash;
|
||||
n.project_hash = exist_assignment.project_hash;
|
||||
n.assignment_hash = assignment_hash;
|
||||
n.convert_hash = convert_hash;
|
||||
n.coopname = coopname;
|
||||
n.status = "created"_n;
|
||||
@@ -49,18 +53,18 @@ void capital::createcnvrt(
|
||||
n.convert_statement = convert_statement;
|
||||
});
|
||||
|
||||
eosio::check(result -> creators_amount_remain >= convert_amount, "Недостаточно средств в result.creators_amount_remain для конвертации");
|
||||
eosio::check(assignment -> creators_base_remain >= convert_amount, "Недостаточно средств в assignment.creators_base_remain для конвертации");
|
||||
|
||||
results.modify(result, coopname, [&](auto &r) {
|
||||
r.creators_amount_remain -= convert_amount;
|
||||
assignments.modify(assignment, coopname, [&](auto &r) {
|
||||
r.creators_base_remain -= convert_amount;
|
||||
});
|
||||
|
||||
resactor_index ractors(_capital, coopname.value);
|
||||
creauthor_index creathors(_capital, coopname.value);
|
||||
|
||||
auto resactor = ractors.find(exist_resactor.id);
|
||||
auto creauthor = creathors.find(exist_creauthor.id);
|
||||
|
||||
//обнуляем доступные средства к выводу или конвертации
|
||||
ractors.modify(resactor, coopname, [&](auto &ra) {
|
||||
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, document 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, document 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, document 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){
|
||||
|
||||
}
|
||||
@@ -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 -> 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, document 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 -> 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, document 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,12 +25,12 @@ 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.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: здесь должна быть проводка по фонду
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,18 @@ void capital::approveinvst(name coopname, name application, name approver, check
|
||||
});
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, _capital_invest_authorize_action,
|
||||
std::make_tuple(coopname, invest -> username, invest -> id, invest -> invest_statement, std::string("")))
|
||||
.send();
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
invest -> username,
|
||||
get_valid_soviet_action("capitalinvst"_n),
|
||||
invest -> invest_hash,
|
||||
_capital,
|
||||
"capauthinvst"_n,
|
||||
"capdeclinvst"_n,
|
||||
invest -> invest_statement,
|
||||
std::string("")
|
||||
)
|
||||
).send();
|
||||
|
||||
};
|
||||
@@ -2,14 +2,15 @@
|
||||
* @brief Принимаем решение совета и вносим средства на кошелек пайщика при УХД
|
||||
*
|
||||
*/
|
||||
void capital::capauthinvst(eosio::name coopname, uint64_t invest_id, document authorization) {
|
||||
void capital::capauthinvst(eosio::name coopname, checksum256 invest_hash, document authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
|
||||
auto exist_invest = get_invest(coopname, invest_hash);
|
||||
eosio::check(exist_invest.has_value(), "Инвестиция не найдена");
|
||||
|
||||
invest_index invests(_capital, coopname.value);
|
||||
auto invest = invests.find(invest_id);
|
||||
|
||||
eosio::check(invest != invests.end(), "Инвестиция не найдена");
|
||||
|
||||
auto invest = invests.find(exist_invest -> id);
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, invest -> project_hash, invest -> username);
|
||||
eosio::check(contributor.has_value(), "Договор УХД с пайщиком по проекту не найден");
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
void capital::capdeclinvst(){
|
||||
//TODO:
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
void capital::allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount) {
|
||||
void capital::allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount) {
|
||||
check_auth_or_fail(_capital, coopname, application, "allocate"_n);
|
||||
|
||||
Wallet::validate_asset(amount);
|
||||
@@ -6,9 +6,9 @@ void capital::allocate(eosio::name coopname, eosio::name application, checksum25
|
||||
auto project = get_project(coopname, project_hash);
|
||||
eosio::check(project.has_value(), "Проект с указанным хэшем не найден");
|
||||
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Объект результата не найден");
|
||||
eosio::check(project -> available >= amount, "Недостаточно средств в проекте для аллокации в результат");
|
||||
auto assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Объект задананиеа не найден");
|
||||
eosio::check(project -> available >= amount, "Недостаточно средств в проекте для аллокации в задание");
|
||||
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project_for_modify = projects.find(project -> id);
|
||||
@@ -18,10 +18,10 @@ void capital::allocate(eosio::name coopname, eosio::name application, checksum25
|
||||
row.allocated += amount;
|
||||
});
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_for_modify = results.find(result -> id);
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment_for_modify = assignments.find(assignment -> id);
|
||||
|
||||
results.modify(result_for_modify, coopname, [&](auto& row) {
|
||||
assignments.modify(assignment_for_modify, coopname, [&](auto& row) {
|
||||
row.allocated += amount;
|
||||
row.available += amount;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
void capital::diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount) {
|
||||
void capital::diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount) {
|
||||
check_auth_or_fail(_capital, coopname, application, "diallocate"_n);
|
||||
|
||||
Wallet::validate_asset(amount);
|
||||
@@ -6,14 +6,14 @@ void capital::diallocate(eosio::name coopname, eosio::name application, checksum
|
||||
auto project = get_project(coopname, project_hash);
|
||||
eosio::check(project.has_value(), "Проект с указанным хэшем не найден");
|
||||
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Объект результата не найден");
|
||||
eosio::check(result -> available >= amount, "Недостаточно средств в результате для возврата в проект");
|
||||
auto assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Объект задананиеа не найден");
|
||||
eosio::check(assignment -> available >= amount, "Недостаточно средств в задананиее для возврата в проект");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_for_modify = results.find(result -> id);
|
||||
assignment_index assignments(_capital, coopname.value);
|
||||
auto assignment_for_modify = assignments.find(assignment -> id);
|
||||
|
||||
results.modify(result_for_modify, coopname, [&](auto& row) {
|
||||
assignments.modify(assignment_for_modify, coopname, [&](auto& row) {
|
||||
row.available -= amount;
|
||||
row.allocated -= amount;
|
||||
});
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
void capital::wthdrcallbck(eosio::name coopname, eosio::name callback_type, checksum256 withdraw_hash) {
|
||||
auto payer = check_auth_and_get_payer_or_fail({ _gateway });
|
||||
|
||||
// Обработка на основе типа callback_type
|
||||
switch(callback_type.value) {
|
||||
case "expense"_n.value: {
|
||||
// Логика для типа "expense"
|
||||
capital::expense_withdraw_callback(coopname, withdraw_hash);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Обработка для неизвестных типов
|
||||
eosio::check(false, "Неизвестный тип коллбэка при обработке платежа");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
1. Создаём результат createresult
|
||||
|
||||
2. Добавляем создателя addcreator
|
||||
|
||||
3.
|
||||
@@ -0,0 +1,37 @@
|
||||
void capital::approverslt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 result_hash, document approved_statement){
|
||||
require_auth(coopname);
|
||||
|
||||
verify_document_or_fail(approved_statement);
|
||||
|
||||
auto exist_result = get_result(coopname, result_hash);
|
||||
eosio::check(exist_result.has_value(), "Клайм пользователя для задания не существует");
|
||||
|
||||
auto assignment = get_assignment(coopname, exist_result -> assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Задание не найдено");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result -> id);
|
||||
|
||||
results.modify(result, coopname, [&](auto &a) {
|
||||
a.status = "approved"_n;
|
||||
a.approved_statement = approved_statement;
|
||||
});
|
||||
|
||||
//отправляем в совет
|
||||
Action::send<createagenda_interface>(
|
||||
_soviet,
|
||||
"createagenda"_n,
|
||||
_capital,
|
||||
coopname,
|
||||
result -> username,
|
||||
get_valid_soviet_action("createresult"_n),
|
||||
result -> result_hash,
|
||||
_capital,
|
||||
"authrslt"_n,
|
||||
"declrslt"_n,
|
||||
result -> result_statement,
|
||||
std::string("")
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
void capital::authrslt(eosio::name coopname, checksum256 result_hash, document decision) {
|
||||
require_auth(_soviet);
|
||||
|
||||
auto exist_result = get_result(coopname, result_hash);
|
||||
eosio::check(exist_result.has_value(), "Объект результата не найден");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result -> id);
|
||||
|
||||
// Проверяем статус
|
||||
eosio::check(result -> status == "statement"_n, "Неверный статус");
|
||||
|
||||
results.modify(result, _capital, [&](auto &r){
|
||||
r.status = "authorized"_n;
|
||||
r.authorization = decision;
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
void capital::createresult(name coopname, name application, checksum256 project_hash, checksum256 result_hash) {
|
||||
check_auth_or_fail(_capital, coopname, application, "generate"_n);
|
||||
|
||||
auto project = get_project(coopname, project_hash);
|
||||
eosio::check(project.has_value(), "проект не найден");
|
||||
|
||||
// Проверяем, существует ли уже RESULT
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(!result.has_value(), "Объект результата уже существует");
|
||||
|
||||
// Создаём RESULT
|
||||
results.emplace(coopname, [&](auto &n){
|
||||
n.id = get_global_id_in_scope(_capital, coopname, "results"_n);
|
||||
n.coopname = coopname;
|
||||
n.project_hash = project_hash;
|
||||
n.result_hash = result_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;
|
||||
|
||||
resactor_index ractors(_capital, coopname.value);
|
||||
|
||||
// Копируем запись автора идеи в result_authors
|
||||
while(author_itr != authors_hash_index.end() && author_itr->project_hash == project_hash) {
|
||||
ractors.emplace(coopname, [&](auto &ra){
|
||||
ra.id = ractors.available_primary_key();
|
||||
ra.result_hash = result_hash;
|
||||
ra.project_hash = project_hash;
|
||||
ra.username = author_itr->username;
|
||||
ra.authors_shares = author_itr -> shares;
|
||||
});
|
||||
authors_count++;
|
||||
author_itr++;
|
||||
}
|
||||
|
||||
eosio::check(authors_count > 0, "Нельзя создать результат без установленных авторов в проекте");
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
declresult
|
||||
@@ -0,0 +1,20 @@
|
||||
void capital::pushrslt(name coopname, name application, checksum256 result_hash, document statement) {
|
||||
require_auth(coopname);
|
||||
|
||||
// проверяем заявление
|
||||
verify_document_or_fail(statement);
|
||||
|
||||
// извлекаем клайм
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Объект результата не найден");
|
||||
eosio::check(result -> status == "created"_n, "Неверный статус результата");
|
||||
|
||||
// обновляем клайм, добавляя заявление
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_for_modify = results.find(result->id);
|
||||
|
||||
results.modify(result_for_modify, coopname, [&](auto &c){
|
||||
c.status = "statement"_n;
|
||||
c.result_statement = statement;
|
||||
});
|
||||
}
|
||||
+7
-7
@@ -6,10 +6,10 @@ void capital::setact1(eosio::name coopname, eosio::name application, eosio::name
|
||||
// commits
|
||||
auto commit = get_commit(coopname, commit_hash);
|
||||
eosio::check(commit.has_value(), "Объект коммита не найден");
|
||||
eosio::check(commit -> username == username, "Неверно указано имя пользователя владельца результата");
|
||||
eosio::check(commit -> username == username, "Неверно указано имя пользователя владельца задананиеа");
|
||||
|
||||
auto result = get_result(coopname, commit -> result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
auto assignment = get_assignment(coopname, commit -> assignment_hash);
|
||||
eosio::check(assignment.has_value(), "Задание не найдено");
|
||||
|
||||
commit_index commits(_capital, coopname.value);
|
||||
auto commit_for_modify = commits.find(commit -> id);
|
||||
@@ -17,8 +17,8 @@ void capital::setact1(eosio::name coopname, eosio::name application, eosio::name
|
||||
// Проверяем статус.
|
||||
eosio::check(commit_for_modify -> status == "authorized"_n, "Неверный статус для поставки акта приёма-передачи");
|
||||
|
||||
commits.modify(commit_for_modify, coopname, [&](auto &n){
|
||||
n.status = "act1"_n;
|
||||
n.act1 = act;
|
||||
});
|
||||
// commits.modify(commit_for_modify, coopname, [&](auto &n){
|
||||
// n.status = "act1"_n;
|
||||
// n.act1 = act;
|
||||
// });
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @brief Принятие второго акта (act2). Убираем любой CRPS, просто плюсуем бонусы.
|
||||
*/
|
||||
void capital::setact2(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 result_hash,
|
||||
document act
|
||||
) {
|
||||
check_auth_or_fail(_capital, coopname, application, "setact2"_n);
|
||||
verify_document_or_fail(act);
|
||||
|
||||
auto exist_result = get_result(coopname, result_hash);
|
||||
eosio::check(exist_result.has_value(), "Объект результата не найден");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result = results.find(exist_result -> id);
|
||||
|
||||
// Проверяем статус
|
||||
eosio::check(result -> status == "act1"_n, "Неверный статус результата.");
|
||||
|
||||
results.modify(result, _capital, [&](auto &r){
|
||||
r.status = "act2"_n;
|
||||
r.act1 = act;
|
||||
});
|
||||
|
||||
auto exist = get_project(coopname, result -> project_hash);
|
||||
eosio::check(exist.has_value(),"Проект не найден");
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist -> id);
|
||||
|
||||
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, result -> username);
|
||||
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor_for_modify = contributors.find(contributor -> id);
|
||||
|
||||
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
|
||||
c.share_balance += result -> creator_base_amount;
|
||||
});
|
||||
|
||||
projects.modify(project, coopname, [&](auto &p) {
|
||||
p.total_share_balance += result -> creator_base_amount;
|
||||
});
|
||||
|
||||
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(result -> id);
|
||||
|
||||
//Увеличиваем баланс средств в капитализации
|
||||
//TODO:
|
||||
Wallet::add_blocked_funds(_capital, coopname, result -> username, result -> creator_base_amount, _source_program, memo);
|
||||
|
||||
//Удаляем объект result за ненадобностью
|
||||
//???
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
void capital::startdistrbn(name coopname, name application, checksum256 result_hash) {
|
||||
check_auth_or_fail(_capital, coopname, application, "start"_n);
|
||||
|
||||
auto result = get_result(coopname, result_hash);
|
||||
eosio::check(result.has_value(), "Результат не найден");
|
||||
eosio::check(result -> status == "created"_n, "Только результат в статусе created может быть запущен в распределение");
|
||||
|
||||
auto project = get_project(coopname, result -> project_hash);
|
||||
eosio::check(project.has_value(), "проект не найден");
|
||||
|
||||
result_index results(_capital, coopname.value);
|
||||
auto result_for_modify = results.find(result -> id);
|
||||
|
||||
results.modify(result_for_modify, coopname, [&](auto& row) {
|
||||
row.status = "opened"_n;
|
||||
row.authors_bonus_remain = row.authors_bonus;
|
||||
row.creators_amount_remain = row.creators_amount;
|
||||
row.creators_bonus_remain = row.creators_bonus;
|
||||
row.capitalists_bonus_remain = row.capitalists_bonus;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,170 @@
|
||||
void capital::updaterslt(
|
||||
eosio::name coopname,
|
||||
eosio::name application,
|
||||
eosio::name username,
|
||||
checksum256 assignment_hash,
|
||||
checksum256 result_hash
|
||||
) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Получаем задание (или кидаем ошибку)
|
||||
auto exist_assignment = get_assignment_or_fail(coopname, assignment_hash, "Задание не найдено");
|
||||
eosio::check(exist_assignment.status == "closed"_n, "Распределение стоимости задания еще не начато или уже завершено");
|
||||
|
||||
// Проверяем, нет ли уже такого клайма
|
||||
auto existing_result = get_result_by_assignment_and_username(coopname, assignment_hash, username);
|
||||
eosio::check(!existing_result.has_value(), "Клайм уже существует");
|
||||
|
||||
auto exist_result = get_result(coopname, result_hash);
|
||||
eosio::check(!exist_result.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 creauthor = get_creauthor(coopname, assignment_hash, username);
|
||||
|
||||
//=== (A) Авторская часть ===
|
||||
eosio::asset author_bonus = asset(0, _root_govern_symbol);
|
||||
{
|
||||
if (creauthor.has_value()) {
|
||||
|
||||
//общее количество авторских премий всех авторов
|
||||
uint64_t authors_total = assignment->authors_bonus.amount;
|
||||
|
||||
//количество долей автора в результате
|
||||
uint64_t user_auth_shares = creauthor -> author_shares;
|
||||
|
||||
//количество долей всех авторов в результате
|
||||
uint64_t total_auth_shares = assignment->authors_shares;
|
||||
|
||||
if (authors_total > 0 && total_auth_shares > 0 && user_auth_shares > 0) {
|
||||
|
||||
//считаем долю автора в авторских премиях задания
|
||||
uint128_t tmp = (uint128_t)authors_total * (uint128_t)user_auth_shares;
|
||||
author_bonus.amount = (uint64_t)(tmp / (uint128_t)total_auth_shares);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=== (B) Создательская часть ===
|
||||
// Себестоимость
|
||||
eosio::asset creator_base = asset(0, _root_govern_symbol);
|
||||
// Премии
|
||||
eosio::asset creator_bonus = asset(0, _root_govern_symbol);
|
||||
{
|
||||
if (creauthor.has_value()) {
|
||||
|
||||
//себестоимость потраченного времени создателем возвращаем как есть
|
||||
creator_base.amount = creauthor -> spended.amount;
|
||||
|
||||
//сколько премий создателей на распределении в результате
|
||||
uint64_t creators_bonus_total = assignment->creators_bonus.amount;
|
||||
|
||||
//количество долей премий создателя в результате
|
||||
uint64_t user_creator_bonus_shares = creauthor -> creator_bonus_shares;
|
||||
|
||||
//количество долей премий всех создателей в результате
|
||||
uint64_t total_creators_bonus_shares = assignment->total_creators_bonus_shares;
|
||||
|
||||
if (creators_bonus_total > 0 && total_creators_bonus_shares > 0 && user_creator_bonus_shares > 0) {
|
||||
uint128_t tmp = (uint128_t)creators_bonus_total * (uint128_t)user_creator_bonus_shares;
|
||||
//считаем премию автора в результате на основе его доли
|
||||
creator_bonus.amount = (uint64_t)(tmp / (uint128_t)total_creators_bonus_shares);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=== (C) Капиталисты ===
|
||||
eosio::asset capitalist_bonus = asset(0, _root_govern_symbol);
|
||||
{
|
||||
//сумма премий капиталистов на распределении
|
||||
uint64_t capitals_total = assignment->capitalists_bonus.amount;
|
||||
|
||||
//количество долей пользователя как капиталиста (участника ЦПП "Капитализация") в премиях капиталистов
|
||||
uint64_t user_capital_shares = get_capital_user_share_balance(coopname, username);
|
||||
|
||||
//общее количество долей капиталистов
|
||||
uint64_t total_capital_shares = get_capital_program_share_balance(coopname);
|
||||
|
||||
if (capitals_total > 0 && total_capital_shares > 0 && user_capital_shares > 0) {
|
||||
uint128_t tmp = (uint128_t)capitals_total * (uint128_t)user_capital_shares;
|
||||
//сумма премий пользователя как капиталиста
|
||||
capitalist_bonus.amount = (uint64_t)(tmp / (uint128_t)total_capital_shares);
|
||||
}
|
||||
}
|
||||
|
||||
//сумма долга пайщика
|
||||
eosio::asset debt_amount = asset(0, _root_govern_symbol);
|
||||
{
|
||||
if (creauthor.has_value()) {
|
||||
debt_amount = creauthor -> debt_amount;
|
||||
}
|
||||
}
|
||||
|
||||
//=== Создаём запись в results ===
|
||||
result_index results(_capital, coopname.value);
|
||||
uint64_t result_id = get_global_id_in_scope(_capital, coopname, "results"_n);
|
||||
|
||||
eosio::check(creator_base >= debt_amount, "Системная ошибка: долгов больше чем себестоимость взносов. Обратитесь в поддержку");
|
||||
|
||||
results.emplace(coopname, [&](auto &n) {
|
||||
n.id = result_id;
|
||||
n.username = username;
|
||||
n.assignment_hash = assignment_hash;
|
||||
n.result_hash = result_hash;
|
||||
n.coopname = coopname;
|
||||
n.status = "created"_n;
|
||||
//сумма себестоимости взноса создателя
|
||||
n.creator_base_amount = creator_base;
|
||||
//сумма долга, которая должна быть погашена отдельным заявлением, если она есть
|
||||
n.debt_amount = debt_amount;
|
||||
//доступные средства к возврату или конвертации после выплаты долга
|
||||
n.available_for_return = creator_base - debt_amount;
|
||||
//доступные средства к конвертации в "Капитализацию"
|
||||
n.available_for_convert = author_bonus + creator_bonus + capitalist_bonus;
|
||||
//разблюдовка по типам премий
|
||||
n.creator_bonus_amount = creator_bonus;
|
||||
n.author_bonus_amount = author_bonus;
|
||||
n.capitalist_bonus_amount = capitalist_bonus;// на эту премию пишем отдельное заявление на взнос
|
||||
//сумма генераций должна быть внесена отдельным заявлением на взнос, потому - суммируем.
|
||||
n.generation_amount = creator_base + author_bonus + creator_bonus;
|
||||
//total_amount - чисто информационный показатель, не используется в расчетах далее
|
||||
n.total_amount = creator_base + author_bonus + creator_bonus + capitalist_bonus;
|
||||
});
|
||||
|
||||
//проверяем что премий достаточно и ошибок в расчетах нигде нет.
|
||||
eosio::check(assignment -> authors_bonus_remain >= author_bonus, "Недостаточно средств для выплаты премии автора. Вероятно, техническая ошибка. Пожалуйста, обратитесь в поддержку.");
|
||||
eosio::check(assignment -> creators_bonus_remain >= creator_bonus, "Недостаточно средств для выплаты премий создателей. Обратитесь в поддержку.");
|
||||
eosio::check(assignment -> creators_base_remain >= creator_base, "Недостаточно средств для выплаты себестоимости взносов создателей. Обратитесь в поддержку.");
|
||||
eosio::check(assignment -> capitalists_bonus_remain >= capitalist_bonus, "Недостаточно средств для пайщиков");
|
||||
|
||||
//=== Уменьшаем остатки в результате ===
|
||||
assignments.modify(assignment, coopname, [&](auto &r) {
|
||||
if (author_bonus.amount > 0) {
|
||||
r.authors_bonus_remain -= author_bonus;
|
||||
}
|
||||
if (creator_bonus.amount > 0) {
|
||||
r.creators_bonus_remain -= creator_bonus;
|
||||
}
|
||||
if (creator_base.amount > 0) {
|
||||
r.creators_base_remain -= creator_base;
|
||||
}
|
||||
if (capitalist_bonus.amount > 0) {
|
||||
r.capitalists_bonus_remain -= capitalist_bonus;
|
||||
}
|
||||
|
||||
print("capitalists_bonus_remain: ", r.capitalists_bonus_remain.to_string());
|
||||
print("capitalist_bonus: ", capitalist_bonus.to_string());
|
||||
print("creators_bonus_remain: ", r.creators_bonus_remain.to_string());
|
||||
print("creator_bonus: ", creator_bonus.to_string());
|
||||
});
|
||||
|
||||
}
|
||||
@@ -16,7 +16,17 @@ void capital::approvewthd3(name coopname, name application, name approver, check
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(coopname, exist_withdraw -> username, _capital, _capital_withdraw_from_program_authorize_action, exist_withdraw -> id, exist_withdraw -> return_statement, std::string("")))
|
||||
.send();
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
exist_withdraw -> username,
|
||||
get_valid_soviet_action("capwthdrprog"_n),
|
||||
withdraw_hash,
|
||||
_capital,
|
||||
"capauthwthd3"_n,
|
||||
"capdeclwthd3"_n,
|
||||
exist_withdraw -> return_statement,
|
||||
std::string("")
|
||||
)
|
||||
).send();
|
||||
|
||||
};
|
||||
@@ -1,11 +1,15 @@
|
||||
void capital::capauthwthd3(name coopname, uint64_t withdraw_id, document authorization) {
|
||||
void capital::capauthwthd3(name coopname, checksum256 withdraw_hash, document authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
|
||||
auto exist_withdraw = get_program_withdraw(coopname, withdraw_hash);
|
||||
eosio::check(exist_withdraw.has_value(), "Объект возврата не найден");
|
||||
|
||||
capital_tables::program_withdraws_index program_withdraws(_capital, coopname.value);
|
||||
auto withdraw = program_withdraws.find(withdraw_id);
|
||||
auto withdraw = program_withdraws.find(exist_withdraw -> id);
|
||||
|
||||
eosio::check(withdraw != program_withdraws.end(), "Объект возврата не найден");
|
||||
|
||||
std::string memo = "Зачёт части целевого паевого взноса по программе 'Капитализация' в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(withdraw_id);
|
||||
std::string memo = "Зачёт части целевого паевого взноса по программе 'Капитализация' в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(withdraw -> id);
|
||||
|
||||
Wallet::sub_blocked_funds(_capital, coopname, withdraw->username, withdraw->amount, _capital_program, memo);
|
||||
Wallet::add_available_funds(_capital, coopname, withdraw->username, withdraw->amount, _wallet_program, memo);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
void capital::capdeclwthd3(name coopname, checksum256 withdraw_hash, std::string reason) {
|
||||
require_auth(_soviet);
|
||||
|
||||
//TODO: реализовать отмену
|
||||
}
|
||||
@@ -16,7 +16,17 @@ void capital::approvewthd2(name coopname, name application, name approver, check
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(coopname, exist_withdraw -> username, _capital, _capital_withdraw_from_project_authorize_action, exist_withdraw -> id, exist_withdraw -> return_statement, std::string("")))
|
||||
.send();
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
exist_withdraw -> username,
|
||||
get_valid_soviet_action("capwthdrproj"_n),
|
||||
withdraw_hash,
|
||||
_capital,
|
||||
"capauthwthd2"_n,
|
||||
"capdeclwthd2"_n,
|
||||
exist_withdraw -> return_statement,
|
||||
std::string("")
|
||||
)
|
||||
).send();
|
||||
|
||||
};
|
||||
@@ -1,10 +1,12 @@
|
||||
void capital::capauthwthd2(name coopname, uint64_t withdraw_id, document authorization) {
|
||||
void capital::capauthwthd2(name coopname, checksum256 withdraw_hash, document authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
|
||||
auto exist_withdraw = get_project_withdraw(coopname, withdraw_hash);
|
||||
eosio::check(exist_withdraw.has_value(), "Объект возврата не найден");
|
||||
|
||||
capital_tables::project_withdraws_index project_withdraws(_capital, coopname.value);
|
||||
auto withdraw = project_withdraws.find(withdraw_id);
|
||||
eosio::check(withdraw != project_withdraws.end(), "Объект возврата не найден");
|
||||
|
||||
auto withdraw = project_withdraws.find(exist_withdraw -> id);
|
||||
|
||||
std::string memo = "Зачёт части целевого паевого взноса по программе 'Капитализация' в качестве паевого взноса по участию в 'Цифровой Кошелёк'";
|
||||
|
||||
Wallet::sub_blocked_funds(_capital, coopname, withdraw->username, withdraw->amount, _capital_program, memo);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
capdeclwthd2
|
||||
@@ -42,7 +42,7 @@ void capital::createwthd2(name coopname, name application, name username, checks
|
||||
}
|
||||
|
||||
// Запись возврата
|
||||
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
|
||||
auto exist_withdraw = get_project_withdraw(coopname, withdraw_hash);
|
||||
eosio::check(!exist_withdraw.has_value(), "Заявка на взнос-возврат с таким хэшем уже существует");
|
||||
|
||||
capital_tables::project_withdraws_index project_withdraws(_capital, coopname.value);
|
||||
|
||||
@@ -16,7 +16,17 @@ void capital::approvewthd1(name coopname, name application, name approver, check
|
||||
|
||||
//отправляем в совет
|
||||
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
|
||||
std::make_tuple(coopname, withdraw -> username, _capital, _capital_withdraw_from_result_authorize_action, withdraw -> id, withdraw -> return_statement, std::string("")))
|
||||
.send();
|
||||
std::make_tuple(
|
||||
coopname,
|
||||
withdraw -> username,
|
||||
get_valid_soviet_action("capwthdrres"_n),
|
||||
withdraw_hash,
|
||||
_capital,
|
||||
"capauthwthd1"_n,
|
||||
"capdeclwthd1"_n,
|
||||
withdraw -> return_statement,
|
||||
std::string("")
|
||||
)
|
||||
).send();
|
||||
|
||||
};
|
||||
@@ -1,13 +1,15 @@
|
||||
void capital::capauthwthd1(eosio::name coopname, uint64_t withdraw_id, document authorization) {
|
||||
void capital::capauthwthd1(eosio::name coopname, checksum256 withdraw_hash, document authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
//Получаем объект возврата
|
||||
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
|
||||
eosio::check(exist_withdraw.has_value(), "Объект возврата не найден");
|
||||
|
||||
capital_tables::result_withdraws_index result_withdraws(_capital, coopname.value);
|
||||
auto withdraw = result_withdraws.find(withdraw_id);
|
||||
eosio::check(withdraw != result_withdraws.end(), "Объект взноса-возврата не найден");
|
||||
auto withdraw = result_withdraws.find(exist_withdraw -> id);
|
||||
|
||||
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, withdraw -> project_hash, withdraw -> username);
|
||||
auto exist_result = get_result_or_fail(coopname, withdraw -> result_hash, "Результат не найден");
|
||||
auto exist_assignment = get_assignment_or_fail(coopname, withdraw -> assignment_hash, "Задание не найдено");
|
||||
|
||||
// списание с УХД
|
||||
std::string memo_out = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(exist_contributor -> id) + " в качестве паевого взноса по программе 'Цифровой Кошелёк'";
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
//TODO:
|
||||
@@ -1,58 +1,46 @@
|
||||
void capital::createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, asset amount, document return_statement) {
|
||||
void capital::createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 withdraw_hash, asset amount, document return_statement) {
|
||||
check_auth_or_fail(_capital, coopname, application, "createwthd1"_n);
|
||||
|
||||
verify_document_or_fail(return_statement);
|
||||
|
||||
Wallet::validate_asset(amount);
|
||||
|
||||
auto exist_result = get_result(coopname, result_hash);
|
||||
eosio::check(exist_result.has_value(), "Результат с указанным хэшем не найден");
|
||||
auto exist_assignment = get_assignment(coopname, assignment_hash);
|
||||
eosio::check(exist_assignment.has_value(), "Задание с указанным хэшем не найден");
|
||||
|
||||
auto exist_project = get_project(coopname, exist_result -> project_hash);
|
||||
auto exist_project = get_project(coopname, exist_assignment -> project_hash);
|
||||
eosio::check(exist_project.has_value(), "Проект с указанным хэшем не найден");
|
||||
|
||||
//обновить сумму выводов по проекту
|
||||
project_index projects(_capital, coopname.value);
|
||||
auto project = projects.find(exist_project->id);
|
||||
eosio::check(project -> total_share_balance >= amount, "Недостаточно средств в project.total_share_balance проекта для осуществления возврата");
|
||||
|
||||
|
||||
projects.modify(project, _capital, [&](auto &p){
|
||||
p.withdrawed += amount;
|
||||
p.total_share_balance -= amount;
|
||||
});
|
||||
|
||||
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, exist_result -> project_hash, username);
|
||||
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, exist_assignment -> project_hash, username);
|
||||
contributor_index contributors(_capital, coopname.value);
|
||||
auto contributor = contributors.find(exist_contributor -> id);
|
||||
eosio::check(contributor -> share_balance >= amount, "Недостаточно средств в contributor.share_balance для осуществления возврата");
|
||||
|
||||
contributors.modify(contributor, coopname, [&](auto &c) {
|
||||
c.withdrawed += amount;
|
||||
c.share_balance -= amount;
|
||||
});
|
||||
|
||||
auto exist_resactor = get_resactor_or_fail(coopname, exist_result->result_hash, username, "Объект актора в результате не найден");
|
||||
auto exist_creauthor = get_creauthor_or_fail(coopname, exist_assignment -> assignment_hash, username, "Объект актора в результате не найден");
|
||||
|
||||
resactor_index ractors(_capital, coopname.value);
|
||||
auto resactor = ractors.find(exist_resactor.id);
|
||||
creauthor_index creathors(_capital, coopname.value);
|
||||
auto creauthor = creathors.find(exist_creauthor.id);
|
||||
|
||||
eosio::check(resactor -> available >= amount, "Недостаточно средств для создания возврата");
|
||||
eosio::check(resactor -> creators_bonus_shares >= amount.amount, "Недостаточно средств в creators_bonus_shares для создания возврата");
|
||||
eosio::check(creauthor -> available >= amount, "Недостаточно средств для создания возврата");
|
||||
|
||||
ractors.modify(resactor, coopname, [&](auto &ra) {
|
||||
creathors.modify(creauthor, coopname, [&](auto &ra) {
|
||||
ra.available -= amount;
|
||||
ra.creators_bonus_shares -= amount.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);
|
||||
|
||||
eosio::check(result -> total_creators_bonus_shares >= amount.amount, "Недостаточное количество result -> total_creators_bonus_shares для осуществления возврата");
|
||||
|
||||
results.modify(result, coopname, [&](auto &row) {
|
||||
row.total_creators_bonus_shares -= amount.amount;
|
||||
});
|
||||
|
||||
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
|
||||
|
||||
eosio::check(!exist_withdraw.has_value(), "Заявка на возврат с таким хэшем уже существует");
|
||||
@@ -63,10 +51,11 @@ void capital::createwthd1(eosio::name coopname, eosio::name application, eosio::
|
||||
w.id = get_global_id_in_scope(_capital, coopname, "withdraws1"_n);
|
||||
w.coopname = coopname;
|
||||
w.withdraw_hash = withdraw_hash;
|
||||
w.result_hash = result_hash;
|
||||
w.project_hash = exist_result -> project_hash;
|
||||
w.assignment_hash = assignment_hash;
|
||||
w.project_hash = exist_assignment -> project_hash;
|
||||
w.username = username;
|
||||
w.amount = amount;
|
||||
w.return_statement = return_statement;
|
||||
});
|
||||
|
||||
};
|
||||
@@ -2,6 +2,15 @@
|
||||
#include <ctime>
|
||||
#include <eosio/transaction.hpp>
|
||||
#include <eosio/crypto.hpp>
|
||||
|
||||
#include "src/createdraft.cpp"
|
||||
#include "src/createtrans.cpp"
|
||||
#include "src/deldraft.cpp"
|
||||
#include "src/deltrans.cpp"
|
||||
#include "src/editdraft.cpp"
|
||||
#include "src/edittrans.cpp"
|
||||
#include "src/upversion.cpp"
|
||||
|
||||
using namespace eosio;
|
||||
|
||||
[[eosio::action]]
|
||||
@@ -12,151 +21,3 @@ void draft::migrate() {
|
||||
void draft::newid(eosio::name scope, uint64_t id) { require_auth(_draft); };
|
||||
|
||||
|
||||
name get_payer_and_check_auth_in_scope(eosio::name scope, eosio::name username, eosio::name action){
|
||||
eosio::name payer;
|
||||
|
||||
if (scope == _draft) {
|
||||
require_auth(_system);
|
||||
payer = _system;
|
||||
}
|
||||
else {
|
||||
get_cooperative_or_fail(scope);
|
||||
check_auth_or_fail(_draft, scope, username, action);
|
||||
payer = username;
|
||||
};
|
||||
|
||||
return payer;
|
||||
}
|
||||
|
||||
void draft::createdraft(eosio::name scope, eosio::name username, uint64_t registry_id, eosio::name lang, std::string title,
|
||||
std::string description, std::string context, std::string model, std::string translation_data) {
|
||||
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "createdraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
|
||||
// Проверка существующих записей с тем же registry_id
|
||||
auto exist = drafts.find(registry_id);
|
||||
eosio::check(exist == drafts.end(), "Уже существует шаблон с тем же идентификатором. Обновите его.");
|
||||
|
||||
// Создание нового шаблона
|
||||
uint64_t translation_id = get_global_id(_draft, "translation"_n);
|
||||
|
||||
drafts.emplace(payer, [&](auto &d) {
|
||||
d.registry_id = registry_id;
|
||||
d.version = 1;
|
||||
d.default_translation_id = translation_id;
|
||||
d.title = title;
|
||||
d.description = description;
|
||||
d.context = context;
|
||||
d.model = model;
|
||||
});
|
||||
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
|
||||
translations.emplace(payer, [&](auto &t) {
|
||||
t.id = translation_id;
|
||||
t.draft_id = registry_id;
|
||||
t.lang = lang;
|
||||
t.data = translation_data;
|
||||
});
|
||||
|
||||
// Отправка действия для обновления идентификаторов
|
||||
action(permission_level{_draft, "active"_n}, _draft, "newid"_n,
|
||||
std::make_tuple(scope, registry_id))
|
||||
.send();
|
||||
};
|
||||
|
||||
|
||||
|
||||
void draft::editdraft(eosio::name scope, eosio::name username, uint64_t registry_id, std::string title, std::string description, std::string context, std::string model){
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "editdraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
auto exist = drafts.find(registry_id);
|
||||
|
||||
eosio::check(exist != drafts.end(), "Шаблон не найден");
|
||||
|
||||
drafts.modify(exist, payer, [&](auto &d){
|
||||
d.title = title;
|
||||
d.description = description;
|
||||
d.context = context;
|
||||
d.model = model;
|
||||
});
|
||||
}
|
||||
|
||||
void draft::upversion(eosio::name scope, eosio::name username, uint64_t registry_id){
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "editdraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
auto exist = drafts.find(registry_id);
|
||||
|
||||
eosio::check(exist != drafts.end(), "Шаблон не найден");
|
||||
|
||||
drafts.modify(exist, payer, [&](auto &d){
|
||||
d.version = exist -> version + 1;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void draft::deldraft(eosio::name scope, eosio::name username, uint64_t registry_id) {
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "deldraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, _draft.value);
|
||||
|
||||
auto draft = drafts.find(registry_id);
|
||||
eosio::check(draft != drafts.end(), "Шаблон не найден");
|
||||
|
||||
drafts.erase(draft);
|
||||
};
|
||||
|
||||
|
||||
void draft::createtrans(eosio::name scope, eosio::name username, uint64_t registry_id, eosio::name lang, std::string data) {
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "createtrans"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
auto draft = drafts.find(registry_id);
|
||||
eosio::check(draft != drafts.end(), "Документ не найден");
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
|
||||
auto trans_index_by_draft_and_lang = translations.template get_index<"bydraftlang"_n>();
|
||||
|
||||
auto trans_combined_index = combine_ids(registry_id, lang.value);
|
||||
auto trans = trans_index_by_draft_and_lang.find(trans_combined_index);
|
||||
eosio::check(trans == trans_index_by_draft_and_lang.end(), "Перевод уже создан для документа");
|
||||
|
||||
uint64_t translation_id = get_global_id(_draft, "translation"_n);
|
||||
|
||||
translations.emplace(payer, [&](auto &d){
|
||||
d.id = translation_id;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
void draft::edittrans(eosio::name scope, eosio::name username, uint64_t translate_id, std::string data) {
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "edittrans"_n);
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
auto trans = translations.find(translate_id);
|
||||
eosio::check(trans != translations.end(), "Перевод не найден");
|
||||
|
||||
translations.modify(trans, _system, [&](auto &t){
|
||||
t.data = data;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
void draft::deltrans(eosio::name scope, eosio::name username, uint64_t translate_id) {
|
||||
eosio::name payer = get_payer_and_check_auth_in_scope(scope, username, "deltrans"_n);
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
|
||||
auto trans = translations.find(translate_id);
|
||||
eosio::check(trans != translations.end(), "Объект с переводом не найден");
|
||||
|
||||
translations.erase(trans);
|
||||
|
||||
};
|
||||
|
||||
@@ -37,4 +37,21 @@ public:
|
||||
[[eosio::action]] void upversion(eosio::name scope, eosio::name username, uint64_t registry_id);
|
||||
|
||||
struct [[eosio::table, eosio::contract(DRAFT)]] counts : counts_base {};
|
||||
|
||||
|
||||
inline name get_payer_and_check_auth_in_scope(eosio::name scope, eosio::name username, eosio::name action){
|
||||
eosio::name payer;
|
||||
|
||||
if (scope == _draft) {
|
||||
require_auth(_system);
|
||||
payer = _system;
|
||||
}
|
||||
else {
|
||||
get_cooperative_or_fail(scope);
|
||||
check_auth_or_fail(_draft, scope, username, action);
|
||||
payer = username;
|
||||
};
|
||||
|
||||
return payer;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
void draft::createdraft(eosio::name scope, eosio::name username, uint64_t registry_id, eosio::name lang, std::string title,
|
||||
std::string description, std::string context, std::string model, std::string translation_data) {
|
||||
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "createdraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
|
||||
// Проверка существующих записей с тем же registry_id
|
||||
auto exist = drafts.find(registry_id);
|
||||
eosio::check(exist == drafts.end(), "Уже существует шаблон с тем же идентификатором. Обновите его.");
|
||||
|
||||
// Создание нового шаблона
|
||||
uint64_t translation_id = get_global_id(_draft, "translation"_n);
|
||||
|
||||
drafts.emplace(payer, [&](auto &d) {
|
||||
d.registry_id = registry_id;
|
||||
d.version = 1;
|
||||
d.default_translation_id = translation_id;
|
||||
d.title = title;
|
||||
d.description = description;
|
||||
d.context = context;
|
||||
d.model = model;
|
||||
});
|
||||
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
|
||||
translations.emplace(payer, [&](auto &t) {
|
||||
t.id = translation_id;
|
||||
t.draft_id = registry_id;
|
||||
t.lang = lang;
|
||||
t.data = translation_data;
|
||||
});
|
||||
|
||||
// Отправка действия для обновления идентификаторов
|
||||
action(permission_level{_draft, "active"_n}, _draft, "newid"_n,
|
||||
std::make_tuple(scope, registry_id))
|
||||
.send();
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
void draft::createtrans(eosio::name scope, eosio::name username, uint64_t registry_id, eosio::name lang, std::string data) {
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "createtrans"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
auto draft = drafts.find(registry_id);
|
||||
eosio::check(draft != drafts.end(), "Документ не найден");
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
|
||||
auto trans_index_by_draft_and_lang = translations.template get_index<"bydraftlang"_n>();
|
||||
|
||||
auto trans_combined_index = combine_ids(registry_id, lang.value);
|
||||
auto trans = trans_index_by_draft_and_lang.find(trans_combined_index);
|
||||
eosio::check(trans == trans_index_by_draft_and_lang.end(), "Перевод уже создан для документа");
|
||||
|
||||
uint64_t translation_id = get_global_id(_draft, "translation"_n);
|
||||
|
||||
translations.emplace(payer, [&](auto &d){
|
||||
d.id = translation_id;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
void draft::deldraft(eosio::name scope, eosio::name username, uint64_t registry_id) {
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "deldraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, _draft.value);
|
||||
|
||||
auto draft = drafts.find(registry_id);
|
||||
eosio::check(draft != drafts.end(), "Шаблон не найден");
|
||||
|
||||
drafts.erase(draft);
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
void draft::deltrans(eosio::name scope, eosio::name username, uint64_t translate_id) {
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "deltrans"_n);
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
|
||||
auto trans = translations.find(translate_id);
|
||||
eosio::check(trans != translations.end(), "Объект с переводом не найден");
|
||||
|
||||
translations.erase(trans);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
void draft::editdraft(eosio::name scope, eosio::name username, uint64_t registry_id, std::string title, std::string description, std::string context, std::string model){
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "editdraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
auto exist = drafts.find(registry_id);
|
||||
|
||||
eosio::check(exist != drafts.end(), "Шаблон не найден");
|
||||
|
||||
drafts.modify(exist, payer, [&](auto &d){
|
||||
d.title = title;
|
||||
d.description = description;
|
||||
d.context = context;
|
||||
d.model = model;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
void draft::edittrans(eosio::name scope, eosio::name username, uint64_t translate_id, std::string data) {
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "edittrans"_n);
|
||||
|
||||
translations_index translations(_draft, scope.value);
|
||||
auto trans = translations.find(translate_id);
|
||||
eosio::check(trans != translations.end(), "Перевод не найден");
|
||||
|
||||
translations.modify(trans, _system, [&](auto &t){
|
||||
t.data = data;
|
||||
});
|
||||
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
void draft::upversion(eosio::name scope, eosio::name username, uint64_t registry_id){
|
||||
eosio::name payer = draft::get_payer_and_check_auth_in_scope(scope, username, "editdraft"_n);
|
||||
|
||||
drafts_index drafts(_draft, scope.value);
|
||||
auto exist = drafts.find(registry_id);
|
||||
|
||||
eosio::check(exist != drafts.end(), "Шаблон не найден");
|
||||
|
||||
drafts.modify(exist, payer, [&](auto &d){
|
||||
d.version = exist -> version + 1;
|
||||
});
|
||||
}
|
||||
@@ -3,11 +3,27 @@
|
||||
#include <ctime>
|
||||
#include <eosio/transaction.hpp>
|
||||
|
||||
#include "src/addaccum.cpp"
|
||||
#include "src/addcirculate.cpp"
|
||||
#include "src/addexpense.cpp"
|
||||
#include "src/addinitial.cpp"
|
||||
#include "src/authorize.cpp"
|
||||
#include "src/delfund.cpp"
|
||||
#include "src/complete.cpp"
|
||||
#include "src/createfund.cpp"
|
||||
#include "src/editfund.cpp"
|
||||
#include "src/fundwithdraw.cpp"
|
||||
#include "src/init.cpp"
|
||||
#include "src/spreadamount.cpp"
|
||||
#include "src/subaccum.cpp"
|
||||
#include "src/subcirculate.cpp"
|
||||
#include "src/subinitial.cpp"
|
||||
|
||||
|
||||
using namespace eosio;
|
||||
|
||||
[[eosio::action]] void fund::migrate() {
|
||||
require_auth(_fund);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,634 +49,3 @@ using namespace eosio;
|
||||
uint64_t id) {
|
||||
require_auth(_fund);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Вызывается при запуске кооператива для создания кооперативного кошелька и некоторых фондов
|
||||
*
|
||||
* @param coopname
|
||||
* @param initial
|
||||
*/
|
||||
[[eosio::action]] void fund::init(eosio::name coopname, eosio::asset initial) {
|
||||
eosio::name payer = check_auth_and_get_payer_or_fail({_soviet, _registrator});
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
|
||||
auto exist = coopwallet.find(0);
|
||||
|
||||
if (exist == coopwallet.end()) {
|
||||
// кошелёк кооператива
|
||||
coopwallet.emplace(payer, [&](auto &row) {
|
||||
row.id = 0;
|
||||
row.coopname = coopname;
|
||||
|
||||
row.circulating_account.available = asset(0, initial.symbol);
|
||||
row.circulating_account.withdrawed = asset(0, initial.symbol);
|
||||
|
||||
row.initial_account.available = asset(0, initial.symbol);
|
||||
row.initial_account.withdrawed = asset(0, initial.symbol);
|
||||
|
||||
row.accumulative_account.available = asset(0, initial.symbol);
|
||||
row.accumulative_account.withdrawed = asset(0, initial.symbol);
|
||||
|
||||
row.accumulative_expense_account.available = asset(0, initial.symbol);
|
||||
row.accumulative_expense_account.withdrawed = asset(0, initial.symbol);
|
||||
});
|
||||
|
||||
// неделимый
|
||||
accfunds.emplace(payer, [&](auto &a) {
|
||||
a.id = get_global_id_in_scope(_fund, coopname, "funds"_n); // 1
|
||||
a.coopname = coopname;
|
||||
a.contract = ""_n;
|
||||
a.name = "Неделимый фонд";
|
||||
a.description = "";
|
||||
a.percent = 1 * ONE_PERCENT;
|
||||
a.available = asset(0, initial.symbol);
|
||||
a.withdrawed = asset(0, initial.symbol);
|
||||
});
|
||||
|
||||
// резервный
|
||||
accfunds.emplace(payer, [&](auto &a) {
|
||||
a.id = get_global_id_in_scope(_fund, coopname, "funds"_n); // 2
|
||||
a.coopname = coopname;
|
||||
a.contract = ""_n;
|
||||
a.name = "Резервный фонд";
|
||||
a.description = "";
|
||||
a.percent = 15 * ONE_PERCENT;
|
||||
a.available = asset(0, initial.symbol);
|
||||
a.withdrawed = asset(0, initial.symbol);
|
||||
});
|
||||
|
||||
// развития
|
||||
accfunds.emplace(payer, [&](auto &a) {
|
||||
a.id = get_global_id_in_scope(_fund, coopname, "funds"_n); // 3
|
||||
a.coopname = coopname;
|
||||
a.contract = ""_n;
|
||||
a.name = "Фонд развития кооперации";
|
||||
a.description = "";
|
||||
a.percent = 5 * ONE_PERCENT;
|
||||
a.available = asset(0, initial.symbol);
|
||||
a.withdrawed = asset(0, initial.symbol);
|
||||
});
|
||||
|
||||
auto e_id = expfunds.available_primary_key();
|
||||
|
||||
// хозяйственный
|
||||
expfunds.emplace(payer, [&](auto &e) {
|
||||
e.id = get_global_id_in_scope(_fund, coopname, "funds"_n); // 4
|
||||
e.coopname = coopname;
|
||||
e.contract = ""_n;
|
||||
e.name = "Хозяйственный фонд";
|
||||
e.description = "";
|
||||
e.expended = asset(0, initial.symbol);
|
||||
});
|
||||
|
||||
// взаимный
|
||||
expfunds.emplace(payer, [&](auto &e) {
|
||||
e.id = get_global_id_in_scope(_fund, coopname, "funds"_n); // 5
|
||||
e.coopname = coopname;
|
||||
e.contract = ""_n;
|
||||
e.name = "Фонд взаимного обеспечения";
|
||||
e.description = "";
|
||||
e.expended = asset(0, initial.symbol);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// атомарные транзакции фондового кошелька
|
||||
// паевый счет
|
||||
[[eosio::action]] void fund::addcirculate(
|
||||
eosio::name coopname,
|
||||
eosio::asset quantity) /// < добавить сумму в паевый фонд
|
||||
{
|
||||
eosio::name payer = check_auth_and_get_payer_or_fail({_gateway, _marketplace});
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
|
||||
auto wal = coopwallet.find(0);
|
||||
|
||||
eosio::check(wal != coopwallet.end(), "Кошелёк кооператива не найден");
|
||||
|
||||
coopwallet.modify(wal, _gateway, [&](auto &w) {
|
||||
w.circulating_account.available += quantity;
|
||||
});
|
||||
};
|
||||
|
||||
[[eosio::action]] void fund::subcirculate(
|
||||
eosio::name coopname,
|
||||
eosio::asset quantity,
|
||||
bool skip_available_check
|
||||
) /// < списать сумму из паевого фонда
|
||||
{
|
||||
// Только контракт шлюза или маркетплейса может списывать оборотные средства из фонда
|
||||
eosio::name payer = check_auth_and_get_payer_or_fail({_gateway, _marketplace});
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
|
||||
auto wal = coopwallet.find(0);
|
||||
|
||||
eosio::check(wal != coopwallet.end(), "Фондовый кошелёк не найден");
|
||||
|
||||
if (!skip_available_check)
|
||||
eosio::check(wal->circulating_account.available >= quantity,
|
||||
"Недостаточно средств для списания на паевом счете кооператива");
|
||||
|
||||
coopwallet.modify(wal, payer, [&](auto &w) {
|
||||
w.circulating_account.available -= quantity;
|
||||
w.circulating_account.withdrawed += quantity;
|
||||
});
|
||||
};
|
||||
|
||||
// фонды накопления
|
||||
[[eosio::action]] void fund::addaccum(eosio::name coopname, uint64_t fund_id,
|
||||
eosio::asset quantity) {
|
||||
require_auth(_fund);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
eosio::check(wal != coopwallet.end(), "Кошелёк кооператива не найден");
|
||||
|
||||
coopwallet.modify(wal, _fund, [&](auto &row) {
|
||||
row.accumulative_account.available += quantity;
|
||||
});
|
||||
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(fund_id);
|
||||
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
|
||||
accfunds.modify(afund, _fund, [&](auto &a) { a.available += quantity; });
|
||||
};
|
||||
|
||||
[[eosio::action]] void fund::subaccum(eosio::name coopname, uint64_t fund_id,
|
||||
eosio::asset quantity) {
|
||||
// списать можно только с помощью вызова метода withdraw смарт-контракта
|
||||
require_auth(_fund);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
eosio::check(wal != coopwallet.end(), "Фондовый кошелёк не найден");
|
||||
eosio::check(wal->accumulative_account.available >= quantity,
|
||||
"Недостаточно средств для списания");
|
||||
|
||||
coopwallet.modify(wal, _fund, [&](auto &row) {
|
||||
row.accumulative_account.available -= quantity;
|
||||
row.accumulative_account.withdrawed += quantity;
|
||||
});
|
||||
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(fund_id);
|
||||
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
|
||||
accfunds.modify(afund, _fund, [&](auto &a) {
|
||||
a.available -= quantity;
|
||||
a.withdrawed += quantity;
|
||||
});
|
||||
};
|
||||
|
||||
// фонды списания
|
||||
[[eosio::action]] void fund::addexpense(eosio::name coopname, uint64_t fund_id,
|
||||
eosio::asset quantity) {
|
||||
require_auth(_fund);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
|
||||
eosio::check(wal != coopwallet.end(), "Фондовый кошелёк не найден");
|
||||
|
||||
eosio::check(wal->accumulative_expense_account.available +
|
||||
wal->initial_account.available >=
|
||||
quantity,
|
||||
"Недостаточно средств для списания");
|
||||
|
||||
coopwallet.modify(wal, _fund, [&](auto &w) {
|
||||
|
||||
/**
|
||||
* @brief проверить что списание идет по хозяйственному фонду
|
||||
если да - уменьшить счет членских взносов автоматически на всю возможную
|
||||
сумму. Остаток снять с накопительного счета списания.
|
||||
*/
|
||||
if (fund_id == 4) {
|
||||
|
||||
// Списываем из initial_account
|
||||
eosio::asset from_initial =
|
||||
std::min(quantity, w.initial_account.available);
|
||||
w.initial_account.available -= from_initial;
|
||||
w.initial_account.withdrawed += from_initial;
|
||||
|
||||
// Если осталось списание, снимаем с accumulative_expense_account
|
||||
eosio::asset remaining = quantity - from_initial;
|
||||
if (remaining.amount > 0) {
|
||||
w.accumulative_expense_account.available -= remaining;
|
||||
w.accumulative_expense_account.withdrawed += remaining;
|
||||
}
|
||||
} else {
|
||||
w.accumulative_expense_account.available -= quantity;
|
||||
w.accumulative_expense_account.withdrawed += quantity;
|
||||
}
|
||||
});
|
||||
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
auto efund = expfunds.find(fund_id);
|
||||
|
||||
eosio::check(efund != expfunds.end(), "Фонд не найден");
|
||||
|
||||
expfunds.modify(efund, _fund, [&](auto &a) { a.expended += quantity; });
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Атомарный метод добавления вступительного взноса на счет кошелька кооператива.
|
||||
*
|
||||
* @param coopname
|
||||
* @param quantity
|
||||
*/
|
||||
[[eosio::action]] void fund::addinitial(eosio::name coopname,
|
||||
eosio::asset quantity) {
|
||||
eosio::name payer = check_auth_and_get_payer_or_fail({_gateway});
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
|
||||
coopwallet.modify(
|
||||
wal, payer, [&](auto &row) { row.initial_account.available += quantity; });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Атомарный метод списания вступительного взноса. Используется только при отмене операции вступления.
|
||||
*
|
||||
* @param coopname
|
||||
* @param quantity
|
||||
*/
|
||||
[[eosio::action]] void fund::subinitial(eosio::name coopname,
|
||||
eosio::asset quantity) {
|
||||
eosio::name payer = check_auth_and_get_payer_or_fail({_gateway});
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
|
||||
coopwallet.modify(
|
||||
wal, payer, [&](auto &row) { row.initial_account.available -= quantity; });
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief Метод распределения членской части взноса по фондам накопления с остатком в
|
||||
кошельке для распределения по фондам списания. Распределить членские взносы по фондам накопления, положив остаток на накопительный счет списания. На входе мы получаем общую членскую часть, которую распределяем по счетам.
|
||||
*
|
||||
* @param coopname
|
||||
* @param quantity
|
||||
*/
|
||||
[[eosio::action]] void fund::spreadamount(eosio::name coopname,
|
||||
eosio::asset quantity) {
|
||||
|
||||
eosio::name payer = check_auth_and_get_payer_or_fail({_marketplace, _gateway, _soviet});
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
|
||||
eosio::check(wal != coopwallet.end(), "Кошелёк кооператива не найден");
|
||||
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
eosio::asset total_accumulated = asset(0, cooperative.initial.symbol);
|
||||
|
||||
// готовим пакет транзакций пополнения счетов накопления
|
||||
for (auto it = accfunds.begin(); it != accfunds.end(); it++) {
|
||||
eosio::asset fund_quantity = it->percent * quantity / HUNDR_PERCENTS;
|
||||
total_accumulated += fund_quantity;
|
||||
action(permission_level{_fund, "active"_n}, _fund, "addaccum"_n,
|
||||
std::make_tuple(coopname, it->id, fund_quantity))
|
||||
.send();
|
||||
};
|
||||
|
||||
// считаем сколько не выплачено по счетам накопления
|
||||
eosio::asset remain_amount = quantity - total_accumulated;
|
||||
|
||||
// начисляем на накопительный счет списания
|
||||
coopwallet.modify(wal, payer, [&](auto &w) {
|
||||
w.accumulative_expense_account.available += remain_amount;
|
||||
});
|
||||
};
|
||||
|
||||
/* Метод создания вывода средств из фонда накопления или по фонду списания
|
||||
* Использование метода не накладывает условие проверки на наличие средств в
|
||||
* целевом фонде. Проверка на наличие происходит в момент списания (complete)
|
||||
* после утверждения решения советом. Т.е. совет может принять решение о будущем
|
||||
* расходе, но фактическое списание осуществится только при наличии средств в
|
||||
* фондах.
|
||||
*/
|
||||
[[eosio::action]] void fund::fundwithdraw(eosio::name coopname,
|
||||
eosio::name username,
|
||||
eosio::name type, uint64_t fund_id,
|
||||
document document,
|
||||
eosio::asset quantity,
|
||||
std::string bank_data_id) {
|
||||
eosio::check(type == _afund_withdraw_action || type == _efund_withdraw_action,
|
||||
"Неверный тип фонда");
|
||||
eosio::name payer;
|
||||
|
||||
if (type == _afund_withdraw_action) {
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(fund_id);
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
payer = afund->contract != ""_n ? afund->contract : username;
|
||||
} else if (type == _efund_withdraw_action) {
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
auto efund = expfunds.find(fund_id);
|
||||
eosio::check(efund != expfunds.end(), "Фонд не найден");
|
||||
payer = efund->contract != ""_n ? efund->contract : username;
|
||||
}
|
||||
|
||||
require_auth(payer);
|
||||
|
||||
if (payer == username) {
|
||||
staff_index staff(_soviet, coopname.value);
|
||||
auto persona = staff.find(username.value);
|
||||
eosio::check(persona != staff.end(),
|
||||
"Указанный аккаунт не является сотрудником");
|
||||
eosio::check(persona->has_right(_soviet, "complete"_n),
|
||||
"Недостаточно прав доступа");
|
||||
};
|
||||
|
||||
fundwithdraws_index fundwithdraws(_fund, coopname.value);
|
||||
uint64_t fundwithdraw_id = get_global_id(_fund, "fundwithdraw"_n);
|
||||
|
||||
fundwithdraws.emplace(payer, [&](auto &s) {
|
||||
s.id = fundwithdraw_id;
|
||||
s.type = type;
|
||||
s.status = "pending"_n;
|
||||
s.coopname = coopname;
|
||||
s.username = username;
|
||||
s.fund_id = fund_id;
|
||||
s.quantity = quantity;
|
||||
s.document = document;
|
||||
s.bank_data_id = bank_data_id;
|
||||
});
|
||||
|
||||
action(permission_level{_fund, "active"_n}, _soviet, "fundwithdraw"_n,
|
||||
std::make_tuple(coopname, username, type, fundwithdraw_id, document))
|
||||
.send();
|
||||
|
||||
// оповещаем себя же
|
||||
action(permission_level{_fund, "active"_n}, _fund, "newwithdraw"_n,
|
||||
std::make_tuple(coopname, type, fundwithdraw_id))
|
||||
.send();
|
||||
}
|
||||
|
||||
[[eosio::action]] void fund::authorize(eosio::name coopname, eosio::name type,
|
||||
uint64_t withdraw_id) {
|
||||
require_auth(_soviet);
|
||||
|
||||
fundwithdraws_index fundwithdraws(_fund, coopname.value);
|
||||
auto withdraw = fundwithdraws.find(withdraw_id);
|
||||
eosio::check(withdraw != fundwithdraws.end(), "Вывод не найден");
|
||||
|
||||
fundwithdraws.modify(withdraw, _soviet,
|
||||
[&](auto &s) { s.status = "authorized"_n; });
|
||||
};
|
||||
|
||||
[[eosio::action]] void fund::complete(eosio::name coopname,
|
||||
eosio::name username,
|
||||
uint64_t withdraw_id) {
|
||||
require_auth(username);
|
||||
// todo check rights for username
|
||||
|
||||
staff_index staff(_soviet, coopname.value);
|
||||
auto persona = staff.find(username.value);
|
||||
|
||||
eosio::check(persona != staff.end(),
|
||||
"Указанный аккаунт не является сотрудником");
|
||||
eosio::check(persona->has_right(_soviet, "complete"_n),
|
||||
"Недостаточно прав доступа");
|
||||
|
||||
fundwithdraws_index fundwithdraws(_fund, coopname.value);
|
||||
auto withdraw = fundwithdraws.find(withdraw_id);
|
||||
eosio::check(withdraw != fundwithdraws.end(), "Вывод не найден");
|
||||
|
||||
fundwithdraws.modify(withdraw, _soviet, [&](auto &s) {
|
||||
s.status = "completed"_n;
|
||||
s.expired_at = eosio::time_point_sec(
|
||||
eosio::current_time_point().sec_since_epoch() + 30 * 86400);
|
||||
});
|
||||
|
||||
if (withdraw->type == _afund_withdraw_action) {
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(withdraw->fund_id);
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
|
||||
action(permission_level{_fund, "active"_n}, _fund, "subaccum"_n,
|
||||
std::make_tuple(coopname, withdraw->fund_id, withdraw->quantity))
|
||||
.send();
|
||||
} else if (withdraw->type == _efund_withdraw_action) {
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
auto efund = expfunds.find(withdraw->fund_id);
|
||||
eosio::check(efund != expfunds.end(), "Фонд не найден");
|
||||
|
||||
action(permission_level{_fund, "active"_n}, _fund, "addexpense"_n,
|
||||
std::make_tuple(coopname, withdraw->fund_id, withdraw->quantity))
|
||||
.send();
|
||||
}
|
||||
};
|
||||
|
||||
// type: accumulation, expend
|
||||
[[eosio::action]] void fund::createfund(eosio::name coopname,
|
||||
eosio::name username, eosio::name type,
|
||||
eosio::name contract, std::string name,
|
||||
std::string description,
|
||||
uint64_t percent) {
|
||||
require_auth(username);
|
||||
|
||||
eosio::check(type == "accumulation"_n || type == "expend"_n,
|
||||
"Неверный тип фонда");
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
auto soviet = get_board_by_type_or_fail(coopname, "soviet"_n);
|
||||
auto chairman = soviet.get_chairman();
|
||||
|
||||
eosio::check(username == chairman,
|
||||
"Только председатель может управлять фондами");
|
||||
|
||||
uint64_t id;
|
||||
|
||||
if (type == "accumulation"_n) {
|
||||
eosio::check(percent > 0 && percent <= HUNDR_PERCENTS,
|
||||
"Процент фонда накопления должен быть больше нуля и меньше 1 "
|
||||
"000 000 (= 100%)");
|
||||
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
uint64_t total_percent = percent;
|
||||
|
||||
// получаем сумму процентов всех фондов
|
||||
for (auto it = accfunds.begin(); it != accfunds.end(); it++) {
|
||||
total_percent += it->percent;
|
||||
}
|
||||
|
||||
// сумма не должна превышать 100%
|
||||
check(total_percent <= HUNDR_PERCENTS,
|
||||
"Сумма всех процентов превышает 100% (1 000 000)");
|
||||
id = get_global_id(_fund, "funds"_n);
|
||||
accfunds.emplace(username, [&](auto &a) {
|
||||
a.id = get_global_id_in_scope(_fund, coopname, "funds"_n);
|
||||
a.coopname = coopname;
|
||||
a.contract = contract;
|
||||
a.name = name;
|
||||
a.description = description;
|
||||
a.percent = percent;
|
||||
a.available = asset(0, cooperative.initial.symbol);
|
||||
a.withdrawed = asset(0, cooperative.initial.symbol);
|
||||
});
|
||||
} else if (type == "expend"_n) {
|
||||
eosio::check(
|
||||
percent == 0,
|
||||
"Процент для фонда списания должен быть равен нулю (не используется)");
|
||||
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
id = get_global_id_in_scope(_fund, coopname, "funds"_n);
|
||||
|
||||
expfunds.emplace(username, [&](auto &e) {
|
||||
e.id = id;
|
||||
e.coopname = coopname;
|
||||
e.contract = contract;
|
||||
e.name = name;
|
||||
e.description = description;
|
||||
e.expended = asset(0, cooperative.initial.symbol);
|
||||
});
|
||||
};
|
||||
|
||||
action(permission_level{_fund, "active"_n}, _fund, "newfund"_n,
|
||||
std::make_tuple(coopname, type, id))
|
||||
.send();
|
||||
};
|
||||
|
||||
[[eosio::action]] void fund::editfund(eosio::name coopname,
|
||||
eosio::name username, eosio::name type,
|
||||
uint64_t fund_id, eosio::name contract,
|
||||
std::string name, std::string description,
|
||||
uint64_t percent) {
|
||||
require_auth(username);
|
||||
|
||||
eosio::check(type == "accumulation"_n || type == "expend"_n,
|
||||
"Неверный тип фонда");
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
auto soviet = get_board_by_type_or_fail(coopname, "soviet"_n);
|
||||
auto chairman = soviet.get_chairman();
|
||||
eosio::check(username == chairman,
|
||||
"Только председатель может управлять фондами");
|
||||
|
||||
|
||||
if (fund_id <= 5){
|
||||
/**
|
||||
Фонд развития кооперации (3) и резервный фонд (2) проценты менять можно.
|
||||
Названия фондов менять нельзя (id < 5).
|
||||
*/
|
||||
|
||||
eosio::check(fund_id != 0, "Неделимый фонд не может быть отредактирован");
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (type == "accumulation"_n) {
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(fund_id);
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
|
||||
if (fund_id <= 3){
|
||||
eosio::check(fund_id == 1, "Нельзя изменить процент неделимого фонда накопления");
|
||||
eosio::check(name == afund -> name, "Нельзя изменить имя обязательного фонда накопления");
|
||||
eosio::check(contract == ""_n, "Нельзя передать в управление обязательный фонд");
|
||||
}
|
||||
|
||||
eosio::check(
|
||||
percent > 0 && percent <= HUNDR_PERCENTS,
|
||||
"Процент фонда накопления должен быть больше нуля и меньше 100%");
|
||||
uint64_t total_percent = 0;
|
||||
|
||||
// получаем сумму процентов всех фондов
|
||||
for (auto it = accfunds.begin(); it != accfunds.end(); it++) {
|
||||
total_percent += it->percent;
|
||||
}
|
||||
|
||||
// вычитаем старый процент и добавляем новый
|
||||
total_percent += percent - afund->percent;
|
||||
|
||||
// сумма процентов не должна превышать 100%
|
||||
check(total_percent <= HUNDR_PERCENTS,
|
||||
"Сумма всех процентов превышает 100%");
|
||||
|
||||
accfunds.modify(afund, username, [&](auto &a) {
|
||||
a.contract = contract;
|
||||
a.name = name;
|
||||
a.description = description;
|
||||
a.percent = percent;
|
||||
});
|
||||
} else if (type == "expend"_n) {
|
||||
eosio::check(
|
||||
percent == 0,
|
||||
"Процент для фонда списания должен быть равен нулю (не используется)");
|
||||
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
auto efund = expfunds.find(fund_id);
|
||||
eosio::check(efund != expfunds.end(), "Фонд не найден");
|
||||
|
||||
if (fund_id <= 5){
|
||||
eosio::check(name == efund -> name, "Нельзя изменить имя обязательного фонда списания");
|
||||
eosio::check(contract == ""_n, "Нельзя передать в управление обязательный фонд");
|
||||
}
|
||||
|
||||
expfunds.modify(efund, username, [&](auto &e) {
|
||||
e.contract = contract;
|
||||
e.name = name;
|
||||
e.description = description;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
[[eosio::action]] void fund::delfund(eosio::name coopname, eosio::name username,
|
||||
eosio::name type, uint64_t fund_id) {
|
||||
require_auth(username);
|
||||
|
||||
eosio::check(type == "accumulation"_n || type == "expend"_n,
|
||||
"Неверный тип фонда");
|
||||
|
||||
auto cooperative = get_cooperative_or_fail(coopname);
|
||||
|
||||
auto soviet = get_board_by_type_or_fail(coopname, "soviet"_n);
|
||||
auto chairman = soviet.get_chairman();
|
||||
eosio::check(username == chairman,
|
||||
"Только председатель может управлять фондами");
|
||||
|
||||
eosio::check(fund_id > 5, "Нельзя удалить обязательные фонды");
|
||||
|
||||
if (type == "accumulation"_n) {
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(fund_id);
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
eosio::check(afund->available.amount == 0,
|
||||
"Только пустой фонд накопления может быть удален");
|
||||
|
||||
accfunds.erase(afund);
|
||||
} else if (type == "expend"_n) {
|
||||
expfunds_index expfunds(_fund, coopname.value);
|
||||
auto efund = expfunds.find(fund_id);
|
||||
eosio::check(efund != expfunds.end(), "Фонд не найден");
|
||||
|
||||
expfunds.erase(efund);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// фонды накопления
|
||||
[[eosio::action]] void fund::addaccum(eosio::name coopname, uint64_t fund_id,
|
||||
eosio::asset quantity) {
|
||||
require_auth(_fund);
|
||||
|
||||
coopwallet_index coopwallet(_fund, coopname.value);
|
||||
auto wal = coopwallet.find(0);
|
||||
eosio::check(wal != coopwallet.end(), "Кошелёк кооператива не найден");
|
||||
|
||||
coopwallet.modify(wal, _fund, [&](auto &row) {
|
||||
row.accumulative_account.available += quantity;
|
||||
});
|
||||
|
||||
accfunds_index accfunds(_fund, coopname.value);
|
||||
auto afund = accfunds.find(fund_id);
|
||||
|
||||
eosio::check(afund != accfunds.end(), "Фонд не найден");
|
||||
|
||||
accfunds.modify(afund, _fund, [&](auto &a) { a.available += quantity; });
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user