Как заменить документ-основание в табличной части при свертке базы 1С, если его дата меньше даты начала конвертации?

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

При работе с системой 1С:Предприятие, особенно в процессе миграции данных, свертки базы или интеграции, часто возникает необходимость гибко управлять логикой конвертации объектов. Одна из таких ситуаций — условная замена ссылочных данных. Рассмотрим подробнее задачу, когда при выгрузке объекта из самописной конфигурации, содержащего табличную часть с документом-основанием, требуется заменить этот документ другим, ранее созданным в рамках той же конвертации, при соблюдении определенного условия по дате.

Предположим, у нас есть документ, который содержит табличную часть, а в этой табличной части присутствует поле ДокументОснование. При конвертации мы сталкиваемся с условием: если дата ДокументаОснования меньше даты начала свертки, то вместо него нужно подставить ссылку на другой, уже созданный документ, например, документ свертки, который был создан на первом этапе этой же конвертации.

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

Особенности работы с "Конвертацией данных" и поиск объектов

Прежде чем перейти к решению, важно понять несколько ключевых аспектов работы инструмента "Конвертация данных 3.0" (или более ранних версий):

  1. Правила конвертации объектов (ПКО): Каждый тип объекта, который мы конвертируем, описывается своим ПКО. Внутри ПКО мы определяем правила конвертации свойств (ПКС) и табличных частей (ПКТЧ).
  2. Правила выгрузки данных (ПВД): ПВД определяют, какие данные выгружаются и в каком порядке. Они могут использовать несколько ПКО. Порядок выполнения ПВД очень важен, так как он определяет, какие объекты будут созданы раньше.
  3. Поиск объектов при загрузке: При загрузке данных в базу-приемник "Конвертация данных" пытается найти существующий объект по заданным правилам поиска. Если объект не найден, он будет создан.
  4. Транзакционность: 1С:Предприятие работает с транзакциями. Объекты, которые были записаны в базу данных в рамках текущей транзакции обмена, могут быть невидимы для запросов, выполняемых в этой же транзакции, до момента ее фиксации. Это основная причина, по которой "только что созданный" документ не находится.

Шаг 1: Определение и создание документа свертки (ПКО3)

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

В нашем случае, автор использует для поиска Комментарий и Организацию, где Комментарий содержит уникальный код, например, "Сформирован при свертке базы_УИД". Убедитесь, что это ПКО (ПКО3) выполняется *до* того, как мы пытаемся найти этот документ из других ПКО. Это можно контролировать с помощью Порядка выполнения в ПВД.

Шаг 2: Условное изменение ПКО для свойства "ДокументОснование"

Для условной замены ссылки на документ-основание мы можем использовать обработчик ПередВыгрузкой в ПКС для свойства ДокументОснование. Здесь мы можем решить, какое ПКО будет использоваться для конвертации текущего документа-основания.

Рассмотрим пример кода в обработчике ПередВыгрузкой ПКС свойства ДокументОснование:


Если Источник.Дата < ДатаНачалаСвертки Тогда
    // Если дата документа-основания меньше даты начала свертки,
    // мы хотим подставить наш документ свертки.
    // Для этого мы указываем имя ПКО, которое умеет искать или создавать
    // наш документ свертки.
    ИмяПКО = "Свертка_РегистрацияПостоянныхУдержаний_Поиск"; 
    
    // Также мы передаем параметры, по которым ПКО 'Свертка_РегистрацияПостоянныхУдержаний_Поиск'
    // будет искать наш целевой документ.
    Значение = Новый Структура("Комментарий,Организация", "Сформирован при свертке базы_УИД", Источник.Организация);
Иначе
    // Если условие не выполняется, используем стандартное ПКО для документа-основания
    ИмяПКО = "ДокументОснование_СтандартноеПКО"; // Или оставляем пустым, если это ПКО по умолчанию
КонецЕсли;

Важные моменты:

  1. ДатаНачалаСвертки: Это параметр, который мы должны передать в конвертацию. Его можно получить из параметров обмена или глобальных переменных.

  2. ИмяПКО = "Свертка_РегистрацияПостоянныхУдержаний_Поиск": Мы создаем отдельное ПКО, которое будет отвечать за поиск и, возможно, создание (если не найден) нашего ДокументаСвертки. Важно, чтобы это ПКО имело правильно настроенные поля поиска.

  3. Значение = Новый Структура(...): Передавая структуру, мы предоставляем ПКО "Свертка_РегистрацияПостоянныхУдержаний_Поиск" необходимые данные для поиска. Поля этой структуры должны соответствовать полям поиска в указанном ПКО.

Автор в своем сообщении (Сообщение 12, 13) пробовал менять ИмяПКО и передавать Значение, но столкнулся с тем, что вместо подстановки существующего документа создавались новые. Это происходит, потому что само по себе изменение ИмяПКО или передача Структуры не гарантирует поиск. Нам нужно явно определить логику поиска внутри ПКО.

Шаг 3: Настройка ПКО для поиска ("Свертка_РегистрацияПостоянныхУдержаний_Поиск")

Для того чтобы ПКО "Свертка_РегистрацияПостоянныхУдержаний_Поиск" не создавало новый документ, а находило уже существующий, нам необходимо настроить в нем поля поиска и, что более важно, использовать обработчик Обработчик Поля поиска.

3.1. Определение полей поиска

В ПКО "Свертка_РегистрацияПостоянныхУдержаний_Поиск" мы должны указать, что поля Комментарий и Организация являются полями поиска. Это позволяет системе "Конвертации данных" использовать их для стандартного поиска по умолчанию.

3.2. Использование "Обработчика Поля поиска"

Это самый мощный инструмент для контроля процесса поиска объектов. В этом обработчике мы можем написать произвольный код 1С для поиска объекта в базе-приемнике. Если объект найден, мы присваиваем его ссылку параметру СсылкаНаОбъект и устанавливаем ПрекратитьПоиск = Истина, чтобы "Конвертация данных" не продолжала стандартный поиск и не создавала новый объект.

Рассмотрим пример кода для Обработчика Поля поиска в ПКО "Свертка_РегистрацияПостоянныхУдержаний_Поиск":


// В обработчике "Обработчик Поля поиска" в ПКО "Свертка_РегистрацияПостоянныхУдержаний_Поиск"

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

В этом коде:

  1. Мы получаем значения полей поиска из структуры СвойстваПоиска, которая автоматически заполняется данными, переданными через Значение = Новый Структура(...).

  2. Формируем запрос к базе данных-приемника для поиска документа РегистрацияПостоянныхУдержаний по Комментарию и Организации.

  3. Если запрос находит документ, мы присваиваем его ссылку переменной СсылкаНаОбъект и устанавливаем ПрекратитьПоиск = Истина, что сигнализирует системе о том, что объект найден и новый создавать не нужно.

Автор в своем сообщении (Сообщение 17) указал, что даже с таким обработчиком запрос выдает 0 результатов. Это и есть проявление транзакционной видимости.

Шаг 4: Разбираемся с проблемой "Объект не найден" и транзакционностью

Как мы уже упоминали, основная проблема заключается в том, что документ (Документ_ПКО3), который был создан чуть раньше в той же конвертации, может быть не виден для запросов к базе данных, выполняемых в рамках текущей, еще не зафиксированной транзакции обмена. Запрос, выполненный сразу после конвертации, находит его, потому что транзакция обмена уже завершена и зафиксирована.

Для решения этой проблемы существует несколько подходов:

4.1. Изменение порядка выполнения ПВД

Убедимся, что ПВД, которое инициирует создание Документа_ПКО3 (назовем его ПВД_ПКО3), имеет меньший порядок выполнения, чем ПВД, которое инициирует конвертацию основного документа (ПВД_ПКО1), в котором мы ищем ссылку. Если ПВД_ПКО3 выполняется сильно раньше, есть шанс, что его транзакция может быть зафиксирована до начала обработки ПВД_ПКО1, что сделает объект видимым.

Автор указал (Сообщение 10), что у ПВД_ПКО3 порядок выполнения 450, а у ПВД_ПКО1 — 1500. Это уже правильное направление. Однако даже такая разница в порядке выполнения не всегда гарантирует фиксацию транзакции между выгрузкой/загрузкой объектов разных типов. "Конвертация данных" может собирать данные в один пакет и загружать его в одной транзакции.

4.2. Использование "Отложенного связывания" (Deferred Linking)

Если прямая подстановка и поиск через `Обработчик Поля поиска` не дают результата из-за транзакционности, мы можем использовать механизм отложенного связывания. Этот подход предполагает, что на первом этапе мы не устанавливаем прямую ссылку на документ, а сохраняем некие "ключевые данные" для последующего поиска.

  1. На этапе конвертации основного документа: Вместо непосредственной установки ссылки на Документ_ПКО3, мы можем записать в какой-то вспомогательный реквизит (например, строковый или ссылочный, который потом очистим) основного объекта его уникальные параметры поиска (Комментарий, Организация).

  2. После загрузки основного документа: В обработчике ПослеЗагрузки основного ПКО (или в отдельной обработке, выполняемой после всей конвертации), мы можем выполнить запрос для поиска Документа_ПКО3 по сохраненным параметрам и затем уже установить правильную ссылку на ДокументОснование.

Пример реализации отложенного связывания в обработчике ПослеЗагрузки ПКО основного документа (ПКО1):


// В обработчике "ПослеЗагрузки" ПКО основного документа

// Предположим, что в табличной части у нас есть временное поле,
// куда мы записали комментарий и организацию для поиска
Для Каждого СтрокаТЧ Из Объект.ТабличнаяЧасть Цикл
    Если ЗначениеЗаполнено(СтрокаТЧ.ВременныйКомментарийДляПоиска) Тогда
        Запрос = Новый Запрос;
        Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    РегистрацияПостоянныхУдержаний.Ссылка КАК Ссылка
        |ИЗ
        |    Документ.РегистрацияПостоянныхУдержаний КАК РегистрацияПостоянныхУдержаний
        |ГДЕ
        |    РегистрацияПостоянныхУдержаний.Комментарий = &Комментарий
        |    И РегистрацияПостоянныхУдержаний.Организация = &Организация";
        
        Запрос.УстановитьПараметр("Комментарий", СтрокаТЧ.ВременныйКомментарийДляПоиска);
        Запрос.УстановитьПараметр("Организация", СтрокаТЧ.Организация); // Организация может быть уже в СтрокаТЧ
        
        Выборка = Запрос.Выполнить().Выбрать();
        
        Если Выборка.Следующий() Тогда
            // Нашли документ свертки, подставляем его
            СтрокаТЧ.ДокументОснование = Выборка.Ссылка;
        КонецЕсли;
        
        // Очищаем временное поле после использования
        СтрокаТЧ.ВременныйКомментарийДляПоиска = ""; 
    КонецЕсли;
КонецЦикла;

Этот метод более сложен в реализации, но он обходит проблему транзакционной видимости, так как поиск выполняется *после* того, как все объекты уже записаны в базу данных (или по крайней мере после того, как завершена запись пакета, содержащего наш Документ_ПКО3).

4.3. Использование `ПередЗаписьюПолученныхДанных` в ПКО

Еще один продвинутый подход, который можно рассмотреть в КД 3.0, это работа с обработчиком ПередЗаписьюПолученныхДанных в ПКО. В этом обработчике мы имеем доступ к:

Мы можем использовать этот обработчик, чтобы переопределить логику поиска. Если ДанныеИБ равно Неопределено, это означает, что объект не найден по стандартным правилам поиска. В этом случае мы можем реализовать собственный поиск и, если объект найден, присвоить его ДанныеИБ, а затем установить ПолученныеДанные = Неопределено, чтобы предотвратить создание нового объекта и обеспечить замещение.


// В обработчике "ПередЗаписьюПолученныхДанных" ПКО "Свертка_РегистрацияПостоянныхУдержаний_Поиск"

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

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

Шаг 5: Отладка процесса конвертации

В любой сложной конвертации данных критически важна отладка. "Конвертация данных 3.0" предоставляет возможность отладки правил. Вы можете:

  1. Запустить отладку во внешней обработке "Конвертация данных", если это локальный клиент.

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

Итог и рекомендации

Для успешного решения задачи по условной замене документа-основания:

  1. Убедитесь в правильном порядке выполнения ПВД: ПВД_ПКО3 (создание документа свертки) должно выполняться до ПВД_ПКО1 (конвертация основного документа).

  2. Используйте ИмяПКО и Значение = Новый Структура(...) в ПередВыгрузкой ПКС для условного выбора ПКО и передачи параметров поиска.

  3. Настройте в целевом ПКО (`Свертка_РегистрацияПостоянныхУдержаний_Поиск`) `Обработчик Поля поиска` с явным запросом по переданным параметрам (Комментарий, Организация). Это наиболее прямой способ реализации поиска.

  4. Если проблема с транзакционной видимостью сохраняется, рассмотрите "отложенное связывание" или использование обработчика `ПередЗаписьюПолученныхДанных`. Это более сложные механизмы, но они позволяют обойти ограничения по видимости данных.

  5. Активно используйте отладчик для пошагового анализа выполнения правил и выявления точного момента, когда документ не находится.

Понимание того, что объекты, записанные в текущей транзакции, могут быть не сразу доступны для запросов, является ключевым моментом в решении подобных задач в "Конвертации данных". Выберите подход, который наилучшим образом соответствует сложности вашей задачи и структуре обмена.

← На главную