Как автоматически записывать дату и время фактического проведения документа в 1С, сохраняя дату создания?

Программист 1С v8.3 (Обычные формы) Управленческий учет
← На главную

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

Постановка задачи и анализ ситуации

Рассмотрим сценарий: пользователь с ограниченными правами (например, Бухгалтер или Заявитель) создает документ, заполняет основные данные и сохраняет его. В этот момент стандартный реквизит Дата фиксирует время создания. Позже пользователь с правами Администратора или Менеджера проверяет документ и нажимает «Провести». Нам необходимо, чтобы в этот момент заполнился дополнительный реквизит ДатаПроводки, при этом время первоначального создания документа должно остаться неизменным.

Разберем, почему простая запись в обработке проведения может не сработать или вызвать ошибки, и как правильно спроектировать это решение.

Выбор места для реализации логики

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

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

Реализация в модуле объекта (Рекомендуемый способ)

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

В модуле объекта находим или создаем процедуру ПередЗаписью. Нам нужно проверить параметр РежимЗаписи. Этот параметр принимает значения из системного перечисления РежимЗаписиДокумента.


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

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

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

Анализ типичной ошибки: Значение не является значением объектного типа

В процессе обсуждения автор столкнулся с ошибкой: Значение не является значением объектного типа (Проведение). Давайте выясним причину. Эта ошибка возникает, когда программист пытается обратиться к свойству, которого нет у переменной. В контексте 1С это часто происходит из-за путаницы между именем параметра процедуры и именем системного перечисления.

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

Особенности работы с правами доступа

Часто бизнес-логика требует, чтобы дату проведения мог устанавливать только определенный круг лиц. В этом случае мы дополняем наше условие проверкой прав доступа. Рассмотрим пример, где дата заполняется только если у пользователя есть роль ПолныеПрава.


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

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

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

Проблема перезаписи стандартной даты (Оперативное проведение)

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

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

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

Альтернативный подход: Использование регистра сведений

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

Преимущества такого метода:

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


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

Подведение итогов

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

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

← На главную