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