Compare commits
144 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ccf2c743c | |||
| 418d43af58 | |||
| 869a75f080 | |||
| c7bc2d1a20 | |||
| 3ea4cd6d73 | |||
| 6a955737e0 | |||
| 51bf49b063 | |||
| 12468b16c8 | |||
| 5ebd28d181 | |||
| defe482ccd | |||
| e99d141f28 | |||
| aa0a6731de | |||
| 46f7f10dce | |||
| 552333faf6 | |||
| e23589d4d3 | |||
| 104b08e1ba | |||
| 1b81cfc0a9 | |||
| 6e51433ae9 | |||
| 421f356987 | |||
| abd9f1931d | |||
| 2b87034abb | |||
| 8d7c919332 | |||
| 4785ea2886 | |||
| 4daa06dac1 | |||
| abc253f47d | |||
| 5fea2f8f34 | |||
| c29e224f2f | |||
| b930543c2b | |||
| 2768d72e90 | |||
| 8ccefe8fac | |||
| c93e59908d | |||
| 22f0fd8a10 | |||
| 8e17d96529 | |||
| 494a164ee8 | |||
| ee28ae1719 | |||
| 3266061359 | |||
| f69d849c4f | |||
| 2628120e35 | |||
| edf7d9ab62 | |||
| 2095e448e5 | |||
| beff507f4a | |||
| bf4fbfabac | |||
| 2f1d88a74c | |||
| b444004f4a | |||
| 6862f2881a | |||
| 73afcabee2 | |||
| b4168a4053 | |||
| 1fe14d5811 | |||
| 89e5c97ef8 | |||
| 258b8304ff | |||
| 69fe9c1348 | |||
| fa4af94fa0 | |||
| 2ac84a6910 | |||
| 3f79cf9a1b | |||
| c155605ca8 | |||
| 80a94f79da | |||
| 89ba6cb356 | |||
| c7bd0326ba | |||
| 2c551a0d9e | |||
| ba103a969e | |||
| 0d9177f98f | |||
| 60c32be299 | |||
| 83c107b8b2 | |||
| b6d582fb2c | |||
| a5818bdc53 | |||
| de0fe5465f | |||
| d43b188a30 | |||
| bfb2be2a72 | |||
| 73c2cd9cb3 | |||
| 61cfc442ef | |||
| 0ed04c2c27 | |||
| 6773509ede | |||
| acd86df785 | |||
| c554b167b3 | |||
| 18cf7b61e3 | |||
| e42b396a68 | |||
| c47e61d42a | |||
| 92559370fa | |||
| c3a2ec46b3 | |||
| fe55d23e65 | |||
| b0d4f5d542 | |||
| be48f7a158 | |||
| 83bd744100 | |||
| ff1615f7b1 | |||
| 696e1a0d2c | |||
| 397670473a | |||
| cab8061bc3 | |||
| 3c2b9bcb4c | |||
| 7a274b7ab1 | |||
| e524244bab | |||
| 14ecaf259a | |||
| 749c13dc91 | |||
| ab2ee4cc92 | |||
| 2907352d61 | |||
| 390b995eb6 | |||
| 24b3dd3c60 | |||
| 55444a4b72 | |||
| 76854207a7 | |||
| 4fcd700e39 | |||
| 05dfcced1b | |||
| 931c366907 | |||
| 71d35b74d7 | |||
| 21fac5c7df | |||
| 0ba9d55081 | |||
| b5b388e95d | |||
| 9c643395b3 | |||
| b989074170 | |||
| 261f010a49 | |||
| af46867939 | |||
| be2355e5c5 | |||
| 8b4a20ed3f | |||
| 1ab1e1d3c5 | |||
| c9aab02aab | |||
| 0643604778 | |||
| fe79f3ff98 | |||
| f919a14927 | |||
| dda389ad75 | |||
| aa42864029 | |||
| 41bb17224a | |||
| fd6f628c43 | |||
| 28ca615d96 | |||
| 76203a88d8 | |||
| aa891adddf | |||
| ecdac6fff9 | |||
| bcba24ea5e | |||
| 44b1f423cc | |||
| 85cc7361d7 | |||
| e5e28ff652 | |||
| 4957182480 | |||
| 84927e943a | |||
| 0d06114f00 | |||
| 2654760e16 | |||
| d02e7ba2be | |||
| e18fd94336 | |||
| 03e2410556 | |||
| 0f1f34f621 | |||
| c08473618f | |||
| 3b4fb195bb | |||
| 827eb10cc2 | |||
| 6e7c60de6e | |||
| 54a4449e0b | |||
| a6011f5d46 | |||
| a1300e2b3c | |||
| 8f58672403 |
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"agentCanUpdateSnapshot": true
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
ВАЖНО!!! Мы работаем в МОНО-репозитории pnpm, любая установка пакетов производится ЧЕРЕЗ ФИЛЬТР компонента в корне: pnpm add glob --filter notificator2.
|
||||
|
||||
ВАЖНО!!! НИКОГДА НЕ ЗАПУСКАЙ ПРИЛОЖЕНИЕ ИЛИ ЕГО СБОРКУ!!! Просто отчитайся что всё сделал.
|
||||
@@ -10,7 +10,6 @@ alwaysApply: false
|
||||
2. Типы IName, IChecksum256, ITimePointSec - это просто строки.
|
||||
3. Домен должен быть полностью изолирован от инфраструктурных деталей.
|
||||
4. Направление зависимостей - внутрь (к ядру, домену).
|
||||
5. Домен, инфраструктура и приложение связаны через App.module, НЕ НУЖНО импортировать их друг в друга, а достаточно просто импортировать домен на уровне приложения чтобы использовать все экспорты домена.
|
||||
|
||||
## Структура проекта
|
||||
- `domain/` - доменный слой (бизнес-логика, независимая от инфраструктуры)
|
||||
|
||||
@@ -1,11 +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'
|
||||
- Всегда удаляем неиспользуемые импорты.
|
||||
- Не используем emit избыточно. Вместо них используем композабл функции моделей фич, если необходимо. Emit только в крайнем случае.
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
Файл [main.py](mdc:monocoop/monocoop/monocoop/components/docs/main.py) автоматически генерит ссылки на документацию SDK и GraphQL, которые формируются и публикуются автоматически. При создании документации к методам всегда применяй ссылки на SDK и GraphQL по форме:
|
||||
{{ get_sdk_doc("Mutations", "Accounts", "RegisterAccount") }} | {{ get_graphql_doc("Mutation.registerAccount") }}
|
||||
|
||||
### 🎯 Основные паттерны использования
|
||||
|
||||
**1. Стандартная структура для методов API:**
|
||||
```markdown
|
||||
## Название действия
|
||||
{{ get_sdk_doc("Namespace", "Module", "Method") }} | {{ get_graphql_doc("Type.methodName") }}
|
||||
|
||||
{{ get_typedoc_input("Namespace.Module.Method") }}
|
||||
|
||||
Результат:
|
||||
{{ get_typedoc_definition("Namespace.Module.Method", "IOutput") }}
|
||||
```
|
||||
|
||||
**2. Описание + пример (для сложных методов):**
|
||||
```markdown
|
||||
{{ get_typedoc_desc("Namespace.Module.Method") }}
|
||||
|
||||
{{ get_typedoc_input("Namespace.Module.Method") }}
|
||||
```
|
||||
|
||||
**3. Ссылки на типы данных:**
|
||||
```markdown
|
||||
У каждого аккаунта есть объект {{ get_graphql_definition("Account") }} в GraphQL-API
|
||||
```
|
||||
|
||||
### 🔧 Макросы и их применение
|
||||
|
||||
| Макрос | Назначение | Пример использования |
|
||||
|--------|------------|---------------------|
|
||||
| `get_sdk_doc` | Ссылка на SDK документацию | `{{ get_sdk_doc("Mutations", "Payments", "CreateDeposit") }}` |
|
||||
| `get_graphql_doc` | Ссылка на GraphQL операцию | `{{ get_graphql_doc("Query.getAccount") }}` |
|
||||
| `get_graphql_definition` | Ссылка на GraphQL тип | `{{ get_graphql_definition("Account") }}` |
|
||||
| `get_class_doc` | Ссылка на класс/метод SDK | `{{ get_class_doc("Document", "sign") }}` |
|
||||
| `get_typedoc_input` | **Полный пример** TypeScript вызова | `{{ get_typedoc_input("Mutations.Auth.Login") }}` |
|
||||
| `get_typedoc_definition` | **Структура интерфейса** | `{{ get_typedoc_definition("Mutations.Auth.Login", "IOutput") }}` |
|
||||
| `get_typedoc_desc` | Описание + примеры | `{{ get_typedoc_desc("Mutations.Auth.Login") }}` |
|
||||
| `get_typedoc_value` | Значение константы | `{{ get_typedoc_value("Constants.API_VERSION") }}` |
|
||||
|
||||
### 📝 Правила оформления
|
||||
|
||||
**ОБЯЗАТЕЛЬНО:**
|
||||
- Всегда используй `get_typedoc_input` для демонстрации **КАК вызывать** метод
|
||||
- Всегда используй `get_typedoc_definition` для показа **ЧТО возвращается**
|
||||
- Комбинируй SDK и GraphQL ссылки через ` | `: `{{ get_sdk_doc(...) }} | {{ get_graphql_doc(...) }}`
|
||||
|
||||
**ЖЕЛАТЕЛЬНО:**
|
||||
- Для сложных методов добавляй `get_typedoc_desc` в начало
|
||||
- Используй `get_graphql_definition` для ссылок на типы данных в тексте
|
||||
- Группируй связанные операции в одном разделе
|
||||
|
||||
**ФОРМАТ ССЫЛОК:**
|
||||
- SDK: `"Namespace", "Module", "Method"` (3 аргумента)
|
||||
- GraphQL: `"Type.methodName"` (точка между типом и методом)
|
||||
- Определения: просто имя типа `"TypeName"`
|
||||
@@ -1,96 +0,0 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Структура файлов шаблонов документов и алгоритм правки
|
||||
|
||||
## Основные директории и файлы
|
||||
|
||||
### 1. Определение типов и интерфейсов (cooptypes)
|
||||
**Путь:** `/cooptypes/src/cooperative/registry/[ID.DocumentName]/index.ts`
|
||||
|
||||
В этих файлах определяются:
|
||||
- Интерфейсы данных (`IAgendaMeet`, etc.)
|
||||
- Основная модель данных документа (`Model`)
|
||||
- HTML шаблон документа (`context`)
|
||||
- Переводы строк (`translations`)
|
||||
- Пример данных для тестирования (`exampleData`)
|
||||
|
||||
**Для изменения шаблона нужно править:**
|
||||
- Интерфейсы модели данных при изменении структуры
|
||||
- HTML в переменной `context` для изменения внешнего вида
|
||||
- Строки переводов в `translations.ru`
|
||||
|
||||
### 2. Схемы валидации (factory)
|
||||
**Путь:** `/factory/src/Schema/[SchemaName].ts`
|
||||
|
||||
Содержат:
|
||||
- JSON схемы для валидации данных
|
||||
- Определение обязательных полей
|
||||
|
||||
**При изменении структуры данных:**
|
||||
- Обновите соответствующую схему валидации
|
||||
- Обновите список обязательных полей в `required`
|
||||
|
||||
### 3. Фабрики документов (factory)
|
||||
**Путь:** `/factory/src/Actions/[ID.DocumentName].ts`
|
||||
|
||||
Обрабатывают:
|
||||
- Получение данных из разных источников
|
||||
- Сборку модели для шаблонизатора
|
||||
- Валидацию данных по схеме
|
||||
- Генерацию PDF
|
||||
|
||||
**При изменении логики сборки документа:**
|
||||
- Обновите метод `generateDocument()`
|
||||
- Добавьте новые источники данных
|
||||
|
||||
### 4. Шаблоны (factory)
|
||||
**Путь:** `/factory/src/Templates/[ID.DocumentName].ts`
|
||||
|
||||
Связывают:
|
||||
- Шаблон из cooptypes
|
||||
- Схему валидации
|
||||
- Метаданные документа
|
||||
|
||||
**После изменения в cooptypes:**
|
||||
- Убедитесь, что схема в Templates соответствует новой модели
|
||||
|
||||
### 5. Тесты (factory)
|
||||
**Путь:** `/factory/test/[category].test.ts`
|
||||
|
||||
Содержат:
|
||||
- Тестовые данные для генерации документов
|
||||
- Вызовы функции `testDocumentGeneration`
|
||||
|
||||
**После внесения изменений:**
|
||||
- Обновите тестовые данные в соответствии с новой структурой
|
||||
- Запустите тесты командой `pnpm test`
|
||||
|
||||
## Алгоритм внесения изменений
|
||||
|
||||
1. **Модификация типов**
|
||||
- Изменить файл в `/cooptypes/src/cooperative/registry/[ID.DocumentName]/index.ts`
|
||||
- Обновить интерфейсы, шаблон HTML и переводы
|
||||
|
||||
2. **Обновление схемы валидации**
|
||||
- Изменить соответствующую схему в `/factory/src/Schema/`
|
||||
- Убедиться, что обязательные поля совпадают с интерфейсом
|
||||
|
||||
3. **Компиляция библиотеки типов**
|
||||
- Выполнить `cd /cooptypes && pnpm build`
|
||||
|
||||
4. **Обновление тестовых данных**
|
||||
- Привести тестовые данные в соответствие с новой структурой
|
||||
|
||||
5. **Запуск тестов**
|
||||
- Выполнить `cd /factory && pnpm test [filename].test.ts`
|
||||
|
||||
## Особенности шаблонизации
|
||||
|
||||
- Используется Nunjucks для шаблонов
|
||||
- Поддерживаются конструкции: `{% if %}`, `{% for %}`, `{% trans %}`
|
||||
- Переменные вставляются через `{{ variable }}`
|
||||
- Переводы через `{% trans 'KEY' %}`
|
||||
@@ -1,261 +0,0 @@
|
||||
---
|
||||
description:
|
||||
globs: src/**/*.ts
|
||||
alwaysApply: false
|
||||
---
|
||||
# Фабрика Документов Кооперативов
|
||||
|
||||
## Общая Архитектура
|
||||
|
||||
Фабрика документов — это система генерации PDF документов для кооперативов, построенная на TypeScript с использованием MongoDB для хранения данных. Система состоит из трех основных частей:
|
||||
|
||||
1. **registry/** — JSON-шаблоны документов (статические данные)
|
||||
2. **factory/** — основная фабрика с логикой генерации
|
||||
3. **cooptypes/** — типы данных и интерфейсы
|
||||
|
||||
## Структура Registry
|
||||
|
||||
В корневой папке `registry/` находятся JSON файлы с номерными названиями, представляющие шаблоны документов:
|
||||
|
||||
### Основные документы:
|
||||
- `1.walletProgramAgreement.json` — соглашение о кошельке
|
||||
- `2.regulationElectronicSignature.json` — регламент электронной подписи
|
||||
- `3.privacyPolicy.json` — политика конфиденциальности
|
||||
- `4.userAgreement.json` — пользовательское соглашение
|
||||
- `50.CoopenomicsAgreement.json` — соглашение с партнерами
|
||||
- `100.participantApplication.json` — заявление участника
|
||||
- `101.selectBranchStatement.json` — заявление о выборе филиала
|
||||
|
||||
### Документы общих собраний (300-304):
|
||||
- `300.annualGeneralMeetingAgenda.json` — предложение повестки дня
|
||||
- `301.annualGeneralMeetingSovietDecision.json` — протокол заседания совета
|
||||
- `302.annualGeneralMeetingNotification.json` — уведомление о собрании
|
||||
- `303.annualGeneralMeetingVotingBallot.json` — бюллетень для голосования
|
||||
- `304.annualGeneralMeetingDecision.json` — протокол общего собрания
|
||||
|
||||
### Инвестиционные документы (1000+):
|
||||
- `1000.investAgreement.json` — инвестиционное соглашение
|
||||
- `1001.investByResultStatement.json` — заявление о зачете по результатам
|
||||
- `1002.investByResultAct.json` — акт зачета по результатам
|
||||
- `1005.investByMoneyStatement.json` — заявление о зачете денежных средств
|
||||
|
||||
### Структура JSON-шаблона:
|
||||
```json
|
||||
{
|
||||
"context": "<div>...HTML шаблон с переменными...</div>",
|
||||
"model": {...данные для примера...},
|
||||
"translation": {...переводы ключей...},
|
||||
"object_model": {...схема объектной модели...}
|
||||
}
|
||||
```
|
||||
|
||||
## Фабрика (factory/)
|
||||
|
||||
### Основные компоненты:
|
||||
|
||||
#### src/index.ts — Главный класс Generator
|
||||
```typescript
|
||||
export class Generator implements IGenerator {
|
||||
// Хранилище фабрик для каждого типа документа
|
||||
factories: { [K in Numbers]: DocFactory<IGenerate> }
|
||||
|
||||
// MongoDB коннектор
|
||||
public storage: MongoDBConnector
|
||||
|
||||
// Основной метод генерации
|
||||
async generate(data: IGenerate, options?: IGenerationOptions): Promise<IGeneratedDocument>
|
||||
}
|
||||
```
|
||||
|
||||
#### Архитектура Factory Pattern:
|
||||
- Базовый класс `DocFactory<T>` в `src/Factory/index.ts`
|
||||
- Каждый документ имеет свою фабрику в `src/Actions/`
|
||||
- Фабрики наследуются от `DocFactory` и реализуют метод `generateDocument()`
|
||||
|
||||
### Сервисы:
|
||||
|
||||
#### Services/Generator/ — PDF генерация
|
||||
- `PDFService` — конвертирует HTML в PDF через WeasyPrint
|
||||
- Использует шрифт Arial (base64)
|
||||
- Добавляет метаданные в PDF
|
||||
- Вычисляет SHA-256 хеш документа
|
||||
|
||||
#### Services/Templator/ — Шаблонизация
|
||||
- Основан на Nunjucks
|
||||
- Поддерживает кастомное расширение `{% trans %}` для переводов
|
||||
- Рендерит HTML из шаблона с подстановкой переменных
|
||||
|
||||
#### Services/Validator/ — Валидация
|
||||
- Использует AJV для JSON Schema валидации
|
||||
- Поддерживает кастомные форматы (телефон)
|
||||
- Локализация ошибок на русском языке
|
||||
|
||||
#### Services/Databazor/ — База данных
|
||||
- `MongoDBConnector` — работа с MongoDB
|
||||
- `DataService` — абстракция над данными
|
||||
- Коллекции: `deltas`, `actions`, `documents`, и другие
|
||||
|
||||
### Модели данных (src/Models/):
|
||||
|
||||
#### Основные типы пользователей:
|
||||
- `Individual` — физические лица (ФИО, паспорт, адрес)
|
||||
- `Organization` — организации (ИНН, ОГРН, представитель)
|
||||
- `Entrepreneur` — ИП (ФИО + ИНН/ОГРН)
|
||||
|
||||
#### Кооперативные данные:
|
||||
- `Cooperative` — данные кооператива
|
||||
- `PaymentMethod` — платежные методы
|
||||
- `Vars` — переменные кооператива
|
||||
- `Project` — проекты
|
||||
|
||||
### Система Action-ов:
|
||||
|
||||
Каждый документ имеет Action класс в `src/Actions/` с методом `generateDocument()`:
|
||||
|
||||
1. **Получение шаблона** — из локального Registry или MongoDB
|
||||
2. **Сбор данных** — пользователь, кооператив, переменные, специфичные данные
|
||||
3. **Валидация** — проверка по JSON схеме
|
||||
4. **Рендеринг** — HTML из шаблона + данные
|
||||
5. **PDF генерация** — HTML → PDF с метаданными
|
||||
6. **Сохранение** — в MongoDB (если не skip_save)
|
||||
|
||||
## Система типов (cooptypes/)
|
||||
|
||||
### cooperative/registry/ — Типы документов
|
||||
Каждый документ имеет папку с интерфейсами:
|
||||
- `Action` — входные данные для генерации
|
||||
- `Model` — модель данных для шаблона
|
||||
- `Template` — структура шаблона
|
||||
|
||||
### contracts/ — Блокчейн контракты
|
||||
- `registrator/` — регистрация кооперативов
|
||||
- `soviet/` — управление советом
|
||||
- `meet/` — общие собрания
|
||||
- `wallet/`, `capital/`, `fund/` — финансовые операции
|
||||
|
||||
## База данных MongoDB
|
||||
|
||||
### Основные коллекции:
|
||||
|
||||
#### deltas — Состояние блокчейна
|
||||
```javascript
|
||||
{
|
||||
block_num: number,
|
||||
present: boolean,
|
||||
code: string, // название контракта
|
||||
scope: string, // область действия
|
||||
table: string, // имя таблицы
|
||||
primary_key: string,
|
||||
value: {...} // данные записи
|
||||
}
|
||||
```
|
||||
|
||||
#### actions — Действия блокчейна
|
||||
```javascript
|
||||
{
|
||||
block_num: number,
|
||||
account: string,
|
||||
name: string, // имя действия
|
||||
receiver: string,
|
||||
data: {...} // данные действия
|
||||
}
|
||||
```
|
||||
|
||||
#### documents — Сгенерированные документы
|
||||
```javascript
|
||||
{
|
||||
hash: string, // SHA-256 хеш
|
||||
binary: Uint8Array, // PDF данные
|
||||
html: string, // HTML исходник
|
||||
meta: { // метаданные
|
||||
title: string,
|
||||
created_at: string,
|
||||
lang: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Таблицы данных:
|
||||
- `coops` — кооперативы
|
||||
- `meets` — собрания
|
||||
- `questions` — вопросы собраний
|
||||
- `decisions` — решения совета
|
||||
- `individuals` — физические лица
|
||||
- `organizations` — организации
|
||||
- `entrepreneurs` — ИП
|
||||
- `paymentMethods` — платежные методы
|
||||
- `vars` — переменные кооперативов
|
||||
|
||||
## Генерация документов
|
||||
|
||||
### Процесс генерации:
|
||||
1. **Вызов** `generator.generate(action, options)`
|
||||
2. **Поиск фабрики** по `registry_id`
|
||||
3. **Загрузка шаблона** (локально или из БД)
|
||||
4. **Сбор данных** из MongoDB по `coopname`, `username`, `block_num`
|
||||
5. **Создание модели** — объединение всех данных
|
||||
6. **Валидация** модели по JSON схеме
|
||||
7. **Рендеринг HTML** через Nunjucks
|
||||
8. **Генерация PDF** через WeasyPrint
|
||||
9. **Добавление метаданных** в PDF
|
||||
10. **Вычисление хеша** SHA-256
|
||||
11. **Сохранение** в MongoDB
|
||||
|
||||
### Пример использования:
|
||||
```typescript
|
||||
const generator = new Generator()
|
||||
await generator.connect(mongoUri)
|
||||
|
||||
const document = await generator.generate({
|
||||
registry_id: '300',
|
||||
coopname: 'voskhod',
|
||||
username: 'ant',
|
||||
block_num: 0,
|
||||
meet: {...},
|
||||
questions: [...]
|
||||
})
|
||||
```
|
||||
|
||||
## Особенности реализации
|
||||
|
||||
### Шаблонизация:
|
||||
- HTML шаблоны с CSS стилями
|
||||
- Переменные в формате `{{variable.field}}`
|
||||
- Условная логика `{% if condition %}`
|
||||
- Циклы `{% for item in array %}`
|
||||
- Переводы `{% trans 'KEY', var1, var2 %}`
|
||||
|
||||
### Подписи:
|
||||
- Цифровые подписи вместо физических
|
||||
- Текст "Подписано электронной подписью"
|
||||
- Убраны подчеркивания для подписей
|
||||
|
||||
### Типы собраний:
|
||||
- `regular` — очередное
|
||||
- `extraordinary` — внеочередное
|
||||
- Условная логика в шаблонах
|
||||
|
||||
### Филиалы:
|
||||
- `coop.is_branched` — проверка на наличие филиалов
|
||||
- "пайщиков" vs "уполномоченных" в зависимости от типа
|
||||
|
||||
### Форматирование дат:
|
||||
- Формат: "г. Москва, 15 декабря 2024 г."
|
||||
- Без кавычек вокруг дат
|
||||
- Запятая после города
|
||||
|
||||
## Тестирование
|
||||
|
||||
### test/utils/index.ts — Тестовые утилиты:
|
||||
- `preLoading()` — инициализация тестовых данных
|
||||
- Создание кооператива, пользователей, платежных методов
|
||||
- Настройка данных собраний и решений
|
||||
- Очистка временных файлов
|
||||
|
||||
### Тестовые данные:
|
||||
- Кооператив "ВОСХОД"
|
||||
- Пользователи: ant, individual, entrepreneur
|
||||
- Организации: voskhod, branch, exampleorg
|
||||
- Собрания с вопросами и решениями
|
||||
|
||||
Фабрика поддерживает полный цикл создания документов кооператива от заявлений до протоколов собраний с возможностью кастомизации под разные типы кооперативов и требования.
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
ref: testnet
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Debug info
|
||||
@@ -76,47 +76,19 @@ jobs:
|
||||
echo "CMD [\"pnpm\", \"-F\", \"coop-notificator\", \"run\", \"start\"]" >> Dockerfile.notificator
|
||||
docker build -t dicoop/notificator:${{ env.DOCKER_TAG }} -f Dockerfile.notificator .
|
||||
docker push dicoop/notificator:${{ env.DOCKER_TAG }}
|
||||
|
||||
- name: Build notifications image
|
||||
run: |
|
||||
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.notifications
|
||||
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/notifications\", \"run\", \"sync\"]" >> Dockerfile.notifications
|
||||
docker build -t dicoop/notifications:${{ env.DOCKER_TAG }} -f Dockerfile.notifications .
|
||||
docker push dicoop/notifications:${{ env.DOCKER_TAG }}
|
||||
|
||||
|
||||
# Отправка хука для деплоя
|
||||
- name: Trigger deployment webhook
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/latest ]]; then
|
||||
# Хук для тестнета
|
||||
curl -X POST ${{ vars.TESTNET_WEBHOOK_URL }} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '${{ env.DOCKER_TAG }}'
|
||||
elif [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
# Хук для продакшена
|
||||
curl -X POST ${{ vars.PRODUCTION_WEBHOOK_URL }} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '${{ env.DOCKER_TAG }}'
|
||||
else
|
||||
# Хук для тестнета (обычная ветка)
|
||||
# Хук для тестнета
|
||||
curl -X POST ${{ vars.TESTNET_WEBHOOK_URL }} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '${{ env.DOCKER_TAG }}'
|
||||
fi
|
||||
|
||||
# Уведомление в Telegram об успехе
|
||||
- name: Telegram notify success
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
curl -s -X POST https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \
|
||||
-d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \
|
||||
-d text="✅ [GITHUB MONO] Успешная сборка контейнеров: $GITHUB_REPOSITORY ($GITHUB_REF) [${{ env.DOCKER_TAG }}]"
|
||||
|
||||
# Уведомление в Telegram об ошибке
|
||||
- name: Telegram notify failure
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
curl -s -X POST https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \
|
||||
-d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \
|
||||
-d text="❌ [GITHUB MONO] Ошибка при сборке контейнеров: $GITHUB_REPOSITORY ($GITHUB_REF) [${{ env.DOCKER_TAG }}]"
|
||||
fi
|
||||
@@ -5,6 +5,3 @@ blockchain-data/
|
||||
scripts/changelog-prompt.md
|
||||
scripts/changelog-release.md
|
||||
scripts/release-info.md
|
||||
components/docs/docs/sdk
|
||||
dist/
|
||||
.env
|
||||
|
||||
Vendored
+5
-48
@@ -1,59 +1,16 @@
|
||||
{
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.guides.bracketPairs": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint":"explicit"
|
||||
},
|
||||
"eslint.run": "onType",
|
||||
"eslint.validate": ["javascript", "typescript", "vue"],
|
||||
"i18n-ally.localesPaths": ["src/i18n"],
|
||||
"typescript.format.enable": true,
|
||||
"typescript.format.indentSwitchCase": false,
|
||||
"typescript.validate.enable": true,
|
||||
"notebook.defaultFormatter": "Vue.volar",
|
||||
|
||||
// Оптимизация для монорепозитория
|
||||
"typescript.preferences.useAliasesForRenames": false,
|
||||
"typescript.preferences.include": false,
|
||||
"typescript.disableAutomaticTypeAcquisition": true,
|
||||
"typescript.preferences.includePackageJsonAutoImports": "off",
|
||||
"typescript.suggest.autoImports": true,
|
||||
"typescript.suggest.paths": true,
|
||||
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||
"typescript.workspaceSymbols.scope": "currentProject",
|
||||
|
||||
// Настройки для снижения нагрузки
|
||||
"files.watcherExclude": {
|
||||
"**/node_modules/**": true,
|
||||
"**/dist/**": true,
|
||||
"**/.git/objects/**": true,
|
||||
"**/.git/subtree-cache/**": true,
|
||||
"**/node_modules/*/**": true,
|
||||
"**/.cache/**": true,
|
||||
"**/.quasar/**": true,
|
||||
"**/*.tsbuildinfo": true
|
||||
},
|
||||
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/dist": true,
|
||||
"**/.cache": true,
|
||||
"**/.quasar": true,
|
||||
"**/*.tsbuildinfo": true
|
||||
},
|
||||
|
||||
"files.exclude": {
|
||||
"**/.cache": true,
|
||||
"**/*.tsbuildinfo": true,
|
||||
"**/node_modules/.cache": true
|
||||
},
|
||||
|
||||
// TypeScript server настройки
|
||||
"typescript.tsserver.maxTsServerMemory": 8192,
|
||||
"typescript.tsserver.watchOptions": {
|
||||
"excludeFiles": [
|
||||
"**/node_modules/**/*",
|
||||
"**/dist/**/*",
|
||||
"**/.cache/**/*"
|
||||
]
|
||||
}
|
||||
"typescript.validate.enable": true
|
||||
}
|
||||
|
||||
@@ -1,87 +1,3 @@
|
||||
# v2025.7.1-1
|
||||
|
||||
В этом релизе реализованы механизмы возврата паевого взноса пайщика и инструменты управления этим процессом для членов совета. Также внесены визуальные доработки интерфейсов для улучшения восприятия информации.
|
||||
|
||||
✨ Новые функции
|
||||
- [#276](https://github.com/coopenomics/mono/issues/276): Реализовать путь возврата паевого взноса из кошелька пайщика
|
||||
- [#281](https://github.com/coopenomics/mono/issues/281): Генерация заявления на возврат паевого взноса
|
||||
- [#282](https://github.com/coopenomics/mono/issues/282): Генерация решения совета на возврат паевого взноса
|
||||
- [#278](https://github.com/coopenomics/mono/issues/278): Введение методов управления возвратами паевых взносов в контроллере
|
||||
- [#279](https://github.com/coopenomics/mono/issues/279): Отобразить исходящие платежи с кнопками управления в реестре платежей для совета
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#286](https://github.com/coopenomics/mono/issues/286): Поправить ошибки склонений времени
|
||||
- [#262](https://github.com/coopenomics/mono/issues/262): Баг: рабочий стол совета включается, однако, страница всегда открывается со стола пайщика
|
||||
- [#261](https://github.com/coopenomics/mono/issues/261): Баг: первая загрузка переадресует на главную страницу всегда - прямой переход на собрание становится недоступен.
|
||||
|
||||
🔧 Улучшения
|
||||
- [#285](https://github.com/coopenomics/mono/issues/285): Корректировка дизайна кошелька, профиля, повестки совета, реестра документов, реестра платежей
|
||||
- [#284](https://github.com/coopenomics/mono/issues/284): Разместить кошелек на главную вместо профиля
|
||||
- [#283](https://github.com/coopenomics/mono/issues/283): Ввести лоадер на переходе между рабочими столами
|
||||
- [#280](https://github.com/coopenomics/mono/issues/280): Мигрировать имеющиеся данные о входящих платежах в новую модель
|
||||
- [#277](https://github.com/coopenomics/mono/issues/277): Рефакторинг модуля платежей: переход на унифицированную модель входящего и исходящего платежа
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# v2025.6.14
|
||||
|
||||
Разработан модуль для проведения очередных общих собраний пайщиков. Исправлены баги, внесены улучшения пользовательского интерфейса.
|
||||
|
||||
✨ Новые функции
|
||||
- [#264](https://github.com/coopenomics/mono/issues/264): Разработан смарт-контракт общего собрания пайщиков (meet)
|
||||
- [#263](https://github.com/coopenomics/mono/issues/263): Реализован модуль оповещений на электронные почты по жизненному циклу общего собрания пайщиков
|
||||
- [#273](https://github.com/coopenomics/mono/issues/273): Встроены реальные шаблоны документов общего собрания
|
||||
- [#268](https://github.com/coopenomics/mono/issues/268): Добавлена страница результатов общего собрания
|
||||
- [#267](https://github.com/coopenomics/mono/issues/267): Добавлена страница просмотра и скачивания бюллетеней и уведомлений по собранию
|
||||
- [#270](https://github.com/coopenomics/mono/issues/270): Ссылка в оповещении ведет на страницу собрания с документом-уведомлением для подписи
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#262](https://github.com/coopenomics/mono/issues/262): Исправлено некорректное открытие рабочего стола совета
|
||||
- [#261](https://github.com/coopenomics/mono/issues/261): Исправлена ошибка с редиректом при первой загрузке и прямом переходе на собрание
|
||||
- [#259](https://github.com/coopenomics/mono/issues/259): Исправлены отступы в мобильной карточке пайщика
|
||||
- [#258](https://github.com/coopenomics/mono/issues/258): Убран hover-эффект на документе и пайщике в таблице
|
||||
|
||||
🔧 Улучшения
|
||||
- [#274](https://github.com/coopenomics/mono/issues/274): Настроена рассылка оповещений на почту при получении решения о проведении собрания
|
||||
- [#272](https://github.com/coopenomics/mono/issues/272): Подписанные уведомления сохраняются и извлекаются из реестра по Graph-QL
|
||||
- [#271](https://github.com/coopenomics/mono/issues/271): Ведется подсчет количества пайщиков в каждом кооперативе при добавлении и удалении
|
||||
- [#260](https://github.com/coopenomics/mono/issues/260): Введен счетчик количества пайщиков в кооперативе на контракте регистратора
|
||||
- [#256](https://github.com/coopenomics/mono/issues/256): Отображается статус членства каждого пайщика
|
||||
- [#255](https://github.com/coopenomics/mono/issues/255): В разделе Платежи отображается ФИО/Наименование плательщика
|
||||
- [#269](https://github.com/coopenomics/mono/issues/269): Реализована рассылка уведомлений перед началом собрания
|
||||
- [#265](https://github.com/coopenomics/mono/issues/265): Проведена отладка и тестирование процесса общего собрания пайщиков
|
||||
- [#266](https://github.com/coopenomics/mono/issues/266): Протестированы все процессы общего собрания
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# v2025.5.14
|
||||
|
||||
В этом релизе реализован новый стандарт передачи и хранения документов по блокчейну с поддержкой неограниченного количества подписей и их валидацией. Также внесены улучшения в интерфейс и исправлены ошибки.
|
||||
|
||||
✨ Новые функции
|
||||
- [#252](https://github.com/coopenomics/mono/issues/252): Внедрение обновленного стандарта хранения и передачи документов по блокчейну
|
||||
- [#251](https://github.com/coopenomics/mono/issues/251): Реализация версионированного мигратора данных для контроллера кооператива
|
||||
- [#244](https://github.com/coopenomics/mono/issues/244): Обновление стандарта сборки документов и переход на хэш-идентификаторы
|
||||
|
||||
🐛 Исправления ошибок
|
||||
- [#249](https://github.com/coopenomics/mono/issues/249): Исправлена спутанная маршрутизация между рабочими столами кооперативов
|
||||
- [#253](https://github.com/coopenomics/mono/issues/253): Исправлена избыточная точность суммы оплаты в заявлении на вступление
|
||||
|
||||
🔧 Улучшения
|
||||
- [#259](https://github.com/coopenomics/mono/issues/259): Исправлены отступы в мобильной карточке пайщика на странице пайщиков
|
||||
- [#258](https://github.com/coopenomics/mono/issues/258): Удалён hover-эффект для документов и пайщиков в таблице
|
||||
- [#257](https://github.com/coopenomics/mono/issues/257): Добавлено сохранение светлой/тёмной темы в localStorage и восстановление при загрузке страницы
|
||||
- [#256](https://github.com/coopenomics/mono/issues/256): Отображение статуса членства каждого пайщика в разделе "Пайщики"
|
||||
- [#255](https://github.com/coopenomics/mono/issues/255): Отображение ФИО/Наименования плательщика в разделе "Платежи"
|
||||
|
||||
#releases
|
||||
|
||||
---
|
||||
|
||||
# v2025.5.2
|
||||
|
||||
В этом релизе рабочие столы переведены на серверный рендеринг, что улучшает стабильность развертывания и упрощает автоматизацию поставки ПО. Данный релиз является подготовительным к переходу на новый стандарт цифровых документов на платформе.
|
||||
|
||||
-129
@@ -1,129 +0,0 @@
|
||||
# 📋 Резюме создания компонентов Notifications
|
||||
|
||||
## ✅ Что создано
|
||||
|
||||
### 1. 📚 Библиотека `@monocoop/notifications`
|
||||
**Расположение:** `components/notifications/`
|
||||
|
||||
**Функции:**
|
||||
- ✅ Типизированные интерфейсы для workflow с Zod
|
||||
- ✅ Builder паттерн для создания workflow
|
||||
- ✅ Базовые шаблоны для email, in-app, push, SMS
|
||||
- ✅ Автоматическая конвертация Zod схем в JSON Schema для Novu
|
||||
- ✅ Экспорт всех workflow для использования в других пакетах
|
||||
|
||||
**Структура:**
|
||||
```
|
||||
src/
|
||||
├── types/ # Базовые типы и интерфейсы
|
||||
├── base/ # Утилиты и настройки по умолчанию
|
||||
├── workflows/ # Папки с workflow
|
||||
│ └── welcome/ # Пример приветственного workflow
|
||||
└── index.ts # Главный экспорт
|
||||
```
|
||||
|
||||
### 2. 🚀 NestJS приложение `@monocoop/notificator2`
|
||||
**Расположение:** `components/notificator2/`
|
||||
|
||||
**Функции:**
|
||||
- ✅ Автоматический upsert всех workflow в Novu при запуске
|
||||
- ✅ RESTful API для триггера уведомлений
|
||||
- ✅ Типизированная валидация payload
|
||||
- ✅ Health check endpoints
|
||||
- ✅ Использует библиотеку notifications для типов
|
||||
|
||||
**API Endpoints:**
|
||||
- `GET /api/notifications/health` - Health check
|
||||
- `GET /api/notifications/workflows` - Список workflow
|
||||
- `POST /api/notifications/trigger` - Универсальный триггер
|
||||
- `POST /api/notifications/trigger/welcome` - Триггер welcome workflow
|
||||
- `POST /api/notifications/workflows/upsert-all` - Принудительный upsert
|
||||
|
||||
## 🔧 Как использовать
|
||||
|
||||
### 1. Настройка библиотеки notifications
|
||||
```bash
|
||||
cd components/notifications
|
||||
pnpm install # или npm install
|
||||
pnpm build # для компиляции TypeScript
|
||||
```
|
||||
|
||||
### 2. Настройка notificator2
|
||||
```bash
|
||||
cd components/notificator2
|
||||
pnpm install # или npm install
|
||||
|
||||
# Настройка окружения
|
||||
cp .env.example .env
|
||||
# Добавить NOVU_API_KEY в .env
|
||||
|
||||
# Запуск
|
||||
pnpm start:dev
|
||||
```
|
||||
|
||||
### 3. Добавление нового workflow
|
||||
|
||||
**В библиотеке notifications:**
|
||||
```typescript
|
||||
// components/notifications/src/workflows/order/order-workflow.ts
|
||||
export const orderWorkflow = WorkflowBuilder
|
||||
.create<OrderPayload>()
|
||||
.name('Order Confirmation')
|
||||
.workflowId('order-confirmation')
|
||||
.payloadSchema(orderPayloadSchema)
|
||||
.addSteps([...])
|
||||
.build();
|
||||
```
|
||||
|
||||
**Регистрация в index.ts:**
|
||||
```typescript
|
||||
// components/notifications/src/workflows/index.ts
|
||||
import { orderWorkflow } from './order';
|
||||
|
||||
export const allWorkflows = [
|
||||
welcomeWorkflow,
|
||||
orderWorkflow, // ← добавить новый workflow
|
||||
];
|
||||
```
|
||||
|
||||
### 4. Использование API
|
||||
|
||||
**Триггер welcome workflow:**
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/api/notifications/trigger/welcome \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"subscriberId": "user-123",
|
||||
"email": "user@example.com",
|
||||
"payload": {
|
||||
"userName": "Иван Иванов",
|
||||
"userEmail": "user@example.com",
|
||||
"age": 25
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
## 🎯 Преимущества архитектуры
|
||||
|
||||
1. **Типобезопасность** - Zod схемы обеспечивают валидацию на уровне TypeScript и runtime
|
||||
2. **Разделение ответственности** - Библиотека содержит только типы, сервер - логику
|
||||
3. **Расширяемость** - Легко добавлять новые workflow
|
||||
4. **Автоматизация** - Workflow автоматически синхронизируются с Novu
|
||||
5. **Переиспользование** - Типы можно использовать в других частях системы
|
||||
|
||||
## 🔄 Workflow при запуске
|
||||
|
||||
1. **Запуск notificator2** →
|
||||
2. **Чтение всех workflow из библиотеки** →
|
||||
3. **Проверка существования в Novu** →
|
||||
4. **Создание/обновление workflow** →
|
||||
5. **Готов к приёму запросов на триггеры**
|
||||
|
||||
## 📁 Структура как в testFramework2.ts
|
||||
|
||||
Вся логика из `testFramework2.ts` была перенесена в structured архитектуру:
|
||||
- ✅ `buildWorkflowData` → `WorkflowBuilder`
|
||||
- ✅ `baseSteps` → `createEmailStep`, `createInAppStep`, etc.
|
||||
- ✅ `upsertWorkflow` → `NovuService.upsertWorkflow`
|
||||
- ✅ `triggerWorkflow` → `NovuService.triggerWorkflow`
|
||||
- ✅ Типизация payload → Zod схемы + TypeScript типы
|
||||
Vendored
BIN
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@coopenomics/boot",
|
||||
"type": "module",
|
||||
"version": "2025.7.23-1",
|
||||
"version": "2025.5.5-2",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "",
|
||||
|
||||
@@ -607,10 +607,10 @@ export default class Blockchain {
|
||||
}
|
||||
|
||||
async registerUser(
|
||||
params: RegistratorContract.Actions.RegisterUser.IRegisterUser,
|
||||
params: RegistratorContract.Actions.RegisterUser.IRegistrerUser,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
console.dir(params, { depth: null })
|
||||
|
||||
await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
@@ -623,7 +623,9 @@ export default class Blockchain {
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: params,
|
||||
data: {
|
||||
...params,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -638,7 +640,7 @@ export default class Blockchain {
|
||||
|
||||
async transfer(params: TokenContract.Actions.Transfer.ITransfer) {
|
||||
await this.update_pass_instance()
|
||||
console.dir(params, { depth: null })
|
||||
|
||||
const result = await this.api.transact(
|
||||
{
|
||||
actions: [
|
||||
@@ -746,7 +748,7 @@ export default class Blockchain {
|
||||
name: SovietContract.Actions.Decisions.VoteFor.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: params.username,
|
||||
actor: params.member,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
@@ -831,7 +833,7 @@ export default class Blockchain {
|
||||
}
|
||||
|
||||
async ConfirmPayment(
|
||||
params: GatewayContract.Actions.CompleteIncome.ICompleteIncome,
|
||||
params: GatewayContract.Actions.CompleteIncome.ICompeteIncome,
|
||||
) {
|
||||
await this.update_pass_instance()
|
||||
|
||||
@@ -921,7 +923,7 @@ export default class Blockchain {
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Шаблон создан: ', params.registry_id)
|
||||
console.log('Шаблон создан: ', params)
|
||||
}
|
||||
|
||||
async createTranslation(
|
||||
@@ -953,7 +955,7 @@ export default class Blockchain {
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Перевод создан: ', params.registry_id)
|
||||
console.log('Перевод создан: ', params)
|
||||
}
|
||||
|
||||
async createProgram(
|
||||
|
||||
@@ -65,11 +65,6 @@ export default [
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/fund'),
|
||||
target: 'fund',
|
||||
},
|
||||
{
|
||||
name: 'ledger',
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/ledger'),
|
||||
target: 'ledger',
|
||||
},
|
||||
{
|
||||
name: 'contributor',
|
||||
path: path.resolve(process.cwd(), '../contracts/build/contracts/contributor'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { startInfra } from './infra'
|
||||
import { startCoop } from './cooperative'
|
||||
import { startInfra } from "./infra"
|
||||
import { startCoop } from "./cooperative"
|
||||
|
||||
export async function boot() {
|
||||
await startInfra()
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import type { Cooperative } from 'cooptypes'
|
||||
import type { Keys } from '../types'
|
||||
import axios from 'axios'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Registry } from '@coopenomics/factory'
|
||||
import { Cooperative as TCooperative } from 'cooptypes'
|
||||
import type { Account, Contract, Keys } from '../types'
|
||||
import config, { GOVERN_SYMBOL, SYMBOL } from '../configs'
|
||||
import Blockchain from '../blockchain'
|
||||
import { sendPostToCoopbackWithSecret, sleep } from '../utils'
|
||||
import { generateRandomSHA256 } from '../utils/randomHash'
|
||||
|
||||
const test_hash
|
||||
@@ -11,23 +15,11 @@ const test_sign
|
||||
const test_pkey = 'EOS5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzxrLg3J'
|
||||
const test_meta = JSON.stringify({})
|
||||
|
||||
const document: Cooperative.Document.ISignedDocument2 = {
|
||||
const document = {
|
||||
hash: test_hash,
|
||||
signatures: [
|
||||
{
|
||||
id: 1,
|
||||
signed_hash: test_hash,
|
||||
public_key: test_pkey,
|
||||
signed_at: '2025-05-14T12:22:26',
|
||||
meta: test_meta,
|
||||
signer: 'cooperative1',
|
||||
signature: test_sign,
|
||||
},
|
||||
],
|
||||
signature: test_sign,
|
||||
public_key: test_pkey,
|
||||
meta: test_meta,
|
||||
version: '1.0.0',
|
||||
doc_hash: test_hash,
|
||||
meta_hash: test_hash,
|
||||
}
|
||||
|
||||
export class CooperativeClass {
|
||||
@@ -93,13 +85,8 @@ export class CooperativeClass {
|
||||
console.log('Голосуем по решению в провайдере')
|
||||
|
||||
await this.blockchain.votefor({
|
||||
version: '1.0.0',
|
||||
signed_at: '2025-05-14T12:22:26',
|
||||
signed_hash: test_hash,
|
||||
signature: test_sign,
|
||||
public_key: test_pkey,
|
||||
coopname: config.provider,
|
||||
username: config.provider_chairman,
|
||||
member: config.provider_chairman,
|
||||
decision_id: 1,
|
||||
})
|
||||
|
||||
@@ -127,7 +114,12 @@ export class CooperativeClass {
|
||||
administrator: config.provider,
|
||||
username: username!,
|
||||
agreement_type: 'wallet',
|
||||
document,
|
||||
document: { // отправляем произвольный документ с валидной подписью
|
||||
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
|
||||
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
|
||||
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
|
||||
meta: '{}',
|
||||
},
|
||||
})
|
||||
|
||||
console.log('Переводим аккаунт в кооператив')
|
||||
@@ -149,7 +141,7 @@ export class CooperativeClass {
|
||||
})
|
||||
|
||||
console.log('Переводим инициализационные токены')
|
||||
await this.blockchain.transfer({ from: 'eosio', to: account.username, quantity: `100.0000 ${SYMBOL}`, memo: '' })
|
||||
await this.blockchain.transfer({ from: 'eosio', to: username, quantity: `100.0000 ${SYMBOL}`, memo: '' })
|
||||
|
||||
console.log(`Арендуем ресурсы кооперативу`)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@coopenomics/cleos",
|
||||
"version": "2025.7.23-1",
|
||||
"version": "2025.5.5-2",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"scripts": {
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
Длинна типа name не должна превышать 12 символов и не должна содержать специальных знаков.
|
||||
@@ -30,7 +30,6 @@ macro(add_contract_build name)
|
||||
endmacro()
|
||||
|
||||
# Добавляем все контракты
|
||||
add_contract_build(ledger)
|
||||
add_contract_build(meet)
|
||||
add_contract_build(loan)
|
||||
add_contract_build(wallet)
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -6,7 +6,6 @@
|
||||
#include "src/addaccum.cpp"
|
||||
#include "src/addcirculate.cpp"
|
||||
#include "src/addexpense.cpp"
|
||||
#include "src/accumfee.cpp"
|
||||
#include "src/addinitial.cpp"
|
||||
#include "src/authorize.cpp"
|
||||
#include "src/delfund.cpp"
|
||||
|
||||
@@ -44,10 +44,10 @@ class [[eosio::contract(FUND)]] fund : public eosio::contract {
|
||||
eosio::name type, uint64_t fund_id);
|
||||
|
||||
// атомарные транзакции фондового кошелька
|
||||
// паевой фонд
|
||||
// паевый фонд
|
||||
[[eosio::action]] void addcirculate(
|
||||
eosio::name coopname,
|
||||
eosio::asset quantity); /// < добавить сумму в паевой фонд
|
||||
eosio::asset quantity); /// < добавить сумму в паевый фонд
|
||||
[[eosio::action]] void subcirculate(
|
||||
eosio::name coopname,
|
||||
eosio::asset quantity,
|
||||
@@ -65,9 +65,6 @@ class [[eosio::contract(FUND)]] fund : public eosio::contract {
|
||||
[[eosio::action]] void addexpense(eosio::name coopname, uint64_t fund_id,
|
||||
eosio::asset quantity);
|
||||
|
||||
// добавить членский взнос на накопительный счет кооператива для дальнейшего управления
|
||||
[[eosio::action]] void accumfee(eosio::name coopname, eosio::asset quantity);
|
||||
|
||||
//счет вступительных взносов
|
||||
[[eosio::action]] void addinitial(eosio::name coopname,
|
||||
eosio::asset quantity);
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* @brief Атомарный метод добавления членского взноса на накопительный счет кооператива.
|
||||
* Минует процесс spreadamount и добавляет средства напрямую на accumulative_expense_account
|
||||
* для дальнейшего управления кооперативом (распределение по фондам или использование на расходы).
|
||||
*
|
||||
* @param coopname Имя кооператива
|
||||
* @param quantity Сумма членского взноса
|
||||
*/
|
||||
[[eosio::action]] void fund::accumfee(eosio::name coopname, eosio::asset quantity) {
|
||||
name payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
|
||||
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, payer, [&](auto &w) {
|
||||
w.accumulative_expense_account.available += quantity;
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// атомарные транзакции фондового кошелька
|
||||
// паевой счет
|
||||
// паевый счет
|
||||
[[eosio::action]] void fund::addcirculate(
|
||||
eosio::name coopname,
|
||||
eosio::asset quantity) /// < добавить сумму в паевой фонд
|
||||
eosio::asset quantity) /// < добавить сумму в паевый фонд
|
||||
{
|
||||
name payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
|
||||
|
||||
@@ -14,12 +14,6 @@ void gateway::createoutpay(eosio::name coopname, eosio::name username, checksum2
|
||||
eosio::check(confirm_callback != ""_n, "Действие для коллбэка-успеха должено быть установлено");
|
||||
eosio::check(decline_callback != ""_n, "Действие для коллбэка-отлонения должно быть установлено");
|
||||
|
||||
// Валидируем callback действия если они от wallet контракта
|
||||
if (callback_contract == _wallet) {
|
||||
Wallet::get_valid_wallet_action(confirm_callback);
|
||||
Wallet::get_valid_wallet_action(decline_callback);
|
||||
}
|
||||
|
||||
auto outcome = Gateway::get_outcome(coopname, outcome_hash);
|
||||
|
||||
eosio::check(!outcome.has_value(), "Объект возврата уже существует с указанным хэшем");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
void gateway::outcomplete(eosio::name coopname, checksum256 outcome_hash){
|
||||
require_auth(coopname);
|
||||
|
||||
auto exist_outcome = Gateway::get_outcome(coopname, outcome_hash);
|
||||
eosio::check(exist_outcome.has_value(), "Объект возврата не существует с указанным хэшем");
|
||||
|
||||
@@ -8,15 +9,13 @@ void gateway::outcomplete(eosio::name coopname, checksum256 outcome_hash){
|
||||
auto outcome = outcomes.find(exist_outcome -> id);
|
||||
|
||||
eosio::check(outcome -> status == "pending"_n, "Только принятые заявления на вывод могут быть обработаны");
|
||||
|
||||
// Используем интерфейс для типизированного вызова callback действия
|
||||
Action::send<completewthd_interface>(
|
||||
|
||||
action(
|
||||
permission_level{ _gateway, "active"_n},
|
||||
outcome -> callback_contract,
|
||||
outcome -> confirm_callback,
|
||||
_gateway,
|
||||
coopname,
|
||||
outcome -> outcome_hash
|
||||
);
|
||||
std::make_tuple(coopname, outcome -> outcome_hash)
|
||||
).send();
|
||||
|
||||
outcomes.erase(outcome);
|
||||
};
|
||||
|
||||
@@ -2,22 +2,19 @@ void gateway::outdecline(eosio::name coopname, checksum256 outcome_hash, std::st
|
||||
require_auth(coopname);
|
||||
|
||||
auto exist_outcome = Gateway::get_outcome(coopname, outcome_hash);
|
||||
eosio::check(exist_outcome.has_value(), "Объект возврата не существует с указанным хэшем");
|
||||
eosio::check(!exist_outcome.has_value(), "Объект возврата уже существует с указанным хэшем");
|
||||
Gateway::outcomes_index outcomes(_gateway, coopname.value);
|
||||
|
||||
auto outcome = outcomes.find(exist_outcome -> id);
|
||||
|
||||
eosio::check(outcome -> status == "pending"_n, "Только принятые заявления на вывод могут быть обработаны");
|
||||
|
||||
// Используем интерфейс для типизированного вызова callback действия
|
||||
Action::send<declinewthd_interface>(
|
||||
outcome -> callback_contract,
|
||||
outcome -> decline_callback,
|
||||
_gateway,
|
||||
coopname,
|
||||
outcome -> outcome_hash,
|
||||
reason
|
||||
);
|
||||
action(
|
||||
permission_level{ _gateway, "active"_n},
|
||||
outcome -> callback_contract,
|
||||
outcome -> decline_callback,
|
||||
std::make_tuple(coopname, outcome -> outcome_hash, reason)
|
||||
).send();
|
||||
|
||||
outcomes.erase(outcome);
|
||||
};
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Проект
|
||||
project(ledger)
|
||||
|
||||
find_package(cdt)
|
||||
|
||||
# Добавление контракта
|
||||
add_contract(ledger ledger ledger.cpp)
|
||||
target_compile_definitions(ledger PUBLIC IS_TESTNET=${IS_TESTNET})
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "ledger.hpp"
|
||||
#include <ctime>
|
||||
#include <eosio/transaction.hpp>
|
||||
|
||||
#include "src/common/add.cpp"
|
||||
#include "src/common/sub.cpp"
|
||||
#include "src/common/transfer.cpp"
|
||||
#include "src/common/block.cpp"
|
||||
#include "src/common/unblock.cpp"
|
||||
#include "src/common/writeoff.cpp"
|
||||
#include "src/common/writeoffcnsl.cpp"
|
||||
|
||||
#include "src/writeoff/create.cpp"
|
||||
#include "src/writeoff/auth.cpp"
|
||||
#include "src/writeoff/complete.cpp"
|
||||
#include "src/writeoff/decline.cpp"
|
||||
#include "src/migrate/migrate.cpp"
|
||||
@@ -1,51 +0,0 @@
|
||||
#include <eosio/asset.hpp>
|
||||
#include <eosio/contract.hpp>
|
||||
#include <eosio/crypto.hpp>
|
||||
#include <eosio/eosio.hpp>
|
||||
#include <eosio/multi_index.hpp>
|
||||
#include <eosio/system.hpp>
|
||||
#include <eosio/time.hpp>
|
||||
|
||||
#include "../lib/common.hpp"
|
||||
|
||||
using namespace eosio;
|
||||
|
||||
/**
|
||||
* @ingroup public_contracts
|
||||
* @brief Контракт ledger для управления бухгалтерской книгой кооператива
|
||||
* @details Обеспечивает ведение счетов согласно стандартам кооперативной отчетности
|
||||
* Счета создаются автоматически при первом пополнении и удаляются при обнулении всех балансов
|
||||
*/
|
||||
class [[eosio::contract(LEDGER)]] ledger : public eosio::contract {
|
||||
|
||||
public:
|
||||
ledger(eosio::name receiver, eosio::name code,
|
||||
eosio::datastream<const char *> ds)
|
||||
: eosio::contract(receiver, code, ds) {}
|
||||
|
||||
void apply(uint64_t receiver, uint64_t code, uint64_t action);
|
||||
[[eosio::action]] void migrate();
|
||||
|
||||
// Операции со счетами (common процесс)
|
||||
[[eosio::action]] void add(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
[[eosio::action]] void sub(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
[[eosio::action]] void transfer(eosio::name coopname, uint64_t from_account_id, uint64_t to_account_id, eosio::asset quantity, std::string comment);
|
||||
|
||||
// Операции блокировки/разблокировки средств
|
||||
[[eosio::action]] void block(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
[[eosio::action]] void unblock(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
|
||||
// Атомарная операция списания
|
||||
[[eosio::action]] void writeoff(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
// Атомарная операция отмены списания
|
||||
[[eosio::action]] void writeoffcnsl(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
|
||||
// Операции процесса списания через совет (writeoff процесс)
|
||||
[[eosio::action]] void create(eosio::name coopname, eosio::name username, uint64_t account_id, eosio::asset quantity, std::string reason, document2 document, checksum256 writeoff_hash);
|
||||
[[eosio::action]] void auth(eosio::name coopname, checksum256 writeoff_hash);
|
||||
|
||||
// Коллбэки от gateway
|
||||
[[eosio::action]] void complete(eosio::name coopname, checksum256 writeoff_hash);
|
||||
[[eosio::action]] void decline(eosio::name coopname, checksum256 writeoff_hash, std::string reason);
|
||||
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* @brief Пополнение счета с автоматическим созданием если не существует
|
||||
* @param actor - кто предоставляет авторизацию
|
||||
* @param coopname - имя кооператива
|
||||
* @param account_id - идентификатор счета
|
||||
* @param quantity - сумма пополнения
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::add(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
|
||||
if (account_iter == accounts.end()) {
|
||||
// Счет не существует - создаем автоматически, получая имя из ACCOUNT_MAP
|
||||
std::string account_name = Ledger::get_account_name_by_id(account_id);
|
||||
eosio::check(account_name != "Неизвестный счет", "Счет с таким ID не предусмотрен в плане счетов");
|
||||
|
||||
// Создаем новый счет
|
||||
accounts.emplace(payer, [&](auto& acc) {
|
||||
acc.id = account_id;
|
||||
acc.name = account_name;
|
||||
acc.available = quantity;
|
||||
acc.blocked = eosio::asset(0, _root_govern_symbol);
|
||||
acc.writeoff = eosio::asset(0, _root_govern_symbol);
|
||||
});
|
||||
} else {
|
||||
// Счет существует - пополняем available
|
||||
accounts.modify(account_iter, payer, [&](auto& acc) {
|
||||
acc.available += quantity;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* @brief Блокировка средств на счете (перенос из available в blocked)
|
||||
* @param coopname - имя кооператива
|
||||
* @param account_id - идентификатор счета
|
||||
* @param quantity - сумма блокировки
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::block(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
// Проверяем достаточность доступных средств
|
||||
eosio::check(account_iter->available >= quantity, "Недостаточно доступных средств для блокировки");
|
||||
|
||||
// Переносим средства из available в blocked
|
||||
accounts.modify(account_iter, payer, [&](auto& acc) {
|
||||
acc.available -= quantity;
|
||||
acc.blocked += quantity;
|
||||
});
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* @brief Списание со счета
|
||||
* @param actor - кто предоставляет авторизацию
|
||||
* @param coopname - имя кооператива
|
||||
* @param account_id - идентификатор счета
|
||||
* @param quantity - сумма списания
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::sub(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
// Проверяем достаточность доступных средств
|
||||
eosio::check(account_iter->available >= quantity, "Недостаточно доступных средств для списания");
|
||||
|
||||
// Обновляем баланс счета
|
||||
accounts.modify(account_iter, payer, [&](auto& acc) {
|
||||
acc.available -= quantity;
|
||||
});
|
||||
|
||||
// Проверяем и удаляем счет если он полностью пуст
|
||||
if (account_iter->is_empty()) {
|
||||
accounts.erase(account_iter);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* @brief Перевод средств между счетами
|
||||
* @param coopname - имя кооператива
|
||||
* @param from_account_id - идентификатор счета списания
|
||||
* @param to_account_id - идентификатор счета зачисления
|
||||
* @param quantity - сумма перевода
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::transfer(eosio::name coopname, uint64_t from_account_id, uint64_t to_account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
eosio::check(from_account_id != to_account_id, "Счета списания и зачисления должны отличаться");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
|
||||
// Проверяем счет списания
|
||||
auto from_account_iter = accounts.find(from_account_id);
|
||||
eosio::check(from_account_iter != accounts.end(), "Счет списания не найден");
|
||||
eosio::check(from_account_iter->available >= quantity, "Недостаточно доступных средств для перевода");
|
||||
|
||||
// Проверяем счет зачисления или создаем его
|
||||
auto to_account_iter = accounts.find(to_account_id);
|
||||
|
||||
// Списываем с источника
|
||||
accounts.modify(from_account_iter, payer, [&](auto& acc) {
|
||||
acc.available -= quantity;
|
||||
});
|
||||
|
||||
if (to_account_iter == accounts.end()) {
|
||||
// Счет получателя не существует - создаем автоматически
|
||||
std::string account_name = Ledger::get_account_name_by_id(to_account_id);
|
||||
eosio::check(account_name != "Неизвестный счет", "Счет получателя с таким ID не предусмотрен в плане счетов");
|
||||
|
||||
accounts.emplace(payer, [&](auto& acc) {
|
||||
acc.id = to_account_id;
|
||||
acc.name = account_name;
|
||||
acc.available = quantity;
|
||||
acc.blocked = eosio::asset(0, _root_govern_symbol);
|
||||
acc.writeoff = eosio::asset(0, _root_govern_symbol);
|
||||
});
|
||||
} else {
|
||||
// Зачисляем на получателя
|
||||
accounts.modify(to_account_iter, payer, [&](auto& acc) {
|
||||
acc.available += quantity;
|
||||
});
|
||||
}
|
||||
|
||||
// Проверяем и удаляем счет источника если он полностью пуст
|
||||
if (from_account_iter->is_empty()) {
|
||||
accounts.erase(from_account_iter);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* @brief Разблокировка средств на счете (перенос из blocked в available)
|
||||
* @param coopname - имя кооператива
|
||||
* @param account_id - идентификатор счета
|
||||
* @param quantity - сумма разблокировки
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::unblock(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
// Проверяем достаточность заблокированных средств
|
||||
eosio::check(account_iter->blocked >= quantity, "Недостаточно заблокированных средств для разблокировки");
|
||||
|
||||
// Переносим средства из blocked в available
|
||||
accounts.modify(account_iter, payer, [&](auto& acc) {
|
||||
acc.blocked -= quantity;
|
||||
acc.available += quantity;
|
||||
});
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* @brief Атомарная операция списания - перевод заблокированных средств в списанные
|
||||
* @param coopname - имя кооператива
|
||||
* @param account_id - идентификатор счета
|
||||
* @param quantity - сумма списания
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::writeoff(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
// Проверяем достаточность заблокированных средств
|
||||
eosio::check(account_iter->blocked >= quantity, "Недостаточно заблокированных средств для списания");
|
||||
|
||||
// Атомарно переводим средства из blocked в writeoff
|
||||
accounts.modify(account_iter, payer, [&](auto& acc) {
|
||||
acc.blocked -= quantity;
|
||||
acc.writeoff += quantity;
|
||||
});
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* @brief Атомарная операция отмены списания - перевод списанных средств обратно в заблокированные
|
||||
* @param coopname - имя кооператива
|
||||
* @param account_id - идентификатор счета
|
||||
* @param quantity - сумма отмены списания
|
||||
* @param comment - комментарий к операции
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::writeoffcnsl(eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::name payer = coopname;
|
||||
if (!has_auth(coopname)) {
|
||||
payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
|
||||
}
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
// Проверяем достаточность списанных средств
|
||||
eosio::check(account_iter->writeoff >= quantity, "Недостаточно списанных средств для отмены списания");
|
||||
|
||||
// Атомарно переводим средства из writeoff в blocked
|
||||
accounts.modify(account_iter, payer, [&](auto& acc) {
|
||||
acc.writeoff -= quantity;
|
||||
acc.blocked += quantity;
|
||||
});
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* @brief Миграция данных из контракта fund
|
||||
* Переносит данные из фондов fund в счета ledger
|
||||
* Теперь счета создаются только при наличии средств для переноса
|
||||
*/
|
||||
void ledger::migrate(){
|
||||
require_auth(_ledger);
|
||||
|
||||
// Получаем все кооперативы
|
||||
cooperatives2_index coops(_registrator, _registrator.value);
|
||||
|
||||
for (auto coop_iter = coops.begin(); coop_iter != coops.end(); ++coop_iter) {
|
||||
eosio::name coopname = coop_iter->username;
|
||||
|
||||
// Проверяем что счета еще не инициализированы
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto existing = accounts.begin();
|
||||
if (existing != accounts.end()) {
|
||||
continue; // Пропускаем уже мигрированные кооперативы
|
||||
}
|
||||
|
||||
// Мигрируем данные из fund контракта
|
||||
// Читаем кошелек кооператива
|
||||
coopwallet_index coopwallets(_fund, coopname.value);
|
||||
auto wallet_iter = coopwallets.find(0); // ID всегда 0
|
||||
|
||||
if (wallet_iter != coopwallets.end()) {
|
||||
// Паевой фонд (circulating_account) -> счет 80 (SHARE_FUND)
|
||||
if (wallet_iter->circulating_account.available.amount > 0) {
|
||||
Ledger::add(_ledger, coopname, Ledger::accounts::SHARE_FUND,
|
||||
wallet_iter->circulating_account.available,
|
||||
"Миграция: перенос паевого фонда из fund контракта");
|
||||
}
|
||||
|
||||
// Вступительные взносы (initial_account) -> счет 861 (ENTRANCE_FEES)
|
||||
if (wallet_iter->initial_account.available.amount > 0) {
|
||||
Ledger::add(_ledger, coopname, Ledger::accounts::ENTRANCE_FEES,
|
||||
wallet_iter->initial_account.available,
|
||||
"Миграция: перенос вступительных взносов из fund контракта");
|
||||
}
|
||||
|
||||
// Накопительный счет членских взносов (accumulative_expense_account) -> счет 86 (TARGET_RECEIPTS)
|
||||
if (wallet_iter->accumulative_expense_account.available.amount > 0) {
|
||||
Ledger::add(_ledger, coopname, Ledger::accounts::TARGET_RECEIPTS,
|
||||
wallet_iter->accumulative_expense_account.available,
|
||||
"Миграция: перенос накопительного счета членских взносов из fund контракта");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* @brief Авторизация операции после положительного решения совета
|
||||
* @param coopname - имя кооператива
|
||||
* @param writeoff_hash - хэш операции списания
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::auth(eosio::name coopname, checksum256 writeoff_hash) {
|
||||
require_auth(_soviet);
|
||||
|
||||
auto writeoff_opt = Ledger::get_writeoff_by_hash(writeoff_hash);
|
||||
eosio::check(writeoff_opt.has_value(), "Операция не найдена");
|
||||
|
||||
auto writeoff = writeoff_opt.value();
|
||||
eosio::check(writeoff.coopname == coopname, "Неверный кооператив");
|
||||
eosio::check(writeoff.status == "pending"_n, "Операция уже обработана");
|
||||
|
||||
// Обновляем статус операции
|
||||
writeoffs_index writeoffs(_ledger, _ledger.value);
|
||||
auto writeoff_iter = writeoffs.find(writeoff.id);
|
||||
writeoffs.modify(writeoff_iter, _soviet, [&](auto& w) {
|
||||
w.status = "approved"_n;
|
||||
});
|
||||
|
||||
// Отправляем запрос на создание исходящего платежа в gateway через интерфейс
|
||||
Action::send<createoutpay_interface>(
|
||||
_gateway,
|
||||
"createoutpay"_n,
|
||||
_ledger,
|
||||
coopname,
|
||||
writeoff.username,
|
||||
writeoff_hash,
|
||||
writeoff.quantity,
|
||||
_ledger, // callback_contract
|
||||
"complete"_n, // confirm_callback
|
||||
"decline"_n // decline_callback
|
||||
);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* @brief Коллбэк при успешном завершении платежа
|
||||
* @param coopname - имя кооператива
|
||||
* @param writeoff_hash - хэш операции списания
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::complete(eosio::name coopname, checksum256 writeoff_hash) {
|
||||
require_auth(_gateway);
|
||||
|
||||
auto writeoff_opt = Ledger::get_writeoff_by_hash(writeoff_hash);
|
||||
eosio::check(writeoff_opt.has_value(), "Операция не найдена");
|
||||
|
||||
auto writeoff = writeoff_opt.value();
|
||||
eosio::check(writeoff.coopname == coopname, "Неверный кооператив");
|
||||
eosio::check(writeoff.status == "approved"_n, "Операция не одобрена");
|
||||
|
||||
// Обновляем статус операции
|
||||
writeoffs_index writeoffs(_ledger, _ledger.value);
|
||||
auto writeoff_iter = writeoffs.find(writeoff.id);
|
||||
writeoffs.modify(writeoff_iter, _gateway, [&](auto& w) {
|
||||
w.status = "paid"_n;
|
||||
});
|
||||
|
||||
// Списываем средства со счета
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(writeoff.account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
accounts.modify(account_iter, _gateway, [&](auto& acc) {
|
||||
acc.blocked -= writeoff.quantity;
|
||||
acc.writeoff += writeoff.quantity;
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* @brief Создание заявления в совет для списания средств
|
||||
* @param coopname - имя кооператива
|
||||
* @param username - инициатор заявления
|
||||
* @param account_id - идентификатор счета для списания
|
||||
* @param quantity - сумма списания
|
||||
* @param reason - обоснование списания
|
||||
* @param document - документ обоснования
|
||||
* @param writeoff_hash - внешний хэш операции списания
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::create(eosio::name coopname, eosio::name username, uint64_t account_id, eosio::asset quantity, std::string reason, document2 document, checksum256 writeoff_hash) {
|
||||
require_auth(coopname);
|
||||
|
||||
eosio::check(quantity.is_valid(), "Некорректная сумма");
|
||||
eosio::check(quantity.amount > 0, "Сумма должна быть положительной");
|
||||
eosio::check(quantity.symbol == _root_govern_symbol, "Некорректный символ валюты");
|
||||
eosio::check(reason.length() > 0, "Обоснование должно быть от 1 символа");
|
||||
|
||||
// Проверяем что кооператив существует
|
||||
cooperatives2_index coops(_registrator, _registrator.value);
|
||||
auto coop_iter = coops.find(coopname.value);
|
||||
eosio::check(coop_iter != coops.end(), "Кооператив не найден");
|
||||
|
||||
// Проверяем что счет существует
|
||||
laccounts_index accounts(_ledger, coopname.value);
|
||||
auto account_iter = accounts.find(account_id);
|
||||
eosio::check(account_iter != accounts.end(), "Счет не найден");
|
||||
|
||||
// Проверяем достаточность средств
|
||||
eosio::check(account_iter -> available >= quantity, "Недостаточно средств на счету");
|
||||
|
||||
// Проверяем уникальность writeoff_hash
|
||||
auto existing_writeoff = Ledger::get_writeoff_by_hash(writeoff_hash);
|
||||
eosio::check(!existing_writeoff.has_value(), "Операция с таким хэшем уже существует");
|
||||
|
||||
// Создаем операцию ожидающую решения совета
|
||||
auto operation_id = get_global_id_in_scope(_ledger, _ledger, "writeoffs"_n);
|
||||
|
||||
writeoffs_index writeoffs(_ledger, _ledger.value);
|
||||
writeoffs.emplace(username, [&](auto& op) {
|
||||
op.id = operation_id;
|
||||
op.coopname = coopname;
|
||||
op.username = username;
|
||||
op.account_id = account_id;
|
||||
op.quantity = quantity;
|
||||
op.reason = reason;
|
||||
op.document = document;
|
||||
op.writeoff_hash = writeoff_hash;
|
||||
op.status = "pending"_n;
|
||||
});
|
||||
|
||||
// Создаем агенду в совете через Action::send
|
||||
Action::send<createagenda_interface>(
|
||||
_soviet,
|
||||
"createagenda"_n,
|
||||
username,
|
||||
coopname,
|
||||
username,
|
||||
get_valid_soviet_action("ledgerwthd"_n), // тип решения
|
||||
writeoff_hash,
|
||||
_ledger, // callback_contract
|
||||
"auth"_n, // confirm_callback
|
||||
"decline"_n, // decline_callback
|
||||
document,
|
||||
reason
|
||||
);
|
||||
|
||||
// Блокируем средства на счету
|
||||
std::string comment = "Служебная записка отправлена в совет для списания средств со счета " + account_iter->name + " на сумму " + quantity.to_string();
|
||||
Ledger::block(coopname, coopname, account_id, quantity, comment);
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* @brief Коллбэк при отклонении платежа или решения совета
|
||||
* @param coopname - имя кооператива
|
||||
* @param writeoff_hash - хэш операции списания
|
||||
* @param reason - причина отклонения
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void ledger::decline(eosio::name coopname, checksum256 writeoff_hash, std::string reason) {
|
||||
// Может быть вызван от _soviet (отклонение решения) или _gateway (отклонение платежа)
|
||||
eosio::check(has_auth(_soviet) || has_auth(_gateway), "Недостаточно прав для отклонения операции");
|
||||
|
||||
auto writeoff_opt = Ledger::get_writeoff_by_hash(writeoff_hash);
|
||||
eosio::check(writeoff_opt.has_value(), "Операция не найдена");
|
||||
|
||||
auto writeoff = writeoff_opt.value();
|
||||
eosio::check(writeoff.coopname == coopname, "Неверный кооператив");
|
||||
|
||||
// Обновляем статус операции
|
||||
writeoffs_index writeoffs(_ledger, _ledger.value);
|
||||
auto writeoff_iter = writeoffs.find(writeoff.id);
|
||||
writeoffs.erase(writeoff_iter);
|
||||
}
|
||||
@@ -164,10 +164,10 @@ struct org_data {
|
||||
std::string announce; ///< Анонс
|
||||
std::string description; ///< Описание
|
||||
eosio::asset initial; ///< Вступительный взнос физического лица / ип
|
||||
eosio::asset minimum; ///< Минимальный паевой взнос физического лица / ип
|
||||
eosio::asset minimum; ///< Минимальный паевый взнос физического лица / ип
|
||||
|
||||
eosio::asset org_initial; ///< Вступительный взнос юридического лица
|
||||
eosio::asset org_minimum; ///< Минимальный паевой взнос юридического лица
|
||||
eosio::asset org_minimum; ///< Минимальный паевый взнос юридического лица
|
||||
|
||||
};
|
||||
|
||||
@@ -192,11 +192,11 @@ struct [[eosio::table, eosio::contract(REGISTRATOR)]] cooperative {
|
||||
|
||||
eosio::asset registration; ///< Регистрационный взнос физического лица / ип
|
||||
eosio::asset initial; ///< Вступительный членский взнос физического лица / ип
|
||||
eosio::asset minimum; ///< Минимальный паевой взнос физического лица / ип
|
||||
eosio::asset minimum; ///< Минимальный паевый взнос физического лица / ип
|
||||
|
||||
eosio::binary_extension<eosio::asset> org_registration; ///< Регистрационный взнос юридического лица
|
||||
eosio::binary_extension<eosio::asset> org_initial; ///< Вступительный членский взнос юридического лица
|
||||
eosio::binary_extension<eosio::asset> org_minimum; ///< Минимальный паевой взнос юридического лица
|
||||
eosio::binary_extension<eosio::asset> org_minimum; ///< Минимальный паевый взнос юридического лица
|
||||
|
||||
eosio::binary_extension<eosio::name> status; ///< Статус процесса подключения
|
||||
eosio::binary_extension<eosio::time_point_sec> created_at; ///< Дата поступления заявки на подключение (pending | ... | active | blocked)
|
||||
@@ -303,16 +303,15 @@ struct [[eosio::table, eosio::contract(REGISTRATOR)]] cooperative2 {
|
||||
|
||||
eosio::asset registration; ///< Регистрационный взнос физического лица / ип
|
||||
eosio::asset initial; ///< Вступительный членский взнос физического лица / ип
|
||||
eosio::asset minimum; ///< Минимальный паевой взнос физического лица / ип
|
||||
eosio::asset minimum; ///< Минимальный паевый взнос физического лица / ип
|
||||
|
||||
eosio::binary_extension<eosio::asset> org_registration; ///< Регистрационный взнос юридического лица
|
||||
eosio::binary_extension<eosio::asset> org_initial; ///< Вступительный членский взнос юридического лица
|
||||
eosio::binary_extension<eosio::asset> org_minimum; ///< Минимальный паевой взнос юридического лица
|
||||
eosio::binary_extension<eosio::asset> org_minimum; ///< Минимальный паевый взнос юридического лица
|
||||
|
||||
eosio::binary_extension<eosio::name> status; ///< Статус процесса подключения
|
||||
eosio::binary_extension<eosio::time_point_sec> created_at; ///< Дата поступления заявки на подключение (pending | ... | active | blocked)
|
||||
eosio::binary_extension<document2> document; ///< Подписанный документ соглашения на подключение
|
||||
eosio::binary_extension<uint64_t> active_participants_count; ///< Счетчик активных пайщиков в кооперативе
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,7 +80,7 @@ struct [[eosio::table, eosio::contract(SOVIET)]] agreement2 {
|
||||
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"agreements3"_n, agreement2,
|
||||
typedef eosio::multi_index<"agreements2"_n, agreement2,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<agreement2, uint64_t, &agreement2::by_username>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<agreement2, uint64_t, &agreement2::by_status>>,
|
||||
eosio::indexed_by<"bydraft"_n, eosio::const_mem_fun<agreement2, uint64_t, &agreement2::by_draft>>,
|
||||
|
||||
@@ -76,21 +76,6 @@ struct [[eosio::table, eosio::contract(BRANCH)]] coobranch {
|
||||
bool is_account_in_trusted(const eosio::name& account) const {
|
||||
return std::find(trusted.begin(), trusted.end(), account) != trusted.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет права доступа пользователя к данному кооперативному участку
|
||||
* @param username Имя пользователя для проверки
|
||||
* @return true если пользователь имеет права доступа, false в противном случае
|
||||
*/
|
||||
bool is_user_authorized(const eosio::name& username) const {
|
||||
// Проверяем является ли пользователь доверенным лицом (trustee)
|
||||
if (trustee == username) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Проверяем находится ли пользователь в списке доверенных (trusted)
|
||||
return is_account_in_trusted(username);
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"branches"_n, coobranch,
|
||||
|
||||
@@ -1,5 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
// Структуры exchange_params и request перенесены в shared_marketplace.hpp
|
||||
|
||||
|
||||
/**
|
||||
\ingroup public_tables
|
||||
\brief Параметры заявки на обмен.
|
||||
*
|
||||
* Эта структура предоставляет набор данных, которые требуются для создания или обновления заявки на обмен в контракте "marketplace".
|
||||
*
|
||||
* @details Следующие параметры определяют заявку:
|
||||
* - username: Имя пользователя, инициирующего или обновляющего заявку.
|
||||
* - parent_id: Идентификатор родительской заявки (если есть).
|
||||
* - coopname: Имя кооператива.
|
||||
* - units: Количество частей (штук) товара или услуги для обмена.
|
||||
* - unit_cost: Цена за единицу (штуку) товара или услуги, выраженная в определенном формате asset.
|
||||
* - data: Содержит дополнительные данные, специфичные для заявки (например, условия обмена).
|
||||
* - meta: Метаданные, предоставляющие дополнительную информацию о заявке (например, описание товара или условия обмена).
|
||||
*/
|
||||
struct exchange_params {
|
||||
eosio::name username; /*!< Имя пользователя, инициирующего или обновляющего заявку */
|
||||
uint64_t parent_id; /*!< Идентификатор родительской заявки */
|
||||
uint64_t program_id; /*!< Идентификатор программы */
|
||||
eosio::name coopname; /*!< Имя кооператива */
|
||||
uint64_t units; /*!< Количество частей (штук) товара или услуги */
|
||||
eosio::asset unit_cost; /*!< Цена за единицу (штуку) товара или услуги */
|
||||
uint64_t product_lifecycle_secs; /*!< Время жизни продукта, заявляемое поставщиком */
|
||||
std::optional<document2> document; /*!< Сопутствующий подписанный документ на взнос или возврат взноса */
|
||||
std::string data; /*!< Дополнительные данные, специфичные для заявки */
|
||||
std::string meta; /*!< Метаданные о заявке */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Таблица обменов для контракта "marketplace"
|
||||
* @ingroup public_tables
|
||||
* Эта таблица используется для хранения информации об обменных заявках в системе.
|
||||
*
|
||||
* @param id Идентификатор обмена, используемый как первичный ключ
|
||||
* @param parent_id Идентификатор родительской заявки (если есть)
|
||||
* @param type Тип обмена (покупка, продажа и т.д.)
|
||||
* @param status Статус обмена (например, "опубликовано", "на модерации" и т.д.)
|
||||
* @param username Имя пользователя, создавшего заявку
|
||||
* @param token_contract Имя контракта токена
|
||||
* @param unit_cost Цена за единицу товара в заявке
|
||||
* @param remain_units Оставшееся количество товара
|
||||
* @param blocked_units Заблокированное количество товара
|
||||
* @param delivered_units Количество доставленного товара
|
||||
* @param data Дополнительные данные, связанные с заявкой
|
||||
* @param meta Метаданные заявки
|
||||
*
|
||||
* Дополнительные индексы по status, type и parent_id позволяют искать заявки по этим полям.
|
||||
*
|
||||
* Пример использования:
|
||||
* @code
|
||||
* requests_index exchange(_me, coopname.value);
|
||||
* auto exchange_order = exchange.find(id);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
struct [[eosio::table, eosio::contract(MARKETPLACE)]] request {
|
||||
uint64_t id; /*!< идентификатор обмена */
|
||||
uint64_t parent_id; /*!< идентификатор родительской заявки */
|
||||
uint64_t program_id; /*!< идентификатор программы */
|
||||
eosio::name coopname; /*!< имя аккаунта кооператива */
|
||||
eosio::name type; /*!< тип обмена */
|
||||
eosio::name status; /*!< статус обмена */
|
||||
eosio::name username; /*!< имя аккаунта владельца заявки */
|
||||
eosio::name parent_username; /*!< имя аккаунта владельца объявления */
|
||||
eosio::name token_contract; /*!< имя контракта токена */
|
||||
|
||||
eosio::asset unit_cost;/*!< себестоимость единицы товара от поставщика */
|
||||
eosio::asset supplier_amount; /*!< сумма взноса поставщика */
|
||||
eosio::asset total_cost; /*!< сумма взноса заказчика */
|
||||
eosio::asset membership_fee; /*!< членский взнос заказчика */
|
||||
|
||||
uint64_t remain_units; /*!< оставшееся количество товара */
|
||||
uint64_t blocked_units; /*!< заблокированное количество товара */
|
||||
uint64_t delivered_units; /*!< количество доставленного товара */
|
||||
std::string data; /*!< дополнительные данные */
|
||||
std::string meta; /*!< метаданные заявки */
|
||||
|
||||
eosio::name money_contributor;
|
||||
eosio::name product_contributor;
|
||||
|
||||
document2 contribute_product_statement;
|
||||
document2 return_product_statement;
|
||||
|
||||
uint64_t contribution_product_decision_id;
|
||||
document2 contribution_product_authorization;
|
||||
|
||||
uint64_t return_product_decision_id;
|
||||
document2 return_product_authorization;
|
||||
|
||||
document2 product_contribution_act_validation;
|
||||
document2 product_contribution_act;
|
||||
|
||||
document2 product_recieve_act;
|
||||
document2 product_recieve_act_validation;
|
||||
|
||||
uint64_t product_lifecycle_secs;
|
||||
uint64_t cancellation_fee; //up to 100
|
||||
eosio::asset cancellation_fee_amount;
|
||||
|
||||
eosio::time_point_sec created_at;
|
||||
eosio::time_point_sec accepted_at;
|
||||
eosio::time_point_sec supplied_at;
|
||||
eosio::time_point_sec delivered_at;
|
||||
eosio::time_point_sec recieved_at;
|
||||
eosio::time_point_sec completed_at;
|
||||
eosio::time_point_sec declined_at;
|
||||
eosio::time_point_sec disputed_at;
|
||||
eosio::time_point_sec canceled_at;
|
||||
// eosio::time_point_sec expired_at;
|
||||
|
||||
eosio::time_point_sec warranty_delay_until;
|
||||
eosio::time_point_sec deadline_for_receipt;
|
||||
|
||||
bool is_warranty_return = false;
|
||||
uint64_t warranty_return_id;
|
||||
|
||||
uint64_t primary_key() const { return id; } /*!< return id - primary_key */
|
||||
uint64_t by_coop() const {return coopname.value;} /*!< кооператив */
|
||||
uint64_t by_status() const { return status.value; } /*!< индекс по статусу */
|
||||
uint64_t by_program() const { return program_id; } /*!< индекс по программе */
|
||||
uint64_t by_type() const { return type.value; } /*!< индекс по типу */
|
||||
uint64_t by_parent() const { return parent_id; } /*!< индекс по родительскому ID */
|
||||
uint64_t by_username() const { return username.value;} /*!< индекс по имени аккаунта */
|
||||
uint64_t by_parent_username() const { return parent_username.value;} /*!< индекс по имени аккаунта владельца объявления */
|
||||
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch();}
|
||||
uint64_t by_completed() const { return completed_at.sec_since_epoch();}
|
||||
uint64_t by_declined() const { return declined_at.sec_since_epoch();}
|
||||
uint64_t by_canceled() const { return canceled_at.sec_since_epoch();}
|
||||
uint64_t by_warranty_id() const { return warranty_return_id;}
|
||||
// uint64_t by_expired() const { return expired_at.sec_since_epoch();}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"requests"_n, request,
|
||||
eosio::indexed_by<"bycoop"_n, eosio::const_mem_fun<request, uint64_t, &request::by_coop>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<request, uint64_t, &request::by_status>>,
|
||||
eosio::indexed_by<"bytype"_n, eosio::const_mem_fun<request, uint64_t, &request::by_type>>,
|
||||
eosio::indexed_by<"byprogram"_n, eosio::const_mem_fun<request, uint64_t, &request::by_program>>,
|
||||
eosio::indexed_by<"byparent"_n, eosio::const_mem_fun<request, uint64_t, &request::by_parent>>,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<request, uint64_t, &request::by_username>>,
|
||||
eosio::indexed_by<"bypausername"_n, eosio::const_mem_fun<request, uint64_t, &request::by_parent_username>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<request, uint64_t, &request::by_created>>,
|
||||
eosio::indexed_by<"bycompleted"_n, eosio::const_mem_fun<request, uint64_t, &request::by_completed>>,
|
||||
eosio::indexed_by<"bydeclined"_n, eosio::const_mem_fun<request, uint64_t, &request::by_declined>>,
|
||||
eosio::indexed_by<"bycanceled"_n, eosio::const_mem_fun<request, uint64_t, &request::by_canceled>>,
|
||||
eosio::indexed_by<"bywarrantyid"_n, eosio::const_mem_fun<request, uint64_t, &request::by_warranty_id>>
|
||||
// eosio::indexed_by<"byexpired"_n, eosio::const_mem_fun<request, uint64_t, &request::by_expired>>
|
||||
>
|
||||
requests_index; /*!< Тип мультииндекса для таблицы обменов */
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
#include <eosio/eosio.hpp>
|
||||
#include <eosio/asset.hpp>
|
||||
#include <eosio/symbol.hpp>
|
||||
#include <eosio/system.hpp>
|
||||
#include <eosio/crypto.hpp>
|
||||
#include <eosio/transaction.hpp>
|
||||
#include <eosio/permission.hpp>
|
||||
|
||||
#include "consts.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "drafts.hpp"
|
||||
#include "shared_document.hpp"
|
||||
#include "accounts.hpp"
|
||||
#include "changes.hpp"
|
||||
#include "coops.hpp"
|
||||
#include "counts.hpp"
|
||||
#include "permissions.hpp"
|
||||
@@ -25,13 +17,9 @@
|
||||
#include "shared_actions.hpp"
|
||||
#include "shared_soviet.hpp"
|
||||
#include "shared_wallet.hpp"
|
||||
#include "shared_fund.hpp"
|
||||
#include "shared_gateway.hpp"
|
||||
#include "shared_ledger.hpp"
|
||||
#include "shared_approver.hpp"
|
||||
#include "shared_registrator.hpp"
|
||||
#include "shared_loan.hpp"
|
||||
#include "shared_branch.hpp"
|
||||
#include "shared_marketplace.hpp"
|
||||
#include "approves.hpp"
|
||||
#include "debts.hpp"
|
||||
@@ -93,7 +93,7 @@ static constexpr eosio::name _result_action = "result"_n;
|
||||
|
||||
//program_types
|
||||
static constexpr eosio::name _wallet_program = "wallet"_n;
|
||||
static constexpr eosio::name _marketplace_program = "marketplace"_n;
|
||||
static constexpr eosio::name _sosedi_program = "cooplace"_n;
|
||||
static constexpr eosio::name _source_program = "source"_n;
|
||||
static constexpr eosio::name _capital_program = "capital"_n;
|
||||
|
||||
@@ -104,8 +104,7 @@ static const std::set<eosio::name> soviet_actions = {
|
||||
//MEET
|
||||
"creategm"_n,//предложение повестки планового общего собрание
|
||||
"completegm"_n, //решение общего собрания пайщиков
|
||||
"ballot"_n, //бюллетень участника общего собрания пайщиков
|
||||
"gmnotify"_n, //уведомление участника общего собрания пайщиков
|
||||
|
||||
//CAPITAL
|
||||
"capitalinvst"_n, //заявление на инвестиции по договору УХД
|
||||
"createresult"_n, //клайм прироста капитализации из задания
|
||||
@@ -114,21 +113,20 @@ static const std::set<eosio::name> soviet_actions = {
|
||||
"capwthdrprog"_n, //произвести возврат накопленных членских взносов по программе на капиталиста
|
||||
"capwthdrproj"_n, //произвести возврат накопленных членских взносов по проекту на актора
|
||||
"capwthdrres"_n, //произвести возврат из задания
|
||||
|
||||
//WALLET
|
||||
"createwthd"_n, //создать заявление на возврат паевого взноса
|
||||
|
||||
//LEDGER
|
||||
"ledgerwthd"_n, //заявление на списание со счета через ledger
|
||||
|
||||
//MARKETPLACE
|
||||
"authoffs2c"_n, //заявление на взнос имуществом
|
||||
"authoffc2r"_n, //заявление на возврат паевого взноса имуществом
|
||||
};
|
||||
|
||||
static const std::set<eosio::name> gateway_income_actions = {
|
||||
"deposit"_n, //паевой взнос по ЦПП Кошелёк
|
||||
};
|
||||
|
||||
static const std::set<eosio::name> gateway_outcome_actions = {
|
||||
"withdraw"_n, //возврат паевого взноса по ЦПП Кошелёк
|
||||
};
|
||||
|
||||
|
||||
//program_ids
|
||||
static constexpr uint64_t _wallet_program_id = 1;
|
||||
static constexpr uint64_t _marketplace_program_id = 2;
|
||||
static constexpr uint64_t _sosedi_program_id = 2;
|
||||
static constexpr uint64_t _capital_program_id = 3;
|
||||
|
||||
static constexpr int64_t REWARD_SCALE = 100000000; ///< Масштабный коэффициент для вознаграждений (1e8).
|
||||
@@ -150,10 +148,7 @@ static constexpr int64_t REWARD_SCALE = 100000000; ///< Масштабный к
|
||||
#define CAPITAL "capital"
|
||||
#define WALLET "wallet"
|
||||
#define LOAN "loan"
|
||||
#define LEDGER "ledger"
|
||||
#define MEET "meet"
|
||||
#define LEDGER "ledger"
|
||||
|
||||
/**
|
||||
* @ingroup public_consts
|
||||
* @{
|
||||
@@ -174,7 +169,6 @@ static constexpr int64_t REWARD_SCALE = 100000000; ///< Масштабный к
|
||||
static constexpr eosio::name _branch = "branch"_n;
|
||||
static constexpr eosio::name _loan = "loan"_n;
|
||||
static constexpr eosio::name _meet = "meet"_n;
|
||||
static constexpr eosio::name _ledger = "ledger"_n;
|
||||
static constexpr eosio::name _power_account = "eosio.power"_n;
|
||||
static constexpr eosio::name _saving_account = "eosio.saving"_n;
|
||||
|
||||
@@ -199,8 +193,7 @@ static constexpr int64_t REWARD_SCALE = 100000000; ///< Масштабный к
|
||||
"eosio.msig"_n,
|
||||
"eosio.wrap"_n,
|
||||
"eosio.power"_n,
|
||||
"eosio.saving"_n,
|
||||
"ledger"_n
|
||||
"eosio.saving"_n
|
||||
// Добавьте остальные стандартные или пользовательские контракты по необходимости
|
||||
};
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ struct [[eosio::table, eosio::contract(SOVIET)]] participant {
|
||||
eosio::name status; //accepted | blocked
|
||||
|
||||
bool is_initial = true; ///< флаг, указывающий, внесен ли регистрационный взнос.
|
||||
bool is_minimum = true; ///< флаг, указывающий, внесен ли минимальный паевой взнос.
|
||||
bool is_minimum = true; ///< флаг, указывающий, внесен ли минимальный паевый взнос.
|
||||
bool has_vote = true; ///< флаг, указывающий, имеет ли член право голоса.
|
||||
|
||||
eosio::binary_extension<eosio::name> type; ///< individual | entrepreneur | organization
|
||||
|
||||
@@ -30,8 +30,6 @@ struct document2 {
|
||||
// Версия стандарта документа
|
||||
std::string version;
|
||||
|
||||
// uint64_t template_id; ///< было бы удобно но этого нет
|
||||
|
||||
// Хэши
|
||||
eosio::checksum256 hash; // общий хэш (doc_hash + meta_hash)
|
||||
eosio::checksum256 doc_hash; // хэш содержимого документа
|
||||
@@ -44,27 +42,13 @@ struct document2 {
|
||||
std::vector<signature_info> signatures;
|
||||
};
|
||||
|
||||
void verify_document_or_fail(
|
||||
const document2 &doc,
|
||||
const std::vector<eosio::name>& required_signers = {}
|
||||
) {
|
||||
void verify_document_or_fail(const document2 &doc)
|
||||
{
|
||||
for (const auto &sig : doc.signatures) {
|
||||
// Проверка завершится прерыванием, если восстановление подписи провалится
|
||||
assert_recover_key(sig.signed_hash, sig.signature, sig.public_key);
|
||||
}
|
||||
if (!required_signers.empty()) {
|
||||
for (const auto& required : required_signers) {
|
||||
bool found = false;
|
||||
for (const auto& sig : doc.signatures) {
|
||||
if (sig.signer == required) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eosio::check(found, ("Не найдена подпись от обязательного подписанта: " + required.to_string()).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool is_empty_document(const document2 &doc)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
struct [[eosio::table, eosio::contract(SOVIET)]] program {
|
||||
uint64_t id; /*!< идентификатор обмена */
|
||||
uint64_t draft_id; ///< Ссылка на шаблон условий
|
||||
eosio::name program_type; /*!< тип кооперативной программы (wallet | market | capital) */
|
||||
eosio::name program_type; /*!< тип кооперативной программы (wallet | market | ...) */
|
||||
|
||||
eosio::name coopname; /*!< имя аккаунта кооператива */
|
||||
bool is_active;
|
||||
@@ -17,9 +17,9 @@ struct [[eosio::table, eosio::contract(SOVIET)]] program {
|
||||
std::string images;
|
||||
std::string meta;
|
||||
|
||||
eosio::name calculation_type; /*!< LEGACY тип настройки платежей по программе ( absolute | relative | free ) */
|
||||
uint64_t membership_percent_fee; /*!< LEGACY процент комиссии со взноса */
|
||||
eosio::asset fixed_membership_contribution; /*!< LEGACY Членский взнос */
|
||||
eosio::name calculation_type; /*!< тип настройки платежей по программе ( absolute | relative | free ) */
|
||||
uint64_t membership_percent_fee; /*!< процент комиссии со взноса */
|
||||
eosio::asset fixed_membership_contribution; /*!< Членский взнос */
|
||||
|
||||
eosio::time_point_sec start_at; /*!< Время открытия */
|
||||
eosio::time_point_sec expired_at; /*!< Временное ограничение */
|
||||
@@ -120,7 +120,7 @@ struct ProgramInfo {
|
||||
|
||||
static const std::map<eosio::name, ProgramInfo> program_map = {
|
||||
{_wallet_program, {1, 1}}, // program_id = 1, draft_id = 1
|
||||
{_marketplace_program, {2, 699}}, // program_id = 2, draft_id = 699
|
||||
{_sosedi_program, {2, 699}}, // program_id = 2, draft_id = 699
|
||||
{_source_program, {3, 0}}, // program_id = 3, draft_id = 0
|
||||
{_capital_program, {4, 1000}} // program_id = 4, draft_id = 1000
|
||||
};
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace Branch {
|
||||
/**
|
||||
* @brief Получает количество кооперативных участков для данного кооператива
|
||||
* @param coopname Имя кооператива
|
||||
* @return Количество участков кооператива
|
||||
*/
|
||||
uint64_t get_branch_count(eosio::name coopname) {
|
||||
branchstat_index stat(_branch, _branch.value);
|
||||
auto st = stat.find(coopname.value);
|
||||
|
||||
if (st == stat.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return st->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, является ли пользователь уполномоченным лицом (trustee) кооперативного участка
|
||||
* @param coopname Имя кооператива
|
||||
* @param username Имя пользователя для проверки
|
||||
* @return true если пользователь является уполномоченным, false в противном случае
|
||||
*/
|
||||
bool is_trustee(eosio::name coopname, eosio::name username) {
|
||||
branch_index branches(_branch, coopname.value);
|
||||
|
||||
auto by_trustee_index = branches.get_index<"bytrustee"_n>();
|
||||
auto trustee_itr = by_trustee_index.find(username.value);
|
||||
|
||||
return trustee_itr != by_trustee_index.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, является ли пользователь доверенным лицом (trusted) в указанном участке кооператива
|
||||
* @param coopname Имя кооператива
|
||||
* @param braname Имя участка
|
||||
* @param username Имя пользователя для проверки
|
||||
* @return true если пользователь является доверенным, false в противном случае
|
||||
*/
|
||||
bool is_trusted(eosio::name coopname, eosio::name braname, eosio::name username) {
|
||||
branch_index branches(_branch, coopname.value);
|
||||
auto branch_itr = branches.find(braname.value);
|
||||
|
||||
if (branch_itr == branches.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return branch_itr->is_account_in_trusted(username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
namespace Document {
|
||||
/**
|
||||
* @brief Проверяет, что переданный документ соответствует ожидаемому шаблону
|
||||
* @param document Документ для проверки
|
||||
* @param expected_registry_id Ожидаемый идентификатор шаблона
|
||||
*/
|
||||
inline void validate_registry_id(document2 document, uint64_t expected_registry_id) {
|
||||
uint64_t registry_id = extract_registry_id_from_meta(document.meta);
|
||||
eosio::check(registry_id == expected_registry_id, "Передан неверный шаблон документа");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Структура именованного документа
|
||||
*/
|
||||
struct named_document {
|
||||
name name; /*!< имя документа (до 12 символов) */
|
||||
document2 document; /*!< сам документ */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Добавить документ с проверкой длины имени
|
||||
* @param docs Вектор документов
|
||||
* @param name Имя документа
|
||||
* @param doc Документ
|
||||
*/
|
||||
inline void add_document(std::vector<named_document>& docs, const name& name, const document2& doc) {
|
||||
docs.push_back({name, doc});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Найти документ по имени
|
||||
* @param docs Вектор документов
|
||||
* @param name Имя для поиска
|
||||
* @param found_doc Найденный документ (выходной параметр)
|
||||
* @return true если документ найден
|
||||
*/
|
||||
inline bool find_document(const std::vector<named_document>& docs, const name& name, document2& found_doc) {
|
||||
for (const auto& nd : docs) {
|
||||
if (nd.name == name) {
|
||||
found_doc = nd.document;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверить наличие документа
|
||||
* @param docs Вектор документов
|
||||
* @param name Имя для поиска
|
||||
* @return true если документ найден
|
||||
*/
|
||||
inline bool has_document(const std::vector<named_document>& docs, const name& name) {
|
||||
for (const auto& nd : docs) {
|
||||
if (nd.name == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Fund {
|
||||
|
||||
}
|
||||
@@ -3,16 +3,6 @@
|
||||
using createoutpay_interface = void(CREATEOUTPAY_SIGNATURE);
|
||||
|
||||
namespace Gateway {
|
||||
|
||||
static const std::set<eosio::name> gateway_income_actions = {
|
||||
"deposit"_n, //паевой взнос по ЦПП Кошелёк
|
||||
};
|
||||
|
||||
static const std::set<eosio::name> gateway_outcome_actions = {
|
||||
"withdraw"_n, //возврат паевого взноса по ЦПП Кошелёк
|
||||
};
|
||||
|
||||
|
||||
inline eosio::name get_valid_income_action(const eosio::name& action) {
|
||||
eosio::check(gateway_income_actions.contains(action), "Недопустимое имя действия");
|
||||
return action;
|
||||
|
||||
@@ -1,369 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Структура бухгалтерского счета
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(LEDGER)]] laccount {
|
||||
uint64_t id; ///< Идентификатор счета
|
||||
std::string name; ///< Название счета
|
||||
eosio::asset available; ///< Доступные средства (было allocation)
|
||||
eosio::asset blocked; ///< Заблокированные средства
|
||||
eosio::asset writeoff; ///< Списанные средства
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
|
||||
/**
|
||||
* @brief Проверяет, пуст ли счет (все балансы равны нулю)
|
||||
*/
|
||||
bool is_empty() const {
|
||||
return available.amount == 0 && blocked.amount == 0 && writeoff.amount == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получает общий баланс счета
|
||||
*/
|
||||
eosio::asset get_total() const {
|
||||
return available + blocked + writeoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получает всего доступных + заблокированных средств (без списанных)
|
||||
*/
|
||||
eosio::asset get_balance() const {
|
||||
return available + blocked;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Типы индексов для таблиц ledger
|
||||
*/
|
||||
typedef eosio::multi_index<"accounts"_n, laccount> laccounts_index;
|
||||
|
||||
/**
|
||||
* @brief Структура для операций ожидающих решения совета
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(LEDGER)]] writeoff_op {
|
||||
uint64_t id; ///< Идентификатор операции
|
||||
eosio::name coopname; ///< Имя кооператива
|
||||
eosio::name username; ///< Инициатор операции
|
||||
uint64_t account_id; ///< Счет для операции
|
||||
eosio::asset quantity; ///< Сумма операции
|
||||
std::string reason; ///< Обоснование
|
||||
document2 document; ///< Документ обоснования
|
||||
checksum256 writeoff_hash; ///< Хэш операции списания
|
||||
eosio::name status; ///< Статус: pending, approved, declined, paid
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
uint64_t by_coop() const { return coopname.value; }
|
||||
checksum256 by_hash() const { return writeoff_hash; }
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<"writeoffs"_n, writeoff_op,
|
||||
eosio::indexed_by<"bycoop"_n, eosio::const_mem_fun<writeoff_op, uint64_t, &writeoff_op::by_coop>>,
|
||||
eosio::indexed_by<"byhash"_n, eosio::const_mem_fun<writeoff_op, checksum256, &writeoff_op::by_hash>>
|
||||
> writeoffs_index;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Класс Ledger для интеграции с ledger контрактом
|
||||
*/
|
||||
class Ledger {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Валидные действия ledger для интеграции с другими контрактами
|
||||
*/
|
||||
static const std::set<eosio::name> ledger_actions;
|
||||
|
||||
/**
|
||||
* @brief Проверка корректности действия ledger
|
||||
*/
|
||||
static eosio::name get_valid_ledger_action(const eosio::name& action);
|
||||
|
||||
/**
|
||||
* @brief Проверка корректности символа валюты для операций ledger
|
||||
*/
|
||||
static void check_ledger_symbol(const eosio::asset& amount);
|
||||
|
||||
/**
|
||||
* @brief Проверка положительности суммы для операций ledger
|
||||
*/
|
||||
static void check_positive_amount(const eosio::asset& amount);
|
||||
|
||||
// Основные операции
|
||||
static void add(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
static void sub(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
static void transfer(eosio::name actor, eosio::name coopname, uint64_t from_account_id, uint64_t to_account_id, eosio::asset quantity, std::string comment);
|
||||
|
||||
// Операции блокировки/разблокировки
|
||||
static void block(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
static void unblock(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
|
||||
// Атомарные операции списания
|
||||
static void writeoff(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
static void writeoffcnsl(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment);
|
||||
|
||||
// Специализированные методы для членских взносов
|
||||
static void add_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment);
|
||||
static void sub_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment);
|
||||
static void block_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment);
|
||||
static void unblock_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment);
|
||||
|
||||
/**
|
||||
* @brief Получает операцию списания по хэшу
|
||||
*/
|
||||
static std::optional<writeoff_op> get_writeoff_by_hash(const checksum256 &writeoff_hash);
|
||||
|
||||
/**
|
||||
* @brief Получает название счета по его ID из ACCOUNT_MAP
|
||||
*/
|
||||
static std::string get_account_name_by_id(uint64_t account_id);
|
||||
|
||||
/**
|
||||
* @brief Константы счетов
|
||||
*/
|
||||
struct accounts {
|
||||
// Денежные средства
|
||||
static constexpr uint64_t CASH = 50; // Касса
|
||||
static constexpr uint64_t BANK_ACCOUNT = 51; // Расчетный счет
|
||||
|
||||
// Расчеты с пайщиками
|
||||
static constexpr uint64_t MEMBER_SETTLEMENTS = 75; // Расчеты с пайщиками по внесению/возврату паевых взносов
|
||||
static constexpr uint64_t MEMBER_DEBT = 751; // Задолженность пайщиков по внесению взносов в паевой фонд
|
||||
static constexpr uint64_t INCOME_ACCRUALS = 752; // Начисление доходов участникам от предпринимательской деятельности ПО (кооперативные выплаты)
|
||||
|
||||
// Паевой фонд
|
||||
static constexpr uint64_t SHARE_FUND = 80; // Паевой фонд (складочный капитал)
|
||||
|
||||
// Расчеты с пайщиками (дебиторами и кредиторами)
|
||||
static constexpr uint64_t MEMBER_FEES = 761; // По членским взносам
|
||||
static constexpr uint64_t PROPERTY_TRANSFER = 762; // По передаче имущества для некоммерческой деятельности
|
||||
static constexpr uint64_t OTHER_SETTLEMENTS = 763; // Другие расчеты
|
||||
|
||||
// Расчеты по займам
|
||||
static constexpr uint64_t LOANS_ISSUED = 583; // Расчеты по выданным займам
|
||||
static constexpr uint64_t LOAN_INTEREST = 911; // Внесение процентов за пользование займами
|
||||
|
||||
// Финансовые вложения из средств ПО
|
||||
static constexpr uint64_t FINANCIAL_INVESTMENTS = 58; // Финансовые вложения из средств ПО
|
||||
static constexpr uint64_t SHARES_AND_STAKES = 581; // Доли, паи и акции в организациях, где участвует ПО
|
||||
static constexpr uint64_t SECURITIES = 582; // Облигации (государственные ценные бумаги)
|
||||
|
||||
// Расчеты с дебиторами и кредиторами
|
||||
static constexpr uint64_t DEBTORS_CREDITORS = 76; // Расчеты с дебиторами и кредиторами
|
||||
|
||||
// Запасы, затраты, расчеты, собственные средства
|
||||
static constexpr uint64_t FIXED_ASSETS = 1; // Основные средства
|
||||
static constexpr uint64_t INTANGIBLE_ASSETS = 4; // Нематериальные активы
|
||||
static constexpr uint64_t MATERIALS_GOODS = 10; // Материалы, товары
|
||||
static constexpr uint64_t MAIN_PRODUCTION = 20; // Основное производство
|
||||
static constexpr uint64_t NON_PROFIT_ACTIVITY = 201; // Некоммерческая деятельность
|
||||
static constexpr uint64_t GENERAL_EXPENSES = 26; // Общехозяйственные расходы (содержание ПО)
|
||||
static constexpr uint64_t RESERVES = 63; // Резервы по сомнительным долгам
|
||||
static constexpr uint64_t LONG_TERM_LOANS = 67; // Расчеты по долгосрочным кредитам и займам
|
||||
static constexpr uint64_t TAXES_FEES = 68; // Расчеты с бюджетом по налогам и сборам
|
||||
static constexpr uint64_t SOCIAL_INSURANCE = 69; // Расчеты по социальному страхованию и обеспечению
|
||||
static constexpr uint64_t SALARY = 70; // Заработная плата
|
||||
static constexpr uint64_t ACCOUNTABLE_PERSONS = 71; // Расчеты с подотчетными лицами
|
||||
static constexpr uint64_t ADDITIONAL_CAPITAL = 83; // Добавочный капитал
|
||||
static constexpr uint64_t FUNDS_PO_1 = 831; // Фонды ПО (вариант пополнения фондов ПО)
|
||||
static constexpr uint64_t CURRENT_YEAR_PROFIT = 841; // Нераспределенная прибыль (убыток) отчетного года
|
||||
static constexpr uint64_t PREVIOUS_YEARS_PROFIT = 842; // Нераспределенная прибыль (непокрытый убыток) прошлых лет
|
||||
static constexpr uint64_t FUNDS_PO_2 = 843; // Фонды ПО (вариант пополнения фондов ПО)
|
||||
static constexpr uint64_t UNDISTRIBUTED_PROFIT = 84; // Нераспределенная прибыль (непокрытый убыток)
|
||||
static constexpr uint64_t TARGET_RECEIPTS = 86; // Целевые поступления
|
||||
static constexpr uint64_t ENTRANCE_FEES = 861; // Вступительные взносы
|
||||
static constexpr uint64_t RESERVE_FUND = 862; // Резервный фонд
|
||||
static constexpr uint64_t INDIVISIBLE_FUND = 863; // Неделимый фонд
|
||||
static constexpr uint64_t ECONOMIC_ACTIVITY_FUND = 864; // Фонд обеспечения хозяйственной деятельности
|
||||
static constexpr uint64_t MUTUAL_SECURITY_FUND = 865; // Фонд взаимного обеспечения
|
||||
static constexpr uint64_t DEVELOPMENT_FUND = 866; // Фонд развития потребительской кооперации
|
||||
static constexpr uint64_t OTHER_INCOME_EXPENSES = 91; // Прочие доходы и расходы
|
||||
static constexpr uint64_t FUTURE_EXPENSES_RESERVE = 96; // Резерв предстоящих расходов
|
||||
static constexpr uint64_t FUTURE_INCOME = 98; // Доходы будущих периодов
|
||||
static constexpr uint64_t FREE_RECEIPT = 981; // Безвозмездное получение имущества
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Карта счетов для инициализации бухгалтерской книги
|
||||
* СОХРАНЯЕМ - используется для получения названий при автосоздании счетов
|
||||
*/
|
||||
static const std::vector<std::tuple<uint64_t, std::string>> ACCOUNT_MAP = {
|
||||
{Ledger::accounts::FIXED_ASSETS, "Основные средства"},
|
||||
{Ledger::accounts::INTANGIBLE_ASSETS, "Нематериальные активы"},
|
||||
{Ledger::accounts::MATERIALS_GOODS, "Материалы, товары"},
|
||||
{Ledger::accounts::MAIN_PRODUCTION, "Основное производство"},
|
||||
{Ledger::accounts::NON_PROFIT_ACTIVITY, "Некоммерческая деятельность"},
|
||||
{Ledger::accounts::GENERAL_EXPENSES, "Общехозяйственные расходы"},
|
||||
{Ledger::accounts::CASH, "Касса"},
|
||||
{Ledger::accounts::BANK_ACCOUNT, "Расчетный счет"},
|
||||
{Ledger::accounts::RESERVES, "Резервы по сомнительным долгам"},
|
||||
{Ledger::accounts::LONG_TERM_LOANS, "Расчеты по долгосрочным кредитам и займам"},
|
||||
{Ledger::accounts::TAXES_FEES, "Расчеты с бюджетом по налогам и сборам"},
|
||||
{Ledger::accounts::SOCIAL_INSURANCE, "Расчеты по социальному страхованию и обеспечению"},
|
||||
{Ledger::accounts::SALARY, "Заработная плата"},
|
||||
{Ledger::accounts::ACCOUNTABLE_PERSONS, "Расчеты с подотчетными лицами"},
|
||||
{Ledger::accounts::MEMBER_SETTLEMENTS, "Расчеты с пайщиками по внесению/возврату паевых взносов"},
|
||||
{Ledger::accounts::SHARE_FUND, "Паевой фонд (складочный капитал)"},
|
||||
{Ledger::accounts::ADDITIONAL_CAPITAL, "Добавочный капитал"},
|
||||
{Ledger::accounts::TARGET_RECEIPTS, "Целевые поступления"},
|
||||
{Ledger::accounts::OTHER_INCOME_EXPENSES, "Прочие доходы и расходы"},
|
||||
{Ledger::accounts::FUTURE_EXPENSES_RESERVE, "Резерв предстоящих расходов"},
|
||||
{Ledger::accounts::FUTURE_INCOME, "Доходы будущих периодов"},
|
||||
{Ledger::accounts::SHARES_AND_STAKES, "Доли, паи и акции в организациях"},
|
||||
{Ledger::accounts::SECURITIES, "Облигации (государственные ценные бумаги)"},
|
||||
{Ledger::accounts::LOANS_ISSUED, "Расчеты по выданным займам"},
|
||||
{Ledger::accounts::MEMBER_DEBT, "Задолженность пайщиков по внесению взносов в паевой фонд"},
|
||||
{Ledger::accounts::INCOME_ACCRUALS, "Начисление доходов участникам от предпринимательской деятельности ПО"},
|
||||
{Ledger::accounts::MEMBER_FEES, "По членским взносам"},
|
||||
{Ledger::accounts::PROPERTY_TRANSFER, "По передаче имущества для некоммерческой деятельности"},
|
||||
{Ledger::accounts::OTHER_SETTLEMENTS, "Другие расчеты"},
|
||||
{Ledger::accounts::DEBTORS_CREDITORS, "Расчеты с дебиторами и кредиторами"},
|
||||
{Ledger::accounts::ENTRANCE_FEES, "Вступительные взносы"},
|
||||
{Ledger::accounts::FUNDS_PO_1, "Фонды ПО (вариант пополнения фондов ПО)"},
|
||||
{Ledger::accounts::CURRENT_YEAR_PROFIT, "Нераспределенная прибыль (убыток) отчетного года"},
|
||||
{Ledger::accounts::PREVIOUS_YEARS_PROFIT, "Нераспределенная прибыль (непокрытый убыток) прошлых лет"},
|
||||
{Ledger::accounts::FUNDS_PO_2, "Фонды ПО (вариант пополнения фондов ПО)"},
|
||||
{Ledger::accounts::UNDISTRIBUTED_PROFIT, "Нераспределенная прибыль (непокрытый убыток)"},
|
||||
{Ledger::accounts::RESERVE_FUND, "Резервный фонд"},
|
||||
{Ledger::accounts::INDIVISIBLE_FUND, "Неделимый фонд"},
|
||||
{Ledger::accounts::ECONOMIC_ACTIVITY_FUND, "Фонд обеспечения хозяйственной деятельности"},
|
||||
{Ledger::accounts::MUTUAL_SECURITY_FUND, "Фонд взаимного обеспечения"},
|
||||
{Ledger::accounts::DEVELOPMENT_FUND, "Фонд развития потребительской кооперации"},
|
||||
{Ledger::accounts::LOAN_INTEREST, "Внесение процентов за пользование займами"},
|
||||
{Ledger::accounts::FINANCIAL_INVESTMENTS, "Финансовые вложения из средств ПО"},
|
||||
{Ledger::accounts::FREE_RECEIPT, "Безвозмездное получение имущества"}
|
||||
};
|
||||
|
||||
// Реализация статических методов класса Ledger
|
||||
|
||||
const std::set<eosio::name> Ledger::ledger_actions = {
|
||||
"add"_n, // пополнение счета
|
||||
"sub"_n, // списание со счета
|
||||
"transfer"_n, // перевод между счетами
|
||||
"block"_n, // блокировка средств
|
||||
"unblock"_n, // разблокировка средств
|
||||
"writeoff"_n, // атомарное списание средств
|
||||
"writeoffcnsl"_n, // атомарная отмена списания
|
||||
"create"_n, // создание заявления на списание
|
||||
"auth"_n, // авторизация списания
|
||||
"complete"_n, // завершение операции
|
||||
"decline"_n // отклонение операции
|
||||
};
|
||||
|
||||
inline eosio::name Ledger::get_valid_ledger_action(const eosio::name& action) {
|
||||
eosio::check(ledger_actions.contains(action), "Недопустимое имя действия ledger");
|
||||
return action;
|
||||
}
|
||||
|
||||
inline void Ledger::check_ledger_symbol(const eosio::asset& amount) {
|
||||
eosio::check(amount.symbol == _root_govern_symbol, "Некорректный символ валюты для операций ledger");
|
||||
}
|
||||
|
||||
inline void Ledger::check_positive_amount(const eosio::asset& amount) {
|
||||
eosio::check(amount.is_valid(), "Некорректная сумма");
|
||||
eosio::check(amount.amount > 0, "Сумма должна быть положительной");
|
||||
}
|
||||
|
||||
inline std::string Ledger::get_account_name_by_id(uint64_t account_id) {
|
||||
for (const auto& account_data : ACCOUNT_MAP) {
|
||||
if (std::get<0>(account_data) == account_id) {
|
||||
return std::get<1>(account_data);
|
||||
}
|
||||
}
|
||||
return "Неизвестный счет";
|
||||
}
|
||||
|
||||
inline void Ledger::add(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("add"_n),
|
||||
std::make_tuple(coopname, account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::sub(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("sub"_n),
|
||||
std::make_tuple(coopname, account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::transfer(eosio::name actor, eosio::name coopname, uint64_t from_account_id, uint64_t to_account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("transfer"_n),
|
||||
std::make_tuple(coopname, from_account_id, to_account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::block(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("block"_n),
|
||||
std::make_tuple(coopname, account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::unblock(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("unblock"_n),
|
||||
std::make_tuple(coopname, account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::writeoff(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("writeoff"_n),
|
||||
std::make_tuple(coopname, account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::writeoffcnsl(eosio::name actor, eosio::name coopname, uint64_t account_id, eosio::asset quantity, std::string comment) {
|
||||
eosio::action(
|
||||
eosio::permission_level{actor, "active"_n},
|
||||
_ledger,
|
||||
get_valid_ledger_action("writeoffcnsl"_n),
|
||||
std::make_tuple(coopname, account_id, quantity, comment)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void Ledger::add_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment) {
|
||||
add(actor, coopname, accounts::TARGET_RECEIPTS, quantity, comment);
|
||||
}
|
||||
|
||||
inline void Ledger::sub_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment) {
|
||||
sub(actor, coopname, accounts::TARGET_RECEIPTS, quantity, comment);
|
||||
}
|
||||
|
||||
inline void Ledger::block_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment) {
|
||||
block(actor, coopname, accounts::TARGET_RECEIPTS, quantity, comment);
|
||||
}
|
||||
|
||||
inline void Ledger::unblock_membership_fee(eosio::name actor, eosio::name coopname, eosio::asset quantity, std::string comment) {
|
||||
unblock(actor, coopname, accounts::TARGET_RECEIPTS, quantity, comment);
|
||||
}
|
||||
|
||||
inline std::optional<writeoff_op> Ledger::get_writeoff_by_hash(const checksum256 &writeoff_hash) {
|
||||
writeoffs_index writeoffs(_ledger, _ledger.value);
|
||||
auto hash_idx = writeoffs.get_index<"byhash"_n>();
|
||||
|
||||
auto op_iter = hash_idx.find(writeoff_hash);
|
||||
if (op_iter == hash_idx.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *op_iter;
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Сигнатуры для callback действий marketplace
|
||||
#define AUTH_SIGNATURE eosio::name coopname, checksum256 request_hash, document2 authorization
|
||||
|
||||
using auth_interface = void(AUTH_SIGNATURE);
|
||||
|
||||
|
||||
namespace Marketplace {
|
||||
|
||||
/**
|
||||
* @brief Сегмент поставки - унифицированная структура для работы с документами
|
||||
* @ingroup public_tables
|
||||
*
|
||||
* Сегмент представляет собой путь поставки от пайщика в кооператив или из кооператива до пайщика
|
||||
*
|
||||
* Типы сегментов:
|
||||
* - "contribute" - сегмент поставки имущества в кооператив
|
||||
* - "return" - сегмент возврата имущества из кооператива
|
||||
* - "wreturn" - сегмент возврата по гарантии (от заказчика в кооператив)
|
||||
* - "wsupply" - сегмент выдачи по гарантии (из кооператива поставщику)
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(MARKETPLACE)]] segment {
|
||||
uint64_t id; /*!< идентификатор сегмента */
|
||||
uint64_t request_id; /*!< идентификатор заявки, к которой относится сегмент */
|
||||
eosio::name type; /*!< тип сегмента: "contribute", "return", "wreturn", "wsupply" */
|
||||
eosio::name status; /*!< статус сегмента */
|
||||
|
||||
document2 convert_in; /*!< заявление на конвертацию из кошелька */
|
||||
document2 statement; /*!< заявление/документ на взнос или возврат */
|
||||
uint64_t decision_id; /*!< идентификатор решения */
|
||||
document2 authorization; /*!< документ авторизации */
|
||||
document2 act1; /*!< акт приёма-передачи */
|
||||
document2 act2; /*!< акт приёма-передачи */
|
||||
document2 convert_out; /*!< заявление на конвертацию в кошелек */
|
||||
|
||||
// Документы транспортировки
|
||||
document2 transport_act_1; /*!< акт товарно-транспортной накладной - передача имущества на транспортировку */
|
||||
document2 transport_act_2; /*!< акт товарно-транспортной накладной - прием имущества водителем */
|
||||
document2 transport_act_3; /*!< акт товарно-транспортной накладной - доставка до КУ получателя */
|
||||
document2 transport_act_4; /*!< акт товарно-транспортной накладной - прием имущества председателем КУ */
|
||||
|
||||
eosio::name coopactor; /*!< представитель кооператива, который действует в этом сегменте */
|
||||
eosio::name username; /*!< пользователь, который действует в этом сегменте */
|
||||
eosio::name driver_username; /*!< водитель-пайщик, который принимает имущество на транспортировку */
|
||||
eosio::name receive_from_driver_coopactor; /*!< председатель КУ, который принимает имущество от водителя */
|
||||
|
||||
eosio::time_point_sec created_at;
|
||||
eosio::time_point_sec updated_at;
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
uint64_t by_request() const { return request_id; }
|
||||
uint64_t by_type() const { return type.value; }
|
||||
uint64_t by_status() const { return status.value; }
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"segments"_n, segment,
|
||||
eosio::indexed_by<"byrequest"_n, eosio::const_mem_fun<segment, uint64_t, &segment::by_request>>,
|
||||
eosio::indexed_by<"bytype"_n, eosio::const_mem_fun<segment, uint64_t, &segment::by_type>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<segment, uint64_t, &segment::by_status>>
|
||||
> segments_index;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Перевозка имущества - объединение нескольких заявок в одну транспортную накладную
|
||||
* @ingroup public_tables
|
||||
*
|
||||
* Перевозка представляет собой процесс транспортировки множества единиц имущества
|
||||
* в рамках одной товарно-транспортной накладной от одного кооперативного участка
|
||||
* к одному или нескольким получателям.
|
||||
*
|
||||
* Статусы перевозки:
|
||||
* - "loading" - идет загрузка товаров в перевозку
|
||||
* - "transit" - перевозка в пути (товары загружены и подписана накладная)
|
||||
* - "arrived" - перевозка прибыла, ожидает подтверждения получателя
|
||||
* - "completed" - все товары из перевозки переданы получателям
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(MARKETPLACE)]] shipment {
|
||||
uint64_t id; /*!< идентификатор перевозки */
|
||||
checksum256 hash; /*!< внешний идентификатор перевозки */
|
||||
eosio::name coopname; /*!< имя кооператива */
|
||||
eosio::name driver_username; /*!< водитель-пайщик */
|
||||
eosio::name source_braname; /*!< КУ отправителя */
|
||||
eosio::name destination_braname; /*!< КУ назначения (может быть промежуточный) */
|
||||
eosio::name status; /*!< статус перевозки */
|
||||
|
||||
std::vector<checksum256> request_hashes; /*!< массив хэшей заявок в перевозке */
|
||||
|
||||
std::vector<Document::named_document> documents; /*!< именованные документы перевозки */
|
||||
|
||||
eosio::time_point_sec created_at; /*!< время создания перевозки */
|
||||
eosio::time_point_sec loaded_at; /*!< время завершения загрузки */
|
||||
eosio::time_point_sec delivered_at; /*!< время доставки */
|
||||
eosio::time_point_sec completed_at; /*!< время завершения перевозки */
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
checksum256 by_hash() const { return hash; }
|
||||
uint64_t by_coop() const { return coopname.value; }
|
||||
uint64_t by_driver() const { return driver_username.value; }
|
||||
uint64_t by_source() const { return source_braname.value; }
|
||||
uint64_t by_destination() const { return destination_braname.value; }
|
||||
uint64_t by_status() const { return status.value; }
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch(); }
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"shipments"_n, shipment,
|
||||
eosio::indexed_by<"byhash"_n, eosio::const_mem_fun<shipment, checksum256, &shipment::by_hash>>,
|
||||
eosio::indexed_by<"bycoop"_n, eosio::const_mem_fun<shipment, uint64_t, &shipment::by_coop>>,
|
||||
eosio::indexed_by<"bydriver"_n, eosio::const_mem_fun<shipment, uint64_t, &shipment::by_driver>>,
|
||||
eosio::indexed_by<"bysource"_n, eosio::const_mem_fun<shipment, uint64_t, &shipment::by_source>>,
|
||||
eosio::indexed_by<"bydest"_n, eosio::const_mem_fun<shipment, uint64_t, &shipment::by_destination>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<shipment, uint64_t, &shipment::by_status>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<shipment, uint64_t, &shipment::by_created>>
|
||||
> shipments_index;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Таблица обменов для контракта "marketplace"
|
||||
* @ingroup public_tables
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(MARKETPLACE)]] request {
|
||||
uint64_t id; /*!< идентификатор обмена */
|
||||
checksum256 hash; /*!< хэш заявки */
|
||||
eosio::name coopname; /*!< имя аккаунта кооператива */
|
||||
eosio::name type; /*!< тип обмена: orderoffer или offerorder */
|
||||
eosio::name status; /*!< статус обмена */
|
||||
eosio::name username; /*!< имя аккаунта владельца заявки */
|
||||
eosio::name braname; /*!< имя кооперативного участка */
|
||||
eosio::name warehouse; /*!< имя КУ где хранится имущество */
|
||||
eosio::name token_contract; /*!< имя контракта токена */
|
||||
|
||||
eosio::name receiver_braname; /*!< КУ заказчика для получения товара */
|
||||
eosio::name supplier_braname; /*!< КУ поставщика для отправки товара */
|
||||
|
||||
eosio::asset unit_cost;/*!< себестоимость единицы товара от поставщика */
|
||||
eosio::asset base_cost; /*!< базовая стоимость заявки */
|
||||
eosio::asset membership_fee_amount; /*!< членский взнос заказчика */
|
||||
eosio::asset total_cost; /*!< общая сумма заявки */
|
||||
|
||||
uint64_t units; /*!< количество единиц товара */
|
||||
std::string meta; /*!< метаданные заявки */
|
||||
|
||||
eosio::name money_contributor; /*!< имя аккаунта, который вносит средства */
|
||||
eosio::name product_contributor; /*!< имя аккаунта, который передаёт товар */
|
||||
|
||||
std::vector<Document::named_document> documents; /*!< именованные документы заявки */
|
||||
|
||||
uint64_t product_lifecycle_secs; // жизненный цикл продукта
|
||||
uint64_t warranty_period_secs; // гарантийный срок в секундах
|
||||
eosio::asset cancellation_fee_amount; // сумма штрафа за отмену заявки
|
||||
|
||||
eosio::time_point_sec warranty_delay_until;
|
||||
eosio::time_point_sec deadline_for_receipt;
|
||||
|
||||
bool is_warranty_return = false;
|
||||
uint64_t warranty_return_id;
|
||||
|
||||
eosio::time_point_sec created_at;
|
||||
eosio::time_point_sec accepted_at;
|
||||
eosio::time_point_sec supplied_at;
|
||||
eosio::time_point_sec delivered_at;
|
||||
eosio::time_point_sec received_at;
|
||||
eosio::time_point_sec completed_at;
|
||||
eosio::time_point_sec declined_at;
|
||||
eosio::time_point_sec disputed_at;
|
||||
eosio::time_point_sec canceled_at;
|
||||
|
||||
|
||||
uint64_t primary_key() const { return id; }
|
||||
uint64_t by_coop() const {return coopname.value;}
|
||||
uint64_t by_status() const { return status.value; }
|
||||
uint64_t by_type() const { return type.value; }
|
||||
checksum256 by_hash() const { return hash; }
|
||||
uint64_t by_username() const { return username.value;}
|
||||
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch();}
|
||||
uint64_t by_completed() const { return completed_at.sec_since_epoch();}
|
||||
uint64_t by_declined() const { return declined_at.sec_since_epoch();}
|
||||
uint64_t by_canceled() const { return canceled_at.sec_since_epoch();}
|
||||
uint64_t by_warranty_id() const { return warranty_return_id;}
|
||||
|
||||
// Логические геттеры для получения актуальных ролей
|
||||
eosio::name get_money_contributor() const {
|
||||
return is_warranty_return ? product_contributor : money_contributor;
|
||||
}
|
||||
|
||||
eosio::name get_product_contributor() const {
|
||||
return is_warranty_return ? money_contributor : product_contributor;
|
||||
}
|
||||
|
||||
// Геттеры для понимания ролей в контексте текущей операции
|
||||
eosio::name get_payer() const {
|
||||
return get_money_contributor();
|
||||
}
|
||||
|
||||
eosio::name get_supplier() const {
|
||||
return get_product_contributor();
|
||||
}
|
||||
|
||||
// Специальные геттеры для гарантийного возврата
|
||||
// Возвращают участников в контексте процесса возврата брака
|
||||
|
||||
/**
|
||||
* @brief Получить пайщика, который возвращает товар в гарантийном возврате
|
||||
* Это тот, кто изначально получил товар и теперь возвращает его как брак
|
||||
*/
|
||||
eosio::name get_product_backer() const {
|
||||
return money_contributor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить поставщика брака в гарантийном возврате
|
||||
* Это тот, кто изначально поставил товар и теперь получает его обратно как брак
|
||||
*/
|
||||
eosio::name get_defective_supplier() const {
|
||||
return product_contributor;
|
||||
}
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"requests"_n, request,
|
||||
eosio::indexed_by<"bycoop"_n, eosio::const_mem_fun<request, uint64_t, &request::by_coop>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<request, uint64_t, &request::by_status>>,
|
||||
eosio::indexed_by<"bytype"_n, eosio::const_mem_fun<request, uint64_t, &request::by_type>>,
|
||||
eosio::indexed_by<"byhash"_n, eosio::const_mem_fun<request, checksum256, &request::by_hash>>,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<request, uint64_t, &request::by_username>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<request, uint64_t, &request::by_created>>,
|
||||
eosio::indexed_by<"bycompleted"_n, eosio::const_mem_fun<request, uint64_t, &request::by_completed>>,
|
||||
eosio::indexed_by<"bydeclined"_n, eosio::const_mem_fun<request, uint64_t, &request::by_declined>>,
|
||||
eosio::indexed_by<"bycanceled"_n, eosio::const_mem_fun<request, uint64_t, &request::by_canceled>>,
|
||||
eosio::indexed_by<"bywarrantyid"_n, eosio::const_mem_fun<request, uint64_t, &request::by_warranty_id>>
|
||||
> requests_index;
|
||||
|
||||
static const std::set<eosio::name> marketplace_callback_actions = {
|
||||
"authoffs2c"_n, // авторизация сегмента contribute для направления OFFER → ORDER
|
||||
"authoffc2r"_n, // авторизация сегмента return для направления OFFER → ORDER
|
||||
"authordcont"_n, // авторизация сегмента contribute для направления ORDER → OFFER
|
||||
"authordret"_n, // авторизация сегмента return для направления ORDER → OFFER
|
||||
"declineacc"_n, // отклонение принятия заявки
|
||||
};
|
||||
|
||||
inline eosio::name get_valid_marketplace_action(const eosio::name& action) {
|
||||
eosio::check(marketplace_callback_actions.contains(action), "Недопустимое имя действия marketplace");
|
||||
return action;
|
||||
}
|
||||
|
||||
// Вспомогательные функции для поиска заявок по хэшу
|
||||
static std::optional<request> get_request_by_hash(eosio::name coopname, checksum256 request_hash) {
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto idx = requests.get_index<"byhash"_n>();
|
||||
auto req = idx.find(request_hash);
|
||||
|
||||
if (req != idx.end()) {
|
||||
return *req;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Вспомогательные функции для поиска перевозок по хэшу
|
||||
static std::optional<shipment> get_shipment_by_hash(eosio::name coopname, checksum256 shipment_hash) {
|
||||
shipments_index shipments(_marketplace, coopname.value);
|
||||
auto idx = shipments.get_index<"byhash"_n>();
|
||||
auto ship = idx.find(shipment_hash);
|
||||
|
||||
if (ship != idx.end()) {
|
||||
return *ship;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static request get_request_by_hash_or_fail(eosio::name coopname, checksum256 request_hash, const std::string& error_msg = "Заявка не найдена по хэшу") {
|
||||
auto request_opt = get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(request_opt.has_value(), error_msg);
|
||||
return *request_opt;
|
||||
}
|
||||
|
||||
static shipment get_shipment_by_hash_or_fail(eosio::name coopname, checksum256 shipment_hash, const std::string& error_msg = "Перевозка не найдена по хэшу") {
|
||||
auto shipment_opt = get_shipment_by_hash(coopname, shipment_hash);
|
||||
eosio::check(shipment_opt.has_value(), error_msg);
|
||||
return *shipment_opt;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Константы для имен документов маркетплейса (максимум 12 символов)
|
||||
*/
|
||||
namespace DocumentNames {
|
||||
static constexpr const name RETURN_STMT = "returnstmt"_n; // заявление на возврат имущества
|
||||
static constexpr const name CONVERT_FROM = "convertfrom"_n; // заявление на конвертацию из кошелька
|
||||
static constexpr const name CONVERT_TO = "convertto"_n; // заявление на конвертацию в кошелек
|
||||
static constexpr const name CONTRIB_STMT = "contribstmt"_n; // заявление на имущественный паевой взнос
|
||||
static constexpr const name CONTRIB_AUTH = "contribauth"_n; // авторизация взноса
|
||||
static constexpr const name RETURN_AUTH = "returnauth"_n; // авторизация возврата
|
||||
static constexpr const name RECEIVE_ACT = "receiveact"_n; // акт получения
|
||||
static constexpr const name RECEIVE_ACT_CONF = "receiveconf"_n; // подтверждение акта получения
|
||||
static constexpr const name TRANSPORT1 = "transport1"_n; // акт транспортировки 1 (УСТАРЕВШИЙ)
|
||||
static constexpr const name TRANSPORT2 = "transport2"_n; // акт транспортировки 2 (УСТАРЕВШИЙ)
|
||||
static constexpr const name TRANSPORT3 = "transport3"_n; // акт транспортировки 3 (УСТАРЕВШИЙ)
|
||||
static constexpr const name TRANSPORT4 = "transport4"_n; // акт транспортировки 4 (УСТАРЕВШИЙ)
|
||||
static constexpr const name SUPPLY_ACT = "supplyact"_n; // акт поставки
|
||||
static constexpr const name SUPPLY_ACT_CONF = "supplyconf"_n; // подтверждение акта поставки
|
||||
static constexpr const name SHIPMENT_ACT = "shipmentact"_n; // товарно-транспортная накладная
|
||||
static constexpr const name DELIVERY_ACT = "deliveryact"_n; // акт доставки (УСТАРЕВШИЙ)
|
||||
|
||||
// Документы новой системы перевозок
|
||||
static constexpr const name SHIPMENT_SEND_ACT = "shsendact"_n; // акт передачи от отправителя
|
||||
static constexpr const name SHIPMENT_LOADING_ACT = "shloadact"_n; // акт приёма водителем
|
||||
static constexpr const name SHIPMENT_ARRIVE_ACT = "sharriveact"_n; // акт прибытия/доставки на склад, подписанный водителем
|
||||
static constexpr const name SHIPMENT_RECV_ACT = "shrecvact"_n; // акт приёма на складе получателем
|
||||
|
||||
// Документы гарантийного возврата
|
||||
static constexpr const name WDISPUTE = "wdispute"_n; // претензия на гарантийный возврат
|
||||
static constexpr const name WRETURN_AUTH = "wreturnauth"_n; // авторизация гарантийного возврата
|
||||
static constexpr const name WSUPPLY_AUTH = "wsupplyauth"_n; // авторизация гарантийной выдачи
|
||||
static constexpr const name WRETURN_ACT = "wreturnact"_n; // акт гарантийного возврата
|
||||
static constexpr const name WOFFER_ACT = "wofferact"_n; // акт предложения товара поставщику
|
||||
static constexpr const name WACCEPT_ACT = "wacceptact"_n; // акт принятия/отказа поставщика
|
||||
}
|
||||
|
||||
} // namespace Marketplace
|
||||
@@ -51,23 +51,4 @@ namespace Registrator {
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получает количество активных пайщиков кооператива
|
||||
* @param coopname Имя кооператива
|
||||
* @return uint64_t Количество активных пайщиков
|
||||
*/
|
||||
inline uint64_t get_active_participants_count(eosio::name coopname) {
|
||||
using namespace eosio;
|
||||
|
||||
// Получаем информацию о кооперативе
|
||||
cooperatives2_index cooperatives(_registrator, _registrator.value);
|
||||
auto coop_itr = cooperatives.find(coopname.value);
|
||||
|
||||
if (coop_itr == cooperatives.end() || !coop_itr->is_cooperative || !coop_itr->active_participants_count.has_value()) {
|
||||
eosio::check(false, "Счетчик пайщиков кооператива не найден");
|
||||
}
|
||||
|
||||
return coop_itr->active_participants_count.value();
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,6 @@ using newdeclined_interface = void(NEWDECLINED_SIGNATURE);
|
||||
#define NEWACT_SIGNATURE name coopname, name username, name action, checksum256 package, document2 document
|
||||
using newact_interface = void(NEWACT_SIGNATURE);
|
||||
|
||||
#define NEWLINK_SIGNATURE name coopname, name username, name action, checksum256 package, document2 document
|
||||
using newlink_interface = void(NEWLINK_SIGNATURE);
|
||||
|
||||
#define NEWAGREEMENT_SIGNATURE name coopname, name username, name type, document2 document
|
||||
using newagreement_interface = void(NEWAGREEMENT_SIGNATURE);
|
||||
|
||||
|
||||
@@ -1,97 +1,12 @@
|
||||
#define COMPLETEWTHD_SIGNATURE name coopname, checksum256 withdraw_hash
|
||||
#define DECLINEWTHD_SIGNATURE name coopname, checksum256 withdraw_hash, std::string reason
|
||||
|
||||
using completewthd_interface = void(COMPLETEWTHD_SIGNATURE);
|
||||
using declinewthd_interface = void(DECLINEWTHD_SIGNATURE);
|
||||
|
||||
static const std::set<eosio::name> wallet_callback_actions = {
|
||||
"authwthd"_n, // авторизация возврата паевого взноса
|
||||
"declinewthd"_n, // отклонение возврата паевого взноса
|
||||
"completewthd"_n, // завершение возврата паевого взноса
|
||||
};
|
||||
|
||||
|
||||
namespace Wallet {
|
||||
|
||||
class Wallet {
|
||||
public:
|
||||
/**
|
||||
* @ingroup public_tables
|
||||
* @brief Таблица `deposits` отслеживает депозиты в контракте WALLET.
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(WALLET)]] deposit {
|
||||
uint64_t id; /*!< Уникальный идентификатор записи ввода */
|
||||
eosio::name coopname; /*!< Имя аккаунта кооператива, в контексте которого совершается депозит */
|
||||
eosio::name username; /*!< Имя аккаунта пользователя, совершившего ввод */
|
||||
checksum256 deposit_hash; ///< Хэш входящего платежа
|
||||
|
||||
eosio::asset quantity; /*!< Количество средств во внутренней валюте */
|
||||
eosio::name status; /*!< Статус ввода */
|
||||
|
||||
eosio::time_point_sec created_at = current_time_point(); ///< Время истечения срока давности
|
||||
|
||||
uint64_t primary_key() const { return id; } /*!< Возвращает id как первичный ключ */
|
||||
uint64_t by_username() const { return username.value; } /*!< Индекс по имени пользователя */
|
||||
checksum256 by_hash() const { return deposit_hash; } /*!< Индекс по хэшу платежа */
|
||||
uint64_t by_status() const { return status.value; } /*!< Индекс по статусу вводу */
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch(); }
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"deposits"_n, deposit,
|
||||
eosio::indexed_by<"byhash"_n, eosio::const_mem_fun<deposit, checksum256, &deposit::by_hash>>,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<deposit, uint64_t, &deposit::by_username>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<deposit, uint64_t, &deposit::by_status>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<deposit, uint64_t, &deposit::by_created>>
|
||||
> deposits_index;
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup public_tables
|
||||
* @brief Таблица `withdraws` отслеживает операции вывода средств в контракте WALLET.
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(WALLET)]] withdraw {
|
||||
uint64_t id; /*!< Уникальный идентификатор записи вывода */
|
||||
eosio::name username; /*!< Имя пользователя, осуществляющего вывод средств */
|
||||
eosio::name coopname; /*!< Имя аккаунта кооператива, в рамках которого осуществляется вывод */
|
||||
checksum256 withdraw_hash; /*!< Идентификатор возврата */
|
||||
eosio::name status; /*!< Статус операции вывода */
|
||||
|
||||
eosio::asset quantity; /*!< Количество средств для вывода во внутренней валюте */
|
||||
document2 statement; /*!< Заявление на возврат */
|
||||
document2 approved_statement; /*!< Предварительно-принятое заявление */
|
||||
document2 authorization; /*!< Решение совета */
|
||||
|
||||
eosio::time_point_sec created_at = current_time_point(); ///< Время истечения срока давности
|
||||
|
||||
uint64_t primary_key() const { return id; } /*!< Возвращает id как первичный ключ */
|
||||
checksum256 by_hash() const { return withdraw_hash; } ///< Индекс по хэшу задачи.
|
||||
uint64_t by_username() const { return username.value; } /*!< Индекс по имени пользователя */
|
||||
uint64_t by_status() const { return status.value; } /*!< Индекс по статусу операции вывода */
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch(); }
|
||||
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"withdraws"_n, withdraw,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<withdraw, uint64_t, &withdraw::by_username>>,
|
||||
eosio::indexed_by<"byhash"_n, const_mem_fun<withdraw, checksum256, &withdraw::by_hash>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<withdraw, uint64_t, &withdraw::by_status>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<withdraw, uint64_t, &withdraw::by_created>>
|
||||
> withdraws_index; /*!< Мультииндекс для доступа и манипуляции данными таблицы `withdraws` */
|
||||
|
||||
|
||||
static eosio::name get_valid_wallet_action(const eosio::name& action) {
|
||||
eosio::check(wallet_callback_actions.contains(action), "Недопустимое имя действия wallet");
|
||||
return action;
|
||||
}
|
||||
|
||||
static void validate_asset(const eosio::asset& amount) {
|
||||
inline void validate_asset(const eosio::asset& amount) {
|
||||
check(amount.symbol == _root_govern_symbol, "Invalid token symbol");
|
||||
check(amount.is_valid(), "Invalid asset");
|
||||
check(amount.amount > 0, "Amount must be positive");
|
||||
}
|
||||
|
||||
static void add_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
inline void add_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
action(
|
||||
@@ -103,7 +18,7 @@ public:
|
||||
|
||||
}
|
||||
|
||||
static void sub_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
inline void sub_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
action(
|
||||
@@ -114,7 +29,7 @@ public:
|
||||
).send();
|
||||
}
|
||||
|
||||
static void add_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
inline void add_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
action(
|
||||
@@ -132,7 +47,7 @@ public:
|
||||
).send();
|
||||
}
|
||||
|
||||
static void sub_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
inline void sub_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
action(
|
||||
@@ -150,7 +65,7 @@ public:
|
||||
).send();
|
||||
}
|
||||
|
||||
static void block_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo){
|
||||
inline void block_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo){
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
action(
|
||||
@@ -161,7 +76,7 @@ public:
|
||||
).send();
|
||||
}
|
||||
|
||||
static void unblock_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo){
|
||||
inline void unblock_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo){
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
action(
|
||||
@@ -171,10 +86,17 @@ public:
|
||||
std::make_tuple(coopname, username, program.id, amount, memo)
|
||||
).send();
|
||||
}
|
||||
|
||||
inline void pay_membership_fee(name contract, name coopname, name username, name amount, eosio::name program_type, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, get_program_id(program_type));
|
||||
|
||||
static void pay_membership_fee(name contract, name coopname, name username, eosio::asset amount, uint64_t program_id, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, program_id);
|
||||
|
||||
action(
|
||||
permission_level{ contract, "active"_n },
|
||||
_soviet,
|
||||
"subbal"_n,
|
||||
std::make_tuple(coopname, username, program.id, amount, false, memo)
|
||||
).send();
|
||||
|
||||
action(
|
||||
permission_level{ contract, "active"_n },
|
||||
_soviet,
|
||||
@@ -184,20 +106,37 @@ public:
|
||||
|
||||
}
|
||||
|
||||
static void unpay_membership_fee(name contract, name coopname, name username, eosio::asset amount, uint64_t program_id, std::string memo) {
|
||||
auto program = get_program_or_fail(coopname, program_id);
|
||||
/**
|
||||
* @ingroup public_tables
|
||||
* @brief Таблица `deposits` отслеживает депозиты в контракте WALLET.
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(WALLET)]] deposit {
|
||||
uint64_t id; /*!< Уникальный идентификатор записи ввода */
|
||||
eosio::name coopname; /*!< Имя аккаунта кооператива, в контексте которого совершается депозит */
|
||||
eosio::name username; /*!< Имя аккаунта пользователя, совершившего ввод */
|
||||
checksum256 deposit_hash; ///< Хэш входящего платежа
|
||||
|
||||
eosio::asset quantity; /*!< Количество средств во внутренней валюте */
|
||||
eosio::name status; /*!< Статус ввода */
|
||||
|
||||
action(
|
||||
permission_level{ contract, "active"_n },
|
||||
_soviet,
|
||||
"submemberfee"_n,
|
||||
std::make_tuple(coopname, username, program.id, amount, memo)
|
||||
).send();
|
||||
|
||||
}
|
||||
eosio::time_point_sec created_at = current_time_point(); ///< Время истечения срока давности
|
||||
|
||||
uint64_t primary_key() const { return id; } /*!< Возвращает id как первичный ключ */
|
||||
uint64_t by_username() const { return username.value; } /*!< Индекс по имени пользователя */
|
||||
checksum256 by_hash() const { return deposit_hash; } /*!< Индекс по хэшу платежа */
|
||||
uint64_t by_status() const { return status.value; } /*!< Индекс по статусу вводу */
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch(); }
|
||||
};
|
||||
|
||||
|
||||
static std::optional<deposit> get_deposit(eosio::name coopname, const checksum256 &hash) {
|
||||
typedef eosio::multi_index<
|
||||
"deposits"_n, deposit,
|
||||
eosio::indexed_by<"byhash"_n, eosio::const_mem_fun<deposit, checksum256, &deposit::by_hash>>,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<deposit, uint64_t, &deposit::by_username>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<deposit, uint64_t, &deposit::by_status>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<deposit, uint64_t, &deposit::by_created>>
|
||||
> deposits_index;
|
||||
|
||||
inline std::optional<deposit> get_deposit(eosio::name coopname, const checksum256 &hash) {
|
||||
deposits_index primary_index(_wallet, coopname.value);
|
||||
auto secondary_index = primary_index.get_index<"byhash"_n>();
|
||||
|
||||
@@ -207,7 +146,41 @@ public:
|
||||
}
|
||||
|
||||
return *itr;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup public_tables
|
||||
* @brief Таблица `withdraws` отслеживает операции вывода средств в контракте WALLET.
|
||||
*/
|
||||
struct [[eosio::table, eosio::contract(WALLET)]] withdraw {
|
||||
uint64_t id; /*!< Уникальный идентификатор записи вывода */
|
||||
eosio::name username; /*!< Имя пользователя, осуществляющего вывод средств */
|
||||
eosio::name coopname; /*!< Имя аккаунта кооператива, в рамках которого осуществляется вывод */
|
||||
checksum256 withdraw_hash; /*!< Идентификатор возврата */
|
||||
eosio::name status; /*!< Статус операции вывода */
|
||||
|
||||
eosio::asset quantity; /*!< Количество средств для вывода во внутренней валюте */
|
||||
document2 statement; /*!< Заявление на возврат */
|
||||
document2 approved_statement; /*!< Предварительно-принятое заявление */
|
||||
document2 authorization; /*!< Решение совета */
|
||||
|
||||
eosio::time_point_sec created_at = current_time_point(); ///< Время истечения срока давности
|
||||
|
||||
uint64_t primary_key() const { return id; } /*!< Возвращает id как первичный ключ */
|
||||
checksum256 by_hash() const { return withdraw_hash; } ///< Индекс по хэшу задачи.
|
||||
uint64_t by_username() const { return username.value; } /*!< Индекс по имени пользователя */
|
||||
uint64_t by_status() const { return status.value; } /*!< Индекс по статусу операции вывода */
|
||||
uint64_t by_created() const { return created_at.sec_since_epoch(); }
|
||||
|
||||
};
|
||||
|
||||
typedef eosio::multi_index<
|
||||
"withdraws"_n, withdraw,
|
||||
eosio::indexed_by<"byusername"_n, eosio::const_mem_fun<withdraw, uint64_t, &withdraw::by_username>>,
|
||||
eosio::indexed_by<"byhash"_n, const_mem_fun<withdraw, checksum256, &withdraw::by_hash>>,
|
||||
eosio::indexed_by<"bystatus"_n, eosio::const_mem_fun<withdraw, uint64_t, &withdraw::by_status>>,
|
||||
eosio::indexed_by<"bycreated"_n, eosio::const_mem_fun<withdraw, uint64_t, &withdraw::by_created>>
|
||||
> withdraws_index; /*!< Мультииндекс для доступа и манипуляции данными таблицы `withdraws` */
|
||||
|
||||
|
||||
/**
|
||||
@@ -216,7 +189,7 @@ public:
|
||||
* @param hash Хэш возврата.
|
||||
* @return `std::optional<withdraw>` - найденное действие или `std::nullopt`, если его нет.
|
||||
*/
|
||||
static std::optional<withdraw> get_withdraw(eosio::name coopname, const checksum256 &hash) {
|
||||
inline std::optional<withdraw> get_withdraw(eosio::name coopname, const checksum256 &hash) {
|
||||
withdraws_index primary_index(_wallet, coopname.value);
|
||||
auto secondary_index = primary_index.get_index<"byhash"_n>();
|
||||
|
||||
@@ -226,6 +199,7 @@ public:
|
||||
}
|
||||
|
||||
return *itr;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -57,44 +57,4 @@ uint64_t generate() {
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
std::string checksum256_to_hex(const eosio::checksum256& hash) {
|
||||
auto hash_bytes = hash.extract_as_byte_array();
|
||||
std::string hash_hex;
|
||||
for (const auto& byte : hash_bytes) {
|
||||
char hex_char[3];
|
||||
sprintf(hex_char, "%02x", byte);
|
||||
hash_hex += hex_char;
|
||||
}
|
||||
return hash_hex;
|
||||
}
|
||||
|
||||
uint64_t extract_registry_id_from_meta(const std::string& meta_json) {
|
||||
// Ищем "registry_id": и извлекаем число после двоеточия
|
||||
std::string search_key = "\"registry_id\":";
|
||||
size_t pos = meta_json.find(search_key);
|
||||
|
||||
eosio::check(pos != std::string::npos, "registry_id not found in meta");
|
||||
|
||||
// Перемещаемся после двоеточия
|
||||
pos += search_key.length();
|
||||
|
||||
// Ищем первую цифру
|
||||
while (pos < meta_json.length() && (meta_json[pos] < '0' || meta_json[pos] > '9')) {
|
||||
pos++;
|
||||
}
|
||||
|
||||
eosio::check(pos < meta_json.length(), "registry_id value not found");
|
||||
|
||||
// Собираем цифры
|
||||
uint64_t result = 0;
|
||||
while (pos < meta_json.length() && meta_json[pos] >= '0' && meta_json[pos] <= '9') {
|
||||
result = result * 10 + (meta_json[pos] - '0');
|
||||
pos++;
|
||||
}
|
||||
|
||||
eosio::check(result > 0, "invalid registry_id value");
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -11,8 +11,17 @@
|
||||
### Структуры
|
||||
|
||||
- `balance`: Описывает баланс пользователя.
|
||||
- `requests`: Описывает информацию об обмене.
|
||||
- `requests_params`: Параметры обмена, включая имя пользователя, контракт, количество единиц, цену за штуку и дополнительные данные и метаданные.
|
||||
- `exchange`: Описывает информацию об обмене.
|
||||
- `exchange_params`: Параметры обмена, включая имя пользователя, контракт, количество единиц, цену за штуку и дополнительные данные и метаданные.
|
||||
|
||||
### Действия
|
||||
|
||||
Контракт включает в себя следующие действия:
|
||||
|
||||
- **Действия обмена**: `offer`, `order`, `complete`, `decline`, `accept`.
|
||||
- **Административные действия**: `moderate`, `prohibit`, `unpublish`, `publish`.
|
||||
- **Действия авторизации**: `authorize`.
|
||||
- **Прочие действия**: `newid` (используется для возврата информации из контракта), `update`, `addpieces`.
|
||||
|
||||
## Использование
|
||||
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
#include "marketplace.hpp"
|
||||
#include <eosio/transaction.hpp>
|
||||
#include "src/accept.cpp"
|
||||
#include "src/addunits.cpp"
|
||||
#include "src/authorize.cpp"
|
||||
#include "src/cancel.cpp"
|
||||
#include "src/change.cpp"
|
||||
#include "src/complete.cpp"
|
||||
#include "src/decline.cpp"
|
||||
#include "src/delivered.cpp"
|
||||
#include "src/dispute.cpp"
|
||||
#include "src/moderate.cpp"
|
||||
#include "src/offer.cpp"
|
||||
#include "src/order.cpp"
|
||||
#include "src/prohibit.cpp"
|
||||
#include "src/publish.cpp"
|
||||
#include "src/recieve.cpp"
|
||||
#include "src/recievecnfrm.cpp"
|
||||
#include "src/supply.cpp"
|
||||
#include "src/supplycnfrm.cpp"
|
||||
#include "src/unpublish.cpp"
|
||||
#include "src/update.cpp"
|
||||
|
||||
// Процесс поставки по заявкам orderoffer
|
||||
#include "src/deliver_on_offer/orderoffer.cpp"
|
||||
#include "src/deliver_on_offer/accept.cpp"
|
||||
#include "src/deliver_on_offer/authcontrib.cpp"
|
||||
#include "src/deliver_on_offer/authreturn.cpp"
|
||||
#include "src/deliver_on_offer/declineacc.cpp"
|
||||
#include "src/deliver_on_offer/supply.cpp"
|
||||
#include "src/deliver_on_offer/supplcnf.cpp"
|
||||
|
||||
#include "src/deliver_on_offer/delivered.cpp"
|
||||
#include "src/deliver_on_offer/receive.cpp"
|
||||
#include "src/deliver_on_offer/receivecnf.cpp"
|
||||
#include "src/deliver_on_offer/complete.cpp"
|
||||
#include "src/deliver_on_offer/decline.cpp"
|
||||
#include "src/deliver_on_offer/cancel.cpp"
|
||||
|
||||
// Новая система перевозок
|
||||
#include "src/shipment/createship.cpp"
|
||||
#include "src/shipment/signbydriver.cpp"
|
||||
#include "src/shipment/arrived.cpp"
|
||||
#include "src/shipment/receiveshipm.cpp"
|
||||
#include "src/shipment/retransport.cpp"
|
||||
|
||||
// Диспуты
|
||||
#include "src/dispute_on_offer/dispute.cpp"
|
||||
#include "src/dispute_on_offer/wauthorize.cpp"
|
||||
#include "src/dispute_on_offer/wreturn.cpp"
|
||||
#include "src/dispute_on_offer/woffer.cpp"
|
||||
#include "src/dispute_on_offer/waccept.cpp"
|
||||
/**
|
||||
* @brief Пустой метод регистрации нового идентификатора
|
||||
* @ingroup public_actions
|
||||
* Этот метод используется для возврата информации из контракта.
|
||||
* @param id идентификатор
|
||||
* @param type тип идентификатора
|
||||
*/
|
||||
[[eosio::action]] void marketplace::newid(uint64_t id, eosio::name type) {
|
||||
require_auth(_marketplace);
|
||||
};
|
||||
|
||||
|
||||
[[eosio::action]] void marketplace::migrate(){
|
||||
// require_auth(_marketplace);
|
||||
}
|
||||
require_auth(_marketplace);
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
#include "../lib/common.hpp"
|
||||
|
||||
using namespace Marketplace;
|
||||
|
||||
/**
|
||||
* \ingroup public_contracts
|
||||
* @brief Класс `marketplace` предоставляет функционал кооперативного маркетплейса, позволяя пользователям
|
||||
@@ -17,28 +15,12 @@ using namespace Marketplace;
|
||||
* центральной точкой для всех операций обмена в рамках кооперативной экосистемы.
|
||||
*
|
||||
* Основные функции класса:
|
||||
* - Создание и управление заявками типа orderoffer (заказчик → поставщик).
|
||||
* - Создание и управление заявками на обмен, включая предложения и заказы.
|
||||
* - Операции обновления, принятия, отказа и завершения обменных операций.
|
||||
* - Модерация и управление публикацией заявок на обмен.
|
||||
* - Административные функции, такие как создание идентификаторов и авторизация операций.
|
||||
*
|
||||
* ## Процесс поставки orderoffer:
|
||||
*
|
||||
* 1. **orderoffer** - заказчик создает заявку с документами на возврат и конвертацию, средства блокируются
|
||||
* 2. **accept** - поставщик принимает заявку и предоставляет документы на взнос и конвертацию
|
||||
* 3. **authcontrib/authreturn** - совет авторизует оба заявления раздельно
|
||||
* 4. **supply** → **supplcnf** - поставка товара и подтверждение председателем КУ
|
||||
* 5. **deliver1** → **deliver2** → **deliver3** → **deliver4** - этапы транспортировки
|
||||
* 6. **receive** → **receivecnf** - получение товара заказчиком
|
||||
* 7. **complete** - завершение поставки после гарантийного периода
|
||||
*
|
||||
* ## Документооборот:
|
||||
*
|
||||
* Все документы сохраняются в векторе `std::vector<document2> documents` в заявке.
|
||||
* Каждый этап процесса добавляет необходимые документы в этот вектор.
|
||||
*
|
||||
* \note Контракт маркетплейса является центральной точкой экономической активности на платформе.
|
||||
* \note Система упрощена для работы с одной заявкой вместо двух встречных.
|
||||
*/
|
||||
class [[eosio::contract(MARKETPLACE)]] marketplace : public eosio::contract {
|
||||
|
||||
@@ -47,47 +29,54 @@ public:
|
||||
eosio::datastream<const char *> ds)
|
||||
: eosio::contract(receiver, code, ds) {}
|
||||
|
||||
|
||||
void apply(uint64_t receiver, uint64_t code, uint64_t action);
|
||||
[[eosio::action]] void migrate();
|
||||
|
||||
// ... определение методов контракта ...
|
||||
|
||||
//marketplace.cpp
|
||||
[[eosio::action]] void newid(uint64_t id, eosio::name type);
|
||||
|
||||
// Действия для создания заявок
|
||||
[[eosio::action]] void orderoffer(eosio::name coopname, eosio::name receiver_braname, eosio::name username, checksum256 hash, uint64_t units, eosio::asset unit_cost, uint32_t product_lifecycle_secs, uint32_t warranty_period_secs, eosio::asset membership_fee_amount, eosio::asset cancellation_fee_amount, document2 product_return_statement, document2 convert_in, std::string meta);
|
||||
//soviet.cpp
|
||||
[[eosio::action]] void authorize(eosio::name coopname, uint64_t exchange_id, uint64_t contribution_product_decision_id, document2 contribution_product_authorization, uint64_t return_product_decision_id, document2 return_product_authorization);
|
||||
|
||||
static void cancel_request(eosio::name coopname, eosio::name username, checksum256 request_hash);
|
||||
|
||||
// Статические методы для отклонения заявок
|
||||
static void decline_request(eosio::name coopname, const request& change);
|
||||
//change.cpp
|
||||
[[eosio::action]] void offer(const exchange_params& params);
|
||||
[[eosio::action]] void order(const exchange_params& params);
|
||||
|
||||
// Методы для направления заявок
|
||||
[[eosio::action]] void accept(eosio::name coopname, eosio::name supplier_braname, eosio::name username, checksum256 request_hash, document2 convert_out, document2 return_document);
|
||||
[[eosio::action]] void authcontrib(eosio::name coopname, checksum256 request_hash, document2 authorization);
|
||||
[[eosio::action]] void authreturn(eosio::name coopname, checksum256 request_hash, document2 authorization);
|
||||
[[eosio::action]] void declineacc(eosio::name coopname, checksum256 hash, std::string reason);
|
||||
[[eosio::action]] void supply(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 act);
|
||||
[[eosio::action]] void supplcnf(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 act);
|
||||
static void create(eosio::name type, const exchange_params& params);
|
||||
static void create_parent(eosio::name type, const exchange_params& params);
|
||||
static void create_child(eosio::name type, const exchange_params& params);
|
||||
static void cancel_parent(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
static void cancel_child(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
|
||||
[[eosio::action]] void accept(eosio::name coopname, eosio::name username, uint64_t exchange_id, document2 document);
|
||||
[[eosio::action]] void decline(eosio::name coopname, eosio::name username, uint64_t exchange_id, std::string meta);
|
||||
|
||||
[[eosio::action]] void supplycnfrm(eosio::name coopname, eosio::name username, uint64_t exchange_id, document2 document);
|
||||
[[eosio::action]] void supply(eosio::name coopname, eosio::name username, uint64_t exchange_id, document2 document);
|
||||
[[eosio::action]] void delivered(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
[[eosio::action]] void recieve(eosio::name coopname, eosio::name username, uint64_t exchange_id, document2 document);
|
||||
[[eosio::action]] void recievecnfrm(eosio::name coopname, eosio::name username, uint64_t exchange_id, document2 document);
|
||||
|
||||
[[eosio::action]] void dispute(eosio::name coopname, eosio::name username, uint64_t exchange_id, document2 document);
|
||||
|
||||
// Новая система перевозок
|
||||
[[eosio::action]] void createship(eosio::name coopname, checksum256 hash, eosio::name driver_username, eosio::name source_braname, eosio::name destination_braname, std::vector<checksum256> request_hashes, document2 transport_act_sender);
|
||||
[[eosio::action]] void signbydriver(eosio::name coopname, checksum256 hash, document2 transport_act_driver);
|
||||
[[eosio::action]] void arrived(eosio::name coopname, checksum256 hash, document2 transport_act_delivery);
|
||||
[[eosio::action]] void receiveshipm(eosio::name coopname, checksum256 hash, document2 warehouse_receipt_act);
|
||||
[[eosio::action]] void retransport(eosio::name coopname, checksum256 completed_hash, eosio::name new_driver_username, eosio::name source_braname, eosio::name new_destination_braname, std::vector<checksum256> request_hashes, document2 transport_act_sender);
|
||||
[[eosio::action]] void complete(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
|
||||
[[eosio::action]] void cancel(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
|
||||
// Доставка заказчику
|
||||
[[eosio::action]] void delivered(eosio::name coopname, eosio::name username, checksum256 request_hash);
|
||||
[[eosio::action]] void receive(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document);
|
||||
[[eosio::action]] void receivecnf(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document);
|
||||
[[eosio::action]] void complete(eosio::name coopname, eosio::name username, checksum256 request_hash);
|
||||
[[eosio::action]] void decline(eosio::name coopname, eosio::name username, checksum256 request_hash, std::string meta);
|
||||
[[eosio::action]] void cancel(eosio::name coopname, eosio::name username, checksum256 request_hash);
|
||||
|
||||
// Методы для работы с диспутом (гарантийный возврат)
|
||||
[[eosio::action]] void dispute(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document);
|
||||
[[eosio::action]] void wauthorize(eosio::name coopname, checksum256 request_hash, uint64_t wreturn_decision_id, document2 wreturn_authorization, uint64_t wsupply_decision_id, document2 wsupply_authorization);
|
||||
[[eosio::action]] void wreturn(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document);
|
||||
[[eosio::action]] void woffer(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document);
|
||||
[[eosio::action]] void waccept(eosio::name coopname, eosio::name username, checksum256 request_hash, bool accept, document2 document);
|
||||
[[eosio::action]] void update(eosio::name coopname, eosio::name username, uint64_t exchange_id, uint64_t remain_units, eosio::asset unit_cost, std::string data, std::string meta);
|
||||
[[eosio::action]] void addunits(eosio::name coopname, eosio::name username, uint64_t exchange_id, uint64_t units);
|
||||
|
||||
//admins.cpp
|
||||
[[eosio::action]] void moderate(eosio::name coopname, eosio::name username, uint64_t exchange_id, uint64_t cancellation_fee);
|
||||
[[eosio::action]] void prohibit(eosio::name coopname, eosio::name username, uint64_t exchange_id, std::string meta);
|
||||
[[eosio::action]] void unpublish(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
[[eosio::action]] void publish(eosio::name coopname, eosio::name username, uint64_t exchange_id);
|
||||
|
||||
|
||||
struct [[eosio::table, eosio::contract("marketplace")]] balances : balances_base {};
|
||||
struct [[eosio::table, eosio::contract("marketplace")]] counts : counts_base {};
|
||||
|
||||
};
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Принятие заявки поставщиком.
|
||||
|
||||
@details Поставщик принимает заявку orderoffer на поставку имущества и предоставляет необходимые документы.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param supplier_braname Имя кооперативного участка поставщика
|
||||
@param username Имя поставщика
|
||||
@param request_hash Хэш заявки
|
||||
@param convert_out Заявление на конвертацию
|
||||
@param product_contribution_statement Заявление на имущественный паевой взнос
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::accept(eosio::name coopname, eosio::name supplier_braname, eosio::name username, checksum256 request_hash, document2 convert_out, document2 product_contribution_statement) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "active"_n, "Только активная заявка может быть принята");
|
||||
eosio::check(change.type == "orderoffer"_n, "Метод accept применим только к заявкам типа orderoffer");
|
||||
|
||||
// Проверяем существование кооперативного участка поставщика
|
||||
get_branch_or_fail(coopname, supplier_braname);
|
||||
|
||||
// Проверяем подписи документов
|
||||
verify_document_or_fail(convert_out);
|
||||
verify_document_or_fail(product_contribution_statement);
|
||||
|
||||
// Валидируем документы по registry_id (пока что нули)
|
||||
Document::validate_registry_id(convert_out, 0);
|
||||
Document::validate_registry_id(product_contribution_statement, 0);
|
||||
|
||||
// Получаем первоначальный документ возврата из заявки по имени
|
||||
document2 initial_return_statement;
|
||||
bool found = Document::find_document(change.documents, DocumentNames::RETURN_STMT, initial_return_statement);
|
||||
eosio::check(found, "В заявке отсутствует заявление на возврат имущества");
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "accepted"_n;
|
||||
o.accepted_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
o.product_contributor = username;
|
||||
o.supplier_braname = supplier_braname;
|
||||
// Добавляем новые документы с именами
|
||||
Document::add_document(o.documents, DocumentNames::CONVERT_TO, convert_out);
|
||||
Document::add_document(o.documents, DocumentNames::CONTRIB_STMT, product_contribution_statement);
|
||||
});
|
||||
|
||||
// Используем хэш заявки как идентификатор пакета решений
|
||||
checksum256 agenda_hash = change.hash;
|
||||
|
||||
// Отправляем ПЕРВЫЙ вопрос в совет - по заявлению на имущественный паевой взнос
|
||||
Action::send<createagenda_interface>(
|
||||
_soviet,
|
||||
"createagenda"_n,
|
||||
_marketplace,
|
||||
coopname,
|
||||
username,
|
||||
get_valid_soviet_action("authcontrib"_n), // авторизация взноса имуществом
|
||||
agenda_hash,
|
||||
_marketplace,
|
||||
Marketplace::get_valid_marketplace_action("authcontrib"_n),
|
||||
"declineacc"_n,
|
||||
product_contribution_statement,
|
||||
std::string("")
|
||||
);
|
||||
|
||||
// Отправляем ВТОРОЙ вопрос в совет - по заявлению на возврат имущества
|
||||
Action::send<createagenda_interface>(
|
||||
_soviet,
|
||||
"createagenda"_n,
|
||||
_marketplace,
|
||||
coopname,
|
||||
username,
|
||||
get_valid_soviet_action("authreturn"_n), // авторизация возврата имуществом
|
||||
agenda_hash,
|
||||
_marketplace,
|
||||
Marketplace::get_valid_marketplace_action("authreturn"_n),
|
||||
"declineacc"_n,
|
||||
initial_return_statement,
|
||||
std::string("")
|
||||
);
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Авторизация заявления на имущественный паевой взнос советом кооператива.
|
||||
|
||||
@details Совет кооператива авторизует заявление на имущественный паевой взнос.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param request_hash Хэш заявки
|
||||
@param authorization Документ авторизации от совета
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p _soviet
|
||||
**/
|
||||
[[eosio::action]] void marketplace::authcontrib(eosio::name coopname, checksum256 request_hash, document2 authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "accepted"_n, "Только принятая заявка может быть авторизована");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(authorization);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(authorization, 0);
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
// Добавляем документ авторизации взноса с именем
|
||||
Document::add_document(o.documents, DocumentNames::CONTRIB_AUTH, authorization);
|
||||
|
||||
// Проверяем, есть ли уже оба документа авторизации
|
||||
bool has_contrib_auth = Document::has_document(o.documents, DocumentNames::CONTRIB_AUTH);
|
||||
bool has_return_auth = Document::has_document(o.documents, DocumentNames::RETURN_AUTH);
|
||||
|
||||
// Если получили оба документа авторизации, переводим в статус authorized
|
||||
if (has_contrib_auth && has_return_auth) {
|
||||
o.status = "authorized"_n;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Авторизация заявления на возврат имущества советом кооператива.
|
||||
|
||||
@details Совет кооператива авторизует заявление на возврат имущества.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param request_hash Хэш заявки
|
||||
@param authorization Документ авторизации от совета
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p _soviet
|
||||
**/
|
||||
[[eosio::action]] void marketplace::authreturn(eosio::name coopname, checksum256 request_hash, document2 authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "accepted"_n, "Только принятая заявка может быть авторизована");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(authorization);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(authorization, 0);
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
// Добавляем документ авторизации возврата с именем
|
||||
Document::add_document(o.documents, DocumentNames::RETURN_AUTH, authorization);
|
||||
|
||||
// Проверяем, есть ли уже оба документа авторизации
|
||||
bool has_contrib_auth = Document::has_document(o.documents, DocumentNames::CONTRIB_AUTH);
|
||||
bool has_return_auth = Document::has_document(o.documents, DocumentNames::RETURN_AUTH);
|
||||
|
||||
// Если получили оба документа авторизации, переводим в статус authorized
|
||||
if (has_contrib_auth && has_return_auth) {
|
||||
o.status = "authorized"_n;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Отмена заявки пользователем.
|
||||
|
||||
@details Пользователь может отменить свою заявку с учетом комиссии за отмену.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя пользователя
|
||||
@param request_hash Хэш заявки
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::cancel(eosio::name coopname, eosio::name username, checksum256 request_hash) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
// Проверяем права доступа
|
||||
eosio::check(change.username == username || change.product_contributor == username, "Недостаточно прав доступа");
|
||||
|
||||
// Ограничения отмены
|
||||
eosio::check(change.status != "completed"_n, "Нельзя отменить завершенную заявку");
|
||||
eosio::check(change.status != "canceled"_n, "Заявка уже отменена");
|
||||
eosio::check(change.status != "declined"_n, "Нельзя отменить отклоненную заявку");
|
||||
|
||||
// Поставщик не может отменить заявку после поставки
|
||||
if ((change.money_contributor != username && change.product_contributor != username) ||
|
||||
(change.product_contributor == username && (change.status == "supplied1"_n || change.status == "supplied2"_n ||
|
||||
change.status == "delivered"_n || change.status == "received1"_n || change.status == "received2"_n))) {
|
||||
eosio::check(false, "Поставщик не может отменить заявку после поставки");
|
||||
}
|
||||
|
||||
std::string memo = "Отмена заявки №" + std::to_string(change.id);
|
||||
|
||||
// Возвращаем средства заказчику с учетом комиссии за отмену
|
||||
if (username == change.money_contributor) {
|
||||
eosio::asset return_amount = change.total_cost - change.cancellation_fee_amount;
|
||||
|
||||
// Списываем заблокированные средства
|
||||
Wallet::sub_blocked_funds(_marketplace, coopname, change.money_contributor, change.total_cost, _marketplace_program, memo);
|
||||
|
||||
// Возвращаем средства в кошелёк
|
||||
Wallet::add_available_funds(_marketplace, coopname, change.money_contributor, return_amount, _wallet_program, memo);
|
||||
|
||||
// Направляем комиссию в фонд членских взносов
|
||||
if (change.cancellation_fee_amount.amount > 0) {
|
||||
// Wallet::add_member_fee(_marketplace, coopname, change.username, _marketplace_program_id, change.cancellation_fee_amount, memo);
|
||||
}
|
||||
}
|
||||
|
||||
// Удаляем заявку из системы
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для удаления");
|
||||
requests.erase(change_itr);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Завершение поставки.
|
||||
|
||||
@details После истечения гарантийной задержки происходит завершение поставки.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя пользователя
|
||||
@param request_hash Хэш заявки
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::complete(eosio::name coopname, eosio::name username, checksum256 request_hash) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "received"_n, "Завершение возможно только после статуса received");
|
||||
eosio::check(eosio::time_point_sec(eosio::current_time_point()) >= change.warranty_delay_until, "Гарантийная задержка ещё не истекла");
|
||||
|
||||
// Проводки по кошельку
|
||||
std::string memo = "Завершение поставки для заказа №" + std::to_string(change.id);
|
||||
|
||||
// Поставщик - списываем заблокированный баланс и начисляем в кошелёк
|
||||
Wallet::sub_blocked_funds(_marketplace, coopname, change.product_contributor, change.base_cost, _marketplace_program, memo);
|
||||
Wallet::add_available_funds(_marketplace, coopname, change.product_contributor, change.base_cost, _wallet_program, memo);
|
||||
|
||||
// Членские взносы (если больше нуля)
|
||||
if (change.membership_fee_amount.amount > 0) {
|
||||
// Wallet::add_member_fee(_marketplace, coopname, change.username, _marketplace_program_id, change.membership_fee_amount, memo);
|
||||
}
|
||||
|
||||
// Удаляем заявку из системы
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для удаления");
|
||||
requests.erase(change_itr);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Отклонение заявки.
|
||||
|
||||
@details Отклонение заявки с указанием причины.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя пользователя
|
||||
@param request_hash Хэш заявки
|
||||
@param meta Причина отклонения
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::decline(eosio::name coopname, eosio::name username, checksum256 request_hash, std::string meta) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "active"_n || change.status == "accepted"_n, "Можно отклонить только активную или принятую заявку");
|
||||
|
||||
std::string memo = "Отклонение заявки №" + std::to_string(change.id) + ": " + meta;
|
||||
|
||||
// Возвращаем средства заказчику если они были заблокированы
|
||||
if (change.status == "active"_n && change.money_contributor != ""_n) {
|
||||
// Списываем заблокированные средства
|
||||
Wallet::sub_blocked_funds(_marketplace, coopname, change.money_contributor, change.total_cost, _marketplace_program, memo);
|
||||
|
||||
// Возвращаем средства в кошелёк
|
||||
Wallet::add_available_funds(_marketplace, coopname, change.money_contributor, change.total_cost, _wallet_program, memo);
|
||||
}
|
||||
|
||||
// Удаляем заявку из системы
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для удаления");
|
||||
requests.erase(change_itr);
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Отклонение принятия заявки советом (declineacc).
|
||||
|
||||
@details Данный метод вызывается советом когда заявление на конвертацию, возврат или взнос отклоняется.
|
||||
После рефакторинга работаем только с одной заявкой orderoffer.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param request_hash Хэш заявки, которая должна быть отменена
|
||||
@param reason Причина отклонения
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p _soviet
|
||||
*/
|
||||
[[eosio::action]] void marketplace::declineacc(eosio::name coopname, checksum256 request_hash, std::string reason) {
|
||||
require_auth(_soviet);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
|
||||
// Если заявка не найдена, ничего не делаем (возможно уже удалена)
|
||||
if (!change_opt.has_value()) {
|
||||
print("Заявка уже удалена или не найдена. Кооператив: ", coopname, ", причина: ", reason);
|
||||
return;
|
||||
}
|
||||
|
||||
auto change = change_opt.value();
|
||||
|
||||
// Логирование отклонения
|
||||
print("Отклонение заявления советом. Заявка ID: ", change.id, ", причина: ", reason);
|
||||
|
||||
// Отклоняем заявку
|
||||
decline_request(coopname, change);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Статический метод для отклонения заявки (используется советом)
|
||||
*/
|
||||
void marketplace::decline_request(eosio::name coopname, const request& change) {
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
|
||||
// Проверяем, что заявка все еще существует
|
||||
auto change_itr = requests.find(change.id);
|
||||
if (change_itr == requests.end()) {
|
||||
return; // Заявка уже удалена
|
||||
}
|
||||
|
||||
std::string memo = "Отклонение заявления советом по программе №" + std::to_string(_marketplace_program_id) + " для заявки ID: " + std::to_string(change.id);
|
||||
|
||||
// Возвращаем средства заказчику если они были заблокированы
|
||||
if (change.type == "orderoffer"_n && change.total_cost.amount > 0 && change.money_contributor != ""_n) {
|
||||
// Списываем заблокированные средства с маркетплейса
|
||||
Wallet::sub_blocked_funds(_marketplace, coopname, change.money_contributor, change.total_cost, _marketplace_program, memo);
|
||||
|
||||
// Возвращаем средства в кошелёк
|
||||
Wallet::add_available_funds(_marketplace, coopname, change.money_contributor, change.total_cost, _wallet_program, memo);
|
||||
}
|
||||
|
||||
// Удаляем заявку из системы
|
||||
requests.erase(change_itr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Перевод заявки в статус готово к выдаче.
|
||||
|
||||
@details Председатель КУ переводит заявку в статус delivered независимо от транспортировки.
|
||||
Используется когда транспортировка между КУ не нужна или имущество уже находится на складе.
|
||||
Просто перевод статуса без дополнительных документов.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя пользователя (может быть поставщиком или заказчиком)
|
||||
@param request_hash Хэш заявки
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::delivered(eosio::name coopname, eosio::name username, checksum256 request_hash) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
// Проверяем что заявка в подходящем статусе (после поставки или перемещения со склада)
|
||||
eosio::check(change.status == "supplied2"_n || change.status == "shiprecvd"_n, "Перевод в статус delivered возможен только после поставки (supplied2) или после получения на склад (shiprecvd)");
|
||||
|
||||
// Обновляем заявку - просто перевод статуса
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "delivered"_n;
|
||||
o.delivered_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
// Устанавливаем крайний срок получения (3 дня)
|
||||
o.deadline_for_receipt = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + 3 * 24 * 60 * 60);
|
||||
});
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Создать заявку orderoffer - заказчик создает заявку на поставку товара от поставщика.
|
||||
*
|
||||
* Данный метод позволяет заказчику создать заявку на поставку товара от поставщика.
|
||||
* Заявка содержит всю информацию о товаре, стоимости, документах и сразу блокирует средства заказчика.
|
||||
*
|
||||
* @param coopname Имя кооператива
|
||||
* @param receiver_braname Имя кооперативного участка заказчика для получения товара
|
||||
* @param username Имя заказчика
|
||||
* @param hash Хэш заявки (уникальный идентификатор)
|
||||
* @param units Количество единиц товара
|
||||
* @param unit_cost Цена за единицу товара
|
||||
* @param product_lifecycle_secs Время жизни продукта
|
||||
* @param warranty_period_secs Гарантийный срок в секундах
|
||||
* @param membership_fee_amount Сумма членского взноса
|
||||
* @param cancellation_fee_amount Сумма комиссии за отмену заявки
|
||||
* @param product_return_statement Заявление на возврат паевого взноса имуществом
|
||||
* @param convert_in Заявление на конвертацию из кошелька в маркетплейс
|
||||
* @param meta Метаданные о заявке
|
||||
*
|
||||
* @note Авторизация требуется от аккаунта: @p coopname
|
||||
*/
|
||||
[[eosio::action]] void marketplace::orderoffer(eosio::name coopname, eosio::name receiver_braname, eosio::name username, checksum256 hash, uint64_t units, eosio::asset unit_cost, uint32_t product_lifecycle_secs, uint32_t warranty_period_secs, eosio::asset membership_fee_amount, eosio::asset cancellation_fee_amount, document2 product_return_statement, document2 convert_in, std::string meta) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем, что заявка с таким хэшем не существует
|
||||
auto existing_request = get_request_by_hash(coopname, hash);
|
||||
eosio::check(!existing_request.has_value(), "Заявка с таким хэшем уже существует");
|
||||
|
||||
// Проверяем, что символ токена совпадает с символом токена кооператива
|
||||
auto coop = get_cooperative_or_fail(coopname);
|
||||
eosio::check(unit_cost.symbol == coop.initial.symbol, "Неверный символ токена");
|
||||
eosio::check(membership_fee_amount.symbol == coop.initial.symbol, "Неверный символ токена для членского взноса");
|
||||
eosio::check(cancellation_fee_amount.symbol == coop.initial.symbol, "Неверный символ токена для комиссии отмены");
|
||||
eosio::check(units > 0, "Количество единиц в заявке должно быть больше нуля");
|
||||
eosio::check(unit_cost.amount >= 0, "Цена не может быть отрицательной");
|
||||
eosio::check(membership_fee_amount.amount >= 0, "Членский взнос не может быть отрицательным");
|
||||
eosio::check(cancellation_fee_amount.amount >= 0, "Комиссия за отмену не может быть отрицательной");
|
||||
|
||||
// Проверяем, что пользователь является пайщиком кооператива
|
||||
get_participant_or_fail(coopname, username);
|
||||
|
||||
// Проверяем существование кооперативного участка заказчика
|
||||
get_branch_or_fail(coopname, receiver_braname);
|
||||
|
||||
// Проверяем существование программы маркетплейса
|
||||
auto program = get_program_or_fail(coopname, _marketplace_program_id);
|
||||
|
||||
// Гарантийный срок возврата должен быть установлен
|
||||
eosio::check(product_lifecycle_secs > 0, "Гарантийный срок возврата для имущества должен быть установлен");
|
||||
eosio::check(warranty_period_secs > 0, "Гарантийный срок должен быть больше нуля");
|
||||
|
||||
// Проводим проверку подписи документов
|
||||
verify_document_or_fail(product_return_statement);
|
||||
verify_document_or_fail(convert_in);
|
||||
|
||||
// Валидируем документы по registry_id (пока что нули как просил пользователь)
|
||||
Document::validate_registry_id(product_return_statement, 0);
|
||||
Document::validate_registry_id(convert_in, 0);
|
||||
|
||||
// Рассчитываем стоимость
|
||||
eosio::asset base_cost = unit_cost * units;
|
||||
eosio::asset total_cost = base_cost + membership_fee_amount;
|
||||
|
||||
// Проверяем что комиссия за отмену не превышает общую стоимость
|
||||
eosio::check(cancellation_fee_amount <= total_cost, "Комиссия за отмену не может превышать общую стоимость заявки");
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
uint64_t request_id = get_global_id(_marketplace, "requests"_n);
|
||||
|
||||
std::string memo = "Начало поставки по программе №" + std::to_string(_marketplace_program_id) + " с ID: " + std::to_string(request_id);
|
||||
|
||||
// Создаем вектор именованных документов
|
||||
std::vector<Document::named_document> documents;
|
||||
Document::add_document(documents, DocumentNames::RETURN_STMT, product_return_statement);
|
||||
Document::add_document(documents, DocumentNames::CONVERT_FROM, convert_in);
|
||||
|
||||
requests.emplace(_marketplace, [&](auto &i) {
|
||||
i.id = request_id;
|
||||
i.hash = hash;
|
||||
i.type = "orderoffer"_n;
|
||||
i.username = username;
|
||||
i.coopname = coopname;
|
||||
i.status = "active"_n;
|
||||
i.units = units;
|
||||
i.unit_cost = unit_cost;
|
||||
i.base_cost = base_cost;
|
||||
i.membership_fee_amount = membership_fee_amount;
|
||||
i.total_cost = total_cost;
|
||||
i.product_lifecycle_secs = product_lifecycle_secs;
|
||||
i.warranty_period_secs = warranty_period_secs;
|
||||
i.money_contributor = username;
|
||||
i.meta = meta;
|
||||
i.created_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
i.cancellation_fee_amount = cancellation_fee_amount;
|
||||
i.receiver_braname = receiver_braname;
|
||||
i.documents = documents;
|
||||
});
|
||||
|
||||
// Конвертируем и блокируем средства заказчика
|
||||
std::string convert_memo = "Конвертация средств из ЦПП 'Цифровой Кошелёк' в ЦПП 'Маркетплейс' для заказа №" + std::to_string(request_id);
|
||||
Wallet::sub_available_funds(_marketplace, coopname, username, total_cost, _wallet_program, convert_memo);
|
||||
|
||||
// Добавляем средства на ЦПП маркетплейса
|
||||
Wallet::add_available_funds(_marketplace, coopname, username, total_cost, _marketplace_program, convert_memo);
|
||||
|
||||
// Блокируем средства на программе маркетплейса
|
||||
Wallet::block_funds(_marketplace, coopname, username, total_cost, _marketplace_program, memo);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Получение товара заказчиком.
|
||||
|
||||
@details Заказчик приходит на КУ для получения имущества. Председатель КУ подписывает акт и передаёт имущество заказчику.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя заказчика
|
||||
@param request_hash Хэш заявки
|
||||
@param document Акт получения имущества
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::receive(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "delivered"_n, "Получение возможно только после статуса delivered");
|
||||
eosio::check(change.money_contributor == username, "Недостаточно прав доступа");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(document);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(document, 0);
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "received1"_n;
|
||||
// Добавляем акт получения с именем
|
||||
Document::add_document(o.documents, DocumentNames::RECEIVE_ACT, document);
|
||||
});
|
||||
};
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Подтверждение получения заказчиком.
|
||||
|
||||
@details Заказчик подтверждает факт получения имущества второй подписью акта приёма-передачи.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя заказчика
|
||||
@param request_hash Хэш заявки
|
||||
@param document Акт подтверждения получения
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::receivecnf(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "received1"_n, "Подтверждение возможно только после статуса received1");
|
||||
eosio::check(change.money_contributor == username, "Недостаточно прав доступа");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(document);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(document, 0);
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "received2"_n;
|
||||
o.received_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
// Устанавливаем время окончания гарантийной задержки
|
||||
o.warranty_delay_until = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + change.warranty_period_secs);
|
||||
// Добавляем акт подтверждения с именем
|
||||
Document::add_document(o.documents, DocumentNames::RECEIVE_ACT_CONF, document);
|
||||
});
|
||||
|
||||
// Проводки по кошельку
|
||||
std::string memo = "Подтверждение получения для заказа №" + std::to_string(change.id);
|
||||
|
||||
// Паевой фонд - уменьшаем циркуляцию
|
||||
Ledger::sub(_marketplace, coopname, Ledger::accounts::SHARE_FUND, change.base_cost, memo);
|
||||
|
||||
// Заказчик - списываем заблокированный баланс
|
||||
Wallet::sub_blocked_funds(_marketplace, coopname, change.money_contributor, change.total_cost, _marketplace_program, memo);
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Подтверждение поставки председателем КУ.
|
||||
|
||||
@details Председатель кооперативного участка или доверенное им лицо подтверждает факт поставки имущества.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя представителя кооператива
|
||||
@param request_hash Хэш заявки
|
||||
@param act Акт подтверждения поставки
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::supplcnf(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 act) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "supplied1"_n, "Поставка должна быть подтверждена после статуса supplied1");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(act);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(act, 0);
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "supplied2"_n;
|
||||
o.warehouse = change.supplier_braname; // Ставим имущество на склад КУ приёма
|
||||
o.supplied_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
// Добавляем акт подтверждения с именем
|
||||
Document::add_document(o.documents, DocumentNames::SUPPLY_ACT_CONF, act);
|
||||
});
|
||||
|
||||
// Проводки по кошельку
|
||||
std::string memo = "Подтверждение поставки для заказа №" + std::to_string(change.id);
|
||||
|
||||
// Паевой фонд - увеличиваем циркуляцию
|
||||
Ledger::add(_marketplace, coopname, Ledger::accounts::SHARE_FUND, change.total_cost, memo);
|
||||
|
||||
// Поставщик - начисляем и блокируем средства
|
||||
Wallet::add_available_funds(_marketplace, coopname, change.product_contributor, change.base_cost, _marketplace_program, memo);
|
||||
Wallet::block_funds(_marketplace, coopname, change.product_contributor, change.base_cost, _marketplace_program, memo);
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Поставка имущества в кооператив.
|
||||
|
||||
@details Поставщик поставляет имущество на указанный кооперативный участок и предоставляет подписанный акт приёма-передачи.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя поставщика
|
||||
@param request_hash Хэш заявки
|
||||
@param act Акт поставки имущества
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::supply(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 act) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "authorized"_n, "Только авторизованная заявка может быть поставлена");
|
||||
eosio::check(change.product_contributor == username, "Недостаточно прав доступа");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(act);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(act, 0);
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "supplied1"_n;
|
||||
o.supplied_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
// Добавляем акт поставки с именем
|
||||
Document::add_document(o.documents, DocumentNames::SUPPLY_ACT, act);
|
||||
});
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
# Система гарантийного возврата (диспут)
|
||||
|
||||
## Обзор
|
||||
|
||||
Новая система диспута работает через создание дополнительных сегментов в рамках существующей пары заявок, а не через создание новых заявок.
|
||||
|
||||
## Типы сегментов диспута
|
||||
|
||||
- **wreturn** - сегмент возврата товара от заказчика в кооператив
|
||||
- **wsupply** - сегмент выдачи товара из кооператива поставщику
|
||||
|
||||
## Процесс диспута
|
||||
|
||||
### 1. Открытие диспута (`dispute`)
|
||||
- Заказчик подает претензию с документом
|
||||
- Создаются два новых сегмента: `wreturn` и `wsupply`
|
||||
- Статус заявки меняется на `disputed`
|
||||
|
||||
### 2. Авторизация диспута (`wauthorize`)
|
||||
- Совет авторизует принятие товара от заказчика
|
||||
- Совет авторизует последующую выдачу товара поставщику
|
||||
- Статус заявки меняется на `wauthorized`
|
||||
|
||||
### 3. Возврат товара (`wreturn`)
|
||||
- Заказчик возвращает товар в кооператив
|
||||
- Председатель принимает товар и подписывает акт
|
||||
- Статус заявки меняется на `wreturned`
|
||||
|
||||
### 4. Предложение товара поставщику (`woffer`)
|
||||
- Кооператив предлагает поставщику забрать товар
|
||||
- Создается акт передачи
|
||||
- Статус заявки меняется на `woffered`
|
||||
|
||||
### 5. Принятие решения поставщиком (`waccept`)
|
||||
- Поставщик может принять товар (`accept=true`) или отказаться (`accept=false`)
|
||||
- При принятии: статус становится `wcompleted`
|
||||
- При отказе: статус становится `wdeclined`
|
||||
|
||||
## Статусы заявок диспута
|
||||
|
||||
- **disputed** - диспут открыт
|
||||
- **wauthorized** - диспут авторизован советом
|
||||
- **wreturned** - товар возвращен в кооператив
|
||||
- **woffered** - товар предложен поставщику
|
||||
- **wcompleted** - поставщик принял товар, диспут завершен
|
||||
- **wdeclined** - поставщик отказался от товара, диспут завершен
|
||||
|
||||
## Статусы сегментов
|
||||
|
||||
- **created** - сегмент создан
|
||||
- **statement** - документ/заявление предоставлено
|
||||
- **authorized** - авторизовано советом
|
||||
- **returned** - товар возвращен в кооператив
|
||||
- **offered** - товар предложен поставщику
|
||||
- **accepted** - поставщик принял товар
|
||||
- **declined** - поставщик отказался от товара
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Открытие гарантийного спора по заявке.
|
||||
|
||||
@details Заказчик может открыть спор после получения товара, если есть проблемы с качеством или соответствием.
|
||||
Создается претензия, которая сохраняется в документах заявки.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя заказчика, открывающего спор
|
||||
@param request_hash Хэш заявки, по которой открывается спор
|
||||
@param document Документ с описанием претензии
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::dispute(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document){
|
||||
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.type == "orderoffer"_n, "Спор может быть открыт только по заявке orderoffer");
|
||||
eosio::check(change.username == username, "Только заказчик может открыть спор");
|
||||
eosio::check(change.is_warranty_return == false, "Нельзя открыть спор на спор");
|
||||
|
||||
eosio::check(change.status == "received"_n || change.status == "completed"_n, "Спор можно открыть только после получения товара");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(document);
|
||||
|
||||
// Обновляем статус заявки на "disputed" и добавляем документ с претензией
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &e){
|
||||
e.status = "disputed"_n;
|
||||
e.disputed_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
e.is_warranty_return = true;
|
||||
Document::add_document(e.documents, Marketplace::DocumentNames::WDISPUTE, document);
|
||||
});
|
||||
|
||||
// Используем хэш заявки как идентификатор пакета решений
|
||||
checksum256 agenda_hash = change.hash;
|
||||
|
||||
// Отправляем заявление на гарантийный возврат в совет
|
||||
Action::send<createagenda_interface>(
|
||||
_soviet,
|
||||
"createagenda"_n,
|
||||
_marketplace,
|
||||
coopname,
|
||||
username,
|
||||
get_valid_soviet_action("mpwreturn"_n),
|
||||
agenda_hash,
|
||||
_marketplace,
|
||||
Marketplace::get_valid_marketplace_action("wauthorize"_n),
|
||||
"wdecline"_n,
|
||||
document,
|
||||
std::string("")
|
||||
);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Принятие или отказ поставщика от товара в рамках гарантийного возврата
|
||||
|
||||
@details Поставщик может принять товар (accept=true) или отказаться от него (accept=false).
|
||||
При принятии товар передается поставщику и диспут завершается.
|
||||
При отказе товар остается у кооператива и диспут завершается.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя поставщика
|
||||
@param request_hash Хэш заявки с диспутом
|
||||
@param accept Принимает ли поставщик товар (true/false)
|
||||
@param document Документ с решением поставщика
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
*/
|
||||
[[eosio::action]] void marketplace::waccept(eosio::name coopname, eosio::name username, checksum256 request_hash, bool accept, document2 document) {
|
||||
require_auth(coopname);
|
||||
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "woffered"_n, "Товар должен быть предложен поставщику");
|
||||
eosio::check(change.product_contributor == username, "Только поставщик может принять решение о товаре");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(document);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
|
||||
if (accept) {
|
||||
// Поставщик принимает товар
|
||||
requests.modify(change_itr, _marketplace, [&](auto &ch) {
|
||||
ch.status = "wcompleted"_n;
|
||||
Document::add_document(ch.documents, Marketplace::DocumentNames::WACCEPT_ACT, document);
|
||||
});
|
||||
} else {
|
||||
// Поставщик отказывается от товара
|
||||
requests.modify(change_itr, _marketplace, [&](auto &ch) {
|
||||
ch.status = "wdeclined"_n;
|
||||
Document::add_document(ch.documents, Marketplace::DocumentNames::WACCEPT_ACT, document);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Авторизация гарантийного возврата советом
|
||||
|
||||
@details Совет авторизует принятие товара от заказчика и его последующую выдачу поставщику
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param request_hash Хэш заявки с диспутом
|
||||
@param wreturn_decision_id Идентификатор решения по принятию товара
|
||||
@param wreturn_authorization Документ авторизации принятия товара
|
||||
@param wsupply_decision_id Идентификатор решения по выдаче товара поставщику
|
||||
@param wsupply_authorization Документ авторизации выдачи товара
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p _soviet
|
||||
*/
|
||||
[[eosio::action]] void marketplace::wauthorize(eosio::name coopname, checksum256 request_hash, uint64_t wreturn_decision_id, document2 wreturn_authorization, uint64_t wsupply_decision_id, document2 wsupply_authorization) {
|
||||
require_auth(_soviet);
|
||||
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "disputed"_n, "Заявка должна быть в статусе диспута");
|
||||
|
||||
// Обновляем статус заявки и добавляем документы авторизации
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _soviet, [&](auto &o) {
|
||||
o.status = "wauthorized"_n;
|
||||
Document::add_document(o.documents, Marketplace::DocumentNames::WRETURN_AUTH, wreturn_authorization);
|
||||
Document::add_document(o.documents, Marketplace::DocumentNames::WSUPPLY_AUTH, wsupply_authorization);
|
||||
});
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Предложение товара поставщику в рамках гарантийного возврата
|
||||
|
||||
@details Кооператив предлагает поставщику забрать товар, возвращенный заказчиком.
|
||||
Создается предложение с актом передачи.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя председателя, предлагающего товар
|
||||
@param request_hash Хэш заявки с диспутом
|
||||
@param document Акт передачи товара поставщику
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
*/
|
||||
[[eosio::action]] void marketplace::woffer(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document) {
|
||||
require_auth(coopname);
|
||||
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "wreturned"_n, "Товар может быть предложен только после возврата в кооператив");
|
||||
|
||||
auto soviet = get_board_by_type_or_fail(coopname, "soviet"_n);
|
||||
auto chairman = soviet.get_chairman();
|
||||
|
||||
eosio::check(username == chairman, "Недостаточно прав доступа для предложения товара");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(document);
|
||||
|
||||
// Обновляем статус заявки и добавляем акт предложения товара
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &ch) {
|
||||
ch.status = "woffered"_n;
|
||||
Document::add_document(ch.documents, Marketplace::DocumentNames::WOFFER_ACT, document);
|
||||
});
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Возврат товара от заказчика в кооператив
|
||||
|
||||
@details Заказчик возвращает товар в кооператив в рамках гарантийного возврата.
|
||||
Председатель принимает товар и подписывает акт приёма.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param username Имя председателя, принимающего товар
|
||||
@param request_hash Хэш заявки с диспутом
|
||||
@param document Акт приёма товара от заказчика
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
*/
|
||||
[[eosio::action]] void marketplace::wreturn(eosio::name coopname, eosio::name username, checksum256 request_hash, document2 document) {
|
||||
require_auth(coopname);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "wauthorized"_n, "Товар может быть возвращен только по авторизованному диспуту");
|
||||
|
||||
auto soviet = get_board_by_type_or_fail(coopname, "soviet"_n);
|
||||
auto chairman = soviet.get_chairman();
|
||||
|
||||
eosio::check(username == chairman, "Недостаточно прав доступа для принятия возврата");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(document);
|
||||
|
||||
// Обновляем статус заявки и добавляем акт приёма возврата
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &ch) {
|
||||
ch.status = "wreturned"_n;
|
||||
Document::add_document(ch.documents, Marketplace::DocumentNames::WRETURN_ACT, document);
|
||||
});
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Перевозка прибыла в место назначения.
|
||||
|
||||
@details Перевозка переходит в статус arrived и ожидает подписи получателя.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param hash Идентификатор перевозки
|
||||
@param transport_act_delivery Акт доставки подписанный водителем
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::arrived(eosio::name coopname, checksum256 hash, document2 transport_act_delivery) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем что перевозка существует
|
||||
auto shipment = Marketplace::get_shipment_by_hash_or_fail(coopname, hash, "Перевозка не найдена");
|
||||
eosio::check(shipment.status == "transit"_n, "Подписывать акт доставки можно только для перевозки в статусе transit");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(transport_act_delivery, { shipment.driver_username });
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(transport_act_delivery, 0);
|
||||
|
||||
// Обновляем перевозку - добавляем третий акт
|
||||
shipments_index shipments(_marketplace, coopname.value);
|
||||
auto hash_index = shipments.get_index<"byhash"_n>();
|
||||
auto shipment_itr = hash_index.find(hash);
|
||||
hash_index.modify(shipment_itr, _marketplace, [&](auto &s) {
|
||||
s.status = "arrived"_n; // Новый статус - прибыл, ожидает приёма получателем
|
||||
Document::add_document(s.documents, DocumentNames::SHIPMENT_ARRIVE_ACT, transport_act_delivery);
|
||||
s.delivered_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
});
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Создание новой перевозки с массивом заявок.
|
||||
|
||||
@details Создает новую перевозку от одного КУ к другому с указанием водителя и массива заявок.
|
||||
Представитель КУ отправления подписывает первый акт приёма-передачи.
|
||||
Заявки остаются на складе до получения подписи от водителя.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param hash Внешний идентификатор перевозки
|
||||
@param driver_username Имя водителя-пайщика
|
||||
@param source_braname КУ отправителя
|
||||
@param destination_braname КУ назначения
|
||||
@param request_hashes Массив хэшей заявок для перевозки
|
||||
@param transport_act_sender Акт приёма-передачи от представителя КУ отправления
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::createship(eosio::name coopname, checksum256 hash, eosio::name driver_username, eosio::name source_braname, eosio::name destination_braname, std::vector<checksum256> request_hashes, document2 transport_act_sender) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем что КУ отправителя и назначения разные
|
||||
eosio::check(source_braname != destination_braname, "КУ отправителя и назначения не могут совпадать");
|
||||
|
||||
// Проверяем что есть хотя бы одна заявка
|
||||
eosio::check(!request_hashes.empty(), "Должна быть указана хотя бы одна заявка");
|
||||
|
||||
// Проверяем что перевозка с таким hash не существует
|
||||
auto existing_shipment = Marketplace::get_shipment_by_hash(coopname, hash);
|
||||
eosio::check(!existing_shipment.has_value(), "Перевозка с таким идентификатором уже существует");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(transport_act_sender);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(transport_act_sender, 0);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
|
||||
// Проверяем все заявки но НЕ снимаем их со склада (это будет при signbydriver)
|
||||
for (auto& request_hash : request_hashes) {
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "supplied2"_n || change.status == "shiprecvd"_n || change.status == "delivered"_n, "Перевозить можно только заявки в статусе supplied2, shiprecvd или delivered");
|
||||
eosio::check(change.type == "orderoffer"_n, "Перевозить можно только заявки типа orderoffer");
|
||||
eosio::check(change.warehouse == source_braname, "Заявка должна находиться на складе КУ отправителя");
|
||||
}
|
||||
|
||||
// Получаем новый ID для перевозки
|
||||
uint64_t next_shipment_id = get_global_id_in_scope(_marketplace, coopname, "shipments"_n);
|
||||
|
||||
// Создаем новую перевозку
|
||||
shipments_index shipments(_marketplace, coopname.value);
|
||||
shipments.emplace(_marketplace, [&](auto &s) {
|
||||
s.id = next_shipment_id;
|
||||
s.hash = hash;
|
||||
s.coopname = coopname;
|
||||
s.driver_username = driver_username;
|
||||
s.source_braname = source_braname;
|
||||
s.destination_braname = destination_braname;
|
||||
s.status = "loading"_n;
|
||||
s.request_hashes = request_hashes;
|
||||
|
||||
// Добавляем первый документ
|
||||
Document::add_document(s.documents, DocumentNames::SHIPMENT_SEND_ACT, transport_act_sender);
|
||||
|
||||
s.created_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Приём имущества на склад по накладной.
|
||||
|
||||
@details Представитель КУ получения принимает имущество на склад по накладной.
|
||||
Все заявки из перевозки переходят в статус delivered и ставятся на склад КУ получения.
|
||||
Объект перевозки удаляется.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param hash Идентификатор перевозки
|
||||
@param warehouse_receipt_act Акт приёма на склад подписанный получателем
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::receiveshipm(eosio::name coopname, checksum256 hash, document2 warehouse_receipt_act) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем что перевозка существует
|
||||
auto shipment = Marketplace::get_shipment_by_hash_or_fail(coopname, hash, "Перевозка не найдена");
|
||||
eosio::check(shipment.status == "arrived"_n, "Принимать имущество на склад можно только для перевозки в статусе arrived");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(warehouse_receipt_act);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(warehouse_receipt_act, 0);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
|
||||
// Обновляем все заявки из перевозки - ставим их на склад получения
|
||||
for (auto& request_hash : shipment.request_hashes) {
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
// Обновляем заявку
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.status = "shiprecvd"_n; // Доставка получена
|
||||
o.warehouse = shipment.destination_braname; // Ставим на склад КУ получения
|
||||
o.delivered_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
// Устанавливаем крайний срок получения (3 дня)
|
||||
o.deadline_for_receipt = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + 3 * 24 * 60 * 60);
|
||||
// Добавляем акт приёма на складе получателем
|
||||
Document::add_document(o.documents, DocumentNames::SHIPMENT_RECV_ACT, warehouse_receipt_act);
|
||||
});
|
||||
}
|
||||
|
||||
// Удаляем объект перевозки после завершения
|
||||
shipments_index shipments(_marketplace, coopname.value);
|
||||
auto hash_index = shipments.get_index<"byhash"_n>();
|
||||
auto shipment_itr = hash_index.find(hash);
|
||||
hash_index.erase(shipment_itr);
|
||||
};
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Промежуточная передача товаров между складами.
|
||||
|
||||
@details Создает новую перевозку для доставленных заявок, позволяя передать все товары
|
||||
из текущего склада в другое место назначения с новым водителем.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param completed_hash Внешний идентификатор новой перевозки
|
||||
@param new_driver_username Имя нового водителя-пайщика
|
||||
@param source_braname КУ с которого забираем товары
|
||||
@param new_destination_braname Новый КУ назначения
|
||||
@param request_hashes Массив хэшей заявок для переотправки
|
||||
@param transport_act_sender Акт передачи от текущего склада
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::retransport(eosio::name coopname, checksum256 completed_hash, eosio::name new_driver_username, eosio::name source_braname, eosio::name new_destination_braname, std::vector<checksum256> request_hashes, document2 transport_act_sender) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем что есть хотя бы одна заявка
|
||||
eosio::check(!request_hashes.empty(), "Должна быть указана хотя бы одна заявка");
|
||||
|
||||
// Проверяем что перевозка с таким hash не существует
|
||||
auto existing_shipment = Marketplace::get_shipment_by_hash(coopname, completed_hash);
|
||||
eosio::check(!existing_shipment.has_value(), "Перевозка с таким идентификатором уже существует");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(transport_act_sender);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(transport_act_sender, 0);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
|
||||
// Проверяем все заявки но НЕ снимаем их со склада (это будет при signbydriver)
|
||||
for (auto& request_hash : request_hashes) {
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.status == "delivered"_n, "Переотправлять можно только доставленные заявки");
|
||||
eosio::check(change.warehouse == source_braname, "Заявка должна находиться на указанном складе");
|
||||
}
|
||||
|
||||
// Получаем новый ID для перевозки
|
||||
uint64_t next_shipment_id = get_global_id_in_scope(_marketplace, coopname, "shipments"_n);
|
||||
|
||||
// Создаем новую перевозку
|
||||
shipments_index shipments(_marketplace, coopname.value);
|
||||
shipments.emplace(_marketplace, [&](auto &s) {
|
||||
s.id = next_shipment_id;
|
||||
s.hash = completed_hash;
|
||||
s.coopname = coopname;
|
||||
s.driver_username = new_driver_username;
|
||||
s.source_braname = source_braname;
|
||||
s.destination_braname = new_destination_braname;
|
||||
s.status = "loading"_n;
|
||||
s.request_hashes = request_hashes;
|
||||
|
||||
// Добавляем первый документ
|
||||
Document::add_document(s.documents, DocumentNames::SHIPMENT_SEND_ACT, transport_act_sender);
|
||||
|
||||
s.created_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
});
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
\ingroup public_actions
|
||||
\brief Подпись акта приёма-передачи водителем.
|
||||
|
||||
@details Водитель подписывает акт приёма имущества на транспортировку.
|
||||
Все заявки снимаются со склада отправления.
|
||||
Перевозка переходит в статус transit.
|
||||
|
||||
@param coopname Имя кооператива
|
||||
@param hash Идентификатор перевозки
|
||||
@param transport_act_driver Акт приёма-передачи подписанный водителем
|
||||
|
||||
@note Авторизация требуется от аккаунта: @p coopname
|
||||
**/
|
||||
[[eosio::action]] void marketplace::signbydriver(eosio::name coopname, checksum256 hash, document2 transport_act_driver) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем что перевозка существует
|
||||
auto shipment = Marketplace::get_shipment_by_hash_or_fail(coopname, hash, "Перевозка не найдена");
|
||||
eosio::check(shipment.status == "loading"_n, "Подписывать акт водитель может только для перевозки в статусе loading");
|
||||
|
||||
// Проверяем подпись документа
|
||||
verify_document_or_fail(transport_act_driver);
|
||||
|
||||
// Валидируем документ по registry_id (пока что ноль)
|
||||
Document::validate_registry_id(transport_act_driver, 0);
|
||||
|
||||
requests_index requests(_marketplace, coopname.value);
|
||||
|
||||
// Снимаем все заявки со склада отправления
|
||||
for (auto& request_hash : shipment.request_hashes) {
|
||||
auto change_opt = Marketplace::get_request_by_hash(coopname, request_hash);
|
||||
eosio::check(change_opt.has_value(), "Заявка не найдена");
|
||||
auto change = change_opt.value();
|
||||
|
||||
eosio::check(change.warehouse == shipment.source_braname, "Заявка должна находиться на складе КУ отправителя");
|
||||
|
||||
// Снимаем заявку со склада
|
||||
auto change_itr = requests.find(change.id);
|
||||
eosio::check(change_itr != requests.end(), "Заявка не найдена для обновления");
|
||||
requests.modify(change_itr, _marketplace, [&](auto &o){
|
||||
o.warehouse = ""_n; // Снимаем со склада
|
||||
});
|
||||
}
|
||||
|
||||
// Обновляем перевозку
|
||||
shipments_index shipments(_marketplace, coopname.value);
|
||||
auto hash_index = shipments.get_index<"byhash"_n>();
|
||||
auto shipment_itr = hash_index.find(hash);
|
||||
hash_index.modify(shipment_itr, _marketplace, [&](auto &s) {
|
||||
s.status = "transit"_n;
|
||||
Document::add_document(s.documents, DocumentNames::SHIPMENT_LOADING_ACT, transport_act_driver);
|
||||
s.loaded_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
|
||||
});
|
||||
};
|
||||
@@ -1,12 +1,9 @@
|
||||
#define NEWGDECISION_SIGNATURE \
|
||||
name coopname, /* Имя кооператива */ \
|
||||
name presider, /* Имя председателя */ \
|
||||
name secretary, /* Имя секретаря */ \
|
||||
checksum256 hash, /* Хэш собрания */ \
|
||||
std::vector<question_result> results, /* Итог по вопросам */ \
|
||||
uint64_t signed_ballots, /* Число подписанных бюллетеней */ \
|
||||
double quorum_percent, /* Процент кворума */ \
|
||||
bool quorum_passed, /* Флаг достигнутого кворума */ \
|
||||
document2 decision /* Протокол общего собрания */
|
||||
uint64_t quorum_percent, /* Процент кворума */ \
|
||||
bool quorum_passed /* Флаг достигнутого кворума */
|
||||
|
||||
using newgdecision_interface = void(NEWGDECISION_SIGNATURE);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Например, во внешем header можно объявить структуру:
|
||||
struct question_result {
|
||||
uint64_t question_id;
|
||||
uint64_t number;
|
||||
std::string title;
|
||||
std::string decision;
|
||||
std::string context;
|
||||
|
||||
@@ -8,8 +8,7 @@ struct [[eosio::table, eosio::contract(MEET)]] meet {
|
||||
uint64_t id; /// Идентификатор собрания.
|
||||
checksum256 hash; /// Внешний хэш-идентификатор собрания.
|
||||
name coopname; ///< Имя кооператива.
|
||||
name type; ///< Тип общего собрания (regular | extra)
|
||||
name level; ///< Уровень общего собрания (cooperative | branch)
|
||||
name type; ///< Тип общего собрания (annual | special)
|
||||
name initiator; ///< Имя пользователя, который инициировал собрание.
|
||||
name presider; ///< Имя аккаунта председателя собрания.
|
||||
name secretary; ///< Имя аккаунта секретаря собрания
|
||||
@@ -19,13 +18,12 @@ struct [[eosio::table, eosio::contract(MEET)]] meet {
|
||||
time_point_sec created_at; ///< Дата создания предложения.
|
||||
time_point_sec open_at; ///< Дата начала собрания.
|
||||
time_point_sec close_at; ///< Дата завершения собрания.
|
||||
std::vector<name> notified_users; ///< Пользователи, которые подписали уведомление
|
||||
|
||||
double quorum_percent = 75.0; /// Цель по кворуму, чтобы собрание считалось состоявшимся
|
||||
uint64_t quorum_percent = 75; /// Цель по кворуму, чтобы собрание считалось состоявшимся
|
||||
uint64_t signed_ballots; /// Общее количество подписанных бюллетеней
|
||||
double current_quorum_percent = 0; /// Текущий процент кворума
|
||||
uint64_t current_quorum_percent; /// Текущий процент кворума
|
||||
uint64_t cycle = 1; /// Цикл общего собрания, который указывает на то, что были предыдущие собрания, которые не состоялись по кворуму
|
||||
bool quorum_passed = false; /// Флаг пройденного кворума
|
||||
bool quorum_passed; /// Флаг пройденного кворума
|
||||
|
||||
document2 proposal; ///< Предложение
|
||||
document2 authorization; ///< Решение совета
|
||||
|
||||
@@ -8,27 +8,9 @@
|
||||
#include "src/signbysecr.cpp"
|
||||
#include "src/signbypresid.cpp"
|
||||
#include "src/newgdecision.cpp"
|
||||
#include "src/gmnotify.cpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
[[eosio::action]]
|
||||
void meet::migrate(){
|
||||
require_auth(_meet);
|
||||
};
|
||||
|
||||
[[eosio::action]]
|
||||
void meet::delmeet(eosio::name coopname, uint64_t meet_id) {
|
||||
require_auth(_meet);
|
||||
|
||||
Meet::meets_index genmeets(_meet, coopname.value);
|
||||
auto meet = genmeets.find(meet_id);
|
||||
|
||||
eosio::check(genmeets.end() != meet, "Собрание не найдено");
|
||||
|
||||
genmeets.erase(meet);
|
||||
};
|
||||
|
||||
std::optional<Meet::meet> meet::get_meet(eosio::name coopname, const checksum256 &hash) {
|
||||
Meet::meets_index genmeets(_meet, coopname.value);
|
||||
auto hash_index = genmeets.get_index<"byhash"_n>();
|
||||
|
||||
@@ -26,15 +26,12 @@ public:
|
||||
void authmeet(eosio::name coopname, checksum256 hash, document2 authorization);
|
||||
[[eosio::action]]
|
||||
void declmeet(name coopname, checksum256 hash, std::string reason);
|
||||
|
||||
[[eosio::action]]
|
||||
void gmnotify(name coopname, checksum256 hash, name username, document2 notification);
|
||||
|
||||
|
||||
[[eosio::action]]
|
||||
void vote(name coopname, checksum256 hash, name username, document2 ballot, std::vector<vote_point> votes);
|
||||
|
||||
[[eosio::action]]
|
||||
void restartmeet(name coopname, checksum256 hash, checksum256 new_hash, document2 newproposal, time_point_sec new_open_at, time_point_sec new_close_at);
|
||||
void restartmeet(name coopname, checksum256 hash, document2 newproposal, time_point_sec new_open_at, time_point_sec new_close_at);
|
||||
|
||||
[[eosio::action]]
|
||||
void signbysecr(name coopname, name username, checksum256 hash, document2 secretary_decision);
|
||||
@@ -42,10 +39,6 @@ public:
|
||||
[[eosio::action]]
|
||||
void signbypresid(name coopname, name username, checksum256 hash, document2 presider_decision);
|
||||
|
||||
[[eosio::action]] void migrate();
|
||||
|
||||
[[eosio::action]] void delmeet(eosio::name coopname, uint64_t meet_id);
|
||||
|
||||
// Сервисное действие:
|
||||
[[eosio::action]] void newgdecision(NEWGDECISION_SIGNATURE);
|
||||
private:
|
||||
|
||||
@@ -6,8 +6,7 @@ void meet::authmeet(eosio::name coopname, checksum256 hash, document2 authorizat
|
||||
|
||||
Meet::meets_index genmeets(_meet, coopname.value);
|
||||
auto genmeet = genmeets.find(exist_meet -> id);
|
||||
eosio::check(genmeet -> status == "onrestart"_n || genmeet -> status == "created"_n, "Собрание не находится в неподходящем статусе");
|
||||
|
||||
|
||||
if (!TEST_MODE)
|
||||
eosio::check(genmeet -> open_at.sec_since_epoch() >= current_time_point().sec_since_epoch() + MIN_OPEN_AGM_DELAY_SEC,
|
||||
"Дата открытия должна быть по крайней мере через 15 дней от момента решения совета");
|
||||
|
||||
@@ -27,8 +27,7 @@ void meet::createmeet(name coopname, checksum256 hash, eosio::name initiator, na
|
||||
g.id = meet_id;
|
||||
g.hash = hash;
|
||||
g.coopname = coopname;
|
||||
g.type = "regular"_n;
|
||||
g.level = "cooperative"_n;
|
||||
g.type = "annual"_n;
|
||||
g.initiator = initiator;
|
||||
g.presider = presider;
|
||||
g.secretary = secretary;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
void meet::gmnotify(name coopname, checksum256 hash, name username, document2 notification) {
|
||||
require_auth(coopname);
|
||||
|
||||
// Проверяем документ уведомления
|
||||
verify_document_or_fail(notification);
|
||||
|
||||
// Получаем собрание по хэшу
|
||||
Meet::meets_index genmeets(_meet, coopname.value);
|
||||
auto meet_idx = genmeets.get_index<"byhash"_n>();
|
||||
auto meet_itr = meet_idx.find(hash);
|
||||
eosio::check(meet_itr != meet_idx.end(), "Собрание не найдено");
|
||||
|
||||
// Проверяем, что пользователь ещё не уведомлял
|
||||
const auto& notified = meet_itr->notified_users;
|
||||
eosio::check(std::find(notified.begin(), notified.end(), username) == notified.end(), "Пользователь уже подписал уведомление");
|
||||
|
||||
// Добавляем пользователя
|
||||
meet_idx.modify(meet_itr, coopname, [&](auto& m) {
|
||||
m.notified_users.push_back(username);
|
||||
});
|
||||
|
||||
Action::send<newlink_interface>(
|
||||
_soviet,
|
||||
"newlink"_n,
|
||||
_meet,
|
||||
coopname,
|
||||
username,
|
||||
get_valid_soviet_action("gmnotify"_n),
|
||||
hash,
|
||||
notification
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user