Как свернуть табличную часть документа из внешней обработки?

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

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

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

Разбор проблемы: клиент-серверное взаимодействие

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

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

Способ №1: Передача коллекции данных формы на сервер

Этот способ является наиболее легким и предпочтительным, если вам нужно изменить только одну конкретную таблицу, не затрагивая логику всего документа. Объект типа ДанныеФормыКоллекция (которым является табличная часть на форме) доступен на сервере как параметр.

Проанализируем шаги реализации (учитывая, что иногда требуется программное изменение форм):

  1. На клиенте получаем ссылку на табличную часть через ВладелецФормы.
  2. Передаем её в серверную процедуру.
  3. На сервере выгружаем данные в промежуточную таблицу значений, сворачиваем её и загружаем обратно.

Рассмотрим пример кода:


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

&НаСервереБезКонтекста
Процедура СвернутьТЧНаСервере(ДанныеТЧ)
    // ДанныеФормыКоллекция имеет метод Выгрузить(), работающий на сервере
    Таблица = ДанныеТЧ.Выгрузить();
    
    // Выполняем группировку: КолонкиГруппировки, КолонкиСуммирования
    Таблица.Свернуть("Номенклатура, Характеристика, Цена", "Количество, Сумма");
    
    // Очищаем и загружаем свернутые данные обратно
    ДанныеТЧ.Загрузить(Таблица);
КонецПроцедуры

Важный нюанс: метод Свернуть() удаляет все колонки, которые не были перечислены в параметрах. Если в вашей табличной части есть важные служебные поля (например, КлючСвязи), обязательно включите их в список группировки.

Способ №2: Полная конвертация объекта (ДанныеФормыВЗначение)

Иногда логика свертки требует обращения к методам самого документа или проверки общих итогов. в этом случае удобнее работать не с коллекцией, а с полноценным объектом ДокументОбъект.

Выясним, как это работает через преобразование типов:


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

Преимущество этого метода в том, что после ЗначениеВДанныеФормы в основной форме документа обновятся не только строки таблицы, но и все зависимые реквизиты (например, итоговая сумма документа), если они пересчитываются в модуле объекта.

Работа над ошибкой «Данные изменены или удалены другим пользователем»

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

Разберем, как правильно синхронизировать состояние:

  1. Не используйте запись в базу: Если ваша цель — дать пользователю увидеть результат и самому нажать «Записать», работайте только с данными формы.
  2. Обновление отображения: Чтобы форма владельца корректно перерисовала изменения, используйте метод ВладелецФормы.ОбновитьДанныеФормы().
  3. Модифицированность: Обязательно устанавливайте ВладелецФормы.Модифицированность = Истина, чтобы система предложила сохранить изменения при закрытии документа.

Использование метода КопироватьДанныеФормы

В современных конфигурациях для передачи изменений между разными формами (обработкой и документом) рекомендуется использовать метод КопироватьДанныеФормы(Источник, Приемник). Это наиболее безопасный способ обновления структуры данных 1С.

Посмотрим на пример финальной реализации в модуле формы обработки:


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

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

← На главную