В данной статье описывается решения только для Конвертации данных версии 3. Аналогичная статья по КД 2 (не моя) здесь - infostart.ru/public/730593/
На одном из проектов возникла необходимость настроить обмен данными между конфигурациями УНФ и Бухгалтерия предприятия таким образом, чтобы каждая пара значений "Номенклатура-Характеристика" в УНФ соответствовала отдельной номенклатуре в Бухгалтерии.
Как известно при типовом обмене теряется такая аналитика учёта как "Характеристика" потому-что в Бухгалтерии просто-напросто отсутствует данное понятие.
Рассмотрим данную ситуацию для наглядности на простом примере. В УНФ есть номенклатура "Картофель фри" по которой заведено 3 характеристики - "Большой", "Средний", "Малый" и есть номенклатура "Картофель по-деревенски" по которой учёт по характеристикам не ведётся.
Если настроить обмен по умолчанию, то 2 номенклатуры из УНФ перегрузятся в 2 номенклатуры БП.
УНФ | БП | |
Номенклатура | Характеристика | Номенклатура |
Картофель фри | Большой | Картофель фри |
Средний | ||
Малый | ||
-- | ||
Картофель по-деревенски | -- | Картофель по-деревенски |
Но нам нужно добиться, чтобы 2 номенклатуры из примера из УНФ выгрузились в 5 (в данном случае) различных номенклатурных позиций в БП как в таблице ниже:
УНФ | БП | |
Номенклатура | Характеристика | Номенклатура |
Картофель Фри Картофель Фри Картофель Фри |
Большой | Картофель фри, Большой |
Средний | Картофель фри, Средний | |
Малый | Картофель фри, Малый | |
-- | Картофель фри | |
Картофель по-деревенски | -- | Картофель по-деревенски |
По таблице видно, что одна номенклатурная позиция в базе УНФ превращается в N+1 номенклатурных позиций в БП, где N - количество характеристик у позиции в УНФ. Причина в том, что в УНФ при определённой настройке в карточке номенклатуры даже если включен учёт по характеристикам, то можно осуществлять операции с товаром по пустой характеристике:
Решим поставленную задачу.
Сразу оговоримся, что приведённое решение не универсально, а только частный случай применимый с рядом допущений:
1. Подразумевается, что в УНФ ведётся учет по характеристикам номенклатуры, а характеристики категорий не используются. То есть в УНФ у всех характеристик владельцем является справочник Номенклатура, а не справочник Категории Номенклатуры. Если это не так то необходимо немного другое решение, например создание регистра сведений с Измерениями Номенклатура и Характеристика и ресурсом УникальныйИдентификатор.
2. Используется односторонний обмен. (Выгрузка из УНФ в БП).
3. Синхронизация происходит по уникальным идентификатором (необходимо произвести начальное сопоставление, так как считаем что данные были вбиты руками в обе базы).
4. Сам процесс загрузки и редактирования правил в конфигурации конвертация данных 3.0 рассматривать не будем. Тут полностью стандартный процесс.
Итак, приступим:
Этап 1 - Редактируем правило обработки данных для выгрузки номенклатуры:
Для этого внесем изменения в правило обработки данных "Справочник_Номенклатура_Отправка" в событие "При обработке".
Суть изменений в том, что при выгрузке номенклатуры обходим все её характеристики и для каждой создаём структуру, которую заполняем данными на основе номенклатуры и характеристики. Созданную структуру выгружаем через типовую функцию ОбменДаннымиXDTOСервер.ВыгрузкаОбъектаВыборки().
Изменённое событие будет выглядеть в итоге так:
Процедура ПОД_Справочник_Номенклатура_Отправка_ПриОбработке(ДанныеИБ, ИспользованиеПКО, КомпонентыОбмена)
ИспользованиеПКО.Справочник_Номенклатура_Отправка = Не ДанныеИБ.ЭтоГруппа;
ИспользованиеПКО.Справочник_НоменклатураГруппа = ДанныеИБ.ЭтоГруппа;
Если Не ДанныеИБ.ЭтоГруппа
И ЗначениеЗаполнено(ДанныеИБ.Родитель)
И Не ОбъектСуществуетВБазе(ДанныеИБ.Родитель) Тогда
ИспользованиеПКО.Справочник_Номенклатура_Отправка = Ложь;
КонецЕсли;
// СТАРТ
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХарактеристикиНоменклатуры.Ссылка КАК Ссылка,
| ХарактеристикиНоменклатуры.Код КАК Код,
| ХарактеристикиНоменклатуры.Наименование КАК Наименование
|ИЗ
| Справочник.ХарактеристикиНоменклатуры КАК ХарактеристикиНоменклатуры
|ГДЕ
| ХарактеристикиНоменклатуры.Владелец = &Владелец";
Запрос.УстановитьПараметр("Владелец", ДанныеИБ.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка= РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
сткНоменклатура = Новый Структура();
сткНоменклатура.Вставить("Ссылка",Выборка.Ссылка);
сткНоменклатура.Вставить("ЭтоГруппа",Ложь);
сткНоменклатура.Вставить("АлкогольнаяПродукция", ДанныеИБ.АлкогольнаяПродукция);
сткНоменклатура.Вставить("Артикул", ДанныеИБ.Артикул);
сткНоменклатура.Вставить("ЕдиницаИзмерения",ДанныеИБ.ЕдиницаИзмерения);
сткНоменклатура.Вставить("ИмпортнаяАлкогольнаяПродукция", ДанныеИБ.ИмпортнаяАлкогольнаяПродукция);
сткНоменклатура.Вставить("КатегорияНоменклатуры", ДанныеИБ.КатегорияНоменклатуры);
сткНоменклатура.Вставить("Код",Выборка.Код);
сткНоменклатура.Вставить("Комментарий", ДанныеИБ.Комментарий);
сткНоменклатура.Вставить("Наименование",ДанныеИБ.Наименование + " " + Выборка.Наименование);
сткНоменклатура.Вставить("ОбъемДАЛ", ДанныеИБ.ОбъемДАЛ);
сткНоменклатура.Вставить("ПроизводительИмпортерАлкогольнойПродукции", ДанныеИБ.ПроизводительИмпортерАлкогольнойПродукции);
сткНоменклатура.Вставить("Родитель", ДанныеИБ.Родитель);
сткНоменклатура.Вставить("СтранаПроисхождения",ДанныеИБ.СтранаПроисхождения);
сткНоменклатура.Вставить("ТипНоменклатуры",ДанныеИБ.ТипНоменклатуры );
сткНоменклатура.Вставить("ВидАлкогольнойПродукции", ДанныеИБ.ВидАлкогольнойПродукции);
сткНоменклатура.Вставить("СтавкаНДС", ДанныеИБ.СтавкаНДС);
сткНоменклатура.Вставить("НаименованиеПолное", ДанныеИБ.НаименованиеПолное + " " + Выборка.Наименование);
строкаПравил = КомпонентыОбмена.ПравилаОбработкиДанных.Найти("Справочник_Номенклатура_Отправка");
ОбменДаннымиXDTOСервер.ВыгрузкаОбъектаВыборки(КомпонентыОбмена, сткНоменклатура, строкаПравил);
КонецЦикла;
// СТОП
КонецПроцедуры
Этап 2 - ПКО Спецификации номенклатуры.
Данное ПКО выделим отдельно, так как тут нестандартная по сравнению с остальными объектами метаданных ситуация - реквизит "Характеристика" присутствует как у самого справочника, так и его табличной части.
Для начала создадим Алгоритмы, которые будут создавать структуру из характеристики для дальнейшей выгрузки в ключевые свойства Номенклатуры. Также в этой функции будем генерировать реквизиты "Наименование" и "НаименованиеПолное".
Функция ПолучитьСтруктуруИзХарактеристикиИНоменклатуры(Номенклатура, Характеристика)
стк = Новый Структура();
стк.Вставить("Ссылка", Характеристика.Ссылка);
стк.Вставить("Код", Характеристика.Код);
стк.Вставить("Наименование",Номенклатура.Наименование + ", " + Характеристика.Наименование);
стк.Вставить("НаименованиеПолное", Номенклатура.НаименованиеПолное + ", " + Характеристика.НаименованиеДляПечати);
стк.Вставить("Артикул", Номенклатура.Артикул);
Возврат стк;
КонецФункции
Далее создадим алгоритм для замены номенклатуры в таблицах значений:
Процедура ЗаменитьНоменклатуруХарактеристикой(ТабличнаяЧасть)
ТабличнаяЧасть.Колонки.Добавить("НоменклатураСтруктурой");
Для Каждого Строка Из ТабличнаяЧасть Цикл
Если ЗначениеЗаполнено(Строка.Характеристика) Тогда
Строка.НоменклатураСтруктурой = ПолучитьСтруктуруИзХарактеристикиИНоменклатуры(Строка.Номенклатура,Строка.Характеристика);
Иначе
Строка.НоменклатураСтруктурой = Строка.Номенклатура.Ссылка;
КонецЕсли;
КонецЦикла;
ТабличнаяЧасть.Колонки.Удалить("Номенклатура");
ТабличнаяЧасть.Колонки.НоменклатураСтруктурой.Имя = "Номенклатура";
КонецПроцедуры
Теперь используя эти алгоритмы внесём изменения в само событие при отправке:
Процедура ПКО_Справочник_СпецификацииНоменклатуры_Отправка_ПриОтправкеДанных(ДанныеИБ, ДанныеXDTO, КомпонентыОбмена, СтекВыгрузки)
Если СтекВыгрузки.Количество() > 1 Тогда
Возврат;
КонецЕсли;
ДанныеXDTO.Вставить("Количество", 1);
// СТАРТ
Если ЗначениеЗаполнено(ДанныеИБ.ХарактеристикаПродукции) Тогда
стк = ПолучитьСтруктуруИзХарактеристикиИНоменклатуры(ДанныеИБ.Владелец, ДанныеИБ.ХарактеристикаПродукции);
ДанныеXDTO.Номенклатура.Ссылка = стк.Ссылка;
ДанныеXDTO.Номенклатура.КодВпрограмме = стк.Код;
ДанныеXDTO.Номенклатура.Наименование = стк.Наименование;
ДанныеXDTO.Номенклатура.НаименованиеПолное = стк.НаименованиеПолное;
КонецЕсли;
// СТОП
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СпецификацииСостав.Номенклатура КАК Номенклатура,
| ВЫБОР
| КОГДА СпецификацииСостав.Количество = 0
| ТОГДА 1
| ИНАЧЕ СпецификацииСостав.Количество
| КОНЕЦ КАК Количество,
| ВЫБОР
| КОГДА СпецификацииСостав.ДоляСтоимости = 0
| ТОГДА 1
| ИНАЧЕ СпецификацииСостав.ДоляСтоимости
| КОНЕЦ КАК ДоляСтоимости,
// СТАРТ
| СпецификацииСостав.Характеристика КАК Характеристика
// СТОП
|ИЗ
| Справочник.Спецификации.Состав КАК СпецификацииСостав
|ГДЕ
| СпецификацииСостав.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ДанныеИБ.Ссылка);
ТаблицаСостав = Запрос.Выполнить().Выгрузить();
// СТАРТ
ЗаменитьНоменклатуруХарактеристикой(ТаблицаСостав);
// СТОП
Если ТаблицаСостав.Количество() > 0 Тогда
ДанныеXDTO.Вставить("Товары", ТаблицаСостав);
КонецЕсли;
КонецПроцедуры
Итак, ПКО готово. Так как в других справочниках, выгружаемых в EnterpriseData характеристики не используются переходим к документам.
Этап 3 - Подменяем номенклатуру при выгрузке по ссылке из документов.
Теперь нужно подменить номенклатура на характеристику во всех документах. После внимательного изучения правил обмена увидим, что данные по документам получаются с помощью алгоритмов, название которых начинается с "ДанныеДокумента".
Всего их больше 30. К сожалению придётся для начала проверить каждый запрос в этих ПКО на наличие выбора поля "Характеристика" если выбирается поле "Номенклатура" и там где оно не выбирается - добавить.
После этого уже используем созданный нами алгоритм ЗаменитьНоменклатуруХарактеристикой(). Ниже приведён пример доработки для ДанныеДокументаАктВыполненныхРабот(). Все остальные функции редактируются аналогично. Все переработанные алгоритмы можно скачать во вложенном файле, который представляет из себя сохраненный в txt модуль "МенеджерОбменаЧерезУниверсальныйФормат".
Функция ДанныеДокументаАктВыполненныхРабот(ДанныеИБ)
Результат = Новый Структура;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| АктВыполненныхРаботРаботыИУслуги.НомерСтроки КАК НомерСтрокиДокумента,
| АктВыполненныхРаботРаботыИУслуги.Номенклатура КАК Номенклатура,
| ВЫБОР
| КОГДА ТИПЗНАЧЕНИЯ(АктВыполненныхРаботРаботыИУслуги.ЕдиницаИзмерения) = ТИП(Справочник.ЕдиницыИзмерения)
| ТОГДА ВЫРАЗИТЬ(АктВыполненныхРаботРаботыИУслуги.Количество * АктВыполненныхРаботРаботыИУслуги.ЕдиницаИзмерения.Коэффициент КАК ЧИСЛО(15, 3))
| ИНАЧЕ АктВыполненныхРаботРаботыИУслуги.Количество
| КОНЕЦ КАК Количество,
| ВЫБОР
| КОГДА ТИПЗНАЧЕНИЯ(АктВыполненныхРаботРаботыИУслуги.ЕдиницаИзмерения) = ТИП(Справочник.ЕдиницыИзмерения)
| И АктВыполненныхРаботРаботыИУслуги.ЕдиницаИзмерения.Коэффициент > 0
| ТОГДА ВЫРАЗИТЬ(АктВыполненныхРаботРаботыИУслуги.Цена / АктВыполненныхРаботРаботыИУслуги.ЕдиницаИзмерения.Коэффициент КАК ЧИСЛО(15, 2))
| ИНАЧЕ АктВыполненныхРаботРаботыИУслуги.Цена
| КОНЕЦ КАК Цена,
| АктВыполненныхРаботРаботыИУслуги.Сумма КАК Сумма,
| АктВыполненныхРаботРаботыИУслуги.СтавкаНДС КАК СтавкаНДС,
| АктВыполненныхРаботРаботыИУслуги.СуммаНДС КАК СуммаНДС,
| ВЫБОР
| КОГДА АктВыполненныхРаботРаботыИУслуги.Номенклатура.СчетУчетаЗатрат <> ЗНАЧЕНИЕ(ПланСчетов.Управленческий.ПустаяСсылка)
| И (АктВыполненныхРаботРаботыИУслуги.Номенклатура.СчетУчетаЗатрат.ТипСчета = ЗНАЧЕНИЕ(Перечисление.ТипыСчетов.КосвенныеЗатраты)
| ИЛИ АктВыполненныхРаботРаботыИУслуги.Номенклатура.СчетУчетаЗатрат.ТипСчета = ЗНАЧЕНИЕ(Перечисление.ТипыСчетов.НезавершенноеПроизводство))
| ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ПроизводственныйРасход,
| ВЫБОР
| КОГДА ПОДСТРОКА(АктВыполненныхРаботРаботыИУслуги.Содержание, 1, 100) = """"
| ТОГДА АктВыполненныхРаботРаботыИУслуги.Номенклатура.НаименованиеПолное
| КОНЕЦ КАК Содержание,
// СТАРТ
| АктВыполненныхРаботРаботыИУслуги.Характеристика КАК Характеристика
// СТОП
|ИЗ
| Документ.АктВыполненныхРабот.РаботыИУслуги КАК АктВыполненныхРаботРаботыИУслуги
|ГДЕ
| АктВыполненныхРаботРаботыИУслуги.Ссылка = &Ссылка
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| АктВыполненныхРаботПредоплата.Документ КАК Документ,
| АктВыполненныхРаботПредоплата.СуммаРасчетов КАК Сумма
|ИЗ
| Документ.АктВыполненныхРабот.Предоплата КАК АктВыполненныхРаботПредоплата
|ГДЕ
| АктВыполненныхРаботПредоплата.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ДанныеИБ.Ссылка);
РезультатыЗапроса = Запрос.ВыполнитьПакет();
ТаблицаУслуги = РезультатыЗапроса[0].Выгрузить();
ЗаполнитьСтавкиНДС_Отправка(ТаблицаУслуги);
// СТАРТ
ЗаменитьНоменклатуруХарактеристикой(ТаблицаУслуги);
// СТОП
Результат.Вставить("Услуги", ТаблицаУслуги);
ПогашениеЗадолженности = Новый ТаблицаЗначений;
ПогашениеЗадолженности.Колонки.Добавить("ДокументРасчетов");
ПогашениеЗадолженности.Колонки.Добавить("Сумма");
ВыборкаРасчеты = РезультатыЗапроса[1].Выбрать();
Пока ВыборкаРасчеты.Следующий() Цикл
ДокументРасчетов = Новый Структура("Значение, ИмяПКО", ВыборкаРасчеты.Документ, ИмяПКОДляДокумента(ВыборкаРасчеты.Документ));
Если Не ЗначениеЗаполнено(ДокументРасчетов.Значение)
ИЛИ Не ЗначениеЗаполнено(ДокументРасчетов.ИмяПКО) Тогда
Продолжить;
КонецЕсли;
СтрокаРасчеты = ПогашениеЗадолженности.Добавить();
СтрокаРасчеты.ДокументРасчетов = ДокументРасчетов;
СтрокаРасчеты.Сумма = ВыборкаРасчеты.Сумма;
КонецЦикла;
Результат.Вставить("ПогашениеЗадолженности", ПогашениеЗадолженности);
Возврат Результат;
КонецФункции