Ситуация, когда после очередного обновления конфигурации в сотнях или тысячах счетов-фактур пропадают ссылки на документы-основания, встречается достаточно часто. Особенно остро эта проблема проявляется в отраслевых решениях (например, в линейке «1С:Подрядчик строительства»), созданных на базе типовой конфигурации «1С:Бухгалтерия предприятия 3.0». Ручная привязка оснований в тысячах документов нереализуема на практике, поэтому разберем причины произошедшего сбоя и эффективные технические способы восстановления данных из резервной копии.
Проанализируем механику платформы «1С:Предприятие», чтобы понять, куда исчезли данные. Документ-основание для счета-фактуры хранится в реквизите составного ссылочного типа, а в актуальных редакциях «1С:Бухгалтерии предприятия» — в табличной части ДокументыОснования (реквизит ДокументОснование).
Если в процессе обновления конфигурации состав типов этого реквизита изменился, платформа ведет себя следующим образом:
cfu от стандартной «Бухгалтерии предприятия»), специфические отраслевые документы исключаются из состава типов реквизитов типовых объектов.NULL непосредственно в таблицах базы данных. Сами документы-основания остаются в базе, но связь со счетами-фактурами безвозвратно теряется.Важное предостережение: если составной тип был урезан, ни выгрузка-загрузка, ни правила «Конвертации данных» не помогут вернуть ссылки до тех пор, пока тип данных не будет возвращен в конфигураторе. Любая попытка записать ссылку недопустимого типа приведет к ошибке или повторной очистке поля.
Разберем первоочередные действия, без которых дальнейший перенос данных лишен смысла:
СчетФактураВыданный и СчетФактураПолученный.ДокументОснование (в шапке документа) и к реквизиту ДокументОснование табличной части ДокументыОснования.Теперь структура базы данных снова готова хранить ссылки на нужные типы объектов, но поля в базе остаются пустыми. Приступаем к их восстановлению из архивной копии, сделанной до обновления.
Самый надежный и прозрачный способ связать счета-фактуры с их основаниями — использовать уникальные идентификаторы (GUID). Уникальные идентификаторы документов в рабочей базе и в копии совпадают, что исключает ошибки сопоставления по номерам или датам.
Рассмотрим алгоритм восстановления с использованием прямого подключения к базе-архиву через COM-соединение. Если база работает на ОС Windows, создадим внешнюю обработку в рабочей базе со следующим кодом:
// Подключаемся к архивной базе данных
V83Connector = Новый COMConnector;
СтрокаПодключения = "Srvr=""ServerName"";Ref=""ArchiveBase"";Usr=""Admin"";Pwd=""Password"";";
Попытка
БазаАрхив = V83Connector.Connect(СтрокаПодключения);
Исключение
ВызватьИсключение "Не удалось подключиться к архиву: " + ОписаниеОшибки();
КонецПопытки;
// Выбираем основания из архивной базы
ЗапросАрхива = БазаАрхив.NewObject("Запрос");
ЗапросАрхива.Текст =
"ВЫБРАТЬ
| СФ.Ссылка КАК СсылкаСФ,
| Основания.ДокументОснование КАК ДокументОснование,
| Основания.НомерСтроки КАК НомерСтроки
|ИЗ
| Документ.СчетФактураВыданный КАК СФ
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетФактураВыданный.ДокументыОснования КАК Основания
| ПО СФ.Ссылка = Основания.Ссылка
|ГДЕ
| Основания.ДокументОснование ССЫЛКА Документ.АктПриемкиВыполненныхРабот"; // Указываем нужный тип
Выборка = ЗапросАрхива.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем строковые представления GUID из архива
УИД_СФ = БазаАрхив.String(Выборка.СсылкаСФ.UUID());
УИД_Основания = БазаАрхив.String(Выборка.ДокументОснование.UUID());
ИмяТипаОснования = Выборка.ДокументОснование.Metadata().Name;
// Ищем документы в текущей рабочей базе
СсылкаСФТекущая = Документы.СчетФактураВыданный.ПолучитьСсылку(Новый УникальныйИдентификатор(УИД_СФ));
МенеджерОснования = Документы[ИмяТипаОснования];
СсылкаОснованиеТекущая = МенеджерОснования.ПолучитьСсылку(Новый УникальныйИдентификатор(УИД_Основания));
// Модифицируем документ без проверок проведения и дат запрета
СФОбъект = СсылкаСФТекущая.ПолучитьОбъект();
Если СФОбъект <> Неопределено Тогда
СФОбъект.ОбменДанными.Загрузка = Истина;
// Очищаем или дополняем табличную часть
НоваяСтрока = СФОбъект.ДокументыОснования.Добавить();
НоваяСтрока.ДокументОснование = СсылкаОснованиеТекущая;
// Если реквизит также дублируется в шапке
СФОбъект.ДокументОснование = СсылкаОснованиеТекущая;
СФОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецЕсли;
КонецЦикла;
Обратим особое внимание на строку СФОбъект.ОбменДанными.Загрузка = Истина;. Использование этого режима обязательно по нескольким причинам:
Если прямое COM-подключение недоступно (например, база работает на сервере под управлением Linux), применим двухэтапный перенос через текстовый файл формата JSON.
В базе-архиве сформируем файл со списком соответствий:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СФ.Ссылка КАК СсылкаСФ,
| Основания.ДокументОснование КАК Основание
|ИЗ
| Документ.СчетФактураВыданный.ДокументыОснования КАК Основания
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетФактураВыданный КАК СФ
| ПО Основания.Ссылка = СФ.Ссылка";
Выборка = Запрос.Выполнить().Выбрать();
СписокДанных = Новый Массив;
Пока Выборка.Следующий() Цикл
Элемент = Новый Структура;
Элемент.Вставить("УИД_СФ", Строка(Выборка.СсылкаСФ.УникальныйИдентификатор()));
Элемент.Вставить("УИД_Основания", Строка(Выборка.Основание.УникальныйИдентификатор()));
Элемент.Вставить("ВидОснования", Выборка.Основание.Метаданные().Имя);
СписокДанных.Добавить(Элемент);
КонецЦикла;
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ОткрытьФайл("C:\temp\bases.json");
ЗаписатьJSON(ЗаписьJSON, СписокДанных);
ЗаписьJSON.Закрыть();
После выгрузки прочитаем полученный файл в рабочей базе и восстановим связи по GUID аналогично коду из предыдущего шага, используя объект ЧтениеJSON.
Нередко возникает соблазн выполнить быструю команду UPDATE напрямую в базе данных СУБД, перенеся колонки из восстановленной копии. Делать этого категорически не рекомендуется:
_TYPE), ссылка (_RREF) и смещение номера строки.Использование штатных механизмов платформы (COM, чтение JSON или обработка «Выгрузка и загрузка данных XML») в сочетании со свойством ОбменДанными.Загрузка = Истина является самым безопасным и быстрым способом вернуть пропавшие документы-основания на свои места.