В данной статье представлен код, который позволяет получать данные ССП для расчета ПДН в режиме "одного окна" из любого БКИ (НБКИ, ОКБ, Эквифакс и прочие).
На этом этапе у вас уже должен быть заключен договор с БКИ, на руках имеется сертификат, полученный от ЦБ, и вы зарегистрировали его в БКИ для отправки запросов и шифрования соединения (согласно требованиям ЦБ - все запросы должны осуществляться по защищенному соединению + запрос должен быть подписан присоединенной ЭП).
Все запросы в случае НБКИ необходимо направлять по адресу https://reports.nbki.ru/qbch/
Ссылка на описание API ЦБ https://www.cbr.ru/ckki/transfer_inform/
По сути, данная разработка применима к любому из четырех БКИ, ведь API у всех одинаковое и теперь ЦБ регулирует, чтобы не нужно было под каждое конкретное БКИ подстраиваться.
Так что - заключить договор можно с любом БКИ, код будет рабочим всегда, меняется только корневой адрес, куда слать запросы.
Первый этап - для упрощения текст шаблона можно поместить в макет, или в процедуру, как строку с символами переноса. Я выбрал для себя первый вариант.
Чтобы не выкладывать готовую обработку, привожу тексты процедур и текст шаблона ниже:
Шаблон запроса (можете вставить в макет или использовать прямо в процедуре):
<ЗапросСведенийОПлатежах ТипЗапроса="2" ИдентификаторЗапроса="[ИдентификаторЗапроса]" Версия="1.2">
<Абонент>
<ЮридическоеЛицо>
<ИНН>[ИННОрганизации]</ИНН>
<ОГРН>[ОГРНОрганизации]</ОГРН>
</ЮридическоеЛицо>
</Абонент>
<Запрос Дата="[ДатаЗапроса]">
<Источник>
<ЮридическоеЛицо ПризнакРегистрацииРФ="1" КодВидаПользователя="3">
<ИНН>[ИННОрганизации]</ИНН>
<ОГРН>[ОГРНОрганизации]</ОГРН>
<ПолноеНаименование>[НаименованиеПолное]</ПолноеНаименование>
<СокращенноеНаименование>[НаименованиеСокращенное]</СокращенноеНаименование>
</ЮридическоеЛицо>
</Источник>
<Субъект>
<ФИО>
<Фамилия>[Фамилия]</Фамилия>
<Имя>[Имя]</Имя>
<Отчество>[Отчество]</Отчество>
</ФИО>
[ПредыдущиеФИО]
<ДатаРождения>[ДатаРождения]</ДатаРождения>
<ДокументЛичности КодДУЛ="21">
<Серия>[СерияПаспорта]</Серия>
<Номер>[НомерПаспорта]</Номер>
<ДатаВыдачи>[ДатаВыдачиПаспорта]</ДатаВыдачи>
<Гражданство>643</Гражданство>
</ДокументЛичности>
[ПредыдущиеДУЛ]
</Субъект>
<Согласие ОбОтветственностиПредупрежден="1" СрокДействия="1" ДатаВыдачи="[ДатаНачалаСогласия]">
<Выдано>
<ЮридическоеЛицо>
<ИНН>[ИННОрганизации]</ИНН>
<ОГРН>[ОГРНОрганизации]</ОГРН>
<ПолноеНаименование>[НаименованиеПолное]</ПолноеНаименование>
</ЮридическоеЛицо>
</Выдано>
<Цель КодЦели="2"/>
</Согласие>
<Цель КодЦели="2"/>
<СуммаОбязательства Валюта="RUB">[СуммаЗайма]</СуммаОбязательства>
</Запрос>
</ЗапросСведенийОПлатежах>
Основная процедура, которая на входе получает заявку на займ (с примитивным набором реквизитов), также можете передавать в виде структуры набор реквизитов, на основании которых формируется тело для POST-запроса.
Для отправки данного запроса соединение необходимо шифровать пользовательским сертификатом ЦБ, который зарегистрирован в БКИ для шифрования соединения.
Я использую stunnel, подробнее можно узнать из других статей.
Далее на основании тела запроса генерируется отсоединенная подпись средствами 1С, и присоединяется к основному запросу.
Функция ПолучитьДанныеПодсистемы_RUTDF_ССП(ЗаявкаНаЗайм, ТекстОтвета) Экспорт
ИдентификаторЗапроса = Новый УникальныйИдентификатор;
РеквизитыЗаявки = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ЗаявкаНаЗайм, "Контрагент, Дата, Организация, Организация.ИНН, Организация.ОГРН, Организация.НаименованиеПолное,
|Организация.НаименованиеСокращенное, ЗаявленоСумма, УтвержденоСумма");
ДанныеКонтрагента = ОбщегоНазначенияМФС.СведенияОЮрФизЛице(РеквизитыЗаявки.Контрагент, РеквизитыЗаявки.Дата);
ДанныеПаспортаКонтрагента = ОбщегоНазначенияМФС.ПолучитьУдостоверениеЛичностиКонтрагента(РеквизитыЗаявки.Контрагент, РеквизитыЗаявки.Дата);
РеквизитыКонтрагента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(РеквизитыЗаявки.Контрагент, "Фамилия, Имя, Отчество, ДатаРождения");
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("ИдентификаторЗапроса", СокрЛП(ИдентификаторЗапроса));
ПараметрыЗапроса.Вставить("ИННОрганизации", РеквизитыЗаявки.ОрганизацияИНН);
ПараметрыЗапроса.Вставить("ОГРНОрганизации", РеквизитыЗаявки.ОрганизацияОГРН);
ПараметрыЗапроса.Вставить("ДатаЗапроса", ТекущаяДата() - 2 * 3600); // текущая дата минус 2 часа, потому что работа по московскому времени
ПараметрыЗапроса.Вставить("НаименованиеПолное", ВРег(РеквизитыЗаявки.ОрганизацияНаименованиеПолное));
ПараметрыЗапроса.Вставить("НаименованиеСокращенное", ВРег(РеквизитыЗаявки.ОрганизацияНаименованиеСокращенное));
ПараметрыЗапроса.Вставить("Фамилия", ДанныеКонтрагента.Фамилия);
ПараметрыЗапроса.Вставить("Имя", ДанныеКонтрагента.Имя);
ПараметрыЗапроса.Вставить("Отчество", ДанныеКонтрагента.Отчество);
ПараметрыЗапроса.Вставить("ДатаРождения", ДанныеКонтрагента.ДатаРождения);
ПараметрыЗапроса.Вставить("ПредыдущиеФИО", ПредыдущиеФИО(РеквизитыЗаявки.Контрагент, РеквизитыЗаявки.Дата));
ПараметрыЗапроса.Вставить("СерияПаспорта", СтроковыеФункцииКлиентСервер.ОставитьТолькоЦифрыВСтроке(ДанныеПаспортаКонтрагента.Серия));
ПараметрыЗапроса.Вставить("НомерПаспорта", СтроковыеФункцииКлиентСервер.ОставитьТолькоЦифрыВСтроке(ДанныеПаспортаКонтрагента.Номер));
ПараметрыЗапроса.Вставить("ДатаВыдачиПаспорта", ДанныеПаспортаКонтрагента.ДатаВыдачи);
ПараметрыЗапроса.Вставить("ПредыдущиеДУЛ", ПредыдущиеДУЛ(РеквизитыЗаявки.Контрагент, РеквизитыЗаявки.Дата));
ПараметрыЗапроса.Вставить("ДатаНачалаСогласия", РеквизитыЗаявки.Дата - 2 * 3600);
ПараметрыЗапроса.Вставить("СуммаЗайма", Формат(?(РеквизитыЗаявки.УтвержденоСумма <> 0, РеквизитыЗаявки.УтвержденоСумма, РеквизитыЗаявки.ЗаявленоСумма), "ЧДЦ=0; ЧРД=,; ЧГ=0"));
ПараметрыПодсистемы = ПроверкаКлиентов.ПолучитьЗначенияПараметровСпособаПроверки(Справочники.СпособыПроверкиКлиентов.НайтиПоНаименованию("Запрос ССП"), РеквизитыЗаявки.Организация);
ИдентификаторОтвета = Неопределено;
СтатусОбработки = Неопределено;
//1 - ответ получен сразу, гет запрос не требуется
//2 - ответ получен, нужно получить расчет по идентификатору путем гет запроса
//3 - получена ошибка
HTTPПодключитьсяОтправитьЗапросКредитнаяИстория_RUTDF_ССП(ЗаявкаНаЗайм, ПараметрыЗапроса, ПараметрыПодсистемы, ТекстОтвета, ИдентификаторОтвета, СтатусОбработки);
Если СтатусОбработки = 1 Тогда
//Запишем сразу в историю проверок
СтруктураРезультата = ПроверкаКлиентов.ПолучитьСтруктуруЗаписиРезультатаПроверки();
СтруктураРезультата.Вставить("СпособПроверки", Справочники.СпособыПроверкиКлиентов.НайтиПоНаименованию("Запрос ССП"));
СтруктураРезультата.Вставить("Контрагент", РеквизитыЗаявки.Контрагент);
СтруктураРезультата.Вставить("Заявка", ЗаявкаНаЗайм);
СтруктураРезультата.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
СтруктураРезультата.Вставить("ТекстОтвета", ТекстОтвета);
СтруктураРезультата.Вставить("ПроверкаПодписиПройдена", Истина);
ПроверкаКлиентов.ЗаписьИсторииПроверок(СтруктураРезультата);
ИначеЕсли СтатусОбработки = 2 Тогда
СтатусОбработки = Неопределено;
ЧислоПопыток = 0;
ТекстОтвета = "";
//нужно отправить еще один запрос, чтобы получить конечный результат, не более 5 попыток
Пока СтатусОбработки <> 1 Цикл
ЧислоПопыток = ЧислоПопыток + 1;
HTTPПодключитьсяОтправитьЗапросКредитнаяИстория_RUTDF_ССП_ПоИдентификатору(ПараметрыПодсистемы, ТекстОтвета, ИдентификаторОтвета, СтатусОбработки);
Если СтатусОбработки = 1 Тогда
СтруктураРезультата = ПроверкаКлиентов.ПолучитьСтруктуруЗаписиРезультатаПроверки();
СтруктураРезультата.Вставить("СпособПроверки", Справочники.СпособыПроверкиКлиентов.НайтиПоНаименованию("Запрос ССП"));
СтруктураРезультата.Вставить("Контрагент", РеквизитыЗаявки.Контрагент);
СтруктураРезультата.Вставить("Заявка", ЗаявкаНаЗайм);
СтруктураРезультата.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
СтруктураРезультата.Вставить("ТекстОтвета", ТекстОтвета);
СтруктураРезультата.Вставить("ПроверкаПодписиПройдена", Истина);
ПроверкаКлиентов.ЗаписьИсторииПроверок(СтруктураРезультата);
Прервать;
ИначеЕсли СтатусОбработки = 2 Тогда
Пауза(1);
ИначеЕсли СтатусОбработки = 3 Тогда
ТекстОтвета = "";
Прервать;
КонецЕсли;
Если ЧислоПопыток = 5 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Результат = ПроверкаКлиентов.ПолучитьРезультатПроверки();
Возврат Результат;
КонецФункции
Функция ПредыдущиеФИО(Контрагент, ДатаСреза) Экспорт
ПредыдущиеФИО = Новый Массив;
ЗапросФИО = Новый Запрос;
ЗапросФИО.Текст = "ВЫБРАТЬ
| ФИОКонтрагентов.Период КАК Период,
| ФИОКонтрагентов.Фамилия КАК Фамилия,
| ФИОКонтрагентов.Имя КАК Имя,
| ФИОКонтрагентов.Отчество КАК Отчество,
| ФИОКонтрагентов.Контрагент КАК Контрагент
|ПОМЕСТИТЬ ВТ_ФИО
|ИЗ
| РегистрСведений.ФИОКонтрагентов КАК ФИОКонтрагентов
|ГДЕ
| ФИОКонтрагентов.Контрагент = &Контрагент
| И ФИОКонтрагентов.Период <= &ДатаСреза
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| МАКСИМУМ(ВТ_ФИО.Период) КАК Период,
| ВТ_ФИО.Контрагент КАК Контрагент
|ПОМЕСТИТЬ ВТ_АктуальныеФИО
|ИЗ
| ВТ_ФИО КАК ВТ_ФИО
|
|СГРУППИРОВАТЬ ПО
| ВТ_ФИО.Контрагент
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ФИО.Период КАК Период,
| ВТ_ФИО.Фамилия КАК Фамилия,
| ВТ_ФИО.Имя КАК Имя,
| ВТ_ФИО.Отчество КАК Отчество
|ИЗ
| ВТ_ФИО КАК ВТ_ФИО
|ГДЕ
| НЕ ВТ_ФИО.Период В
| (ВЫБРАТЬ
| ВТ_АктуальныеФИО.Период
| ИЗ
| ВТ_АктуальныеФИО КАК ВТ_АктуальныеФИО)
|
|УПОРЯДОЧИТЬ ПО
| ВТ_ФИО.Период";
ЗапросФИО.УстановитьПараметр("Контрагент", Контрагент);
ЗапросФИО.УстановитьПараметр("ДатаСреза", ДатаСреза);
РезультатФИО = ЗапросФИО.Выполнить();
ВыборкаФИО = РезультатФИО.Выбрать();
Пока ВыборкаФИО.Следующий() Цикл
СтруктураДокумент = Новый Структура();
СтруктураДокумент.Вставить("Фамилия", СокрЛП(ВыборкаФИО.Фамилия));
СтруктураДокумент.Вставить("Имя", СокрЛП(ВыборкаФИО.Имя));
СтруктураДокумент.Вставить("Отчество", СокрЛП(ВыборкаФИО.Отчество));
ПредыдущиеФИО.Добавить(СтруктураДокумент);
КонецЦикла;
Возврат ?(ПредыдущиеФИО.Количество() = 0, "", ПредыдущиеФИО);
КонецФункции
Функция ПредыдущиеДУЛ(Контрагент, ДатаСреза) Экспорт
ПредыдущиеДУЛ = Новый Массив;
ЗапросДУЛ = Новый Запрос;
ЗапросДУЛ.Текст = "ВЫБРАТЬ
| ДокументыКонтрагентов.Контрагент КАК Контрагент,
| ДокументыКонтрагентов.Период КАК Период,
| ДокументыКонтрагентов.Серия КАК Серия,
| ДокументыКонтрагентов.Номер КАК Номер,
| ДокументыКонтрагентов.ДатаВыдачи КАК ДатаВыдачи,
| ДокументыКонтрагентов.КемВыдан КАК КемВыдан,
| ДокументыКонтрагентов.КодПодразделения КАК КодПодразделения
|ПОМЕСТИТЬ ВТ_ДУЛ
|ИЗ
| РегистрСведений.ДокументыКонтрагентов КАК ДокументыКонтрагентов
|ГДЕ
| ДокументыКонтрагентов.ЯвляетсяДокументомУдостоверяющимЛичность
| И ДокументыКонтрагентов.Контрагент = &Контрагент
| И ДокументыКонтрагентов.Период <= &ДатаСреза
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ДУЛ.Контрагент КАК Контрагент,
| МАКСИМУМ(ВТ_ДУЛ.Период) КАК Период
|ПОМЕСТИТЬ ВТ_АктуальныйДУЛ
|ИЗ
| ВТ_ДУЛ КАК ВТ_ДУЛ
|
|СГРУППИРОВАТЬ ПО
| ВТ_ДУЛ.Контрагент
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ДУЛ.Контрагент КАК Контрагент,
| ВТ_ДУЛ.Период КАК Период,
| ВТ_ДУЛ.Серия КАК Серия,
| ВТ_ДУЛ.Номер КАК Номер,
| ВТ_ДУЛ.ДатаВыдачи КАК ДатаВыдачи,
| ВТ_ДУЛ.КемВыдан КАК КемВыдан,
| ВТ_ДУЛ.КодПодразделения КАК КодПодразделения
|ИЗ
| ВТ_ДУЛ КАК ВТ_ДУЛ
|ГДЕ
| НЕ ВТ_ДУЛ.Период В
| (ВЫБРАТЬ
| ВТ_АктуальныйДУЛ.Период
| ИЗ
| ВТ_АктуальныйДУЛ КАК ВТ_АктуальныйДУЛ)
|
|УПОРЯДОЧИТЬ ПО
| Период";
ЗапросДУЛ.УстановитьПараметр("Контрагент", Контрагент);
ЗапросДУЛ.УстановитьПараметр("ДатаСреза", ДатаСреза);
РезультатДУЛ = ЗапросДУЛ.Выполнить();
ВыборкаДУЛ = РезультатДУЛ.Выбрать();
Пока ВыборкаДУЛ.Следующий() Цикл
СтруктураДокумент = Новый Структура();
СтруктураДокумент.Вставить("НомерДокумента", СокрЛП(ВыборкаДУЛ.Номер));
СтруктураДокумент.Вставить("СерияДокумента", СокрЛП(ВыборкаДУЛ.Серия));
СтруктураДокумент.Вставить("КемВыданДокумент", СокрЛП(ВыборкаДУЛ.КемВыдан));
СтруктураДокумент.Вставить("КодПодразделения", СокрЛП(ВыборкаДУЛ.КодПодразделения));
СтруктураДокумент.Вставить("ДатаВыдачиДокумента", ВыборкаДУЛ.ДатаВыдачи);
ПредыдущиеДУЛ.Добавить(СтруктураДокумент);
КонецЦикла;
Возврат ?(ПредыдущиеДУЛ.Количество() = 0, "", ПредыдущиеДУЛ);
КонецФункции
Процедура HTTPПодключитьсяОтправитьЗапросКредитнаяИстория_RUTDF_ССП(ПараметрыЗапроса, ПараметрыПодсистемы, ТекстОтвета, ИдентификаторОтвета, СтатусОбработки)
ИмяПользователя = СокрЛП(ПараметрыПодсистемы.ИмяПользователя);
Пароль = СокрЛП(ПараметрыПодсистемы.Пароль);
URL = СокрЛП(ПараметрыПодсистемы.АдресПодключения) + "/dlrequest";
URL = СтрЗаменить(URL, "https://", "");
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
ПервыйСлеш = СтрНайти(URL, "/");
Хост = Лев(URL, ПервыйСлеш - 1);
АдресРесурса = Сред(URL, ПервыйСлеш);
Если ПараметрыПодсистемы.Свойство("Таймаут") Тогда
Таймаут = ПараметрыПодсистемы.Таймаут;
Иначе
Таймаут = 3;
КонецЕсли;
Если ПараметрыПодсистемы.Свойство("Прокси_Сервер") Тогда
Прокси = Новый ИнтернетПрокси;
Прокси.Установить("https", ПараметрыПодсистемы.Прокси_Сервер, ПараметрыПодсистемы.Прокси_Порт, ПараметрыПодсистемы.Прокси_Пользователь, ПараметрыПодсистемы.Прокси_Пароль);
СоединениеHTTP = Новый HTTPСоединение(Хост, Неопределено, ИмяПользователя, Пароль, Прокси, Таймаут, ЗащищенноеСоединение);
Иначе
СоединениеHTTP = Новый HTTPСоединение(Хост, Неопределено, ИмяПользователя, Пароль, Неопределено, Таймаут);
КонецЕсли;
ContentType = "";
Если ПараметрыПодсистемы.Свойство("ContentType") Тогда
ContentType = ПараметрыПодсистемы.ContentType;
КонецЕсли;
Если Не ЗначениеЗаполнено(ContentType) Тогда
ContentType = "application/octet-stream";
КонецЕсли;
КодировкаТекстаЗапроса = "";
Если ПараметрыПодсистемы.Свойство("КодировкаТекстаЗапроса") Тогда
КодировкаТекстаЗапроса = ПараметрыПодсистемы.КодировкаТекстаЗапроса;
КонецЕсли;
Если Не ЗначениеЗаполнено(КодировкаТекстаЗапроса) Тогда
КодировкаТекстаЗапроса = "UTF-8";
КонецЕсли;
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", ContentType);
Заголовки.Вставить("User-Agent", "HTTPTool/1.0");
ЗапросHTTP = Новый HTTPЗапрос(АдресРесурса, Заголовки);
ТекстЗапроса = ПолучитьТекстЗапросаКредитнаяИстория_RUTDF_ССП(ПараметрыЗапроса, ПараметрыПодсистемы);
ТекстЗапроса = "<?xml version=""1.0"" encoding=""" + КодировкаТекстаЗапроса + """?>" + Символы.ПС + ТекстЗапроса;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, Символы.ПС, "");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, Символы.Таб, "");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, Символы.НПП, "");
ТекстОбработанный = ЗаменитьНедопустимыеСимволыXML(ТекстЗапроса);
МенеджерыКриптографии = Новый Массив;
Крипто = Новый МенеджерКриптографии("Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider", "", 80);
МенеджерыКриптографии.Добавить(Крипто);
ХранилищеСертификатов = МенеджерыКриптографии[0].ПолучитьХранилищеСертификатов(, РасположениеХранилищаСертификатовКриптографии.ДанныеКомпьютера);
ОтпечатокСертификатаПодписи = НРег(СтрЗаменить(ПараметрыПодсистемы.СертификатПодписи, " ", ""));
СертификатыХранилища = ХранилищеСертификатов.ПолучитьВсе();
Для каждого Сертификат Из СертификатыХранилища Цикл
Если НРег(СтрЗаменить(Строка(Сертификат.Отпечаток), " ", "")) = ОтпечатокСертификатаПодписи Тогда
СертификатПодписи = Сертификат;
Прервать;
КонецЕсли;
КонецЦикла;
ДвоичныеДанныеДляПодписания = ПолучитьДвоичныеДанныеИзСтроки(ТекстЗапроса, КодировкаТекстаЗапроса);
Для каждого Крипто Из МенеджерыКриптографии Цикл
Крипто.ПарольДоступаКЗакрытомуКлючу = ПараметрыПодсистемы.СертификатПодписиПароль;
ОтсоединеннаяПодпись = Крипто.Подписать(ДвоичныеДанныеДляПодписания, СертификатПодписи);
Прервать;
КонецЦикла;
Отказ = Ложь;
ОписаниеОшибки = "";
ПрисоединеннаяПодпись = Присоединить(ОтсоединеннаяПодпись,ДвоичныеДанныеДляПодписания,Отказ,ОписаниеОшибки);
ЗапросHTTP.УстановитьТелоИзДвоичныхДанных(ПрисоединеннаяПодпись);
ПроверкаПодписиПройдена = Ложь;
Попытка
ФайлОтчета = ПолучитьИмяВременногоФайла(".xml");
ФайлЗашифрованный = ФайлОтчета + ".p7s";
ОтветHTTP = СоединениеHTTP.ОтправитьДляОбработки(ЗапросHTTP, ФайлЗашифрованный);
КодВозврата = Неопределено;
ПутьКCryptcp = Константы.ПутьДоCryptcp.Получить();
ПутьКCryptcp = СтрЗаменить(ПутьКCryptcp, "cryptcp.exe", "csptest.exe");
СтрокаВызова = """" + ПутьКCryptcp + """ -sfsign -verify -in """ + ФайлЗашифрованный + """ -out """ + ФайлОтчета + """";
ЗапуститьПриложение(СтрокаВызова, , Истина, КодВозврата);
Если КодВозврата = Неопределено Или КодВозврата > 0 Тогда
ТекстОтвета = НСтр("ru = '%1. Не удалось проверить подпись ответа. Код ошибки: %2.'");
ТекстОтвета = СтрШаблон(ТекстОтвета, "Запрос ССП из НБКИ в режиме одного окна", КодВозврата);
СтатусОбработки = 3;
Иначе
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ФайлОтчета, КодировкаТекстаЗапроса);
ТекстОтвета = ТекстДок.ПолучитьТекст();
ПроверкаПодписиПройдена = Истина;
Если ОтветHTTP.КодСостояния = 200 Тогда //200 – результат запроса содержит сведения о среднемесячных платежах Субъекта;
СтатусОбработки = 1;
ИначеЕсли ОтветHTTP.КодСостояния = 202 Тогда //202 – результат запроса содержит квитанцию с идентификатором ответа;
СтатусОбработки = 2;
ИдентификаторОтвета = Сред(ТекстОтвета, СтрНайти(ТекстОтвета, "<ИдентификаторОтвета") + 81, СтрНайти(ТекстОтвета, "</ИдентификаторОтвета") - СтрНайти(ТекстОтвета, "<ИдентификаторОтвета") - 81);
Иначе
СтатусОбработки = 3;
КонецЕсли;
КонецЕсли;
УдалитьФайлы(ФайлЗашифрованный);
УдалитьФайлы(ФайлОтчета);
Исключение
ТекстСообщения = НСтр("ru = '%1. Не удалось отправить отчет, попробуйте еще раз. %2.'");
ТекстСообщения = СтрШаблон(ТекстСообщения, "Запрос ССП из НБКИ в режиме одного окна", ИнформацияОбОшибке().Описание);
Ош = ОписаниеОшибки();
СтатусОбработки = 3;
ТекстОтвета = ТекстСообщения;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Ош);
КонецПопытки;
КонецПроцедуры
Функция ПолучитьТекстЗапросаКредитнаяИстория_ССП(ПараметрыЗапросов, ПараметрыПодсистемы)
Перем Макет, ШаблонЗапроса;
Макет = Обработки.ПроверкаКлиента.ПолучитьМакет("Шаблон_НБКИ_ЗапросСведенийОПлатежах");
ШаблонЗапроса = Макет.ПолучитьТекст();
ТекстЗапроса = ШаблонЗапроса;
Для каждого Параметр Из ПараметрыЗапросов Цикл
ЗначениеПараметра = Параметр.Значение;
Если Параметр.Ключ = "ПредыдущиеДУЛ" Тогда
Если ЗначениеЗаполнено(ЗначениеПараметра) Тогда
БлокДУЛШаблон = "<ДокументЛичности КодДУЛ=""21"">" +
"<OKSM>643</OKSM>" +
"<Серия>[СерияПаспорта]</Серия>" +
"<Номер>[НомерПаспорта]</Номер>" +
"<ДатаВыдачи>[ДатаВыдачиПаспорта]</ДатаВыдачи>" +
"<Гражданство>643</Гражданство>" +
"</ДокументЛичности>";
БлокПредыдущихДУЛ = "";
Для Каждого ДУЛ Из ЗначениеПараметра Цикл
БлокДУЛ = БлокДУЛШаблон;
БлокДУЛ = СтрЗаменить(БлокДУЛ, "[НомерПаспорта]", ДУЛ.НомерДокумента);
БлокДУЛ = СтрЗаменить(БлокДУЛ, "[СерияПаспорта]", СтрЗаменить(ДУЛ.СерияДокумента, " ", ""));
БлокДУЛ = СтрЗаменить(БлокДУЛ, "[ДатаВыдачиПаспорта]", Формат(ДУЛ.ДатаВыдачиДокумента, "ДФ=yyyy-MM-dd"));
БлокПредыдущихДУЛ = БлокПредыдущихДУЛ + БлокДУЛ;
КонецЦикла;
ЗначениеПараметра = БлокПредыдущихДУЛ;
Иначе
ЗначениеПараметра = "";
КонецЕсли;
КонецЕсли;
Если Параметр.Ключ = "ПредыдущиеФИО" Тогда
Если ЗначениеЗаполнено(ЗначениеПараметра) Тогда
БлокФИОШаблон = "<ФИО>" +
"<Фамилия>[Фамилия]</Фамилия>" +
"<Имя>[Имя]</Имя>" +
"<Отчество>[Отчество]</Отчество>" +
"</ФИО>";
БлокПредыдущихФИО = "";
Для Каждого ФИО Из ЗначениеПараметра Цикл
БлокФИО = БлокФИОШаблон;
БлокФИО = СтрЗаменить(БлокФИО, "[Фамилия]", ФИО.Фамилия);
БлокФИО = СтрЗаменить(БлокФИО, "[Имя]", ФИО.Имя);
БлокФИО = СтрЗаменить(БлокФИО, "[Отчество]", ФИО.Отчество);
БлокПредыдущихФИО = БлокПредыдущихФИО + БлокФИО;
КонецЦикла;
ЗначениеПараметра = БлокПредыдущихФИО;
Иначе
ЗначениеПараметра = "";
КонецЕсли;
КонецЕсли;
Если ТипЗнч(ЗначениеПараметра) = Тип("Дата") Тогда
ЗначениеПараметра = Формат(ЗначениеПараметра, "ДФ=yyyy-MM-dd");
КонецЕсли;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[" + Параметр.Ключ + "]", ЗначениеПараметра);
КонецЦикла;
Возврат ТекстЗапроса;
КонецФункции
Данная процедура вернет результат обработки, подписанный сертификатом. Необходимо снять эту подпись, чтобы затем сохранить результат в файл.
Применяется бесплатная утилита csptest.exe, входящая в комплект установки Крипто Про.
На первом этапе будет либо сразу получен результат, либо вернется идентификатор запроса, по которому GET-запросом необходимо получить конечный результат:
Процедура HTTPПодключитьсяОтправитьЗапросКредитнаяИстория_ССП_ПоИдентификатору(ПараметрыПодсистемы, ТекстОтвета, ИдентификаторОтвета, СтатусОбработки)
ИмяПользователя = СокрЛП(ПараметрыПодсистемы.ИмяПользователя);
Пароль = СокрЛП(ПараметрыПодсистемы.Пароль);
URL = СокрЛП(ПараметрыПодсистемы.АдресПодключения) + "/dlanswer";
URL = СтрЗаменить(URL, "https://", "");
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
ПервыйСлеш = СтрНайти(URL, "/");
Хост = Лев(URL, ПервыйСлеш - 1);
АдресРесурса = Сред(URL, ПервыйСлеш);
Если ПараметрыПодсистемы.Свойство("Таймаут") Тогда
Таймаут = ПараметрыПодсистемы.Таймаут;
Иначе
Таймаут = 3;
КонецЕсли;
Если ПараметрыПодсистемы.Свойство("Прокси_Сервер") Тогда
Прокси = Новый ИнтернетПрокси;
Прокси.Установить("https", ПараметрыПодсистемы.Прокси_Сервер, ПараметрыПодсистемы.Прокси_Порт, ПараметрыПодсистемы.Прокси_Пользователь, ПараметрыПодсистемы.Прокси_Пароль);
СоединениеHTTP = Новый HTTPСоединение(Хост, Неопределено, ИмяПользователя, Пароль, Прокси, Таймаут, ЗащищенноеСоединение);
Иначе
СоединениеHTTP = Новый HTTPСоединение(Хост, Неопределено, ИмяПользователя, Пароль, Неопределено, Таймаут);
КонецЕсли;
ContentType = "";
Если ПараметрыПодсистемы.Свойство("ContentType") Тогда
ContentType = ПараметрыПодсистемы.ContentType;
КонецЕсли;
Если Не ЗначениеЗаполнено(ContentType) Тогда
ContentType = "application/octet-stream";
КонецЕсли;
КодировкаТекстаЗапроса = "";
Если ПараметрыПодсистемы.Свойство("КодировкаТекстаЗапроса") Тогда
КодировкаТекстаЗапроса = ПараметрыПодсистемы.КодировкаТекстаЗапроса;
КонецЕсли;
Если Не ЗначениеЗаполнено(КодировкаТекстаЗапроса) Тогда
КодировкаТекстаЗапроса = "UTF-8";
КонецЕсли;
Заголовки = Новый Соответствие;
ЗапросHTTP = Новый HTTPЗапрос(АдресРесурса + "?id=" + ИдентификаторОтвета, Заголовки);
ПроверкаПодписиПройдена = Ложь;
Попытка
ФайлОтчета = ПолучитьИмяВременногоФайла(".xml");
ФайлЗашифрованный = ФайлОтчета + ".p7s";
ОтветHTTP = СоединениеHTTP.Получить(ЗапросHTTP, ФайлЗашифрованный);
КодВозврата = Неопределено;
ПутьКCryptcp = Константы.ПутьДоCryptcp.Получить();
ПутьКCryptcp = СтрЗаменить(ПутьКCryptcp, "cryptcp.exe", "csptest.exe");
СтрокаВызова = """" + ПутьКCryptcp + """ -sfsign -verify -in """ + ФайлЗашифрованный + """ -out """ + ФайлОтчета + """";
ЗапуститьПриложение(СтрокаВызова, , Истина, КодВозврата);
Если КодВозврата = Неопределено Или КодВозврата > 0 Тогда
ТекстОтвета = НСтр("ru = '%1. Не удалось проверить подпись ответа. Код ошибки: %2.'");
ТекстОтвета = СтрШаблон(ТекстОтвета, "Запрос ССП из НБКИ в режиме одного окна", КодВозврата);
СтатусОбработки = 3;
Иначе
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ФайлОтчета, КодировкаТекстаЗапроса);
ТекстОтвета = ТекстДок.ПолучитьТекст();
ПроверкаПодписиПройдена = Истина;
Если ОтветHTTP.КодСостояния = 200 Тогда //результат запроса содержит сведения о среднемесячных платежах Субъекта;
СтатусОбработки = 1;
ИначеЕсли ОтветHTTP.КодСостояния = 202 Тогда //результат запроса содержит квитанцию с информацией об ошибке «Ответ не готов»;
СтатусОбработки = 2;
Иначе
СтатусОбработки = 3;
КонецЕсли;
КонецЕсли;
УдалитьФайлы(ФайлЗашифрованный);
УдалитьФайлы(ФайлОтчета);
Исключение
ТекстСообщения = НСтр("ru = '%1. Не удалось отправить отчет, попробуйте еще раз. %2.'");
ТекстСообщения = СтрШаблон(ТекстСообщения, "Запрос ССП из НБКИ в режиме одного окна", ИнформацияОбОшибке().Описание);
Ош = ОписаниеОшибки();
СтатусОбработки = 3;
ТекстОтвета = ТекстСообщения;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Ош);
КонецПопытки;
КонецПроцедуры
Конечный результат получаете в формате XML, который содержит данные о всех среднемесячных платежах контрагента во всех БКИ. Структура его довольно простая, по ссылке на API ЦБ есть примеры с текстом запроса и ответа.
Свои вопросы можете писать в комментариях к этой статье, надеюсь, она поможет вам сэкономить время. Ведь НБКИ в скором времени перестанет предоставлять даже кредитные отчеты своим клиентам, если не шифровать соединение сертификатом при запросе и не пользоваться двусторонней аутентификацией (то есть, требуют подписывать текст запроса и снимать подпись с ответа, проверяя подпись).