Если после обновления конфигурации вариант универсального отчёта 1С не открывается, падает с ошибкой и даже не даёт сбросить настройки, почти всегда причина одна: в сохранённых настройках варианта есть ссылка на тип, которого в новой версии конфигурации уже нет. Чаще всего это объект, переименованный разработчиками с префиксом «Удалить». Лечится это исправлением XML настроек в справочнике ВариантыОтчетов: достаём настройки из хранилища значения как текст, меняем имя типа и записываем обратно.

Ниже — как диагностировать проблему, какой обработкой найти все сломанные варианты разом и как аккуратно их починить, не потеряв настройки пользователей.

Почему ломается вариант отчёта

В конфигурациях на БСП вариант отчёта — это элемент справочника ВариантыОтчетов. Его настройки компоновки лежат в реквизите Настройки типа ХранилищеЗначения, а внутри хранилища — объект НастройкиКомпоновкиДанных, сериализованный в XML.

В XML сохраняются не только поля и группировки, но и значения отборов и параметров вместе с их типами. Если пользователь когда-то поставил отбор по значению перечисления ВидыСтраховыхВзносовИП, в XML окажется ссылка на этот тип. Фирма «1С» при выводе объекта из употребления переименовывает его в УдалитьВидыСтраховыхВзносовИП. После обновления платформа читает XML, не находит тип по старому имени — и падает.

Почему не помогает «Сбросить настройки»: чтобы показать форму отчёта, БСП сначала читает настройки варианта, и ошибка возникает раньше, чем пользователь доберётся до кнопки.

Диагностика: где именно возникает ошибка

  1. Откройте базу в режиме отладки и включите «Остановку по ошибке».
  2. Откройте проблемный вариант.
  3. Отладчик остановится в обработчике загрузки хранилища вариантов отчётов (ХранилищаНастроек.ХранилищеВариантовОтчетов) на чтении настроек из хранилища.

В тексте ошибки обычно прямо указано имя типа, который не удалось найти. Сверьте его с деревом метаданных: если в конфигурации есть объект с тем же именем и префиксом «Удалить», диагноз подтверждён.

Простые варианты решения, которые стоит проверить первыми:

СитуацияЧто делать
Сломан один вариант, настройки несложныеПометить на удаление и создать заново
Сломаны пользовательские настройки, а не сам вариантОчистить настройки пользователя через «Настройки пользователей»
Сломаны десятки вариантов у разных пользователейИсправить XML обработкой (ниже)

Как достать XML из хранилища значения

Вызов Настройки.Получить() здесь не работает — он как раз пытается превратить XML в объект и падает. Нужно получить «сырое» содержимое хранилища, не десериализуя его.

Для этого подходит ЗначениеВСтрокуВнутр(). Для хранилища значения она возвращает служебную строку, внутри которой данные лежат в виде Base64 после маркера #base64:. Вырезаем этот фрагмент, превращаем в двоичные данные функцией Base64Значение() и читаем как текст.

Ремонт варианта отчёта 1С: от закрытого хранилища к читаемому XML настроек
Ремонт варианта отчёта 1С: от закрытого хранилища к читаемому XML настроек
1С
// Возвращает текст XML настроек из хранилища значения без десериализации.
// Если формат не распознан — Неопределено.
Функция ТекстНастроекИзХранилища(Хранилище)

	ВнутреннееПредставление = ЗначениеВСтрокуВнутр(Хранилище);

	Маркер = "#base64:";
	НачалоДанных = СтрНайти(ВнутреннееПредставление, Маркер);
	Если НачалоДанных = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	НачалоДанных = НачалоДанных + СтрДлина(Маркер);

	КонецДанных = СтрНайти(ВнутреннееПредставление, "}", , НачалоДанных);
	СтрокаBase64 = Сред(ВнутреннееПредставление, НачалоДанных, КонецДанных - НачалоДанных);
	СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ПС, "");

	ДвоичныеДанные = Base64Значение(СтрокаBase64);
	Текст = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, КодировкаТекста.UTF8);

	// Перед XML есть служебная вставка — отрезаем всё до объявления XML.
	НачалоXML = СтрНайти(Текст, "<?xml");
	Если НачалоXML = 0 Тогда
		Возврат Неопределено; // данные сжаты или в другом формате
	КонецЕсли;

	Возврат Сред(Текст, НачалоXML);

КонецФункции

Если функция вернула Неопределено из-за отсутствия <?xml, скорее всего хранилище было записано со сжатием: тогда текст XML напрямую не виден, и этот способ без доработки не подойдёт. В моих случаях с вариантами отчётов БСП данные читались без проблем, но проверяйте на своей базе.

Исправление и запись настроек

Когда XML в руках, остаётся заменить имя типа, прочитать XML в объект и записать вариант.

1С
// Исправляет настройки варианта отчёта, заменяя устаревшие имена типов.
// Замены — соответствие: старое полное имя типа -> новое.
Функция ИсправитьВариантОтчета(ВариантСсылка, Замены) Экспорт

	ВариантОбъект = ВариантСсылка.ПолучитьОбъект();
	ТекстXML = ТекстНастроекИзХранилища(ВариантОбъект.Настройки);
	Если ТекстXML = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;

	ИсходныйТекст = ТекстXML;
	Для Каждого Замена Из Замены Цикл
		ТекстXML = СтрЗаменить(ТекстXML, Замена.Ключ, Замена.Значение);
	КонецЦикла;

	Если ТекстXML = ИсходныйТекст Тогда
		Возврат Ложь; // заменять нечего
	КонецЕсли;

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(ТекстXML);
	НастройкиКомпоновки = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
	ЧтениеXML.Закрыть();

	ВариантОбъект.Настройки = Новый ХранилищеЗначения(НастройкиКомпоновки);
	ВариантОбъект.Записать();

	Возврат Истина;

КонецФункции

Пример вызова:

1С
Замены = Новый Соответствие;
Замены.Вставить("EnumRef.ВидыСтраховыхВзносовИП", "EnumRef.УдалитьВидыСтраховыхВзносовИП");

Обратите внимание на ключ замены. Если менять просто ВидыСтраховыхВзносовИП, то при повторном запуске обработки строка УдалитьВидыСтраховыхВзносовИП превратится в УдалитьУдалитьВидыСтраховыхВзносовИП. Поэтому заменяю полное имя типа с префиксом вида (EnumRef., CatalogRef. и т. п.) — перед этим посмотрите фактический текст XML, как именно тип в нём записан.

Как найти все сломанные варианты

Чинить по одному неудобно: после обновления обычно ломается сразу пачка вариантов у разных пользователей. Сломанный вариант легко определить — у него Настройки.Получить() вызывает исключение.

1С
// Возвращает массив ссылок на варианты, настройки которых не читаются.
Функция СломанныеВариантыОтчетов() Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ВариантыОтчетов.Ссылка КАК Ссылка,
	|	ВариантыОтчетов.Настройки КАК Настройки
	|ИЗ
	|	Справочник.ВариантыОтчетов КАК ВариантыОтчетов
	|ГДЕ
	|	ВариантыОтчетов.Пользовательский
	|	И НЕ ВариантыОтчетов.ПометкаУдаления";

	Результат = Новый Массив;
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Попытка
			Выборка.Настройки.Получить();
		Исключение
			Результат.Добавить(Выборка.Ссылка);
		КонецПопытки;
	КонецЦикла;

	Возврат Результат;

КонецФункции

Дальше по каждому варианту вызываем ИсправитьВариантОтчета и повторно проверяем Получить(). Если после замены вариант всё равно не читается, значит, в нём есть ещё один устаревший тип — текст исключения подскажет какой.

Типичные ошибки

  • Работа без резервной копии. Перед массовой правкой сделайте копию базы или хотя бы выгрузите настройки сломанных вариантов в файлы. Исправление необратимо.
  • Слишком широкая замена. Подстрока может встретиться в именах полей, представлениях, других типах. Меняйте полное имя типа.
  • Запуск под пользователем без прав. Справочник ВариантыОтчетов защищён правами; обработку запускают под администратором и на сервере.
  • Забыли про пользовательские настройки. Помимо варианта, у каждого пользователя могут быть свои сохранённые настройки этого варианта со старым типом. Если после починки варианта у кого-то ошибка осталась — очистите его пользовательские настройки отчёта.
  • Правка в рабочей базе в рабочее время. Запись вариантов во время формирования отчётов пользователями может вызвать конфликты блокировок.

Как не попадать в эту ситуацию

После каждого обновления я прогоняю проверочную обработку, которая пытается прочитать настройки всех пользовательских вариантов, и до выхода пользователей узнаю о проблеме. Это пять минут на этапе тестирования вместо волны обращений в понедельник. Такая проверка входит в мой регламент обновления 1С, а для клиентов на сопровождении выполняется автоматически.

Итог

  • Вариант отчёта ломается, когда в его XML-настройках есть тип, переименованный или удалённый при обновлении.
  • Настройки.Получить() использовать нельзя — нужно достать «сырой» XML через ЗначениеВСтрокуВнутр() и Base64.
  • Заменяйте полное имя типа, затем читайте XML через СериализаторXDTO.ПрочитатьXML() и записывайте новое хранилище.
  • Ищите сломанные варианты массово — попыткой чтения настроек в цикле.
  • Делайте резервную копию и проверяйте варианты сразу после обновления.