Как пометить на удаление проведенный документ через COM-соединение и избежать ошибки мутабельного значения

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

При интеграции различных систем с конфигурациями на базе 1С:Предприятие 8.3 часто используется механизм COM-соединения. Однако разработчики нередко сталкиваются со специфической ошибкой при попытке пометить на удаление именно проведенный документ. В то время как обычные (черновики) документы обрабатываются корректно, проведенные вызывают исключение: "Попытка передачи с клиента на сервер мутабельного значения 1-го параметра метода УдалитьДвиженияРегистратора". Разберем подробно, почему это происходит и как правильно решить данную задачу.

Анализируем причину возникновения ошибки

Для начала проанализируем ситуацию: почему код успешно отрабатывает для непроведенных документов, но спотыкается на проведенных? Причина кроется в архитектуре платформы и особенностях работы внешнего соединения. Когда мы вызываем метод УстановитьПометкуУдаления(Истина) для проведенного документа, платформа автоматически инициирует процесс отмены проведения. В этот момент управление передается в модуль объекта документа, а именно в обработчик ОбработкаУдаленияПроведения.

В типовых конфигурациях, таких как "Бухгалтерия предприятия 3.0", внутри этого обработчика часто вызываются методы общих модулей для очистки движений по регистрам (например, ОбщегоНазначенияБПВызовСервера.УдалитьДвиженияРегистратора). Проблема заключается в следующем:

  1. Контекст выполнения: COM-соединение работает в своем собственном контексте. При вызове серверного метода, не имеющего флага "Внешнее соединение", платформа пытается передать объект ДокументОбъект.
  2. Мутабельность: Объект документа является мутабельным (изменяемым). Платформа запрещает передачу таких объектов между клиентом (или внешним соединением) и сервером напрямую, если требуется сериализация.
  3. Отсутствие флагов: Если общий модуль, к которому обращается документ, помечен только как "Сервер" или "Вызов сервера", но у него не стоит галочка "Внешнее соединение", происходит попытка передачи объекта через границу контекстов, что и вызывает ошибку.

Рассмотрим типовой код, который обычно приводит к этой ошибке при выполнении через COM:


// Код на стороне вызывающей системы
Пока РезультатЗапроса.Следующий() Цикл
    НайденныйДокумент = РезультатЗапроса.Ссылка.ПолучитьОбъект();
    // Ошибка возникнет здесь, если документ проведен
    НайденныйДокумент.УстановитьПометкуУдаления(Истина); 
КонецЦикла;

Способ 1: Изменение свойств общего модуля (Быстрый путь)

Самый простой, но не всегда рекомендуемый метод — это изменение свойств метаданных в конфигурации-приемнике. Как было замечено в ходе обсуждения проблемы, включение флага "Внешнее соединение" у проблемного общего модуля решает вопрос. В случае с БП 3.0 это модуль ОбщегоНазначенияБПВызовСервера.

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

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

Способ 2: Использование режима ОбменДанными.Загрузка

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

Разберем, как это реализовать программно:


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

Важный нюанс: При установке ОбменДанными.Загрузка = Истина стандартная очистка регистров не произойдет автоматически. Если документ был проведен, его движения "зависнут" в регистрах, хотя сам документ будет помечен на удаление. Поэтому этот способ требует дополнительной очистки движений программным путем, если целостность данных критична.

Способ 3: Создание серверного "моста" (Рекомендуемый путь)

Наиболее правильным с точки зрения архитектуры 1С является перенос всей логики работы с объектом на сторону сервера конфигурации-приемника. Вместо того чтобы манипулировать объектом через COM напрямую, мы создаем специальную процедуру-обертку в своем собственном (не типовом) общем модуле.

Выполним следующие шаги:

  1. Создаем новый общий модуль, например, КастомныйМодульCOM.
  2. Устанавливаем ему флаги "Сервер" и "Внешнее соединение".
  3. Пишем в нем процедуру, которая принимает Ссылку, а не объект.

Пример кода в новом модуле:


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

Теперь из внешней системы через COM-соединение мы вызываем не стандартный метод объекта, а нашу новую процедуру:


// Код во внешней системе
COMСоединение.КастомныйМодульCOM.ПометитьДокументНаУдалениеНаСервере(СсылкаНаДокумент);

В этом случае передается только Ссылка (которая не является мутабельным значением и легко сериализуется), а создание объекта и вызов всех обработчиков (включая очистку движений) происходит внутри одного серверного вызова. Это исключает возникновение ошибки контекста.

Резюме

Выясним причину еще раз: ошибка "мутабельного значения" — это защитный механизм платформы 1С, предотвращающий некорректную передачу тяжелых объектов между клиентом/COM и сервером. При работе с проведенными документами эта проблема проявляется наиболее остро из-за срабатывания триггеров отмены проведения.

Подводя итог, при работе через COM-соединение старайтесь:

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

← На главную