Вступление
Zimbra Collaboration Suite — почтовый сервер, органайзер и персонализация пользователя. Это решение корпоративного класса для совместной работы с электронной почтой, календарем и офисными инструментами. Более детальное описание решения можно получить по этой Ссылке
Не так давно мы отказались от использования встроенного почтового клиента в УТ 11.2 и удачно переехали в Zimbra Open Source Edition, все пользователи стали счастливы.
Zimbra Open Source Edition, зарекомендовала себя положительно, по лицензированию отличный FAQ ссылка.
После у нас отвалился функционал из блока CRM, а именно:
- Общая адресная книга email адресов контрагентов, среди всех сотрудников.
- Автоматическая регистрация взаимодействий, по тем контрагентам, чей email есть в справочнике.
- Отчеты показывающие активность общения сотрудников с контрагентами, по каналу интернет почты.
Ниже подробно расскажу как решить вопрос общей адресной книги если у Вас тоже 1С и Zimbra.
Для этого нам понадобится:
- 1C Платформа. В момент написания публикации использовалась версия 8.3.11
- SOAP UI. Он нам позволит быстро и легко выполнять тестовые вызовы soap сервиса Zimbra, а так же просматривать сами сообщения. Достаточно бесплатной версии Ссылка
- Рабочая система Zimbra. Для тестов, на этап разработки, можно развернуть тестовый сервер на виртуальной машине под OS Linux, там же установить 1С. Как это сделать в интернете полно инструкций.
Zimbra
Zimbra понравилась мне еще больше, после того как стало понятно, что она из коробки предоставляет функционал интеграции через SOAP. При этом больше всего радует, что в данном вопросе у этих ребят все задокументировано.
Из коробки у нас есть 7 soap сервисов, в данной публикации мы будем использовать только 2:
- zimbraAccount - Включает в себя методы для извлечения, хранения и управления информацией учетной записи пользователя.
- zimbraMail - Включает в себя методы для управления почтой и информацией календаря.
Узнать весь функционал, а так же описание всех методов, можно по данной Ссылке.
После установки почтового сервера, описание wsdl схем от soap Zimbra, у Вас будут доступны по ссылке вида:
https://mail.<Ваш домен>.ru/service/wsdl/ZimbraUserService.wsdl - Где ZimbraUserService это имя нужного сервиса
Как пример ссылка на wsdl в интернете.
Для синхронизации общей адресной книги у Zimbra так же все реализовано, нам остается лишь настроить.
После установки автоматически создается учетная запись Gal Sync Account. Именно под ней создаются контакты, которые доступны всем пользователям. Все общие контакты хранятся в выделенной папке, по дефолту это "InternalGAL".А в настройках на сервере остается лишь включить её и выставить время, раз в которое сервер автоматически будет их синхронизировать у себя.
Скрин из консоли администратора Zimbra, настройка GAL Sync Account.
Подробнее можно почитать тут Ссылка.
В нашей задаче все контакты(email адреса), хранятся и заводятся в 1С. А 1С уже через soap, будет их переносить в Zimbra, в регламентом задание. В папку "InternalGAL", используя GAL Sync Account.
Всем пользователям они будут доступны после внутренней синхронизации, которая у нас настроена на выполнение раз в 1 минуту.
Реализация
Выбор способа обращения к soap сервису из кода 1С.
Встретив слова soap, wsdl, сразу становится понятно что мы будем использовать такие объекты 1С платформы как "WS-ссылка","WSПрокси","XDTO".
Но нет, мы будем использовать объекты "HTTPЗапрос","HTTPСоединение", для формирования POST запросов к soap.
Связано это с тем что у Zimbra, для авторизации используется Token Authentication, подробнее можно почитать тут.
Перед вызовом какого либо метода у soap Zimbra, нам нужно авторизоваться, после авторизации мы получаем auth token. В дальнейшем мы должны его использовать при вызове методов.
auth token - Простыми словами, это уникальный ключ авторизации для нашей сессии. Существование, валидность, которого ограничена временем.
Все мы знаем что структура сообщений, отправляемых через POST,GET запросы, имеет два основных раздела Header и Body.
Так вот Zimbra построила свой soap таким образом что authToken должен присутствовать в Заголовках("Header") сообщений.
А удобные объекты для работы с soap "WS-ссылка","WSПрокси","XDTO", не позволяют 1с разработчику задавать свои свойства в разделе "Header", только "Body".
Именно по этому мы их не используем, а будем использовать "HTTPЗапрос","HTTPСоединение".
При этом формировать сами сообщения, в формате xml, будем встроенным языком 1с.
Авторизация
Для начала обмена с Zimbra нам нужно авторизоваться.Делать мы это будем под учетной записью GAL Sync Account, поскольку именно под ней мы будем управлять контактами.
Для авторизации soap сервис zimbraAccount предоставляет метод Auth, описание.
Для того что бы понять, какое сообщение нам нужно отправить через POST, мы обратимся к SOAP UI.
Данная публикация не затрагивает мануал по работе в SOAP UI. Для того что бы видеть все методы и формировать сообщения, Вам нужно создать новый проект тип SOAP, указав его название и ссылку на wsdl описание Zimbra.
Под спойлером скриншот, который описывает сообщение в SOAP UI, для метода Auth.
Далее в публикации обращаться к SOAP UI больше не будем, Вы просто должны понимать, что он нужен для просмотра и тестирования сообщений отправляемых в soap сервис.
Хочется затронуть лишь одну деталь, связанную с ним, а именно ссылку которую он по дефолту формирует для сообщений. Она имеет вид "https://mail.<Ваш домен>.ru:8443/service/soap/". При этом Ваш сервер Zimbra может быть настроен так, что порт 8443 не виден и сделана переадресация. Верная ссылка будет "https://mail.<Ваш домен>.ru/service/soap/".
Для удобной отправки сообщений(вызов методов soap) и получение результата, реализуем метод:
ОтправитьЗапросSOAP(Запрос,SOAPAction)
//Отправляет SOAP сообщение на сервер zimbra
//Запрос - Строка - XML сообщение которое нужно отправить
//SOAPAction - Строка - Имя сервиса soap и метода куда обращаемся
//Возвращает - Неопределено в случае ошибки или Строка,XML сообщение ответ, в случае успеха
//В случае ошибки делает запись в журнал регистраций
Функция ОтправитьЗапросSOAP(Запрос,SOAPAction)
Попытка
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "text/xml;charset=UTF-8");
Заголовки.Вставить("SOAPAction", SOAPAction);
HTTPЗапрос = Новый HTTPЗапрос("/service/soap/", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(Запрос, "UTF-8");
HTTPСоединение = Новый HTTPСоединение("mail.<ВАШ ДОМЕН>.ru");
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Ответ=HTTPОтвет.ПолучитьТелоКакСтроку();
Если HTTPОтвет.КодСостояния<>200 Тогда
ЗаписьЖурналаРегистрации("Синхронизация с Zimbra", УровеньЖурналаРегистрации.Ошибка,,,"При отправке SOAP запроса случилась ошибка,код ответа не 200, текст ошибки:"+Символы.ПС+HTTPОтвет.ПолучитьТелоКакСтроку());
Возврат Неопределено;
КонецЕсли;
Возврат Ответ;
Исключение
ЗаписьЖурналаРегистрации("Синхронизация с Zimbra", УровеньЖурналаРегистрации.Ошибка,,,"Критическая ошибка при отправке SOAP запроса, текст ошибки:"+Символы.ПС+ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Данный метод мы будем часто использовать для отправки SOAP сообщений и получения результата. По сути его можно назвать "ВызватьМетодSOAP".
Для авторизации, получения токена, будем использовать следующий метод:
ПолучитьТокенАвторизации()
//Авторизуется на сервере Zimbra и возвращет Токен авторизации
//Который исопльзуется в дальнешем общение по soap
//Возвращет строку с токеном в случае успеха или Неопределено если ошибка.
Функция ПолучитьТокенАвторизации()
Запрос="<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" >
| <soapenv:Header>
| <urn:context xmlns:urn=""urn:zimbra""/>
| </soapenv:Header>
| <soapenv:Body>
| <urn1:AuthRequest xmlns:urn1=""urn:zimbraAccount"">
| <!--You may enter the following 8 items in any order-->
| <!--Optional:-->
| <urn1:account by=""name"">galsync@<Ваш Домен>.ru</urn1:account>
| <!--Optional:-->
| <urn1:password>Ваш пароль от GAL Sync Account</urn1:password>
| </urn1:AuthRequest>
| </soapenv:Body>
|</soapenv:Envelope>";
Ответ=ОтправитьЗапросSOAP(Запрос,"urn:zimbraAccount/Auth");
Если Ответ=Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
//Выбираем из xml токен
ЧтениеXML=Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(Ответ);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.Имя="authToken" И ЧтениеXML.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда
ЧтениеXML.Прочитать();
Возврат ЧтениеXML.Значение;
КонецЕсли;
КонецЦикла;
ЗаписьЖурналаРегистрации("Синхронизация с Zimbra", УровеньЖурналаРегистрации.Ошибка,,,"Ошибка при получение токена авторизации, в xml не удалось найти токен, xml:"+Символы.ПС+Ответ);
Возврат Неопределено;
КонецФункции
В данном Случае сам Запрос, сообщение, объявлено просто строкой, в статье это сделано специально, для наглядности. В релизе все xml сообщения лучше формировать стандартным объектом ЗаписьXML. По скольку он будет экранировать нужный символы под формат XML.
Получение всех созданных контактов
Как указано выше, все наши глобальные контакты, у Zimbra, хранятся в определенной папке "InternalGAL".Для того что бы создавать новые контакты, нам нужно знать уникальный ид данной папки.
Самое простое что бы это сделать, мы можем реализовать метод который получит все контакты, а затем мы найдем данную папку и узнаем её ид. Ниже метод который получает все контакты:
ПолучитьКонтактыЗимбы(Токен)
//Возвращает таблицу из всех контактов, в том числе и группы, какие есть у GAL Sync Account
//Токен - Строка - Полученный токен при авторизации
Функция ПолучитьКонтактыЗимбы(Токен)
//Каких колонок не будет, создадим при чтение XML
Результат=Новый ТаблицаЗначений;
Результат.Колонки.Добавить("fileAsStr");
Результат.Колонки.Добавить("rev");
Результат.Колонки.Добавить("d");
Результат.Колонки.Добавить("id");
Результат.Колонки.Добавить("l");
Результат.Колонки.Добавить("firstName");
Результат.Колонки.Добавить("lastName");
Результат.Колонки.Добавить("notes");
Результат.Колонки.Добавить("fileAs");
Результат.Колонки.Добавить("zimbraId");
Результат.Колонки.Добавить("createTimeStamp");
Результат.Колонки.Добавить("objectClass");
Результат.Колонки.Добавить("fullName");
Результат.Колонки.Добавить("modifyTimeStamp");
Результат.Колонки.Добавить("email");
Результат.Колонки.Добавить("nickname");
Результат.Колонки.Добавить("type");
Результат.Колонки.Добавить("C");
Запрос="<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:zimbra"" xmlns:urn1=""urn:zimbraMail"">
|<soapenv:Header>
| <urn:context>
| <urn:authToken>"+Токен+"</urn:authToken>
| </urn:context>
| </soapenv:Header>
| <soapenv:Body>
| <urn1:GetContactsRequest >
|
| </urn1:GetContactsRequest>
| </soapenv:Body>
|</soapenv:Envelope>";
Ответ=ОтправитьЗапросSOAP(Запрос,"urn:zimbraMail/GetContacts");
Если Ответ=Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
//Конвертим ответ в таблицу
ЧтениеXML=Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(Ответ);
стрРезультата=Неопределено;
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.Имя="cn" И ЧтениеXML.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда
стрРезультата=Результат.Добавить();
стрРезультата.fileAsStr=ЧтениеXML.ПолучитьАтрибут("fileAsStr");
стрРезультата.rev=ЧтениеXML.ПолучитьАтрибут("rev");
стрРезультата.d=ЧтениеXML.ПолучитьАтрибут("d");
стрРезультата.id=ЧтениеXML.ПолучитьАтрибут("id");
стрРезультата.l=ЧтениеXML.ПолучитьАтрибут("l");
ИначеЕсли ЧтениеXML.Имя="cn" И ЧтениеXML.ТипУзла=ТипУзлаXML.КонецЭлемента Тогда
стрРезультата=Неопределено;
КонецЕсли;
Если стрРезультата<>Неопределено И ЧтениеXML.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда
Если ЧтениеXML.Имя="a" Тогда
врПризнак=СтрЗаменить(ЧтениеXML.ПолучитьАтрибут("n")," ","");
ЧтениеXML.Прочитать();
Если врПризнак="objectClass" Тогда
//objectClass в одну колонку через разделитель пишем
Если НЕ ЗначениеЗаполнено(стрРезультата.objectClass) Тогда
стрРезультата.objectClass=ЧтениеXML.Значение;
Иначе
стрРезультата.objectClass=стрРезультата.objectClass+";"+ЧтениеXML.Значение;
КонецЕсли;
Иначе
//Возможно такой колонки нет, тогда создадим ее
Если Результат.Колонки.Найти(врПризнак)=Неопределено Тогда
Результат.Колонки.Добавить(врПризнак);
КонецЕсли;
стрРезультата[врПризнак]=ЧтениеXML.Значение;
КонецЕсли;
ИначеЕсли ЧтениеXML.Имя="m" Тогда
врПризнак=ЧтениеXML.ПолучитьАтрибут("type");
//Если это группа, то её состав будет тут, все в одну колонку через разделитель
//Состав это ид контактов, которые входят в данную группу
Если врПризнак="C" Тогда
знч=ЧтениеXML.ПолучитьАтрибут("value");
Если НЕ ЗначениеЗаполнено(стрРезультата.C) Тогда
стрРезультата.C=знч;
Иначе
стрРезультата.C=стрРезультата.C+";"+знч;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Данный метод получит в ответе большой XML, в котором будут все созданные контакты, у учетной записи GAL Sync. Далее просто для удобства использования перенесет xml в ТаблицуЗначений, у которой каждая строка будет сам контакт, а колонки атрибуты из XML.
В рамках данной публикации из таблицы нам интересна только колонка "l", именно она несет ИД группы, в которой создан контакт. Это и будет ид нашей группы "InternalGAL".
Создание нового контакта
После того как мы узнали ИД группы, в которой будем создавать контакты, можем создать новый контакт.
Для этого zimbra предоставляет метод "CreateContact", у сервиса "zimbraMail", реализуем:
ДобавитьНовыйКонтактВЗимбра(Токен,Контакт)
//Создает новый контакт в зимбра, возвращет его ид
//Токен - Стркоа - токен авторизации
//Контакт - Структура - Своя структура, описывающая контакт который нужно создать
Функция ДобавитьНовыйКонтактВЗимбра(Токен,Контакт)
//l="257" Это ид группы для общих контактов
//Запрос="<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:zimbra"" xmlns:urn1=""urn:zimbraMail"">
// |<soapenv:Header>
// | <urn:context>
// | <urn:authToken>"+Токен+"</urn:authToken>
// | </urn:context>
// |</soapenv:Header>
// |<soapenv:Body>
// | <urn1:CreateContactRequest >
// | <urn1:cn l=""257"">
// | <!--Zero or more repetitions:-->
// | <urn1:a n=""firstName"">"+Контакт.firstName+"</urn1:a>
// | <urn1:a n=""lastName"">"+Контакт.lastName+"</urn1:a>
// | <urn1:a n=""middleName"">"+Контакт.middleName+"</urn1:a>
// | <urn1:a n=""company"">"+Контакт.company+"</urn1:a>
// | <urn1:a n=""jobTitle"">"+Контакт.jobTitle+"</urn1:a>
// | <urn1:a n=""mobilePhone"">"+Контакт.mobilePhone+"</urn1:a>
// | <urn1:a n=""workPhone"">"+Контакт.workPhone+"</urn1:a>
// | <urn1:a n=""email"">"+Контакт.email+"</urn1:a>
// | <urn1:a n=""notes"">"+Контакт.notes+"</urn1:a>
// | </urn1:cn>
// | </urn1:CreateContactRequest>
// |</soapenv:Body>
// |</soapenv:Envelope>";
Запрос=ПолучитьXMLСообщениеДляЗапроса(Токен,Контакт);
Ответ=ОтправитьЗапросSOAP(Запрос,"urn:zimbraMail/CreateContact");
Если Ответ=Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
//Из ответа находим его созданный ИД и возвращаем как число
ЧтениеXML=Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(Ответ);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.Имя="cn" И ЧтениеXML.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда
Возврат Число(ЧтениеXML.ПолучитьАтрибут("id"));
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Данный метод принимает Токен авторизации и свою структуру Контакт, которая заполнена данными для создания. Далее отправляет сообщение в Зимбра и в случае успеха вернет ИД созданного контакта. Используя данный ид, можно выполнять обновление информации по данному контакту(см. ниже).
Что касается сообщения, его формат специально оставлен в данном методе, но для формирования используется:
ПолучитьXMLСообщениеДляЗапроса(Токен,Контакт,ZimbraID=Неопределено,ЭтоГруппа=Ложь)
//Просто метод помощник у одноименного
Процедура ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,Имя,Данные)
ЗаписьXML.ЗаписатьНачалоЭлемента("urn1:a");
ЗаписьXML.ЗаписатьАтрибут("n",Имя);
ЗаписьXML.ЗаписатьТекст(Данные);
ЗаписьXML.ЗаписатьКонецЭлемента();//urn1:a
КонецПроцедуры
//На основе входящих данных, формирует нужное сообщение для передачи через SOAP
//Токен - Строка - Токен авторизации
//Контакт - Структура - Своя структура которая несет данные для записи
//ZimbraID - Число - Необязательный - ИД контакта в системе зимбра, если указан будет сообщение обновления
//ЭтоГруппа - Булево - Необязательный - признак сообщение нужно для группы или нет
Функция ПолучитьXMLСообщениеДляЗапроса(Токен,Контакт,ZimbraID=Неопределено,ЭтоГруппа=Ложь)
ИмяРеквеста="urn1:CreateContactRequest";
Если ZimbraID<>Неопределено Тогда
//Тогда используем метод для обновления
ИмяРеквеста="urn1:ModifyContactRequest";
КонецЕсли;
ЗаписьXML=Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8");
ЗаписьXML.ЗаписатьНачалоЭлемента("soapenv:Envelope");
ЗаписьXML.ЗаписатьАтрибут("xmlns:soapenv","http://schemas.xmlsoap.org/soap/envelope/");
ЗаписьXML.ЗаписатьАтрибут("xmlns:urn","urn:zimbra");
ЗаписьXML.ЗаписатьАтрибут("xmlns:urn1","urn:zimbraMail");
ЗаписьXML.ЗаписатьНачалоЭлемента("soapenv:Header");
ЗаписьXML.ЗаписатьНачалоЭлемента("urn:context");
ЗаписьXML.ЗаписатьНачалоЭлемента("urn:authToken");
ЗаписьXML.ЗаписатьТекст(Токен);
ЗаписьXML.ЗаписатьКонецЭлемента();//("urn:authToken");
ЗаписьXML.ЗаписатьКонецЭлемента();//("urn:context");
ЗаписьXML.ЗаписатьКонецЭлемента();//("soapenv:Header");
ЗаписьXML.ЗаписатьНачалоЭлемента("soapenv:Body");
ЗаписьXML.ЗаписатьНачалоЭлемента(ИмяРеквеста);
Если ZimbraID<>Неопределено Тогда
//Если 1 тогда перезапишем карточку целиком, иначе обновятся только указанные поля
ЗаписьXML.ЗаписатьАтрибут("replace","1");
КонецЕсли;
ЗаписьXML.ЗаписатьНачалоЭлемента("urn1:cn");
Если ZimbraID<>Неопределено Тогда
ЗаписьXML.ЗаписатьАтрибут("id",СтрЗаменить(Строка(ZimbraID),Символы.НПП,""));
Иначе
//Только для новых контактов указываем ид группы
ЗаписьXML.ЗаписатьАтрибут("l","257");
КонецЕсли;
Если ЭтоГруппа Тогда
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"fullName",Контакт.fullName);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"type","group");
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"nickname",Контакт.fullName);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"fileAs","8:"+Контакт.fullName);
Для Каждого Ид из Контакт.СоставИД Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("urn1:m");
ЗаписьXML.ЗаписатьАтрибут("type","C");
ЗаписьXML.ЗаписатьАтрибут("value",СтрЗаменить(Строка(Ид),Символы.НПП,""));
ЗаписьXML.ЗаписатьКонецЭлемента();//urn1:m
КонецЦикла;
Иначе
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"firstName",Контакт.firstName);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"lastName",Контакт.lastName);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"middleName",Контакт.middleName);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"company",Контакт.company);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"jobTitle",Контакт.jobTitle);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"mobilePhone",Контакт.mobilePhone);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"workPhone",Контакт.workPhone);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"email",Контакт.email);
ПолучитьXMLСообщениеДляЗапроса_Добавитьurn1(ЗаписьXML,"notes",Контакт.notes);
КонецЕсли;
ЗаписьXML.ЗаписатьКонецЭлемента();//urn1:cn
ЗаписьXML.ЗаписатьКонецЭлемента();//urn1:CreateContactRequest
ЗаписьXML.ЗаписатьКонецЭлемента();//soapenv:Body
ЗаписьXML.ЗаписатьКонецЭлемента();//"soapenv:Envelope"
Возврат ЗаписьXML.Закрыть();
КонецФункции
Данный метод реализован специально для формирования XML сообщений, с целью экранировать такие символы например как "<",">" и т.д. При этом он сделан немного унифицировано, в том смысле что может формировать сообщение для Создания новых контактов, Обновления существующих, а так же формировать для Групп. Про группы в двух словах поговорим в конце публикации.
Скриншот созданного из 1С контакта в зимбра
На нем видно что у нас папка для общих контактов называется "_zimbra". Персональные данные по понятным причинам замазаны.
Обновление созданного контакта
Для понимания с стороны 1С какие контакты у нас меняются пользователями, создаются, что и как нужно синхронизировать. Мы внесли изменения в конфигурацию, у справочников Контрагенты и КонтактныеЛицаПартнеров добавили два новых реквизита:
- "ZimbraID" - Число - изначально у всех он равен 0, если ноль значит вызывается метод создать новый контакт. После создания мы в 1с запоминаем его ид из zimbra.
- "ZimbraState" - Число - изначально у всех равен 0, что значит что он подлежит синхронизации. После синхронизации присваивается 1.
Дополнительно, в карточках Контрагентов и КонтактныхЛиц, в обработчике изменения email адресов на форме, мы дописали свой код. Который при смене пользователем адреса, у уже существующего элемента, присваивает ему ZimbraState=0.
Таким образом, для того что бы найти в 1С те карточки, которые нужно выгрузить в zimbra, написан простой запрос в котором есть условие "Где ZimbraState=0". Он так же выбирает поле "ZimbraID" и если оно заполнено вызывается метод:
ОбновитьКонтактВЗимбра(Токен,Контакт,ZimbraID)
Функция ОбновитьКонтактВЗимбра(Токен,Контакт,ZimbraID)
//Запрос="<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:zimbra"" xmlns:urn1=""urn:zimbraMail"">
// |<soapenv:Header>
// | <urn:context>
// | <urn:authToken>"+Токен+"</urn:authToken>
// | </urn:context>
// |</soapenv:Header>
// |<soapenv:Body>
// | <urn1:ModifyContactRequest replace=""1"">
// | <urn1:cn id="""+СтрЗаменить(Строка(ZimbraID),Символы.НПП,"")+""">
// | <!--Zero or more repetitions:-->
// | <urn1:a n=""firstName"">"+Контакт.firstName+"</urn1:a>
// | <urn1:a n=""lastName"">"+Контакт.lastName+"</urn1:a>
// | <urn1:a n=""middleName"">"+Контакт.middleName+"</urn1:a>
// | <urn1:a n=""company"">"+Контакт.company+"</urn1:a>
// | <urn1:a n=""jobTitle"">"+Контакт.jobTitle+"</urn1:a>
// | <urn1:a n=""mobilePhone"">"+Контакт.mobilePhone+"</urn1:a>
// | <urn1:a n=""workPhone"">"+Контакт.workPhone+"</urn1:a>
// | <urn1:a n=""email"">"+Контакт.email+"</urn1:a>
// | <urn1:a n=""notes"">"+Контакт.notes+"</urn1:a>
// | </urn1:cn>
// | </urn1:ModifyContactRequest>
// |</soapenv:Body>
// |</soapenv:Envelope>";
Запрос=ПолучитьXMLСообщениеДляЗапроса(Токен,Контакт,ZimbraID);
Ответ=ОтправитьЗапросSOAP(Запрос,"urn:zimbraMail/ModifyContact");
Если Ответ=Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
Конецфункции
Данный метод вызывает "ModifyContact" у "zimbraMail", возвращает истина или ложь. Для наглядности в методе оставил xml сообщение.
Работа с группами для рассылки
Так же существуют задачи по формированию Групп для рассылок. Группы могут быть как внешние(например разослать письмо всем покупателям товара "Стол") или внутренние по отделам, структуры компании, для внутренней рассылки.
Для этих целей так же используются методы CreateContact ModifyContact.
А для правильного формирования сообщения, у метода ПолучитьXMLСообщениеДляЗапроса(), последним параметром указываем что это группа. В структуре Контакт, добавляем свойство "СоставИД" это массив, который заполняем ид созданных контактов.
После чего на сервере zimbra будет создана группа, при её вводе пользователем, в поле Кому, сразу подставятся те адреса, ид которых Вы укажите в СоставИД.
Итог
На этом все, информации выше должно быть достаточно, для решения задач интеграции 1с и Zimbra. Дополнительно читаем документацию к Zimbra.
От себя хочется добавить лишь пару слов об так называемых Zimlets.
По сути это аналог 1с - совских внешних обработок. Аналогично выполняют роль Zimlets, они позволяют без изменения основного кода системы, расширить её функционал. Ссылка на каталог.
При этом есть достаточно подробно задокументированное API, Ссылка.
Таким образом, если Вам нужно что бы Zimbra обращалась к 1С, Вы можете сделать свой Zimlet, чем мы и собираемся в ближайшее время заняться для решения остальных проблем.
Описание, что для этого нужно