Небольшая статья о том, как добавить нового провайдера SMS на примере конфигурации «Управление торговлей 11», используя библиотеку стандартных подсистем (БСП).Перед началом добавления нового провайдера услуг нужно убедиться в работоспособности его API. Поможет в этом замечательный инструмент-расширение к браузеру Google Chrome click.
Будем считать, что все тесты прошли успешно. Во-первых, нужно разрешить возможность редактирования общего модуля ОтправкаСМСПереопределяемый и перечисления ПровайдерыСМС:
Во-вторых, добавить в перечисление ПровайдерыСМС название своего провайдера:
В-третьих, выполнить настройку провайдера SMS, указать логин и пароль в базе данных. Вкладка «Администрирование»:
Далее нужно определить описание взаимодействия с API в общем модуле ОтправкаСМСПереопределяемый. Нужно переопределить 3 пустых процедуры:
// Проверяет правильность сохраненных настроек отправки SMS. Процедура ПриПроверкеНастроекОтправкиSMS(НастройкиОтправкиSMS, Отказ) // Отправляет SMS через настроенного поставщика услуги, возвращает идентификатор сообщения. Процедура ОтправитьSMS(ПараметрыОтправки, Результат) // Запрашивает статус доставки SMS у поставщика услуг. Процедура СтатусДоставки(ИдентификаторСообщения, Провайдер, Логин, Пароль, Результат)
Важно, провайдер alphasms использует для коммуникации POST-запросы, на входе и выходе xml-файлы, у других провайдеров может быть все иначе (GET, POST, etc. и другие форматы).
Код процедуры ПриПроверкеНастроекОтправкиSMS у меня получился такой:
Процедура ПриПроверкеНастроекОтправкиSMS(НастройкиОтправкиSMS, Отказ) Экспорт Перем Провайдер, Логин, Пароль; Если ТипЗнч(НастройкиОтправкиSMS) = Тип("Структура") Тогда Если НастройкиОтправкиSMS.Свойство("Логин", Логин) И НастройкиОтправкиSMS.Свойство("Пароль", Пароль) И НастройкиОтправкиSMS.Свойство("Провайдер", Провайдер)Тогда Если Логин = Неопределено ИЛИ ПустаяСтрока(Логин) Тогда Отказ = Истина; КонецЕсли; Если Пароль = Неопределено ИЛИ ПустаяСтрока(Пароль) Тогда Отказ = Истина; КонецЕсли; Если Провайдер = Неопределено ИЛИ Провайдер = Перечисления.ПровайдерыSMS.ПустаяСсылка() Тогда Отказ = Истина; КонецЕсли; Иначе Отказ = Истина; КонецЕсли; Иначе Отказ = Истина; КонецЕсли; КонецПроцедуры
Код отправки SMS у меня базировался на API провайдера:
- тело POST запроса в кодировке «UTF-8»:
- примерный ответ сервиса в результате успеха:
- примерный ответ сервиса в результате ошибки:
// Отправляет SMS через настроенного поставщика услуги, возвращает идентификатор сообщения. // // Параметры: // ПараметрыОтправки - Структура: // * Провайдер - ПеречислениеСсылка.ПровайдерыSMS - поставщик услуги по отправке SMS. // * НомераПолучателей - Массив - массив строк номеров получателей в формате +7ХХХХХХХХХХ. // * Текст - Строка - текст сообщения, максимальная длина у операторов может быть разной. // * ИмяОтправителя - Строка - имя отправителя, которое будет отображаться вместо номера у получателей. // * Логин - Строка - логин для доступа к услуге отправки SMS. // * Пароль - Строка - пароль для доступа к услуге отправки SMS. // Результат - Структура - (возвращаемое значение): // * ОтправленныеСообщения - Массив структур: // * НомерПолучателя - Строка - номер получателя из массива НомераПолучателей; // * ИдентификаторСообщения - Строка - идентификатор SMS, по которому можно запросить статус отправки. // * ОписаниеОшибки - Строка - пользовательское представление ошибки, если пустая строка, то ошибки нет. // Процедура ОтправитьSMS(ПараметрыОтправки, Результат) Экспорт Если ПараметрыОтправки.Провайдер = Перечисления.ПровайдерыSMS.AlfaSMS Тогда // проверка на заполнение обязательных параметров Если ПараметрыОтправки.НомераПолучателей.Количество() = 0 Или ПустаяСтрока(ПараметрыОтправки.Текст) Тогда Результат.ОписаниеОшибки = НСтр("ru = 'Неверные параметры сообщения'"); Возврат; КонецЕсли; // отправка запроса ИмяФайлаОтвета = ВыполнитьЗапрос(ПараметрыОтправки); Если ПустаяСтрока(ИмяФайлаОтвета) Тогда Результат.ОписаниеОшибки = Результат.ОписаниеОшибки + НСтр("ru = 'Соединение не установлено'"); Возврат; КонецЕсли; // обработка результата запроса (получение идентификаторов сообщений) СтруктураОтвета = Новый ЧтениеXML; СтруктураОтвета.ОткрытьФайл(ИмяФайлаОтвета); ОписаниеОшибки = ""; ИндексНомера = 0; Пока СтруктураОтвета.Прочитать() Цикл Если СтруктураОтвета.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда Если СтруктураОтвета.Имя = "msg" Тогда ИдентификаторСообщения = ""; НомерПолучателя = ""; Пока СтруктураОтвета.ПрочитатьАтрибут() Цикл Если СтруктураОтвета.Имя = "sms_id" Тогда ИдентификаторСообщения = СтруктураОтвета.Значение; НомерПолучателя = ФорматироватьНомер(ПараметрыОтправки.НомераПолучателей[ИндексНомера]); ИндексНомера = ИндексНомера + 1; КонецЕсли; КонецЦикла; Если Не ПустаяСтрока(НомерПолучателя) Тогда ОтправленноеСообщение = Новый Структура("НомерПолучателя,ИдентификаторСообщения", НомерПолучателя,ИдентификаторСообщения); Результат.ОтправленныеСообщения.Добавить(ОтправленноеСообщение); КонецЕсли; ИначеЕсли СтруктураОтвета.Имя = "error" Тогда СтруктураОтвета.Прочитать(); ОписаниеОшибки = ОписаниеОшибки + СтруктураОтвета.Значение + Символы.ПС; КонецЕсли; КонецЕсли; КонецЦикла; СтруктураОтвета.Закрыть(); УдалитьФайлы(ИмяФайлаОтвета); Результат.ОписаниеОшибки = СокрП(ОписаниеОшибки); КонецЕсли; КонецПроцедуры // ОтправитьSMS() Функция ВыполнитьЗапрос(ПараметрыЗапроса) Результат = ""; ИмяФайлаЗапроса = СформироватьФайлДляPOSTЗапроса(ПараметрыЗапроса); ИмяФайлаОтвета = ПолучитьИмяВременногоФайла("xml"); // формирование заголовка Заголовок = Новый Соответствие; Заголовок.Вставить("Content-Type", "application/x-www-form-urlencoded"); Заголовок.Вставить("Content-Length", XMLСтрока(РазмерФайла(ИмяФайлаЗапроса))); // отправка запроса и получение ответа Попытка Соединение = Новый HTTPСоединение("alphasms.com.ua", , , , ПолучениеФайловИзИнтернетаКлиентСервер.ПолучитьПрокси("https"), 3); Соединение.ОтправитьДляОбработки(ИмяФайлаЗапроса, "api/xml.php", ИмяФайлаОтвета, Заголовок); Результат = ИмяФайлаОтвета; Исключение ЗаписьЖурналаРегистрации( НСтр("ru = 'Отправка SMS'", ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); КонецПопытки; УдалитьФайлы(ИмяФайлаЗапроса); Возврат Результат; КонецФункции // ВыполнитьЗапрос() Функция СформироватьФайлДляPOSTЗапроса(ПараметрыЗапроса) ИмяФайлаЗапроса = ПолучитьИмяВременногоФайла("xml"); ТелоЗапросаXML = Новый ЗаписьXML; ТелоЗапросаXML.ОткрытьФайл(ИмяФайлаЗапроса, "UTF-8"); ТелоЗапросаXML.ЗаписатьОбъявлениеXML(); ТелоЗапросаXML.ЗаписатьНачалоЭлемента("package"); ТелоЗапросаXML.ЗаписатьАтрибут("login", ПараметрыЗапроса.Логин); ТелоЗапросаXML.ЗаписатьАтрибут("password", ПараметрыЗапроса.Пароль); Если ПараметрыЗапроса.Свойство("ИдентификаторСообщения") Тогда ТелоЗапросаXML.ЗаписатьНачалоЭлемента("status"); ТелоЗапросаXML.ЗаписатьНачалоЭлемента("msg"); ТелоЗапросаXML.ЗаписатьАтрибут("sms_id", ПараметрыЗапроса.ИдентификаторСообщения); ТелоЗапросаXML.ЗаписатьКонецЭлемента(); ТелоЗапросаXML.ЗаписатьКонецЭлемента(); Иначе ТелоЗапросаXML.ЗаписатьНачалоЭлемента("message"); Для каждого НомераПолучателя Из ПараметрыЗапроса.НомераПолучателей Цикл ТелоЗапросаXML.ЗаписатьНачалоЭлемента("msg"); ТелоЗапросаXML.ЗаписатьАтрибут("recipient", ФорматироватьНомер(НомераПолучателя)); ТелоЗапросаXML.ЗаписатьАтрибут("sender", "KTC-ua.com"); ТелоЗапросаXML.ЗаписатьАтрибут("type", "0"); ТелоЗапросаXML.ЗаписатьТекст(ПараметрыЗапроса.Текст); ТелоЗапросаXML.ЗаписатьКонецЭлемента(); КонецЦикла; ТелоЗапросаXML.ЗаписатьКонецЭлемента(); КонецЕсли; ТелоЗапросаXML.ЗаписатьКонецЭлемента(); ТелоЗапросаXML.Закрыть(); Возврат ИмяФайлаЗапроса; КонецФункции // СформироватьФайлДляPOSTЗапроса() Функция ФорматироватьНомер(Номер) Результат = ""; ДопустимыеСимволы = "+1234567890"; Для Позиция = 1 По СтрДлина(Номер) Цикл Символ = Сред(Номер,Позиция,1); Если Найти(ДопустимыеСимволы, Символ) > 0 Тогда Результат = Результат + Символ; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // ФорматироватьНомер() Функция РазмерФайла(ИмяФайла) Файл = Новый Файл(ИмяФайла); Возврат Файл.Размер(); КонецФункции // РазмерФайла()
После переопределения 2-х функций уже должна работать отправка sms. Чтобы выполнялась отправка sms конфигурацией, нужно настроить расписание предопределенного регламентного задания:
А вот и результат:
Осталось переопределить последнюю процедуру СтатусДоставки, она нужна для обновления статуса sms-сообщения в базе. API провайдера:
- тело POST запроса в кодировке «UTF-8»:
- примерный ответ сервиса в результате успеха:
// Запрашивает статус доставки SMS у поставщика услуг. // // Параметры: // ИдентификаторСообщения - Строка - идентификатор, присвоенный SMS при отправке; // Логин - Строка - логин для доступа к услуге отправки SMS. // Пароль - Строка - пароль для доступа к услуге отправки SMS. // Результат - Строка - (возвращаемое значение) статус доставки, // см. описание функции ОтправкаSMS.СтатусДоставки. Процедура СтатусДоставки(ИдентификаторСообщения, Провайдер, Логин, Пароль, Результат) Экспорт Если Провайдер = Перечисления.ПровайдерыSMS.AlfaSMS Тогда // подготовка параметров запроса ПараметрыЗапроса = Новый Структура; ПараметрыЗапроса.Вставить("Логин", Логин); ПараметрыЗапроса.Вставить("Пароль", Пароль); ПараметрыЗапроса.Вставить("ИдентификаторСообщения", ИдентификаторСообщения); // отправка запроса ИмяФайлаОтвета = ВыполнитьЗапрос(ПараметрыЗапроса); Если ПустаяСтрока(ИмяФайлаОтвета) Тогда Результат = "Ошибка"; Возврат; КонецЕсли; // обработка результата запроса SMSSTS_CODE = ""; ТекущийSMS_ID = ""; СтруктураОтвета = Новый ЧтениеXML; СтруктураОтвета.ОткрытьФайл(ИмяФайлаОтвета); Пока СтруктураОтвета.Прочитать() Цикл Если СтруктураОтвета.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда Если СтруктураОтвета.Имя = "msg" Тогда Пока СтруктураОтвета.ПрочитатьАтрибут() Цикл Если СтруктураОтвета.Имя = "sms_id" Тогда ТекущийSMS_ID = СтруктураОтвета.Значение; КонецЕсли; КонецЦикла; СтруктураОтвета.Прочитать(); SMSSTS_CODE = СтруктураОтвета.Значение; КонецЕсли; КонецЕсли; КонецЦикла; СтруктураОтвета.Закрыть(); УдалитьФайлы(ИмяФайлаОтвета); Результат = СтатусДоставкиSMS(SMSSTS_CODE); КонецЕсли; КонецПроцедуры // СтатусДоставки() Функция СтатусДоставкиSMS(СтатусСтрокой) СоответствиеСтатусов = Новый Соответствие; СоответствиеСтатусов.Вставить("", "НеОтправлялось"); СоответствиеСтатусов.Вставить("100", "НеОтправлялось"); // SCHEDULED СоответствиеСтатусов.Вставить("101", "Отправляется"); // ENROUTE СоответствиеСтатусов.Вставить("102", "Доставлено"); // DELIVERED СоответствиеСтатусов.Вставить("103", "НеДоставлено"); // EXPIRED СоответствиеСтатусов.Вставить("104", "НеДоставлено"); // DELETED СоответствиеСтатусов.Вставить("105", "НеДоставлено"); // UNDELIVERABLE СоответствиеСтатусов.Вставить("106", "Отправлено"); // ACCEPTED СоответствиеСтатусов.Вставить("107", "НеОпознаноПровайдером"); // UNKNOWN СоответствиеСтатусов.Вставить("108", "НеОпознаноПровайдером"); // REJECTED СоответствиеСтатусов.Вставить("109", "НеОпознаноПровайдером"); // DISCARDED СоответствиеСтатусов.Вставить("110", "Отправляется"); // SENDING СоответствиеСтатусов.Вставить("111", "НеДоставлено"); // NOT_SUPPORTED СоответствиеСтатусов.Вставить("112", "НеДоставлено"); // WRONG_ALPHANAME СоответствиеСтатусов.Вставить("113", "НеДоставлено"); // WRONG_ALPHANAME_RETURNED Результат = СоответствиеСтатусов[НРег(СтатусСтрокой)]; Возврат ?(Результат = Неопределено, "Ошибка", Результат); КонецФункции // СтатусДоставкиSMS()
Для обновления статусов sms-сообщений, так же, нужно задать расписание предопределенного регламентного задания:
А вот и результат: