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