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