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