Как правильно реализовать поиск и программное создание договора в ПКО «После загрузки»

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

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

Анализ исходной проблемы: почему объект не создается

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


// Ошибка в логике проверки результата поиска
НужныйДоговор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию(Строка(Объект.Номер + " от " + Формат(Объект.Дата,"ДФ=dd.MM.yyyy")));
Если НЕ НужныйДоговор = Неопределено Тогда
    Объект.ДоговорКонтрагента = НужныйДоговор;
Иначе
    // Код создания нового договора
КонецЕсли;

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

Следовательно, условие Если НЕ НужныйДоговор = Неопределено Тогда всегда будет истинным, так как «Пустая ссылка» не равна «Неопределено». В результате программа пытается присвоить пустую ссылку в реквизит ДоговорКонтрагента и никогда не заходит в блок создания нового элемента.

Правильные способы проверки существования объекта

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

  1. Использование метода .Пустая(): Это самый явный способ проверить, была ли найдена ссылка в базе данных.
    
    Если НЕ НужныйДоговор.Пустая() Тогда
        Объект.ДоговорКонтрагента = НужныйДоговор;
    Иначе
        // Создаем новый договор
    КонецЕсли;
    
  2. Использование функции ЗначениеЗаполнено(): Универсальная функция, которая вернет Ложь для пустой ссылки, Неопределено или Null.
    
    Если ЗначениеЗаполнено(НужныйДоговор) Тогда
        Объект.ДоговорКонтрагента = НужныйДоговор;
    КонецЕсли;
    

Важное замечание: При написании кода будьте внимательны с логическим отрицанием НЕ. Ошибка в расстановке приоритетов или лишнее отрицание — частая причина того, что код «не заходит» в нужное условие.

Решение проблемы дублирования объектов

Другая распространенная проблема — появление дублей договоров. Например, если код выполняется в ПКО «Реализация» и ПКО «Счет на оплату», а даты этих документов различаются. Поскольку наименование договора формируется как Номер + Дата, для реализации и счета создаются два разных договора, хотя по смыслу они должны относиться к одному соглашению.

Чтобы избежать дублирования, мы должны нормализовать логику поиска:

Оптимальная архитектура через ПКО и Поля поиска

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

Разберем этот подход подробнее:

  1. Создадим ПКО_Договоры.
  2. В настройках этого ПКО на вкладке «Поля поиска» отметим «Наименование» и «Владелец». Система сама сгенерирует эффективный запрос для поиска существующего договора.
  3. В ПКО основного документа для свойства ДоговорКонтрагента укажем правило ПКО_Договоры.
  4. Если данные для создания договора (номер и дата) отсутствуют в источнике в явном виде, мы можем передать их через Параметры в событии ПередВыгрузкой свойства.

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

Рекомендации по отладке и записи объектов

Проанализируем еще один технический нюанс. В обработчике ПослеЗагрузки мы оперируем переменной Объект. Важно помнить:

1. Запись основного объекта: Вам не нужно вызывать Объект.Записать() в конце обработчика, если вы просто поменяли значение реквизита (например, Объект.ДоговорКонтрагента = ...). Платформа сама запишет Объект после завершения кода обработчика.

2. Запись подчиненного объекта: Если вы создаете новый договор программно через Справочники.ДоговорыКонтрагентов.СоздатьЭлемент(), то вызов метода НовыйДоговор.Записать() обязателен. Без этого у вас не будет ссылки (НовыйДоговор.Ссылка), которую можно присвоить основному объекту.

3. Мониторинг процесса: Если обмен идет в фоновом режиме, команда Сообщить() может быть бесполезна. Для диагностики используйте запись в журнал регистрации:


ЗаписьЖурналаРегистрации("ОбменДанными.ПоискДоговора", УровеньЖурналаРегистрации.Информация, , , "Для документа " + Объект + " найден договор: " + НужныйДоговор);

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

← На главную