Как реализовать оценку и расчет уровней рисков в 1С:Предприятие

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

Автоматизация оценки профессиональных, финансовых или операционных рисков — частая задача в корпоративных системах. Обычно пользователю предлагается выбрать параметры по нескольким шкалам (например, вероятность наступления события, частота подверженности опасности и тяжесть последствий), а система должна мгновенно рассчитать итоговый уровень угрозы.

В этой статье мы подробно разберем, как правильно реализовать этот алгоритм в 1С:Предприятие. Мы рассмотрим теорию оценки рисков, разберем и исправим типичные ошибки в коде 1С, с которыми сталкиваются начинающие разработчики, а также спроектируем профессиональную и масштабируемую архитектуру решения с использованием регистров сведений.

Теоретическая основа: Как правильно считать риски?

В процессе обсуждения подобных задач часто возникает дилемма: какую математическую модель использовать для расчета? Рассмотрим два основных подхода:

  1. Аддитивный подход (сложение баллов): Каждому значению в шкалах присваивается балл (например, от 1 до 6). Итоговый балл рассчитывается как среднее арифметическое или сумма: Риск = Вероятность + Подверженность + Последствия. Этот подход прост в реализации, но имеет существенный недостаток: он "сглаживает" критические угрозы. Смертельный исход при минимальной вероятности может дать такой же средний балл, как регулярная мелкая царапина.
  2. Мультипликативный подход (умножение коэффициентов): Это классический профессиональный метод оценки рисков (например, широко известный метод Файна — Кинни). Формула выглядит следующим образом: ИндексРиска = Вероятность * Подверженность * Последствия. Умножение нелинейно увеличивает итоговую оценку при возрастании тяжести последствий, что позволяет корректно выделять критические риски, требующие немедленного вмешательства.

В зависимости от требований вашего бизнеса вы можете использовать любую из этих моделей. Ниже мы детально разберем программную реализацию обоих вариантов в 1С.

Решение 1. Простой (наивный) алгоритм на условиях и исправление ошибок

Часто разработчики начинают с написания простых условных конструкций в модуле формы. Однако здесь легко совершить ошибку приведения типов. Проанализируем типичный некорректный код, который часто приводит к ошибке "Преобразование значения к типу Булево не может быть выполнено":


// ПРИМЕР С ОШИБКОЙ
Если ПочтиНевозможно Тогда 
    Вероятность = 1;
КонецЕсли;

Выясним причину этой ошибки. Конструкция Если...Тогда ожидает, что выражение между ключевым словом Если и Тогда вернет логическое значение (Истина или Ложь). Если переменная ПочтиНевозможно содержит строку, ссылку или число, платформа 1С попытается преобразовать его к типу Булево и выдаст ошибку времени выполнения.

Чтобы исправить эту ситуацию, нам необходимо сравнивать выбранное пользователем значение с конкретным эталоном (строкой или элементом перечисления). Разберем по шагам корректный вариант функции расчета на клиенте:


&НаКлиенте
Функция РассчитатьИндексРискаЛокально(ВыбраннаяВероятность, ВыбраннаяПодверженность, ВыбранныйРезультат)
    
    БаллВероятности = 0;
    БаллПодверженности = 0;
    БаллРезультата = 0;
    
    // Оцифровка шкалы Вероятности
    Если ВыбраннаяВероятность = "Почти невозможно" Тогда
        БаллВероятности = 1;
    ИначеЕсли ВыбраннаяВероятность = "Маловероятно" Тогда
        БаллВероятности = 2;
    ИначеЕсли ВыбраннаяВероятность = "Возможно" Тогда
        БаллВероятности = 4;
    ИначеЕсли ВыбраннаяВероятность = "Почти всегда" Тогда
        БаллВероятности = 6;
    КонецЕсли;
    
    // Оцифровка шкалы Подверженности
    Если ВыбраннаяПодверженность = "Редко" Тогда
        БаллПодверженности = 1;
    ИначеЕсли ВыбраннаяПодверженность = "Еженедельно" Тогда
        БаллПодверженности = 3;
    ИначеЕсли ВыбраннаяПодверженность = "Постоянно" Тогда
        БаллПодверженности = 6;
    КонецЕсли;
    
    // Оцифровка шкалы Последствий (Результата)
    Если ВыбранныйРезультат = "Первая помощь" Тогда
        БаллРезультата = 1;
    ИначеЕсли ВыбранныйРезультат = "Инвалидность" Тогда
        БаллРезультата = 4;
    ИначеЕсли ВыбранныйРезультат = "Смертельный случай" Тогда
        БаллРезультата = 6;
    КонецЕсли;
    
    // Пример расчета по методу сложения долей
    СуммаБаллов = БаллВероятности + БаллПодверженности + БаллРезультата;
    МаксимальноВозможнаяСумма = 18; // 6 + 6 + 6
    ПроцентРиска = (СуммаБаллов / МаксимальноВозможнаяСумма) * 100;
    
    // Определение текстового уровня риска
    Если ПроцентРиска < 30 Тогда
        Возврат "Низкий уровень риска";
    ИначеЕсли ПроцентРиска >= 30 И ПроцентРиска < 70 Тогда
        Возврат "Средний уровень риска";
    Иначе
        Возврат "Высокий уровень риска";
    КонецЕсли;

КонецФункции

Этот код полностью работоспособен, однако он обладает серьезным недостатком — жестким кодированием параметров (hardcoding). Если бизнес-пользователи завтра захотят изменить веса коэффициентов, добавить новые уровни или переименовать пункты меню, вам придется переписывать программный код конфигурации.

Решение 2. Профессиональная архитектура на регистрах сведений

Для создания гибкой и легко поддерживаемой системы мы полностью откажемся от написания портянок из условий Если...Тогда. Перенесем все настройки шкал и весов в базу данных. Спроектируем структуру метаданных:

  1. Перечисления (или Справочники):
    • Перечисление.ВероятностиРиска со значениями: ПочтиНевозможно, Маловероятно, Возможно, ПочтиВсегда.
    • Перечисление.ПодверженностиРиска со значениями: Редко, Еженедельно, Постоянно.
    • Перечисление.ПоследствияРиска со значениями: ПерваяПомощь, Инвалидность, СмертельныйСлучай.
  2. Регистр сведений ВесаПараметровРиска:
    • Измерение: ПараметрОценки (Тип: ЛюбаяСсылка на наши перечисления или составной тип).
    • Ресурс: Балл (Тип: Число, длина 5, точность 2).
  3. Регистр сведений ШкалаУровнейРиска:
    • Ресурс: НижняяГраница (Тип: Число, хранит минимальный балл диапазона).
    • Ресурс: ВерхняяГраница (Тип: Число, хранит максимальный балл диапазона).
    • Ресурс: УровеньРиска (Тип: Строка или Справочник "УровниРисков").

Теперь напишем универсальную функцию расчета в общем модуле. Данная функция будет динамически получать веса из регистра сведений, рассчитывать итоговый индекс путем перемножения (методология Файна-Кинни) и сопоставлять результат со шкалой диапазонов с помощью запроса.


// Функция рассчитывает индекс профессионального риска и возвращает его категорию
Функция РассчитатьКатегориюРиска(Вероятность, Подверженность, Последствия) Экспорт
    
    // Инициализируем баллы значениями по умолчанию
    БаллВр = 0;
    БаллПд = 0;
    БаллПс = 0;
    
    // Запрос для быстрого получения баллов по выбранным значениям
    ЗапросБаллов = Новый Запрос;
    ЗапросБаллов.Текст = 
        "ВЫБРАТЬ
        |	Веса.ПараметрОценки КАК Параметр,
        |	Веса.Балл КАК Балл
        |ИЗ
        |	РегистрСведений.ВесаПараметровРиска КАК Веса
        |ГДЕ
        |	Веса.ПараметрОценки В(&СписокПараметров)";
        
    СписокПараметров = Новый Массив;
    СписокПараметров.Добавить(Вероятность);
    СписокПараметров.Добавить(Подверженность);
    СписокПараметров.Добавить(Последствия);
    
    ЗапросБаллов.УстановитьПараметр("СписокПараметров", СписокПараметров);
    ВыборкаБаллов = ЗапросБаллов.Выполнить().Выбрать();
    
    Пока ВыборкаБаллов.Следующий() Цикл
        Если ВыборкаБаллов.Параметр = Вероятность Тогда
            БаллВр = ВыборкаБаллов.Балл;
        ИначеЕсли ВыборкаБаллов.Параметр = Подверженность Тогда
            БаллПд = ВыборкаБаллов.Балл;
        ИначеЕсли ВыборкаБаллов.Параметр = Последствия Тогда
            БаллПс = ВыборкаБаллов.Балл;
        КонецЕсли;
    КонецЦикла;
    
    // Вычисление индекса риска по мультипликативной модели (Файн-Кинни)
    ИндексРиска = БаллВр * БаллПд * БаллПс;
    
    // Запрос для определения категории риска по шкале диапазонов
    ЗапросШкалы = Новый Запрос;
    ЗапросШкалы.Текст = 
        "ВЫБРАТЬ
        |	Шкала.УровеньРиска КАК Уровень
        |ИЗ
        |	РегистрСведений.ШкалаУровнейРиска КАК Шкала
        |ГДЕ
        |	&ИндексРиска МЕЖДУ Шкала.НижняяГраница И Шкала.ВерхняяГраница";
        
    ЗапросШкалы.УстановитьПараметр("ИндексРиска", ИндексРиска);
    ВыборкаШкалы = ЗапросШкалы.Выполнить().Выбрать();
    
    Если ВыборкаШкалы.Следующий() Тогда
        Возврат ВыборкаШкалы.Уровень;
    Иначе
        Возврат "Не определен (вне шкалы диапазонов)";
    КонецЕсли;
    
КонецФункции

Интеграция расчета в форму документа

Проанализируем, как связать этот алгоритм с интерфейсом пользователя на управляемой форме. Предположим, у нас есть документ оценки рисков, на форму которого выведены реквизиты: Объект.Вероятность, Объект.Подверженность и Объект.Последствия.

Для обеспечения мгновенной реакции интерфейса нам необходимо назначить обработчик события ПриИзменении для каждого из этих трех элементов управления на форме. Все они могут вызывать одну общую процедуру:


&НаКлиенте
Процедура ОценкаРискаПриИзменении(Элемент)
    
    // Проверяем заполненность всех ключевых полей перед началом расчета
    Если ЗначениеЗаполнено(Объект.Вероятность) 
        И ЗначениеЗаполнено(Объект.Подверженность) 
        И ЗначениеЗаполнено(Объект.Последствия) Тогда
        
        // Вызываем серверный контекст для выполнения расчета по регистрам сведений
        Объект.УровеньРиска = ПолучитьУровеньРискаНаСервере(Объект.Вероятность, Объект.Подверженность, Объект.Последствия);
        
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьУровеньРискаНаСервере(Вероятность, Подверженность, Последствия)
    // Вызываем нашу универсальную функцию из общего модуля
    Возврат ПроведениеОценкиРисковСервер.РассчитатьКатегориюРиска(Вероятность, Подверженность, Последствия);
КонецФункции

Преимущества использования регистров сведений

Рассмотренный нами подход с вынесением логики в регистры сведений предоставляет следующие преимущества:

Применение мультипликативного метода Файна-Кинни совместно с гибкой архитектурой метаданных 1С позволит вам создать надежную, отказоустойчивую и удобную систему мониторинга рисков любой сложности.

← На главную