Как узнать старую дату документа в модуле набора записей регистра при проведении

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

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

Почему Ссылка.Дата не возвращает старое значение?

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

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

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

Решение 1: Использование механизма ДополнительныеСвойства (Рекомендуемый метод)

Рассмотрим наиболее надежный и лаконичный способ — передачу значения через коллекцию ДополнительныеСвойства. Важно понимать, что у документа и у набора записей регистра — это разные коллекции. Нам нужно организовать «эстафету» передачи данных.

Шаг 1: Фиксация старой даты в документе

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


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

    // Получаем текущее значение даты из базы данных через ссылку
    СтараяДата = Источник.Ссылка.Дата;
    
    // Сохраняем старую дату в свойствах документа, чтобы она была доступна в ОбработкеПроведения
    Источник.ДополнительныеСвойства.Вставить("СтараяДатаДокумента", СтараяДата);
    
КонецПроцедуры

Шаг 2: Передача даты из документа в набор записей

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


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

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

Шаг 3: Получение данных в модуле регистра

Наконец, в модуле набора записей регистра Хозрасчетный мы можем прочитать это значение.


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

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

Решение 2: Использование Версионирования объектов (БСП)

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

Выясним причину использования этого метода: он позволяет не модифицировать модули документов и не создавать цепочку подписок. Проанализируем пример получения версии:


Функция ПолучитьСтаруюДатуИзВерсий(СсылкаНаДокумент)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	ВерсииОбъектов.ОбъектВерсии КАК ДанныеВерсии
        |ИЗ
        |	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
        |ГДЕ
        |	ВерсииОбъектов.Объект = &Ссылка
        |УПОРЯДОЧИТЬ ПО
        |	ВерсииОбъектов.НомерВерсии УБЫВ_";
    
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
    // ... далее десериализация версии и получение реквизита "Дата"
    
КонецФункции

Важный нюанс: Этот метод довольно ресурсоемкий, так как требует обращения к таблице версий и десериализации объекта (обычно это XML или Binary Data). Использовать его внутри записи регистра стоит только в крайнем случае, если другие методы недоступны.

Решение 3: Платформенный механизм «История данных»

Если используется платформа 8.3.11 и выше, можно задействовать механизм «История данных». Он работает на уровне платформы и более эффективен, чем версионирование БСП. Рассмотрим алгоритм:

  1. В модуле регистра получаем менеджер истории данных для типа регистратора.
  2. Запрашиваем последнюю версию до текущего момента.
  3. Извлекаем значение реквизита Дата.

Это позволяет получить состояние объекта «на вчера» без необходимости пробрасывать параметры через свойства. Однако это требует включенной настройки истории данных для конкретных объектов метаданных.

Сравнение подходов

Выясним, какой метод выбрать в зависимости от ситуации:

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

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

← На главную