В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача: при создании одного документа на основании другого (например, «Перемещения товаров» на основании «Заказа клиента») необходимо автоматически изменить статус или иной реквизит в родительском документе. При этом важно, чтобы изменения отобразились визуально, если форма родительского документа в данный момент открыта у пользователя.
Рассмотрим подробнее несколько способов реализации этой задачи, разберем их преимущества и возможные подводные камни, такие как блокировки данных и конфликты версий.
Проанализируем ситуацию, когда нам нужно изменить данные в форме основания непосредственно в момент открытия формы нового документа. Для этого мы можем попытаться найти форму родительского документа в памяти и обратиться к её данным. Этот метод удобен тем, что изменения происходят «на лету» без обязательной записи объекта в базу данных.
Для реализации этого подхода в коде формы создаваемого документа (например, в обработчике ПриОткрытии или после выполнения логики заполнения) мы используем следующий алгоритм:
Объект.Посмотрим на пример кода:
// Процедура в модуле формы нового документа (например, ПеремещениеТоваров)
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если ЗначениеЗаполнено(Объект.ДокументОснование) Тогда
// Формируем структуру параметров для поиска формы по ссылке
ПараметрыФормы = Новый Структура("Ключ", Объект.ДокументОснование);
// Пытаемся получить форму. Если она уже открыта, система вернет существующий экземпляр
ФормаОснования = ПолучитьФорму("Документы.ЗаказКлиента.Форма.ФормаОбъекта", ПараметрыФормы);
Если ФормаОснования.Открыта() Тогда
// Важно изменять именно реквизит Объект, а не элементы формы напрямую
ФормаОснования.Объект.Статус = ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.ВРаботе");
// Если на форме есть логика, зависящая от изменения статуса,
// можно вызвать экспортную процедуру формы основания
// ФормаОснования.ОбновитьСостояниеФормы();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важный нюанс: при таком подходе изменения в заказе клиента не будут сохранены в базе данных до тех пор, пока пользователь сам не нажмет кнопку «Записать» в форме заказа. Если он закроет заказ без сохранения, изменения статуса будут потеряны.
Более гибким и правильным с точки зрения архитектуры 1С является использование механизма оповещений. Выясним причину, по которой этот метод считается предпочтительным: он позволяет соблюсти принцип независимости объектов. Документ-приемник просто «сообщает» системе о событии, а форма-источник сама решает, как на это реагировать.
Разберем этот процесс по шагам:
Шаг 1. Отправка оповещения из формы нового документа. В модуле формы создаваемого документа (например, после успешной записи) вызываем метод Оповестить.
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
// Оповещаем всю систему о том, что на основании заказа создано перемещение
СтруктураПараметров = Новый Структура;
СтруктураПараметров.Вставить("Основание", Объект.ДокументОснование);
СтруктураПараметров.Вставить("НовыйСтатус", ПредопределенноеЗначение("Перечисление.СтатусыЗаказов.Отработано"));
Оповестить("ОбновлениеСтатусаЗаказа", СтруктураПараметров, ЭтаФорма);
КонецПроцедуры
Шаг 2. Обработка в форме документа-основания. В форме «Заказа клиента» необходимо прописать обработчик события ОбработкаОповещения.
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ОбновлениеСтатусаЗаказа" Тогда
// Проверяем, что оповещение касается именно текущего открытого документа
Если Параметр.Основание = Объект.Ссылка Тогда
Объект.Статус = Параметр.НовыйСтатус;
// Можно также вывести сообщение пользователю
ПоказатьОповещениеПользователя("Статус заказа изменен автоматически");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Проанализируем ситуацию, когда статус должен меняться строго при проведении документа-приемника, независимо от того, открыта форма основания или нет. В этом случае логику лучше перенести в модуль объекта или использовать подписки на события.
Однако здесь возникает проблема: если форма основания открыта, и мы программно изменим её объект на сервере, пользователь при попытке записи получит ошибку «Данные были изменены или удалены другим пользователем». Чтобы этого избежать, нужно использовать комбинацию методов.
ПриЗаписи меняем статус заказа в базе данных.ОповеститьОбИзменении(Объект.ДокументОснование).Метод ОповеститьОбИзменении заставляет динамические списки и открытые формы перечитать данные из базы. В управляемом приложении форма сама может отследить это изменение. Если же автоматического обновления недостаточно, в ОбработкаОповещения формы заказа можно вызвать метод Прочитать(), который принудительно обновит данные объекта с сервера, синхронизировав версию данных.
Рассмотрим важные моменты, которые помогут сделать решение более надежным:
ОбработкаЗаполнения выполняется на сервере. В ней удобно заполнять реквизиты нового документа, но изменять статус родительского документа «на лету» без записи рискованно, так как пользователь может отменить создание документа.ОткрытьФорму), можно передать текущую форму заказа как Владелец. Тогда в новой форме доступ к заказу можно получить через ЭтаФорма.ВладелецФормы, что упрощает взаимодействие без поиска по ключу.Подводя итог, можно сказать: если требуется чисто визуальное изменение в открытой форме — используйте ПолучитьФорму и прямой доступ к Объект. Если требуется надежная бизнес-логика — используйте оповещения и запись данных на сервере с последующим вызовом ОповеститьОбИзменении.