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

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

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

Анализ проблемы и причин ошибки

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


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

Проанализируем, почему этот подход приводит к ошибке и некорректен с точки зрения архитектуры платформы 1С:

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

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

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

Посмотрим на базовый пример исправления процедуры на сервере:


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

Оптимизация клиент-серверного взаимодействия

Рассмотрим более надежный и оптимизированный вариант реализации. Для уменьшения объема передаваемых данных между клиентом и сервером рекомендуется использовать директиву &НаСервереБезКонтекста, передавая на сервер только необходимые значения через параметры. Кроме того, после записи объекта на сервере полезно оповестить открытые формы и динамические списки об изменении данных с помощью клиентского метода ОповеститьОбИзменении.

Посмотрим на пример комплексной реализации:


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

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

Рекомендации при программной записи документов

При программном редактировании документов из обработок следует учитывать несколько важных нюансов:

  1. Режим проведения документа: если документ уже был проведен, стандартный вызов ДокументОбъект.Записать() перезапишет его в режиме обычной записи без формирования или пересчета движений. Если требуется обновить движения, явно передавайте параметр РежимЗаписиДокумента.Проведение.
  2. Флаг загрузки данных: если выполняется техническая корректировка и не требуется выполнять проверки в модуле объекта (события ПередЗаписью, ОбработкаПроверкиЗаполнения), можно установить свойство ДокументОбъект.ОбменДанными.Загрузка = Истина перед вызовом метода Записать().
  3. Блокировки и обработка ошибок: при групповой обработке или работе в многопользовательском режиме рекомендуется использовать конструкцию Попытка ... Исключение и явные транзакции (НачатьТранзакцию() / ЗафиксироватьТранзакцию()), чтобы избежать частичной записи некорректных данных при возникновении конфликтов блокировок.
← На главную