Как исправить ошибку «ВидКонтактнойИнформации указан несколько раз» при обмене УТ 11.2 – БП 3.0?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При ведении учета в связке конфигураций 1С:Управление торговлей (УТ) и 1С:Бухгалтерия предприятия (БП) пользователи часто сталкиваются со сбоями синхронизации данных. Одна из типичных проблем старых релизов (например, УТ 11.2) при обмене через универсальный формат (EnterpriseData) — ошибка загрузки данных в БП 3.0 с текстом: «Вид контактной информации полученного объекта указан несколько раз. Загрузка невозможна» или «ВидКонтактнойИнформации указан несколько раз».

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

---

Выясняем причину возникновения ошибки

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

Когда эта опция включена, при изменении адреса организации старая запись не заменяется новой. Вместо этого в базе сохраняются обе записи с заполнением реквизита ДействуетС (дата начала действия адреса). Это позволяет системе знать, какой адрес был у компании, например, год назад, и выводить его в печатные формы старых документов.

Проблема кроется в механизме выгрузки данных. В устаревших правилах обмена УТ 11.2 (за которые отвечает модуль МенеджерОбменаЧерезУниверсальныйФормат, в частности процедура ДобавитьПКО_Справочник_Организации_Отправка) выборка контактной информации выполняется простым запросом к табличной части или регистру сведений без учета среза последних. Модуль обмена выбирает все когда-либо созданные записи юридического адреса для организации.

В результате в XML-файле выгрузки формируется дублирующий блок данных:


<Справочник.Организации>
    <КонтактнаяИнформация>
        <Строка>
            <ВидКонтактнойИнформации>ЮридическийАдрес</ВидКонтактнойИнформации>
            <ЗначенияПолей>АдресЮридическийСтарый</ЗначенияПолей>
        </Строка>
        <Строка>
            <ВидКонтактнойИнформации>ЮридическийАдрес</ВидКонтактнойИнформации>
            <ЗначенияПолей>АдресЮридическийНовый</ЗначенияПолей>
        </Строка>
    </КонтактнаяИнформация>
</Справочник.Организации>

Принимающая сторона — 1С:Бухгалтерия предприятия 3.0 — ожидает увидеть в рамках одного объекта строго уникальные типы контактной информации. Получив две строки с типом ЮридическийАдрес, БП выдает ошибку и полностью блокирует загрузку пакета данных.

---

Способ 1. Очистка истории адреса в пользовательском интерфейсе

Если для вашей организации не критично хранение старого (неактуального) юридического адреса в базе УТ, самым простым и быстрым решением будет удаление исторической записи. Для этого выполним следующие шаги:

  1. Перейдем в раздел НСИ и администрирование — Сведения об организации (или откроем карточку организации через справочник «Организации»).
  2. Найдем поле Юридический адрес и нажмем на кнопку выбора (три точки) или на значок лупы для открытия формы ввода адреса.
  3. В открывшейся форме найдем кнопку Еще в правом верхнем углу и выберем пункт История изменений (в некоторых релизах кнопка «История» вынесена непосредственно на форму адреса).
  4. В списке исторических записей мы увидим несколько строк: старый адрес с прошедшей датой действия и новый адрес.
  5. Выделим строку со старым адресом, нажмем по ней правой кнопкой мыши и выберем команду Удалить.
  6. Сохраним изменения в карточке организации.

После удаления старой записи в базе останется только один актуальный адрес. Повторная выгрузка сформирует корректный XML-файл, и обмен в БП пройдет без ошибок.

---

Способ 2. Отключение хранения истории адресов в настройках системы

Если вы хотите предотвратить появление подобных ошибок в будущем при последующих изменениях адресов, можно полностью отключить ведение истории для юридического адреса. Рассмотрим, как это сделать:

  1. Перейдем в раздел НСИ и администрирование — Общие настройки.
  2. Развернем группу параметров Контактная информация и перейдем по гиперссылке Виды контактной информации.
  3. В открывшемся списке найдем группу Контактная информация справочника "Организации".
  4. Найдем и откроем элемент Юридический адрес.
  5. В форме настройки вида контактной информации найдем флаг Хранить историю изменений (или «Редактировать вместе с историей») и снимем его.
  6. Запишем и закроем элемент. При отключении опции система может выдать предупреждение и предложить свернуть существующую историю — соглашаемся с этим.

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

---

Способ 3. Программная фильтрация дублей через расширение конфигурации

Что делать, если конфигурация УТ сильно доработана (как в случае автора темы, где изменено более 100 объектов), обновлять её нельзя, но история адресов в базе обязательно должна вестись? В таком случае мы можем использовать механизм расширений конфигурации, чтобы не снимать основную конфигурацию с поддержки.

Нам необходимо скорректировать алгоритм заполнения табличной части контактной информации при формировании XML-выгрузки. Рассмотрим пример кода, который можно внедрить в расширение для фильтрации выгружаемых записей:


&После("ДобавитьПКО_Справочник_Организации_Отправка")
Процедура Расш_ДобавитьПКО_Справочник_Организации_Отправка(ПравилаКонвертации)
    // Данный обработчик выполняется после инициализации ПКО.
    // Нам нужно перехватить алгоритм выборки данных и отфильтровать ТЧ КонтактнаяИнформация.
КонецПроцедуры

Для точечного исправления в самом правиле конвертации объектов (ПКО) найдем процедуру, отвечающую за выборку контактной информации организации. Нам нужно добиться того, чтобы перед записью данных в выгрузку табличная часть КонтактнаяИнформация организации сворачивалась, оставляя только запись с максимальной датой ДействуетС. Реализовать это можно следующим алгоритмом фильтрации таблицы значений:


// Пример алгоритма для сворачивания истории КИ перед отправкой:
ТаблицаКИ = Источник.КонтактнаяИнформация.Выгрузить();

// Сортируем таблицу по Виду (возрастание) и Дате действия (убывание)
ТаблицаКИ.Сортировать("Вид Возрастание, ДействуетС Убывание");

ПредыдущийВид = Неопределено;
ИндексыДляУдаления = Новый Массив;

Для Каждого СтрокаКИ Из ТаблицаКИ Цикл
    Если СтрокаКИ.Вид = ПредыдущийВид Тогда
        // Так как таблица отсортирована по ДействуетС убыванию, 
        // все последующие строки с тем же Видом являются устаревшей историей.
        ИндексыДляУдаления.Добавить(ТаблицаКИ.Индекс(СтрокаКИ));
    Иначе
        ПредыдущийВид = СтрокаКИ.Вид;
    КонецЕсли;
КонецЦикла;

// Удаляем устаревшие строки с конца таблицы
Для Счетчик = 1 По ИндексыДляУдаления.Количество() Цикл
    ОбратныйИндекс = ИндексыДляУдаления.Количество() - Счетчик;
    ТаблицаКИ.Удалить(ИндексыДляУдаления[ОбратныйИндекс]);
КонецЦикла;

// Теперь в ТаблицаКИ остались только самые актуальные записи для каждого вида КИ

Этот код гарантирует, что в XML-выгрузку попадет только одна — самая актуальная по дате действия — запись юридического (или любого другого) адреса.

---

Способ 4. Групповое удаление устаревших исторических записей

Если проблема носит массовый характер (например, дублируются адреса не только у вашей организации, но и у сотен контрагентов в базе данных), ручная очистка не подойдет. В этом случае мы можем написать простую внешнюю обработку, которая найдет все дубли в регистре сведений КонтактнаяИнформация и очистит устаревшие записи.

Ниже представлен готовый код для внешней обработки, выполняющий очистку устаревших исторических записей юридических адресов организаций:


Процедура ОчиститьУстаревшуюИсториюАдресов() Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	КонтактнаяИнформация.Объект КАК Объект,
        |	КонтактнаяИнформация.Тип КАК Тип,
        |	КонтактнаяИнформация.Вид КАК Вид,
        |	КонтактнаяИнформация.ДействуетС КАК ДействуетС
        |ИЗ
        |	РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
        |ГДЕ
        |	КонтактнаяИнформация.Объект ССЫЛКА Справочник.Организации
        |	И КонтактнаяИнформация.Вид = &ВидЮрАдрес
        |ИТОГИ ПО
        |	Объект";
    
    // Получаем ссылку на предопределенный вид контактной информации
    ВидЮрАдрес = Справочники.ВидыКонтактнойИнформации.ЮридическийАдресОрганизации;
    Запрос.УстановитьПараметр("ВидЮрАдрес", ВидЮрАдрес);
    
    ВыборкаОрганизаций = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    НачатьТранзакцию();
    Попытка
        Пока ВыборкаОрганизаций.Следующий() Цикл
            
            // Выгружаем записи по конкретной организации во временную таблицу для сортировки
            ТаблицаЗаписей = ВыборкаОрганизаций.Выбрать().Выгрузить();
            Если ТаблицаЗаписей.Количество() <= 1 Тогда
                Продолжить; // Истории изменений нет, пропускаем
            КонецЕсли;
            
            // Сортируем по дате действия (сначала самые новые)
            ТаблицаЗаписей.Sортировать("ДействуетС Убывание");
            
            // Первую строку (индекс 0) с актуальным адресом оставляем. 
            // Все остальные (начиная с индекса 1) удаляем из регистра.
            Для Индекс = 1 По ТаблицаЗаписей.Количество() - 1 Цикл
                СтрокаДляУдаления = ТаблицаЗаписей[Индекс];
                
                НаборЗаписей = РегистрыСведений.КонтактнаяИнформация.СоздатьНаборЗаписей();
                НаборЗаписей.Отбор.Объект.Установить(СтрокаДляУдаления.Объект);
                НаборЗаписей.Отбор.Тип.Установить(СтрокаДляУдаления.Тип);
                НаборЗаписей.Отбор.Вид.Установить(СтрокаДляУдаления.Вид);
                НаборЗаписей.Отбор.ДействуетС.Установить(СтрокаДляУдаления.ДействуетС);
                
                // Записываем пустой набор записей с установленным отбором для удаления строки
                НаборЗаписей.Записать(Истина);
            КонецЦикла;
            
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
        Сообщить("Очистка дублей истории юридических адресов успешно завершена!");
    Исключение
        ОтменитьТранзакцию();
        Сообщить("Ошибка при очистке записей: " + ОписаниеОшибки(), СтатусСообщения.Важное);
    КонецПопытки;
    
КонецПроцедуры

Использование данной обработки позволит вам в автоматическом режиме исправить базу данных УТ, приведя её в состояние, при котором штатный механизм обмена отработает корректно и без ошибок загрузки на стороне 1С:Бухгалтерии.

← На главную