При разработке информационных систем на платформе 1С:Предприятие 8 часто возникает необходимость контролировать полноту и корректность вводимых пользователем данных. В частности, проверка заполнения полей в таблицах является одной из базовых и критически важных задач. Если оставить какие-либо ячейки незаполненными там, где это недопустимо, это может привести к ошибкам в учете, некорректным расчетам или невозможности дальнейшей обработки данных. Вместе мы разберем, как эффективно прописать код для проверки заполнения полей в различных типах таблиц 1С и обеспечить пользователя понятными сообщениями об обнаруженных недочетах.
Для начала, давайте проанализируем саму суть вопроса: что мы понимаем под «таблицей» в контексте 1С и как к ней получить доступ для проверки.
В платформе 1С:Предприятие существует несколько видов объектов, которые мы можем назвать «таблицами». От того, с каким типом мы работаем, зависит и подход к проверке заполнения. Рассмотрим три основных типа, с которыми мы можем столкнуться:
Табличная часть документа или справочника (ТабличнаяЧасть)
Это, пожалуй, наиболее распространенный тип «таблиц», с которым работают разработчики 1С. Табличная часть представляет собой список однородных данных, являющихся частью какого-либо объекта конфигурации (например, список товаров в документе «Реализация товаров и услуг» или список сотрудников в справочнике «Организации»). Реквизиты такой таблицы жестко заданы в метаданных конфигурации, и к ним можно обращаться напрямую по имени.
Таблица значений (ТаблицаЗначений)
ТаблицаЗначений – это программный объект, существующий исключительно в оперативной памяти программы. Она не является частью метаданных конфигурации и создается непосредственно в коде для временного хранения и обработки данных. Это может быть результат какого-либо запроса, временный набор данных для формирования отчета или промежуточное хранилище информации, введенной пользователем на форме.
Табличный документ (ТабличныйДокумент)
ТабличныйДокумент – это объект для формирования печатных форм, отчетов и интерактивных таблиц. Его ячейки заполняются, как правило, программно, и основной целью его использования является вывод информации, а не ввод данных, требующих строгой валидации. Проверка заполнения отдельных ячеек в ТабличномДокументе менее распространена, но возможна, если, например, пользователь может интерактивно редактировать его и нам нужно проверить внесенные им изменения.
Поскольку вопрос автора подразумевает, что «таблицу нужно создать программно и при создании необходимо прописать код, который будет проверять наличие данных в соответствующих ячейках», мы будем уделять особое внимание программным методам проверки, которые применимы к ТабличнойЧасти и ТаблицеЗначений.
ЗначениеЗаполнено()Независимо от типа таблицы, общий подход к проверке заполнения всегда один и тот же, как и было предложено на форуме: мы обходим в цикле строки нашей таблицы и для каждого поля (колонки) проверяем, заполнено ли оно. Главным инструментом для такой проверки является встроенная функция 1С:Предприятия — ЗначениеЗаполнено().
Функция ЗначениеЗаполнено()
Эта функция является краеугольным камнем для проверки заполнения большинства типов данных в 1С. Она возвращает Истина, если переменная или поле содержит непустое значение, характерное для своего типа, и Ложь в противном случае. Давайте рассмотрим ее поведение подробнее:
Для строковых значений: Функция вернет Истина, если строка содержит хотя бы один непробельный символ. Если строка пуста ("") или состоит только из пробелов (" "), то ЗначениеЗаполнено() вернет Ложь.
Для ссылочных типов (например, СправочникСсылка, ДокументСсылка): Функция вернет Истина, если ссылка указывает на существующий объект и не является пустой ссылкой (например, Справочники.Номенклатура.ПустаяСсылка()). Если ссылка пустая, то вернет Ложь.
Для числовых значений, булевых и дат: Здесь есть важный нюанс. ЗначениеЗаполнено() для этих типов всегда возвращает Истина, если значение задано. Это означает, что:
0 (ноль) функция вернет Истина;Ложь функция вернет Истина;'00010101000000') функция вернет Истина.Если нам требуется проверить, что число не равно нулю или булево значение равно Истина, то мы должны использовать прямое сравнение, а не ЗначениеЗаполнено() (например, Если МоеЧисло = 0 Тогда... или Если Не МоеБулево Тогда...).
Для коллекций (например, массивы, списки значений): Функция возвращает Истина, если коллекция содержит хотя бы один элемент.
Итак, зная о поведении ЗначениеЗаполнено(), мы можем приступить к конкретным примерам кода для каждого типа таблиц.
Для табличных частей объектов конфигурации у нас есть два основных подхода к проверке заполнения: автоматическая проверка через конфигуратор и программная проверка в модуле объекта. Обычно эти подходы дополняют друг друга.
Этот метод позволяет настроить простейшую проверку обязательности заполнения реквизитов табличной части без написания кода. Платформа сама позаботится о выводе сообщения, если поле будет пустым.
Откройте конфигуратор: Запустите 1С:Предприятие в режиме конфигуратора.
Перейдите к нужному объекту: В дереве конфигурации найдите интересующий вас документ или справочник, который содержит табличную часть.
Выберите табличную часть: В ветке объекта разверните "Табличные части" и выберите ту, которую нужно проверить (например, "Товары").
Настройте реквизиты: В списке реквизитов табличной части выделите тот, который должен быть обязательно заполнен (например, "Номенклатура", "Количество").
Установите свойство "Проверка заполнения": В палитре свойств для выбранного реквизита найдите свойство "Проверка заполнения" и установите его в значение "Выдавать ошибку".
После сохранения конфигурации и обновления базы данных, при попытке записи документа с незаполненным таким реквизитом, платформа автоматически выдаст стандартное сообщение об ошибке, предотвращая запись.
Программная проверка дает нам значительно больше контроля над логикой, текстом сообщений и возможностью комбинировать проверки. Этот метод обычно реализуется в обработчике события ПриЗаписи или ОбработкаПроверкиЗаполнения() модуля объекта (например, документа).
Рассмотрим пример, где мы хотим убедиться, что в табличной части "Товары" поля "Номенклатура" и "Количество" заполнены, а "Количество" также больше нуля. Мы будем использовать обработчик ОбработкаПроверкиЗаполнения(), который является рекомендуемым для таких задач, так как он вызывается платформой автоматически при интерактивном сохранении любой формы или проведении документов.
// В модуле объекта, например, документа "РеализацияТоваровУслуг"
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Инициализируем флаг отказа. Если хотя бы одна проверка не пройдена, установим его в Истина.
// Если Отказ уже установлен (например, в обработчиках подписок), сохраняем его состояние.
Если Отказ Тогда
Возврат;
КонецЕсли;
// Проверяем основную табличную часть "Товары"
Для Каждого СтрокаТЧ Из ЭтотОбъект.Товары Цикл
// Проверка заполнения поля "Номенклатура"
Если НЕ ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) Тогда
// Выводим информативное сообщение пользователю
// НСтр("ru = 'Номенклатура'") позволяет отображать имя поля на текущем языке интерфейса
Сообщить("В строке " + СтрокаТЧ.НомерСтроки + " не заполнено поле '"
+ НСтр("ru = 'Номенклатура'") + "'.", СтатусСообщения.Важное);
Отказ = Истина; // Устанавливаем Отказ = Истина, чтобы предотвратить запись документа
// Мы можем выйти из цикла сразу после первой ошибки или продолжить собирать все ошибки.
// Для примера оставим возможность собрать все ошибки.
КонецЕсли;
// Проверка заполнения поля "Количество"
Если НЕ ЗначениеЗаполнено(СтрокаТЧ.Количество) Тогда
Сообщить("В строке " + СтрокаТЧ.НомерСтроки + " не заполнено поле '"
+ НСтр("ru = 'Количество'") + "'.", СтатусСообщения.Важное);
Отказ = Истина;
ИначеЕсли СтрокаТЧ.Количество <= 0 Тогда
// Дополнительная проверка на числовое значение: количество должно быть больше нуля.
// ЗначениеЗаполнено() для числа 0 вернет Истина, поэтому нужна отдельная проверка.
Сообщить("В строке " + СтрокаТЧ.НомерСтроки + " поле '"
+ НСтр("ru = 'Количество'") + "' должно быть больше нуля.", СтатусСообщения.Важное);
Отказ = Истина;
КонецЕсли;
// Можно добавить другие проверки для полей этой строки
// Например, проверка суммы
Если СтрокаТЧ.Количество * СтрокаТЧ.Цена < 0 Тогда
Сообщить("В строке " + СтрокаТЧ.НомерСтроки + " сумма отрицательна.", СтатусСообщения.Важное);
Отказ = Истина;
КонецЕсли;
КонецЦикла;
// Если у документа есть другие табличные части, мы можем проверить их аналогично.
// Например, если есть табличная часть "Услуги"
Для Каждого СтрокаТЧ Из ЭтотОбъект.Услуги Цикл
Если НЕ ЗначениеЗаполнено(СтрокаТЧ.Услуга) Тогда
Сообщить("В строке " + СтрокаТЧ.НомерСтроки + " табличной части '"
+ НСтр("ru = 'Услуги'") + "' не заполнено поле '" + НСтр("ru = 'Услуга'") + "'.", СтатусСообщения.Важное);
Отказ = Истина;
КонецЕсли;
КонецЦикла;
// Мы также можем проверять реквизиты самого объекта (не табличной части)
Если НЕ ЗначениеЗаполнено(ЭтотОбъект.Контрагент) Тогда
Сообщить("Не заполнен основной реквизит '" + НСтр("ru = 'Контрагент'") + "'.", СтатусСообщения.Важное);
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
В этом примере мы видим, как:
Используется цикл Для Каждого СтрокаТЧ Из Объект.НазваниеТабличнойЧасти для обхода всех строк табличной части.
Применяется функция НЕ ЗначениеЗаполнено(СтрокаТЧ.ИмяРеквизита) для проверки конкретного поля.
Выводится информативное сообщение пользователю с указанием номера строки и имени незаполненного поля с помощью функции Сообщить(). Использование НСтр() позволяет корректно отображать сообщения на разных языках, если конфигурация мультиязычная.
Устанавливается параметр Отказ = Истина;, что предотвращает запись или проведение документа, пока ошибки не будут исправлены.
Добавляется дополнительная проверка для числовых полей (СтрокаТЧ.Количество <= 0), поскольку ЗначениеЗаполнено() для нуля вернет Истина.
ТаблицаЗначений является программным объектом, существующим только в памяти, поэтому все проверки для нее будут реализованы исключительно программно. Мы обходим ее строки и колонки аналогично тому, как это делалось для ТабличнойЧасти, используя те же принципы и функцию ЗначениеЗаполнено().
Предположим, у нас есть ТаблицаЗначений с колонками "Колонка1" (строка), "Колонка2" (ссылка) и "ЧисловаяКолонка" (число).
// Пример проверки ТаблицыЗначений
// Функция, которая принимает ТаблицуЗначений и возвращает, успешно ли прошла проверка
Функция ПроверитьТаблицуЗначений(МояТаблицаЗначений)
ПереданнаяТаблицаЗаполнена = Истина; // Флаг для отслеживания результата проверки
// Проверяем, что сама таблица значений не пуста
Если МояТаблицаЗначений.Количество() = 0 Тогда
Сообщить("Таблица значений пуста, нет данных для проверки.", СтатусСообщения.Важное);
Возврат Ложь;
КонецЕсли;
Для Каждого СтрокаТЗ Из МояТаблицаЗначений Цикл
// Получаем индекс текущей строки для более информативного сообщения
Перем НомерСтроки;
Попытка
НомерСтроки = МояТаблицаЗначений.Индекс(СтрокаТЗ) + 1; // Индексы начинаются с 0, поэтому +1 для пользователя
Исключение
// В некоторых случаях (например, если строка была удалена и повторно добавлена
// в другую таблицу или каким-то образом потеряла связь), Индекс может не найтись.
// Для таких случаев можно использовать счетчик.
// Сейчас просто используем заглушку, но в реальной ситуации можно передать счетчик.
НомерСтроки = " (Неизвестная строка)";
КонецПопытки;
// Проверка заполнения "Колонки1" (строка)
Если НЕ ЗначениеЗаполнено(СтрокаТЗ.Колонка1) Тогда
Сообщить("В таблице значений не заполнена колонка '"
+ НСтр("ru = 'Колонка1'") + "' в строке " + НомерСтроки + ".", СтатусСообщения.Важное);
ПереданнаяТаблицаЗаполнена = Ложь;
КонецЕсли;
// Проверка заполнения "Колонки2" (ссылочный тип)
Если НЕ ЗначениеЗаполнено(СтрокаТЗ.Колонка2) Тогда
Сообщить("В таблице значений не заполнена колонка '"
+ НСтр("ru = 'Колонка2'") + "' в строке " + НомерСтроки + ".", СтатусСообщения.Важное);
ПереданнаяТаблицаЗаполнена = Ложь;
КонецЕсли;
// Дополнительная проверка для "ЧисловойКолонки" (число),
// если нужно убедиться, что значение не равно нулю
Если НЕ ЗначениеЗаполнено(СтрокаТЗ.ЧисловаяКолонка) Тогда // Эта проверка для числа всегда Истина, если оно не Неопределено
Сообщить("В таблице значений не заполнена колонка '"
+ НСтр("ru = 'ЧисловаяКолонка'") + "' в строке " + НомерСтроки + ".", СтатусСообщения.Важное);
ПереданнаяТаблицаЗаполнена = Ложь;
ИначеЕсли СтрокаТЗ.ЧисловаяКолонка = 0 Тогда
Сообщить("В таблице значений колонка '"
+ НСтр("ru = 'ЧисловаяКолонка'") + "' в строке " + НомерСтроки + " не может быть равна нулю.", СтатусСообщения.Важное);
ПереданнаяТаблицаЗаполнена = Ложь;
КонецЕсли;
// Если вы хотите прервать проверку после первой же ошибки,
// можно добавить проверку: Если НЕ ПереданнаяТаблицаЗаполнена Тогда Прервать; КонецЕсли;
КонецЦикла;
Возврат ПереданнаяТаблицаЗаполнена; // Возвращаем общий результат проверки
КонецФункции
// Пример вызова этой функции:
// МояТЗ = Новый ТаблицаЗначений;
// МояТЗ.Колонки.Добавить("Колонка1");
// МояТЗ.Колонки.Добавить("Колонка2", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
// МояТЗ.Колонки.Добавить("ЧисловаяКолонка", Новый ОписаниеТипов("Число"));
// Строка = МояТЗ.Добавить();
// Строка.Колонка1 = "Значение1";
// Строка.Колонка2 = Справочники.Номенклатура.НайтиПоНаименованию("МояНоменклатура");
// Строка.ЧисловаяКолонка = 10;
// Строка = МояТЗ.Добавить();
// // Строка.Колонка1 = ""; // Оставим пустым для примера
// Строка.Колонка2 = Справочники.Номенклатура.ПустаяСсылка();
// Строка.ЧисловаяКолонка = 0; // Оставим нулем для примера
// Если ПроверитьТаблицуЗначений(МояТЗ) Тогда
// Сообщить("Таблица значений прошла все проверки.");
// Иначе
// Сообщить("В таблице значений найдены незаполненные поля.", СтатусСообщения.Важное);
// КонецЕсли;
В этом примере мы создали функцию ПроверитьТаблицуЗначений, которая возвращает булево значение, указывающее, прошла ли таблица проверку. Мы используем МояТаблицаЗначений.Индекс(СтрокаТЗ) + 1 для получения номера строки, что делает сообщения об ошибках более понятными для пользователя.
Как мы уже упоминали, ТабличныйДокумент преимущественно используется для вывода информации. Тем не менее, если возникает специфическая задача по проверке его ячеек на заполнение (например, после интерактивного редактирования пользователем), мы можем это сделать, обращаясь к ячейкам по их координатам (строка, колонка) или по именованным областям.
Обращаться к содержимому ячейки следует через ее свойства Текст (если нас интересует текстовое представление) или Значение (если мы ожидаем данные определенного типа).
// Пример проверки ТабличногоДокумента
Процедура ПроверитьЯчейкиТабличногоДокумента(ТабДок)
// Проверяем, что ТабличныйДокумент вообще что-то содержит
Если ТабДок.ВысотаТаблицы = 0 И ТабДок.ШиринаТаблицы = 0 Тогда
Сообщить("Табличный документ пуст, нет ячеек для проверки.", СтатусСообщения.Важное);
Возврат;
КонецЕсли;
// Пример 1: Проверка конкретной ячейки по координатам
// Предположим, что мы знаем, что ячейка R2C3 (строка 2, колонка 3) должна быть заполнена.
// Обратите внимание: координаты в ТабличномДокументе начинаются с 1.
Если НЕ ЗначениеЗаполнено(ТабДок.Область(2, 3).Текст) Тогда
Сообщить("В табличном документе не заполнена ячейка в строке 2, колонке 3.", СтатусСообщения.Важное);
КонецЕсли;
// Пример 2: Проверка именованной области
// Если у вас есть именованные области (например, "ИтоговаяСумма"),
// вы можете проверить их заполнение.
Если ТабДок.ИменованныеОбласти.Найти("ИтоговаяСумма") <> Неопределено Тогда
// Проверяем текст области, который может быть результатом формулы или введенным значением
Если НЕ ЗначениеЗаполнено(ТабДок.ИменованныеОбласти.ИтоговаяСумма.Текст) Тогда
Сообщить("В табличном документе не заполнена именованная область '"
+ НСтр("ru = 'ИтоговаяСумма'") + "'.", СтатусСообщения.Важное);
КонецЕсли;
// Если область должна содержать числовое значение, проверяем Значение
// ИначеЕсли ТабДок.ИменованныеОбласти.ИтоговаяСумма.Значение = 0 Тогда
// Сообщить("В табличном документе значение области '"
// + НСтр("ru = 'ИтоговаяСумма'") + "' не может быть равно нулю.", СтатусСообщения.Важное);
// КонецЕсли;
КонецЕсли;
// Пример 3: Обход диапазона ячеек в цикле
// Если требуется проверить целую область таблицы, используем вложенные циклы.
// Допустим, нам нужно проверить ячейки с 5 по 10 строку и с 1 по 3 колонку.
Для НомерСтроки = 5 По 10 Цикл
Для НомерКолонки = 1 По 3 Цикл
// Используем .Текст для строкового содержимого ячейки
Если НЕ ЗначениеЗаполнено(ТабДок.Область(НомерСтроки, НомерКолонки).Текст) Тогда
Сообщить("В табличном документе не заполнена ячейка в строке " + НомерСтроки
+ ", колонке " + НомерКолонки + ".", СтатусСообщения.Важное);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Здесь важно помнить, что ТабличныйДокумент в основном служит для представления, и его ячейки могут содержать не только текст, но и другие типы данных. Выбор свойства (.Текст или .Значение) зависит от того, что именно вы хотите проверить.
Помимо прямого использования ЗначениеЗаполнено(), платформа 1С предоставляет и другие полезные механизмы для организации комплексной проверки заполнения.
ОбработкаПроверкиЗаполнения()Для объектов конфигурации (таких как документы, справочники, планы видов характеристик и т.д.) существует специальное событие ОбработкаПроверкиЗаполнения(), которое располагается в модуле объекта. Этот обработчик вызывается автоматически платформой в следующих случаях:
Записать() объекта с параметром РежимЗаписи.Запись или РежимЗаписи.Проведение.Это идеальное место для размещения логики проверки заполнения как реквизитов самого объекта, так и его табличных частей. Параметр Отказ в этом обработчике позволяет отменить запись или проведение объекта, если обнаружены ошибки. Пример его использования мы уже рассматривали при проверке ТабличнойЧасти.
Критически важно не просто обнаружить ошибку, но и информативно сообщить о ней пользователю. Сообщения должны быть максимально понятными, указывать, какое именно поле и в какой строке (или области) не заполнено, чтобы пользователь мог быстро найти и исправить ошибку.
Используйте функцию Сообщить() для вывода сообщений. Для улучшения юзабилити рекомендуется:
Указывать номер строки: Для табличных данных всегда включайте номер строки в сообщение ("В строке " + СтрокаТЧ.НомерСтроки).
Указывать имя поля: Четко называйте незаполненное поле ("не заполнено поле 'Номенклатура'").
Использовать НСтр(): Если ваша конфигурация может быть многоязычной, используйте НСтр("ru = 'НаименованиеПоля'") для получения локализованного имени поля.
Выделять важные сообщения: Используйте СтатусСообщения.Важное для того, чтобы сообщение было более заметным для пользователя.
// Пример информативного сообщения
Сообщить("Необходимо заполнить поле '"
+ НСтр("ru = 'НаименованиеПоля'") + "' в строке " + СтрокаТЧ.НомерСтроки + ".",
СтатусСообщения.Важное);
&НаКлиенте, &НаСервере)При написании кода проверки важно учитывать контекст выполнения процедур и функций:
&НаКлиенте: Проверки, выполняемые на клиенте, могут повысить интерактивность, обнаруживая ошибки до отправки данных на сервер. Однако они не могут изменять данные в базе и устанавливать Отказ = Истина для объекта.
&НаСервере: Проверки, которые должны влиять на запись данных в базу (например, устанавливать Отказ = Истина, обращаться к данным других объектов), обязательно должны выполняться на сервере или в серверных обработчиках. Обработчик ОбработкаПроверкиЗаполнения() всегда выполняется на сервере, что делает его идеальным местом для основной валидации.
Таким образом, для большинства критически важных проверок, влияющих на целостность данных, мы будем использовать серверные процедуры или функции.
В заключение, проверка заполнения полей в таблицах 1С — это фундаментальная задача, требующая внимательного подхода. Мы рассмотрели, как работать с различными типами таблиц: ТабличнаяЧасть, ТаблицаЗначений и ТабличныйДокумент. Мы подробно изучили ключевую функцию ЗначениеЗаполнено(), ее особенности для разных типов данных, и представили примеры кода для каждого случая. Не забывайте использовать механизмы автоматической проверки через конфигуратор и событие ОбработкаПроверкиЗаполнения() для комплексной валидации, а также всегда предоставлять пользователям четкие и понятные сообщения об ошибках.