Как создать единицу измерения или упаковку при переносе номенклатуры в Конвертации данных 2.1?

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

При настройке правил обмена в конфигурации «Конвертация данных 2.1» разработчики часто сталкиваются с ситуацией, когда в базе-источнике отсутствует справочник единиц измерения или упаковок, либо структура хранения данных кардинально отличается от базы-приемника (например, при переносе из нетиповых конфигураций в Управление торговлей 11). Попытка создать подчиненный элемент непосредственно в обработчике ПослеЗагрузки номенклатуры на стороне приемника обычно завершается системной ошибкой: объект-владелец еще не записан в базу данных, и внешняя ссылка отсутствует.

Разберем по шагам, почему возникает эта ошибка, какие архитектурные особенности конфигураций 1С следует учитывать и как реализовать корректный перенос данных несколькими способами.

Причины сбоя при прямой записи подчиненных объектов

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

Когда отрабатывает событие ПослеЗагрузки, объект Номенклатура находится в памяти, реквизиты заполнены, но метод физической записи в базу данных еще не выполнился. Если в этот момент попытаться создать элемент подчиненного справочника и передать ему Объект.Ссылка, платформа 1С или СУБД вернет ошибку целостности данных, так как внешний ключ ссылается на еще не существующую запись в таблице.

Использование методов ПолучитьСсылкуНового() или УстановитьСсылкуНового() в данном контексте не решает проблему: эти методы лишь резервируют GUID в оперативной памяти сеанса, но физически запись в таблице базы данных не появляется до завершения транзакции записи владельца.

Попытка принудительно вызвать Объект.Записать() до создания подчиненного элемента также часто приводит к исключениям из-за прикладных проверок конфигурации-приемника (например, модули типовой конфигурации проверяют заполненность обязательных реквизитов ставки НДС, вида номенклатуры или самой базовой единицы). Чтобы подавить такой контроль при вынужденной записи, необходимо явно указывать свойство Объект.ОбменДанными.Загрузка = Истина, однако это все равно является обходным решением.

Архитектурная специфика справочника «УпаковкиЕдиницыИзмерения» в УТ 11

Проанализируем структуру базы-приемника на примере конфигурации Управление торговлей 11. В этой конфигурации классификатор единиц измерения (ОКЕИ) и справочник упаковок объединены в общую таблицу УпаковкиЕдиницыИзмерения.

Важно учитывать ключевое методическое правило: базовые единицы хранения номенклатуры хранятся без владельца (реквизит Владелец пустой). Реквизит Номенклатура.ЕдиницаИзмерения должен ссылаться именно на такой общий классификаторный элемент. Владелец (конкретная номенклатура или набор упаковок) заполняется только для упаковок (индивидуальных или типовых). Таким образом, если номенклатуре требуется назначить лишь базовую единицу хранения (например, «шт»), создавать подчиненную запись не требуется вовсе.

Решение 1. ПКО без источника через исходящие данные (решение автора)

Если стоит задача сформировать подчиненную запись упаковок или индивидуальных единиц измерения через стандартный конвейер КД, оптимально использовать ПКО без источника, передавая ссылку владельца через параметр ИсходящиеДанные.

Разберем по шагам настройку правил обмена:

  1. Создаем ПКО УпаковкиЕдиницыИзмерения. Поле «Источник» оставляем пустым, в поле «Приемник» указываем справочник УпаковкиЕдиницыИзмерения.
  2. В созданном ПКО добавляем ПКС для реквизита Владелец. Источник оставляем пустым, взводим флаг Получить из входящих данных и отмечаем его как поле поиска.
  3. В ПКО Номенклатура в обработчике ПослеВыгрузки программно инициируем выгрузку зависимого правила через метод ВыгрузитьПоПравилу.

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


ИсходящиеДанные = Новый Структура("Владелец");
ИсходящиеДанные.Владелец = Источник.Ссылка;
ВыгрузитьПоПравилу(,, ИсходящиеДанные, , "УпаковкиЕдиницыИзмерения");

В ПКО УпаковкиЕдиницыИзмерения в обработчике ПослеЗагрузки заполняем реквизиты создаваемой упаковки по классификатору:


ЕдиницаШтука = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("796");
    
Объект.ЕдиницаИзмерения = ЕдиницаШтука;
Объект.КоличествоУпаковок = 1;
Объект.МеждународноеСокращение = ЕдиницаШтука.МеждународноеСокращение;
Объект.НаименованиеПолное = ЕдиницаШтука.НаименованиеПолное;
Объект.Наименование = ЕдиницаШтука.Наименование; 
Объект.ТипУпаковки = ЕдиницаШтука.ТипУпаковки;

После этого возвращаемся в ПКО Номенклатура и в обработчике ПослеЗагрузки связываем записанную номенклатуру с созданной единицей:


Объект.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Товар;
    
Если НЕ ЗначениеЗаполнено(Объект.ЕдиницаИзмерения) Тогда
    Единицы = Справочники.УпаковкиЕдиницыИзмерения.Выбрать(, Объект.Ссылка); 
    Если Единицы.Следующий() Тогда
        Объект.ЕдиницаИзмерения = Единицы.Ссылка;
        Объект.ЕдиницаДляОтчетов = Единицы.Ссылка;
        Объект.КоэффициентЕдиницыДляОтчетов = 1;
    КонецЕсли;    
КонецЕсли;

Решение 2. Прямая привязка системной единицы измерения (без создания подчиненных объектов)

Рассмотрим более простой и методически верный вариант для Управление торговлей 11, когда для номенклатуры требуется только базовая единица хранения (например, «штука»). Поскольку общесистемные единицы не подчинены номенклатуре, создавать подчиненный элемент не нужно.

В обработчике ПослеЗагрузки ПКО Номенклатура достаточно найти общесистемный элемент классификатора по коду и напрямую присвоить его реквизитам объекта:


БазоваяЕдиница = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("796"); // Код штуки по ОКЕИ
Если ЗначениеЗаполнено(БазоваяЕдиница) Тогда
    Объект.ЕдиницаИзмерения = БазоваяЕдиница;
    Если НЕ ЗначениеЗаполнено(Объект.ЕдиницаДляОтчетов) Тогда
        Объект.ЕдиницаДляОтчетов = БазоваяЕдиница;
        Объект.КоэффициентЕдиницыДляОтчетов = 1;
    КонецЕсли;
КонецЕсли;

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

Решение 3. Отложенное создание через обработчик «ПослеЗагрузкиВсехДанных»

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

  1. В обработчике правил конвертации ПередЗагрузкойДанных инициализируем массив в таблице параметров: Параметры.Вставить("СписокСозданнойНоменклатуры", Новый Массив);
  2. В ПКО Номенклатура в обработчике ПослеЗагрузки фиксируем ссылку на успешно загруженный объект: Параметры.СписокСозданнойНоменклатуры.Добавить(Объект.Ссылка);
  3. В обработчике правил конвертации ПослеЗагрузкиВсехДанных обходим накопленную коллекцию. На этом этапе все элементы номенклатуры гарантированно записаны в информационную базу:
    
    ЕдиницаШтука = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("796");
    
    Для Каждого СсылкаНоменклатура Из Параметры.СписокСозданнойНоменклатуры Цикл
        // Проверяем, создана ли уже упаковка для данной номенклатуры
        Выборка = Справочники.УпаковкиЕдиницыИзмерения.Выбрать(, СсылкаНоменклатура);
        Если НЕ Выборка.Следующий() Тогда
            НоваяУпаковка = Справочники.УпаковкиЕдиницыИзмерения.СоздатьЭлемент();
            НоваяУпаковка.ОбменДанными.Загрузка = Истина;
            НоваяУпаковка.Владелец = СсылкаНоменклатура;
            НоваяУпаковка.ЕдиницаИзмерения = ЕдиницаШтука;
            НоваяУпаковка.КоличествоУпаковок = 1;
            НоваяУпаковка.Наименование = "Штука";
            НоваяУпаковка.Записать();
        КонецЕсли;
    КонецЦикла;
    

Использование обработчика ПослеЗагрузкиВсехДанных обеспечивает надежность переноса, исключает ошибки незаписанных ссылок и снижает нагрузку на транзакции при обмене большими массивами номенклатуры.

← На главную