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

· 9 мин

Содержание

Проверить, заполнено ли поле, в 1С 8.3 чаще всего нужно одной строкой: ЗначениеЗаполнено(Реквизит). Функция вернёт Ложь, если значение пустое для своего типа — пустая строка, ноль, пустая дата, пустая ссылка или Неопределено. Это самый быстрый способ и для одного реквизита, и для условия внутри обработчика.

Частая ошибка — думать, что для обязательных реквизитов проверку надо писать руками. Для реквизитов, выведенных на форму, достаточно свойства Проверка заполнения = Выдавать ошибку, и платформа сама не даст записать объект с пустым полем. Код нужен там, где условие сложнее: поле обязательно только при определённом виде операции, зависит от другого реквизита или проверяется у тысяч записей сразу.

Что именно нужно проверить?

Функция ЗначениеЗаполнено — базовый инструмент

ЗначениеЗаполнено() — глобальная функция встроенного языка. Она сравнивает значение с «пустым» значением по умолчанию для его типа и возвращает Булево.

Если НЕ ЗначениеЗаполнено(Объект.Контрагент) Тогда
    Сообщить("Не выбран контрагент");
КонецЕсли;

Что функция считает незаполненным:

  • 🔢 число 0;
  • 📝 пустую строку "";
  • 📅 пустую дату ('00010101000000');
  • 🔗 пустую ссылку любого справочника, документа или перечисления;
  • ❓ Неопределено и NULL.

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

Зеркальный вариант — просто поставить НЕ перед вызовом. Отдельной функции «НеЗаполнено» в платформе нет.

Автоматическая проверка в управляемой форме

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

После этого при нажатии Записать и закрыть платформа сама вызывает проверку: незаполненное поле подсветится красным, а в окне сообщений появится текст «Поле <имя> не заполнено». Запись не пройдёт, пока поле пустое.

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

Если НЕ Объект.ПроверитьЗаполнение() Тогда
    Возврат; // проверка не пройдена, сообщения уже выданы
КонецЕсли;

Метод ПроверитьЗаполнение() вернёт Ложь и сам выведет сообщения по всем реквизитам, у которых включена проверка. У управляемой формы есть одноимённый метод — он проверяет реквизиты самой формы.

Чтобы добавить своё условие сверх стандартного, в модуле объекта реализуйте обработчик ОбработкаПроверкиЗаполнения:

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

Свойство Поле и метод УстановитьДанные связывают сообщение с конкретным реквизитом: пользователь кликнет по тексту и попадёт прямо в нужную ячейку, а поле подсветится.

Если установить Отказ = Истина, объект не запишется. Это и есть способ запретить запись при невыполненном условии, не трогая свойство реквизита.

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

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    Если Бессрочный Тогда
        Индекс = ПроверяемыеРеквизиты.Найти("ДатаОкончания");
        Если Индекс <> Неопределено Тогда
            ПроверяемыеРеквизиты.Удалить(Индекс);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

Проверка в обычных формах и старых конфигурациях

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

Разница только в отображении. Красная пометка незаполненного поля — это поведение управляемой формы. В обычной форме результат проверки вы показываете сами через объект Сообщение (в старых версиях — глобальную процедуру вывода сообщений) и привязываете текст к элементу формы.

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

Поиск незаполненных полей запросом к базе

Когда нужно проверить не один объект в форме, а найти все записи с пустым полем, перебирать объекты в цикле нельзя — это долго. Задачу решает один запрос.

Для ссылочного реквизита сравнивайте с пустой ссылкой через функцию ЗНАЧЕНИЕ:

ВЫБРАТЬ
    Контрагенты.Ссылка КАК Контрагент
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ГДЕ
    Контрагенты.ОсновнойМенеджер = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)

Для строки проверяйте равенство пустой строке, для числа — нулю:

ГДЕ
    Контрагенты.ИНН = ""
    ИЛИ Контрагенты.КПП = ""

Пустую дату в запросе сравнивают с «началом времён» — функцией ДАТАВРЕМЯ:

ГДЕ
    Договоры.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1)

Если поле приходит из левого соединения и может отсутствовать физически, проверяйте на NULL отдельно — пустая ссылка и NULL в запросе не одно и то же:

ГДЕ
    СоединённаяТаблица.Поле ЕСТЬ NULL

Для реквизита составного типа ссылку на пустое значение так просто не задать: у каждого типа своя пустая ссылка. В таком случае удобнее проверить представление или вынести реквизит во встроенный язык и применить ЗначениеЗаполнено уже к полученному значению.

Функции ЗначениеЗаполнено в языке запросов нет — она работает только во встроенном языке. В запросе условие пустоты пишут явно под каждый тип поля.

Проверка при вводе и перед записью

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

&НаКлиенте
Процедура ВидДоговораПриИзменении(Элемент)
    Если Объект.ВидДоговора = ПредопределённоеЗначение("Перечисление.ВидыДоговоров.Срочный")
        И НЕ ЗначениеЗаполнено(Объект.ДатаОкончания) Тогда
        Элементы.ДатаОкончания.ПометкаНезаполненного = Истина;
    КонецЕсли;
КонецПроцедуры

Свойство элемента ПометкаНезаполненного включает ту же красную рамку, что и стандартная проверка, но управляете ею вы.

Финальный барьер перед сохранением — обработчик ПередЗаписью. В модуле объекта он срабатывает при любой записи, в том числе программной, когда форма не открыта:

Процедура ПередЗаписью(Отказ)
    Если Проведён И НЕ ЗначениеЗаполнено(Ответственный) Тогда
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

Разделяйте зоны ответственности: ОбработкаПроверкиЗаполнения — для сообщений пользователю в интерактивном режиме, ПередЗаписью объекта — для гарантии, что ни один путь записи не создаст объект с пустым критичным полем.

Сложные условия: формат, зависимость и группы полей

ЗначениеЗаполнено отвечает только на вопрос «пусто или нет». Когда поле заполнено, но нужно проверить корректность, добавляйте свои условия.

Проверка длины и состава строки — через строковые функции. Например, ИНН юрлица должен состоять из 10 цифр:

Функция ИННКорректен(ИНН)
    Если СтрДлина(ИНН) <> 10 И СтрДлина(ИНН) <> 12 Тогда
        Возврат Ложь;
    КонецЕсли;
    Для Позиция = 1 По СтрДлина(ИНН) Цикл
        Символ = Сред(ИНН, Позиция, 1);
        Если НЕ (Символ >= "0" И Символ <= "9") Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;
    Возврат Истина;
КонецФункции

Проверка «заполнено хотя бы одно из полей» — через накопление флага:

Если НЕ ЗначениеЗаполнено(Телефон) И НЕ ЗначениеЗаполнено(Электронная_Почта) Тогда
    Сообщить("Укажите телефон или e-mail");
КонецЕсли;

Проверка табличной части — обойдите строки и проверьте обязательные колонки:

Для Каждого Строка Из Объект.Товары Цикл
    Если НЕ ЗначениеЗаполнено(Строка.Номенклатура) Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Не заполнена номенклатура в строке " + Строка.НомерСтроки;
        Сообщение.Поле = "Объект.Товары[" + (Строка.НомерСтроки - 1) + "].Номенклатура";
        Сообщение.УстановитьДанные(ЭтотОбъект);
        Сообщение.Сообщить();
    КонецЕсли;
КонецЦикла;

Индекс в пути Товары[...] начинается с нуля, а НомерСтроки — с единицы. Поэтому в пути к данным вычитаем единицу, иначе сообщение привяжется к соседней строке.

Массовая проверка: как не положить базу

Отдельная задача — проверить заполнение у большого количества записей, например при обработке данных перед обменом. Главное правило: не читайте каждый объект в память ради одного поля.

  • ❌ Медленно: получить выборку всех ссылок, в цикле вызывать Ссылка.ПолучитьОбъект() и проверять реквизит. На десятках тысяч записей это чтение полного объекта на каждой итерации.
  • ✅ Быстро: одним запросом выбрать только те записи, где поле пустое (условие в ГДЕ), и работать уже с коротким результатом.

Если по итогам проверки нужно что-то записать, оборачивайте изменения порциями и не держите открытую транзакцию на весь объём. Для фоновой проверки используйте регламентное задание, а не ручной запуск в сеансе пользователя.

Отдельно о выборке данных. Если из полного объекта вам нужны всего два-три реквизита, не читайте объект целиком — запросите именно эти поля. Разница заметна уже на тысячах строк: запрос поднимает из СУБД только нужные колонки, а ПолучитьОбъект разворачивает весь объект со всеми табличными частями.

Сравнение подходов:

СпособКогда применятьРиск
ЗначениеЗаполнено в цикле по объектамединичные записи, формачтение объектов целиком тормозит на больших выборках
Запрос с условием пустотыпоиск по всей базепочти нет, нагрузка на СУБД предсказуема
Регламентное задание с запросомрегулярная массовая проверкаследить за временем выполнения и блокировками

Типичные ошибки при проверке заполнения

Проверьте себя
Чему равно ЗначениеЗаполнено(Ложь) для реквизита типа Булево?
ЗначениеЗаполнено(" ") для строки из одних пробелов вернёт:

Две ловушки из викторины выше разбираем подробнее — на них спотыкаются чаще всего.

Булево. Для типа Булево пустое значение — это Ложь. Поэтому ЗначениеЗаполнено(Ложь) вернёт Ложь, и флажок, который пользователь осознанно снял, проверка сочтёт незаполненным. Для булевых реквизитов проверяйте не «заполненность», а конкретное значение: Если Согласие Тогда.

Пробелы. Функция не обрезает строку. Поле из одних пробелов она считает заполненным. Если пробелы недопустимы, сначала примените СокрЛП:

Если НЕ ЗначениеЗаполнено(СокрЛП(Комментарий)) Тогда
    Сообщить("Комментарий фактически пуст");
КонецЕсли;

Ещё несколько промахов:

  • ✂️ проверка только в форме, без обработчика ПередЗаписью объекта — программная запись проходит мимо контроля;
  • 🔁 дублирование условия и в свойстве реквизита, и в коде — одно и то же поле выдаёт две ошибки;
  • 🧮 сравнение числа с пустой строкой (Сумма = "") в запросе — типы не совпадают, условие не отработает; для числа сравнивайте с нулём;
  • 🐢 вызов ПроверитьЗаполнение для каждого объекта в длинном цикле — метод тяжёлый, он прогоняет все реквизиты; для массовой проверки достаточно запроса по нужному полю.

Полезно помнить и про обратную сторону: ссылка на помеченный на удаление объект для ЗначениеЗаполнено остаётся заполненной. Функция проверяет только наличие значения, а не его актуальность. Если важно, чтобы объект был «живым», проверяйте пометку удаления отдельным условием.

Частые вопросы

Чем ЗначениеЗаполнено отличается от проверки на Неопределено?
Неопределено — это один конкретный тип. ЗначениеЗаполнено шире: ловит и Неопределено, и NULL, и пустую ссылку, и ноль, и пустую строку. Сравнение = Неопределено для пустой ссылки вернёт Ложь, то есть не сработает.
Как сделать поле обязательным без единой строки кода?
В конфигураторе задайте реквизиту свойство Проверка заполнения → Выдавать ошибку. Поле выведено на форму — платформа сама проверит его при записи.
Почему проверка в форме срабатывает, а при загрузке данных обработкой — нет?
Автоматическая проверка привязана к интерактивной записи через форму. Программная запись объекта её не вызывает. Вставьте условие в обработчик ПередЗаписью модуля объекта — он отрабатывает при любой записи.
Можно ли проверить заполнение в языке запросов?
Функции ЗначениеЗаполнено в запросе нет. Пишите условие явно: пустая строка = "", пустая ссылка = ЗНАЧЕНИЕ(...ПустаяСсылка), отсутствие значения ЕСТЬ NULL.
Как привязать текст ошибки к конкретному полю на форме?
Через объект СообщениеПользователю: задайте свойство Поле (путь к реквизиту) и вызовите УстановитьДанные. Пользователь кликнет по сообщению и перейдёт в нужную ячейку.