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