В процессе разработки в среде 1С:Предприятие одной из наиболее частых задач является контроль качества вводимых данных. Особую сложность для начинающих разработчиков представляет проверка табличных частей, когда необходимо не просто запретить запись пустого документа, а указать пользователю на конкретную строку и колонку, где допущена ошибка. Рассмотрим подробно, как реализовать такую проверку до момента записи документа в базу данных, проанализируем различные подходы и выберем наиболее эффективные инструменты.
Представим ситуацию, описанную в теме: у нас есть табличная часть с перечнем номенклатуры. Нам необходимо убедиться, что для каждой позиции заполнена цена. Если цена отсутствует, система должна прервать процесс записи и выдать информативное сообщение. Важное условие — проверка должна происходить до записи, чтобы не засорять базу данных неполными или некорректными объектами.
Рассмотрим ситуацию, когда документ еще не создан (новый). В этом случае у объекта еще нет ссылки в базе данных (Объект.Ссылка будет пустой), что накладывает определенные ограничения на использование запросов и внешних функций, завязанных на уникальный идентификатор объекта.
Это «золотой стандарт» платформы 1С для валидации данных. Данное событие вызывается на сервере автоматически при нажатии пользователем кнопки «Провести и закрыть» или «Записать», но строго до начала транзакции записи.
Разберем, как реализовать этот механизм в модуле объекта (быстро подготовить каркас поможет Консоль кода + ИИ-помощник):
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Индекс строки для формирования пути к данным
Индекс = 0;
Для Каждого ТекСтрока Из Товары Цикл
Если ТекСтрока.Цена = 0 Тогда
// Если находим ошибку, устанавливаем Отказ в Истина
Отказ = Истина;
// Формируем сообщение, привязанное к конкретной ячейке
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "В строке №" + (Индекс + 1) + " не заполнена цена для номенклатуры: " + ТекСтрока.Номенклатура;
Сообщение.Поле = "Объект.Товары[" + Индекс + "].Цена";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
КонецЕсли;
Индекс = Индекс + 1;
КонецЦикла;
КонецПроцедуры
Проанализируем этот код. Параметр Отказ — это ключевой рычаг управления. Если мы присвоим ему значение Истина, платформа прервет выполнение операции записи. Объект СообщениеПользователю позволяет не просто вывести текст, но и подсветить красным цветом ту самую ячейку Цена, в которой обнаружена ошибка. Это значительно повышает удобство работы пользователя (UX).
Иногда логика проверки требует данных, которые есть только на форме, или сложного взаимодействия с интерфейсом. В этом случае мы используем событие ПередЗаписью в модуле формы. Однако здесь важно понимать разницу между клиентским и серверным контекстом.
Выясним причину использования клиентской проверки: она экономит ресурсы сервера, не отправляя данные на запись, если заведомо известно, что они некорректны. Рассмотрим пример реализации:
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
// Простейшая проверка на клиенте перед уходом на сервер
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
Если СтрокаТЧ.Цена = 0 Тогда
Отказ = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Цена должна быть заполнена!", , "Объект.Товары[" + Объект.Товары.Индекс(СтрокаТЧ) + "].Цена");
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важно: Проверка на форме не заменяет проверку в модуле объекта, так как документ может быть записан программно (из другой обработки), минуя форму. Поэтому критически важные проверки всегда дублируйте в модуле объекта.
Как обсуждалось на форуме, можно проверять данные в момент их ввода в событии ПриИзменении. Это позволяет пользователю сразу увидеть ошибку, не дожидаясь нажатия кнопки записи. Посмотрим на пример кода для реквизита номенклатуры:
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
// Вызываем серверную функцию для получения цены
ЦенаТовара = ПолучитьЦенуНаСервере(ТекущаяСтрока.Номенклатура, Объект.Дата);
Если ЦенаТовара = 0 Тогда
// Предупреждаем пользователя, но не блокируем работу
ПоказатьПредупреждение(, "Внимание: для данной номенклатуры не задана цена в прайс-листе!");
Иначе
ТекущаяСтрока.Цена = ЦенаТовара;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот подход хорош тем, что он проактивен. Однако, как верно заметили участники дискуссии, избыточные походы на сервер при каждом изменении могут замедлить работу при плохом интернет-соединении. Используйте этот метод разумно, комбинируя его с финальной проверкой в ОбработкаПроверкиЗаполнения.
Рассмотрим нюанс, упомянутый в 10-м сообщении форума. Если ваша процедура проверки (например, ПослеВнесенияЗаказовНаСервер) требует наличия ссылки на документ (например, для записи в связанные регистры или передачи в запросы), а документ еще не записан, используйте метод УстановитьСсылкуНового().
Проанализируем ситуацию: платформа позволяет заранее зарезервировать УникальныйИдентификатор для объекта. Это делается следующим образом:
// В модуле формы или при создании объекта
СсылкаНаБудущийДокумент = Документы.ЗаказПокупателя.ПолучитьСсылку();
ЭтотОбъект.УстановитьСсылкуНового(СсылкаНаБудущийДокумент);
Теперь, даже если документ физически не записан в таблицу SQL, свойство Объект.Ссылка уже будет содержать валидный идентификатор, который можно использовать в алгоритмах проверки заполнения.
Если в вашем документе тысячи строк, перебор в цикле Для Каждого может вызвать зависание интерфейса. В таких случаях мы рекомендуем использовать временные таблицы и запросы.
Разберем по шагам алгоритм быстрой проверки:
Цена = 0.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТчТовары.НомерСтроки КАК НомерСтроки,
| ТчТовары.Номенклатура.Наименование КАК НоменклатураНаименование
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТчТовары КАК ТчТовары
|;
|ВЫБРАТЬ
| ВТ_Товары.НомерСтроки,
| ВТ_Товары.НоменклатураНаименование
|ИЗ
| ВТ_Товары КАК ВТ_Товары
|ГДЕ
| ВТ_Товары.Цена = 0";
Запрос.УстановитьПараметр("ТчТовары", Товары.Выгрузить());
РезультатЗапроса = Запрос.Выполнить();
// Далее обработка результата...
Такой подход работает значительно быстрее на больших объемах данных, так как оптимизация поиска пустых значений перекладывается на движок СУБД.
Для качественной реализации проверки заполнения данных в 1С следует придерживаться комплексного подхода:
ОбработкаПроверкиЗаполнения.СообщениеПользователю для точной адресации ошибки в конкретную строку табличной части.Соблюдение этих правил позволит вам создавать надежные и удобные решения, которые минимизируют ошибки ввода и облегчают работу конечных пользователей программы.