Как зафиксировать дату первого проведения документа в 1С:Комплексная автоматизация без ошибки «Документ изменен»?

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

Переход с обычных форм (например, в конфигурации «Управление торговлей 10.3») на управляемые формы («Комплексная автоматизация 2.x» или «ERP Управление предприятием») часто вызывает трудности у начинающих разработчиков. Типичный пример — задача фиксации даты первого проведения документа. Код, который отлично работал в обычной форме, в управляемом приложении начинает вызывать назойливое предупреждение системы: «Документ изменен. Провести или нет?».

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

Выясняем причину: почему возникает ошибка «Документ изменен»?

Для начала проанализируем ситуацию и поймем, почему старый подход из «Управления торговлей 10.3» перестал работать в «Комплексной автоматизации».

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

Когда вы пишете код модификации реквизитов внутри обработчиков формы (например, ПередЗаписьюНаСервере), происходят следующие процессы:

  1. Пользователь нажимает кнопку «Провести».
  2. Данные формы передаются на сервер и конвертируются в реальный объект базы данных.
  3. В процедуре формы вы изменяете реквизит напрямую в объекте (например, присваиваете значение реквизиту ДатаСоздания).
  4. Объект успешно записывается и проводится в базе данных.
  5. Управляемая форма на клиенте «не знает» о том, что на сервере значение реквизита изменилось, так как эти изменения произошли в обход стандартного механизма синхронизации данных формы и объекта.
  6. Платформа обнаруживает рассинхронизацию между данными на клиенте и данными в базе и выдает предупреждение о том, что объект был изменен другой транзакцией или процессом.

Кроме того, если пользователь решит провести документ не из самой формы, а из списка документов (нажатием правой кнопки мыши или кнопкой на панели списка), то события формы вообще не будут вызваны! В результате ваш код просто проигнорируется, и дата первого проведения останется пустой.

Вывод: Любая бизнес-логика, которая должна гарантированно выполняться при записи или проведении объекта (независимо от того, откуда именно инициировано это действие), должна располагаться исключительно в Модуле объекта.

---

Пошаговое решение: пишем правильный код в Модуле объекта

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

  1. Проверка первого проведения: дата должна записываться только один раз. Повторные проведения или отмены проведения не должны менять первоначальную дату.
  2. Копирование документов: при создании нового документа путем копирования старого, дата первого проведения должна очищаться.
  3. Часовые пояса: время должно определяться по часовому поясу пользователя, а не сервера.
  4. Обмен данными: при интеграциях и загрузках из внешних систем автоматическое заполнение дат должно отключаться, чтобы сохранить исходные исторические данные.

Шаг 1. Переходим в модуль объекта

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

Шаг 2. Реализуем обработчик ПередЗаписью

Добавим предопределенную процедуру ПередЗаписью. Именно здесь мы будем перехватывать момент проведения документа.

Рассмотрим структуру кода, который решает поставленные задачи:


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

Разберем подробнее ключевые моменты этого кода:

Шаг 3. Обрабатываем копирование документов

Если пользователь скопирует уже проведенный документ, система скопирует все его реквизиты, включая заполненное поле ДатаСоздания. В итоге у нового документа это поле будет заполнено еще до его первого проведения. Чтобы избежать этого бага, добавим обработчик события ПриКопировании в этот же модуль объекта:


Процедура ПриКопировании(ОбъектКопирования)
	
	// Очищаем реквизит у нового скопированного документа.
	// Присваиваем пустую дату ('00010101000000').
	ДатаСоздания = '00010101000000';
	
КонецПроцедуры

Теперь при создании копии реквизит ДатаСоздания у нового документа сразу станет пустым, и при его первом проведении корректно отработает условие в процедуре ПередЗаписью.

---

Альтернативные архитектурные подходы (Best Practices)

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

Вариант 1. Использование независимого регистра сведений

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

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

Вариант 2. Использование типового механизма БСП «Версионирование объектов»

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

Для решения вашей задачи вам может вообще не потребоваться писать код! Достаточно выполнить следующие действия в режиме «1С:Предприятие»:

  1. Перейдите в раздел НСИ и администрирование -> Поддержка и обслуживание -> История изменений.
  2. Установите флаг «Хранить историю изменений».
  3. Для интересующего вас документа выберите режим версионирования (например, «При проведении» или «Всегда»).

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

← На главную