При переносе данных между базами 1С с помощью конфигурации «Конвертация данных 2.0» (КД 2.0) программисты часто сталкиваются с необходимостью «расщепления» одного документа на несколько. Типичный пример: выгрузка Заказ-наряда из отраслевого решения (например, «Альфа-Авто») в УПП или Бухгалтерию, где по правилам учета работы и запчасти должны быть разнесены в разные документы Реализация товаров и услуг из-за разных систем налогообложения (НДС и патент/ЕНВД).
В такой ситуации возникает проблема: платежные документы (РКО, ПКО, Платежные поручения) ссылаются на один исходный Заказ-наряд. Если при загрузке основной документ (например, с товарами) не создается, ссылка в платеже превращается в «Объект не найден», хотя документ с услугами в базе присутствует. Рассмотрим подробнее, как решить эту проблему, правильно настроить поля поиска и избежать типичных ошибок при написании кода в обработчиках.
Разберем ситуацию: в правилах конвертации объектов (ПКО) прописана логика, согласно которой в обработчике После загрузки создается второй документ (ДокЕНВД). Если в исходном заказе нет товаров, первая реализация (основной объект ПКО) помечается на удаление или не записывается (ОтказЗаписиОбъекта = Истина). Однако в XML-файле выгрузки платежный документ уже содержит ссылку (GUID) именно на этот основной объект.
Когда система загружает платеж, она пытается найти документ по этому GUID. Если основной документ не был создан, мы получаем «битую» ссылку. Для решения задачи нам нужно заставить систему поиска в платеже «перепрыгнуть» на второй созданный документ (услуги), если первый (товары) отсутствует.
В процессе отладки кода поиска часто возникает ошибка: Поле объекта недоступно для записи (Ссылка). Проанализируем причину. Вы пытаетесь передать Объект.Ссылка в качестве параметра функции и изменить его внутри. Рассмотрим пример ошибочного кода:
// ОШИБОЧНЫЙ КОД
Процедура ПроверитьОплату(ДокументСсылка, ТекущийДокументОплаты)
...
ТекущийДокументОплаты = Выборка.Ссылка; // Здесь возникнет ошибка, если передана ссылка на текущий объект
КонецПроцедуры
Почему это происходит: Ссылка на объект (Ref) в 1С является неизменяемым типом данных (ReadOnly) для уже существующих или инициализированных объектов в памяти. Вы не можете просто «подменить» ссылку внутри переменной, которая напрямую связана с реквизитом Объект.Ссылка.
Как исправить: Используйте промежуточные переменные. Сначала выполните все вычисления и поиск в локальных переменных, а затем возвращайте результат (например, через структуру или просто возвращаемое значение функции), как показано ниже:
МойДокументОплаты = ?(ОбъектНайден, Объект.Ссылка, Неопределено);
МояСуммаОплаты = 0;
// Вызываем функцию, которая возвращает состояние
МойФлагОплаты = ОбщийМодуль.ДокументПродажиОплачен(ДокументПродажи, МояСуммаОплаты, МойДокументОплаты);
Если МойФлагОплаты Тогда
// Дальнейшая логика
КонецЕсли;
Если поиск по GUID не дал результатов (или документ с таким GUID был удален/не создан), необходимо задействовать вкладку «Поля поиска» в ПКО документа. Посмотрим, как реализовать сложный поиск через СтрокаИменСвойствПоиска.
Рассмотрим алгоритм в обработчике Поля поиска:
Пример кода в обработчике Поля поиска:
// Если объект не найден по GUID, система перейдет сюда
Если ПустаяСтрока(СвойстваПоиска["Номер"]) Тогда
// Пример ручного поиска через запрос
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Документ.РеализацияТоваровУслуг
|ГДЕ Дата МЕЖДУ &НачДата И &КонДата
|И Организация = &Организация И Контрагент = &Контрагент";
Запрос.УстановитьПараметр("НачДата", НачалоДня(СвойстваПоиска.Получить("Дата")));
Запрос.УстановитьПараметр("КонДата", КонецДня(СвойстваПоиска.Получить("Дата")));
Запрос.УстановитьПараметр("Организация", СвойстваПоиска.Получить("Организация"));
Запрос.УстановитьПараметр("Контрагент", СвойстваПоиска.Получить("Контрагент"));
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
СсылкаНаОбъект = Выборка.Ссылка;
КонецЕсли;
Иначе
// Стандартный поиск по номеру и дате (важно для периодических номеров)
СтрокаИменСвойствПоиска = "Номер, Дата";
КонецЕсли;
Важный нюанс: Чтобы этот код заработал, в настройках ПКО должна стоять галочка Продолжить поиск по полям поиска, если объект по идентификатору не найден. Для смежных задач также будет полезен разбор нюансов поведения системы при полностью отключенном поиске по внутреннему идентификатору.
Самый надежный способ обеспечить связку платежей с документами услуг (когда товары отсутствуют) — это программная установка GUID. Если мы создаем Реализацию услуг вместо Реализации товаров, мы можем присвоить новому документу GUID, который пришел из источника для Заказ-наряда.
Для этого в обработчике Перед загрузкой или После загрузки (если создается новый объект) используем метод УстановитьСсылкуНового(). Разберем пример:
// В обработчике создания второго документа (ДокЕНВД)
НовыйУИД = Новый УникальныйИдентификатор(XMLСтрока(Объект.ПолучитьСсылкуНового()));
НоваяСсылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(НовыйУИД);
ДокЕНВД = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
ДокЕНВД.УстановитьСсылкуНового(НоваяСсылка);
// Заполнение реквизитов...
ДокЕНВД.Записать();
Что это дает: Теперь, когда платежный документ будет загружаться и искать «Реализацию» по GUID исходного Заказ-наряда, он найдет именно ваш документ с услугами (ДокЕНВД), потому что вы «подарили» ему этот идентификатор. Это исключает появление битых ссылок Объект не найден без необходимости сложного переопределения правил для каждого платежа.
Для более чистого кода в Полях поиска рекомендуется использовать встроенную переменную НомерВариантаПоиска. Это позволяет системе сделать несколько попыток поиска разными способами:
Если НомерВариантаПоиска = 1 Тогда
// Первая попытка: строгий поиск по номеру и дате
СтрокаИменСвойствПоиска = "Номер, Дата";
ИначеЕсли НомерВариантаПоиска = 2 Тогда
// Вторая попытка: если номер изменился, ищем по сумме и контрагенту
СтрокаИменСвойствПоиска = "Дата, Организация, Контрагент, СуммаДокумента";
КонецЕсли;
Выясним причину, почему поиск иногда не срабатывает: если в СтрокаИменСвойствПоиска указано слишком много полей (например, Номер, Дата, Организация, Контрагент), то при малейшем расхождении в одном из них (например, время даты в базе-приемнике отличается на секунду) объект найден не будет. Поэтому старайтесь минимизировать количество полей в строке поиска или используйте поиск «по дате без времени» (соответствующая настройка в ПКС). При необходимости сложной идентификации можно рассмотреть пример реализации поиска по дополнительному реквизиту.
Подводя итог, проанализируем: при разделении документов в КД 2.0 залогом успеха является управление GUID-ом. Либо вы обеспечиваете подмену ссылки в платеже через сложные Поля поиска, либо (что проще и надежнее) гарантируете, что хотя бы один из созданных в приемнике документов получит GUID источника.