Иногда при сопровождении конфигураций сторонних разработчиков или доработанных типовых решений мы сталкиваемся с модулями объектов без исходного текста (с признаком «Исходный текст модуля отсутствует»). Если в таком закрытом модуле в процедуре ПередЗаписью разработчики установили безусловный запрет на снятие пометки удаления и забыли предусмотреть проверку свойства ОбменДанными.Загрузка = Истина, штатное изменение объекта становится невозможным.
Разберем детально, почему стандартные средства платформы в виде подписок на события здесь бессильны, и какие существуют практические способы решения данной проблемы.
Проанализируем поведение платформы при вызове событий объекта. Первым делом у многих возникает идея создать подписку на событие ПередЗаписью и принудительно переопределить параметр Отказ = Ложь.
Однако в платформе 1С соблюдается строгий порядок выполнения цепочки событий:
Если внутри модуля объекта параметр Отказ устанавливается в значение Истина, платформа немедленно прерывает выполнение транзакции и цепочки обработки. Обработчики подписок на событие ПередЗаписью в этом случае даже не вызываются, поэтому программно сбросить отказ через расширение или подписку не удастся.
Кроме того, механизм расширений конфигурации с аннотациями &Вместо или &ИзменениеИКонтроль также неприменим к методам модулей, поставляемых без исходного текста.
Если логика закрытого модуля проверяет именно факт изменения существующего объекта (например, сравнивает Ссылка.ПометкаУдаления = Истина и ЭтотОбъект.ПометкаУдаления = Ложь), то запись нового объекта обычно не блокируется.
Рассмотрим, как можно программно пересоздать объект с сохранением его исходного уникального идентификатора:
Удалить().УстановитьСсылкуНового().Посмотрим на пример программного кода:
// Получаем исходный объект и его идентификатор
ОбъектСсылка = ВыбранныйЭлементСсылка;
Идентификатор = ОбъектСсылка.УникальныйИдентификатор();
ИсходныйОбъект = ОбъектСсылка.ПолучитьОбъект();
// Сохраняем значения реквизитов (например, для справочника)
СтруктураРеквизитов = Новый Структура;
СтруктураРеквизитов.Вставить("Наименование", ИсходныйОбъект.Наименование);
СтруктураРеквизитов.Вставить("Код", ИсходныйОбъект.Код);
// Удаляем старый объект без проверок
ИсходныйОбъект.Удалить();
// Создаем новый объект с тем же UUID
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
НовыйОбъект.УстановитьСсылкуНового(Справочники.Номенклатура.ПолучитьСсылку(Идентификатор));
ЗаполнитьЗначенияСвойств(НовыйОбъект, СтруктураРеквизитов);
НовыйОбъект.ПометкаУдаления = Ложь;
НовыйОбъект.Записать();
Если конфигурация доступна для редактирования (находится на поддержке с возможностью изменения), можно физически удалить или заменить тело проблемного закрытого модуля без использования специализированных утилит.
Разберем по шагам алгоритм действий:
После этого модуль станет открытым для редактирования либо полностью очистится от блокирующего кода.
Если конфигурацию изменять нельзя, остается вариант изменения данных на уровне СУБД. В таблицах СУБД за признак пометки удаления отвечает колонка _Marked (где 0x00 — пометка снята, 0x01 — пометка установлена).
Однако при выполнении прямого SQL-запроса UPDATE необходимо учитывать критические риски:
ragent._ChangeRec*). Объект не будет выгружен в другие узлы при следующей синхронизации.Наиболее корректным и безопасным способом для рабочей базы данных является обращение к разработчику закрытого модуля с запросом исправления ошибки и добавления корректной проверки:
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если оперативная связь с разработчиком невозможна, прибегают к восстановлению исходного текста модуля с помощью специализированных утилит дешифрации модулей 1С, после чего вносят необходимые правки непосредственно в код обработчика события.