Как установить значение в табличную часть открытого документа из внешней обработки в 1С 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

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

Способ 1. Передача контекста через параметры формы (Классический метод)

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

Рассмотрим по шагам реализацию этого механизма.

Шаг 1. Вызов внешней обработки из формы документа

В модуле формы документа (например, при нажатии на кнопку или при событии ПриНачалеРедактированияСтроки) мы открываем обработку модально и передаем текущий контекст:


// Пример вызова из формы документа
Процедура ПриНачалеРедактированияСтроки(ИмяРеквизита, ФлагВхода)
    Если ИмяРеквизита = "Товар" Тогда
        // Запрещаем стандартное редактирование в ячейке
        ФлагВхода = 0; 
        
        // Передаем контекст текущего документа в параметре
        ОткрытьФормуМодально("Отчет", Контекст, "ПутьКНашейОбработке\ЗаполнениеТЧ.ert");
    КонецЕсли;
КонецПроцедуры

Шаг 2. Прием контекста и изменение данных во внешней обработке

В модуле внешней обработки (в процедуре ПриОткрытии) мы считываем переданный параметр и сохраняем его в локальную переменную модуля, чтобы иметь доступ к документу из любой процедуры обработки:


Переменная КонтДокумента; // Переменная модуля для хранения контекста

Процедура ПриОткрытии()
    // Проверяем, передан ли параметр формы
    Если ТипЗначенияСтр(Форма.Параметр) = "Контекст" Тогда
        КонтДокумента = Форма.Параметр;
    Иначе
        Предупреждение("Обработка может быть запущена только из формы документа!");
        СтатусВозврата(0);
        Возврат;
    КонецЕсли;
КонецПроцедуры

Теперь мы можем изменить реквизит табличной части непосредственно в строке, на которой сейчас стоит курсор в документе-инициаторе. Для этого достаточно обратиться к реквизиту через полученный контекст:


Процедура ЗаписатьЗначениеИЗакрыть()
    // Присваиваем значение реквизиту текущей строки документа
    КонтДокумента.Товар = ВыбранноеЗначениеТовара;
    КонтДокумента.Цена = ВыбраннаяЦена;
    
    // Принудительно обновляем форму документа для визуализации изменений
    КонтДокумента.Форма.Обновить(0);
    
    // Закрываем внешнюю обработку
    Закрыть();
КонецПроцедуры

Важное примечание: при изменении реквизитов через КонтДокумента.Реквизит = Значение данные изменяются в текущей активной строке табличной части. Метод Форма.Обновить(0) гарантирует перерисовку экрана без записи самого документа в базу данных.

Способ 2. Передача контекста и номера строки через СписокЗначений

Иногда при работе с контекстом в 1С 7.7 возникает проблема: если пользователь переключит фокус или во внешней обработке произойдет позиционирование, текущая строка документа может "сброситься". Чтобы гарантировать заполнение именно той строки, из которой была вызвана обработка, передадим во внешнюю форму не просто контекст, а структуру данных через СписокЗначений.

Давайте проанализируем этот код:


// Код в модуле формы документа
Процедура ВызватьОбработку()
    ПараметрыПередачи = СоздатьОбъект("СписокЗначений");
    ПараметрыПередачи.Установить("Контекст", Контекст);
    ПараметрыПередачи.Установить("НомерСтроки", НомерСтроки); // Запоминаем текущий номер строки
    
    ОткрытьФормуМодально("Отчет", ПараметрыПередачи, "ПутьКНашейОбработке\ЗаполнениеТЧ.ert");
КонецПроцедуры

В самой обработке мы извлекаем переданные параметры и строго позиционируемся на нужной строке перед изменением данных:


Переменная КонтДокумента;
Переменная НомСтроки;

Процедура ПриОткрытии()
    Параметры = Форма.Параметр;
    Если ТипЗначенияСтр(Параметры) = "СписокЗначений" Тогда
        КонтДокумента = Параметры.Получить("Контекст");
        НомСтроки = Параметры.Получить("НомерСтроки");
    КонецЕсли;
КонецПроцедуры

Процедура ЗаполнитьЯчейку()
    // Позиционируем документ на нужной строке по ее уникальному номеру
    КонтДокумента.ПолучитьСтрокуПоНомеру(НомСтроки);
    
    // Заполняем реквизиты
    КонтДокумента.Товар = ВыбранныйТовар;
    КонтДокумента.Форма.Обновить(0);
    Закрыть();
КонецПроцедуры

Способ 3. Использование механизма "ОбработкаОжидания" (Альтернативный хак)

Существуют ситуации, когда прямое изменение реквизитов через переданный контекст не вызывает автоматические формулы пересчета колонок табличной части (например, когда при изменении количества должна пересчитываться сумма или НДС, прописанные в формулах ячеек визуальной формы документа). Для обхода этой проблемы опытные разработчики используют асинхронный запуск процедур документа через ОбработкаОжидания.

Разберем этот изящный алгоритм по шагам:

  1. В форме документа на невидимый слой (или просто на форму) помещаются служебные реквизиты, например: СлужебныйТовар и СлужебныйНомерСтроки.
  2. В модуле формы документа пишется локальная процедура, которая считывает данные из этих служебных реквизитов, выполняет заполнение строки табличной части и запускает все необходимые пересчеты.
  3. В начале этой локальной процедуры обязательно отключается обработка ожидания с помощью вызова Форма.ОбработкаОжидания("", 0).
  4. Внешняя обработка при закрытии записывает нужные значения в служебные реквизиты формы документа напрямую через контекст и вешает обработку ожидания на подготовленную локальную процедуру документа с интервалом в 1 секунду.

Посмотрим на программную реализацию этого механизма.

Код в модуле формы документа-инициатора:


// Локальная процедура, которая выполнит заполнение и штатные пересчеты
Процедура ЗаполнитьСтрокуПоСлужебнымРеквизитам()
    // Первым делом отключаем обработку ожидания, чтобы процедура не зациклилась
    Форма.ОбработкаОжидания("ЗаполнитьСтрокуПоСлужебнымРеквизитам", 0);
    
    // Позиционируемся и вносим изменения
    ПолучитьСтрокуПоНомеру(СлужебныйНомерСтроки);
    Товар = СлужебныйТовар;
    
    // Имитируем интерактивный пересчет (вызываем штатную функцию пересчета ТЧ)
    РассчитатьСуммуСтроки(); 
    Форма.Обновить(0);
КонецПроцедуры

Код во внешней обработке при нажатии кнопки «Выполнить»:


Процедура ВыполнитьЗаполнение()
    // Записываем данные в служебные реквизиты документа через сохраненный контекст
    КонтДокумента.СлужебныйТовар = ВыбранныйТовар;
    КонтДокумента.СлужебныйНомерСтроки = НомСтроки;
    
    // Запускаем в форме документа обработчик ожидания, который сработает через 1 секунду
    КонтДокумента.Форма.ОбработкаОжидания("ЗаполнитьСтрокуПоСлужебнымРеквизитам", 1);
    
    Закрыть();
КонецПроцедуры

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

Способ 4. Вызов локальных процедур формы через FormEx и 1С++

Если в вашей системе используются популярные внешние компоненты расширения платформы FormEx или 1С++, вы можете вызывать любые локальные процедуры модуля формы документа напрямую из внешней обработки без использования костылей с обработками ожидания.

Для этого используется объект Сервис из библиотеки FormEx. Разберем пример вызова локальной процедуры расчета суммы:


Процедура ЗаписатьИПересчитать()
    // Меняем значения напрямую в контексте документа
    КонтДокумента.Количество = 10;
    КонтДокумента.Цена = 150;
    
    // Создаем объект Сервис для работы с недокументированными возможностями
    СервисКомпоненты = СоздатьОбъект("Сервис");
    
    // Выполняем локальную процедуру формы документа "ПриИзмененииЦены" 
    // так, будто ее вызвал сам документ в своем контексте
    СервисКомпоненты.ВыполнитьПроцедуру(КонтДокумента, "ПриИзмененииЦены");
    
    КонтДокумента.Форма.Обновить(0);
    Закрыть();
КонецПроцедуры

Этот метод является наиболее профессиональным и чистым с точки зрения кода, однако он требует обязательной регистрации внешних ВК (FormEx.dll или 1cpp.dll) на клиентских компьютерах пользователей.

Важные правила безопасности при работе с контекстом

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

Мы рассмотрели все основные и альтернативные варианты решения задачи. Выбирайте наиболее подходящий под стандарты разработки в вашей компании и делайте работу пользователей удобной и быстрой!

← На главную