work-license-server 1.0.0 → 1.0.2
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 +319 -93
- package/src/index.js +6 -0
- package/src/landing.js +746 -882
- package/src/server.js +103 -5
- package/src/store.js +202 -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,40 @@ export function calculateOrderQuote({
|
|
|
170
276
|
}
|
|
171
277
|
|
|
172
278
|
/**
|
|
173
|
-
* Параметры партнёрской программы и региональной франшизы WORK:
|
|
174
|
-
* -
|
|
175
|
-
* -
|
|
279
|
+
* Параметры партнёрской программы и региональной франшизы ODANT-WORK:
|
|
280
|
+
* - Базовый паушальный взнос = 500 000 ₽ (корректируется пропорционально экономическому индексу региона).
|
|
281
|
+
* - Сразу при резервировании франшизы вносится невозвратный залог = 100 000 ₽, полная оплата паушального взноса — в течение 1 года (12 мес.).
|
|
282
|
+
* - Максимальное количество франшиз в регионе пропорционально населению региона (partnersPerMillion * populationMillions, мин. 1).
|
|
176
283
|
* - Партнёрская скидка растёт пропорционально годовому объёму продаж от начальных 10% до максимальных 50%.
|
|
177
284
|
*/
|
|
178
285
|
export const FRANCHISE_PROGRAM = Object.freeze({
|
|
179
|
-
baseFranchiseFeeRub:
|
|
180
|
-
|
|
286
|
+
baseFranchiseFeeRub: 500_000, // Базовый паушальный взнос (500 тыс. ₽ при экономическом индексе 1.0)
|
|
287
|
+
reservationDepositRub: 100_000, // Невозвратный залог сразу за резервирование региональной франшизы (100 тыс. ₽)
|
|
288
|
+
fullPaymentPeriodMonths: 12, // Срок полной оплаты паушального взноса — в течение 1 года (12 месяцев)
|
|
289
|
+
fullPaymentPeriodYears: 1, // 1 год на полную оплату паушального взноса после резервирования
|
|
290
|
+
partnersPerMillionPopulation: 1, // Норматив квоты партнёров: 1 франшиза на 1 млн населения региона
|
|
181
291
|
minDiscountPercent: 10, // Начальная партнёрская скидка (10%)
|
|
182
292
|
maxDiscountPercent: 50, // Максимальная партнёрская скидка (50%)
|
|
183
|
-
maxDiscountAnnualSalesRub: 100_000_000, // Годовой объём продаж (100 млн ₽ = ~20 ПАК), при котором достигается
|
|
184
|
-
hardwareWarrantyYears: 1, //
|
|
293
|
+
maxDiscountAnnualSalesRub: 100_000_000, // Годовой объём продаж (100 млн ₽ = ~20 ПАК), при котором достигается скидка 50%
|
|
294
|
+
hardwareWarrantyYears: 1, // Годовая гарантия на оборудование, предоставляемая партнёром
|
|
185
295
|
partnerOperationsModel: Object.freeze([
|
|
186
|
-
'Партнёр самостоятельно закупает аппаратную платформу (AMD Ryzen 495
|
|
187
|
-
'Партнёр
|
|
188
|
-
'Партнёр самостоятельно привязывает оборудование (HWID + #system/node-key.json) и выдаёт лицензии клиентам
|
|
189
|
-
'Партнёр предоставляет клиенту годовую гарантию (1 год) на поставленное оборудование
|
|
296
|
+
'Партнёр самостоятельно закупает аппаратную платформу (AMD Ryzen™ AI Max+ PRO 495 · Radeon™ 8065S · 192 ГБ RAM · SSD 4 ТБ)',
|
|
297
|
+
'Партнёр устанавливает ODANT-WORK, систему учёта, документооборота, процессов и 4 локальные модели ИИ',
|
|
298
|
+
'Партнёр самостоятельно привязывает оборудование (HWID + #system/node-key.json) и выдаёт лицензии клиентам',
|
|
299
|
+
'Партнёр предоставляет клиенту годовую гарантию (1 год) на поставленное оборудование',
|
|
190
300
|
]),
|
|
191
301
|
partnerRevenueStreams: Object.freeze([
|
|
192
302
|
{
|
|
193
303
|
id: 'pak-license-margin',
|
|
194
|
-
title: 'Продажа
|
|
195
|
-
share: 'Скидка партнёра от 10% до 50% пропорционально годовому объёму продаж + аппаратная
|
|
304
|
+
title: 'Продажа комплексов ODANT-WORK и лицензий (скидка 10% → 50%)',
|
|
305
|
+
share: 'Скидка партнёра от 10% до 50% пропорционально годовому объёму продаж + аппаратная маржа сборки',
|
|
196
306
|
recommendedAvgRub: 1_500_000,
|
|
197
307
|
},
|
|
198
308
|
{
|
|
199
309
|
id: 'nas-backup-hardware',
|
|
200
310
|
title: 'Поставка NAS-систем для резервного копирования',
|
|
201
311
|
share: '100% доход партнёра',
|
|
202
|
-
description: 'Поставка и настройка сетевых хранилищ NAS для автоматической архивации и
|
|
312
|
+
description: 'Поставка и настройка сетевых хранилищ NAS для автоматической архивации и резервного копирования баз организаций',
|
|
203
313
|
recommendedAvgRub: 350_000,
|
|
204
314
|
},
|
|
205
315
|
{
|
|
@@ -219,7 +329,7 @@ export const FRANCHISE_PROGRAM = Object.freeze({
|
|
|
219
329
|
{
|
|
220
330
|
id: 'partner-tech-support',
|
|
221
331
|
title: 'Техническая поддержка и сервисное сопровождение',
|
|
222
|
-
share: 'Доход партнёра по договорам SLA и
|
|
332
|
+
share: 'Доход партнёра по договорам SLA и гарантийному обслуживанию',
|
|
223
333
|
description: 'Первая и вторая линия техподдержки предприятий региона, администрирование серверов и регламентное ТО',
|
|
224
334
|
recommendedAvgRub: 240_000,
|
|
225
335
|
},
|
|
@@ -227,77 +337,192 @@ export const FRANCHISE_PROGRAM = Object.freeze({
|
|
|
227
337
|
id: 'agent-training-skills',
|
|
228
338
|
title: 'Дообучение ИИ-агентов (LoRA) и разработка навыков (skills)',
|
|
229
339
|
share: '100% проектный доход партнёра',
|
|
230
|
-
description: 'Сборка датасетов предприятия, дообучение моделей под отраслевую специфику, создание навыков (skills) и
|
|
340
|
+
description: 'Сборка датасетов предприятия, дообучение моделей под отраслевую специфику, создание навыков (skills) и процессных схем',
|
|
231
341
|
recommendedAvgRub: 600_000,
|
|
232
342
|
},
|
|
233
343
|
]),
|
|
234
344
|
});
|
|
235
345
|
|
|
236
346
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
347
|
+
* Перечень всех субъектов Российской Федерации для партнёрской программы:
|
|
348
|
+
* численность населения (populationMillions — определяет квоту франшиз), ВРП (grpTrillionRub, оценка)
|
|
349
|
+
* и экономический индекс (economicIndex — множитель базовой стоимости франшизы).
|
|
350
|
+
* Контуры субъектов для интерактивной карты лежат в assets/russia-regions.json (по коду субъекта).
|
|
351
|
+
* Служебный «Типовой регион» (RU-REG, hidden) используется для расчётов и на витрине не показывается.
|
|
240
352
|
*/
|
|
353
|
+
const region = (code, name, district, populationMillions, grpTrillionRub, economicIndex, extra = {}) => Object.freeze({
|
|
354
|
+
code,
|
|
355
|
+
name,
|
|
356
|
+
district,
|
|
357
|
+
populationMillions,
|
|
358
|
+
grpTrillionRub,
|
|
359
|
+
activeEnterprises: Math.round(populationMillions * 22_000 / 1000) * 1000,
|
|
360
|
+
economicIndex,
|
|
361
|
+
...extra,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
export const FEDERAL_DISTRICTS = Object.freeze({
|
|
365
|
+
'ЦФО': 'Центральный',
|
|
366
|
+
'СЗФО': 'Северо-Западный',
|
|
367
|
+
'ЮФО': 'Южный',
|
|
368
|
+
'СКФО': 'Северо-Кавказский',
|
|
369
|
+
'ПФО': 'Приволжский',
|
|
370
|
+
'УФО': 'Уральский',
|
|
371
|
+
'СФО': 'Сибирский',
|
|
372
|
+
'ДФО': 'Дальневосточный',
|
|
373
|
+
});
|
|
374
|
+
|
|
241
375
|
export const REGIONS_CATALOG = Object.freeze([
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
376
|
+
// Центральный федеральный округ
|
|
377
|
+
region('RU-MOW', 'Москва', 'ЦФО', 13.1, 28.5, 2.0, { activeEnterprises: 620_000 }),
|
|
378
|
+
region('RU-MOS', 'Московская область', 'ЦФО', 8.6, 8.4, 1.4, { activeEnterprises: 185_000 }),
|
|
379
|
+
region('RU-BEL', 'Белгородская область', 'ЦФО', 1.5, 1.4, 0.9),
|
|
380
|
+
region('RU-BRY', 'Брянская область', 'ЦФО', 1.15, 0.6, 0.7),
|
|
381
|
+
region('RU-VLA', 'Владимирская область', 'ЦФО', 1.33, 0.75, 0.8),
|
|
382
|
+
region('RU-VOR', 'Воронежская область', 'ЦФО', 2.3, 1.5, 0.9),
|
|
383
|
+
region('RU-IVA', 'Ивановская область', 'ЦФО', 0.91, 0.35, 0.6),
|
|
384
|
+
region('RU-KLU', 'Калужская область', 'ЦФО', 1.07, 0.8, 0.8),
|
|
385
|
+
region('RU-KOS', 'Костромская область', 'ЦФО', 0.57, 0.3, 0.6),
|
|
386
|
+
region('RU-KRS', 'Курская область', 'ЦФО', 1.07, 0.8, 0.8),
|
|
387
|
+
region('RU-LIP', 'Липецкая область', 'ЦФО', 1.12, 1.0, 0.9),
|
|
388
|
+
region('RU-ORL', 'Орловская область', 'ЦФО', 0.7, 0.35, 0.6),
|
|
389
|
+
region('RU-RYA', 'Рязанская область', 'ЦФО', 1.08, 0.65, 0.8, { headquarters: true }),
|
|
390
|
+
region('RU-SMO', 'Смоленская область', 'ЦФО', 0.88, 0.45, 0.7),
|
|
391
|
+
region('RU-TAM', 'Тамбовская область', 'ЦФО', 0.97, 0.5, 0.7),
|
|
392
|
+
region('RU-TVE', 'Тверская область', 'ЦФО', 1.21, 0.7, 0.8),
|
|
393
|
+
region('RU-TUL', 'Тульская область', 'ЦФО', 1.5, 1.1, 0.9),
|
|
394
|
+
region('RU-YAR', 'Ярославская область', 'ЦФО', 1.2, 0.9, 0.9),
|
|
395
|
+
|
|
396
|
+
// Северо-Западный федеральный округ
|
|
397
|
+
region('RU-SPE', 'Санкт-Петербург', 'СЗФО', 5.6, 11.2, 1.6, { activeEnterprises: 245_000 }),
|
|
398
|
+
region('RU-LEN', 'Ленинградская область', 'СЗФО', 2.0, 1.8, 1.0),
|
|
399
|
+
region('RU-KGD', 'Калининградская область', 'СЗФО', 1.0, 0.9, 0.9),
|
|
400
|
+
region('RU-MUR', 'Мурманская область', 'СЗФО', 0.7, 1.2, 1.0),
|
|
401
|
+
region('RU-ARK', 'Архангельская область', 'СЗФО', 0.96, 1.1, 0.9),
|
|
402
|
+
region('RU-NEN', 'Ненецкий автономный округ', 'СЗФО', 0.04, 0.35, 0.6),
|
|
403
|
+
region('RU-VLG', 'Вологодская область', 'СЗФО', 1.1, 1.1, 0.9),
|
|
404
|
+
region('RU-KR', 'Республика Карелия', 'СЗФО', 0.52, 0.45, 0.7),
|
|
405
|
+
region('RU-KO', 'Республика Коми', 'СЗФО', 0.72, 0.9, 0.9),
|
|
406
|
+
region('RU-NGR', 'Новгородская область', 'СЗФО', 0.58, 0.4, 0.7),
|
|
407
|
+
region('RU-PSK', 'Псковская область', 'СЗФО', 0.58, 0.25, 0.6),
|
|
408
|
+
|
|
409
|
+
// Южный федеральный округ
|
|
410
|
+
region('RU-KDA', 'Краснодарский край', 'ЮФО', 5.8, 4.3, 1.3, { activeEnterprises: 120_000 }),
|
|
411
|
+
region('RU-ROS', 'Ростовская область', 'ЮФО', 4.2, 2.6, 1.0),
|
|
412
|
+
region('RU-VGG', 'Волгоградская область', 'ЮФО', 2.5, 1.4, 0.9),
|
|
413
|
+
region('RU-AST', 'Астраханская область', 'ЮФО', 0.95, 0.6, 0.8),
|
|
414
|
+
region('RU-AD', 'Республика Адыгея', 'ЮФО', 0.5, 0.15, 0.6),
|
|
415
|
+
region('RU-KL', 'Республика Калмыкия', 'ЮФО', 0.26, 0.1, 0.5),
|
|
416
|
+
region('RU-CR', 'Республика Крым', 'ЮФО', 1.91, 0.75, 0.8),
|
|
417
|
+
region('RU-SEV', 'Севастополь', 'ЮФО', 0.56, 0.2, 0.8),
|
|
418
|
+
region('RU-DPR', 'Донецкая Народная Республика', 'ЮФО', 2.29, null, 0.6),
|
|
419
|
+
region('RU-LPR', 'Луганская Народная Республика', 'ЮФО', 1.32, null, 0.6),
|
|
420
|
+
region('RU-ZAP', 'Запорожская область', 'ЮФО', 0.49, null, 0.6),
|
|
421
|
+
region('RU-KHE', 'Херсонская область', 'ЮФО', 0.36, null, 0.6),
|
|
422
|
+
|
|
423
|
+
// Северо-Кавказский федеральный округ
|
|
424
|
+
region('RU-STA', 'Ставропольский край', 'СКФО', 2.9, 1.3, 0.9),
|
|
425
|
+
region('RU-DA', 'Республика Дагестан', 'СКФО', 3.2, 1.0, 0.8),
|
|
426
|
+
region('RU-CE', 'Чеченская Республика', 'СКФО', 1.53, 0.35, 0.6),
|
|
427
|
+
region('RU-KB', 'Кабардино-Балкарская Республика', 'СКФО', 0.9, 0.25, 0.6),
|
|
428
|
+
region('RU-SE', 'Республика Северная Осетия — Алания', 'СКФО', 0.68, 0.2, 0.6),
|
|
429
|
+
region('RU-IN', 'Республика Ингушетия', 'СКФО', 0.52, 0.1, 0.5),
|
|
430
|
+
region('RU-KC', 'Карачаево-Черкесская Республика', 'СКФО', 0.47, 0.13, 0.5),
|
|
431
|
+
|
|
432
|
+
// Приволжский федеральный округ
|
|
433
|
+
region('RU-TA', 'Республика Татарстан', 'ПФО', 4.0, 4.6, 1.3, { activeEnterprises: 98_000 }),
|
|
434
|
+
region('RU-BA', 'Республика Башкортостан', 'ПФО', 4.1, 2.4, 1.0),
|
|
435
|
+
region('RU-NIZ', 'Нижегородская область', 'ПФО', 3.1, 2.5, 1.1),
|
|
436
|
+
region('RU-SAM', 'Самарская область', 'ПФО', 3.1, 2.6, 1.1),
|
|
437
|
+
region('RU-PER', 'Пермский край', 'ПФО', 2.5, 2.1, 1.0),
|
|
438
|
+
region('RU-SAR', 'Саратовская область', 'ПФО', 2.4, 1.3, 0.9),
|
|
439
|
+
region('RU-ORE', 'Оренбургская область', 'ПФО', 1.84, 1.6, 0.9),
|
|
440
|
+
region('RU-UD', 'Удмуртская Республика', 'ПФО', 1.5, 1.0, 0.9),
|
|
441
|
+
region('RU-PNZ', 'Пензенская область', 'ПФО', 1.24, 0.6, 0.7),
|
|
442
|
+
region('RU-ULY', 'Ульяновская область', 'ПФО', 1.18, 0.6, 0.7),
|
|
443
|
+
region('RU-CU', 'Чувашская Республика', 'ПФО', 1.17, 0.45, 0.7),
|
|
444
|
+
region('RU-KIR', 'Кировская область', 'ПФО', 1.12, 0.5, 0.7),
|
|
445
|
+
region('RU-MO', 'Республика Мордовия', 'ПФО', 0.76, 0.3, 0.6),
|
|
446
|
+
region('RU-ME', 'Республика Марий Эл', 'ПФО', 0.67, 0.25, 0.6),
|
|
447
|
+
|
|
448
|
+
// Уральский федеральный округ
|
|
449
|
+
region('RU-SVE', 'Свердловская область', 'УФО', 4.2, 4.2, 1.3, { activeEnterprises: 112_000 }),
|
|
450
|
+
region('RU-CHE', 'Челябинская область', 'УФО', 3.4, 2.5, 1.0),
|
|
451
|
+
region('RU-TYU', 'Тюменская область', 'УФО', 1.6, 1.9, 1.1),
|
|
452
|
+
region('RU-KHM', 'ХМАО — Югра', 'УФО', 1.7, 6.9, 1.5),
|
|
453
|
+
region('RU-YAN', 'Ямало-Ненецкий автономный округ', 'УФО', 0.5, 5.4, 1.4),
|
|
454
|
+
region('RU-KGN', 'Курганская область', 'УФО', 0.76, 0.3, 0.6),
|
|
455
|
+
|
|
456
|
+
// Сибирский федеральный округ
|
|
457
|
+
region('RU-NVS', 'Новосибирская область', 'СФО', 2.8, 2.3, 1.1, { activeEnterprises: 82_000 }),
|
|
458
|
+
region('RU-KYA', 'Красноярский край', 'СФО', 2.9, 3.5, 1.2),
|
|
459
|
+
region('RU-KEM', 'Кемеровская область — Кузбасс', 'СФО', 2.6, 2.2, 1.0),
|
|
460
|
+
region('RU-IRK', 'Иркутская область', 'СФО', 2.3, 2.4, 1.1),
|
|
461
|
+
region('RU-ALT', 'Алтайский край', 'СФО', 2.1, 1.1, 0.8),
|
|
462
|
+
region('RU-OMS', 'Омская область', 'СФО', 1.8, 1.1, 0.9),
|
|
463
|
+
region('RU-TOM', 'Томская область', 'СФО', 1.1, 0.9, 0.9),
|
|
464
|
+
region('RU-KK', 'Республика Хакасия', 'СФО', 0.53, 0.35, 0.7),
|
|
465
|
+
region('RU-TY', 'Республика Тыва', 'СФО', 0.34, 0.1, 0.5),
|
|
466
|
+
region('RU-AL', 'Республика Алтай', 'СФО', 0.21, 0.07, 0.5),
|
|
467
|
+
|
|
468
|
+
// Дальневосточный федеральный округ
|
|
469
|
+
region('RU-PRI', 'Приморский край', 'ДФО', 1.8, 1.7, 1.0),
|
|
470
|
+
region('RU-KHA', 'Хабаровский край', 'ДФО', 1.3, 1.3, 1.0),
|
|
471
|
+
region('RU-SA', 'Республика Саха (Якутия)', 'ДФО', 1.0, 2.0, 1.1),
|
|
472
|
+
region('RU-ZAB', 'Забайкальский край', 'ДФО', 0.98, 0.55, 0.7),
|
|
473
|
+
region('RU-BU', 'Республика Бурятия', 'ДФО', 0.97, 0.4, 0.7),
|
|
474
|
+
region('RU-AMU', 'Амурская область', 'ДФО', 0.75, 0.6, 0.8),
|
|
475
|
+
region('RU-SAK', 'Сахалинская область', 'ДФО', 0.46, 1.6, 1.1),
|
|
476
|
+
region('RU-KAM', 'Камчатский край', 'ДФО', 0.29, 0.35, 0.8),
|
|
477
|
+
region('RU-YEV', 'Еврейская автономная область', 'ДФО', 0.15, 0.08, 0.5),
|
|
478
|
+
region('RU-MAG', 'Магаданская область', 'ДФО', 0.14, 0.4, 0.8),
|
|
479
|
+
region('RU-CHU', 'Чукотский автономный округ', 'ДФО', 0.05, 0.15, 0.6),
|
|
480
|
+
|
|
481
|
+
// Служебный типовой регион для расчётов (на витрине не показывается)
|
|
482
|
+
region('RU-REG', 'Типовой регион РФ (до 1 млн чел.)', 'РФ', 1.0, 0.9, 0.5, { hidden: true, activeEnterprises: 25_000 }),
|
|
258
483
|
]);
|
|
259
484
|
|
|
260
485
|
/**
|
|
261
|
-
* Программа обучения и сертификации специалистов партнёров WORK.
|
|
486
|
+
* Программа обучения и сертификации специалистов партнёров ODANT-WORK.
|
|
262
487
|
*/
|
|
263
488
|
export const PARTNER_TRAINING_TRACKS = Object.freeze([
|
|
264
489
|
{
|
|
265
490
|
id: 'pak-ai-engineer',
|
|
266
|
-
title: 'Сертифицированный инженер ПАК и локального ИИ WORK',
|
|
491
|
+
title: 'Сертифицированный инженер ПАК и локального ИИ ODANT-WORK',
|
|
267
492
|
code: 'WORK-CERT-ENG',
|
|
268
493
|
hours: 40,
|
|
269
494
|
passScore: 80,
|
|
270
495
|
requiredForFranchise: true,
|
|
271
496
|
topics: [
|
|
272
|
-
'Архитектура ПАК AMD Ryzen 495
|
|
273
|
-
'Администрирование
|
|
274
|
-
'Сборка корпоративных датасетов
|
|
497
|
+
'Архитектура ПАК на AMD Ryzen™ AI Max+ PRO 495 и Radeon™ 8065S (192 ГБ Unified RAM, SSD 4 ТБ) и профилирование памяти',
|
|
498
|
+
'Администрирование предустановленных типов моделей: большая языковая модель (LLM), голосовая модель (ASR/TTS), генерация изображений и векторный поиск (Embedding)',
|
|
499
|
+
'Сборка корпоративных датасетов и дообучение моделей в контуре предприятия',
|
|
275
500
|
'Аппаратная привязка лицензий (HWID + #system/node-key.json) и закрытый контур безопасности',
|
|
276
501
|
],
|
|
277
502
|
},
|
|
278
503
|
{
|
|
279
504
|
id: 'accounting-architect',
|
|
280
|
-
title: 'Сертифицированный архитектор
|
|
505
|
+
title: 'Сертифицированный архитектор систем учёта, документооборота и процессов ODANT-WORK',
|
|
281
506
|
code: 'WORK-CERT-ACC',
|
|
282
507
|
hours: 48,
|
|
283
508
|
passScore: 80,
|
|
284
509
|
requiredForFranchise: true,
|
|
285
510
|
topics: [
|
|
286
|
-
'
|
|
511
|
+
'Встроенная система учёта (/MODULES/Register): справочники $catalog, виртуальные справочники $virtual, план счетов $account',
|
|
287
512
|
'Явная двойная запись, проведение операций $operation, сторно и двухэтапные субаналитики',
|
|
288
|
-
'Отчётность
|
|
289
|
-
'
|
|
513
|
+
'Отчётность корпоративного стандарта: Оборотно-сальдовая ведомость, Анализ счёта, Обороты счёта, Журнал проводок',
|
|
514
|
+
'Построение сквозного документооборота, управления процессами и перенос исторических данных в изолированные БД организаций',
|
|
290
515
|
],
|
|
291
516
|
},
|
|
292
517
|
{
|
|
293
518
|
id: 'platform-developer',
|
|
294
|
-
title: 'Сертифицированный разработчик модулей и ИИ-агентов WORK',
|
|
519
|
+
title: 'Сертифицированный разработчик модулей и ИИ-агентов ODANT-WORK',
|
|
295
520
|
code: 'WORK-CERT-DEV',
|
|
296
521
|
hours: 36,
|
|
297
522
|
passScore: 75,
|
|
298
523
|
requiredForFranchise: false,
|
|
299
524
|
topics: [
|
|
300
|
-
'Трёхосевое наследование метаданных WORK (Types → Ancestor → Parent → Class)',
|
|
525
|
+
'Трёхосевое наследование метаданных ODANT-WORK (Types → Ancestor → Parent → Class)',
|
|
301
526
|
'Разработка представлений work-form на компонентах ODA и серверных методов шлюза',
|
|
302
527
|
'Создание прикладных навыков (skills), инструментов и триггеров для ИИ-консультанта',
|
|
303
528
|
'Федерация серверов NODES и подключение периферии через LAN / MCP',
|
|
@@ -305,21 +530,21 @@ export const PARTNER_TRAINING_TRACKS = Object.freeze([
|
|
|
305
530
|
},
|
|
306
531
|
{
|
|
307
532
|
id: 'sales-sla-manager',
|
|
308
|
-
title: 'Сертифицированный эксперт по продажам и сопровождению
|
|
533
|
+
title: 'Сертифицированный эксперт по продажам и сопровождению ODANT-WORK',
|
|
309
534
|
code: 'WORK-CERT-SLS',
|
|
310
535
|
hours: 24,
|
|
311
536
|
passScore: 75,
|
|
312
537
|
requiredForFranchise: true,
|
|
313
538
|
topics: [
|
|
314
|
-
'Экономическое обоснование внедрения
|
|
315
|
-
'Лицензионная политика: расчёт конкурентных сессий и подбор тарифов SLA (Start / Business / Enterprise)',
|
|
539
|
+
'Экономическое обоснование внедрения ODANT-WORK (5 вечных мест + локальный ИИ в собственном контуре)',
|
|
540
|
+
'Лицензионная политика: расчёт конкурентных сессий со скидками от объёма и подбор тарифов SLA (Start / Business / Enterprise)',
|
|
316
541
|
'Регламент первой и второй линии поддержки через боты MAX, Telegram и VK',
|
|
317
542
|
],
|
|
318
543
|
},
|
|
319
544
|
]);
|
|
320
545
|
|
|
321
546
|
/**
|
|
322
|
-
* Рассчитать максимальное число
|
|
547
|
+
* Рассчитать максимальное число франшиз (квоту партнёров) для региона пропорционально численности населения.
|
|
323
548
|
*/
|
|
324
549
|
export function calculateRegionPartnerQuota(populationMillions = 1.0) {
|
|
325
550
|
const pop = Math.max(0.1, Number(populationMillions || 1.0));
|
|
@@ -327,8 +552,8 @@ export function calculateRegionPartnerQuota(populationMillions = 1.0) {
|
|
|
327
552
|
}
|
|
328
553
|
|
|
329
554
|
/**
|
|
330
|
-
* Рассчитать фиксированную стоимость региональной франшизы пропорционально экономическим характеристикам
|
|
331
|
-
* и квоту
|
|
555
|
+
* Рассчитать фиксированную стоимость региональной франшизы пропорционально экономическим характеристикам региона,
|
|
556
|
+
* невозвратный залог резервирования (100 000 ₽) и квоту франшиз пропорционально населению региона.
|
|
332
557
|
*/
|
|
333
558
|
export function calculateFranchiseFee(regionCodeOrIndex = 'RU-SVE', customPopulationMillions = null) {
|
|
334
559
|
let region = null;
|
|
@@ -347,12 +572,15 @@ export function calculateFranchiseFee(regionCodeOrIndex = 'RU-SVE', customPopula
|
|
|
347
572
|
}
|
|
348
573
|
|
|
349
574
|
const franchiseFeeRub = Math.round(FRANCHISE_PROGRAM.baseFranchiseFeeRub * economicIndex);
|
|
575
|
+
const reservationDepositRub = FRANCHISE_PROGRAM.reservationDepositRub;
|
|
350
576
|
const maxPartnersQuota = calculateRegionPartnerQuota(populationMillions);
|
|
351
577
|
|
|
352
578
|
return {
|
|
353
579
|
regionCode: region?.code || 'CUSTOM',
|
|
354
580
|
regionName: region?.name || 'Выбранный регион',
|
|
355
581
|
district: region?.district || 'РФ',
|
|
582
|
+
hidden: !!region?.hidden,
|
|
583
|
+
headquarters: !!region?.headquarters,
|
|
356
584
|
populationMillions,
|
|
357
585
|
maxPartnersQuota,
|
|
358
586
|
grpTrillionRub: region?.grpTrillionRub ?? null,
|
|
@@ -360,6 +588,10 @@ export function calculateFranchiseFee(regionCodeOrIndex = 'RU-SVE', customPopula
|
|
|
360
588
|
economicIndex,
|
|
361
589
|
baseFranchiseFeeRub: FRANCHISE_PROGRAM.baseFranchiseFeeRub,
|
|
362
590
|
franchiseFeeRub,
|
|
591
|
+
reservationDepositRub,
|
|
592
|
+
remainingAfterDepositRub: Math.max(0, franchiseFeeRub - reservationDepositRub),
|
|
593
|
+
fullPaymentPeriodMonths: FRANCHISE_PROGRAM.fullPaymentPeriodMonths,
|
|
594
|
+
fullPaymentPeriodYears: FRANCHISE_PROGRAM.fullPaymentPeriodYears,
|
|
363
595
|
};
|
|
364
596
|
}
|
|
365
597
|
|
|
@@ -398,11 +630,7 @@ export function calculatePartnerDiscount(annualSalesRub = 0) {
|
|
|
398
630
|
}
|
|
399
631
|
|
|
400
632
|
/**
|
|
401
|
-
* Полный расчёт экономики
|
|
402
|
-
* - фиксированный региональный взнос (по экономике региона) и квота партнёров (по населению);
|
|
403
|
-
* - скидка партнёра (10% → 50%) от годового объёма продаж;
|
|
404
|
-
* - дополнительный 100% доход партнёра: поставка NAS, серверов инференса, платный API к моделям,
|
|
405
|
-
* техподдержка, дообучение ИИ-агентов (LoRA) и разработка навыков (skills).
|
|
633
|
+
* Полный расчёт экономики партнёра-франчайзи.
|
|
406
634
|
*/
|
|
407
635
|
export function calculatePartnerEconomics({
|
|
408
636
|
regionCode = 'RU-SVE',
|
|
@@ -416,7 +644,6 @@ export function calculatePartnerEconomics({
|
|
|
416
644
|
const partnerMarginRub = Math.round(retailRub * (discount.discountPercent / 100));
|
|
417
645
|
const netToVendorRub = retailRub - partnerMarginRub;
|
|
418
646
|
|
|
419
|
-
// Расчёт дополнительных источников дохода партнёра (100% выручка партнёра)
|
|
420
647
|
const nasBackupRub = Math.max(0, Number(extraServices.nasBackupRub ?? 350_000));
|
|
421
648
|
const inferenceHardwareRub = Math.max(0, Number(extraServices.inferenceHardwareRub ?? 0));
|
|
422
649
|
const modelApiAnnualRub = Math.max(0, Number(extraServices.modelApiAnnualRub ?? 360_000));
|
|
@@ -448,4 +675,3 @@ export function calculatePartnerEconomics({
|
|
|
448
675
|
operationsModel: FRANCHISE_PROGRAM.partnerOperationsModel,
|
|
449
676
|
};
|
|
450
677
|
}
|
|
451
|
-
|