Право удаление неприменимо к регистрсведений

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

В представленных алгоритмах были проработаны следующие вопросы:

1. Запуск синхронизации производится в реальном режиме времени при записи (удалении) объекта (документа, справочника), но только если запись выполняется интерактивно. То есть, при пакетном перепроведении документов при восстановлении последовательности или из обработки «Групповая обработка справочников и документов» синхронизация не требуется (предполагается, что движения документов не переносятся, а формируются при проведении).

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

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

4. Для универсальности данные передаются в базу приемник в формате XML, сформированными программно с помощью обработки «Универсальный обмен данными XML» по правилам обмена, подготовленными в конфигурации «Конвертация данных». Соответственно, на стороне приемника производится загрузка этой же обработкой. Как правило, во всех типовых конфигурациях данная обработка присутствует, а для самописных можно загрузить из состава .cf данной публикации.

5. Пакет передаваемых данных должен иметь минимальный объем данных, Чтобы не загружать сетевые службы и Веб-сервер. Для этих целей, предусмотрено:

— за один раз производится выгрузка только одного объекта (с подчиненными объектами, выгруженными по ссылкам, если это справочник);

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

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

Реализация

1. Для всех синхронизируемых объектов в форме элемента справочника (форме документа) в обработчике «При открытии» необходимо добавить следующий код: Процедура ПриОткрытии() ДополнительныеСвойства.Вставить(«СинхронизироватьПриЗаписи»); КонецПроцедуры 2. Добавляем подписки на события

3. Общий модуль «ЛУ_СинхронизацияКлиентСервер» (Сервер, Клиент Обычное приложение) — обработчики подписок Процедура ОбъектПриЗаписиСинхронизировать(Источник, Отказ) Экспорт ПланОбменаРегистрацияИзменений(ПланыОбмена.ЛУ_WebСервис, Источник, Отказ); КонецПроцедуры Процедура ОбъектПередУдалениемСинхронизировать(Источник, Отказ) Экспорт ПланОбменаРегистрацияИзменений(ПланыОбмена.ЛУ_WebСервис, Источник, Отказ, Истина); КонецПроцедуры Процедура ПланОбменаРегистрацияИзменений(ПланОбмена, Источник, Отказ, Удаление=Ложь) Экспорт #Если НЕ ТолстыйКлиентОбычноеПриложение Тогда Возврат; #КонецЕсли Если Отказ или Источник.ОбменДанными.Загрузка Тогда Возврат; КонецЕсли; Если НЕ (Источник.ДополнительныеСвойства.Свойство(«СинхронизироватьПриЗаписи») или Удаление) Тогда Возврат; КонецЕсли; ПланОбменаМетаданные = ПланОбмена.ПустаяСсылка().Метаданные(); Если НЕ ПланОбменаМетаданные.Состав.Содержит(Источник.Метаданные()) Тогда Возврат; КонецЕсли; // Регистрация изменениий в плане обмена ВыборкаУзлов = ПланОбмена.Выбрать(); Пока ВыборкаУзлов.Следующий() Цикл ТекущийУзел = ВыборкаУзлов.Ссылка; Если ТекущийУзел = ПланОбмена.ЭтотУзел() Тогда Продолжить; КонецЕсли; Если НЕ ТекущийУзел.Синхронизировать Тогда Продолжить; КонецЕсли; ОбъектРегистрации = ?(Удаление, Новый УдалениеОбъекта(Источник.Ссылка), Источник.Ссылка); ПланыОбмена.ЗарегистрироватьИзменения(ТекущийУзел, ОбъектРегистрации); КонецЦикла; ЛУ_СинхронизацияВызовСервера.ПланОбменаСинхронизироватьАсинхронно(ПланОбменаМетаданные.Имя); КонецПроцедуры 4. План обмена ЛУ_WebСервис

Здесь:

  • Синхронизировать — булево,
  • Сервер, База, Пользователь, Пароль — Строка, 100, переменная
  • ПравилаКонвертации — ХранилищеЗначения (в форме узла реализована загрузка в этот реквизит правил обмена из файла XML)

5. Общий модуль «ЛУ_СинхронизацияВызовСервера» (Сервер, Вызов сервера) (для наглядности из листингов исключены все конструкции связанные с обработкой исключений, вывода ошибок, и вспомогательные методы) Процедура ПланОбменаСинхронизировать(ИмяПланаОбмена) Экспорт ПланОбмена = ПланыОбмена; ВыборкаУзлов = ПланОбмена.Выбрать(); Пока ВыборкаУзлов.Следующий() Цикл ТекущийУзел = ВыборкаУзлов.Ссылка; Если ТекущийУзел = ПланОбмена.ЭтотУзел() Тогда Продолжить; КонецЕсли; Если НЕ ТекущийУзел.Синхронизировать Тогда Продолжить; КонецЕсли; ИмяСобытияДляЖурнала = «ПланОбмена.» + ИмяПланаОбмена + » » + ПланОбмена.ЭтотУзел().Код + » -> » + ТекущийУзел.Код; ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения(); ЗаписьСообщенияXML = Новый ЗаписьXML; ЗаписьСообщенияXML.УстановитьСтроку(); Попытка ЗаписьСообщения.НачатьЗапись(ЗаписьСообщенияXML, ТекущийУзел); Исключение // ТекущийУзел заблокирован, пока пропустим, следующая попытка будет по регламентному заданию через 60 сек Продолжить; КонецПопытки; НомерСообщения = ЗаписьСообщения.НомерСообщения; МетаданныеДокументы = Метаданные.Документы; МассивУдаляемыхОбъектов = Новый Массив; МассивОбъектов = Новый Массив; Выборка = ПланыОбмена.ВыбратьИзменения(ТекущийУзел, НомерСообщения); Пока Выборка.Следующий() Цикл // В этом цикле только подготовим массив объектов, содержащихся в сообщении плана обмена // Чтобы побыстрее освободить ЗаписьСообщения // (до вызова метода ЗакончитьЗапись() в плане обмена устанавливается исключительная блокировка) Объект = Выборка.Получить(); Если ТипЗнч(Объект) = Тип(«УдалениеОбъекта») Тогда МассивУдаляемыхОбъектов.Добавить(Объект); ИначеЕсли НЕ МетаданныеДокументы.Содержит(Объект.Ссылка.Метаданные()) Тогда МассивОбъектов.Вставить(0, Объект.Ссылка); // Документы сдвигаем в конец массива Иначе МассивОбъектов.Добавить(Объект.Ссылка); КонецЕсли; КонецЦикла; Если МассивОбъектов.Количество() = 0 и МассивУдаляемыхОбъектов.Количество() = 0 Тогда ЗаписьСообщения.ПрерватьЗапись(); // Освобождаем номер сообщения плана обмена Продолжить; КонецЕсли; ЗаписьСообщения.ЗакончитьЗапись(); // Фиксируем исходящее сообщение плана обмена данных // Полученный XML сообщения игнорируем. // Так как в базе приемнике фиксация номеров входящих сообщений плана обмена не предусмотрена // (В приемнике вообще может не быть корреспондирующего плана обмена при одностороннем обмене). ЗаписьСообщенияXML.Закрыть(); // Передача измененных объектов в базу приемник Отказ = Ложь; ОбработкаОбмена = ИнициализироватьОбработкуОбмена(ТекущийУзел, ИмяСобытияДляЖурнала, Отказ); ФайлОбмена = Новый Файл(ОбработкаОбмена.ИмяФайлаОбмена); // Подключение LuExchange = ПолучитьWSПрокси(ТекущийУзел, «LuExchange.1cws», «http://www.LuExchange.ru», «LuExchange»); // Удаляемые объекты // Поиск удаляемого объекта выполняется только по ссылке ВыгрузитьУдаляемыеОбъектыВБазуПриемник(ТекущийУзел, МассивУдаляемыхОбъектов, LuExchange, ОбработкаОбмена, ФайлОбмена, ИмяСобытияДляЖурнала, Отказ); // Измененные объекты Для каждого ОбъектСсылка Из МассивОбъектов Цикл ОшибкаВыгрузкиОбъекта = Ложь; СтрокаЗагруженныеДокументы = «»; // Массив загруженных документов в базе приемнике (строка внутренняя) для инициации последующего проведения ВыгрузитьОбъектВБазуПриемник(ОбъектСсылка, LuExchange, ОбработкаОбмена, ФайлОбмена, ИмяСобытияДляЖурнала, СтрокаЗагруженныеДокументы, ОшибкаВыгрузкиОбъекта); Если ОшибкаВыгрузкиОбъекта Тогда Отказ = Истина; Продолжить; КонецЕсли; // Для выгруженных документов необходимо выполнить команду проведения или, если документ был распроведен, удалить движения ОшибкаПроведенияДокумента = Ложь; ОбработкаПризнакаПроведенияДокумента(СтрокаЗагруженныеДокументы, LuExchange, ИмяСобытияДляЖурнала, ОшибкаПроведенияДокумента); // Фиксируем успешную синхронизацию в плане обмена для объекта ПланыОбмена.УдалитьРегистрациюИзменений(ТекущийУзел, ОбъектСсылка); КонецЦикла; УдалитьФайлы(ОбработкаОбмена.ИмяФайлаОбмена); Если НЕ Отказ Тогда // Фиксируем успешную синхронизацию в плане обмена для всего сообщения ПланыОбмена.УдалитьРегистрациюИзменений(ТекущийУзел, НомерСообщения); КонецЕсли; КонецЦикла; КонецПроцедуры Процедура ВыгрузитьОбъектВБазуПриемник(ОбъектСсылка, LuExchange, ОбработкаОбмена, ФайлОбмена, ИмяСобытияДляЖурнала, СтрокаЗагруженныеДокументы=»», Отказ) // Получаем ДанныеXML ВыгруженоОбъектов = 0; ДанныеXML = ПолучитьДанныеXMLПоПравиламКонвертации(ОбработкаОбмена, ОбъектСсылка, ВыгруженоОбъектов, ИмяСобытияДляЖурнала); // ExecuteExchange ТекстОшибки = «»; ОшибкаВыгрузки = Ложь; СтрокаФиктивныеСсылки = «»; Данные = Новый ХранилищеЗначения(ДанныеXML, Новый СжатиеДанных(9)); ЗагруженоОбъектов = LuExchange.ExecuteExchange(Данные, ИмяСобытияДляЖурнала, СтрокаФиктивныеСсылки, СтрокаЗагруженныеДокументы, ТекстОшибки); // Фиктивные ссылки (выгружаем объекты по ссылкам) ОбработкаФиктивныхСсылок(СтрокаФиктивныеСсылки, LuExchange, ОбработкаОбмена, ФайлОбмена, ИмяСобытияДляЖурнала, ОшибкаВыгрузки); КонецПроцедуры Процедура ОбработкаФиктивныхСсылок(СтрокаФиктивныеСсылки, LuExchange, ОбработкаОбмена, ФайлОбмена, ИмяСобытияДляЖурнала, Отказ) Если ПустаяСтрока(СтрокаФиктивныеСсылки) Тогда Возврат; КонецЕсли; ФиктивныеСсылки = ЗначениеИзСтрокиВнутр(СтрокаФиктивныеСсылки); Для каждого ФиктивнаяСсылка Из ФиктивныеСсылки Цикл ФиктивнаяСсылка = СтрЗаменить(ФиктивнаяСсылка, «.», Символы.ПС); ВидПриемника = СтрПолучитьСтроку(ФиктивнаяСсылка, 1); ТипПриемника = СтрПолучитьСтроку(ФиктивнаяСсылка, 2); УИД = СтрПолучитьСтроку(ФиктивнаяСсылка, 3); // Здесь тип объекта соответствует метаданным базы приемника, // для обработки необходимо привести к соответствующему типу текущей базы // Найдем корреспондирующий тип по правилам обмена ПравилоКонвертации = ОбработкаОбмена.ТаблицаПравилКонвертации.Найти(ВидПриемника+»Ссылка.»+ТипПриемника, «Приемник»); Если ПравилоКонвертации = Неопределено Тогда Продолжить; КонецЕсли; TypeOf = СтрЗаменить(ПравилоКонвертации.ТипИсточника, «.», Символы.ПС); ВидИсточника = СтрПолучитьСтроку(TypeOf, 1); ТипИсточника = СтрПолучитьСтроку(TypeOf, 2); Если ВидИсточника = «ДокументСсылка» Тогда МенеджерОбъекта = Документы; ИначеЕсли ВидИсточника = «СправочникСсылка» Тогда МенеджерОбъекта = Справочники; Иначе Отказ = Истина; Продолжить; КонецЕсли; ОбъектСсылка = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(УИД)); НайденныйОбъект = ОбъектСсылка.ПолучитьОбъект(); Если НайденныйОбъект = Неопределено Тогда Отказ = Истина; Продолжить; КонецЕсли; ВыгрузитьОбъектВБазуПриемник(ОбъектСсылка, LuExchange, ОбработкаОбмена, ФайлОбмена, ИмяСобытияДляЖурнала,, Отказ); КонецЦикла; КонецПроцедуры Процедура ОбработкаПризнакаПроведенияДокумента(СтрокаЗагруженныеДокументы, LuExchange, ИмяСобытияДляЖурнала, Отказ) Если ПустаяСтрока(СтрокаЗагруженныеДокументы) Тогда Возврат; КонецЕсли; // PostingDocuments ТекстОшибки = «»; Отказ = LuExchange.PostingDocuments(СтрокаЗагруженныеДокументы, ТекстОшибки); КонецПроцедуры Функция ИнициализироватьОбработкуОбмена(ТекущийУзел, ИмяСобытияДляЖурнала, Отказ) // Инициализация ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать(); ОбработкаОбмена.РежимОбмена = «Выгрузка»; ОбработкаОбмена.ПостроительОтчета = Новый ПостроительОтчета; ОбработкаОбмена.НеВыводитьНикакихИнформационныхСообщенийПользователю = Истина; // Загрузка правил ПравилаОбмена = ТекущийУзел.ПравилаКонвертации.Получить(); ОбработкаОбмена.ЗагрузитьПравилаОбмена(ПравилаОбмена, «Строка»); ОбработкаОбмена.ИмяФайлаПравилОбмена = «Неопределено»; // Обходим глюк обработки, иначе она считает, что правила не загружены // ИмяФайлаОбмена ОбработкаОбмена.ИмяФайлаОбмена = ПолучитьИмяВременногоФайла(«xml»); // Для всех правил конвертации справочников и документов рекомендуется по возможности устанавливать в ИСТИНА следующие свойства: // — Искать объект приемника по внутреннему идентификатору объекта источника; // — При переносе объкта по ссылке НЕ создавать новый объект, а только переносить ссылку; // Для правил конвертации документов дополнительно рекомендуется устанавливать в ИСТИНА следующее свойство: // — Не выгружать объекты свойств источника по ссылкам; // В этом случае файл данных XML для выгружаемого объекта не будет содержать объекты выгружаемые по ссылкам. // Это существенно уменьшит размер передаваемого файла и ускорит процесс синхронизации. // Выгрузка этих объектов при необходимости будет инициироваться автоматически. Возврат ОбработкаОбмена; КонецФункции Функция ПолучитьДанныеXMLПоПравиламКонвертации(ОбработкаОбмена, ОбъектСсылка, ВыгруженоОбъектов, ИмяСобытияДляЖурнала) МетаИмя = ОбъектСсылка.Метаданные().Имя; // Сначала все отключаем Для Каждого Строка из ОбработкаОбмена.ТаблицаПравилВыгрузки.Строки Цикл Строка.Включить = 0; ОбработкаОбмена.УстановитьПометкиПодчиненных(Строка, «Включить»); КонецЦикла; // Включаем нужное правило СтрПравил = ОбработкаОбмена.ТаблицаПравилВыгрузки.Строки.Найти(МетаИмя, «Имя», Истина); Если СтрПравил = Неопределено Тогда Возврат Неопределено; КонецЕсли; Если НЕ ЗначениеЗаполнено(СтрПравил.ИмяОбъектаДляЗапроса) Тогда Возврат Неопределено; КонецЕсли; СтрПравил.Включить = 1; ОбработкаОбмена.УстановитьПометкиРодителей(СтрПравил, «Включить»); // Отбор ИмяОтбора = СтрЗаменить(СтрПравил.ИмяОбъектаДляЗапроса, «.», «_»); ПостроительОтчета = Новый ПостроительОтчета(«ВЫБРАТЬ ПЕРВЫЕ 1 _.* ИЗ » + СтрПравил.ИмяОбъектаДляЗапроса + » КАК _ {ГДЕ _.Ссылка.* КАК » + ИмяОтбора + «}»); Отбор = ПостроительОтчета.Отбор.Добавить(ИмяОтбора); Отбор.ВидСравнения = ВидСравнения.Равно; Отбор.Установить(ОбъектСсылка); СтрПравил.ИспользоватьОтбор = Истина; СтрПравил.НастройкиПостроителя = ПостроительОтчета.ПолучитьНастройки(); // Выгрузка ОбработкаОбмена.ВыполнитьВыгрузку(); ВыгруженоОбъектов = ОбработкаОбмена.мСчетчикВыгруженныхОбъектов; ЧтениеТекста = Новый ЧтениеТекста; ЧтениеТекста.Открыть(ОбработкаОбмена.ИмяФайлаОбмена, КодировкаТекста.UTF8); СтрокаXML = ЧтениеТекста.Прочитать(); ЧтениеТекста.Закрыть(); Возврат СтрокаXML; КонецФункции // ПолучитьДанныеXMLПоПравиламКонвертации() Функция ПолучитьWSПрокси(Параметры, ИмяФайлаПубликации, URIПространстваИменСервиса, ИмяСервиса) Определения = Новый WSОпределения(«http://»+Параметры.Сервер+»/»+Параметры.База+»/ws/»+ИмяФайлаПубликации+»?wsdl», Параметры.Пользователь, Параметры.Пароль); WSПрокси = Новый WSПрокси(Определения, URIПространстваИменСервиса, ИмяСервиса, ИмяСервиса+»Soap»); WSПрокси.Пользователь = Параметры.Пользователь; WSПрокси.Пароль = Параметры.Пароль; Возврат WSПрокси; КонецФункции 6. Настройка Веб-сервиса для базы приемника

7. Модуль Веб-сервиса Функция ExecuteExchange(DataXML, NameOfEvent, FictitiousObjects, UploadedDocuments, ErrorMessage) УстановитьПривилегированныйРежим(Истина); Попытка ОбработкаОбмена = Обработки.УниверсальныйОбменДаннымиXML.Создать(); ОбработкаОбмена.РежимОбмена = «Загрузка»; ОбработкаОбмена.НеВыводитьНикакихИнформационныхСообщенийПользователю = Истина; ОбработкаОбмена.ЗагружатьДанныеВРежимеОбмена = Истина; ОбработкаОбмена.ЗаписыватьВИнформационнуюБазуТолькоИзмененныеОбъекты = Истина; ОбработкаОбмена.ОптимизированнаяЗаписьОбъектов = Истина; ОбработкаОбмена.ЗаписыватьРегистрыНаборамиЗаписей = Истина; РаботаВозможна = ОбработкаОбмена.ВыполнитьДействияПередЧтениемДанных(DataXML.Получить()); Если НЕ РаботаВозможна Тогда ErrorMessage = «ExecuteExchange(1). ОбработкаОбмена.ВыполнитьДействияПередЧтениемДанных — работа не возможна»; Возврат 0; КонецЕсли; ОбработкаОбмена.ПроизвестиЧтениеДанных(ErrorMessage); Если НЕ ПустаяСтрока(ErrorMessage) Тогда Возврат 0; КонецЕсли; ОбработкаОбмена.ВыполнитьДействияПослеЗавершенияЧтенияДанных(); // Подготовим для возврата в базу источник массивы Фиктивных ссылок и массив выгруженных документов МассивФиктивныхСсылок = Новый Массив; МассивЗагруженныхДокументов = Новый Массив; МетаданныеДокументы = Метаданные.Документы; Для каждого КлючИЗначение Из ОбработкаОбмена.ЗагруженныеОбъекты Цикл ОбъектСсылка = КлючИЗначение.Значение.СсылкаНаОбъект; ОбъектМетаданные = ОбъектСсылка.Метаданные(); Если КлючИЗначение.Значение.СсылкаФиктивная Тогда // Фиктивная ссылка — объект не найденный в базе приемнике и не выгруженный по ссылкам МассивФиктивныхСсылок.Добавить(ОбъектМетаданные.ПолноеИмя() + «.» + XMLСтрока(ОбъектСсылка.Ссылка)); ИначеЕсли МетаданныеДокументы.Содержит(ОбъектМетаданные) Тогда МассивЗагруженныхДокументов.Добавить(ОбъектСсылка.Ссылка); КонецЕсли; КонецЦикла; Если МассивФиктивныхСсылок.Количество() > 0 Тогда FictitiousObjects = ЗначениеВСтрокуВнутр(МассивФиктивныхСсылок); КонецЕсли; Если МассивЗагруженныхДокументов.Количество() > 0 Тогда UploadedDocuments = ЗначениеВСтрокуВнутр(МассивЗагруженныхДокументов); КонецЕсли; Исключение ErrorMessage = «ExecuteExchange(2). » + ОписаниеОшибки(); Возврат 0; КонецПопытки; Возврат ОбработкаОбмена.мСчетчикЗагруженныхОбъектов; КонецФункции Функция DeleteObject(TypeOf, UUID, ErrorMessage) УстановитьПривилегированныйРежим(Истина); Попытка TypeOf = СтрЗаменить(TypeOf, «.», Символы.ПС); ВидОбъекта = СтрПолучитьСтроку(TypeOf, 1); ТипОбъекта = СтрПолучитьСтроку(TypeOf, 2); Если ВидОбъекта = «ДокументСсылка» Тогда МенеджерОбъекта = Документы; ИначеЕсли ВидОбъекта = «СправочникСсылка» Тогда МенеджерОбъекта = Справочники; Иначе ErrorMessage = «DeleteObject(1). Ошибка получения менеджера объекта » + ВидОбъекта + «.» + ТипОбъекта + «!»; Возврат Истина; КонецЕсли; ОбъектСсылка = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(UUID)); НайденныйОбъект = ОбъектСсылка.ПолучитьОбъект(); Если НЕ НайденныйОбъект = Неопределено Тогда НайденныйОбъект.Удалить(); // В базе приемнике удаление происходит без проверки ссылочной целостности // В некоторых схемах целесообразнее отключать данный функционал // а удаление выполнять соответствующей обработкой // («ПометкаУдаления» синхронизируется обычным образом в ExecuteExchange) КонецЕсли; Исключение ErrorMessage = «DeleteObject(2). » + ОписаниеОшибки(); Возврат Истина; КонецПопытки; Возврат Ложь; КонецФункции Функция PostingDocuments(UploadedDocuments, ErrorMessage) УстановитьПривилегированныйРежим(Истина); Отказ = Ложь; Попытка МассивВыгруженныхДокументов = ЗначениеИзСтрокиВнутр(UploadedDocuments); Для каждого ДокументСсылка Из МассивВыгруженныхДокументов Цикл ДокументОбъект = ДокументСсылка.ПолучитьОбъект(); Если ДокументОбъект = Неопределено Тогда Отказ = Истина; ErrorMessage = ErrorMessage + Символы.ПС + «PostingDocuments(1). Объект не найден: » + ДокументСсылка; Продолжить; КонецЕсли; // Проведение Если ДокументОбъект.Проведен Тогда Попытка ПолучитьСообщенияПользователю(Истина); // Очистим все предыдущие сообщения на момент проведения ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение); Исключение Сообщения = ПолучитьСообщенияПользователю(Истина); // Вернем в базу источник ошибки проведения ТекстСообщения = «»; Для каждого Сообщение Из Сообщения Цикл ТекстСообщения = ТекстСообщения + Символы.ПС + Сообщение.Текст; КонецЦикла; ErrorMessage = ErrorMessage + Символы.ПС + «PostingDocuments(2). » + ДокументСсылка + Символы.ПС + ОписаниеОшибки() + ТекстСообщения; Отказ = Истина; // Сбросим признак проведения ДокументОбъект.Проведен = Ложь; ДокументОбъект.ОбменДанными.Загрузка = Истина; ДокументОбъект.Записать(РежимЗаписиДокумента.Запись); КонецПопытки; КонецЕсли; // Если снят с проведения, очистим движения Если НЕ ДокументОбъект.Проведен Тогда Для каждого НаборДвижений Из ДокументОбъект.Движения Цикл НаборДвижений.Прочитать(); Если НаборДвижений.Количество() > 0 Тогда НаборДвижений.Очистить(); НаборДвижений.Записать(); КонецЕсли; КонецЦикла; КонецЕсли; КонецЦикла; Исключение ErrorMessage = «PostingDocuments(3). » + ОписаниеОшибки(); Отказ = Истина; КонецПопытки; Возврат Отказ; КонецФункции 8. Рекомендации При разработке правил конвертации очень сложно отлаживать правила в боевой схеме, поэтому для сложных конвертаций рекомендую сначало воспользоваться средствами отладки встроенными в обработку «Универсальный обмен данными XML», в этом случае имеется возможность подключить алгоритмы из правил в виде модулей внешней обработки как при выгрузке, так и при загрузке данных. И только после успешной выгрузки — загрузки в интерактивном режиме через промежуточный файл — пробовать синхронизацию через Веб. 9. Опыт внедрения

Данная схема успешно реализована в реальных действующих системах:

  • связка УТ 10.3 и УПП 1.3. (УТ нетиповая, доработана под производство с вводом данных через тач-панели на конвейерной линии)
  • связка Самописная конфигурация и БП 3.0 (В самописной конфигурации ведется учет технологических операций на фабрике птицы)

10. Состав вложенных файлов

  • ОбменДаннымиОнлайнЧерезВебСервис.cf — содержит все описанные объекты для синхронизации (Источник + Приемник). Обычные формы. Клиент-серверный вариант. В файловом варианте тоже все будет работать, кроме регламентного задания. В этом случае необходимо предусмотреть периодический запуск синхронизации с помощью метода ПодключитьОбработчикОжидания(). При сравнении, объединении необходимо отметить по подсистемам файла: подсистема «ЛУ_СинхронизацияЧерезВебСервис».
  • ДемоБазы.zip — содержит выгрузки из двух баз (PR1.dt и PR2.dt) для демонстрации готовой настроенной схемы синхронизации. Базы содержат простенькие документы и справочники. Имена метаданных синхронизируемых объектов различаются. Правила конвертации загружены в базу. Необходимо восстановить базы из .dt. Выполнить публикацию на Веб-сервере под именами PR1 и PR2 с установленной галочкой Публиковать Веб-сервисы и LuExchange. В режиме Предприятия в настройках соответствующих узлов планов обмена необходимо прописать имя Веб-сервера на котором была выполнена публикация баз.
  • ОбменДаннымиОнлайнЧерезВебСервис.cfe — вариант доработки в виде расширения конфигурации для баз находящихся на поддержке без возможности редактирования. Ввиду ограниченного функционала расширений, не содержит объекты: План обмена и Регламентное задание. То есть синхронизация здесь реализована без квитирования успешности доставки данных, но полностью совместима с протоколом обмена основного .cf

11. Инструкция по внедрению (ОбменДаннымиОнлайнЧерезВебСервис.cf)

Скачиваем файл ОбменДаннымиОнлайнЧерезВебСервис.cf

Выполняем команду: Конфигурация — Сравнить, объединить с конфигурацией из файла… После вывода результатов сравнения конфигураций выполняем команду: Действия — Отметить по подсистемам файла — отмечаем подсистему «ЛУ_СинхронизацияЧерезВебСервис». Далее — Выполнить. Обновляем конфигурацию базы данных. То же повторяем для корреспондирующей базы. Публикуем обе базы на Веб-сервере (Как? — это отдельная тема, поиск в помощь)
При публикации отмечаем галочками Публиковать Веб-сервисы и LuExchange. Настраиваем соответствующие узлы Планов обменов обеих баз В первой базе создаем узел с настройками подключения ко второй базе и наоборот. Здесь:

  • Сервер — имя веб-сервера, на котором выполнена публикация баз
  • База — имя, под которым выполнена публикация корреспондирующей базы на веб-сервере, как правило совпадает с именем базы на сервере 1С Предприятие
  • Логин — имя пользователя, которого необходимо создать в обеих базах с ролью WebСервисLuExchange (подключение веб-сервиса будет происходить под этим пользователем)
  • Пароль
  • Правила конвертации — сюда необходимо загрузить правила конвертации, созданные в конфигурации «Конвертация данных»

Создание правил конвертации — тоже отдельная большая тема. (Если не в курсе, можно поштудировать инет) Если Вы владеете этим мощным и универсальным инструментом, то для идентичных корреспондирующих баз, правила конвертации сможете создать полностью автоматически за несколько минут. Открываем состав плана обмена ЛУ_WebСервис и добавляем все объекты, для которых в правилах конвертации прописали ПВД (Правила выгрузки данных). Для всех объектов состава запрещаем авторегистрацию. При разработке правил конвертации придерживаемся следующих рекомендаций:

  • Для ПВД поддерживается только способ выборки: «Стандартная выборка»
  • Для всех ПКО справочников и документов рекомендуется устанавливать в ИСТИНА следующие свойства:
    • Искать объект приемника по внутреннему идентификатору объекта источника;
    • При переносе объкта по ссылке НЕ создавать новый объект, а только переносить ссылку;
  • Для ПКО документов дополнительно рекомендуется устанавливать в ИСТИНА следующее свойство:
    • Не выгружать объекты свойств источника по ссылкам;

В этом случае файл данных XML для выгружаемого объекта не будет содержать объекты выгружаемые по ссылкам. Это существенно уменьшит размер передаваемых данных и ускорит процесс синхронизации. Выгрузка этих объектов при необходимости будет инициироваться автоматически.

Если возникнут затруднения в настройке планов обменов
можно скачать вложение «ДемоБазы.zip» и посмотреть как это выполнено в них. Если понравилось и желаешь порекомендовать другим коллегам, ставь плюс!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *