work-license-server 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -14
- package/assets/landing.css +609 -0
- package/assets/landing.js +1187 -0
- package/assets/odant-logo.png +0 -0
- package/assets/russia-regions.json +1 -0
- package/package.json +2 -1
- package/src/agent.js +195 -0
- package/src/bots.js +2 -2
- package/src/catalog.js +315 -93
- package/src/index.js +6 -0
- package/src/landing.js +746 -882
- package/src/server.js +103 -5
- package/src/store.js +200 -2
package/src/catalog.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Каталог комплектации
|
|
3
|
-
*
|
|
2
|
+
* Каталог комплектации ODANT-WORK, тарифов годовых пользовательских лицензий со скидками от количества,
|
|
3
|
+
* региональной франшизы (базовая стоимость 5 млн ₽, невозвратный залог резервирования 100 тыс. ₽,
|
|
4
|
+
* квота вакантных франшиз по населению) для сервера https://work.odant.org.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
export const PAK_PRODUCT = Object.freeze({
|
|
7
8
|
sku: 'WORK-PAK-495-192-4T',
|
|
8
|
-
name: '
|
|
9
|
+
name: 'ODANT-WORK',
|
|
9
10
|
domain: 'work.odant.org',
|
|
10
11
|
basePriceRub: 5_000_000,
|
|
11
12
|
baseSeats: 5,
|
|
@@ -13,56 +14,121 @@ export const PAK_PRODUCT = Object.freeze({
|
|
|
13
14
|
includedSupportYears: 1,
|
|
14
15
|
includedSupportTier: 'business',
|
|
15
16
|
hardware: Object.freeze({
|
|
16
|
-
cpu: 'AMD Ryzen 495
|
|
17
|
-
|
|
17
|
+
cpu: 'AMD Ryzen™ AI Max+ PRO 495 (Zen 5, 16 ядер / 32 потока, до 5.2 ГГц, кэш 80 МБ)',
|
|
18
|
+
gpu: 'AMD Radeon™ 8065S Graphics (40 ядер, 3000 МГц, до 61 TFLOPS FP16)',
|
|
19
|
+
aiEngine: 'До 132 TOPS (NPU 55 TOPS + 61 TFLOPS FP16 AI Compute)',
|
|
20
|
+
ram: '192 ГБ 256-bit LPDDR5x-8533 Unified RAM',
|
|
18
21
|
ramGb: 192,
|
|
19
|
-
storage: 'SSD 4 ТБ NVMe PCIe
|
|
22
|
+
storage: 'SSD 4 ТБ NVMe PCIe® 4.0 (поддержка RAID0 / RAID1)',
|
|
20
23
|
ssdTb: 4,
|
|
24
|
+
security: 'AMD PRO Technologies · AMD Memory Guard · AMD Secure Processor',
|
|
21
25
|
}),
|
|
22
26
|
software: Object.freeze({
|
|
23
|
-
accounting: '
|
|
24
|
-
seatModel: 'По одновременным активным сессиям (5 вечных рабочих мест в базовом комплекте + докупка срочных годовых лицензий)',
|
|
27
|
+
accounting: 'Встроенная система учёта, документооборота, управления процессами и приватный мультимодальный ИИ (справочники, план счетов, двойная запись, оборотно-сальдовая ведомость, анализ счёта, первичные документы и сквозные процессы)',
|
|
28
|
+
seatModel: 'По одновременным активным сессиям (5 вечных рабочих мест в базовом комплекте + докупка срочных годовых лицензий со скидкой от количества)',
|
|
25
29
|
hardwareBinding: 'Привязка вечной лицензии к Hardware ID материнской платы/CPU AMD Ryzen + криптографическому ключу узла (#system/node-key.json)',
|
|
26
30
|
}),
|
|
27
31
|
preinstalledModels: Object.freeze([
|
|
28
32
|
{
|
|
29
|
-
id: '
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
id: 'llm-core',
|
|
34
|
+
type: 'Большая языковая модель (LLM)',
|
|
35
|
+
title: 'Интеллектуальное текстовое и аналитическое ядро',
|
|
36
|
+
badge: 'Диалог · Учёт · Документы · Процессы',
|
|
37
|
+
description: 'Ведение живого диалога, проведение хозяйственных операций, подготовка документов, управление бизнес-процессами, финансовый анализ и генерация программного кода.',
|
|
33
38
|
ramGb: 18.5,
|
|
34
39
|
},
|
|
35
40
|
{
|
|
36
|
-
id: '
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
id: 'voice-core',
|
|
42
|
+
type: 'Голосовая модель (распознавание и синтез речи)',
|
|
43
|
+
title: 'Полнодуплексный речевой контур',
|
|
44
|
+
badge: 'Голосовой диалог · ASR · TTS',
|
|
45
|
+
description: 'Локальное распознавание устной речи, стенографирование совещаний и синтез естественного голоса с мгновенным откликом и взаимным перебиванием.',
|
|
40
46
|
ramGb: 4.2,
|
|
41
47
|
},
|
|
42
48
|
{
|
|
43
|
-
id: '
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
id: 'image-core',
|
|
50
|
+
type: 'Модель генерации изображений',
|
|
51
|
+
title: 'Визуальный и графический синтез',
|
|
52
|
+
badge: 'Иллюстрации · Карточки · Схемы',
|
|
53
|
+
description: 'Локальное создание иллюстраций, визуального оформления карточек номенклатуры, презентационных материалов и графики внутри закрытого контура.',
|
|
47
54
|
ramGb: 12.0,
|
|
48
55
|
},
|
|
49
56
|
{
|
|
50
|
-
id: '
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
id: 'embedding-core',
|
|
58
|
+
type: 'Модель векторных представлений (Embedding)',
|
|
59
|
+
title: 'Семантический поиск и база знаний (RAG)',
|
|
60
|
+
badge: 'Векторный индекс · Поиск по смыслу',
|
|
61
|
+
description: 'Глубокая индексация всех договоров, первичных документов, регламентов, задач и истории переписки предприятия для мгновенного поиска по смыслу.',
|
|
54
62
|
ramGb: 2.5,
|
|
55
63
|
},
|
|
56
64
|
]),
|
|
57
65
|
});
|
|
58
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Агентная ИИ-платформа ODANT-WORK: ИИ-консультант в каждой форме, мультиагентная система
|
|
69
|
+
* из ролевых субагентов и библиотека навыков (по контрактам $server/$folder/$class/ai/{agents,skills}).
|
|
70
|
+
*/
|
|
71
|
+
export const AI_PLATFORM = Object.freeze({
|
|
72
|
+
consultant: Object.freeze({
|
|
73
|
+
title: 'ИИ-консультант в каждой форме',
|
|
74
|
+
features: Object.freeze([
|
|
75
|
+
'Вкладка «ИИ» в проводнике и кнопка «?» в шапке любой формы — вопрос по открытой форме задаётся автоматически',
|
|
76
|
+
'Полнодуплексный голосовой диалог: распознавание и синтез речи с взаимным перебиванием',
|
|
77
|
+
'Действует в рамках роли и прав пользователя (ADMIN · BOSS · USER)',
|
|
78
|
+
'Инструменты учётного ядра: описание класса, поиск объектов, проведение операций, отчёты',
|
|
79
|
+
'Каждая консультация сохраняется задачей в личном кабинете и в ленте пользователя',
|
|
80
|
+
'Работает полностью локально на комплексе — данные не покидают контур предприятия',
|
|
81
|
+
]),
|
|
82
|
+
}),
|
|
83
|
+
orchestration: Object.freeze([
|
|
84
|
+
{ title: 'Декомпозиция и параллельное исполнение', description: 'Основной агент раскладывает задачу на поручения и запускает независимые субагенты параллельно, собирая их итоговые отчёты.' },
|
|
85
|
+
{ title: 'Жёсткие границы прав', description: 'Субагент никогда не получает больше инструментов и прав, чем у вызвавшего; аудитор и ревьюер работают строго на чтение — на уровне кода.' },
|
|
86
|
+
{ title: 'Изолированные ветки изменений', description: 'Параллельные правки готовятся в изолированных ветках и сливаются в оригинал с проверкой конфликтов и единым откатом.' },
|
|
87
|
+
{ title: 'Фоновые продолжимые задачи', description: 'Долгая работа идёт отдельной задачей в фоне: её можно проверить, дополнить сообщением или остановить.' },
|
|
88
|
+
{ title: 'Подтверждение человеком', description: 'Значимые изменения агент согласует с ответственным сотрудником в той же задаче — с полным журналом действий.' },
|
|
89
|
+
{ title: 'Навыки и самообучение', description: 'Удачно выполненная работа сохраняется как навык подразделения и переиспользуется всеми агентами.' },
|
|
90
|
+
]),
|
|
91
|
+
agents: Object.freeze([
|
|
92
|
+
{ id: 'explore', title: 'Разведчик', description: 'Исследует дерево организации только на чтение и возвращает отчёт с путями' },
|
|
93
|
+
{ id: 'web', title: 'Веб-исследователь', description: 'Находит факты в интернете и подтверждает их ссылками' },
|
|
94
|
+
{ id: 'general', title: 'Исполнитель', description: 'Самостоятельно решает подзадачу со всеми разрешёнными инструментами' },
|
|
95
|
+
{ id: 'analyst', title: 'Аналитик', description: 'Отчёты и сводки по объектам, лентам и документам, таблицы xlsx / csv' },
|
|
96
|
+
{ id: 'secretary', title: 'Секретарь', description: 'Входящие, поручения с исполнителями и сроками, контроль исполнения' },
|
|
97
|
+
{ id: 'auditor', title: 'Аудитор', description: 'Аудит прав доступа и журнала безопасности — строго только чтение' },
|
|
98
|
+
{ id: 'builder', title: 'Конструктор', description: 'Прикладная модель: типы, поля, роли, зоны доступа и контракты' },
|
|
99
|
+
{ id: 'developer', title: 'Разработчик', description: 'Код, точечные правки, git, проверки и диагностика' },
|
|
100
|
+
{ id: 'reviewer', title: 'Ревьюер', description: 'Ревью изменений классов, методов и контрактов' },
|
|
101
|
+
{ id: 'it-admin', title: 'ИТ-администратор', description: 'Сервер и локальная сеть: здоровье, службы, устройства' },
|
|
102
|
+
{ id: 'integrator', title: 'Интегратор', description: 'Чтение внешних учётных систем по OData, выгрузка и сверка данных' },
|
|
103
|
+
{ id: 'negotiator', title: 'Представитель', description: 'Действует от имени компании на серверах-партнёрах федерации' },
|
|
104
|
+
{ id: 'operator', title: 'Оператор ПК', description: 'Команды, экран и браузер в изолированной песочнице' },
|
|
105
|
+
]),
|
|
106
|
+
skills: Object.freeze([
|
|
107
|
+
'Согласование документов', 'Протокол совещания', 'Документ по шаблону', 'Импорт таблиц',
|
|
108
|
+
'Отчёты по расписанию', 'Делегирование поручений', 'Контроль качества данных', 'Онбординг сотрудника',
|
|
109
|
+
'Почта и календарь', 'Сканирование в систему', 'Проверка резервных копий', 'ИИ-триггеры на события',
|
|
110
|
+
'Инвентаризация сети', 'Восстановление файлов', 'Офисные документы', 'Создание новых навыков',
|
|
111
|
+
]),
|
|
112
|
+
skillsCount: 26,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/** Разработчик и правообладатель платформы ODANT. */
|
|
116
|
+
export const VENDOR_CONTACTS = Object.freeze({
|
|
117
|
+
company: 'Бизнес Интер Софт',
|
|
118
|
+
description: 'Разработка и продажа программного обеспечения, автоматизация бизнес-процессов',
|
|
119
|
+
address: '390000, г. Рязань, ул. Ленина, 47',
|
|
120
|
+
phones: Object.freeze(['+7 (4912) 77-70-21', '+7 (4912) 77-70-22']),
|
|
121
|
+
site: 'https://www.odant.ru',
|
|
122
|
+
geo: Object.freeze({ lat: 54.62795, lon: 39.74585 }),
|
|
123
|
+
});
|
|
124
|
+
|
|
59
125
|
/** Тарифы годовой лицензии на 1 дополнительного пользователя (зависят от уровня поддержки SLA). */
|
|
60
126
|
export const SLA_TIERS = Object.freeze({
|
|
61
127
|
start: Object.freeze({
|
|
62
128
|
id: 'start',
|
|
63
129
|
name: 'Start',
|
|
64
130
|
badge: 'Базовый SLA',
|
|
65
|
-
pricePerUserYearRub:
|
|
131
|
+
pricePerUserYearRub: 10_000,
|
|
66
132
|
ticketsLimitPerSeatYear: 12,
|
|
67
133
|
reactionMinutes: 480,
|
|
68
134
|
reactionLabel: 'до 8 рабочих часов',
|
|
@@ -73,14 +139,14 @@ export const SLA_TIERS = Object.freeze({
|
|
|
73
139
|
'До 12 обращений в техподдержку в год на каждое место',
|
|
74
140
|
'Время реакции инженера — до 8 рабочих часов',
|
|
75
141
|
'Поддержка через боты MAX, Telegram, VK',
|
|
76
|
-
'Доступ ко всем обновлениям ядра WORK и
|
|
142
|
+
'Доступ ко всем обновлениям ядра ODANT-WORK и встроенной системы учёта',
|
|
77
143
|
],
|
|
78
144
|
}),
|
|
79
145
|
business: Object.freeze({
|
|
80
146
|
id: 'business',
|
|
81
147
|
name: 'Business',
|
|
82
148
|
badge: 'Рекомендуемый',
|
|
83
|
-
pricePerUserYearRub:
|
|
149
|
+
pricePerUserYearRub: 15_000,
|
|
84
150
|
ticketsLimitPerSeatYear: 48,
|
|
85
151
|
reactionMinutes: 120,
|
|
86
152
|
reactionLabel: 'до 2 часов',
|
|
@@ -90,7 +156,7 @@ export const SLA_TIERS = Object.freeze({
|
|
|
90
156
|
'1 дополнительное конкурентное рабочее место на 1 год',
|
|
91
157
|
'До 48 обращений в техподдержку в год на каждое место',
|
|
92
158
|
'Приоритетное время реакции — до 2 часов',
|
|
93
|
-
'Консультации по настройке учётных
|
|
159
|
+
'Консультации по настройке учётных схем, документооборота и процессов',
|
|
94
160
|
'Помощь в администрировании предустановленных локальных моделей ИИ',
|
|
95
161
|
],
|
|
96
162
|
}),
|
|
@@ -98,7 +164,7 @@ export const SLA_TIERS = Object.freeze({
|
|
|
98
164
|
id: 'enterprise',
|
|
99
165
|
name: 'Enterprise',
|
|
100
166
|
badge: 'Максимальный 24/7',
|
|
101
|
-
pricePerUserYearRub:
|
|
167
|
+
pricePerUserYearRub: 20_000,
|
|
102
168
|
ticketsLimitPerSeatYear: 9999,
|
|
103
169
|
reactionMinutes: 15,
|
|
104
170
|
reactionLabel: 'до 15 минут (24/7)',
|
|
@@ -109,13 +175,42 @@ export const SLA_TIERS = Object.freeze({
|
|
|
109
175
|
'Безлимитное количество обращений в поддержку',
|
|
110
176
|
'Критическое время реакции — до 15 минут 24/7',
|
|
111
177
|
'Выделенный инженер и прямая линия сопровождения',
|
|
112
|
-
'Помощь с дообучением моделей ИИ
|
|
178
|
+
'Помощь с дообучением моделей ИИ под процессы предприятия',
|
|
113
179
|
],
|
|
114
180
|
}),
|
|
115
181
|
});
|
|
116
182
|
|
|
117
183
|
/**
|
|
118
|
-
*
|
|
184
|
+
* Шкала скидок от количества докупаемых пользовательских лицензий (объёмная скидка для клиентов).
|
|
185
|
+
*/
|
|
186
|
+
export const SEAT_VOLUME_DISCOUNTS = Object.freeze([
|
|
187
|
+
{ minSeats: 100, discountPercent: 25, label: 'Корпоративный пакет (100+ мест): −25%' },
|
|
188
|
+
{ minSeats: 50, discountPercent: 20, label: 'Крупный пакет (50–99 мест): −20%' },
|
|
189
|
+
{ minSeats: 25, discountPercent: 15, label: 'Расширенный пакет (25–49 мест): −15%' },
|
|
190
|
+
{ minSeats: 10, discountPercent: 10, label: 'Командный пакет (10–24 места): −10%' },
|
|
191
|
+
{ minSeats: 5, discountPercent: 5, label: 'Малый пакет (5–9 мест): −5%' },
|
|
192
|
+
{ minSeats: 1, discountPercent: 0, label: 'Стандарт (1–4 места): 0%' },
|
|
193
|
+
]);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Вычислить процент скидки от количества докупаемых пользователей.
|
|
197
|
+
*/
|
|
198
|
+
export function calculateSeatVolumeDiscount(seats = 1) {
|
|
199
|
+
const count = Math.max(0, Math.floor(Number(seats || 0)));
|
|
200
|
+
for (const tier of SEAT_VOLUME_DISCOUNTS) {
|
|
201
|
+
if (count >= tier.minSeats) {
|
|
202
|
+
return {
|
|
203
|
+
seats: count,
|
|
204
|
+
discountPercent: tier.discountPercent,
|
|
205
|
+
label: tier.label,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { seats: count, discountPercent: 0, label: 'Без скидки' };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Рассчитать стоимость заказа (покупка базового комплекса ODANT-WORK и/или докупка годовых лицензий со скидкой от количества).
|
|
119
214
|
*/
|
|
120
215
|
export function calculateOrderQuote({
|
|
121
216
|
includeBasePak = false,
|
|
@@ -128,8 +223,14 @@ export function calculateOrderQuote({
|
|
|
128
223
|
const seats = Math.max(0, Math.floor(Number(addonSeats || 0)));
|
|
129
224
|
const periodYears = Math.max(1, Math.min(5, Math.floor(Number(years || 1))));
|
|
130
225
|
|
|
226
|
+
const volumeDiscount = calculateSeatVolumeDiscount(seats);
|
|
227
|
+
const volumeDiscountPercent = volumeDiscount.discountPercent;
|
|
228
|
+
|
|
131
229
|
const baseAmountRub = includeBasePak ? PAK_PRODUCT.basePriceRub : 0;
|
|
132
|
-
const
|
|
230
|
+
const addonsGrossAmountRub = seats * tierSpec.pricePerUserYearRub * periodYears;
|
|
231
|
+
const addonsDiscountRub = Math.round(addonsGrossAmountRub * (volumeDiscountPercent / 100));
|
|
232
|
+
const addonsAmountRub = addonsGrossAmountRub - addonsDiscountRub;
|
|
233
|
+
const effectiveUnitPriceRub = seats > 0 ? Math.round(addonsAmountRub / seats) : tierSpec.pricePerUserYearRub * periodYears;
|
|
133
234
|
const totalAmountRub = baseAmountRub + addonsAmountRub;
|
|
134
235
|
|
|
135
236
|
const items = [];
|
|
@@ -142,10 +243,11 @@ export function calculateOrderQuote({
|
|
|
142
243
|
});
|
|
143
244
|
}
|
|
144
245
|
if (seats > 0) {
|
|
246
|
+
const discSuffix = volumeDiscountPercent > 0 ? `, скидка −${volumeDiscountPercent}% за объём` : '';
|
|
145
247
|
items.push({
|
|
146
|
-
title: `Годовая лицензия WORK на доп. рабочее место (уровень
|
|
248
|
+
title: `Годовая лицензия ODANT-WORK на доп. рабочее место (уровень ${tierSpec.name}, ${periodYears} г.${discSuffix})`,
|
|
147
249
|
quantity: seats,
|
|
148
|
-
unitPriceRub:
|
|
250
|
+
unitPriceRub: effectiveUnitPriceRub,
|
|
149
251
|
totalRub: addonsAmountRub,
|
|
150
252
|
});
|
|
151
253
|
}
|
|
@@ -160,6 +262,10 @@ export function calculateOrderQuote({
|
|
|
160
262
|
pricePerUserYearRub: tierSpec.pricePerUserYearRub,
|
|
161
263
|
addonSeats: seats,
|
|
162
264
|
years: periodYears,
|
|
265
|
+
volumeDiscountPercent,
|
|
266
|
+
volumeDiscountLabel: volumeDiscount.label,
|
|
267
|
+
addonsGrossAmountRub,
|
|
268
|
+
addonsDiscountRub,
|
|
163
269
|
addonsAmountRub,
|
|
164
270
|
totalAmountRub,
|
|
165
271
|
reactionMinutes: tierSpec.reactionMinutes,
|
|
@@ -170,36 +276,38 @@ export function calculateOrderQuote({
|
|
|
170
276
|
}
|
|
171
277
|
|
|
172
278
|
/**
|
|
173
|
-
* Параметры партнёрской программы и региональной франшизы WORK:
|
|
174
|
-
* -
|
|
175
|
-
* -
|
|
279
|
+
* Параметры партнёрской программы и региональной франшизы ODANT-WORK:
|
|
280
|
+
* - Предварительная базовая стоимость франшизы = 5 000 000 ₽ (корректируется пропорционально экономическому индексу региона).
|
|
281
|
+
* - Сразу при резервировании франшизы вносится невозвратный залог = 100 000 ₽.
|
|
282
|
+
* - Максимальное количество франшиз в регионе пропорционально населению региона (partnersPerMillion * populationMillions, мин. 1).
|
|
176
283
|
* - Партнёрская скидка растёт пропорционально годовому объёму продаж от начальных 10% до максимальных 50%.
|
|
177
284
|
*/
|
|
178
285
|
export const FRANCHISE_PROGRAM = Object.freeze({
|
|
179
|
-
baseFranchiseFeeRub:
|
|
180
|
-
|
|
286
|
+
baseFranchiseFeeRub: 5_000_000, // Предварительная базовая стоимость франшизы (5 млн ₽ при экономическом индексе 1.0)
|
|
287
|
+
reservationDepositRub: 100_000, // Невозвратный залог сразу за резервирование региональной франшизы (100 тыс. ₽)
|
|
288
|
+
partnersPerMillionPopulation: 1, // Норматив квоты партнёров: 1 франшиза на 1 млн населения региона
|
|
181
289
|
minDiscountPercent: 10, // Начальная партнёрская скидка (10%)
|
|
182
290
|
maxDiscountPercent: 50, // Максимальная партнёрская скидка (50%)
|
|
183
|
-
maxDiscountAnnualSalesRub: 100_000_000, // Годовой объём продаж (100 млн ₽ = ~20 ПАК), при котором достигается
|
|
184
|
-
hardwareWarrantyYears: 1, //
|
|
291
|
+
maxDiscountAnnualSalesRub: 100_000_000, // Годовой объём продаж (100 млн ₽ = ~20 ПАК), при котором достигается скидка 50%
|
|
292
|
+
hardwareWarrantyYears: 1, // Годовая гарантия на оборудование, предоставляемая партнёром
|
|
185
293
|
partnerOperationsModel: Object.freeze([
|
|
186
|
-
'Партнёр самостоятельно закупает аппаратную платформу (AMD Ryzen 495
|
|
187
|
-
'Партнёр
|
|
188
|
-
'Партнёр самостоятельно привязывает оборудование (HWID + #system/node-key.json) и выдаёт лицензии клиентам
|
|
189
|
-
'Партнёр предоставляет клиенту годовую гарантию (1 год) на поставленное оборудование
|
|
294
|
+
'Партнёр самостоятельно закупает аппаратную платформу (AMD Ryzen™ AI Max+ PRO 495 · Radeon™ 8065S · 192 ГБ RAM · SSD 4 ТБ)',
|
|
295
|
+
'Партнёр устанавливает ODANT-WORK, систему учёта, документооборота, процессов и 4 локальные модели ИИ',
|
|
296
|
+
'Партнёр самостоятельно привязывает оборудование (HWID + #system/node-key.json) и выдаёт лицензии клиентам',
|
|
297
|
+
'Партнёр предоставляет клиенту годовую гарантию (1 год) на поставленное оборудование',
|
|
190
298
|
]),
|
|
191
299
|
partnerRevenueStreams: Object.freeze([
|
|
192
300
|
{
|
|
193
301
|
id: 'pak-license-margin',
|
|
194
|
-
title: 'Продажа
|
|
195
|
-
share: 'Скидка партнёра от 10% до 50% пропорционально годовому объёму продаж + аппаратная
|
|
302
|
+
title: 'Продажа комплексов ODANT-WORK и лицензий (скидка 10% → 50%)',
|
|
303
|
+
share: 'Скидка партнёра от 10% до 50% пропорционально годовому объёму продаж + аппаратная маржа сборки',
|
|
196
304
|
recommendedAvgRub: 1_500_000,
|
|
197
305
|
},
|
|
198
306
|
{
|
|
199
307
|
id: 'nas-backup-hardware',
|
|
200
308
|
title: 'Поставка NAS-систем для резервного копирования',
|
|
201
309
|
share: '100% доход партнёра',
|
|
202
|
-
description: 'Поставка и настройка сетевых хранилищ NAS для автоматической архивации и
|
|
310
|
+
description: 'Поставка и настройка сетевых хранилищ NAS для автоматической архивации и резервного копирования баз организаций',
|
|
203
311
|
recommendedAvgRub: 350_000,
|
|
204
312
|
},
|
|
205
313
|
{
|
|
@@ -219,7 +327,7 @@ export const FRANCHISE_PROGRAM = Object.freeze({
|
|
|
219
327
|
{
|
|
220
328
|
id: 'partner-tech-support',
|
|
221
329
|
title: 'Техническая поддержка и сервисное сопровождение',
|
|
222
|
-
share: 'Доход партнёра по договорам SLA и
|
|
330
|
+
share: 'Доход партнёра по договорам SLA и гарантийному обслуживанию',
|
|
223
331
|
description: 'Первая и вторая линия техподдержки предприятий региона, администрирование серверов и регламентное ТО',
|
|
224
332
|
recommendedAvgRub: 240_000,
|
|
225
333
|
},
|
|
@@ -227,77 +335,192 @@ export const FRANCHISE_PROGRAM = Object.freeze({
|
|
|
227
335
|
id: 'agent-training-skills',
|
|
228
336
|
title: 'Дообучение ИИ-агентов (LoRA) и разработка навыков (skills)',
|
|
229
337
|
share: '100% проектный доход партнёра',
|
|
230
|
-
description: 'Сборка датасетов предприятия, дообучение моделей под отраслевую специфику, создание навыков (skills) и
|
|
338
|
+
description: 'Сборка датасетов предприятия, дообучение моделей под отраслевую специфику, создание навыков (skills) и процессных схем',
|
|
231
339
|
recommendedAvgRub: 600_000,
|
|
232
340
|
},
|
|
233
341
|
]),
|
|
234
342
|
});
|
|
235
343
|
|
|
236
344
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
345
|
+
* Перечень всех субъектов Российской Федерации для партнёрской программы:
|
|
346
|
+
* численность населения (populationMillions — определяет квоту франшиз), ВРП (grpTrillionRub, оценка)
|
|
347
|
+
* и экономический индекс (economicIndex — множитель базовой стоимости франшизы).
|
|
348
|
+
* Контуры субъектов для интерактивной карты лежат в assets/russia-regions.json (по коду субъекта).
|
|
349
|
+
* Служебный «Типовой регион» (RU-REG, hidden) используется для расчётов и на витрине не показывается.
|
|
240
350
|
*/
|
|
351
|
+
const region = (code, name, district, populationMillions, grpTrillionRub, economicIndex, extra = {}) => Object.freeze({
|
|
352
|
+
code,
|
|
353
|
+
name,
|
|
354
|
+
district,
|
|
355
|
+
populationMillions,
|
|
356
|
+
grpTrillionRub,
|
|
357
|
+
activeEnterprises: Math.round(populationMillions * 22_000 / 1000) * 1000,
|
|
358
|
+
economicIndex,
|
|
359
|
+
...extra,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
export const FEDERAL_DISTRICTS = Object.freeze({
|
|
363
|
+
'ЦФО': 'Центральный',
|
|
364
|
+
'СЗФО': 'Северо-Западный',
|
|
365
|
+
'ЮФО': 'Южный',
|
|
366
|
+
'СКФО': 'Северо-Кавказский',
|
|
367
|
+
'ПФО': 'Приволжский',
|
|
368
|
+
'УФО': 'Уральский',
|
|
369
|
+
'СФО': 'Сибирский',
|
|
370
|
+
'ДФО': 'Дальневосточный',
|
|
371
|
+
});
|
|
372
|
+
|
|
241
373
|
export const REGIONS_CATALOG = Object.freeze([
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
374
|
+
// Центральный федеральный округ
|
|
375
|
+
region('RU-MOW', 'Москва', 'ЦФО', 13.1, 28.5, 2.0, { activeEnterprises: 620_000 }),
|
|
376
|
+
region('RU-MOS', 'Московская область', 'ЦФО', 8.6, 8.4, 1.4, { activeEnterprises: 185_000 }),
|
|
377
|
+
region('RU-BEL', 'Белгородская область', 'ЦФО', 1.5, 1.4, 0.9),
|
|
378
|
+
region('RU-BRY', 'Брянская область', 'ЦФО', 1.15, 0.6, 0.7),
|
|
379
|
+
region('RU-VLA', 'Владимирская область', 'ЦФО', 1.33, 0.75, 0.8),
|
|
380
|
+
region('RU-VOR', 'Воронежская область', 'ЦФО', 2.3, 1.5, 0.9),
|
|
381
|
+
region('RU-IVA', 'Ивановская область', 'ЦФО', 0.91, 0.35, 0.6),
|
|
382
|
+
region('RU-KLU', 'Калужская область', 'ЦФО', 1.07, 0.8, 0.8),
|
|
383
|
+
region('RU-KOS', 'Костромская область', 'ЦФО', 0.57, 0.3, 0.6),
|
|
384
|
+
region('RU-KRS', 'Курская область', 'ЦФО', 1.07, 0.8, 0.8),
|
|
385
|
+
region('RU-LIP', 'Липецкая область', 'ЦФО', 1.12, 1.0, 0.9),
|
|
386
|
+
region('RU-ORL', 'Орловская область', 'ЦФО', 0.7, 0.35, 0.6),
|
|
387
|
+
region('RU-RYA', 'Рязанская область', 'ЦФО', 1.08, 0.65, 0.8, { headquarters: true }),
|
|
388
|
+
region('RU-SMO', 'Смоленская область', 'ЦФО', 0.88, 0.45, 0.7),
|
|
389
|
+
region('RU-TAM', 'Тамбовская область', 'ЦФО', 0.97, 0.5, 0.7),
|
|
390
|
+
region('RU-TVE', 'Тверская область', 'ЦФО', 1.21, 0.7, 0.8),
|
|
391
|
+
region('RU-TUL', 'Тульская область', 'ЦФО', 1.5, 1.1, 0.9),
|
|
392
|
+
region('RU-YAR', 'Ярославская область', 'ЦФО', 1.2, 0.9, 0.9),
|
|
393
|
+
|
|
394
|
+
// Северо-Западный федеральный округ
|
|
395
|
+
region('RU-SPE', 'Санкт-Петербург', 'СЗФО', 5.6, 11.2, 1.6, { activeEnterprises: 245_000 }),
|
|
396
|
+
region('RU-LEN', 'Ленинградская область', 'СЗФО', 2.0, 1.8, 1.0),
|
|
397
|
+
region('RU-KGD', 'Калининградская область', 'СЗФО', 1.0, 0.9, 0.9),
|
|
398
|
+
region('RU-MUR', 'Мурманская область', 'СЗФО', 0.7, 1.2, 1.0),
|
|
399
|
+
region('RU-ARK', 'Архангельская область', 'СЗФО', 0.96, 1.1, 0.9),
|
|
400
|
+
region('RU-NEN', 'Ненецкий автономный округ', 'СЗФО', 0.04, 0.35, 0.6),
|
|
401
|
+
region('RU-VLG', 'Вологодская область', 'СЗФО', 1.1, 1.1, 0.9),
|
|
402
|
+
region('RU-KR', 'Республика Карелия', 'СЗФО', 0.52, 0.45, 0.7),
|
|
403
|
+
region('RU-KO', 'Республика Коми', 'СЗФО', 0.72, 0.9, 0.9),
|
|
404
|
+
region('RU-NGR', 'Новгородская область', 'СЗФО', 0.58, 0.4, 0.7),
|
|
405
|
+
region('RU-PSK', 'Псковская область', 'СЗФО', 0.58, 0.25, 0.6),
|
|
406
|
+
|
|
407
|
+
// Южный федеральный округ
|
|
408
|
+
region('RU-KDA', 'Краснодарский край', 'ЮФО', 5.8, 4.3, 1.3, { activeEnterprises: 120_000 }),
|
|
409
|
+
region('RU-ROS', 'Ростовская область', 'ЮФО', 4.2, 2.6, 1.0),
|
|
410
|
+
region('RU-VGG', 'Волгоградская область', 'ЮФО', 2.5, 1.4, 0.9),
|
|
411
|
+
region('RU-AST', 'Астраханская область', 'ЮФО', 0.95, 0.6, 0.8),
|
|
412
|
+
region('RU-AD', 'Республика Адыгея', 'ЮФО', 0.5, 0.15, 0.6),
|
|
413
|
+
region('RU-KL', 'Республика Калмыкия', 'ЮФО', 0.26, 0.1, 0.5),
|
|
414
|
+
region('RU-CR', 'Республика Крым', 'ЮФО', 1.91, 0.75, 0.8),
|
|
415
|
+
region('RU-SEV', 'Севастополь', 'ЮФО', 0.56, 0.2, 0.8),
|
|
416
|
+
region('RU-DPR', 'Донецкая Народная Республика', 'ЮФО', 2.29, null, 0.6),
|
|
417
|
+
region('RU-LPR', 'Луганская Народная Республика', 'ЮФО', 1.32, null, 0.6),
|
|
418
|
+
region('RU-ZAP', 'Запорожская область', 'ЮФО', 0.49, null, 0.6),
|
|
419
|
+
region('RU-KHE', 'Херсонская область', 'ЮФО', 0.36, null, 0.6),
|
|
420
|
+
|
|
421
|
+
// Северо-Кавказский федеральный округ
|
|
422
|
+
region('RU-STA', 'Ставропольский край', 'СКФО', 2.9, 1.3, 0.9),
|
|
423
|
+
region('RU-DA', 'Республика Дагестан', 'СКФО', 3.2, 1.0, 0.8),
|
|
424
|
+
region('RU-CE', 'Чеченская Республика', 'СКФО', 1.53, 0.35, 0.6),
|
|
425
|
+
region('RU-KB', 'Кабардино-Балкарская Республика', 'СКФО', 0.9, 0.25, 0.6),
|
|
426
|
+
region('RU-SE', 'Республика Северная Осетия — Алания', 'СКФО', 0.68, 0.2, 0.6),
|
|
427
|
+
region('RU-IN', 'Республика Ингушетия', 'СКФО', 0.52, 0.1, 0.5),
|
|
428
|
+
region('RU-KC', 'Карачаево-Черкесская Республика', 'СКФО', 0.47, 0.13, 0.5),
|
|
429
|
+
|
|
430
|
+
// Приволжский федеральный округ
|
|
431
|
+
region('RU-TA', 'Республика Татарстан', 'ПФО', 4.0, 4.6, 1.3, { activeEnterprises: 98_000 }),
|
|
432
|
+
region('RU-BA', 'Республика Башкортостан', 'ПФО', 4.1, 2.4, 1.0),
|
|
433
|
+
region('RU-NIZ', 'Нижегородская область', 'ПФО', 3.1, 2.5, 1.1),
|
|
434
|
+
region('RU-SAM', 'Самарская область', 'ПФО', 3.1, 2.6, 1.1),
|
|
435
|
+
region('RU-PER', 'Пермский край', 'ПФО', 2.5, 2.1, 1.0),
|
|
436
|
+
region('RU-SAR', 'Саратовская область', 'ПФО', 2.4, 1.3, 0.9),
|
|
437
|
+
region('RU-ORE', 'Оренбургская область', 'ПФО', 1.84, 1.6, 0.9),
|
|
438
|
+
region('RU-UD', 'Удмуртская Республика', 'ПФО', 1.5, 1.0, 0.9),
|
|
439
|
+
region('RU-PNZ', 'Пензенская область', 'ПФО', 1.24, 0.6, 0.7),
|
|
440
|
+
region('RU-ULY', 'Ульяновская область', 'ПФО', 1.18, 0.6, 0.7),
|
|
441
|
+
region('RU-CU', 'Чувашская Республика', 'ПФО', 1.17, 0.45, 0.7),
|
|
442
|
+
region('RU-KIR', 'Кировская область', 'ПФО', 1.12, 0.5, 0.7),
|
|
443
|
+
region('RU-MO', 'Республика Мордовия', 'ПФО', 0.76, 0.3, 0.6),
|
|
444
|
+
region('RU-ME', 'Республика Марий Эл', 'ПФО', 0.67, 0.25, 0.6),
|
|
445
|
+
|
|
446
|
+
// Уральский федеральный округ
|
|
447
|
+
region('RU-SVE', 'Свердловская область', 'УФО', 4.2, 4.2, 1.3, { activeEnterprises: 112_000 }),
|
|
448
|
+
region('RU-CHE', 'Челябинская область', 'УФО', 3.4, 2.5, 1.0),
|
|
449
|
+
region('RU-TYU', 'Тюменская область', 'УФО', 1.6, 1.9, 1.1),
|
|
450
|
+
region('RU-KHM', 'ХМАО — Югра', 'УФО', 1.7, 6.9, 1.5),
|
|
451
|
+
region('RU-YAN', 'Ямало-Ненецкий автономный округ', 'УФО', 0.5, 5.4, 1.4),
|
|
452
|
+
region('RU-KGN', 'Курганская область', 'УФО', 0.76, 0.3, 0.6),
|
|
453
|
+
|
|
454
|
+
// Сибирский федеральный округ
|
|
455
|
+
region('RU-NVS', 'Новосибирская область', 'СФО', 2.8, 2.3, 1.1, { activeEnterprises: 82_000 }),
|
|
456
|
+
region('RU-KYA', 'Красноярский край', 'СФО', 2.9, 3.5, 1.2),
|
|
457
|
+
region('RU-KEM', 'Кемеровская область — Кузбасс', 'СФО', 2.6, 2.2, 1.0),
|
|
458
|
+
region('RU-IRK', 'Иркутская область', 'СФО', 2.3, 2.4, 1.1),
|
|
459
|
+
region('RU-ALT', 'Алтайский край', 'СФО', 2.1, 1.1, 0.8),
|
|
460
|
+
region('RU-OMS', 'Омская область', 'СФО', 1.8, 1.1, 0.9),
|
|
461
|
+
region('RU-TOM', 'Томская область', 'СФО', 1.1, 0.9, 0.9),
|
|
462
|
+
region('RU-KK', 'Республика Хакасия', 'СФО', 0.53, 0.35, 0.7),
|
|
463
|
+
region('RU-TY', 'Республика Тыва', 'СФО', 0.34, 0.1, 0.5),
|
|
464
|
+
region('RU-AL', 'Республика Алтай', 'СФО', 0.21, 0.07, 0.5),
|
|
465
|
+
|
|
466
|
+
// Дальневосточный федеральный округ
|
|
467
|
+
region('RU-PRI', 'Приморский край', 'ДФО', 1.8, 1.7, 1.0),
|
|
468
|
+
region('RU-KHA', 'Хабаровский край', 'ДФО', 1.3, 1.3, 1.0),
|
|
469
|
+
region('RU-SA', 'Республика Саха (Якутия)', 'ДФО', 1.0, 2.0, 1.1),
|
|
470
|
+
region('RU-ZAB', 'Забайкальский край', 'ДФО', 0.98, 0.55, 0.7),
|
|
471
|
+
region('RU-BU', 'Республика Бурятия', 'ДФО', 0.97, 0.4, 0.7),
|
|
472
|
+
region('RU-AMU', 'Амурская область', 'ДФО', 0.75, 0.6, 0.8),
|
|
473
|
+
region('RU-SAK', 'Сахалинская область', 'ДФО', 0.46, 1.6, 1.1),
|
|
474
|
+
region('RU-KAM', 'Камчатский край', 'ДФО', 0.29, 0.35, 0.8),
|
|
475
|
+
region('RU-YEV', 'Еврейская автономная область', 'ДФО', 0.15, 0.08, 0.5),
|
|
476
|
+
region('RU-MAG', 'Магаданская область', 'ДФО', 0.14, 0.4, 0.8),
|
|
477
|
+
region('RU-CHU', 'Чукотский автономный округ', 'ДФО', 0.05, 0.15, 0.6),
|
|
478
|
+
|
|
479
|
+
// Служебный типовой регион для расчётов (на витрине не показывается)
|
|
480
|
+
region('RU-REG', 'Типовой регион РФ (до 1 млн чел.)', 'РФ', 1.0, 0.9, 0.5, { hidden: true, activeEnterprises: 25_000 }),
|
|
258
481
|
]);
|
|
259
482
|
|
|
260
483
|
/**
|
|
261
|
-
* Программа обучения и сертификации специалистов партнёров WORK.
|
|
484
|
+
* Программа обучения и сертификации специалистов партнёров ODANT-WORK.
|
|
262
485
|
*/
|
|
263
486
|
export const PARTNER_TRAINING_TRACKS = Object.freeze([
|
|
264
487
|
{
|
|
265
488
|
id: 'pak-ai-engineer',
|
|
266
|
-
title: 'Сертифицированный инженер ПАК и локального ИИ WORK',
|
|
489
|
+
title: 'Сертифицированный инженер ПАК и локального ИИ ODANT-WORK',
|
|
267
490
|
code: 'WORK-CERT-ENG',
|
|
268
491
|
hours: 40,
|
|
269
492
|
passScore: 80,
|
|
270
493
|
requiredForFranchise: true,
|
|
271
494
|
topics: [
|
|
272
|
-
'Архитектура ПАК AMD Ryzen 495
|
|
273
|
-
'Администрирование
|
|
274
|
-
'Сборка корпоративных датасетов
|
|
495
|
+
'Архитектура ПАК на AMD Ryzen™ AI Max+ PRO 495 и Radeon™ 8065S (192 ГБ Unified RAM, SSD 4 ТБ) и профилирование памяти',
|
|
496
|
+
'Администрирование предустановленных типов моделей: большая языковая модель (LLM), голосовая модель (ASR/TTS), генерация изображений и векторный поиск (Embedding)',
|
|
497
|
+
'Сборка корпоративных датасетов и дообучение моделей в контуре предприятия',
|
|
275
498
|
'Аппаратная привязка лицензий (HWID + #system/node-key.json) и закрытый контур безопасности',
|
|
276
499
|
],
|
|
277
500
|
},
|
|
278
501
|
{
|
|
279
502
|
id: 'accounting-architect',
|
|
280
|
-
title: 'Сертифицированный архитектор
|
|
503
|
+
title: 'Сертифицированный архитектор систем учёта, документооборота и процессов ODANT-WORK',
|
|
281
504
|
code: 'WORK-CERT-ACC',
|
|
282
505
|
hours: 48,
|
|
283
506
|
passScore: 80,
|
|
284
507
|
requiredForFranchise: true,
|
|
285
508
|
topics: [
|
|
286
|
-
'
|
|
509
|
+
'Встроенная система учёта (/MODULES/Register): справочники $catalog, виртуальные справочники $virtual, план счетов $account',
|
|
287
510
|
'Явная двойная запись, проведение операций $operation, сторно и двухэтапные субаналитики',
|
|
288
|
-
'Отчётность
|
|
289
|
-
'
|
|
511
|
+
'Отчётность корпоративного стандарта: Оборотно-сальдовая ведомость, Анализ счёта, Обороты счёта, Журнал проводок',
|
|
512
|
+
'Построение сквозного документооборота, управления процессами и перенос исторических данных в изолированные БД организаций',
|
|
290
513
|
],
|
|
291
514
|
},
|
|
292
515
|
{
|
|
293
516
|
id: 'platform-developer',
|
|
294
|
-
title: 'Сертифицированный разработчик модулей и ИИ-агентов WORK',
|
|
517
|
+
title: 'Сертифицированный разработчик модулей и ИИ-агентов ODANT-WORK',
|
|
295
518
|
code: 'WORK-CERT-DEV',
|
|
296
519
|
hours: 36,
|
|
297
520
|
passScore: 75,
|
|
298
521
|
requiredForFranchise: false,
|
|
299
522
|
topics: [
|
|
300
|
-
'Трёхосевое наследование метаданных WORK (Types → Ancestor → Parent → Class)',
|
|
523
|
+
'Трёхосевое наследование метаданных ODANT-WORK (Types → Ancestor → Parent → Class)',
|
|
301
524
|
'Разработка представлений work-form на компонентах ODA и серверных методов шлюза',
|
|
302
525
|
'Создание прикладных навыков (skills), инструментов и триггеров для ИИ-консультанта',
|
|
303
526
|
'Федерация серверов NODES и подключение периферии через LAN / MCP',
|
|
@@ -305,21 +528,21 @@ export const PARTNER_TRAINING_TRACKS = Object.freeze([
|
|
|
305
528
|
},
|
|
306
529
|
{
|
|
307
530
|
id: 'sales-sla-manager',
|
|
308
|
-
title: 'Сертифицированный эксперт по продажам и сопровождению
|
|
531
|
+
title: 'Сертифицированный эксперт по продажам и сопровождению ODANT-WORK',
|
|
309
532
|
code: 'WORK-CERT-SLS',
|
|
310
533
|
hours: 24,
|
|
311
534
|
passScore: 75,
|
|
312
535
|
requiredForFranchise: true,
|
|
313
536
|
topics: [
|
|
314
|
-
'Экономическое обоснование внедрения
|
|
315
|
-
'Лицензионная политика: расчёт конкурентных сессий и подбор тарифов SLA (Start / Business / Enterprise)',
|
|
537
|
+
'Экономическое обоснование внедрения ODANT-WORK (5 вечных мест + локальный ИИ в собственном контуре)',
|
|
538
|
+
'Лицензионная политика: расчёт конкурентных сессий со скидками от объёма и подбор тарифов SLA (Start / Business / Enterprise)',
|
|
316
539
|
'Регламент первой и второй линии поддержки через боты MAX, Telegram и VK',
|
|
317
540
|
],
|
|
318
541
|
},
|
|
319
542
|
]);
|
|
320
543
|
|
|
321
544
|
/**
|
|
322
|
-
* Рассчитать максимальное число
|
|
545
|
+
* Рассчитать максимальное число франшиз (квоту партнёров) для региона пропорционально численности населения.
|
|
323
546
|
*/
|
|
324
547
|
export function calculateRegionPartnerQuota(populationMillions = 1.0) {
|
|
325
548
|
const pop = Math.max(0.1, Number(populationMillions || 1.0));
|
|
@@ -327,8 +550,8 @@ export function calculateRegionPartnerQuota(populationMillions = 1.0) {
|
|
|
327
550
|
}
|
|
328
551
|
|
|
329
552
|
/**
|
|
330
|
-
* Рассчитать фиксированную стоимость региональной франшизы пропорционально экономическим характеристикам
|
|
331
|
-
* и квоту
|
|
553
|
+
* Рассчитать фиксированную стоимость региональной франшизы пропорционально экономическим характеристикам региона,
|
|
554
|
+
* невозвратный залог резервирования (100 000 ₽) и квоту франшиз пропорционально населению региона.
|
|
332
555
|
*/
|
|
333
556
|
export function calculateFranchiseFee(regionCodeOrIndex = 'RU-SVE', customPopulationMillions = null) {
|
|
334
557
|
let region = null;
|
|
@@ -347,12 +570,15 @@ export function calculateFranchiseFee(regionCodeOrIndex = 'RU-SVE', customPopula
|
|
|
347
570
|
}
|
|
348
571
|
|
|
349
572
|
const franchiseFeeRub = Math.round(FRANCHISE_PROGRAM.baseFranchiseFeeRub * economicIndex);
|
|
573
|
+
const reservationDepositRub = FRANCHISE_PROGRAM.reservationDepositRub;
|
|
350
574
|
const maxPartnersQuota = calculateRegionPartnerQuota(populationMillions);
|
|
351
575
|
|
|
352
576
|
return {
|
|
353
577
|
regionCode: region?.code || 'CUSTOM',
|
|
354
578
|
regionName: region?.name || 'Выбранный регион',
|
|
355
579
|
district: region?.district || 'РФ',
|
|
580
|
+
hidden: !!region?.hidden,
|
|
581
|
+
headquarters: !!region?.headquarters,
|
|
356
582
|
populationMillions,
|
|
357
583
|
maxPartnersQuota,
|
|
358
584
|
grpTrillionRub: region?.grpTrillionRub ?? null,
|
|
@@ -360,6 +586,8 @@ export function calculateFranchiseFee(regionCodeOrIndex = 'RU-SVE', customPopula
|
|
|
360
586
|
economicIndex,
|
|
361
587
|
baseFranchiseFeeRub: FRANCHISE_PROGRAM.baseFranchiseFeeRub,
|
|
362
588
|
franchiseFeeRub,
|
|
589
|
+
reservationDepositRub,
|
|
590
|
+
remainingAfterDepositRub: Math.max(0, franchiseFeeRub - reservationDepositRub),
|
|
363
591
|
};
|
|
364
592
|
}
|
|
365
593
|
|
|
@@ -398,11 +626,7 @@ export function calculatePartnerDiscount(annualSalesRub = 0) {
|
|
|
398
626
|
}
|
|
399
627
|
|
|
400
628
|
/**
|
|
401
|
-
* Полный расчёт экономики
|
|
402
|
-
* - фиксированный региональный взнос (по экономике региона) и квота партнёров (по населению);
|
|
403
|
-
* - скидка партнёра (10% → 50%) от годового объёма продаж;
|
|
404
|
-
* - дополнительный 100% доход партнёра: поставка NAS, серверов инференса, платный API к моделям,
|
|
405
|
-
* техподдержка, дообучение ИИ-агентов (LoRA) и разработка навыков (skills).
|
|
629
|
+
* Полный расчёт экономики партнёра-франчайзи.
|
|
406
630
|
*/
|
|
407
631
|
export function calculatePartnerEconomics({
|
|
408
632
|
regionCode = 'RU-SVE',
|
|
@@ -416,7 +640,6 @@ export function calculatePartnerEconomics({
|
|
|
416
640
|
const partnerMarginRub = Math.round(retailRub * (discount.discountPercent / 100));
|
|
417
641
|
const netToVendorRub = retailRub - partnerMarginRub;
|
|
418
642
|
|
|
419
|
-
// Расчёт дополнительных источников дохода партнёра (100% выручка партнёра)
|
|
420
643
|
const nasBackupRub = Math.max(0, Number(extraServices.nasBackupRub ?? 350_000));
|
|
421
644
|
const inferenceHardwareRub = Math.max(0, Number(extraServices.inferenceHardwareRub ?? 0));
|
|
422
645
|
const modelApiAnnualRub = Math.max(0, Number(extraServices.modelApiAnnualRub ?? 360_000));
|
|
@@ -448,4 +671,3 @@ export function calculatePartnerEconomics({
|
|
|
448
671
|
operationsModel: FRANCHISE_PROGRAM.partnerOperationsModel,
|
|
449
672
|
};
|
|
450
673
|
}
|
|
451
|
-
|