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

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

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

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

В чем причина разрыва контекста и отсутствия строк в форме?

Основная ошибка заключается в получении нового экземпляра объекта через ссылку внутри обработки. Проанализируем ошибочный фрагмент кода:


Процедура ЗаполнитьТЧ()
    Док = СсылкаНаОбъект.ПолучитьОбъект();
    // Заполнение строк в переменную Док...
    Док.Записать();
КонецПроцедуры

Выясним, что происходит на уровне платформы 1С при таком подходе:

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

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

Вариант 1. Возврат данных из формы обработки в процедуру «Инициализировать»

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

Разберем по шагам реализацию данного варианта.

В модуле объекта внешней обработки заполнения ТЧ прописываем экспортную процедуру:


Процедура Инициализировать(Объект, ИмяТабличнойЧасти = Неопределено, ТабличноеПолеОбъекта = Неопределено) Экспорт

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

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

В модуле формы обработки по нажатию кнопки «Выполнить» подготавливаем результат и закрываем форму с передачей данных:


Процедура КнопкаВыполнитьНажатие(Кнопка)

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

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

Вариант 2. Передача контекста объекта в форму обработки

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

  1. В форме обработки создаем реквизит формы ДокументОбъект (тип произвольный или соответствующий типу документа).
  2. В процедуре Инициализировать передаем входящий Объект в этот реквизит перед открытием.
  3. В процедуре нажатия кнопки «Выполнить» производим добавление строк напрямую в ДокументОбъект.

В модуле объекта обработки:


Процедура Инициализировать(Объект, ИмяТабличнойЧасти = Неопределено, ТабличноеПолеОбъекта = Неопределено) Экспорт

    ФормаОбработки = ЭтотОбъект.ПолучитьФорму("Форма");
    ФормаОбработки.ДокументОбъект = Объект;
    ФормаОбработки.ОткрытьМодально();

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

В модуле формы обработки:


Процедура КнопкаВыполнитьНажатие(Кнопка)

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

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

Особенности обновления интерфейса и заполнения реквизитов

При работе с обычными формами обратите внимание на следующие нюансы:

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