Как отследить изменение проведенности документа в 1С?

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

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

Почему свойства Проведен и Ссылка.Проведен совпадают

Проанализируем последовательность событий при проведении документа. В транзакции записи выполняются обработчики ПередЗаписью, ПриЗаписи и ОбработкаПроведения.

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

Посмотрим на поведение в процедуре ПередЗаписью. В параметрах обработчика доступен РежимЗаписи, принимающий значение системного перечисления РежимЗаписиДокумента. Однако здесь кроется классическая ошибка: свойство ЭтотОбъект.Проведен отражает целевое состояние объекта, в которое он перейдет после записи. Если пользователь или алгоритм инициирует проведение, платформа еще до входа в ПередЗаписью устанавливает свойству Проведен значение Истина. По этой причине проверка вида НЕ Проведен И РежимЗаписи = РежимЗаписиДокумента.Проведение никогда не определит факт первого проведения.

Решение 1. Определение изменения статуса проведения в процедуре ПередЗаписью

Чтобы выяснить, находился ли документ в проведенном состоянии до текущей записи, необходимо обратиться к исходному состоянию документа в базе данных до применения текущих изменений. Разберем алгоритм проверки:

  1. Проверяем, является ли документ новым с помощью метода ЭтоНовый(). Новый документ гарантированно не был проведен ранее.
  2. Если документ уже существует в информационной базе, считываем его исходный признак проведения через ссылку: Ссылка.Проведен.
  3. Сравниваем целевой режим записи РежимЗаписи с исходным состоянием документа.

Посмотрим на пример правильной реализации в модуле документа или в подписке на событие:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

	// Новый документ не может быть проведен ранее
	БылПроведен = ?(ЭтоНовый(), Ложь, Ссылка.Проведен);

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

КонецПроцедуры

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

Решение 2. Передача признака проведения в обработчик ОбработкаПроведения

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

Рассмотрим по шагам реализацию этого механизма:

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

Посмотрим на пример программного кода в модуле документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

	БылПроведен = ?(ЭтоНовый(), Ложь, Ссылка.Проведен);
	ДополнительныеСвойства.Вставить("БылПроведен", БылПроведен);

КонецПроцедуры

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

	// Получаем сохраненное состояние
	БылПроведен = Ложь;
	Если ДополнительныеСвойства.Свойство("БылПроведен") Тогда
		БылПроведен = ДополнительныеСвойства.БылПроведен;
	КонецЕсли;

	Если НЕ БылПроведен Тогда
		// Код, выполняемый только при первом проведении
	КонецЕсли;

КонецПроцедуры

Оптимизация производительности при массовом проведении

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

Для высоконагруженных участков рекомендуется получать статус проведения через точечный запрос:


Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	Док.Проведен КАК Проведен
	|ИЗ
	|	Документ.РеализацияТоваровУслуг КАК Док
	|ГДЕ
	|	Док.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда
	БылПроведен = Выборка.Проведен;
Иначе
	БылПроведен = Ложь;
КонецЕсли;

Альтернативные способы контроля проведения

Проанализируем альтернативные инструменты платформы, позволяющие отслеживать изменения без вмешательства в логику проведения самого документа:

  1. Подписка на событие ПередЗаписью: чтобы не дублировать проверки в десятках документов конфигурации, создайте общую подписку на событие для источника ДокументОбъект. Это позволит централизованно отслеживать изменение проведения любых документов системы.
  2. Штатное версионирование объектов (БСП): если задача отслеживания вызвана необходимостью аудита действий пользователей (кто и когда провел или распровел документ), используйте подсистему «Версионирование объектов» из «Библиотеки стандартных подсистем». Она автоматически сохраняет историю версий при каждом изменении статуса.
  3. Журнал регистрации: платформа 1С автоматически фиксирует факты проведения и отмены проведения документа специальными системными событиями («Данные.Проведение», «Данные.Отмена проведения»), которые можно анализировать программно через объект ЖурналРегистрации без создания дополнительных реквизитов и регистров.
← На главную