Как разделить ИНН/КПП при переносе из 1С 7.7 в 1С 8.х и эффективно отфильтровать документы по контрагенту в Конвертации данных 2.1

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

Перенос данных между старыми версиями платформ (например, 1С 7.7) и современными конфигурациями на платформе 1С 8.х — классическая задача, с которой регулярно сталкиваются разработчики. При разработке правил обмена в конфигурации «Конвертация данных 2.1» (КД 2.1) возникает множество нюансов, связанных с различиями в структуре метаданных и качеством хранения информации в базах-источниках. В этой статье мы подробно разберем две распространенные практические проблемы: корректное разделение ИНН и КПП контрагентов и организацию быстрой, производительной фильтрации документов по конкретному контрагенту при выгрузке.

Часть 1: Разделение ИНН и КПП при обмене из 1С 7.7 в 1С 8.х

В конфигурациях на платформе 1С 7.7 (например, «Бухгалтерский учет 7.7» или самописных решениях) ИНН и КПП контрагента часто хранились в одном строковом реквизите ИНН через косую черту (например, 7712345678/771201001). В современных же конфигурациях 1С 8.х (таких как «Бухгалтерия предприятия 3.0», «Управление торговлей 11» или ERP) под эти данные выделены два абсолютно разных реквизита: отдельно ИНН и отдельно КПП. Наша задача — правильно распределить эти данные в процессе переноса.

Рассмотрим базовое решение, предложенное на форуме, а затем проанализируем его слабые места и составим максимально надежный, профессиональный алгоритм.

Простой вариант разделения (на основе вида контрагента)

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

Для свойства ИНН:


Если Источник.ВидКонтрагента = Перечисление.ВидыКонтрагентов.ЧастноеЛицо Тогда
    Значение = Лев(Источник.ИНН, 12);
Иначе
    Значение = Лев(Источник.ИНН, 10);
КонецЕсли;

Для свойства КПП:


Если Источник.ВидКонтрагента = Перечисление.ВидыКонтрагентов.ЧастноеЛицо Тогда
    Значение = "";
Иначе
    // КПП у юридических лиц состоит из 9 символов и находится в конце строки
    Значение = Прав(Источник.ИНН, 9);
КонецЕсли;

Почему этот подход может привести к ошибкам в реальной базе?

Проанализируем слабые стороны этого простого алгоритма:

  1. Проблема «грязных» данных. В 1С 7.7 не было жесткого контроля ввода ИНН/КПП. Пользователи могли записать строку как 7712345678 / 771201001 (с пробелами), использовать обратный слэш \ или вообще написать произвольный текст. Прямое использование функций Лев() и Прав() в таких случаях приведет к тому, что в новую базу перенесутся некорректные символы (например, косая черта или пробелы попадут в начало КПП).
  2. Проблема Индивидуальных Предпринимателей (ИП). У ИП ИНН всегда состоит из 12 цифр, а КПП отсутствует вовсе. При этом в старых базах 1С 7.7 индивидуальные предприниматели очень часто регистрировались с видом «Юридическое лицо» (чтобы корректно выписывать первичные документы). Если отработать по коду выше, система отрежет у ИП последние 2 цифры ИНН, решив, что это юрлицо, и попытается записать «хвост» в КПП. Это грубое искажение данных, которое заблокирует сдачу отчетности по НДС.

Создаем надежный и отказоустойчивый алгоритм парсинга

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

Алгоритм для ПКС ИНН (Перед выгрузкой):


СтрокаИНН = СокрЛП(Источник.ИНН);

// Шаг 1. Очищаем строку от пробелов
СтрокаИНН = СтрЗаменить(СтрокаИНН, " ", "");

// Шаг 2. Ищем разделитель (косую черту)
ПозРазделителя = Найти(СтрокаИНН, "/");
Если ПозРазделителя = 0 Тогда
    ПозРазделителя = Найти(СтрокаИНН, "\");
КонецЕсли;

// Шаг 3. Извлекаем ИНН
Если ПозРазделителя > 0 Тогда
    // Если есть разделитель, ИНН гарантированно находится слева от него
    Значение = Лев(СтрокаИНН, ПозРазделителя - 1);
Иначе
    // Если разделителя нет, анализируем длину цифровой строки
    ДлинаСтроки = СтрДлина(СтрокаИНН);
    Если ДлинаСтроки > 12 Тогда
        // Слитная строка типа "7712345678771201001" (10 цифр ИНН + 9 цифр КПП)
        Значение = Лев(СтрокаИНН, 10);
    Иначе
        // Обычный ИНН (10 или 12 символов)
        Значение = СтрокаИНН;
    EndIf;
КонецЕсли;

Алгоритм для ПКС КПП (Перед выгрузкой):


СтрокаИНН = СокрЛП(Источник.ИНН);
СтрокаИНН = СтрЗаменить(СтрокаИНН, " ", "");

ПозРазделителя = Найти(СтрокаИНН, "/");
Если ПозРазделителя = 0 Тогда
    ПозРазделителя = Найти(СтрокаИНН, "\");
КонецЕсли;

Если ПозРазделителя > 0 Тогда
    // КПП находится справа от разделителя
    Значение = СокрЛП(Сред(СтрокаИНН, ПозРазделителя + 1));
Иначе
    ДлинаСтроки = СтрДлина(СтрокаИНН);
    Если ДлинаСтроки = 19 Тогда
        // Если строка слитная и ее общая длина ровно 19 символов (10 ИНН + 9 КПП)
        Значение = Прав(СтрокаИНН, 9);
    Иначе
        // Для ИП (12 символов) или некорректно заполненных данных КПП оставляем пустым
        Значение = "";
    КонецЕсли;
КонецЕсли;

Этот алгоритм защитит базу-приемник от попадания «мусорных» символов разделителей и корректно обработает ситуации с индивидуальными предпринимателями.

---

Часть 2: Оптимальная фильтрация документов по контрагенту при выгрузке

Теперь разберем вторую проблему, поднятую на форуме. Разработчику необходимо перенести документы «Реализация товаров услуг» из базы «Управление торговлей» в документ «Поступление» базы ERP, отфильтровав их по конкретному контрагенту (партнеру).

Попытка автора решить задачу «в лоб» через написание следующего кода в ПКО (Правиле конвертации объектов) в обработчике «Перед выгрузкой» является критической архитектурной ошибкой:


ПартнерЧЛ = "00-00000358";
Если Источник.Партнер.Код <> ПартнерЧЛ Тогда
    Отказ = Истина;
КонецЕсли;

Выясним причины, почему так делать категорически нельзя:

  1. Катастрофическое падение производительности (обращения «через точку»). Конструкция Источник.Партнер.Код заставляет платформу на каждый обрабатываемый документ делать отдельный неявный SQL-запрос к базе данных для получения кода связанного справочника. Если в базе миллионы документов, процесс выгрузки затянется на долгие часы или вызовет переполнение памяти сервера.
  2. Неэффективная фильтрация. Использование оператора Отказ = Истина в обработчике ПКО срабатывает на самом позднем этапе. Система уже сделала выборку всех документов из базы данных, подготовила их структуру в памяти и только перед непосредственной сериализацией в XML сбрасывает объект. Ресурсы СУБД тратятся впустую на чтение ненужных документов.
  3. Жестко зашитые данные (Hardcode). Указывать код партнера строкой напрямую в коде правил обмена ("00-00000358") — плохой тон разработки. При изменении кода контрагента или необходимости выгрузить данные по другому партнеру вам придется заново переписывать и перекомпилировать правила обмена.

Выясним, как решить эту задачу профессионально и быстро.

Решение: Использование ПВД (Правила выгрузки данных) с произвольным алгоритмом

Правильным решением является фильтрация данных на уровне базы данных (СУБД) еще до того, как объекты начнут обрабатываться механизмами Конвертации данных. Для этого мы создадим Правило выгрузки данных (ПВД) для нашего документа и настроим его работу через Произвольный алгоритм.

Выполним настройку по шагам:

Шаг 1. Создание параметра конвертации

В конфигурации «Конвертация данных» перейдем на вкладку «Параметры» и добавим новый параметр:

Шаг 2. Настройка ПВД

Создаем ПВД для документа «РеализацияТоваровУслуг». В поле «Способ выборки данных» выбираем «Произвольный алгоритм». В обработчике события «Перед обработкой» пишем следующий код:


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

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

Запрос.УстановитьПараметр("ОтборПартнер", Параметры.ОтборПартнер);

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

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

В чем преимущества такого подхода?

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

← На главную