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

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет Промышленность, строительство и АПК
← На главную

Ситуация, когда после очередного обновления конфигурации в сотнях или тысячах счетов-фактур пропадают ссылки на документы-основания, встречается достаточно часто. Особенно остро эта проблема проявляется в отраслевых решениях (например, в линейке «1С:Подрядчик строительства»), созданных на базе типовой конфигурации «1С:Бухгалтерия предприятия 3.0». Ручная привязка оснований в тысячах документов нереализуема на практике, поэтому разберем причины произошедшего сбоя и эффективные технические способы восстановления данных из резервной копии.

Выясняем причину: почему очистились ссылки на основания

Проанализируем механику платформы «1С:Предприятие», чтобы понять, куда исчезли данные. Документ-основание для счета-фактуры хранится в реквизите составного ссылочного типа, а в актуальных редакциях «1С:Бухгалтерии предприятия» — в табличной части ДокументыОснования (реквизит ДокументОснование).

Если в процессе обновления конфигурации состав типов этого реквизита изменился, платформа ведет себя следующим образом:

  1. Установка типового релиза поверх отраслевого: если отраслевую базу обновили файлом поставки типовой конфигурации (например, применили cfu от стандартной «Бухгалтерии предприятия»), специфические отраслевые документы исключаются из состава типов реквизитов типовых объектов.
  2. Физическое удаление данных при реструктуризации: когда из составного типа реквизита исключается определенный вид документа, при сохранении конфигурации базы данных платформа физически заменяет ссылки на такие документы значением NULL непосредственно в таблицах базы данных. Сами документы-основания остаются в базе, но связь со счетами-фактурами безвозвратно теряется.
  3. Сбой отложенного обновления данных: при переходе на новые механизмы БСП часть переноса связей между документами выполняется регламентными заданиями. Если процедура обновления завершилась аварийно, ссылки могут не отображаться. Проверить это можно через раздел Администрирование — Обслуживание — Результаты обновления программы.

Важное предостережение: если составной тип был урезан, ни выгрузка-загрузка, ни правила «Конвертации данных» не помогут вернуть ссылки до тех пор, пока тип данных не будет возвращен в конфигураторе. Любая попытка записать ссылку недопустимого типа приведет к ошибке или повторной очистке поля.

Шаг 1. Восстановление метаданных в конфигураторе

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

  1. Открываем рабочую базу в режиме «Конфигуратор».
  2. Находим документы СчетФактураВыданный и СчетФактураПолученный.
  3. Переходим к реквизиту ДокументОснование (в шапке документа) и к реквизиту ДокументОснование табличной части ДокументыОснования.
  4. Открываем окно редактирования свойства Тип.
  5. Находим в списке отраслевые документы (акты подрядчика, КС-2, КС-3 и другие прикладные документы) и устанавливаем напротив них флажки.
  6. Выполняем обновление конфигурации базы данных (клавиша F7).

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

Шаг 2. Восстановление связей через программное сопоставление по УИД

Самый надежный и прозрачный способ связать счета-фактуры с их основаниями — использовать уникальные идентификаторы (GUID). Уникальные идентификаторы документов в рабочей базе и в копии совпадают, что исключает ошибки сопоставления по номерам или датам.

Рассмотрим алгоритм восстановления с использованием прямого подключения к базе-архиву через COM-соединение. Если база работает на ОС Windows, создадим внешнюю обработку в рабочей базе со следующим кодом:


// Подключаемся к архивной базе данных
V83Connector = Новый COMConnector;
СтрокаПодключения = "Srvr=""ServerName"";Ref=""ArchiveBase"";Usr=""Admin"";Pwd=""Password"";";
Попытка
    БазаАрхив = V83Connector.Connect(СтрокаПодключения);
Исключение
    ВызватьИсключение "Не удалось подключиться к архиву: " + ОписаниеОшибки();
КонецПопытки;

// Выбираем основания из архивной базы
ЗапросАрхива = БазаАрхив.NewObject("Запрос");
ЗапросАрхива.Текст = 
"ВЫБРАТЬ
|	СФ.Ссылка КАК СсылкаСФ,
|	Основания.ДокументОснование КАК ДокументОснование,
|	Основания.НомерСтроки КАК НомерСтроки
|ИЗ
|	Документ.СчетФактураВыданный КАК СФ
|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетФактураВыданный.ДокументыОснования КАК Основания
|		ПО СФ.Ссылка = Основания.Ссылка
|ГДЕ
|	Основания.ДокументОснование ССЫЛКА Документ.АктПриемкиВыполненныхРабот"; // Указываем нужный тип

Выборка = ЗапросАрхива.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    // Получаем строковые представления GUID из архива
    УИД_СФ = БазаАрхив.String(Выборка.СсылкаСФ.UUID());
    УИД_Основания = БазаАрхив.String(Выборка.ДокументОснование.UUID());
    ИмяТипаОснования = Выборка.ДокументОснование.Metadata().Name;
    
    // Ищем документы в текущей рабочей базе
    СсылкаСФТекущая = Документы.СчетФактураВыданный.ПолучитьСсылку(Новый УникальныйИдентификатор(УИД_СФ));
    
    МенеджерОснования = Документы[ИмяТипаОснования];
    СсылкаОснованиеТекущая = МенеджерОснования.ПолучитьСсылку(Новый УникальныйИдентификатор(УИД_Основания));
    
    // Модифицируем документ без проверок проведения и дат запрета
    СФОбъект = СсылкаСФТекущая.ПолучитьОбъект();
    Если СФОбъект <> Неопределено Тогда
        СФОбъект.ОбменДанными.Загрузка = Истина;
        
        // Очищаем или дополняем табличную часть
        НоваяСтрока = СФОбъект.ДокументыОснования.Добавить();
        НоваяСтрока.ДокументОснование = СсылкаОснованиеТекущая;
        
        // Если реквизит также дублируется в шапке
        СФОбъект.ДокументОснование = СсылкаОснованиеТекущая;
        
        СФОбъект.Записать(РежимЗаписиДокумента.Запись);
    КонецЕсли;
КонецЦикла;

Шаг 3. Использование флага «ОбменДанными.Загрузка = Истина»

Обратим особое внимание на строку СФОбъект.ОбменДанными.Загрузка = Истина;. Использование этого режима обязательно по нескольким причинам:

  1. Обход даты запрета изменения данных: счета-фактуры за закрытые периоды не позволят записать себя в обычном интерактивном режиме.
  2. Сохранение движений регистров: флаг отключает обработчики проведения и валидацию данных, предотвращая автоматический пересчет движений по НДС, регистров учета и книг покупок/продаж.
  3. Высокая скорость обработки: запись 5000 документов в режиме загрузки займет считанные секунды, тогда как стандартная запись с проверками может занять часы.

Альтернативный вариант: перенос через выгрузку в промежуточный файл (JSON)

Если прямое COM-подключение недоступно (например, база работает на сервере под управлением Linux), применим двухэтапный перенос через текстовый файл формата JSON.

В базе-архиве сформируем файл со списком соответствий:


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

Выборка = Запрос.Выполнить().Выбрать();
СписокДанных = Новый Массив;

Пока Выборка.Следующий() Цикл
    Элемент = Новый Структура;
    Элемент.Вставить("УИД_СФ", Строка(Выборка.СсылкаСФ.УникальныйИдентификатор()));
    Элемент.Вставить("УИД_Основания", Строка(Выборка.Основание.УникальныйИдентификатор()));
    Элемент.Вставить("ВидОснования", Выборка.Основание.Метаданные().Имя);
    СписокДанных.Добавить(Элемент);
КонецЦикла;

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ОткрытьФайл("C:\temp\bases.json");
ЗаписатьJSON(ЗаписьJSON, СписокДанных);
ЗаписьJSON.Закрыть();

После выгрузки прочитаем полученный файл в рабочей базе и восстановим связи по GUID аналогично коду из предыдущего шага, используя объект ЧтениеJSON.

Почему не стоит править таблицы напрямую в SQL

Нередко возникает соблазн выполнить быструю команду UPDATE напрямую в базе данных СУБД, перенеся колонки из восстановленной копии. Делать этого категорически не рекомендуется:

  1. Реквизиты составного типа в таблицах 1С разделяются на три поля: код типа (_TYPE), ссылка (_RREF) и смещение номера строки.
  2. При обновлении конфигурации внутренние коды типов в словаре метаданных базы могут измениться.
  3. Прямое вмешательство нарушит внутренний кэш объектов платформы и при первом же тестировании и исправлении базы приведет к ошибкам нарушения ссылочной целостности.

Использование штатных механизмов платформы (COM, чтение JSON или обработка «Выгрузка и загрузка данных XML») в сочетании со свойством ОбменДанными.Загрузка = Истина является самым безопасным и быстрым способом вернуть пропавшие документы-основания на свои места.

← На главную