Отправка смс из 1C по протоколу SMPP v3.4
В жизни всякое бывает и, возможно, кому понадобится отправлять много СМС из 1C.
Главное, не забывать, что работа SMPP протокола подразумевает под собой поддержание постоянного подключения к поставщику.
В описании пойдет речь о подключении программы семейства «1C: Предприятие 8x».
Для реализации проекта, нам понадобится сторонний компонент – ActiveX: Winsock.
Для установки данного компонента достаточно просто скачать и установить его с официального сайта — http://www.microsoft.com/ru-ru/softmicrosoft/VisualStudioExpress.aspx
После установки – размещаем на форме компонент Winsock.

Добавление компонента
После установки – проверяем и настраиваем (при необходимости методы).

Методы Winsock
Если описать вкратце метод поднятия SMPP сессии, то этот процесс делится на два этапа: поднятие TCP подключения и поднятие SMPP подключения.
Сперва необходимо подключить по TCP протоколу (т. е. поднять / создать сокет соединение).
Процедура Иницилизация() ЭкспортмWinSocketActiveX = ПолучитьФорму(«Форма»).ЭлементыФормы.WinSocket;//иницилизация настроек для подключениямWinSocketActiveX.RemotePort = 2775;мWinSocketActiveX.RemoteHost = «smsc.smppc.com.ua»;ВыполнитьПодключение();КонецПроцедуры // Иницилизация()Процедура ВыполнитьПодключение()Если мWinSocketActiveX.State = 0 ТогдамWinSocketActiveX.Connect();КонецЕсли;КонецПроцедуры |
После успешного соединение с сервером, необходимо отправить команду BIND_TRANSMITTER или BIND_TRANSCEIVER (в зависимости от выбранного метода подключения). Если не отправить команду – то соединение оборвется.
Поэтому после проверки отправляем PDU пакет — (Protocol Data Units (Bind_Transceiver).
Процедура ОпроситьСоединение() Экспорт Если мWinSocketActiveX.State = 7 Тогда PDU = СобратьПакет_BIND_Transceiver(); мWinSocketActiveX.SendData(PDU); Иначе //обработать другие состояния!!! КонецЕсли; КонецПроцедуры // УстановитьСоединение() |
Для обработки ответа (ответного PDU пакета) необходимо использовать многомерный массив 1C COMSafeArray.
Функция СобратьПакет_BIND_Transceiver() Матрица = Новый COMSafeArray("VT_UI1",37); Матрица.SetValue(0,0); Матрица.SetValue(1,0); Матрица.SetValue(2,0); Матрица.SetValue(3,37); //код сокращен для этой статьи*** //*** Матрица.SetValue(32,0); Матрица.SetValue(33,52); Матрица.SetValue(34,1); Матрица.SetValue(35,1); Матрица.SetValue(36,0); Возврат Матрица; КонецФункции // СобратьПакет_BIND_Transceiver() |
Клиент обязан отвечать на все пакеты, отправляемые сервером, в течение 10 – 60 секунд (в зависимости от требований поставщика) – resp пакетами. Если игнорировать запросы и не отвечать – соединение будет разорвано.
Отдельно нужно ответить команде ENQUIRE_LINK, которая используется для проверки работоспособности соединения. Отвечать на нее обязательно, если нужно чтобы СМС продолжали ходить.
Методом DataArrival() принимаем и обрабатываем входящие пакеты:
Процедура WinSocketDataArrival(Элемент, bytesTotal) ВходящийПакет = Неопределено; мWinSocketActiveX.GetData(ВходящийПакет);
Если ТипЗнч(ВходящийПакет) = Тип("COMSafeArray") Тогда ОбработатьВходящийПакет(ВходящийПакет); КонецЕсли; КонецПроцедуры … Процедура ОбработатьВходящийПакет(Пакет) Экспорт //пришел пакет ENQUIRE_LINK Если Пакет.GetValue(4) = 0 И Пакет.GetValue(7) = 21 Тогда PDU = Фабрика_PDU_ENQUIRE_LINK_RESP(Пакет); ОтправитьПакет(PDU); Если мФлагОтправитьСМС Тогда СобратьИОтправитьПакет_CMC();//отсюда отправялем смс-сообщение мФлагОтправитьСМС = Ложь; КонецЕсли; КонецЕсли; //пришел пакет bind_transceiver_resp Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 9 Тогда ОбработатьПакет_bind_transceiver_resp(Пакет); КонецЕсли; //пришел пакет submit_sm_resp Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 4 Тогда ОбработатьПакет_submit_sm_resp(Пакет); КонецЕсли; //пришел пакет Query_sm_resp Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 3 Тогда ОбработатьПакет_Query_sm_resp(Пакет); КонецЕсли; //пришел пакет UNBIND_resp Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 6 Тогда мWinSocketActiveX = Неопределено; КонецЕсли;
КонецПроцедуры // ОбработатьВходящийПакет() |
После того как клиент и сервер успешно обменялись пакетами ENQUIRE_LINK, можно отправить текст смс-сообщения.
Процедура СобратьИОтправитьПакет_CMC() Перем PDU;
Если ЗаполнитьТаблицуЗначенийСМС() Тогда НомерТел = мТабЗнДиспетчерСМС[0].НомерТелефона; НомерДок = мТабЗнДиспетчерСМС[0].НомерДокумента; ДатаДок = мТабЗнДиспетчерСМС[0].ДатаДокумента; СтатусСМС = мТабЗнДиспетчерСМС[0].СтатусСМС; ИдентификаторСМС = мТабЗнДиспетчерСМС[0].ИдентификаторСМС; ТипДокумента = мТабЗнДиспетчерСМС[0].ЗаказПокупателя; Если СтатусСМС = 0 Тогда PDU = СобратьПакет_Submit_SM(НомерТел,НомерДок,ДатаДок,ТипДокумента); СтрокаСообщения = Формат(ТекущаяДата(),"ДЛФ=DT")+" <= Отправляю СМС на номер: " +НомерТел+". Inf..."; Лог.ДобавитьСтроку(СтрокаСообщения); ИначеЕсли СтатусСМС = 10 Тогда PDU = СобратьПакет_Query_SM(ИдентификаторСМС); СтрокаСообщения = Формат(ТекущаяДата(),"ДЛФ=DT")+" <= Запрашиваю статус СМС для номера: "+НомерТел + " . Inf..."; Лог.ДобавитьСтроку(СтрокаСообщения); КонецЕсли; Иначе СтрокаСообщения = Формат(ТекущаяДата(),"ДЛФ=DT")+" <= Нет данных для отправки смс. Закрываю канал связи. Inf..."; Лог.ДобавитьСтроку(СтрокаСообщения); PDU = СобратьПакет_UNBIND(); // отправлять больше нечего. Закрываем соединение; КонецЕсли; ОтправитьПакет(PDU); КонецПроцедуры // СобратьИОтправитьПакет_CMC() // <Описание функции> // // Параметры // <Параметр1> - <Тип.Вид> - <описание параметра> // <продолжение описания параметра> // <Параметр2> - <Тип.Вид> - <описание параметра> // <продолжение описания параметра> // // Возвращаемое значение: // <Тип.Вид> - <описание возвращаемого значения> // Функция СобратьПакет_Submit_SM(НомерТелефона,НомерДокумента,ДатаДокумента,Объект) Перем ИспользоватьРусский; ИспользоватьРусский = Истина; //настройка Если ТипЗнч(Объект) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда СообщениеТекстЛатиница = "Vash tovar po zakazu N "+НомерДокумента+" ot " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy")+" dostavlen"; СообщениеТекстРусский = "Ваш товар по заказу № "+НомерДокумента+" от " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy")+" доставлен"; ИначеЕсли ТипЗнч(Объект) = Тип("ДокументСсылка.АктПретензий") Тогда СообщениеТекстЛатиница = "Vash tovar gotov k vydachi. Akt pretenzii N "+ НомерДокумента+" ot " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy"); СообщениеТекстРусский = "Ваш товар готов к выдаче. Акт претензии № "+ НомерДокумента+" от " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy"); КонецЕсли; Если ИспользоватьРусский Тогда СообщениеТекст = СообщениеТекстРусский; МассивКодовРусскихБукв = ЗакодироватьРусскийТекст(СообщениеТекстРусский); ДлинаСообщения = СтрДлина(СообщениеТекст)*2; DataCod = 8; Иначе СообщениеТекст = СообщениеТекстЛатиница; ДлинаСообщения = СтрДлина(СообщениеТекст); DataCod = 0; КонецЕсли; ДлинаНомераТелефона = СтрДлина(НомерТелефона); ДлинаПакета = 32+ДлинаНомераТелефона+11+ДлинаСообщения; МатрицаДанных = Новый COMSafeArray("VT_UI1",ДлинаПакета-1); //Заголовок МатрицаДанных.SetValue(0, 0); МатрицаДанных.SetValue(1, 0); МатрицаДанных.SetValue(2, 0); МатрицаДанных.SetValue(3, ДлинаПакета-1); МатрицаДанных.SetValue(4, 0); МатрицаДанных.SetValue(5, 0); МатрицаДанных.SetValue(6, 0); МатрицаДанных.SetValue(7, 4); МатрицаДанных.SetValue(8, 0); МатрицаДанных.SetValue(9, 0); МатрицаДанных.SetValue(10, 0); МатрицаДанных.SetValue(11, 0); МатрицаДанных.SetValue(12, 0); МатрицаДанных.SetValue(13, 0); МатрицаДанных.SetValue(14, 0); МатрицаДанных.SetValue(15, 2); //номер пакета //тело МатрицаДанных.SetValue(16, 0); МатрицаДанных.SetValue(17, 5); МатрицаДанных.SetValue(18, 1); МатрицаДанных.SetValue(19, КодСимвола("S")); МатрицаДанных.SetValue(20, КодСимвола("e")); МатрицаДанных.SetValue(21, КодСимвола("n")); // МатрицаДанных.SetValue(22, КодСимвола("d")); // МатрицаДанных.SetValue(23, КодСимвола("e")); // МатрицаДанных.SetValue(24, КодСимвола("r"));// МатрицаДанных.SetValue(25, КодСимвола("s")); МатрицаДанных.SetValue(26, КодСимвола("m")); МатрицаДанных.SetValue(27, КодСимвола("s")); // МатрицаДанных.SetValue(28, 0); МатрицаДанных.SetValue(29, 1); МатрицаДанных.SetValue(30, 1); Индекс = 31; Для НомерСтроки = 1 По ДлинаНомераТелефона Цикл МатрицаДанных.SetValue(Индекс,КодСимвола(НомерТелефона,НомерСтроки)); Индекс = Индекс+1; КонецЦикла; МатрицаДанных.SetValue(42, 0); МатрицаДанных.SetValue(43, 0); МатрицаДанных.SetValue(44, 0); МатрицаДанных.SetValue(45, 0); МатрицаДанных.SetValue(46, 0); МатрицаДанных.SetValue(47, 0); МатрицаДанных.SetValue(48, 1); МатрицаДанных.SetValue(49, 1); МатрицаДанных.SetValue(50, DataCod);//data coding МатрицаДанных.SetValue(51, 1); МатрицаДанных.SetValue(52, ДлинаСообщения); Индекс = 53; Если ИспользоватьРусский Тогда Для НомерСтроки1 = 0 По ДлинаСообщения-1 Цикл СимВ = МассивКодовРусскихБукв[НомерСтроки1]; МатрицаДанных.SetValue(Индекс,СимВ); Индекс = Индекс+1; КонецЦикла; Иначе Для НомерСтроки2 = 1 По ДлинаСообщения Цикл ЗначениеСимвола = КодСимвола(СообщениеТекст,НомерСтроки2); МатрицаДанных.SetValue(Индекс,ЗначениеСимвола); Индекс = Индекс+1; КонецЦикла; КонецЕсли; Возврат МатрицаДанных; КонецФункции // СобратьПакет_Submit_SM() … Процедура ОтправитьПакет(PDU) Если мWinSocketActiveX.State = 7 Тогда мWinSocketActiveX.SendData(PDU); КонецЕсли; КонецПроцедуры // ОтправитьПакет() |
Несмотря на то, что SMPP подключение подразумевает под собой постоянное соединение, можно, конечно, и разрывать соединение (правильно это делать через команду UNBIND), но только, если в течение нескольких часов у Вас не предвидится отправка СМС. Иначе лучше оставлять соединение рабочим.
Источник – www.1c83.ru