В процессе разработки учетных механизмов в 1С часто возникает задача контроля данных, вводимых пользователем вручную. Типичный пример — распределение показателей по месяцам года, где сумма долей внутри каждого квартала должна строго равняться единице. Рассмотрим подробнее, как эффективно реализовать такую проверку, обеспечив при этом удобство работы пользователя и надежность хранения данных.
Наиболее надежный способ — выполнение проверки непосредственно перед фиксацией данных в базе. Для этого проанализируем событие ПередЗаписью или стандартный обработчик ОбработкаПроверкиЗаполнения. Основная идея заключается в последовательном обходе строк табличной части и накоплении суммы для каждой группы из трех месяцев.
Разберем пример алгоритма, который можно разместить в модуле документа. Важно учитывать, что строки в таблице должны быть жестко отсортированы по месяцам, иначе простая итерация «по три строки» приведет к ошибке.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Инициализируем переменные для накопления
ТекущаяСуммаКвартала = 0;
СчетчикМесяцев = 0;
НомерКвартала = 1;
Для Каждого СтрокаТЧ Из ТаблицаДолей Цикл
ТекущаяСуммаКвартала = ТекущаяСуммаКвартала + СтрокаТЧ.Доля;
СчетчикМесяцев = СчетчикМесяцев + 1;
// Каждые три месяца проверяем итог
Если СчетчикМесяцев = 3 Тогда
// Используем округление для исключения ошибок плавающей точки
Если Окр(ТекущаяСуммаКвартала, 10) <> 1 Тогда
ТекстСообщения = СтрШаблон("Ошибка в %1 квартале: сумма долей равна %2, а должна быть 1!",
НомерКвартала, ТекущаяСуммаКвартала);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , , , Отказ);
КонецЕсли;
// Сбрасываем счетчики для следующего квартала
ТекущаяСуммаКвартала = 0;
СчетчикМесяцев = 0;
НомерКвартала = НомерКвартала + 1;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем ситуацию, когда строки могут располагаться в произвольном порядке. В этом случае полагаться на простой счетчик нельзя. Выясним причину возможной ошибки: если пользователь отсортировал таблицу по значению доли, а не по времени, предыдущий алгоритм выдаст неверный результат. Чтобы этого избежать, используем математическое определение квартала по номеру месяца.
Для определения номера квартала воспользуемся формулой: (НомерМесяца - 1) / 3 + 1. Посмотрим, как применить это в коде:
// Создадим таблицу для накопления итогов по кварталам
КвартальныеИтоги = Новый Соответствие;
КвартальныеИтоги.Вставить(1, 0); // 1 квартал
КвартальныеИтоги.Вставить(2, 0); // 2 квартал
КвартальныеИтоги.Вставить(3, 0); // 3 квартал
КвартальныеИтоги.Вставить(4, 0); // 4 квартал
Для Каждого Строка Из ТаблицаДолей Цикл
НомерМесяца = Строка.НомерМесяца; // Предположим, у нас есть колонка с номером месяца
НомерКвартала = Цел((НомерМесяца - 1) / 3) + 1;
ТекущийИтог = КвартальныеИтоги.Получить(НомерКвартала);
КвартальныеИтоги.Вставить(НомерКвартала, ТекущийИтог + Строка.Доля);
КонецЦикла;
// Теперь проверяем результаты в соответствии
Для Кв = 1 По 4 Цикл
Если Окр(КвартальныеИтоги.Получить(Кв), 10) <> 1 Тогда
// Вывод ошибки пользователю
КонецЕсли;
КонецЦикла;
Рассмотрим ситуацию с точки зрения пользователя. Блокировка записи — это эффективная, но иногда раздражающая мера. Проанализируем, как можно подсветить ошибку еще в процессе ввода данных. Для этого в управляемых формах 1С предусмотрен механизм Условного оформления.
Мы можем настроить оформление программно или в конфигураторе так, чтобы при отклонении суммы от единицы ячейки окрашивались в красный цвет. Однако, поскольку условное оформление плохо работает с агрегатными функциями по группам строк в реальном времени, рекомендуется добавить в форму вспомогательные надписи (декорации), которые будут обновляться в событии ПриИзменении колонок табличной части.
Пошаговая инструкция для улучшения UX:
ПриИзменении для колонки Доля.Выясним важный технический нюанс: работа с типом Число в 1С при делении может приводить к появлению бесконечных дробей (например, 1/3). Если пользователь вводит 0.333, 0.333 и 0.334, сумма будет равна 1. Но если логика программы предполагает автоматическое распределение, прямое сравнение Сумма = 1 может вернуть Ложь из-за разницы в 15-м знаке после запятой.
Всегда используйте функцию Окр() при сравнении накопленных долей. Обычно достаточно точности до 10 знаков: Окр(Сумма, 10) = 1.
Чтобы минимизировать ошибки, разберем возможность автоматического заполнения. Например, если пользователь заполнил первый и второй месяцы квартала, система может автоматически рассчитать значение для третьего месяца по формуле 1 - Доля1 - Доля2. Это реализуется в обработчике ПриИзменении. Такой подход избавляет человека от необходимости вручную вычислять остатки и подгонять цифры под единицу.
Внедрение подобных проверок и механизмов помощи делает интерфейс системы 1С:Предприятие профессиональным и защищенным от человеческого фактора.