БСП: добавление нового провайдера SMS

04.06.17

Интеграция - SMS рассылки

Небольшая статья о том, как добавить нового провайдера 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-сообщений, так же, нужно задать расписание предопределенного регламентного задания:

А вот и результат:

Статья в личном блоге pbazeliuk.com

БСП SMS

См. также

БСП (Библиотека стандартных подсистем) Программист Платные (руб)

Синтакс-помощник БСП - cправочник по библиотеке стандартных подсистем. В состав справочника входит описание экспортных процедур и функций, размещенных в областях кода ПрограммныйИнтерфейс БСП.

1800 руб.

21.11.2024    2356    8    14    

8

SMS рассылки Оптовая торговля Розничная торговля Пользователь Оперативный учет 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Управленческий учет Платные (руб)

Клиенту на номер телефона уходит СМС с четырехзначным случайным цифровым кодом. Клиент сообщает код продавцу, если код подходит, только тогда применяется скидка или бонусная программа. Вместо SMS можно направлять входящий звонок на телефон покупателя, последние четыре цифры и будут являться кодом подтверждения.

4500 руб.

06.09.2017    25770    28    2    

35

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Бесплатно (free)

В статье описан алгоритм для включения документа или справочника в систему БСП. Будет полезно программистам 1С, начинающим работать с БСП.

24.10.2024    1396    PROSTO-1C    0    

16

БСП (Библиотека стандартных подсистем) Работа с интерфейсом Программист Платформа 1С v8.3 Бесплатно (free)

В материале описан универсальный механизм работы с добавленными элементами на общую форму «ФормаОтчета». Думаю, облегчит работу многим разработчикам.

08.10.2024    1194    PROSTO-1C    4    

14

БСП (Библиотека стандартных подсистем) Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В статье рассмотрим пошаговую инструкцию создания дополнительного отчета с фоновым формированием результата.

04.10.2024    2082    MadRave    11    

24

БСП (Библиотека стандартных подсистем) Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример отслеживания прогресса фонового выполнения дополнительной обработки с использованием программного интерфейса длительных операций БСП.

10.09.2024    2203    MadRave    5    

19

БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Добавим дополнительные свойства в новый документ средствами БСП

02.09.2024    4364    John_d    10    

53
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. asved.ru 37 03.12.14 09:53 Сейчас в теме
Я правильно понимаю, что подсистема не поддерживает многопоточную отправку и многопоточный контроль статуса?
2. pbazeliuk 1970 03.12.14 10:41 Сейчас в теме
(1) asved.ru, 1C не поддерживает многопоточного программирования. Частный случай запуск нескольких фоновых заданий.
3. asved.ru 37 03.12.14 20:31 Сейчас в теме
(2) Вы сами себе противоречите :)

Любой многопоточный алгоритм есть продукт распараллеливания линейного алгоритма тем или иным методом. В 1С, в частности, это делается при помощи механизма фоновых заданий.

В силу того, что (я надеюсь) Вы разбирали работу подсистемы, я и спрашиваю, поддерживается ли в подсистеме многопоточная отправка.
4. pbazeliuk 1970 03.12.14 21:04 Сейчас в теме
(3) asved.ru, нет не поддерживается, отправка последовательная. Механизм фоновых заданий, не считаю, полноценным решением для полноценного многопоточного программирования.
nickperel; i_volodin; +2 Ответить
5. nickperel 5 09.06.17 11:26 Сейчас в теме
(4)
Хорошая работа.
Первый раз вижу такой дельный пример разработки БСП через реализацию переопределяемых. Надо будет с Мегафоном попробовать.
Можно ОтправитьSMS обернуть в ВыполнитьВФоне, рассылка пойдет в задании. Но ее, рассылку, делать надо. В коде чего-то с налету не нашел.
pbazeliuk; +1 Ответить
Оставьте свое сообщение