В какой момент меняется граница последовательности и как предотвратить её сдвиг при перепроведении документов без изменений

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

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

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

Анализ механизмов сдвига границы в УТ 10.3

Для начала проанализируем, как именно платформа и код конфигурации управляют границей. В 1С существует два параллельных процесса, которые могут изменять ГП:

  1. Программный метод: В коде конфигурации явно вызывается метод Последовательности.ПартионныйУчет.УстановитьГраницу().
  2. Автоматический (платформенный) метод: Платформа сама отслеживает запись движений в регистры, которые входят в состав последовательности. Даже если в свойствах последовательности стоит «Перемещение границы при проведении — Не перемещать», платформа может сдвинуть границу назад при очистке старых движений документа.

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


СдвигатьГраницу = ОпределитьНеобходимостьСдвигаГраницы(ДокументМоментВремени, "Упр");
Если СдвигатьГраницу Тогда
    Последовательности.ПартионныйУчет.УстановитьГраницу(ДокументМоментВремени);
КонецЕсли;

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

Почему граница уходит назад «сама»?

Выясним причину скрытого сдвига. У каждого документа, включенного в последовательность, есть записи в системной таблице регистрации. Когда документ перепроводится, 1С выполняет следующие действия:

  1. Удаляет существующие записи документа из таблицы регистрации последовательности.
  2. Удаляет движения по регистрам накопления (например, по регистру ПартииТоваровНаСкладах).
  3. В этот момент платформа понимает, что данные «в прошлом» (относительно текущей ГП) изменились или исчезли. Чтобы не нарушить логическую целостность партий, ГП автоматически сдвигается назад на Момент Времени этого документа.

Важный вывод: Чтобы граница не двигалась, нужно либо предотвратить запись набора записей регистра (если он идентичен старому), либо программно вернуть ГП на место сразу после записи.

Стратегия решения: Сравнение движений

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

Для реализации нам понадобятся подписки на события. Разберем по шагам:

Шаг 1: Подписка на событие ПередЗаписью набора записей регистра

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


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

    Регистратор = Источник.Отбор.Регистратор.Значение;
    
    // Считываем текущие движения из БД
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ * ИЗ РегистрНакопления.ПартииТоваровНаСкладах ГДЕ Регистратор = &Регистратор";
    Запрос.УстановитьПараметр("Регистратор", Регистратор);
    ТаблицаБД = Запрос.Выполнить().Выгрузить();
    
    ТаблицаНовая = Источник.Выгрузить();
    
    // Сравниваем таблицы (нужно написать функцию сравнения составов)
    Если ДвиженияИдентичны(ТаблицаБД, ТаблицаНовая) Тогда
        // Если движения не изменились, ставим флаг в дополнительные свойства
        Источник.ДополнительныеСвойства.Вставить("ДвиженияНеИзменились", Истина);
        
        // Опционально: можно вообще отменить запись в БД, чтобы сэкономить ресурсы
        // Источник.Записывать = Ложь; 
    КонецЕсли;
КонецПроцедуры

Шаг 2: Использование Дополнительных Свойств для передачи флага

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

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

Шаг 3: Модификация кода установки границы

Теперь вернемся к коду в модуле УправлениеЗапасамиПартионныйУчет. Нам необходимо изменить логику функции ОпределитьНеобходимостьСдвигаГраницы или непосредственно место вызова УстановитьГраницу.

Посмотрим на пример модификации:


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

    Если НЕ ДвиженияНеМенялись Тогда
        Последовательности.ПартионныйУчет.УстановитьГраницу(ДокументМоментВремени);
    КонецЕсли;
КонецЕсли;

Как реализовать сравнение таблиц движений?

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

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

Альтернативный вариант: Возврат границы «ПриЗаписи»

Существует еще один подход, который обсуждался коллегами. Если мы не хотим глубоко внедряться в логику сравнения таблиц, можно использовать «запоминание» границы:

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

Однако этот метод менее надежен, так как программный возврат границы вперед может «перепрыгнуть» через реально измененные другими пользователями документы в многопользовательской среде.

Резюме и рекомендации

Выяснив причины поведения системы, мы можем сделать следующие выводы:

  1. Сдвиг ГП в УТ 10.3 — это защитный механизм платформы, гарантирующий актуальность себестоимости.
  2. Оптимальное решение заключается в предотвращении перезаписи наборов записей регистров накопления, если новые данные полностью соответствуют старым.
  3. Использование ДополнительныеСвойства позволяет связать логику проведения документа с логикой регистрации в последовательностях без изменения структуры метаданных.

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

← На главную