Веб-сервисы, что они и как их применить в реальных условиях.
Уже не раз я сталкивался с разного рода реализациями веб сервисов разными людьми, под разные задачи и т.д. Однако, все эти решения содержали ряд упущений, проблем, и не совсем верных подходов. По сему я решил написать краткий гайд о том, как и почему мы докатились до использования веб сервисов.
Ну пожалуй начнем немного с теории и того, как было раньше.
Была 1 центральная база (далее ЦБ) и был 1 интернет магазин (далее ИМ), и нам, как и всем смертным было необходимо выгружать туда остатки, цены и прочий хлам.
Ну пожалуй следует начать с того, как мы выгружали номенклатуру и ее описание, изначально мы просто раз в какой то период – выгружали файлик xml на ftp, этот период выбирал кто угодно, сайт его автоматом подхватывал и обновлял. Но, так как мы легких путей не ищем, было принято решение добавить в номенклатуру реквизит ДатаИзменения, и тогда выгружалась только та номенклатура, которая была изменена начиная с указанного периода.
Далее, мы раз в день выгружали полные остатки товара в файл и отправляли на фтп, и каждый час, стоял регламент, который выгружал такой же файлик, но только уже не остатков, а оборотов.
Вроде все красиво, удобно, но душа желала большего, особенно после того, как начал увеличиваться объем товара, методично падать фтп, и люди начали использовать групповые обработки номенклатуры, для того, что бы менять реквизиты и тут понеслась жара.
Далее открыли другие партнерские ИМ и с ними тоже надо было как то и что то делать.
В тот момент я уже поднатаскался в веб сервисах 1С и технологии соап в целом, и мы РЕШИЛИСЬ!
Ну во первых у нас возник вопрос – как выгрузить остатки, он решился довольно таки быстро, на стороне сайта подняли соап сервер и я к нему подключаясь через 1С слал строку, но строку не простую, а великолепную :).
Код этой злобной функции приведен ниже.
Однако, мы пока еще немного зайдем в глубь, и так, цель выгрузок для ИМ1 и ИМ2 – была разной, т.е. для ИМ1 выгружались все остатки по складам, а в случае ИМ2 – остатки нужны были в целом, без разбиения по складам.
Поэтому, для того что бы не плодить кучу функций, был добавлен параметр Номер, если Номер = 0, то это выгрузка была для ИМ1, если Номер = 1, то для ИМ2.
И та
//Выгрузка регламентная остатков, эта процедура вызывалась регламентом раз в сутки и отправляла данные в ИМ.
Процедура ВыгрузкаОстатковДляИнтернетМагазина() Экспорт
//Тут мы определяем цикл, т.е. функция выполняется столько раз, сколько ИМ магазинов у нас есть.
Для Номер = 0 По 1 Цикл
Запрос = Новый Запрос;
Если Номер = 0 Тогда
Запрос.Текст =
"ВЫБРАТЬ
| Склады.Ссылка
|ИЗ
| Справочник.Склады КАК Склады
|ГДЕ
| Склады.СтатусСклада = ЗНАЧЕНИЕ(Перечисление.СтатусСклада.Розничный)";
Результат = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = Результат.Выбрать();
//Определяем переменную, которую будет отправлять на сервер
хмл = "";
//Для случая ИМ1 мы выполняем отдельный запрос и отправку для каждого склада
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Попытка
//Пытаемся получить хмл строку для данного склада
хмл = ПолучитьХМЛ(ВыборкаДетальныеЗаписи.Ссылка, Номер);
Если хмл = Неопределено Тогда
Иначе
//Если все успешно, то получаем структуру подключения, куда передаем номер ИМ и имя функции.
СтруктураДанных = ПолучитьСоединение("Prod_1c",Номер);
//Получили строку, теперь надо отправить данные по SOAP, тут передается три параметра на сервер
//1 – сама строка хмл
//2 – код склада
//3 – тип остатков, если это начальные остатки, то он равен «0», если это оборот – то «1»
Ответ = СтруктураДанных.ВСПрокси. Prod_1c(ФабрикаXDTO.Создать(СтруктураДанных.ТипыXDTO[0], хмл),
ФабрикаXDTO.Создать(СтруктураДанных.ТипыXDTO[1], СокрЛП(ВыборкаДетальныеЗаписи.Ссылка.Код)),
ФабрикаXDTO.Создать(СтруктураДанных.ТипыXDTO[2], "0"));
//Тут стоить понимать, что посылая данные, мы получаем и ответ, ответ может быть разным, для нас в одних случаях ответ должен быть «Success» или «Error», в других случаях, мы просто возвращали количество строк в таблице. Т.е. я например выгрузил 1000 строк в хмл, сайт отпарсил и отвечает мне, если ответ != 1000, то это считалось ошибкой, хотя не всегда, например был новый товар, которого в ИМ еще нету, или не должно быть, тогда это просто записывается в журнал и дальше просматривается в ручную.
Если Ответ = "Success" Тогда
//ЗаписьЖурналаРегистрации("Отправка остатков со склада, кол. символов = " + СтрДлина(хмл), УровеньЖурналаРегистрации.Информация, ,ВыборкаДетальныеЗаписи.Ссылка , Ответ);
Иначе
ЗаписьЖурналаРегистрации("Отправка остатков со склада, кол. символов = " + СтрДлина(хмл), УровеньЖурналаРегистрации.Ошибка, ,ВыборкаДетальныеЗаписи.Ссылка , Ответ);
КонецЕсли;
КонецЕсли;
Исключение
ТекстОшибки = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("Отправка остатков со склада, кол. символов = " + СтрДлина(хмл), УровеньЖурналаРегистрации.Ошибка, ,ВыборкаДетальныеЗаписи.Ссылка , ТекстОшибки);
КонецПопытки;
хмл = "";
КонецЦикла;
ИначеЕсли Номер = 1 Тогда
//В этом случае, цикла по складам не было, мы просто выгружаем остатки
хмл = "";
Попытка
хмл = ПолучитьХМЛ("", Номер);
Если хмл = Неопределено Тогда
Иначе
СтруктураДанных = ПолучитьСоединение("Prod_1c",Номер);
Ответ = СтруктураДанных.ВСПрокси. Prod_1c(ФабрикаXDTO.Создать(СтруктураДанных.ТипыXDTO[0], хмл),
ФабрикаXDTO.Создать(СтруктураДанных.ТипыXDTO[1], ""),
ФабрикаXDTO.Создать(СтруктураДанных.ТипыXDTO[2], "0"));
Если Ответ = "Success" Тогда
//ЗаписьЖурналаРегистрации("Отправка остатков со склада, кол. символов = " + СтрДлина(хмл), УровеньЖурналаРегистрации.Информация, ,ВыборкаДетальныеЗаписи.Ссылка , Ответ);
Иначе
ЗаписьЖурналаРегистрации("Отправка остатков со склада, кол. символов = " + СтрДлина(хмл), УровеньЖурналаРегистрации.Ошибка, ,"ИМ" , Ответ);
КонецЕсли;
КонецЕсли;
Исключение
ТекстОшибки = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("Отправка остатков со склада, кол. символов = " + СтрДлина(хмл), УровеньЖурналаРегистрации.Ошибка, ,"ИМ", ТекстОшибки);
КонецПопытки;
хмл = "";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
//Собственно сама функция для получения хмл
Функция ПолучитьХМЛ(Склад,Номер)
//тут для каждого случая, мы создаем свою таблицу
Если Номер = 0 Тогда
Запрос = Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ТоварыНаСкладахОстатки.Номенклатура.Код КАК nom_id,
| ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры.Наименование КАК size_name,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК count
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| Склад = &Склад
| И Номенклатура.ВидНоменклатуры = &ВидНоменклатуры) КАК ТоварыНаСкладахОстатки");
Запрос.УстановитьПараметр("Склад", Склад);
Запрос.УстановитьПараметр("ВидНоменклатуры", Справочники.ВидыНоменклатуры.НайтиПоКоду("000000001"));
ИначеЕсли Номер = 1 Тогда
Запрос = Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ТоварыНаСкладахОстатки.Номенклатура.Код КАК nom_id,
| ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры.Наименование КАК size_name,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК count
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| ,
| Склад.родитель = &Склад
| И (Склад.СтатусСклада = ЗНАЧЕНИЕ(Перечисление.СтатусСклада.Розничный)
| ИЛИ Склад.СтатусСклада = ЗНАЧЕНИЕ(Перечисление.СтатусСклада.Склад))) КАК ТоварыНаСкладахОстатки");
Запрос.УстановитьПараметр("Склад", Справочники.Склады.НайтиПоКоду("00001"));
КонецЕсли;
Результат = Запрос.Выполнить().Выгрузить();
Если Результат.Количество() = 0 Тогда
Возврат Неопределено;
КонецЕсли;
//Тут обратите внимание, я не создаю файл хмл, я не занимаюсь собственной наработкой для создания хмл структуры, я использую сериализатор 1С
ДеревоВОбъектеXDTO = СериализаторXDTO.ЗаписатьXDTO(Результат);
МойXML = Новый ЗаписьXML;
МойXML.УстановитьСтроку();
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ФабрикаXDTO.ЗаписатьXML(МойXML, ДеревоВОбъектеXDTO);
xml = МойXML.Закрыть();
//Вот и все, теперь в xml находится хмл структура, в виде строки, которую я и возвращаю в первую функцию, и передаю потом на сервер сайта ИМ.
//А вот очень интересная функция, УбратьЛишнее, она чистит хмл структуру созданную 1С, убирая оттуда не нужные данные и символы, таким образом мы сжимаем файл в 3 – 5 раз, а на парсинг это никак не влияет.
xml = УбратьЛишнее(xml);
Возврат xml
КонецФункции
//Чистка хмл на лишний мусор
//А вот и сама функция
Функция УбратьЛишнее(xml)
xml = СтрЗаменить(xml,"xsi:type=""xs:decimal""", "");
xml = СтрЗаменить(xml,"xsi:type=""xs:string""", "");
xml = СтрЗаменить(xml,"xsi:type=""xs:boolean""", "");
xml = СтрЗаменить(xml,"xsi:type=""xs:dateTime""", "");
xml = СтрЗаменить(xml,"T00:00:00", "");
xml = СтрЗаменить(xml,"0001-01-01", "");
xml = СтрЗаменить(xml,"<Value ", "<Vl");
xml = СтрЗаменить(xml,"", "");
xml = СтрЗаменить(xml,"false", "0");
xml = СтрЗаменить(xml,"true", "1");
xml = СтрЗаменить(xml,"xsi:type=""Null""", "");
//Для красоты 1С рисует структуру при помощи табуляции, это удобно читать, то для парсинга – это мусор, поэтому мы убираем все лишние табуляции, что позволяет сократить объем данных в 2 раза
xml = СтрЗаменить(xml," ","");
Возврат xml
КонецФункции
//Куда же без функции подключения к соап серверу?
//Сюда мы передаем имя операции, которую нам надо вернуть в структуре и номер ИМ
Функция ПолучитьСоединение(Имя, НомерСоединения)
СтруктураДанных = Новый Структура;
Если НомерСоединения = 0 Тогда
Пользователь = " Пользователь 1";
Пароль = " Пароль 1";
Адрес = "http:// 127.0.0.1/sync";
URIПространстваИменСервиса = "URI";
ИмяСервиса = " ИмяСервиса ";
ИмяТочкиПодключения = " ИмяСервиса Soap";
ИначеЕсли НомерСоединения = 1 Тогда
Пользователь = " Пользователь 2";
Пароль = " Пароль 2";
Адрес = "http:// 127.0.0.1:12345/product";
URIПространстваИменСервиса = "URI";
ИмяСервиса = " ИмяСервиса ";
ИмяТочкиПодключения = " ИмяСервиса Soap";
ИначеЕсли НомерСоединения = 2 Тогда
Пользователь = " Пользователь 3";
Пароль = " Пароль 3";
//Адрес = "http://127.0.0.1/IM/ws/SendUsers.1cws?wsdl";
URIПространстваИменСервиса = "URI";
ИмяСервиса = " ИмяСервиса ";
ИмяТочкиПодключения = " ИмяСервиса Soap";
КонецЕсли;
ВСОпределение = Новый WSОпределения(Адрес, Пользователь, Пароль);
ВСПрокси = Новый WSПрокси(ВСОпределение, URIПространстваИменСервиса, ИмяСервиса, ИмяТочкиПодключения) ;
ВСПрокси.Пользователь = Пользователь;
ВСПрокси.Пароль = Пароль;
ВСервис = ВСОпределение.Сервисы.Получить(0);
ВТочкаВхода = ВСервис.ТочкиПодключения.Получить(0);
ВОперация = ПоискФункции(ВТочкаВхода.Интерфейс.Операции, Имя);
ТипыXDTO = Новый Массив;
Для Каждого Параметр Из ВОперация.Параметры Цикл
_ТипXDTO = ФабрикаXDTO.Тип(Параметр.Тип.URIПространстваИмен, Параметр.Тип.Имя);
ТипыXDTO.Добавить(_ТипXDTO);
КонецЦикла;
// ТипыXDTO – это массив параметров, в нашем случае он будет равен 3. Я специально не привязываюсь к имени параметров, так как тогда, нужно будет под каждую операцию писать свою функцию, а мне влом.
СтруктураДанных.Вставить("ВСОпределение", ВСОпределение);
СтруктураДанных.Вставить("ВСПрокси", ВСПрокси);
СтруктураДанных.Вставить("ВСервис", ВСервис);
СтруктураДанных.Вставить("ВТочкаВхода", ВТочкаВхода);
СтруктураДанных.Вставить("ВОперация", ВОперация);
СтруктураДанных.Вставить("ТипыXDTO", ТипыXDTO);
Возврат СтруктураДанных;
//Тут по сути ничего менять не надо, кроме данных авторизации
КонецФункции
//Найдем нужную функцию
//Ну тут все просто, после того как вы получили коллекцию операций, мы ищем нужную нам операцию и возвращаем ее. Сделана для экономии пространства
Функция ПоискФункции(Операции, Имя)
Для Каждого Операция ИЗ Операции Цикл
Если Операция.Имя = Имя Тогда
Возврат Операция
КонецЕсли;
КонецЦикла;
КонецФункции
В итоге – на сайт придет строка такого формата:
Изначально идет описание колонок ТЗ, где указывается имя колонки, длина символов (максимальная), тип данных и др.
Далее – последовательно идут теги row, это строка таблицы, и теги Vl, их порядок соответствует порядку колонок в заголовке. Если бы мы не сделали сжатие, то данных там было бы на порядок больше, но они были бы бесполезны.
<ValueTable xmlns="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<column>
<Name>nom_id>
<ValueType>
<Type>Null>
<Type>xs:decimal>
<NumberQualifiers>
<Digits>11>
<FractionDigits>0>
<AllowedSign>Nonnegative>
>
>
<Title>nom_id>
<Width>11>
>
<column>
<Name>size_name>
<ValueType>
<Type>xs:string>
<Type>Null>
<StringQualifiers>
<Length>100>
<AllowedLength>Variable>
>
>
<Title>size_name>
<Width>100>
>
<column>
<Name>count>
<ValueType>
<Type>Null>
<Type>xs:decimal>
<NumberQualifiers>
<Digits>38>
<FractionDigits>0>
<AllowedSign>Any>
>
>
<Title>count>
<Width>38>
>
<row>
<Vl>95761>
<Vl>40>
<Vl>2>
>
<row>
<Vl>95761>
<Vl>41>
<Vl>1>
>
<row>
<Vl>95761>
<Vl>42>
<Vl>1>
>
<row>
<Vl>95761>
<Vl>44>
<Vl>2>
>
<row>
<Vl>95762>
<Vl>40>
<Vl>1>
>
>
Часть xml тегов съел сайт, но тут главное суть :).
Теперь можно передавать данные на сайт, минуя всякие там фтп, файлы и прочую лабуду. Для пущей безопасности – у нас обмен данными идет внутри тунеля, так что просто так, со стороны, туда ничего не отправишь. Скорость обмена – выше всех похвал, таблица на 10 000 строк передается около 30 секунд, это с учетом времени запроса, формирования хмл, создания подключения, отправки данных, парсинг данных на стороне ИМ и получение ответа от сайта.
Ну как? Интересно? А может пойдем еще дальше? Мы же программисты 1С, а не веба? А может веб программист не хочет этого делать, такое тоже бывает, но вот у вас, допустим, есть франчайзы, и у вас общая дисконтная система, ну бывает же такое? Бывает. А база у них – своя, а вот дисконтов хочется видеть у себя, или вот вы сделали документ перемещения на них, а теперь надо что бы он попал в их базу, бывает? А для того что бы он выгрузился к ним в базу, нужно что бы у них была вся номенклатура? Ну без этого никак, а вдруг они сделают загрузят документ у себя, через файлик, а потом что то изменят, и начинается сверка, а там полная лажа. Тоже бывает.
И так, давайте поставим сами себе задачу – СДЕЛАТЬ ВСЕ КРАСИВО.
Ну вначале давайте определимся с тем, что есть красиво?
В нашем случае, это есть последовательная передача данных с базы в базу, логично?
И так, если мы хотим выгрузить документ перемещения в базу франчайзи, нам надо быть уверенными в том, что как минимум у них стоит 1С и включен сервер. Проверили? Ок. Следующая задача – убедиться что у них есть вся номенклатура, логично? А как мы можем быть в этом уверенными?
Тут стоит отметить, что я специально исключаю вредительство, т.е. если мы раз им выгрузили номенлатуру, то она никуда потом не девается :).
Но, давайте посмотрим на то, как и что делается в нашей базе.
Изначально, до создания документа – создается номенклатура, хотя надо предусмотреть вариант, когда создался документ, потом мы создали номенклатуру, а потом ее добавили в тот документ :). Но те кто с этим работает постоянно, знают как выкрутиться из этой ситуации.
И так, рисуется определенный алгоритм, а именно, вначале мы создаем номенклатуру, потом документ.
Тут приходит осознание того, что если эту же последовательность действий перенести на другую базу, то там тоже должно быть все красиво.
И так, выходом в моем случае – было создание регистра сведений Синхронизация, с вот такими вот полями:
Объект – это составной тип данных, в нашем случае указываем в нем Номенклатуру, ДокументПеремещения
ДатаДобавления - Дата
ДатаПопытки - Дата
ОписаниеОшибки - Строка
НомерСайта – число, хотите делайте строкой, дело ваше.
Тут все очень просто, это регистр сведений без подчинения, непериодический.
Далее, мы делаем подписку на события документа перемещения и номенклатуры.
Подписка работает в случае записи.
В подписке вот такой код:
Процедура ЗаписатьОбъектВОчередь(Объект) Экспорт
Для Номер = 0 По 1 Цикл
Нов = РегистрыСведений.СинхронизацияССайтом.СоздатьМенеджерЗаписи();
Нов.Объект = Объект;
Нов.ДатаДобавления = ТекущаяДата();
Нов.НомерСайта = Номер;
Попытка
Нов.Записать();
//ЗаписьЖурналаРегистрации("Поставить в очередь", УровеньЖурналаРегистрации.Информация, ,Объект ,);
Исключение
ЗаписьЖурналаРегистрации("Поставить в очередь", УровеньЖурналаРегистрации.Ошибка, ,Объект ,);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Вроде все красиво, не так ли? Я использовал цикл, так как данные выгружаются одинаковые, то я никаких условий не ставил, однако если у вас должны быть ограничения, например только документы перемещения на этот склад, то вы ставите тут условие, если условие не выполняется, то этот документ не попадает в регистр сведений.
И так, теперь в случае создания/изменения номенклатуры или документа, он попадет в этот регистр.
При чем в той же последовательности.
И так, вроде все идет хорошо, теперь же что то надо делать с этим регистром?
А делаем мы вот что, создаем регламент, у меня периодичность стоит 5 минут.
Процедура ПрочитатьОчередь() Экспорт
Выборка = РегистрыСведений.СинхронизацияССайтом.Выбрать(,"ДатаДобавления");
Успешно = Ложь;
Пока Выборка.Следующий() Цикл
Успешно = Ложь;
Попытка
Если ТипЗнч(Выборка.Объект) = Тип("СправочникСсылка.Номенклатура") Тогда
Успешно = ВыгрузкаНоменклатуры(Выборка.Объект, Выборка.НомерСайта);
ИначеЕсли ТипЗнч(Выборка.Объект) = Тип("ДокументСсылка.ПеремещениеТоваров") Тогда
Успешно = ВыгрузкаСкидокДляИнтернетМагазина(Выборка.Объект, Выборка.НомерСайта);
Иначе
Успешно = Истина;
КонецЕсли;
Если Успешно Тогда
Выборка.ПолучитьМенеджерЗаписи().Удалить();
Иначе
Запись = Выборка.ПолучитьМенеджерЗаписи();
Запись.Прочитать();
Запись.ДатаПопытки = ТекущаяДата();
Запись.Записать();
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("Отправка данных", УровеньЖурналаРегистрации.Ошибка, , Выборка.Объект, ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Тут все просто, вызываются функции – идентичные первой процедуре, за исключением того, что это будет функция, и в случае успешной выгрузки – она будет возвращать истину, и это строка будет удаляться из регистра сведений, в случае ложь – будет ставиться дата попытки и причина ошибки.
Давайте отработаем ситуацию, когда у нас в очереди 2 Номенлатуры и 1 Документ с ними.
Допустим – первая прошла успешно и удалилась из регистра, а вот вторая, не прошла, например не удалось создать ее в базе приемнике, тогда эта запись не удалится, и документ не создается, так как не может найти эту номенлатуру, как только решат с ней проблему – трубы прорвет и все выгрузиться, но остальная очередь не пострадает.
Тут можно долго мудрить, у меня например в случае ошибки приходит сообщение, и запись помечается – как запись ошибочная и она не долбится постоянно в базу приемник, пока я не сниму эту метку.
Так же для выравнивания партионного учета, у нас есть специальный пользователь – если он проводит документ, то в регистр ничего не записывается.
На стороне базы приемника – есть система логов, которая логирует, когда и какой документ изменился и что в нем поменяли.
Тут можно думать долго и нудно, и каждый найдет свой путь просвещения.
Однако, на такой нотке было бы закончить совсем не весело, по этому я осмелюсь напомнить о вот таком куске кода:
ДеревоВОбъектеXDTO = СериализаторXDTO.ЗаписатьXDTO(Результат);
МойXML = Новый ЗаписьXML;
МойXML.УстановитьСтроку();
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ФабрикаXDTO.ЗаписатьXML(МойXML, ДеревоВОбъектеXDTO);
хмл = МойXML.Закрыть();
хмл = СтрЗаменить(хмл," ","");
Помните? Ну тот, который создает сам хмл структуру и она потом уходит на сайт. А давайте посмотрим, что можно придумать, если эта структура уходит в другую базу 1С?
ЧтениеXMLДанных = Новый ЧтениеXML;
ЧтениеXMLДанных.УстановитьСтроку(хмл);
ТЗ = СериализаторXDTO.ПрочитатьXML(ЧтениеXMLДанных);
ЧтениеXMLДанных.Закрыть();
А вот эта операция вернет вам таблицу значений, т.е. больше ничего парсить не надо, вы сериализовали таблицу товаров документа, передали в базу приемник и там же – десериализовали. И дальше работаете с обычной ТЗ.
Однако! Обратите внимание, что я вырезаль только табуляцию, так как остальные параметры нужны 1С для десериализации!
Правда если вы синхронизацию с базами делаете не через GUID, то в этом случае, я например, сериализую таблицу, но вместо ссылки на номенклатуру передаю код, в базе приемнике – я добавляю к ТЗ колонку Номенклатура, заполняю ее по коду, и просто загружаю в ТЗ документа, так как название колонок в таблицах совпадают.
Надеюсь это кому то помогло!
Тему о поднятии веб сервисов – я не рассматриваю, так как она уже достаточно разжевана и в моих и в других статьях.
Если есть вопросы – добро пожаловать в комментарии.
Очень приветствуется злобная критика. Я еще учусь :)