Получение суммы среднемесячных платежей в режиме "Одного окна" для расчета показателя долговой нагрузки

17.05.24

Интеграция - WEB-интеграция

C 1 июля 2024 г. для расчета ПДН (Показателя долговой нагрузки) в целях расчета суммы величин ССП (суммы среднемесячных платежей) к использованию возможен только подход, установленный пунктом 2.3 Указания № 6579-У ЦБ РФ, а именно - необходимо получать данные из всех четырех КБКИ, а не только из одного.

В данной статье представлен код, который позволяет получать данные ССП для расчета ПДН в режиме "одного окна" из любого БКИ (НБКИ, ОКБ, Эквифакс и прочие).

На этом этапе у вас уже должен быть заключен договор с БКИ, на руках имеется сертификат, полученный от ЦБ, и вы зарегистрировали его в БКИ для отправки запросов и шифрования соединения (согласно требованиям ЦБ - все запросы должны осуществляться по защищенному соединению + запрос должен быть подписан присоединенной ЭП).

Все запросы в случае НБКИ необходимо направлять по адресу 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 ЦБ есть примеры с текстом запроса и ответа.

Свои вопросы можете писать в комментариях к этой статье, надеюсь, она поможет вам сэкономить время. Ведь НБКИ в скором времени перестанет предоставлять даже кредитные отчеты своим клиентам, если не шифровать соединение сертификатом при запросе и не пользоваться двусторонней аутентификацией (то есть, требуют подписывать текст запроса и снимать подпись с ответа, проверяя подпись).

ЦБ ССП ПДН Показатель долговой нагрузки 6579-У сумма среднемесячных платежей Банк России СМП НБКИ Национальное бюро кредитных историй КБКИ БКИ Одно окно

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    16295    14    18    

14

Интеграция 1С и Битрикс 24 — модуль синхронизации для обмена задачами

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс 24. Разработка имеет двухстороннюю синхронизацию 1С и Bitrix24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (платформа начиная с 8.3.23). При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

5040 руб.

04.05.2021    18510    10    15    

16

Модуль для обмена "1С:Предприятие 8. УАТ. ПРОФ" с FortMonitor

WEB-интеграция 8.3.8 Конфигурации 1cv8 Автомобили, автосервисы Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

Расширение предназначено для конфигурации "1С:Предприятие 8. Управление Автотранспортом. ПРОФ". Функционал модуля: 1. Заполнение регистров сведений по подсистеме "Мониторинг", а именно: события по мониторингу, координаты по мониторингу, пробег и расход по мониторингу, текущее местоположение ТС по мониторингу 2. Заполнение путевого листа: пробег по мониторингу, время выезда/заезда, табличная часть ГСМ, места стоянок по геозонам. 3. Отчеты по данным загруженным в регистры сведений. 4. Предусмотрена автоматическая загрузка данных в фоновом режиме (условия работы данной загрузке читайте в описании товара) Модуль работает без включенной константы по настройкам мониторинга. Модуль формы предоставляется с открытым кодом, общий модуль защищен. Любой заинтересованный пользователь, имеет возможность скачать демо-версию расширения.

22656 руб.

25.05.2021    13127    34    8    

13

Автоматическая загрузка файлов (например, прайс-листов) из электронной почты, FTP, HTTP, их обработка и выгрузка на FTP (на сайт) и для других целей

Прайсы WEB-интеграция Ценообразование, анализ цен Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Автомобили, автосервисы Оптовая торговля, дистрибуция, логистика Управленческий учет Платные (руб)

Программа с заданным интервалом времени (или по ручной команде) скачивает файлы (например, прайс-листы поставщиков) из различных источников: письма электронной почты, FTP или HTTP-адреса, и сохраняет их в каталог упорядоченной структуры. При этом извлекает файлы из архивов, может переименовывать файлы и менять их формат (csv, xls, txt). Можно настроить выгрузку обработанных файлов на сайт (через FTP-подключение). Программа будет полезна компаниям, у которых есть большое количество поставщиков и/или прайс-листы поставщиков обновляются часто (необязательно прайс-листы, файлы могут быть любого назначения). Собранные таким образом актуальные версии прайс-листов можно выгрузить с помощью программы себе на сайт (или на любой FTP-сервер) или выполнить другие необходимые задачи.

25200 руб.

28.05.2015    85867    26    51    

50
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. user1666028 31.05.24 09:07 Сейчас в теме
Спасибо вам за статью и приложенное решение! Как раз сейчас работаю над такой задачей.
Подскажите пожалуйста, не сталкивались ли вы со следующим моментом:

Я пытаюсь настроить stunnel для подключение к reports.nbki.ru. но при попытке подключения на этапе handshake возникает обрыв соединения.


Лог Stunnel:
2024.05.31 12:59:53 LOG5[19296:45532]: 1460 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 1460 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 2636 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 1460 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 7300 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 1460 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 1460 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 1460 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG5[19296:45532]: 349 bytes of handshake(in handshake loop) data received.
2024.05.31 12:59:53 LOG3[19296:45532]: **** Server unexpectedly disconnected
2024.05.31 12:59:53 LOG3[19296:45532]: Error performing handshake
Оставьте свое сообщение