При работе с крупными конфигурациями, такими как 1С:ERP Управление предприятием 2 или 1С:Комплексная автоматизация 2, разработчики часто сталкиваются с необходимостью изменить стандартную логику проведения документов. Типичная задача: добавить в табличную часть документа новое поле и сделать так, чтобы при проведении значение из этого поля попадало в ресурс регистра сведений вместо (или вместе) с типовым значением.
В этой статье мы подробно разберем, как реализовать такую задачу на примере документа РегистрацияЗемельныхУчастков и одноименного регистра сведений. Мы проанализируем внутреннее устройство механизмов проведения в современных конфигурациях и выберем наиболее оптимальный способ доработки.
Прежде чем приступать к написанию кода, давайте разберем, чем проведение в ERP отличается от проведения в старых конфигурациях (например, УПП 1.3). В современных решениях на базе Библиотеки Стандартных Подсистем (БСП) используется так называемая "запросная" модель проведения. Это означает, что движения формируются не путем перебора строк табличной части в цикле, а с помощью выполнения пакета запросов.
Основные этапы этой модели выглядят так:
ОбработкаПроведения.ПроведениеСерверУТ), который инициирует сбор данных.Понимание этой схемы крайне важно: если вы будете пытаться менять движения "по старинке" в модуле объекта, вы можете столкнуться с тем, что ваши изменения будут перезаписаны типовым механизмом или приведут к ошибкам производительности.
Как мы выяснили, основной код формирования данных для движений находится в модуле менеджера документа. В случае с документом РегистрацияЗемельныхУчастков нас интересует одноименная процедура. Давайте рассмотрим пример кода, который подготавливает данные для записи в регистр.
Проанализируем типовой запрос, который извлекает данные из табличной части ОС документа:
Процедура РегистрацияЗемельныхУчастков(ТекстыЗапроса, Регистры)
ИмяРегистра = "РегистрацияЗемельныхУчастков";
Если Не ПроведениеСерверУТ.ТребуетсяТаблицаДляДвижений(ИмяРегистра, Регистры) Тогда
Возврат;
КонецЕсли;
Текст =
"ВЫБРАТЬ
| &Ссылка КАК Регистратор,
| &Дата КАК Период,
| &Организация КАК Организация,
| ТабличнаяЧастьДокумента.ОсновноеСредство КАК ОсновноеСредство,
| ИСТИНА КАК ВключатьВНалоговуюБазу,
| ТабличнаяЧастьДокумента.КадастроваяСтоимость КАК КадастроваяСтоимость,
| // ... остальные поля ...
|ИЗ
| Документ.РегистрацияЗемельныхУчастков.ОС КАК ТабличнаяЧастьДокумента
|ГДЕ
| ТабличнаяЧастьДокумента.Ссылка = &Ссылка";
ТекстыЗапроса.Добавить(Текст, ИмяРегистра, Истина);
КонецПроцедуры
Чтобы реализовать выбор между типовым полем и вашим новым полем (например, МояКадастроваяСтоимость), нам нужно использовать оператор ВЫБОР прямо в тексте запроса. Предположим, условием является заполненность нового поля.
Рассмотрим, как изменить фрагмент запроса:
| ВЫБОР
| КОГДА ТабличнаяЧастьДокумента.МояКадастроваяСтоимость <> 0
| ТОГДА ТабличнаяЧастьДокумента.МояКадастроваяСтоимость
| ИНАЧЕ ТабличнаяЧастьДокумента.КадастроваяСтоимость
| КОНЕЦ КАК КадастроваяСтоимость,
Важный нюанс: поскольку ERP находится на поддержке, мы не должны менять типовой код напрямую. Для внесения изменений используйте Расширение конфигурации. В расширении используйте аннотацию &ИзменениеИКонтроль для процедуры модуля менеджера. Это позволит вам точечно заменить текст запроса, сохранив остальную логику нетронутой.
Если логика выбора значения слишком сложна для реализации в SQL-запросе (например, требуются сложные вычисления на встроенном языке), можно воспользоваться методом "подмены" данных в самом объекте перед его проведением. Рассмотрим этот вариант подробнее.
В модуле объекта документа в событии ПередЗаписью (или в ОбработкаПроведения до начала формирования движений) мы можем программно заполнить типовое поле значением из нашего нового поля. Тогда типовой запрос в модуле менеджера просто "подхватит" уже готовое значение.
Пример реализации в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
Для Каждого СтрокаОС Из ОС Цикл
Если ЗначениеЗаполнено(СтрокаОС.МоеНовоеПоле) Тогда
// Подменяем типовое значение перед тем, как механизм проведения его прочитает
СтрокаОС.КадастроваяСтоимость = СтрокаОС.МоеНовоеПоле;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Плюсы этого метода: простота реализации и отсутствие необходимости править сложные запросы в модуле менеджера.
Минусы: данные в табличной части документа будут изменены физически. Если пользователю важно видеть в поле КадастроваяСтоимость одно значение, а в регистр передавать другое — этот метод не подойдет, так как он затирает исходные данные в документе.
Иногда возникает вопрос: можно ли использовать подписку на событие ПередЗаписью самого регистра сведений? Технически — да, но для задач проведения документов в ERP это наименее предпочтительный вариант.
Разберем причины, почему так делать не стоит:
Использовать подписку стоит только в том случае, если вам нужно принудительно менять данные во всех документах системы, которые пишут в этот регистр, независимо от их типа.
Проанализировав ситуацию, мы пришли к выводу, что для 1С:ERP наиболее правильным и "чистым" решением является модификация текста запроса в модуле менеджера через расширение.
Давайте закрепим последовательность действий:
РегистрацияЗемельныхУчастков и его модуль менеджера.&ИзменениеИКонтроль, чтобы внедрить логику ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ в секцию ВЫБРАТЬ запроса.Такой подход гарантирует, что типовые механизмы контроля (например, проверка на дублирование записей в регистре сведений) отработают корректно, а ваши изменения не "слетят" при первом же обновлении конфигурации.