В процессе кастомизации типовых решений, таких как 1С:Управление нашей фирмой (УНФ), программисты часто сталкиваются с необходимостью изменить логику работы стандартных форм. Типичный пример — ограничение подбора товаров в корзину. Например, когда в компании ведется учет по характеристикам, важно запретить пользователю добавлять в документ «пустую» номенклатуру, заставляя его выбирать конкретную характеристику (цвет, размер и т.д.).
Разберем ситуацию: при клике на иконку корзины в дереве остатков товар все равно добавляется, даже если поле Характеристика визуально пустое. Проанализируем, почему стандартные проверки могут не срабатывать, и как написать надежный код для решения этой задачи.
Проанализируем фрагмент кода, который часто пишут новички: Если ТекущиеДанные.Характеристика = Неопределено Тогда Возврат; КонецЕсли;. На первый взгляд, логика верна, но в контексте 1С:Предприятие 8 она ошибочна для ссылочных типов данных.
Выясним причину. В системе 1С ссылочные данные (справочники, документы) практически никогда не принимают значение Неопределено. Если поле в базе данных не заполнено, оно содержит так называемую пустую ссылку. Пустая ссылка — это объект определенного типа, у которого уникальный идентификатор (GUID) состоит из одних нулей. С точки зрения встроенного языка, ПустаяСсылка не равна Неопределено. Именно поэтому условие не срабатывает, и программа продолжает выполнение кода, добавляя товар в корзину.
Рассмотрим самый современный и рекомендуемый стандарт разработки — использование встроенной функции платформы ЗначениеЗаполнено(). Это наиболее универсальный метод, так как он корректно обрабатывает пустые ссылки любого типа, пустые строки, нулевые числа и даже Неопределено.
Перепишем наш фрагмент кода с использованием этой функции:
Если Поле.Имя = "ДеревоОстаткиКартинкаКорзина" Тогда
// Проверяем, заполнена ли характеристика в текущей строке
Если Не ЗначениеЗаполнено(ТекущиеДанные.Характеристика) Тогда
// Если не заполнена, просто выходим из процедуры, не добавляя в корзину
Возврат;
КонецЕсли;
// Далее идет стандартная проверка на доступность и партии
Если ТекущиеДанные.ПартияДляИсключения Или ТекущиеДанные.Недоступен Тогда
// Формирование и вывод сообщения пользователю
// ... (ваш код обработки ошибок)
Возврат
КонецЕсли;
ДобавитьВКорзинуСписок(Истина);
Возврат;
КонецЕсли;
Преимущество этого метода: он безопасен. Даже если в будущем состав данных в ТекущиеДанные изменится (например, вместо ссылки придет строка), функция ЗначениеЗаполнено() отработает без ошибок.
Если мы точно знаем, что в реквизите Характеристика всегда находится ссылка конкретного справочника, мы можем использовать метод Пустая(). Посмотрим, как это выглядит на практике:
Если ТекущиеДанные.Характеристика.Пустая() Тогда
Возврат;
КонецЕсли;
Однако здесь есть важный нюанс. Рассмотрим ситуацию: если поле Характеристика имеет составной тип данных или по какой-то причине содержит значение Неопределено, вызов метода через точку .Пустая() приведет к фатальной ошибке и аварийному завершению работы программы. Поэтому данный метод стоит использовать только тогда, когда вы абсолютно уверены в типизации данных.
Проанализируем еще один строгий вариант проверки, который часто встречается в системном коде типовых конфигураций. Мы можем напрямую сравнить значение с эталонной пустой ссылкой конкретного справочника.
Если ТекущиеДанные.Характеристика = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка() Тогда
Возврат;
КонецЕсли;
Этот способ работает быстро, но он «жестко» привязан к конкретному метаданному. Если в вашей форме подбора могут быть характеристики разных видов или другие объекты, этот код придется усложнять.
Посмотрим на специфику программы Управление нашей фирмой. Форма подбора здесь довольно сложная и часто строится на иерархическом дереве значений. Важно учитывать, что в некоторых строках характеристика может быть пустой не потому, что она не выбрана, а потому, что для данной номенклатуры учет по характеристикам не ведется в принципе.
Чтобы сделать код более профессиональным, добавим проверку настройки самой номенклатуры. Проанализируем следующий алгоритм:
Пример реализации такой логики:
Если Поле.Имя = "ДеревоОстаткиКартинкаКорзина" Тогда
// Получаем признак использования характеристик из данных строки
ИспользоватьХарактеристики = Ложь;
Если ТекущиеДанные.Свойство("ИспользоватьХарактеристики") Тогда
ИспользоватьХарактеристики = ТекущиеДанные.ИспользоватьХарактеристики;
КонецЕсли;
// Если характеристики нужны, но не заполнены - блокируем подбор
Если ИспользоватьХарактеристики И Не ЗначениеЗаполнено(ТекущиеДанные.Характеристика) Тогда
ОбщегоНазначенияКлиент.СообщитьПользователю("Для данного товара необходимо выбрать характеристику!");
Возврат;
КонецЕсли;
// Продолжаем стандартную логику подбора
ДобавитьВКорзинуСписок(Истина);
КонецЕсли;
В некоторых обсуждениях можно встретить совет использовать ПустаяСтрока(ТекущиеДанные.Характеристика). Разберем, почему это работает и стоит ли так делать. Платформа 1С при передаче ссылки в функцию, ожидающую строку, выполняет неявное приведение типов. Ссылка преобразуется в свое текстовое представление. У пустой ссылки текстовое представление — это пустая строка "".
Важный момент: использование этого метода считается «плохим тоном» (bad practice) в современной разработке на платформе 8.3. Это снижает производительность (затраты на преобразование типов) и может привести к логическим ошибкам, если объект имеет наименование, состоящее из пробелов. Всегда отдавайте предпочтение ЗначениеЗаполнено().
Таким образом, мы разобрали основные способы проверки данных на пустоту в 1С:УНФ. Наилучшим решением для формы подбора будет использование ЗначениеЗаполнено() в сочетании с анализом контекста (используются ли характеристики для конкретной позиции номенклатуры).