Для тех, кто хочет организовать взаимодействие с клиентом и получение обратной связи без увеличения нагрузки на персонал, будет полезна данная статья.
Будем использовать технологии:
Начнем с того, что у многих стоит база 1С и в ней есть продажи, клиенты и хотелось бы организовать опросы клиентов по качеству обслуживания или по другим вопросам (в этом случае модифицируем приложенный к публикации модуль и поехали).
Наилучшим образом подходит для данной реализации использование сайта на .NET MVC и платформы 1С с загрузкой результатов в базу 1С.
Со стороны 1С подключаем расширение (пока реализовано для ERP 1С:ERP Управление предприятием 2 (2.5.6.98), Управление торговлей, редакция 11 (11.4.13.227) в дальнейшем планируется выпустить расширения и для других конфигураций), подключаем внешнюю обработку и настраиваем регламентные задания из обработки.
Заносим подключение к сайту в настройки сайта опросов.
Настраиваем системную учетную запись электронной почты.
Со стороны сайта публикуем на IIS и устанавливаем строку подключения к базе сайта в Web.config.
Подключаем базу сайта в MSSQL.
Просим пользователей указывать электронные адреса в карточках клиентов и показываем руководству отчеты.
Тестирование решения проводилось на платформе 8.3.18.1363.
А теперь немного тонкостей реализации
За основу синхронизации возьмем JSON с сериализацией и десериализацией средствами 1С и .Net, будет API на стороне сайта и обращение к нему из 1С.
Для обращения к базе на стороне сайта будем использовать хранимые процедуры MSSQL с целью исключения SQL инъекции.
Как сделано API
public IHttpActionResult Put(string id, [FromBody]InputStructtoBase InputStruct)
{
if (InputStruct == null)
{
return Ok("Не определены входные параметры");
}
if (InputStruct.tok == null)
{
return Ok("Не определены входные параметры");
}
ResPuttoBasebyID rezprov = rezprovtok(InputStruct.tok);
if (rezprov.vipoln == false)
{
return Ok(rezprov.soobhenie);
}
if (InputStruct.Id == null || InputStruct.Id.Count == 0)
{
return Ok("Не определены входные параметры");
}
if (InputStruct.deistvie == "zaneszapisi")
{
Workwithdb workbd = new Workwithdb();
ResPuttoBasebyID resultput;
resultput = workbd.PuttoBasebyID(InputStruct);
if (resultput.vipoln)
{
return Ok(true);
}
else
{
return Ok(resultput.soobhenie);
}
}
else
{
return Ok("Не определены входные параметры");
}
}
Как сделано взаимодействие с базой
public ResPuttoBasebyID PuttoBasebyID(InputStructtoBase InputStruct)
{
ResPuttoBasebyID srtbs = new ResPuttoBasebyID();
if (InputStruct.Id.Count == 0)
{
srtbs.soobhenie = "Некорректный id";
srtbs.vipoln = false;
return srtbs;
}
string connectionString = ConfigurationManager.ConnectionStrings["baseconnectionstring"].ConnectionString;
sqlConnection = new SqlConnection(connectionString);
try
{
sqlConnection.Open();
}
catch (Exception ex)
{
srtbs.soobhenie = "Ошибка обработки запроса " + ex.Message.ToString() + " " + ex.Source.ToString();
srtbs.vipoln = false;
return srtbs;
}
SqlCommand command = new SqlCommand("putstrtotable", sqlConnection);
command.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter Param1 = new SqlParameter
{
ParameterName = "@id",
Value = InputStruct.Id.Select(c => c.ToSqlDataRecord()),
SqlDbType = System.Data.SqlDbType.Structured,
TypeName = "[dbo].[structelvers]"
};
command.Parameters.Add(Param1);
try
{
command.ExecuteNonQuery();
srtbs.vipoln = true;
}
catch (Exception ex)
{
srtbs.soobhenie = "Ошибка обработки запроса " + ex.Message.ToString() + " " + ex.Source.ToString();
srtbs.vipoln = false;
}
if (sqlConnection != null && sqlConnection.State != ConnectionState.Closed)
sqlConnection.Close();
return srtbs;
}
Интерфейс страницы
@model WebApplication1.Models.modeltest
@{
ViewBag.Title = "Условия доставки";
}
@using (Html.BeginForm())
{
<center>
<h4>Оцените качество обслуживания по документу №@Model.numotgr</h4>
<div class="rating-area">
<input type="radio" id="star5" name="rating" value=5>
<label for="star5" title="Оценка «5»"></label>
<input type="radio" id="star4" name="rating" value=4>
<label for="star4" title="Оценка «4»"></label>
<input type="radio" id="star3" name="rating" value=3>
<label for="star3" title="Оценка «3»"></label>
<input type="radio" id="star2" name="rating" value=2>
<label for="star2" title="Оценка «2»"></label>
<input type="radio" id="star1" name="rating" value=1>
<label for="star1" title="Оценка «1»"></label>
</div>
<caption>Текст отзыва</caption>
<br>
@Html.TextArea("texstotziv", @Model.texstotziv, new { @type = "Text", style = "resize: both; width:100%; height: 150px"})
<br>
<br>
<input type="submit" value="Отправить" style="border: 2px solid #000">
</center>
}
И со стороны 1С
Взаимодействие с API
Отправим методом PUT данные на сайт
Функция ОтправитьНаСайт(ОбработатанныеДанные)
РезультатОтправки = Новый Структура("Отказ", Ложь);
ПодключениеКСайту = ПолучитьПоключениеКСайту();
Если ПодключениеКСайту = Неопределено Тогда
РезультатОтправки.Отказ = Истина;
Возврат РезультатОтправки;
КонецЕсли;
ТекстЗапросаОтправки = ПолучитьТекстЗапросаОтправки(ОбработатанныеДанные);
ЗаголовокHTTP = ПолучитьЗаголовкиПодключения();
Ресурс = "";
HTTPЗапрос = Новый HTTPЗапрос(Ресурс, ЗаголовокHTTP);
HTTPЗапрос.УстановитьТелоИзСтроки(ТекстЗапросаОтправки, КодировкаТекста.UTF8);
Попытка
ОтветССайта = ПодключениеКСайту.Записать(HTTPЗапрос);
Исключение
ЗаписьЖурналаРегистрации("Отправка на сайт",,,, ОписаниеОшибки());
РезультатОтправки.Отказ = Истина;
Возврат РезультатОтправки;
КонецПопытки;
Если ОтветССайта = Неопределено Тогда
РезультатОтправки.Отказ = Истина;
Возврат РезультатОтправки;
КонецЕсли;
КодСостояния = ОтветССайта.КодСостояния;
Если Не КодСостояния = 200 Тогда
ЗаписьЖурналаРегистрации("Ошибка отправки на сайт",,, "Ошибка " + ОтветССайта.ПолучитьТелоКакСтроку());
РезультатОтправки.Отказ = Истина;
Возврат РезультатОтправки;
КонецЕсли;
Тело = ОтветССайта.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Тело);
ЗначениеСчитанное = ПрочитатьJSON(ЧтениеJSON);
СтрокаОтвета = Строка(ЗначениеСчитанное);
Если Не СтрокаОтвета = "Да" Тогда
ЗаписьЖурналаРегистрации("Ошибка отправки на сайт",,, "Ошибка " + СтрокаОтвета);
РезультатОтправки.Отказ = Истина;
Возврат РезультатОтправки;
КонецЕсли;
Возврат РезультатОтправки;
КонецФункции
Сформируем данные для отправки
Функция ПолучитьТекстЗапросаОтправки(ОбработатанныеДанные)
тЗаписьJSON = Новый ЗаписьJSON;
тПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
тЗаписьJSON.УстановитьСтроку(тПараметрыJSON);
ЗаписатьJSON(тЗаписьJSON, ОбработатанныеДанные);
strJSON = тЗаписьJSON.Закрыть();
Структура = Новый Структура;
Структура.Вставить("tok", ПолучитьТокенПодключения());
Структура.Вставить("Id", ОбработатанныеДанные);
Структура.Вставить("deistvie", "zaneszapisi");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Структура);
Строка = ЗаписьJSON.Закрыть();
Возврат Строка;
КонецФункции
Получим данные с сайта сформировав запрос методом Post
HTTP = ПолучитьПоключениеКСайту();
ЗаголовокHTTP = ПолучитьЗаголовкиПодключения();
Ресурс = "";
HTTPЗапрос = Новый HTTPЗапрос(Ресурс, ЗаголовокHTTP);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса, КодировкаТекста.UTF8);
ОтветСайта = HTTP.ОтправитьДляОбработки(HTTPЗапрос);
КодСост = ОтветСайта.КодСостояния;
Если Не КодСост = 200 Тогда
ЗаписьЖурналаРегистрации("ПолучениеРезультатаОпросов",,, "Код ответа не 200");
РезультатыОпроса.Отказ = Истина;
КонецЕсли;
Тело = ОтветСайта.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Тело);
ЗначСчит = ПрочитатьJSON(ЧтениеJSON);
Если Не ТипЗнч(ЗначСчит) = Тип("Структура") Тогда
ЗаписьЖурналаРегистрации("ПолучениеРезультатаОпросов",,, ОтветСайта.ПолучитьТелоКакСтроку());
РезультатыОпроса.Отказ = Истина;
Возврат РезультатыОпроса;
КонецЕсли;
Если ЗначСчит.otkazpoluch = Истина Тогда
ЗаписьЖурналаРегистрации("ПолучениеРезультатаОпросов",,, ЗначСчит.soobhohibka);
РезультатыОпроса.Отказ = Истина;
КонецЕсли;
РезультатыОпроса.Данные = ЗначСчит.elemets;
Возврат РезультатыОпроса;
Функция ПолучитьПоключениеКСайту()
Сервер = ПолучитьАдресСервера() + "/api/Reservation/1";
ПодключениеКСайту = Новый HTTPСоединение(Сервер);
Возврат ПодключениеКСайту;
КонецФункции
Функция ПолучитьТекстЗапросаОтправки(ОбработатанныеДанные)
тЗаписьJSON = Новый ЗаписьJSON;
тПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
тЗаписьJSON.УстановитьСтроку(тПараметрыJSON);
ЗаписатьJSON(тЗаписьJSON, ОбработатанныеДанные);
strJSON = тЗаписьJSON.Закрыть();
Структура = Новый Структура;
Структура.Вставить("tok", ПолучитьТокенПодключения());
Структура.Вставить("Id", ОбработатанныеДанные);
Структура.Вставить("deistvie", "zaneszapisi");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Структура);
Строка = ЗаписьJSON.Закрыть();
Возврат Строка;
КонецФункции
Обработаем полученные данные сайта производя определение ссылки документа методом ПолучитьСсылку() менеджера объекта передавая в него уникальный идентификатор
Функция ОбработатьРезультатыОпроса(РезультатыОпроса)
ОбработанныеРезультатыОпроса = Новый Массив;
Для Каждого ЭлРезультата Из РезультатыОпроса.Данные Цикл
СтруктураДанных = Новый Структура("УИД, Основание, РезультатОпроса, Сохранен, Версия, Баллов");
СтруктураДанных.РезультатОпроса = ЭлРезультата.texstotziv;
Попытка
ОснованиеУИД = Новый УникальныйИдентификатор(ЭлРезультата.Id);
Исключение
ЗаписьЖурналаРегистрации("Обработка результатов опроса получение ссылки",,,, Строка(ЭлРезультата.Id) + " " + ОписаниеОшибки());
Продолжить;
КонецПопытки;
Попытка
ОснованиеСсылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(ОснованиеУИД);
Исключение
ЗаписьЖурналаРегистрации("Обработка результатов опроса получение ссылки",,,, Строка(ЭлРезультата.Id) + " " + ОписаниеОшибки());
Продолжить;
КонецПопытки;
СтруктураДанных.Основание = ОснованиеСсылка;
СтруктураДанных.УИД = ЭлРезультата.Id;
СтруктураДанных.Версия = ЭлРезультата.version;
СтруктураДанных.Баллов = ЭлРезультата.ballov;
ОбработанныеРезультатыОпроса.Добавить(СтруктураДанных);
КонецЦикла;
Возврат ОбработанныеРезультатыОпроса;
КонецФункции
На SQL сервере добавление записи по опросу
CREATE PROCEDURE putstrtotable
@id [dbo].[structelvers] Readonly
AS
INSERT INTO [dbo].[ResultsZaprosov] (Id, textotziv, ballov, obrabotano, versionstr, dateobrab, numotgr)
Select tableid.id , '', 0, 0, 1, GETDATE(), tableid.numotgr from @id tableid
left join [dbo].[ResultsZaprosov]
on tableid.id = [dbo].[ResultsZaprosov].id
Where [dbo].[ResultsZaprosov].id is null
RETURN 0