Как в расширении 1С правильно доработать заполнение документа

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

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

Разбор проблемы: работа с коллекциями в памяти и по ссылке

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

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

Важное правило: при доработке заполнения всегда обращайтесь к коллекциям напрямую или через ЭтотОбъект. Рассмотрим пример правильного обращения в расширении:


&После("ЗаполнитьДокументНаОснованииЗаказа")
Процедура Рес_ЗаполнитьДокументНаОснованииЗаказа(Знач ЗаказКлиента)
    // Неправильно: Для каждого Стр Из Ссылка.Товары Цикл
    // Правильно:
    Для Каждого Стр Из Товары Цикл
        // Здесь мы работаем с данными, которые уже есть в памяти объекта
        Стр.Цена = 100; 
    КонецЦикла;
КонецПроцедуры

Заимствование метаданных и работа конфигуратора

Выясним причину, по которой конфигуратор может подчеркивать слово Товары красным и сообщать о неизвестном объекте. Это происходит потому, что расширение — это отдельный слой метаданных. Если табличная часть Товары не добавлена (не заимствована) в расширение, встроенный контроль синтаксиса и механизм «автокомплита» (подсказок кода) не будут видеть это свойство.

Несмотря на то, что код фактически отработает успешно во время выполнения (так как расширение в рантайме «сливается» с основной конфигурацией), для комфортной разработки рекомендуется заимствовать объекты:

  1. Найдите нужный документ в основной конфигурации.
  2. Нажмите правой кнопкой мыши и выберите «Добавить в расширение».
  3. В дереве расширения раскройте документ и добавьте необходимые табличные части и реквизиты.

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

Использование запросов в расширениях

Проанализируем ситуацию, когда для заполнения документа нам требуются данные из регистров сведений или накопления. Здесь возникает дилемма: переносить ли регистр в расширение целиком?

Если вы используете Конструктор запроса, вам обязательно нужно заимствовать регистр и все его измерения/реквизиты, к которым вы планируете обращаться. Без этого конструктор просто не увидит таблицы основной базы. Однако у этого подхода есть и обратная сторона: если в будущем в основной конфигурации изменится тип какого-либо реквизита, ваше расширение может войти в конфликт с основной конфигурацией при обновлении.

Существует альтернативный путь — написание текста запроса вручную (строкой). Рассмотрим пример:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
    |ИЗ
    |   РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, Номенклатура = &Номенклатура) КАК ЦеныНоменклатурыСрезПоследних";

Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("Номенклатура", Стр.Номенклатура);

В этом случае заимствовать регистр не обязательно. Код будет работать, но вы теряете проверку типов на этапе компиляции. Лучшей практикой считается использование конструктора в основной базе для получения текста запроса с последующим копированием этого текста в модуль расширения.

Модификация форм: визуально или программно?

Часто после заполнения реквизитов их нужно отобразить на форме. Разберем два подхода к добавлению элементов на форму через расширение:

  1. Визуальный способ: Заимствуем форму в расширение и мышкой перетаскиваем нужные поля. Это быстро и удобно. Но если в типовом решении фирма 1С удалит группу или изменит структуру формы, ваше расширение может выдать ошибку «Объект не найден» при открытии.
  2. Программный способ: Использование обработчика ПриСозданииНаСервере с аннотацией &После. Мы программно создаем элементы формы через ЭтотОбъект.Элементы.Добавить().

Проанализируем пример программного добавления поля:


&После("ПриСозданииНаСервере")
Процедура Рес_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Проверим, нет ли уже такого элемента (чтобы избежать дублей)
    Если Элементы.Найти("Рес_НовоеПоле") = Неопределено Тогда
        НовыйЭлемент = Элементы.Добавить("Рес_НовоеПоле", Тип("ПолеФормы"), Элементы.ГруппаШапка);
        НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
        НовыйЭлемент.ПутьКДанным = "Объект.Рес_ДополнительныйРеквизит";
    КонецЕсли;
КонецПроцедуры

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

Резюме и рекомендации

Для успешной доработки заполнения документа в расширении придерживайтесь следующих советов:

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

← На главную