Как убрать предупреждение «Документ изменен» и исключить повторное проведение при записи даты в 1С

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

Каждый начинающий разработчик в среде «1С:Предприятие» рано или поздно сталкивается с ситуацией, когда при попытке программно изменить реквизит документа в процессе его проведения система начинает вести себя некорректно. Документ проводится, но платформа неожиданно выдает предупреждение: «Данные были изменены. Сохранить изменения?». Если пользователь соглашается, документ проводится повторно, порождая двойные транзакции, лишнюю нагрузку на сервер и путаницу в учете. Особо остро эта проблема проявляется на обычных формах в комплексных конфигурациях, таких как «1С:Комплексная автоматизация 1.1» или «Управление торговлей 10.3».

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

Анализируем природу ошибки: почему платформа задает лишние вопросы?

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

Рассмотрим по шагам, что происходит в этот момент внутри платформы:

  1. Пользователь инициирует запись/проведение из формы. Флаг Модифицированность формы в этот момент равен Ложь (так как физически пользователь ничего в полях ввода не менял).
  2. Срабатывает событие формы ПередЗаписью, где разработчик программно меняет значение реквизита: ДатаСоздания = ТекущаяДата().
  3. Платформа видит, что данные объекта на форме изменились, и автоматически взводит флаг Модифицированность = Истина.
  4. Документ успешно записывается в базу данных. Транзакция завершается.
  5. Но после завершения записи платформа обнаруживает, что у формы все еще взведен флаг модифицированности! Система «считает», что после того, как документ сохранился в базу, пользователь (или код) внес в форму новые изменения, которые еще не были сохранены.
  6. При попытке закрыть форму или провести документ повторно система выдает то самое назойливое окно с вопросом о сохранении изменений. При согласии запускается повторный цикл записи, что приводит к двойному проведению.

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

Шаг 1. Перенос логики в Модуль Объекта — золотой стандарт

Для того чтобы избежать конфликтов модифицированности формы, мы должны четко разделить логику интерфейса и логику данных. Любые действия по автозаполнению реквизитов перед непосредственным сохранением в базу данных должны происходить в Модуле Объекта, а не в модуле формы.

Когда код выполняется в модуле объекта, платформа производит запись данных напрямую. После успешного завершения транзакции обычная форма автоматически перечитывает измененные данные из базы и сбрасывает свою модифицированность в значение Ложь.

Давайте откроем модуль объекта нашего документа и добавим предопределенную процедуру ПередЗаписью. Напишем чистый и отказоустойчивый код:


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

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

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

Шаг 2. Управление модифицированностью формы (для обычных форм)

В таких конфигурациях, как «Комплексная автоматизация 1.1», присутствует огромное количество подписок на события и внутренних механизмов, которые могут принудительно взводить модифицированность формы даже после записи объекта. Если вы перенесли код в модуль объекта, но проблема в редких случаях сохраняется, нам необходимо программно «успокоить» форму после записи.

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


Процедура ПослеЗаписи()
	
	// Способ 1: Сброс флага измененности вручную
	ЭтаФорма.Модифицированность = Ложь;
	
	// Способ 2: Полное перечитывание объекта из базы данных для синхронизации
	// Этот способ более надежен, если параллельно сработали подписки на события
	ЭтаФорма.Прочитать();
	
КонецПроцедуры

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

Шаг 3. Настройка свойств элементов управления на форме

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

Выполним следующие настройки для элемента управления (поля ввода), связанного с реквизитом ДатаСоздания:

Шаг 4. Настройка проведения в метаданных документа

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

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

Рекомендуется установить это свойство в значение Записывать автоматически. Это гарантирует предсказуемое поведение платформы при записи движений и самого документа в рамках одной транзакции проведения.

Подведем итоги решения

Мы детально изучили проблему повторного проведения документов и выяснили, что она всегда связана с некорректным изменением реквизитов в обработчиках событий интерактивной формы. Для красивого и правильного решения этой задачи мы:

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

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

← На главную