Как настроить проверку, чтобы при проведении документа был выбран ровно один из двух флажков?

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

В разработке на платформе 1С часто возникает задача: ограничить выбор пользователя в документе. Классический пример — на форме есть два флажка, и при проведении документа должен быть установлен ровно один из них. Не ноль и не оба. Эта, на первый взгляд, простая задача может стать источником трудностей для начинающего разработчика, так как она затрагивает фундаментальные различия между данными формы и данными объекта.

Давайте вместе разберемся, почему стандартная проверка может не работать, в чем заключается основная ошибка, и какие существуют правильные и элегантные способы решения этой задачи.

Выясняем причину: почему проверка не работает? Реквизиты формы vs. Реквизиты объекта

Самая распространенная ошибка, из-за которой не срабатывает серверная проверка, — это работа с реквизитами формы вместо реквизитов объекта.

Проанализируем ситуацию. Разработчик программно создает на форме два флажка. Код может выглядеть примерно так:


НовыйРеквизитФормы1 = Новый РеквизитФормы("КапитальныеЗатраты", Новый ОписаниеТипов("Булево"));
// ...добавление в массив реквизитов формы...
ИзменитьРеквизиты(ДобавляемыеРеквизиты);

НовыйЭлементФормы = Элементы.Добавить("КапитальныеЗатраты", Тип("ПолеФормы"), ...);
НовыйЭлементФормы.Вид = ВидПоляФормы.ПолеФлажка;
НовыйЭлементФормы.ПутьКДанным = "КапитальныеЗатраты"; // <-- Ключевая ошибка здесь

После этого он пишет код проверки в модуле объекта документа, в обработчике события ОбработкаПроверкиЗаполнения, но проверка не работает, и документ спокойно проводится без установленных флажков. В чем же дело?

Разберем ключевые отличия:

Процедура ОбработкаПроверкиЗаполнения выполняется в модуле объекта на сервере, непосредственно перед записью данных в базу. Этот обработчик работает исключительно с реквизитами объекта и ничего не знает о временных реквизитах формы. Соответственно, любая проверка, обращенная к несуществующим в объекте реквизитам, не даст нужного результата.

Правильный подход:

  1. Сначала создайте два реквизита с типом Булево («КапитальныеЗатраты» и «ОперационныеРасходы») непосредственно в самом объекте документа в конфигураторе.
  2. При создании элементов на форме (программно или интерактивно) правильно указывайте путь к данным. Он должен вести к реквизиту объекта через свойство Объект.

Правильная привязка данных выглядит так:

НовыйЭлементФормы.ПутьКДанным = "Объект.КапитальныеЗатраты";

Только после этого серверные проверки в модуле объекта начнут корректно работать с данными, которые ввел пользователь.

Решение 1: Проверка двух булевых реквизитов в модуле объекта

Итак, мы создали реквизиты в самом документе и правильно связали их с элементами формы. Теперь можно приступать к написанию кода проверки. Наиболее подходящее место для этого — процедура ОбработкаПроверкиЗаполнения в модуле объекта документа.

Подход А: Логическое сравнение

Логика этого подхода проста. Если нам нужно, чтобы был выбран ровно один флажок, это означает, что их значения не должны быть одинаковыми. Рассмотрим все варианты:

Таким образом, нам нужно заблокировать проведение, если значения флажков равны. Код будет выглядеть следующим образом:


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

КонецПроцедуры

Важный момент: если вы используете ВызватьИсключение "Текст ошибки", то строка Отказ = Истина; становится избыточной, так как исключение прерывает выполнение кода и откатывает транзакцию.

Подход Б: Арифметический трюк

Этот способ основан на том, что платформа 1С при арифметических операциях неявно преобразует тип Булево в Число, где Истина становится 1, а Ложь — 0. Если нам нужно, чтобы был установлен ровно один флажок, значит, сумма их числовых представлений должна быть равна 1.

Код с использованием этого метода очень лаконичен:


// В модуле объекта документа
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    Если Цел(КапитальныеЗатраты) + Цел(ОперационныеРасходы) <> 1 Тогда
        ТекстСообщения = "Необходимо выбрать ровно один вид расходов: капитальные или операционные.";
        ОбщегоНазначения.СообщитьПользователю(ТекстСообщения, ЭтотОбъект,,, Отказ);
    КонецЕсли;

КонецПроцедуры

Примечание: Использование функции Цел() делает код более явным и понятным для других разработчиков, хотя платформа справилась бы и без нее.

Упрощенная проверка (если интерфейс уже содержит ограничения)

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


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

Однако полагаться только на интерфейсные ограничения рискованно, так как документ может быть создан или изменен программно, в обход логики формы. Поэтому полная проверка, как в подходах А и Б, является более надежной.

Решение 2 (рекомендуемое): Использование Перечисления

Хотя варианты с двумя флажками работают, с точки зрения архитектуры системы они не являются оптимальными. Когда у нас есть несколько взаимоисключающих вариантов, правильнее использовать Перечисление. Этот подход делает систему более гибкой, масштабируемой и понятной.

Разберем реализацию по шагам:

  1. Создаем перечисление. В дереве конфигурации создайте новый объект Перечисление, назовите его, например, ВидыРасходов. Добавьте в него два значения: КапитальныеЗатраты и ОперационныеРасходы.
  2. Создаем один реквизит в документе. Удалите два булевых реквизита. Вместо них создайте один реквизит, например, ВидРасхода, и укажите для него тип ПеречислениеСсылка.ВидыРасходов.
  3. Настраиваем форму. На форме документа разместите поле для нового реквизита Объект.ВидРасхода. В свойствах элемента формы установите свойство Вид в значение Поле переключателя. Платформа автоматически создаст на форме удобные для пользователя радио-кнопки, которые физически не позволят выбрать более одного значения.
  4. Упрощаем проверку. Теперь задача проверки сводится к тривиальной проверке на заполненность одного реквизита.

Код проверки в модуле объекта становится максимально простым и читаемым:


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

КонецПроцедуры

Преимущества использования перечисления:

Таким образом, для решения задачи выбора одного из нескольких вариантов всегда отдавайте предпочтение перечислениям. Это не только решает текущую проблему, но и закладывает правильную архитектуру для будущего развития вашей конфигурации.

← На главную