В процессе разработки правил обмена данными в «1С:Конвертация данных 2.1» (особенно при переносе данных из УПП в Бухгалтерию предприятия) часто возникает задача автоматического создания или подбора договора контрагента. Мы можем столкнуться с ситуацией, когда стандартных полей поиска ПКО недостаточно и требуется написать программный код в обработчике ПослеЗагрузки. Разберем типичные ошибки, с которыми сталкиваются разработчики, и способы их решения.
Рассмотрим ситуацию, когда в обработчике ПослеЗагрузки правила конвертации объекта (ПКО) документа прописана логика поиска или создания договора по номеру и дате самого документа. Одной из первых преград становится неправильная проверка результата поиска. Проанализируем исходный код, который часто приводит к ошибкам:
// Ошибка в логике проверки результата поиска
НужныйДоговор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию(Строка(Объект.Номер + " от " + Формат(Объект.Дата,"ДФ=dd.MM.yyyy")));
Если НЕ НужныйДоговор = Неопределено Тогда
Объект.ДоговорКонтрагента = НужныйДоговор;
Иначе
// Код создания нового договора
КонецЕсли;
В данном примере разработчик ожидает, что если договор не найден, метод НайтиПоНаименованию вернет Неопределено. Однако, согласно спецификации платформы 1С, метод НайтиПоНаименованию для справочников всегда возвращает пустую ссылку, если объект не найден. Исключение составляет лишь случай, когда у справочника вообще не задана длина наименования, что для договоров невозможно.
Следовательно, условие Если НЕ НужныйДоговор = Неопределено Тогда всегда будет истинным, так как «Пустая ссылка» не равна «Неопределено». В результате программа пытается присвоить пустую ссылку в реквизит ДоговорКонтрагента и никогда не заходит в блок создания нового элемента.
Для корректной работы алгоритма нам необходимо изменить условие проверки. Рассмотрим два надежных способа, которые мы можем применить в коде:
Если НЕ НужныйДоговор.Пустая() Тогда
Объект.ДоговорКонтрагента = НужныйДоговор;
Иначе
// Создаем новый договор
КонецЕсли;
Ложь для пустой ссылки, Неопределено или Null.
Если ЗначениеЗаполнено(НужныйДоговор) Тогда
Объект.ДоговорКонтрагента = НужныйДоговор;
КонецЕсли;
Важное замечание: При написании кода будьте внимательны с логическим отрицанием НЕ. Ошибка в расстановке приоритетов или лишнее отрицание — частая причина того, что код «не заходит» в нужное условие.
Другая распространенная проблема — появление дублей договоров. Например, если код выполняется в ПКО «Реализация» и ПКО «Счет на оплату», а даты этих документов различаются. Поскольку наименование договора формируется как Номер + Дата, для реализации и счета создаются два разных договора, хотя по смыслу они должны относиться к одному соглашению.
Чтобы избежать дублирования, мы должны нормализовать логику поиска:
// Второй параметр метода - Поиск по владельцу
НужныйДоговор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию(ИмяДоговора, Истина, Объект.Контрагент);
Хотя написание кода в ПослеЗагрузки кажется быстрым решением, в «1С:Конвертация данных» есть более правильный («штатный») путь — использование отдельного ПКО для справочника ДоговорыКонтрагентов.
Разберем этот подход подробнее:
ДоговорКонтрагента укажем правило ПКО_Договоры.ПередВыгрузкой свойства.Преимущество такого метода в том, что система сама управляет транзакциями. Если основной документ не будет записан из-за ошибки, автоматически созданный через ПКО договор не останется в базе «мусором» (если включен режим транзакционной загрузки).
Проанализируем еще один технический нюанс. В обработчике ПослеЗагрузки мы оперируем переменной Объект. Важно помнить:
1. Запись основного объекта: Вам не нужно вызывать Объект.Записать() в конце обработчика, если вы просто поменяли значение реквизита (например, Объект.ДоговорКонтрагента = ...). Платформа сама запишет Объект после завершения кода обработчика.
2. Запись подчиненного объекта: Если вы создаете новый договор программно через Справочники.ДоговорыКонтрагентов.СоздатьЭлемент(), то вызов метода НовыйДоговор.Записать() обязателен. Без этого у вас не будет ссылки (НовыйДоговор.Ссылка), которую можно присвоить основному объекту.
3. Мониторинг процесса: Если обмен идет в фоновом режиме, команда Сообщить() может быть бесполезна. Для диагностики используйте запись в журнал регистрации:
ЗаписьЖурналаРегистрации("ОбменДанными.ПоискДоговора", УровеньЖурналаРегистрации.Информация, , , "Для документа " + Объект + " найден договор: " + НужныйДоговор);
Использование этих подходов позволит вам создавать надежные и отказоустойчивые правила обмена, минимизируя количество дублей и ошибок в базе-приемнике.