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