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