Как обратиться через форму документа к реквизиту справочника и проверить его данные

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

В процессе разработки в среде 1С:Предприятие 8.3 часто возникает задача проверки данных связанных объектов. Например, при заполнении документа «Реализация товаров и услуг» необходимо убедиться, что в поле Контрагент выбрано физическое лицо, и его наименование не содержит цифр (номеров лицевых счетов). На первый взгляд задача кажется простой, но начинающие разработчики часто сталкиваются с ошибками доступа к данным из-за непонимания клиент-серверной архитектуры и контекста формы. Рассмотрим подробно, как правильно реализовать такую проверку.

Разберем типичные ошибки контекста

Проанализируем ситуацию, когда разработчик пытается использовать директиву &НаСервереБезКонтекста. Основная проблема здесь заключается в том, что внутри такой функции сервер «не видит» форму. Попытка обратиться к Объект.Контрагент или любой другой переменной формы приведет к ошибке «Переменная не определена».

Важно помнить: при использовании &НаСервереБезКонтекста на сервер не передаются данные формы (реквизит Объект и другие элементы). Это делается для ускорения работы программы, так как объем передаваемых данных между клиентом и сервером минимизируется. Однако в этом случае все необходимые данные для проверки нужно передавать в функцию в качестве параметров.

Работа с метаданными и значениями: в чем разница?

Еще одна распространенная ошибка — путаница между данными (конкретными значениями в базе) и метаданными (описанием структуры конфигурации). Рассмотрим пример неправильного кода:


// ОШИБОЧНЫЙ КОД
КонтрагентыФЛ = Метаданные.Справочники.Контрагенты.Реквизиты.ЮридическоеФизическоеЛицо;
Если КонтрагентыФЛ = Метаданные.Перечисления.ЮридическоеФизическоеЛицо.ЗначенияПеречисления.ФизическоеЛицо Тогда
    // Это условие никогда не выполнится правильно для сравнения значений данных
КонецЕсли;

В данном примере Метаданные возвращают описание объекта, а не само значение перечисления, которое хранится у конкретного контрагента. Для сравнения значений данных в коде следует использовать ссылки на объекты базы данных или функцию ПредопределенноеЗначение().

Правильный способ обращения к реквизитам через ссылку

Выясним, как правильно получить значение реквизита справочника Контрагенты, находясь в форме документа. На клиенте мы имеем только Ссылку на контрагента. Чтобы узнать, является ли он физическим лицом, нам нужно «заглянуть» внутрь этого объекта в базе данных.

Рассмотрим реализацию через контекстную серверную процедуру (где доступен Объект):


&НаСервере
Функция ПроверитьКонтрагентаНаСервере()
    
    // Получаем ссылку на контрагента из данных формы
    КонтрагентСсылка = Объект.Контрагент;
    
    // Проверяем, заполнена ли ссылка
    Если КонтрагентСсылка.Пустая() Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Обращаемся к реквизиту через точку (допустимо на сервере)
    // Внимание: это приведет к неявному получению всего объекта из БД
    Если КонтрагентСсылка.ЮридическоеФизическоеЛицо = Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо Тогда
        
        // Проверяем наименование на наличие цифр
        Наименование = КонтрагентСсылка.Наименование;
        Возврат СодержитЦифры(Наименование);
        
    КонецЕсли;
    
    Возврат Ложь;
    
КонецФункции

Оптимизация: Использование БСП и бесконтекстных вызовов

Проанализируем более профессиональный подход. В конфигурациях на базе БСП (Библиотека стандартных подсистем), таких как «Бухгалтерия предприятия 3.0», рекомендуется использовать функции общего модуля ОбщегоНазначения. Это позволяет избежать лишней нагрузки на сервер при получении только одного-двух реквизитов.

Посмотрим на пример кода с использованием &НаСервереБезКонтекста:


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

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

Реализация алгоритма проверки строки на цифры

Теперь разберем, как именно проверить наличие цифр в наименовании. Мы можем воспользоваться стандартными функциями работы со строками или написать простой цикл перебора символов. Рассмотрим вариант с использованием функции СтрНайти.


&НаСервереБезКонтекста
Функция СтрокаСодержитЦифры(Знач ТестируемаяСтрока)
    
    Цифры = "0123456789";
    
    Для Индекс = 1 По СтрДлина(ТестируемаяСтрока) Цикл
        Символ = Сред(ТестируемаяСтрока, Индекс, 1);
        Если СтрНайти(Цифры, Символ) > 0 Тогда
            Возврат Истина; // Цифра найдена
        КонецЕсли;
    КонецЦикла;
    
    Возврат Ложь;
    
КонецФункции

Подведем итоги работы

Для успешного решения задачи мы выполнили следующие шаги:

  1. Определили правильную точку вызова: проверку лучше всего размещать в обработчике ПередЗаписью формы документа или в событии ПриИзменении поля «Контрагент».
  2. Разграничили контекст: на клиенте мы получаем ссылку, а на сервере (желательно без контекста формы) считываем значения реквизитов этой ссылки.
  3. Использовали правильные типы данных: для проверки типа лица мы сравнивали значение реквизита с ПредопределенноеЗначение("Перечисление.ЮридическоеФизическоеЛицо.ФизическоеЛицо").
  4. Реализовали эффективный запрос: вместо получения всего объекта через КонтрагентСсылка.ПолучитьОбъект(), мы использовали чтение конкретных полей через ОбщегоНазначения.ЗначенияРеквизитовОбъекта.

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

← На главную