Можно ли в расширении добавить движения существующему документу по существующему регистру?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникают задачи по доработке типового функционала без снятия конфигурации с поддержки. Один из распространенных сценариев: есть типовой документ (из основной конфигурации) и типовой регистр сведений. Нам необходимо, чтобы этот документ начал делать движения (записи) в этот регистр, хотя изначально такая логика не была предусмотрена разработчиком типового решения. И главное требование — реализовать это только средствами расширения.

Давайте подробно разберем, возможно ли это технически, с какими ограничениями мы столкнемся и какие существуют пути решения.

Анализ проблемы: Тип регистра имеет значение

Прежде чем приступать к написанию кода, мы должны четко определить режим записи целевого регистра сведений. Удобно это сделать, используя инструменты для поиска и просмотра свойств объектов метаданных — для этого подойдёт анализ метаданных и редактор свойств объектов. От этого фундаментально зависит стратегия решения.

Регистры сведений бывают двух типов:

  1. Подчиненные регистратору (запись происходит только при проведении документа).
  2. Независимые (запись может происходить в любой момент времени).

Рассмотрим оба варианта, так как подход к реализации кардинально отличается.

Вариант 1. Регистр сведений подчинен регистратору

Это самый сложный случай, который вызывает больше всего вопросов у разработчиков. Суть проблемы заключается в архитектуре механизма расширений.

Чтобы документ мог делать движения по регистру (использовать коллекцию Движения), он должен входить в состав регистраторов этого регистра. Свойство "Регистраторы" определяется в метаданных самого регистра.

Техническое ограничение: Если регистр сведений находится в основной конфигурации ("родной" объект), то в расширении мы не можем расширить состав его регистраторов. Платформа 1С на текущий момент не позволяет в расширении "заимствовать" регистр из основной конфигурации и добавить ему в список регистраторов еще один документ (даже если этот документ тоже из основной конфигурации).

Попытка просто написать код формирования движений в модуле расширения приведет к ошибке, так как платформа проверит метаданные и увидит, что данный документ не имеет права писать в этот регистр.

Что делать? Варианты решения:

  1. Снятие конфигурации с поддержки (частично)
    Как справедливо замечено в обсуждении, самый "прямой" способ — это включить возможность изменения основной конфигурации и добавить документ в регистраторы регистра в самом дереве метаданных. Однако это нарушает условие "делать всё в расширении" и может усложнить дальнейшие обновления.

  2. Создание дублирующего регистра в расширении
    Если менять основную конфигурацию нельзя, мы вынуждены идти обходным путем. Рассмотрим алгоритм:

    • В расширении создаем новый регистр сведений (собственный объект расширения).
    • Полностью копируем структуру измерений, ресурсов и реквизитов оригинального регистра. Чтобы не упустить ни одной детали, можно воспользоваться, например, разработкой Универсальный отчет по метаданным расширенный.
    • Устанавливаем этому новому регистру режим записи "Подчинение регистратору".
    • В качестве регистратора указываем нужный нам документ (заимствуем его из основной конфигурации в расширение).

    В этом случае при проведении документа мы будем писать данные в наш новый регистр.

    Минус подхода: Данные будут "размазаны" по двум таблицам (оригинальный регистр и регистр из расширения). Если эти данные используются в типовых отчетах, отчеты не увидят наши новые записи без дополнительной доработки (например, через переопределение схем компоновки данных). Такой подход требует внимательности, и после реализации рекомендуется провести комплексный анализ расширения на наличие ошибок.

Вариант 2. Независимый регистр сведений

Если регистр является независимым (или мы решаем использовать независимую запись вместо движений), задача решается программно через подписки на события. Прежде чем создавать новые, полезно провести анализ подписок на объекты конфигурации, чтобы избежать конфликтов с уже существующей логикой. В этом случае понятие "Движения" как таковое отсутствует, но мы можем эмулировать поведение системы.

Нам понадобятся две подписки на событие в расширении:

  1. ОбработкаПроведения — для записи данных.
  2. ОбработкаУдаленияПроведения — для очистки данных при отмене проведения (поможет массовое перепроведение и групповая обработка документов).

Разберем пример реализации через создание менеджера записи или набора записей.

Шаг 1. Запись данных при проведении

Создадим в расширении подписку на событие ОбработкаПроведения для нашего документа. В модуле подписки напишем код:


Процедура Расш_ОбработкаПроведения(Источник, Отказ, РежимПроведения)
    
    // Формируем набор записей
    НаборЗаписей = РегистрыСведений.НашРегистрСведений.СоздатьНаборЗаписей();
    
    // Если регистр имеет измерение-ссылку на документ (эмуляция регистратора)
    // Устанавливаем отбор по этому измерению
    НаборЗаписей.Отбор.ДокументОснование.Установить(Источник.Ссылка);
    
    // Добавляем новую строку в набор
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.ДокументОснование = Источник.Ссылка;
    НоваяЗапись.Период = Источник.Дата;
    НоваяЗапись.Измерение1 = Источник.Реквизит1;
    НоваяЗапись.Ресурс1 = Источник.Сумма;
    
    // Записываем набор. Истина - замещать существующие записи по данному отбору
    НаборЗаписей.Записать(Истина);
    
КонецПроцедуры

Шаг 2. Очистка данных при отмене проведения

Очень важно не забыть про отмену проведения. Иначе данные останутся в регистре, даже если документ станет непроведенным. Создадим подписку на ОбработкаУдаленияПроведения:


Процедура Расш_ОбработкаУдаленияПроведения(Источник, Отказ)
    
    // Создаем набор записей с отбором по нашему документу
    НаборЗаписей = РегистрыСведений.НашРегистрСведений.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.ДокументОснование.Установить(Источник.Ссылка);
    
    // Записываем пустой набор, что эквивалентно удалению записей
    НаборЗаписей.Записать(Истина);
    
КонецПроцедуры

Нюанс с "Псевдо-регистратором"

Если оригинальный регистр является независимым, но нам нужно строго привязать записи к документу, хорошей практикой является наличие в регистре измерения, хранящего ссылку на документ (например, измерение ДокументОснование).

Если такого измерения в типовом регистре нет, мы снова сталкиваемся с проблемой: расширения не позволяют добавлять измерения в заимствованные регистры сведений (изменение структуры хранения данных заимствованных объектов ограничено).

В такой ситуации (если регистр независимый и в нем нет ссылки на документ) корректно связать запись и документ будет сложно. Вам придется полагаться на уникальность комбинации других измерений, что не всегда надежно.

Резюме

Подведем итог нашему исследованию задачи "Движения по существующему регистру из расширения":

  1. Если регистр подчинен регистратору: Сделать это "красиво" только расширением нельзя. Платформа не позволяет расширять тип Регистратор для объектов основной конфигурации. Либо снимайте конфигурацию с поддержки, либо создавайте свой "зеркальный" регистр в расширении.
  2. Если регистр независимый: Вы можете реализовать логику записи через подписки на события ОбработкаПроведения и ОбработкаУдаленияПроведения, используя объект НаборЗаписей. Это будет работать в расширении без проблем.

Понимая эти ограничения платформы, вы сможете выбрать наиболее подходящее архитектурное решение для вашей задачи, не тратя время на попытки реализовать невозможный код. А когда расширений в информационной базе становится много, для удобства администрирования можно использовать инструменты для групповой обработки расширений.

← На главную