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