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