Согласно документации, находящейся по ссылке:
https://честныйзнак.рф/business/projects/retail/checkout/regulations/ описал методику работы. Учел временные блокировки серверов (по умолчанию на 15 мин.), то, что запросы доступных площадок нужно делать раз в шесть часов, то, что может быть аварийный режим в самом ЦРПТ,...... , все эти ситуации работают в автоматическом режиме:
//******************************************************************************
Процедура глУстановитьАварийнуюБлокировкуСервераОнлайнПроверкиЦРПТ(ПроверитьБлокировку=0,КолДнейБлокировки=0) Экспорт //Позволяется устанавливать блокировку! По умолчанию устанавливаем блокировку на сутки.
Если ПроверитьБлокировку=1 Тогда
Если ТекущаяДата()>Константа.ДатаВременнойБлокировкиОнлайнПроверокМарокЧерезЦРПТ Тогда
Константа.АварийнаяБлокировкаОнлайнПроверокМарокЧерезЦРПТ = 0;
Константа.ДатаВременнойБлокировкиОнлайнПроверокМарокЧерезЦРПТ = "";
КонецЕсли;
Иначе
Если КолДнейБлокировки<=0 Тогда
КолДнейБлокировки = 1;
КонецЕсли;
................. и т.д.
//******************************************************************************
Процедура глУстановитьБлокировкуСервераОнлайнПроверкиЦРПТ(АдресПлощадки,ВремяБлокировкиЦРПТ=0) Экспорт
Если ВремяБлокировкиЦРПТ<=0 Тогда
ВремяБлокировкиЦРПТ = 15; //По умолчанию блокируем на 15 мин.
КонецЕсли;
ТекДатаБлокировки = ТекущаяДата();
ТекЧасПроверки = 0;
ТекМинПроверки = 0;
ТекущееВремя(ТекЧасПроверки,ТекМинПроверки);
ТекМинБлокировки = ТекЧасПроверки*60+ТекМинПроверки+ВремяБлокировкиЦРПТ;
КолДнейПлюсом = Цел(ТекМинБлокировки/1440);
Если КолДнейПлюсом>0 Тогда
ТекДатаБлокировки = ТекДатаБлокировки+КолДнейПлюсом;
ТекМинБлокировки = ТекМинБлокировки-КолДнейПлюсом*1440;
КонецЕсли;
................. и т.д.
//******************************************************************************
Функция ВернутьТекущийСерверОнлайнПроверкиЦРПТ(ТекДатаПроверки,ТекЧасПроверки,ТекМинПроверки) Экспорт
глКоличествоДоступныхСерверовОнлайнПроверкиЦРПТ = 0;
ВыбТекСервЦРПТ = "";
СпрСервераДляОнлайнПроверкиВЦРПТ = СоздатьОбъект("Справочник.СервераДляОнлайнПроверкиВЦРПТ");
СпрСервераДляОнлайнПроверкиВЦРПТ.ПорядокРеквизита("Приоритет");
СпрСервераДляОнлайнПроверкиВЦРПТ.ВыбратьЭлементы();
Пока СпрСервераДляОнлайнПроверкиВЦРПТ.ПолучитьЭлемент() = 1 Цикл
Если ТекДатаПроверки=СпрСервераДляОнлайнПроверкиВЦРПТ.ДатаПровеки Тогда
Если (ТекЧасПроверки-СпрСервераДляОнлайнПроверкиВЦРПТ.ЧасПроверки)<6 Тогда //Проверка серверов еще не требуется
врЕстьБлокировкаЦРПТ =0;
Если ПустоеЗначение(СпрСервераДляОнлайнПроверкиВЦРПТ.ДатаБлокировкиДо)=0 Тогда //Проверяем, а не заблокирован ли временно сервер!
Если (ТекДатаПроверки<СпрСервераДляОнлайнПроверкиВЦРПТ.ДатаБлокировкиДо) Тогда
врЕстьБлокировкаЦРПТ =1;
ИначеЕсли (ТекДатаПроверки=СпрСервераДляОнлайнПроверкиВЦРПТ.ДатаБлокировкиДо) и ((ТекЧасПроверки*60+ТекМинПроверки)<СпрСервераДляОнлайнПроверкиВЦРПТ.ВремяБлокировкиДо) Тогда
................. и т.д.
Функция глОбновитьДанныеПлощадокCDN(ПринудительноОбновить=0,ВывестиСообщение=0) Экспорт
Рез = СоздатьОбъект("СписокЗначений");
Рез.Установить("ТекстОшибки","");
Рез.Установить("КодОтвета",0);
ТекЧасПроверки = 0;
ТекМинПроверки = 0;
ТекущееВремя(ТекЧасПроверки,ТекМинПроверки);
ТекДатаПроверки = ТекущаяДата();
Если ПринудительноОбновить=0 Тогда
глТекущийСерверОнлайнПроверкиЦРПТ = ВернутьТекущийСерверОнлайнПроверкиЦРПТ(ТекДатаПроверки,ТекЧасПроверки,ТекМинПроверки);
Если ПустоеЗначение(глТекущийСерверОнлайнПроверкиЦРПТ)=0 Тогда
Возврат Рез;
КонецЕсли;
КонецЕсли;
РезЗапроса = глЗапроситьДанныеПлощадокCDN(ВывестиСообщение);
ТекстОшибки = СокрЛП(РезЗапроса.Получить("ТекстОшибки"));
КодОтвета = РезЗапроса.Получить("КодОтвета");
Рез.Установить("КодОтвета",КодОтвета);
Рез.Установить("ТекстОшибки",ТекстОшибки);
Если КодОтвета=203 Тогда //Включена Аварийная ситуация!
Если ВывестиСообщение=1 Тогда
Сообщить("Текст ошибки: Включена аварийная ситуация в ЦРПТ! Код ошибки: 203");
КонецЕсли;
Возврат Рез;
ИначеЕсли (КодОтвета=401) или (ПустоеЗначение(КодОтвета)=1) Тогда
Возврат Рез;
КонецЕсли;
ЕстьОшибки = 0;
Если ПустоеЗначение(ТекстОшибки)=1 Тогда //Ошибок нет
ВыбраннаяПлощадка = РезЗапроса.Получить("ВыбраннаяПлощадка");
Если ВыбраннаяПлощадка<>"" Тогда
глТекущийСерверОнлайнПроверкиЦРПТ = ВыбраннаяПлощадка;
Иначе
ЕстьОшибки = 1;
Если ВывестиСообщение=1 Тогда
Сообщить("Текст ошибки: Не определен оптимальный сервер в ЦРПТ!");
КонецЕсли;
КонецЕсли;
...................... и т.д.
Функция ВыполнитьОнлайнПроверкуЦРПТ(ТекНом,текКМ,РезОнлайнПроверкиЦРПТ,ТекНомерФН="",ПовторЗапроса=0)
Рез = 1;
Если (Константа.ОнлайнПроверкаМарокЧерезЦРПТ=1) и (Константа.АварийнаяБлокировкаОнлайнПроверокМарокЧерезЦРПТ<>1) Тогда
//Если ПроверитьТипМаркируемойПродукцииДляОнлайнПроверкиВЦРПТ(ТекНом)=1 Тогда //Здесь проверяем, а нужно ли вообще делать проверку данного типа продукции
Токен = СокрЛП(Константа.ТокенДляОнлайнПроверкиВЦРПТ);
Если ПустоеЗначение(Токен)=1 Тогда
ОписаниеРезультата = "Ошибка! Не заполнен Токен в Константах для онлайн проверки ЦРПТ!";
Рез = 0;
Иначе
КодОтвета = 0;
ТекстОшибки = "";
Если ПустоеЗначение(глТекущийСерверОнлайнПроверкиЦРПТ)=1 Тогда
РезПроверки = глОбновитьДанныеПлощадокCDN();
КодОтвета = РезПроверки.Получить("КодОтвета");
ТекстОшибки = РезПроверки.Получить("ТекстОшибки");
КонецЕсли;
Если КодОтвета=203 Тогда
//Включили аварийный режим!
ИначеЕсли КодОтвета=401 Тогда
ОписаниеРезультата = ТекстОшибки;
Рез = 0;
ИначеЕсли ПустоеЗначение(глТекущийСерверОнлайнПроверкиЦРПТ)=1 Тогда
ОписаниеРезультата = "Ошибка! Нет доступных серверов для онлайн проверки в ЦРПТ!";
Рез = 0;
Иначе
РезПроверки = глВыполнитьОнлайнКонтрольМаркиЧестныйЗнак(СокрЛП(текКМ),ТекНомерФН);
ТекстОшибки = РезПроверки.Получить("ТекстОшибки");
Если ПустоеЗначение(ТекстОшибки)=0 Тогда
Рез = 0;
КодОтвета = РезПроверки.Получить("КодОтвета");
ОписаниеРезультата = ТекстОшибки;
Если ПустоеЗначение(КодОтвета)=1 Тогда //сервер не ответил
Если (глКоличествоДоступныхСерверовОнлайнПроверкиЦРПТ>1) и (ПовторЗапроса =0) Тогда
ПовторЗапроса = 1;
глУстановитьБлокировкуСервераОнлайнПроверкиЦРПТ(глТекущийСерверОнлайнПроверкиЦРПТ,15);
глОбновитьДанныеПлощадокCDN();
Рез =ВыполнитьОнлайнПроверкуЦРПТ(ТекНом,текКМ,РезОнлайнПроверкиЦРПТ,ТекНомерФН,ПовторЗапроса); //Повторная проверка
Если Рез=1 Тогда
ОписаниеРезультата = "";
КонецЕсли;
КонецЕсли;
ИначеЕсли (КодОтвета=203) или (КодОтвета=429) или (КодОтвета>=500) Тогда
ЗаписатьЛогОшибкиОнлайнПроверкиЦРПТ(ТекНом,текКМ,ТекстОшибки,КодОтвета);
Если (КодОтвета=203) или ((КодОтвета=5000) и (ПовторЗапроса=1)) Тогда //203 - Включена Аварийная ситуация! 5000 - просто можно пробивать далее без проверки!
Если (КодОтвета=203) Тогда
глУстановитьАварийнуюБлокировкуСервераОнлайнПроверкиЦРПТ();
КонецЕсли;
Рез = 1;
ОписаниеРезультата = "";
Иначе
Если ПовторЗапроса = 0 Тогда
ПовторЗапроса = 1;
Иначе
ПовторЗапроса = 0;
глУстановитьБлокировкуСервераОнлайнПроверкиЦРПТ(глТекущийСерверОнлайнПроверкиЦРПТ,15);
глОбновитьДанныеПлощадокCDN();
................. и т.д.
Сделал три варианта отправки API запросов (марки экранируются, проблем с двойными кавычками внутри я не увидел - проходят корректно):
1) WinHttp.WinHttpRequest.5.1 - за описание этого метода, огромное спасибо: Кириллу Логинову
(kirlog). Но этот метод работает только на свежих операционках Windows. Два способа ниже работают и на старых операционках;
HTTPЗапрос = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
HTTPЗапрос.Option(2,"utf-8");
HTTPЗапрос.SetTimeouts(1500, 1500, 1500, 1500);
HTTPЗапрос.Open("POST",АдресРесурса,1);
HTTPЗапрос.SetRequestHeader("X-API-KEY", СокрЛП(Токен));
HTTPЗапрос.SetRequestHeader("Accept-Charset", "utf-8");
HTTPЗапрос.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
...................... и т.д.
2) Curl1С.dll - через внешнюю компоненту, визуально, по ощущениям, скорость работы аналогична первому варианту. Проблем с запросами я не увидел.
глКарлик.УстановитьПараметр("URL",АдресРесурса);
глКарлик.УстановитьПараметр("TIMEOUT",ТаймаутОжидания);
глКарлик.УстановитьПараметр("HTTPHEADER","Content-Type: application/json;charset=utf-8");
глКарлик.УстановитьПараметр("HTTPHEADER","Accept-Charset: utf-8");
глКарлик.УстановитьПараметр("HTTPHEADER","X-API-KEY: "+СокрЛП(Токен));
глКарлик.УстановитьПараметр("CUSTOMREQUEST","POST");
...................... и т.д.
3) Curl.exe - бросаемся командами на экзешник. Визуально работает чуть медленней двух предыдущих вариантов, т.к. все делаем через файлы (запись, удаление). Но, несмотря на чуть медленную работу, для меня этот вариант весьма рабочий, т.к. еще несколько лет назад сделал работу с ЕГАИСом по аналогичной схеме и до сих пор работает все замечательно.
КомандаСистемыСкрипт( КаталогИБ()+"curl.exe -d ""@"+ПутьКТелуЗапроса+""" -s -w \nRespCode:%{response_code} -H ""X-API-KEY: "+СокрЛП(Токен)+..................................... и т.д.
В архиве находятся все необходимые файлы, включая MD, в котором реализовано описанное выше. Код полностью открыт.
Тестировалось все на платформе: 7.70.027. Конфигурация: любая!!!
Данный механизм можно взять как готовую основу для внедрения в свою программу. Логика работы с ЦРПТ реализована (согласно документации), думаю, почти вся. Как минимум можно сэкономить немало времени на внедрении.
Обновление: 14.04.2024 - Архив с данными 002.zip
Улучшен механизм обработки результата ответа от ЦРПТ.
Устранены выявленные ошибки.
Обновление: 15.08.2024 - Архив с данными 003.zip
Устранены выявленные ошибки.
Обновление: 29.08.2024 - Архив с данными 004.zip
Устранена ошибка связанная с внешней компонентой Curl1C.dll - плодились заголовки в запросах, в следствии чего, начинали приходить отрицательные ответы в запросах.