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