Есть две базы 8.2, между ними запускается обмен. Номенклатура конвертируются по принципу: Если не находим номенклатуру по связке 3-ех полей (Наименование, Код, ЭтоГруппа), то ищем ее в приемнике в регистре сведений "Номенклатура контрагентов". В правиле конвертации номенклатуры, стоит признак "Не создавать новый объект в приемнике, если он НЕ найден".
Задача:
Не начинать/Полностью откатывать обмен (в транзакции) если номенклатура не нашлась в приемнике. При этом выдавать сообщение об ошибке с наименованием номенклатуры источника, которой нет в приемнике.
Я тоже считаю, что нужно проверку делать перед загрузкой данных.
Все про это пишут, но никакой конкретики, вот что у меня получилось (делал с контрагентами, но суть от этого не изменится):
Мысль такая:
1. При выгрузке данных заполняем массив, где будут все выгруженные контрагенты
2. После выгрузки этот массив сохраняется в файл (через параметр передать не получилось)
3. После загрузки параметров, читаем массив из файла
4. Проверяем контрагентов, если что-то не устраивает - отказываемся от загрузки
Плохой нюанс в том, что данные сохраняются в файл, возможно возникнут проблемы если будут выгружать - загружать несколько пользователей (или даже 1 пользователь но "перепутает файл с данными")
Хотя имя файла можно попробовать формировать через Новый УникальныйИдентификатор(), тогда путаница точно не возникнет.
я делал предзагрузку.
Вычитываю справочники, пропускаю документы. При загрузке справочников кладу в кэш результат загрузки.
После предзагрузки анализирую кэш и т.д. продолжаю или прерываюсь.
ПЕРЕД ЗАГРУЗКОЙ ДАННЫХ
//----------------------------------------------------------------------------------------------------
ДанныеЗагрузки= Новый Структура();
Параметры.ДанныеЗагрузки= ДанныеЗагрузки;
Кэш= Новый Структура();
Кэш.Вставить("Номенклатура",Новый Соответствие());
Кэш.Вставить("СоответствиеНПП",Новый Соответствие());
Кэш.Вставить("Контрагенты",Новый Соответствие());
Кэш.Вставить("Договора",Новый Соответствие());
Параметры.КэшЗагрузки= Кэш;
//----------------------------------------------------------------------------------------------------
Предзагрузка= Новый Соответствие;
Предзагрузка.Вставить("СправочникСсылка.Контрагенты",Истина);
Предзагрузка.Вставить("СправочникСсылка.ДоговорыКонтрагентов",Истина);
Ответ = Вопрос("Выполнить вначале загрузку справочников?", РежимДиалогаВопрос.ДаНет, 60);
Если Ответ = КодВозвратаДиалога.Да Тогда
Попытка // Скопировано из штатной обработки
Пока ФайлОбмена.Прочитать() Цикл
ИмяУзла = ФайлОбмена.ЛокальноеИмя;
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
Если ИмяУзла = "Объект" Тогда
// Обрабатываем только типы из соответствия.
ТипОбъектаСтрокой = одАтрибут(ФайлОбмена, одТипСтрока, "Тип");
Если Предзагрузка.Получить(ТипОбъектаСтрокой)<> Неопределено Тогда // Проверяем и грузим только то что нужно.
ПоследнийОбъектЗагрузки = ПрочитатьОбъект();
ОбработатьОкончаниеЧтенияНовогоЭлемента(ПоследнийОбъектЗагрузки);
Иначе
одПропустить(ФайлОбмена, "Объект"); // Всё остальное пропускаем
ПоследнийОбъектЗагрузки = Неопределено;
КонецЕсли;
ИначеЕсли ИмяУзла = "ЗначениеПараметра" Тогда // Параметры грузим - на будущее.
ЗагрузитьЗначенияПараметровОбменаДанными();
Иначе
одПропустить(ФайлОбмена);
КонецЕсли;
КонецЦикла;
Исключение
СтрокаОшибки = ОписаниеОшибки();
РезультирующаяСтрокаСИнформациейОбОшибке = ЗаписатьВПротоколВыполнения("Ошибка при загрузке данных: " + СтрокаОшибки, Неопределено, Истина, , , Истина);
ЗавершитьВедениеПротоколаОбмена();
ФайлОбмена.Закрыть();
КонецПопытки;
// ПРЕДЗАГРУЗКА ОКОНЧЕНА
// ВОЗРВАЩАЕМ ПЕРЕМЕННЫЕ В ИСХОДНОЕ СОСТОЯНИЕ
// Переоткрываем файл заново.
ФайлОбмена = Новый ЧтениеXML();
ФайлОбмена.ОткрытьФайл(ИмяФайлаОбмена);
ФайлОбмена.Прочитать();
// Устанавливаем соответствия.
//ОбработкаСоответствий= ВнешниеОбработки.Создать("m:\documents\work\Казахстан\УстановкаСоответствий.epf");
ОбработкаСоответствий= ДопОбработки.ОбработкаСоответствий;
ОбработкаСоответствий.КэшЗагрузки= Параметры.КэшЗагрузки;
Если ОбработкаСоответствий.Инициализировать() Тогда
НеЗагружать= ОбработкаСоответствий.ПолучитьФорму().ОткрытьМодально();
Отказ= НеЗагружать= Истина;
Если Не Отказ Тогда
Для Каждого эл из ОбработкаСоответствий.Контрагенты Цикл // Устанавливаем новые соответсвия в кэш загруженных данных. Заглушка(может просто очистить кэш?)
Если ЗначениеЗаполнено(эл.Ссылка) Тогда
СтруктураЗаписи = Новый Структура("СсылкаНаОбъект, СсылкаФиктивная");
СтруктураЗаписи.СсылкаНаОбъект= эл.Ссылка;
ЗагруженныеОбъекты[эл.Нпп] = СтруктураЗаписи; // Заглушка(Считаем что для контрагентов не будет "быстрого поиска при загрузке" (ГНпп))
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Показать
В нужных ПКО: Например Контрагенты.
ПОЛЯ ПОИСКА - запоминаем объект и его свойства, которые искали.
ПРИ ЗАГРУЗКЕ - если нашли объект, добавляем его ссылку в сохраненные свойства.
Если ОбъектНайден Тогда
НомерСсылки= ?(НППГлобальнойСсылки= 0,НППСсылки,НППГлобальнойСсылки);
СтрОбъекта= Параметры.КэшЗагрузки.Контрагенты.Получить(НомерСсылки);
стрОбъекта.Вставить("Ссылка",Ссылка);
Параметры.КэшЗагрузки.Контрагенты.Вставить(НомерСсылки,стрОбъекта);
Параметры.КэшЗагрузки.СоответствиеНПП.Вставить(Ссылка,НомерСсылки); // Это чтобы искать Владельца для договора
КонецЕсли;
В типовом обмене в обработке ОбменДаннымиXml, есть настройка - "Использовать транзакции при выгрузке для планов обмена". Т.е весь обмен идет в транзакции.
Потом в алгоритме поиска, нужно указать, что то наподобии "Если ОбъектНайден=Ложь Тогда ВызватьИсключение НазваниеНоменклатуры"
(3) red80, А где в конвертации данных взять такой обработчик "ПередНачаломОбмена". И если допустить, что есть такой обработчик, то данный обработчик по логике вещей должен видеть данные источника, но никак приемника.
Если НомерВариантаПоиска = 1 И ПараметрыОбъекта<>Неопределено Тогда
Выполнить(Алгоритмы.ПоискПоСоответствию);
Иначе
СтрокаИменСвойствПоиска = "Код, Наименование,ЭтоГруппа";
КонецЕсли;
Если НЕ ОбъектНайден Тогда
СтрокаИменСвойствПоиска = "Код, Наименование,ЭтоГруппа";
КонецЕсли;
Показать
Алгоритм.ПоискПоСоответствию
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| СоответствиеОбъектовДляОбмена.СобственнаяСсылка КАК Ссылка
|ИЗ
| РегистрСведений.СоответствиеОбъектовДляОбмена КАК СоответствиеОбъектовДляОбмена
|ГДЕ
| СоответствиеОбъектовДляОбмена.УзелОбмена = &УзелОбмена
| И СоответствиеОбъектовДляОбмена.СсылкаВДругойИБ = &СсылкаВДругойИБ
| И СоответствиеОбъектовДляОбмена.ИмяТипаПриемника = &ИмяТипаПриемника";
Запрос.УстановитьПараметр("УзелОбмена", Неопределено);
Запрос.УстановитьПараметр("СсылкаВДругойИБ",ПараметрыОбъекта.Получить("СсылкаСтрокой"));
Запрос.УстановитьПараметр("ИмяТипаПриемника", СтруктураСвойств.ТипСсылкиСтрокой);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
СсылкаНаОбъект=Выборка.Ссылка;
ОбъектНайден=Истина;
КонецЕсли;
Показать
Скидываю свой алгоритм, может окажется полезным.
Вот в конце обработчика твоего "Поля поиска" пишешь Если ОбъектНайден=Ложь Тогда ВызватьИсключение ТвойПараметр КонецЕсли;
Или в Обработчике "ПриЗагрузке" пишешь такой код.
(14) alexlights, Поиск по соответствию обмен делает сам автоматически. Переменной "ОбъектНайден" нет в обработчике "Поля поиска", она есть в обработчике "ПриЗагрузке".
Если ОбъектНайден=Ложь Тогда ВызватьИсключение ТвойПараметр КонецЕсли;
- хотелось бы увидеть пример. И есть ли возможность в справочнике "Настройка обмена данными" указать, что обмен происходит в единой транзакции?
(15) Lyns_owner, В Справочнике "НастройкиОбменаДанными", на вкладке Интерактивный обмен. Там указываются указываются количество элементов в транзакции. Можно поставить нереальное число и весь обмен будет в одной транзакции.
(17) alexlights, Если почитать подсказку к этому полю то там написано следующее: "Количество элементов данных, обрабатываемых в одной транзакции на загрузку. Если 0 то все данные загружаются в одной транзакции".
В обработчике "При загрузке" ПКО "Номенклатура" написал:
Если НЕ ОбъектНайден Тогда
ТекстОшибки = "Не найдено соответствие номенклатуры " + Параметры.НаименованиеПолное + " в базе приемнике!";
ВызватьИсключение ТекстОшибки;
КонецЕсли;
- не взлетело. Обмен спокойно сработал: создал, что нашел, что не нашел - не создал.
Пошел по другому пути: В обработчике "Поля поиска" ПКО "Номенклатура" написал код (приведу кусок):
Если Выборка.Следующий() Тогда
СсылкаНаОбъект = Выборка.Номенклатура;
Иначе
СсылкаНаОбъект = Неопределено;
ТекстОшибки = "Не найдено соответствие номенклатуры " + СвойстваПоиска.Получить("Наименование") + " в базе приемнике!";
ВызватьИсключение ТекстОшибки;
КонецЕсли;
- взлетело - обмен встал с моим текстом ошибки. Это уже кое-что. Но все-таки обмен прошел не в транзакции, что успело загрузиться - то осталось.
Есть две базы 8.2, между ними запускается обмен. Номенклатура конвертируются по принципу: Если не находим номенклатуру по связке 3-ех полей (Наименование, Код, ЭтоГруппа), то ищем ее в приемнике в регистре сведений "Номенклатура контрагентов". В правиле конвертации номенклатуры, стоит признак "Не создавать новый объект в приемнике, если он НЕ найден".
Задача:
Не начинать/Полностью откатывать обмен (в транзакции) если номенклатура не нашлась в приемнике. При этом выдавать сообщение об ошибке с наименованием номенклатуры источника, которой нет в приемнике.
Ваши Правила обмена прикрепите или на внешний ресурс и ссылку киньте на нее
(16) kilokilo, Это специфические базы данных, у вас нет описания их метаданных. В правилах обмена пока нет ничего кроме вышеприведенного кода обработчика "Поля поиска" ПКО "Номенклатура". Кроме того, не вижу в этом ровно никакого смысла, если только вы не хотите скинуть мне готовые правила обмена)
Я предпочитаю писать свои обработки обмена, если есть возможность, то не через файлы обмена, а через подключение COM/OLE, в этом случае пусть затрачу чуть больше времени на написание и настройку, но зато получаю большую гибкость при проведении обменов. А когда есть готовые шаблоны, то настройка таких обменов по времени сопоставима с настройкой в конвертации данных
(23) Farpost, А смысл написания ручного обмена. Тут никакой гибкости. Если обмен происходит между конфигурациями 1С, то быстрее, гибче делать через конвертацию данных. Ну а всякие мелочи, то можно и вручную написать.
Быстрее может быть, но ненамного и то сомневаюсь, а насчёт гибкости - я в коде гораздо большими возможностями и инструментами обладаю, нежели настройки в конвертации... ибо язык внутренний ниже уровнем чем настройки внутри конфигурации, ну, а недостатков файлообмена, я вообще касаться не буду... впрочем у каждого свои предпочтения... мне лично удобнее работать не с конвертацией данных, а с внешними обработками, начинающим само собой чем выше уровень, тем легче...
Я же не говорю, что КД это плохо - я говорю, что мне удобнее
(26) Farpost, Как смешно читать ваше сообщение. Собираясь поесть, вы не возьмете в руку вилку, вы скажете, что она неудобная. Пойдете добывать руду, затем будете ее обрабатывать и в итоге у вас получится жалкое подобие вилки, которым вы будете гордо пользоваться. Остальным же останется только посмеяться над вами.
Плюс ко всему, кто сказал, что обмен по правилам обмена не может работать через COM/OLE?
Ребята, вы смотрю не вышли ещё из возраста детского, всё то у вас в черно-белом контрастном цвете... КД инструмент типа конструктора, язык тоже инструмент, но типа несколько другого, им конструкторы создают, кому привычней будет работать на уровне языка - это моё и никому я его не навязываю... насчёт руды и вилки -
(26) Собираясь поесть, вы не возьмете в руку вилку, вы скажете, что она неудобная. Пойдете добывать руду, затем будете ее обрабатывать и в итоге у вас получится жалкое подобие вилки, которым вы будете гордо пользоваться.
Вы сударь передёргиваете и слишком сильно... я же не призываю писать обработки на ассемблере..., хотя вы наверное про такой язык и не слыхивали...
Хотя истины ради настоящие спецы на ассемблере такие вещи делают - никаким языкам более высокого уровня не угнаться...
Ещё раз повторю, для особо упёртых - Я НЕ ГОВОРЮ, ЧТО КД ГОВНО!!! Я ГОВОРЮ, ЧТО ЛИЧНО МНЕ УДОБНЕЕ ПОЛЬЗОВАТЬСЯ ВНЕШНИМИ САМОПИСНЫМИ ОБРАБОТКАМИ!!!
Если Вам удобнее ваять обмен в КД - флаг в руки и вперёд, только тогда возникает вопрос - а что при всём удобстве и гибкости КД знаний не хватает решить проблемы при обмене, раз вы их здесь выносите или всё таки КД не такая уж гибкая весч? ;-)
а что при всём удобстве и гибкости КД знаний не хватает решить проблемы
Если я не знаю, как решить задачу с помощью определенного функционала, это еще не означает, что данным функционалом задачу решить нельзя.
Если у меня нет опыта в решении какого-либо вопроса, это не означает, что типовыми средствами я его не решу и буду писать функционал, который, возможно, уже не раз был написан и отлажен. Первым делом я попытаюсь решить вопрос типовыми средствами.
Не умеете пользоваться функционалом и не хотите учиться - ваше дело, пишите свой неуниверсальный функционал.
Впредь попрошу в данной теме писать по вопросу, описанному в первом сообщении, а не флудить.
А я смотрю Вы сразу родились со знанием 1С :) И ни у кого не спрашивали как решить проблему
Нет конечно - учился, спрашивал, экспериментировал..., но при этом никому не навязывал своего мнения - оно моё и для меня... так же как весь мой опыт. И своим мнением и опытом я делюсь с другими, так же как делились со мной мои "учителя" в том числе и заочные...
Интересно. А обмен между двумя разнородными конфигурациями с кучей справочников, документов Вы тоже будете делать через самописную обработку ?
Если Вам интересно - как раз обмен между разнородными конфигурациями наиболее эффективно получается при использовании самописной моей обработки - это из моего личного опыта...
Что за глупые оскорбления? Кто из нас после этого ребенок?
Ну дык не я же первый начал... вот ваш посыл, если забыли:
(26) Farpost, Как смешно читать ваше сообщение. Собираясь поесть, вы не возьмете в руку вилку, вы скажете, что она неудобная. Пойдете добывать руду, затем будете ее обрабатывать и в итоге у вас получится жалкое подобие вилки, которым вы будете гордо пользоваться. Остальным же останется только посмеяться над вами.
Хех, развели тут... В общем, нужно просто в обработчике "Перед загрузкой данных" вручную проверить загружаемую номенклатуру и вызвать исключении при ее отсутствии.
в общем согласна с (37) .. но я бы использовала "после загрузки объекта" в обработчиках конвертации .. т.е. глобальный обработчик , там есть ссылка и объект , если ссылка не определена , но объект не записывать и падать.
(37) Robot123, (38) Нагайна,
Как бы это проблему то решили :) Читаем внимательно посты.
Нужно, что бы откатывался весь обмен. Это Вы можете увидеть, если еще раз перечитаете первое сообщение ТС
Как бы это проблему то решили :) Читаем внимательно посты.
Нужно, что бы откатывался весь обмен. Это Вы можете увидеть, если еще раз перечитаете первое сообщение ТС
- не совсем понял : проблема с транзакцией решена?
При чем здесь транзакции. Я же русским языком написал, что нужна проверка до загрузки всех данных и реализовать ее можно в глобальном обработчике "Перед загрузкой данных". Тогда и откатывать никакие измения не придется. Номенклатуру для проверки можно поместить в параметры конвертации в какую-нибудь коллекцию.
Я тоже считаю, что нужно проверку делать перед загрузкой данных.
Все про это пишут, но никакой конкретики, вот что у меня получилось (делал с контрагентами, но суть от этого не изменится):
Мысль такая:
1. При выгрузке данных заполняем массив, где будут все выгруженные контрагенты
2. После выгрузки этот массив сохраняется в файл (через параметр передать не получилось)
3. После загрузки параметров, читаем массив из файла
4. Проверяем контрагентов, если что-то не устраивает - отказываемся от загрузки
Плохой нюанс в том, что данные сохраняются в файл, возможно возникнут проблемы если будут выгружать - загружать несколько пользователей (или даже 1 пользователь но "перепутает файл с данными")
Хотя имя файла можно попробовать формировать через Новый УникальныйИдентификатор(), тогда путаница точно не возникнет.
(50) Lyns_owner, тогда тем более незначительно увеличится объем передаваемых данных. А при прямом подключении вообще почти не ощутится нагрузка при моем методе
а что собсно мешает создать правила сначала для поиска, а затем уже для конечной загрузки?
т.е. первый раз выгружаем только связку реквизитов по которым ищете, перед загрузкой проверка на найден ли элемент. в параметрах конвертации указываем флаг были ли пропуски при загрузке этих полей проверки. если хоть одна номенклатура пропущена, тогда загрузку реальную не начинаем вообще.
(46) serg_gres, а чем не нравится событие ПередЗагрузкойОбъекта у конвертации данных? по сути ведь то же самое что и прописывать у каждого объекта перед загрузкой? (Поправьте, если не так, сам ни разу не использовал это событие)
А что мешает в обработчике "Поля поиска" описать свой алгоритм поиска объекта в базе приемника. Если объект не найден указать "ПрекратитьПоиск = Истина". Потом в обработчике ПриЗагрузке написать
Если НЕ ОбъектНайден Тогда
Отказ = Истина
КонецЕсли
В типовом обмене в обработке ОбменДаннымиXml, есть настройка - "Использовать транзакции при выгрузке для планов обмена". Т.е весь обмен идет в транзакции.
Потом в алгоритме поиска, нужно указать, что то наподобии "Если ОбъектНайден=Ложь Тогда ВызватьИсключение НазваниеНоменклатуры"
А что мешает в обработчике "Поля поиска" описать свой алгоритм поиска объекта в базе приемника. Если объект не найден указать "ПрекратитьПоиск = Истина".
(53) Rufous,
Параметр "ОбъектНайден" доступен в обработчике ПриЗагрузке, там же и надо вызывать исключение. При этом объект не должен записаться, а транзакция должна откатиться. Именно это и требуется в задаче.
Я может не правильно прочитал условие задачи, но если обе БД находятся "территориально рядом", стоит использовать СОМ подключение для обмена.
В этом случае источник будет видеть приемник. Обмен будет проходить в одно действие, а не в два. И всю процедуру можно будет взять в общую транзакцию и в любой момент откатить. Этот способ значительно лучше, но имеет целый ряд технических нюансов. Если такой способ допустим по условию - можем обсудить условия реализации.