Как программно заполнить ячейки в табличной части документа в 1С:УНФ с помощью внешней обработки?

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

При разработке расширений функционала для 1С:Управление нашей фирмой (УНФ) одной из наиболее частых задач является автоматизация заполнения табличных частей. Типичный сценарий: пользователю нужно, чтобы при нажатии кнопки в документе «Расходный ордер» или «Приходная накладная» поле Ячейка автоматически заполнялось значением основной ячейки, указанной в карточке номенклатуры. В этой статье мы подробно разберем, как правильно спроектировать такую обработку, избежав распространенных ошибок с контекстом выполнения и обновлением экранных данных.

Разберем основную проблему: почему код «не работает»

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

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

Проектирование обработки по стандартам БСП

Современная конфигурация УНФ построена на Библиотеке стандартных подсистем (БСП). Чтобы ваша обработка корректно встроилась в меню «Заполнение», она должна иметь определенную структуру в модуле объекта. Рассмотрим обязательную функцию СведенияОВнешнейОбработке, которая регистрирует наш инструмент в системе:


Функция СведенияОВнешнейОбработке() Экспорт
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
    ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта();
    ПараметрыРегистрации.Наименование = "Заполнение ячеек по умолчанию";
    ПараметрыРегистрации.Информация = "Обработка заполняет поле Ячейка в ТЧ Запасы из карточки номенклатуры";
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.БезопасныйРежим = Ложь;

    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = "Заполнить ячейки из номенклатуры";
    НоваяКоманда.Идентификатор = "ЗаполнитьЯчейкиКоманда";
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
    НоваяКоманда.ПоказыватьОповещение = Истина;

    Возврат ПараметрыРегистрации;
КонецФункции

Обратите внимание на тип команды: ТипКомандыВызовКлиентскогоМетода(). Это критически важно, так как позволяет нам получить доступ к форме документа-владельца без необходимости предварительного сохранения объекта в базу данных.

Реализация логики в форме обработки

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

Шаг 1: Получение данных владельца на клиенте. Разберем по шагам процедуру ВыполнитьКоманду в модуле формы обработки:


&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
    
    // Получаем объект документа из формы владельца
    ОбъектДокумента = ВладелецФормы.Объект;
    
    // Вызываем серверную процедуру для обработки данных
    ЗаполнитьДанныеНаСервере(ОбъектДокумента);
    
    // Копируем измененные данные обратно в форму владельца
    КопироватьДанныеФормы(ОбъектДокумента, ВладелецФормы.Объект);
    
    // Оповещаем пользователя
    ПоказатьОповещениеПользователя("Готово", , "Ячейки успешно заполнены");

КонецПроцедуры

Шаг 2: Обработка данных на сервере. Теперь проанализируем ситуацию на стороне сервера. Здесь нам нужно обойти каждую строку табличной части и извлечь данные из справочника номенклатуры. Важно помнить, что обращение через точку ТекСтрока.Номенклатура.Ячейка на сервере работает эффективно, так как 1С оптимизирует такие запросы.


&НаСервереБезКонтекста
Процедура ЗаполнитьДанныеНаСервере(ДанныеФормы)
    
    Для Каждого СтрокаЗапасы Из ДанныеФормы.Запасы Цикл
        // Проверяем, заполнена ли номенклатура, чтобы избежать пустых ссылок
        Если ЗначениеЗаполнено(СтрокаЗапасы.Номенклатура) Тогда
            // Присваиваем ячейку из реквизитов справочника Номенклатура
            // Предполагается, что в УНФ используется реквизит 'Ячейка' (Основная ячейка)
            СтрокаЗапасы.Ячейка = СтрокаЗапасы.Номенклатура.Ячейка;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Важные нюансы и подводные камни

Рассмотрим подробнее несколько технических моментов, которые часто упускают из виду:

  1. Обновление итогов: При программном изменении ячеек итоги документа обычно не меняются, но если ваша обработка меняет цены или количество, обязательно вызывайте пересчет суммы. В УНФ для этого существуют экспортные процедуры в модулях менеджеров документов.
  2. Складской контекст: Помните, что ячейка в номенклатуре — это лишь «предпочтительное» место хранения. Проанализируем ситуацию: если в документе выбран «Склад А», а в номенклатуре указана ячейка, принадлежащая «Складу Б», проведение документа может завершиться ошибкой. Рекомендуется добавить проверку на соответствие ячейки выбранному складу.
  3. Обработчики событий: Как верно подмечено в сообщениях форума, программное присвоение значения реквизиту Ячейка не вызывает выполнение кода в процедуре ЯчейкаПриИзменении на форме документа. Если в этой процедуре заложена сложная логика (например, проверка остатков), её придется продублировать в коде обработки.

Использование метода ОповеститьОбИзменении

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

ОповеститьОбИзменении(Тип("ДокументСсылка.РасходныйОрдер"));

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

Таким образом, создание надежной обработки заполнения ТЧ требует понимания жизненного цикла данных в управляемом приложении. Использование данных формы вместо прямой работы с объектами базы данных позволяет достичь высокой скорости работы и корректного отображения изменений «на лету».

← На главную