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

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

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

Суть проблемы

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

Алгоритм, который использовал автор, выглядит следующим образом:

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

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

Давайте проанализируем два способа решения этой задачи: «архитектурно правильный» (без лишней записи в БД) и «прямой» (с перечитыванием после записи).

Способ 1. Изменение данных формы (Рекомендуемый)

Самый правильный подход при создании обработок заполнения — не записывать документ в базу данных принудительно, а менять данные непосредственно в открытой форме. Это позволяет пользователю увидеть изменения, проверить их и самому нажать кнопку «Записать и закрыть».

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

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


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

Преимущества этого метода:

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

Способ 2. Принудительное перечитывание (Если запись необходима)

Если алгоритм вашей задачи требует обязательной записи документа в базу данных (например, создаются связанные движения или документы), то подход меняется. После того как ваш серверный код записал изменения в БД, клиентская форма всё еще "не знает" об этом.

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

Посмотрим, как должен выглядеть код в этом случае:


// 1. Серверная процедура, которая меняет и ЗАПИСЫВАЕТ документ
&НаСервере
Процедура ЗаполнитьИЗаписатьНаСервере(ДокСсылка)
    
    ДокОбъект = ДокСсылка.ПолучитьОбъект();
    
    // ... какие-то изменения данных ...
    ДокОбъект.Товары.Очистить();
    // ...
    
    // Запись в базу данных
    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
    
КонецПроцедуры

// 2. Клиентская процедура кнопки
&НаКлиенте
Процедура ВыполнитьОбработку(Команда)
    
    // Получаем ссылку на документ из владельца
    СсылкаНаДокумент = ВладелецФормы.Объект.Ссылка;
    
    // Выполняем изменения и запись на сервере
    ЗаполнитьИЗаписатьНаСервере(СсылкаНаДокумент);
    
    // ВАЖНО: Обновляем данные в форме владельца из базы данных
    ВладелецФормы.Прочитать();
    
    // Опционально: обновить отображение (условное оформление и доступность)
    ВладелецФормы.ОбновитьОтображениеДанных();
    
    Закрыть();
    
КонецПроцедуры

Важные нюансы:

Использование механизма оповещений

В теме также упоминался метод ОповеститьОбИзменении(Ссылка). Это глобальный метод, который посылает сигнал всем открытым формам, отображающим данные указанной ссылки.


&НаКлиенте
Процедура ПослеЗаписи(Команда)
    // ... код записи ...
    ОповеститьОбИзменении(СсылкаНаДокумент);
КонецПроцедуры

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

Резюме

Подведем итог. Чтобы пользователь увидел изменения, сделанные внешней обработкой, у вас есть два пути:

  1. Лучший вариант: Не записывать документ программно. Обращаться к ВладелецФормы.Объект и менять данные коллекций напрямую. Это быстро и безопасно.
  2. Альтернативный вариант: Если запись неизбежна, после выполнения серверного кода вызовите на клиенте метод ВладелецФормы.Прочитать().
← На главную