Как правильно реализовать подписку на событие «Обработка проведения» в конфигурациях УТ 11, КА и ERP?

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

При работе с современными типовыми конфигурациями на базе платформы 1С:Предприятие 8.3, такими как ERP Управление предприятием, Комплексная автоматизация или Управление торговлей 11, программисты часто сталкиваются с проблемой: стандартная подписка на событие ОбработкаПроведения работает не так, как ожидается. Это связано с тем, что архитектура проведения в этих системах существенно отличается от старых версий (например, УПП или УТ 10.3). В этой статье мы разберем, почему обычные подписки могут быть неэффективны и как правильно дорабатывать механизмы формирования движений.

В чем заключается сложность «Проведения 2.0»?

В современных конфигурациях используется механизм, который часто называют «Проведение 2.0». Его главная особенность — отделение логики подготовки данных от физической записи в регистры. Рассмотрим типовую схему работы процедуры ОбработкаПроведения в модуле документа:

  1. Вызывается ИнициализироватьДополнительныеСвойстваДляПроведения. Здесь создается структура ДополнительныеСвойства, в которой будут храниться все данные для движений.
  2. Вызывается ИнициализироватьДанныеДокумента (обычно в модуле менеджера). Программа выполняет тяжелые запросы и подготавливает временные таблицы в памяти сервера.
  3. Вызывается ПодготовитьНаборыЗаписейКРегистрацииДвижений.
  4. И, наконец, выполняется ЗаписатьНаборыЗаписей и ВыполнитьКонтрольРезультатовПроведения.

Проблема подписки на ОбработкаПроведения заключается в том, что она срабатывает после выполнения основного кода в модуле документа. К этому моменту наборы записей уже сформированы, записаны в базу данных, и, что самое критичное, контроль остатков уже выполнен. Если мы добавим свои движения в подписке, система просто не «увидит» их при проверке отрицательных остатков, либо нам придется инициировать контроль заново, что крайне негативно скажется на производительности системы.

Решение 1: Использование подписки с повторной инициализацией данных

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


Процедура ОбработкаПроведенияРеализацияТоваровУслуг(Источник, Отказ, РежимПроведения) Экспорт
    
    Ссылка = Источник.Ссылка;
    ДополнительныеСвойства = Источник.ДополнительныеСвойства;
    Движения = Источник.Движения;
    
    // Инициализируем менеджер временных таблиц для работы запросов модуля менеджера
    ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
    
    // Повторно вызываем подготовку данных (это «тяжелая» операция)
    Документы.РеализацияТоваровУслуг.ИнициализироватьДанныеДокумента(Ссылка, ДополнительныеСвойства);
    
    // Вызываем процедуры отражения в нужных регистрах
    ВзаиморасчетыСервер.ОтразитьРасчетыСПоставщиками(ДополнительныеСвойства, Движения, Отказ);
    ДоходыИРасходыСервер.ОтразитьПрочиеРасходы(ДополнительныеСвойства, Движения, Отказ);
    
    // Если нужно добавить движения в управленческий баланс
    Если ПолучитьФункциональнуюОпцию("ФормироватьУправленческийБаланс") Тогда
        УправленческийУчетПроведениеСервер.ДобавитьДвиженияАктивовПассивов(Источник);
    КонецЕсли;
    
КонецПроцедуры

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

Решение 2: Подписка на событие «Перед записью» набора записей регистра

Если ваша задача состоит в том, чтобы изменить логику формирования движений по конкретному регистру (например, РасчетыСКлиентами) для всех документов системы, более правильным будет использование подписки на событие ПередЗаписью соответствующего набора записей регистра накопления.

Разберем алгоритм этого подхода:

  1. Создаем подписку на событие ПередЗаписью для объекта РегистрНакопленияНаборЗаписей.ИмяРегистра.
  2. В обработчике проверяем свойство НаборЗаписей.ОбменДанными.Загрузка. Если это истина — выходим.
  3. Проверяем, что регистратором является нужный нам тип документа через НаборЗаписей.Отбор.Регистратор.Значение.
  4. Модифицируем строки внутри коллекции ЭтотОбъект (который и является набором записей).

Этот метод хорош тем, что он «вклинивается» в процесс записи данных непосредственно перед тем, как они попадут в базу, и типовой контроль остатков (который обычно выполняется после записи) увидит ваши изменения. Однако здесь есть минус: в наборе записей у вас нет доступа к реквизитам документа-объекта напрямую, их придется дочитывать запросом.

Решение 3: Использование расширений (рекомендуемый способ)

С появлением и развитием механизма расширений конфигурации, использование подписок для модификации проведения в ERP/УТ стало «крайней мерой». Рассмотрим наиболее элегантный и производительный способ — перехват процедуры подготовки данных в модуле менеджера.

Выясним причину, почему это лучше: вклиниваясь в процедуру ИнициализироватьДанныеДокумента с помощью аннотации &После, мы можем модифицировать таблицы значений, которые лежат в ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы. Система сама подхватит ваши измененные данные и запишет их в регистры штатным кодом.

Проанализируем пример расширения модуля менеджера:


&После("ИнициализироватьДанныеДокумента")
Процедура Моя_ИнициализироватьДанныеДокумента(Ссылка, ДополнительныеСвойства)
    
    // Получаем доступ к подготовленным временным таблицам
    ТаблицыДанных = ДополнительныеСвойства.ДляПроведения.СтруктураВременныеТаблицы;
    
    // Например, нам нужно подправить таблицу для регистра «ВыручкаИСебестоимостьПродаж»
    Если ТаблицыДанных.Свойство("ТаблицаВыручкаИСебестоимостьПродаж") Тогда
        ТаблицаДвижений = ТаблицыДанных.ТаблицаВыручкаИСебестоимостьПродаж;
        Для Каждого СтрокаДвижения Из ТаблицаДвижений Цикл
            // Выполняем свою логику корректировки
            СтрокаДвижения.СуммаВыручки = СтрокаДвижения.СуммаВыручки * 1.1; 
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

Преимущества использования расширения:

Подведем итоги

Рассмотрим краткое резюме по выбору метода доработки:

  1. Если вам нужно добавить движения в совершенно новый (ваш) регистр — используйте обычную подписку на ОбработкаПроведения. Это безопасно и не мешает типовым механизмам.
  2. Если вам нужно изменить данные в типовых регистрах — используйте расширение модуля менеджера и вклинивайтесь в подготовку временных таблиц.
  3. Если по каким-то причинам расширения использовать нельзя — используйте подписку на ПередЗаписью набора записей регистра, но помните о необходимости дочитывать данные регистратора.

Помните, что архитектура ERP требует аккуратного отношения к транзакциям и производительности. Всегда проверяйте свои доработки замером производительности, особенно при массовом проведении документов.

← На главную