Как разрешить запись документа без заполнения реквизита, но запретить его проведение в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки прикладных решений на платформе 1С:Предприятие часто возникает задача разделения логики записи и проведения документа. Типичный сценарий: пользователю необходимо разрешить сохранять документ в базу данных как «черновик» (даже если заполнены не все обязательные поля), но при попытке провести документ система должна жестко контролировать заполнение ключевых реквизитов и отменять операцию при их отсутствии.

В этой статье мы подробно разберем, как правильно реализовать такое поведение системы. Мы проанализируем различные подходы — от стандартных свойств конфигуратора до программного кода в модулях формы и объекта. Также мы выясним, почему некоторые очевидные решения (например, использование стандартных предупреждений) могут нарушить стабильность работы всей базы данных.

Способ 1. Стандартная проверка заполнения в конфигураторе (Без кода)

Прежде чем писать программный код, давайте проанализируем стандартное поведение платформы 1С. Существует распространенное заблуждение, что если у реквизита документа установить свойство «Проверка заполнения» в значение «Выдавать ошибку», то система заблокирует любую запись документа.

Это не так. Разработчики платформы заложили разную логику для различных объектов метаданных:

Рассмотрим подробнее, как это использовать. Вам достаточно открыть свойства нужного реквизита документа в конфигураторе и в поле «Проверка заполнения» выбрать значение «Выдавать ошибку». Это самое простое и быстрое решение, не требующее написания ни одной строки кода.

Однако этот способ работает только при интерактивной работе пользователя в форме и не подходит для сложных сценариев проверки (например, если заполнение реквизита зависит от значения другого поля).

Способ 2. Проверка в модуле объекта (Событие ПередЗаписью)

Если вам требуется гарантировать проверку как при интерактивной работе пользователя, так и при программной записи документа (например, при обмене данными, загрузке из внешних систем или создании документов на основании), то лучшим местом для реализации будет предопределенная процедура ПередЗаписью в модуле объекта документа.

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

Посмотрим на пример реализации:


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

Этот код абсолютно безопасен, так как он выполняется на сервере внутри транзакции базы данных и не использует интерактивные методы. Если условие не выполнено, переменная Отказ принимает значение Истина, транзакция откатывается, а пользователю выводится понятное сообщение с фокусом на незаполненном поле.

Способ 3. Проверка в модуле управляемой формы

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

В управляемых формах в процедуру ПередЗаписью передается параметр ПараметрыЗаписи, который содержит свойство РежимЗаписи. Проанализируем его на клиенте:


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

Обратите внимание: при проверке на клиенте в управляемой форме мы обращаемся к реквизиту через структуру Объект (например, Объект.ДатаВыдачи), а при привязке сообщения к полю ввода указываем путь к данным в кавычках: "Объект.ДатаВыдачи".

Способ 4. Использование обработчика ОбработкаПроверкиЗаполнения

Для более гибкого управления проверками в платформу 1С встроен специализированный механизм — обработчик ОбработкаПроверкиЗаполнения в модуле объекта. Он позволяет динамически управлять списком проверяемых реквизитов.

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


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

Используя этот метод, мы полностью следуем стандартам разработки фирмы 1С. Платформа сама проверит оставшиеся в массиве реквизиты, подсветит их на форме и сформирует системные сообщения об ошибках.

Важное предупреждение: Почему нельзя использовать «Предупреждение» и «Вопрос» в транзакциях

Давайте выясним причину распространенной ошибки начинающих разработчиков, которая упоминалась в сообщениях форума. Речь идет об использовании функции Предупреждение (или ПоказатьПредупреждение) внутри транзакционных процедур, таких как ПередЗаписью модуля объекта или ОбработкаПроведения.

Существует две критические причины, почему так делать категорически запрещено:

  1. Клиент-серверная архитектура: процедуры записи и проведения объекта выполняются строго на сервере. На сервере нет интерфейса, поэтому любая попытка вызвать модальное или диалоговое окно (методы типа Предупреждение) приведет к падению системы с критической ошибкой «Интерактивные операции недоступны».
  2. Блокировка базы данных: запись и проведение происходят внутри неделимой транзакции СУБД. На время транзакции СУБД накладывает блокировки на таблицы базы данных (чтобы другие пользователи не могли изменить те же данные). Если бы платформа вывела модальное окно и остановила выполнение кода в ожидании клика пользователя, транзакция осталась бы открытой. Пользователь мог уйти пить кофе, оставив систему заблокированной. В результате все остальные пользователи базы данных начали бы получать ошибки ожидания блокировок.

Золотое правило разработчика 1С: внутри транзакционных процедур (запись, проведение) для вывода ошибок мы используем исключительно объект СообщениеПользователю совместно с установкой переменной Отказ = Истина.

Резюме

Мы рассмотрели различные методы решения задачи условного запрета проведения документа. Для простых ситуаций лучшим выбором будет стандартная настройка свойства реквизита в конфигураторе. Для сложных алгоритмов и обеспечения гарантированной проверки при программной записи следует использовать событие ПередЗаписью модуля объекта с анализом параметра РежимЗаписи. Соблюдение этих правил гарантирует высокую производительность системы и корректную работу пользователей.

← На главную