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

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

При разработке внешних печатных форм и обработок заполнения на базе БСП (Библиотеки стандартных подсистем) программисты часто сталкиваются с одной и той же проблемой. Рассмотрим типичную ситуацию: создается внешняя обработка для документа (например, табеля в конфигурации ЗУП 3.1). Пользователь открывает документ, вызывает обработку, она отрабатывает, данные в базе обновляются, но сама открытая форма документа остается в старом виде. Чтобы увидеть изменения, пользователю приходится закрывать и открывать документ заново, либо вручную нажимать кнопку «Перечитать».

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

Способ 1: Использование метода ОповеститьОбИзменении()

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

Посмотрим, как это работает: после того как на сервере объект был программно изменен и записан с помощью метода Записать(), нам необходимо на стороне клиента просигнализировать платформе об этом факте. Для этого используется метод ОповеститьОбИзменении().


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

При таком подходе платформа 1С автоматически разошлет сигнал всем связанным формам. Если форма документа открыта, она сама "поймет", что данные устарели, и инициирует перечитывание с сервера без дополнительных действий пользователя.

Способ 2: Работа напрямую с данными формы через ВладелецФормы

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

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


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

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

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


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

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

Способ 3: Программный вызов метода Прочитать()

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

Для этого у клиентских форм существует метод Прочитать(). Рассмотрим пример его безопасного использования с предварительной проверкой контекста:


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

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

Особенности работы со сложными формами (на примере ЗУП 3.1)

Разберем специфику конфигурации "Зарплата и Управление Персоналом 3.1". Документ "Табель" и многие другие кадровые и расчетные документы содержат сложное условное оформление, вычисляемые итоги и невидимые реквизиты, управляющие поведением интерфейса.

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


// ...после вызова ВладелецФормы.Прочитать()
ВладелецФормы.ОбновитьОтображениеДанных();

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

Резюме: Правильный алгоритм создания обработок заполнения в БСП

Подведем итоги и сформируем "best practice" (лучшую практику) для разработки внешних обработок заполнения:

  1. Всегда анализируйте параметры регистрации вашей обработки. Если вы используете Вид = "ЗаполнениеОбъекта", старайтесь использовать команду ТипКомандыЗаполнениеФормы() вместо вызова клиентского метода. В этом случае БСП сама передаст контекст формы на сервер.
  2. Если используете ТипКомандыВызовКлиентскогоМетода(), обязательно разделяйте логику работы. Если обработка запущена из списка — меняйте объекты в базе и используйте ОповеститьОбИзменении().
  3. Если обработка запущена из открытой формы документа (определяем через ВладелецФормы) — не записывайте объект в базу! Меняйте данные напрямую в реквизите ВладелецФормы.Объект. Это самый "чистый" и безопасный метод, который не приведет к блокировкам базы данных и ошибкам рассинхронизации версий объекта у пользователя.
← На главную