Как реализовать заполнение табличной части документа «Заказ поставщику» из внешней обработки?

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

При разработке расширений функционала для типовых конфигураций 1С (таких как УТ 11, ERP 2.5 или КА) часто возникает задача создания удобного интерфейса подбора товаров. Стандартные механизмы не всегда удовлетворяют потребности бизнеса, поэтому программисты прибегают к созданию внешних обработок заполнения. Рассмотрим ситуацию, когда нам необходимо из внешней обработки, содержащей «Корзину» товаров, перенести данные в документ ЗаказПоставщику, не прибегая к изменению типовой конфигурации.

Анализ механизма БСП для внешних обработок

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

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

Способ №1: Прямое заполнение через ВладелецФормы (Рекомендуемый)

Это наиболее эффективный метод, так как он позволяет изменять данные «на лету» в оперативной памяти, пока пользователь еще не нажал кнопку «Записать» в документе. Проанализируем, как должен выглядеть код в модуле формы внешней обработки.

Рассмотрим процедуру переноса данных. Вместо того чтобы пытаться вернуть структуру через оповещение (которое требует наличия обработчика в самом документе), мы обратимся напрямую к объекту формы-владельца. Выясним, как это реализовать программно:


&НаКлиенте
Процедура ПеренестиВДокумент(Команда)
    
    // Проверим, что обработка открыта из формы документа
    Если ВладелецФормы = Неопределено Тогда
        Возврат;
    КонецЕсли;

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

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

Способ №2: Использование механизма «ОбработкаВыбора»

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

Разберем алгоритм действий:

  1. В форме обработки вызываем ОповеститьОВыборе(ТаблицаСДанными).
  2. В форме документа в событии ОбработкаВыбора принимаем эти данные.

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


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

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

Способ №3: Заполнение через объектную модель на сервере

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

Алгоритм работы будет следующим:

  1. Передаем ссылку на текущий документ в реквизит обработки.
  2. На сервере получаем объект документа по ссылке.
  3. Заполняем табличную часть.
  4. Записываем объект.
  5. Оповещаем форму документа о необходимости обновить данные.

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


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

&НаКлиенте
Процедура ПеренестиВДокумент(Команда)
    
    ЗаполнитьДокументНаСервере(Объект.ДокументСсылка);
    
    // Оповещаем систему об изменении объекта, чтобы открытые формы обновились
    Оповестить("Запись_ЗаказПоставщику", , Объект.ДокументСсылка);
    
    Закрыть();
    
КонецПроцедуры

Как обеспечить пересчет итогов в документе?

При программном заполнении через ВладелецФормы (Способ №1) крайне важно, чтобы в документе пересчитались суммы. В современных конфигурациях на платформе 1С 8.3 (УТ 11, ERP) для этого используются экспортные методы в модуле формы документа. Выясним, как их вызвать:

После цикла добавления строк в процедуре ПеренестиВДокумент, попробуем обратиться к методам владельца:


// Попытка вызвать типовой пересчет (названия процедур могут отличаться в разных версиях)
Попытка
    ВладелецФормы.Подключаемый_ПересчитатьСуммы();
Исключение
    // Если метод недоступен, можно вызвать стандартное оповещение об изменении данных
    ВладелецФормы.ОповеститьОбИзмененииРеквизита("Объект.Товары");
КонецПопытки;

Проанализируем ситуацию с «Безопасным режимом». В коде регистрации автора указано БезопасныйРежим = Ложь. Это абсолютно верно для данной задачи. В безопасном режиме 1С ограничивает использование ВладелецФормы для изменения данных и вызов многих интерактивных методов. При установке обработки в базу через справочник «Дополнительные отчеты и обработки» обязательно проверьте, что флаг безопасного режима снят, иначе прямое заполнение может быть заблокировано системой.

Резюме по решению проблемы

Для успешного переноса товара из «Корзины» внешней обработки в «Заказ поставщику» без изменения конфигурации выполним следующие шаги:

  1. Убедимся, что форма обработки открывается с указанием владельца (это происходит автоматически при использовании команды ВызовКлиентскогоМетода в БСП).
  2. В процедуре переноса используем обращение ВладелецФормы.Объект.Товары.
  3. После заполнения устанавливаем ВладелецФормы.Модифицированность = Истина.
  4. Для обновления визуальных итогов (Сумма, НДС) инициируем пересчет через экспортные процедуры формы документа или через оповещение об изменении реквизитов.

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

← На главную