Как правильно реализовать движения в непроводном документе 1С и стоит ли разрешать проведение?

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

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

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

---

Зачем делать документ непроводным, если он делает движения?

На первый взгляд, создание непроводного документа-регистратора кажется грубым нарушением стандартов разработки 1С. Однако опытные архитекторы сознательно идут на этот шаг, руководствуясь следующими соображениями:

  1. Оптимизация производительности и блокировок. Механизм проведения документа запускает сложную транзакционную цепочку, накладывая блокировки на таблицы базы данных. Запись движений напрямую в обработчике записи происходит быстрее и снижает вероятность возникновения взаимных блокировок (Deadlocks) в высоконагруженных многопользовательских системах.
  2. Исключение из последовательностей документов. Проводные документы при проведении или отмене проведения могут автоматически сдвигать назад границу последовательности (например, в партионном учете или взаиморасчетах). Если документ предназначен для вспомогательного учета (например, учет рабочего времени, как в обсуждаемом на форуме примере), его проведение приводило бы к постоянному сдвигу границы последовательности и необходимости регулярного перепроведения базы.
  3. Упрощение пользовательского интерфейса (UX). У непроводного документа отсутствует статус «Проведен» (зеленая галочка на иконке). Пользователю не нужно совершать лишнее действие — нажимать кнопку «Провести». Достаточно просто нажать «Записать», и данные мгновенно попадают в регистры. Это минимизирует путаницу, когда пользователь сохранил документ, но забыл его провести.

---

Главные подводные камни схемы «Движения при записи»

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

1. Ловушка пометки удаления

Для стандартного проводного документа интерактивная установка пометки удаления автоматически запускает механизм отмены проведения. Платформа сама очищает все движения по регистрам.

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

2. Игнорирование свойства «Удалять движения автоматически»

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

3. Проблема обмена данными

При синхронизации или загрузке данных из внешних систем документы часто записываются с установленным свойством ОбменДанными.Загрузка = Истина. В этом режиме стандартные обработчики событий (включая ПриЗаписи) обычно обходятся или отключаются. Если логика движений завязана на обработчик ПриЗаписи, то при переносе документов в другую базу они запишутся пустой ссылкой, а движения в регистрах не создадутся.

---

Как правильно организовать запись и очистку движений?

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

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


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

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

---

Чем чреват переход на схему «Проведение = Разрешить»?

Если вы решите отказаться от текущей логики и сделать документ стандартным проводным, перенеся код в предопределенные процедуры ОбработкаПроведения и ОбработкаУдаленияПроведения, вы столкнетесь со следующими рисками:

  1. Интерфейсный шок для пользователей. Пользователям придется привыкать вместо кнопки «Записать» нажимать «Провести и закрыть». Простое сохранение документа больше не будет обновлять данные в регистрах.
  2. Проблема исторических данных. Это самый опасный момент. В базе уже существует множество документов, которые имеют статус «Не проведен» (поскольку проведение было запрещено), но при этом имеют физические записи в регистрах.
    • Как только вы включите свойство «Проведение — Разрешить», эти документы так и останутся со статусом «Не проведен».
    • При любой перезаписи старого документа (или при групповой обработке) платформа увидит статус «Не проведен» и автоматически очистит все движения этого документа, так как логика платформы не предполагает наличие движений у непроведенного документа.

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


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

---

Примеры аналогичных решений в типовых конфигурациях

Стоит отметить, что разработчики фирмы «1С» активно используют схему непроводных документов с движениями в конфигурациях ERP, ЗУП и Комплексная автоматизация. Рассмотрим два ярких примера:

Резюме

Схема с непроводным документом-регистратором вполне жизнеспособна и активно применяется даже в типовых решениях от фирмы «1С». Если ваш документ не участвует в сложных цепочках последовательностей, переводить его в статус проводного нет необходимости. Главное — строго соблюдать правила программного контроля за очисткой движений при перезаписи и пометке удаления в обработчике ПередЗаписью.

← На главную