Как выгрузить документы «Реализация товаров и услуг» из БП 3.0 в УТ 10.3 с поиском по Артикулу и ИНН?

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

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

В этой статье мы подробно разберем, как решить задачу переноса документа РеализацияТоваровУслуг. Нам необходимо организовать поиск номенклатуры по Артикулу, контрагентов — по ИНН, а также обеспечить жесткий контроль: если объект не найден в базе-приемнике, загрузка должна прерываться с выводом ошибки, чтобы избежать появления пустых ссылок («битых» объектов).

Мы проанализируем два наиболее эффективных и жизнеспособных метода решения этой задачи:

  1. Использование конфигурации «Конвертация данных 2.1» (КД 2.1).
  2. Написание собственной выгрузки и загрузки на базе встроенных механизмов XML.

---

Почему не подходит Конвертация данных 3.0 (КД 3)?

Прежде чем перейти к практике, проанализируем архитектурный нюанс. На форумах часто советуют использовать современную КД 3, работающую через формат EnterpriseData. Однако этот подход ориентирован на современные конфигурации на управляемых формах (БП 3.0, УТ 11, ERP). Конфигурация УТ 10.3 базируется на обычных формах и не имеет штатной поддержки формата EnterpriseData. Попытка адаптировать КД 3 под УТ 10.3 приведет к колоссальным трудозатратам. Поэтому наш выбор для готовых правил — проверенная временем КД 2.1.

---

Метод 1. Настройка правил поиска и контроля ошибок в КД 2.1

Использование «Конвертации данных 2.1» — это наиболее гибкий метод, позволяющий в будущем легко масштабировать правила обмена. Выясним, как настроить правила для жесткого контроля поиска объектов.

Шаг 1. Настройка полей поиска в ПКС и ПКО

Для того чтобы поиск выполнялся по нужным нам реквизитам, выполним следующие действия в конфигурации КД 2.1:

  1. Для Контрагентов:
    • В ПКС (Правила конвертации свойств) для свойства ИНН установите флаг «Поиск».
    • В ПКО (Правила конвертации объектов) для контрагентов отключите флаг «Искать по внутреннему идентификатору» (если у вас нет гарантии совпадения ГУИД в обеих базах). Либо оставьте его включенным, но обязательно активируйте опцию «Продолжить поиск по полям поиска, если по идентификатору не найден».
  2. Для Номенклатуры:
    • В ПКС для реквизита Артикул установите флаг «Поиск».
    • Настройте ПКО аналогично контрагентам, сделав артикул ключевым полем сопоставления.

Шаг 2. Предотвращение создания «битых» ссылок

По умолчанию КД 2.1 при неудачном поиске создает новый элемент в базе-приемнике. Нам же требуется выдать ошибку и не создавать объект. Для этого:

  1. В свойствах ПКО для Номенклатура и Контрагенты установите флаг «Не создавать новый объект в приемнике, если он НЕ найден». В этом случае пустые карточки создаваться не будут.
  2. Если объект не найден и не создан, в документе-приемнике на месте реквизита запишется пустая ссылка или объект со статусом "<Объект не найден>". Чтобы предотвратить запись некорректного документа, нам потребуется написать код в обработчиках событий КД.

Шаг 3. Написание обработчиков событий для контроля ошибок

Рассмотрим два варианта реализации проверки в ПКО документа РеализацияТоваровУслуг.

Вариант А. Мягкая отмена загрузки конкретного документа

В ПКО документа в событии «После загрузки» мы можем проверить, успешно ли сопоставились Контрагент и вся Номенклатура в табличной части. Если проверка не пройдена, мы взводим флаг Отказ = Истина, и текущий документ не записывается в базу.


// Проверяем сопоставление Контрагента
Если Не ЗначениеЗаполнено(Объект.Контрагент) Или Объект.ContragentIsNotValid() Тогда // Используем проверку битой ссылки
    Сообщить("Документ " + Объект.Номер + " не загружен: Контрагент не найден по ИНН в базе УТ!");
    Отказ = Истина;
КонецЕсли;

// Проверяем номенклатуру в табличной части "Товары"
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Если Не ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) Или СтрокаТЧ.Номенклатура.ПолучитьОбъект() = Неопределено Тогда
        Сообщить("Документ " + Объект.Номер + " не загружен: Номенклатура с переданным артикулом отсутствует в УТ!");
        Отказ = Истина;
        Прервать; // Прерываем цикл проверки строк, так как документ уже бракуется
    КонецЕсли;
КонецЦикла;

Вариант Б. Жесткое прерывание всего процесса импорта

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


// Проверка Контрагента на корректность ссылки
Если Не ЗначениеЗаполнено(Объект.Контрагент) Или Объект.Контрагент.ПолучитьОбъект() = Неопределено Тогда
    ВызватьИсключение "Критическая ошибка обмена! Контрагент не найден в базе-приемнике УТ. Загрузка остановлена.";
КонецЕсли;

// Проверка Номенклатуры в табличной части
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Если Не ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) Или СтрокаТЧ.Номенклатура.ПолучитьОбъект() = Неопределено Тогда
        ВызватьИсключение "Критическая ошибка обмена! Номенклатура с артикулом '" + СтрокаТЧ.Номенклатура.Артикул + "' не найдена. Загрузка остановлена.";
    КонецЕсли;
КонецЦикла;

---

Метод 2. Собственная выгрузка и загрузка через XML (без использования КД)

Если вам необходимо быстро перенести только один тип документов («Реализация товаров и услуг»), а тратить время на изучение КД 2.1 нет возможности, оптимальным решением станет написание собственных процедур выгрузки и загрузки с использованием механизмов ЗаписьXML и ЧтениеXML. Это обеспечит вам абсолютный контроль над процессом чтения данных и обработки исключений.

Реализация выгрузки на стороне БП 3.0

Создадим внешнюю обработку на стороне БП 3.0. Напишем процедуру, которая выбирает документы за определенный период и записывает их структуру в XML-файл. Обратите внимание, что мы выгружаем не ссылки на объекты, а только строковые значения реквизитов поиска — ИНН контрагента и артикулы товаров.


Процедура ВыгрузитьРеализацииВXML(ПутьКФайлу, НачалоПериода, КонецПериода) Экспорт

    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.ОткрытьФайл(ПутьКФайлу, "UTF-8");
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеОбмена");

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

    Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
    Запрос.УстановитьПараметр("КонецПериода", КонецПериода);

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

    Пока Выборка.Следующий() Цикл
        
        ЗаписьXML.ЗаписатьНачалоЭлемента("Документ");
        ЗаписьXML.ЗаписатьАтрибут("Тип", "Реализация");
        ЗаписьXML.ЗаписатьАтрибут("Номер", Строка(Выборка.Номер));
        ЗаписьXML.ЗаписатьАтрибут("Дата", Формат(Выборка.Дата, "ДФ=yyyy-MM-ddТHH:mm:ss"));
        ЗаписьXML.ЗаписатьАтрибут("ИННКонтрагента", СокрЛП(Выборка.ИННКонтрагента));
        
        // Переходим к выгрузке табличной части "Товары"
        ЗаписьXML.ЗаписатьНачалоЭлемента("Товары");
        
        Для Каждого СтрокаТЧ Из Выборка.Ссылка.Товары Цикл
            
            ЗаписьXML.ЗаписатьНачалоЭлемента("Строка");
            // Ключевое поле сопоставления номенклатуры - Артикул
            ЗаписьXML.ЗаписатьАтрибут("Артикул", СокрЛП(СтрокаТЧ.Номенклатура.Артикул));
            ЗаписьXML.ЗаписатьАтрибут("Количество", Строка(СтрокаТЧ.Количество));
            ЗаписьXML.ЗаписатьАтрибут("Цена", Строка(СтрокаТЧ.Цена));
            ЗаписьXML.ЗаписатьАтрибут("Сумма", Строка(СтрокаТЧ.Сумма));
            ЗаписьXML.ЗаписатьКонецЭлемента(); // Строка
            
        КонецЦикла;
        
        ЗаписьXML.ЗаписатьКонецЭлемента(); // Товары
        ЗаписьXML.ЗаписатьКонецЭлемента(); // Документ
        
    КонецЦикла;

    ЗаписьXML.ЗаписатьКонецЭлемента(); // ДанныеОбмена
    ЗаписьXML.Закрыть();
    
    Сообщить("Выгрузка успешно завершена в файл: " + ПутьКФайлу);

КонецПроцедуры

Реализация загрузки на стороне УТ 10.3

Теперь напишем код загрузки для УТ 10.3. Проанализируем алгоритм: мы последовательно читаем XML-файл. При чтении заголовка документа мы немедленно ищем контрагента по ИНН с помощью метода НайтиПоРеквизиту. Если контрагент не найден, мы мгновенно прерываем выполнение операции вызовом ВызватьИсключение, предотвращая запись битых данных. Аналогично поступаем с поиском номенклатуры по артикулу в цикле чтения строк.


Процедура ЗагрузитьРеализацииИзXML(ПутьКФайлу) Экспорт

    ЧтениеXML = Новый ЧтениеXML;
    Попытка
        ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
    Исключение
        Сообщить("Не удалось открыть файл обмена: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;

    НовыйДок = Неопределено;

    Пока ЧтениеXML.Прочитать() Цикл
        
        // Определение начала чтения документа
        Если ЧтениеXML.Имя = "Документ" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            
            Номер = ЧтениеXML.ПолучитьАтрибут("Номер");
            // Преобразуем строковую дату XML обратно в формат Даты 1С
            СтрокаДаты = СтрЗаменить(ЧтениеXML.ПолучитьАтрибут("Дата"), "Т", " ");
            ДатаДокумента = Дата(СтрокаДаты);
            ИНН = ЧтениеXML.ПолучитьАтрибут("ИННКонтрагента");
            
            // Выполняем поиск контрагента по ИНН
            КонтрагентСсылка = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИНН);
            
            Если КонтрагентСсылка.Пустая() Тогда
                ЧтениеXML.Закрыть();
                ВызватьИсключение "Ошибка загрузки! Контрагент с ИНН '" + ИНН + "' не найден в УТ 10.3. Операция отменена.";
            КонецЕсли;
            
            // Инициализируем создание документа в УТ 10.3
            НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
            НовыйДок.Дата = ДатаДокумента;
            НовыйДок.Номер = Номер;
            НовыйДок.Контрагент = КонтрагентСсылка;
            
            // В УТ 10.3 важно заполнить обязательные реквизиты по умолчанию
            НовыйДок.Организация = Справочники.Организации.Выбрать(); // Или конкретная организация
            НовыйДок.ОтражатьВУправленческомУчете = Истина;
            НовыйДок.ОтражатьВБухгалтерскомУчете = Истина;
            
        // Чтение строк табличной части
        ИначеЕсли ЧтениеXML.Имя = "Строка" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            
            Если НовыйДок <> Неопределено Тогда
                
                Артикул = ЧтениеXML.ПолучитьАтрибут("Артикул");
                Количество = Число(ЧтениеXML.ПолучитьАтрибут("Количество"));
                Цена = Число(ЧтениеXML.ПолучитьАтрибут("Цена"));
                Сумма = Число(ЧтениеXML.ПолучитьАтрибут("Сумма"));
                
                // Ищем номенклатуру по артикулу
                НоменклатураСсылка = Справочники.Номенклатура.FindByAttribute("Артикул", Артикул); // НайтиПоРеквизиту
                Если НоменклатураСсылка.Пустая() Тогда
                    ЧтениеXML.Закрыть();
                    ВызватьИсключение "Ошибка загрузки! Товар с артикулом '" + Артикул + "' не обнаружен в УТ 10.3. Загрузка прекращена.";
                КонецЕсли;
                
                // Добавляем строку в документ
                НоваяСтрока = НовыйДок.Товары.Добавить();
                НоваяСтрока.Номенклатура = НоменклатураСсылка;
                НоваяСтрока.Количество = Количество;
                НоваяСтрока.Цена = Цена;
                НоваяСтрока.Сумма = Сумма;
                
            КонецЕсли;
            
        // Конец чтения документа - производим запись
        ИначеЕсли ЧтениеXML.Имя = "Документ" И ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
            
            Если НовыйДок <> Неопределено Тогда
                Попытка
                    // Записываем документ без проведения для последующего контроля пользователем
                    НовыйДок.Записать(РежимЗаписиДокумента.Запись);
                    Сообщить("Успешно загружен документ № " + НовыйДок.Номер + " от " + НовыйДок.Дата);
                Исключение
                    Сообщить("Не удалось записать документ: " + ОписаниеОшибки());
                КонецПопытки;
                НовыйДок = Неопределено;
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЦикла;

    ЧтениеXML.Закрыть();

КонецПроцедуры

---

Сравнение подходов: что выбрать?

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

Использование КД 2.1:

Собственный обмен через XML:

Таким образом, если перед вами стоит задача разового переноса или у вас в обмене участвует всего один-два документа, смело используйте прямую XML-сериализацию. Если же планируется постоянное развитие интеграции между БП 3.0 и УТ 10.3, рекомендуется один раз потратить время на настройку правил в КД 2.1.

← На главную