Проверка заполнения реквизитов и полей в 1С 8.3: от функции до запроса
Содержание
Проверить, заполнено ли поле, в 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.Как привязать текст ошибки к конкретному полю на форме?
СообщениеПользователю: задайте свойство Поле (путь к реквизиту) и вызовите УстановитьДанные. Пользователь кликнет по сообщению и перейдёт в нужную ячейку.