Как изменить реквизит формы документа-основания при создании нового документа

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

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

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

Способ 1. Прямое обращение к открытой форме через Ключ

Проанализируем ситуацию, когда нам нужно изменить данные в форме основания непосредственно в момент открытия формы нового документа. Для этого мы можем попытаться найти форму родительского документа в памяти и обратиться к её данным. Этот метод удобен тем, что изменения происходят «на лету» без обязательной записи объекта в базу данных.

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

  1. Получаем ссылку на документ-основание.
  2. Ищем открытую форму этого документа по ключу ссылки.
  3. Если форма найдена и открыта, меняем значение реквизита через свойство Объект.

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


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

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

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

Способ 2. Использование механизма оповещений (Оповестить)

Более гибким и правильным с точки зрения архитектуры 1С является использование механизма оповещений. Выясним причину, по которой этот метод считается предпочтительным: он позволяет соблюсти принцип независимости объектов. Документ-приемник просто «сообщает» системе о событии, а форма-источник сама решает, как на это реагировать.

Разберем этот процесс по шагам:

Шаг 1. Отправка оповещения из формы нового документа. В модуле формы создаваемого документа (например, после успешной записи) вызываем метод Оповестить.


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

Шаг 2. Обработка в форме документа-основания. В форме «Заказа клиента» необходимо прописать обработчик события ОбработкаОповещения.


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

Способ 3. Изменение через серверный объект и метод Прочитать()

Проанализируем ситуацию, когда статус должен меняться строго при проведении документа-приемника, независимо от того, открыта форма основания или нет. В этом случае логику лучше перенести в модуль объекта или использовать подписки на события.

Однако здесь возникает проблема: если форма основания открыта, и мы программно изменим её объект на сервере, пользователь при попытке записи получит ошибку «Данные были изменены или удалены другим пользователем». Чтобы этого избежать, нужно использовать комбинацию методов.

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

Метод ОповеститьОбИзменении заставляет динамические списки и открытые формы перечитать данные из базы. В управляемом приложении форма сама может отследить это изменение. Если же автоматического обновления недостаточно, в ОбработкаОповещения формы заказа можно вызвать метод Прочитать(), который принудительно обновит данные объекта с сервера, синхронизировав версию данных.

Архитектурные рекомендации

Рассмотрим важные моменты, которые помогут сделать решение более надежным:

Подводя итог, можно сказать: если требуется чисто визуальное изменение в открытой форме — используйте ПолучитьФорму и прямой доступ к Объект. Если требуется надежная бизнес-логика — используйте оповещения и запись данных на сервере с последующим вызовом ОповеститьОбИзменении.

← На главную