Руководство прикладного разработчика#

Назначение документа#

В настоящем документе представлено руководство прикладного разработчика компонента Фасад НСИ (NSIC) продукта Platform V Dictionaries (SDT).

Обозначения, сокращения, термины и определения приведены в документе Термины и определения.

Системные требования#

С основными системными требованиями можно ознакомиться в документе Руководство по установке.

Подключение и конфигурирование#

Для подключения и конфигурирования необходимо выполнить следующие настройки:

  1. Внедрение значений параметров клиента осуществляется с помощью аннотации @Value. Задача разработчика — обеспечить инициализацию значения параметров клиента любым из доступных способов в Spring Framework. Например, это может быть файл application.properties. Для конфигурации клиента доступны следующие параметры:

      # Протокол передачи данных HTTP/HTTPS
      nsi.cloud.server.protocol=HTTP
      # Имя хоста, на котором предоставляется API
      nsi.cloud.server.host=nsi-ift.no-ingress.apps.dev-gen.maindomain.mycompany.ru
      # Порт
      nsi.cloud.server.port=80
      # Timeout подключения, мс
      nsi.cloud.server.connectTimeout=5000
      # Timeout обмена данными, мс
      nsi.cloud.server.readTimeout=5000

В целевом варианте вызовы проходят через ingress NSIC, в результате чего необходимо:

  • указать протокол HTTP;

  • указать порт 80;

  • настроить шифрование на egress.

  1. Импорт класса конфигурации Spring в проект:

      @Configuration
      @Import(sbp.com.sbt.nsi.cloud.client.config.WebClientConfiguration.class)
      public class MyConfig {
      }

Миграция на текущую версию#

В четвертом поколении NSIC реализована обратная совместимость.

Миграция на текущую версию представляет собой ее подключение в соответствии с разделом Подключение и конфигурирование настоящего документа.

Быстрый старт#

Требуемые навыки для работы с NSIC#

Основными требуемыми навыками являются:

  • Опыт промышленной разработки с использованием Java.

  • Опыт разработки Spring-boot приложений для различных сред контейнеризации (DropApp, Kubernetes, OpenShift).

  • Знание SQL и опыт работы с PostgreSQL (Platform V Pangolin SE).

  • Опыт работы с технологиями: Spring MVC/IoC/Tx, Hibernate, Junit, Liquibase.

Типы задач разработчика#

Типовыми задачами проектов NSIC являются:

  • разработка специализированного API для получения данных справочников общего назначения;

  • разработка специализированного API для получения данных справочников продуктового каталога;

  • расширение функциональности библиотеки «кеширующий клиент».

Модули проекта#

В проекте используются следующие модули:

  • nsi-cloud-api — содержит API, DTO, доступные внешним потребителям. Новые API следует размещать в этом модуле.

  • nsi-cloud-bom — pom-файл с версиями артефактов.

  • nsi-cloud-client — реализация SPI (клиентской библиотеки).

  • nsi-cloud-facade — реализация cloud-native приложения (backend).

  • nsi-cloud-testrunner — cloud-native приложение для запуска тестов.

Вызов API через Java-клиент#

Зависимости для подключения#

API:

<dependency>
  <groupId>sbp.com.sbt.nsi.cloud</groupId>
  <artifactId>nsi-cloud-api</artifactId>
  <version>{nsi-cloud-version}</version>
</dependency>

Артефакт не содержит зависимость на классы модели ЕКПиТ (ekpit-model). Необходимо добавить зависимость на ЕКПиТ модель (ekpit-model):

<dependency>
  <groupId>sbp.com.sbt.cdm.ora</groupId>
  <artifactId>ekpit-model</artifactId>
  <version>{ekpit-model-version}</version>
</dependency>

Примечание

Примечание:
Актуальную версию для параметров {nsi-cloud-version} и {ekpit-model-version} необходимо уточнять у специалистов сопровождения.

Клиентская библиотека:

<dependency>
      <groupId>sbp.com.sbt.nsi.cloud</groupId>
      <artifactId>nsi-cloud-client</artifactId>
      <version>{nsi-cloud-version}</version>
</dependency>

Примечание

Примечание:
Актуальную версию для параметра {nsi-cloud-version} необходимо уточнять у специалистов сопровождения.

Описание параметров клиента#

Внедрение значений параметров клиента, осуществляется с помощью аннотации @Value. Задача разработчика - обеспечить инициализацию значения параметров клиента любым из доступных способов в Spring Framework. Например, это может быть файл application.properties. Для конфигурации клиента доступны следующие параметры:

# Протокол передачи данных HTTP/HTTPS
nsi.cloud.server.protocol=HTTP
# Имя хоста, на котором предоставляется API
nsi.cloud.server.host={NSI_HOST} 
# Порт
nsi.cloud.server.port=80
# Тайм-аут подключения, мс
nsi.cloud.server.connectTimeout=5000
# Тайм-аут обмена данными, мс
nsi.cloud.server.readTimeout=5000

Примечание

Примечание:
Актуальное значение для параметра {NSI_HOST} необходимо уточнять у специалистов сопровождения.

В целевом варианте вызовы идут через ingress NSIC, в результате чего:

  • укажите протокол HTTP;

  • укажите порт 80;

  • настройте шифрование на egress фабрики.

Создание конфигурационного класса#

Импортируйте класс конфигурации Spring в свой проект:

@Configuration
@Import(sbp.com.sbt.nsi.cloud.client.config.WebClientConfiguration.class)
public class MyConfig {
}

Поддержка использования nsi-cloud-client в JDK17#

Для корректной работы клиентской библиотеки в Java версии 11 и выше необходимо на стороне потребителя добавить параметры в JAVA_OPTS:

--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED

Использование программного компонента#

NSIC может использоваться как с помощью подключенной клиентской библиотеки (КМ), так и без нее.

Использование NSIC с помощью КМ#

Интерфейсы доступных API находятся в пакете sbp.com.sbt.nsi.cloud.api. При подключении библиотеки разворачивается HTTP-клиент, исполняющий запросы через REST либо JsonRPC (в зависимости от метода API). Результат возвращается в виде DTO либо классов модели ЕКПиТ.

Предупреждение

Важно!
Если запись в справочнике отмечена как isDeleted =true, то она не будет участвовать в процессах выборки данных.
Свойство isDeleted =false проставляется автоматически для каждого запроса, кроме методов API, обрабатывающих HQL-запросы. Для API, обрабатывающих HQL-запросы по нескольким справочникам, необходимо в WHERE или JOIN добавлять предикаты .isDeleted = false. Добавлять их необходимо для всех справочников, участвующих в запросе, кроме первого справочника в FROM.

Примеры использования API общего назначения с помощью КМ#

API общего назначения предназначены для получения требуемой информации из любого справочника.

Получение списка справочников

import com.sbt.cdm.domain.ora.ekpit.RspitVersionDictionary
import sbp.com.sbt.nsi.cloud.api.DictionaryService;

// ...

@Autowired
DictionaryService dictService;

// ...

List<RspitVersionDictionary> dicts = dictService.getDictionaryRecords(RspitVersionDictionary.class, null, 0);
dicts.stream().map(RspitVersionDictionary::getDictionaryName).forEach(log::info);

Получение записей по objectId (getRecordById)

import sbp.com.sbt.nsi.cloud.api.DictionaryService;
import sbp.com.sbt.nsi.cloud.dto.Field;
import sbp.com.sbt.nsi.cloud.dto.Fields;


import com.sbt.cdm.domain.ora.ekpit.Currency;  // класс справочника в модели ЕКПиТ

// ...

@Autowired
DictionaryService dictService;

// ...

Currency currency = dictService.getRecordById(Currency.class, "666");
log.info(currency == null ? "Такой валюты нет" : ("Код валюты: " + currency.getCode()));

Получение записей по JPQL-запросу (getRecordsByHql)

import sbp.com.sbt.nsi.cloud.api.DictionaryService;
import sbp.com.sbt.nsi.cloud.dto.Field;
import sbp.com.sbt.nsi.cloud.dto.Fields;


import com.sbt.cdm.domain.ora.ekpit.Currency;  // класс справочника в модели ЕКПиТ

// ...

@Autowired
DictionaryService dictService;

// ...

String hql = "select c.digitalCode as code, c.nameRus as name from Currency c where c.digitalCode between '800' and '899'";
List<Currency> currencies = dictService.getRecordsByHql(Currency.class, hql, 10, 0);
currencies.stream().forEach(f -> log.info("Code: {}, Name: {}", c.getCode(), c.getName()));

Получение свойств по JPQL-запросу (getFields)

import sbp.com.sbt.nsi.cloud.api.DictionaryService;
import sbp.com.sbt.nsi.cloud.dto.Field;
import sbp.com.sbt.nsi.cloud.dto.Fields;

// ...

@Autowired
DictionaryService dictService;

// ...

String hql = "select c.digitalCode as code, c.nameRus as name from Currency c where c.digitalCode between '800' and '899'";
List<Fields> fieldsList = dictService.getFieldsByHql(hql, 10, 0);
fieldsList.stream().forEach(f -> log.info("Code: {}, Name: {}", f.get("code"), f.get("name()));

В методах API общего назначения вложенные объекты (связанные записи справочников) возвращаются с единственным заполненным атрибутом: objectId.

При необходимости развернуть вложенную запись требуется запрос на DictionaryService#getRecordById.

Обработка ошибок при использовании КМ#

При невозможности вызова API по HTTP приходит ошибка springframework.web.client.RestClientException.

Ошибки, возвращаемые с сервера, перебрасываются в виде NsiApiCallException, в котором содержится описание и stacktrace серверной ошибки NsiApiError.

try {
// вызываем API фасада
} catch (RestClientException e) {
logger.error("Не удалось вызвать API фасада", e);
} catch (NsiApiCallException e) {
logger.error("API фасада вернул ошибку", e);
logger.error(e.getApiError());
}

Включение логирования HTTP-запросов#

Если КМ используется в SpringBoot с включенным Actuator, то включить логирование запросов можно в runtime. Для этого необходимо в терминале pod выполнить команду:

curl -i -X POST -H 'Content-Type: application/json' -d '{"configuredLevel": "DEBUG"}' http://localhost:8081/actuator/loggers/org.springframework.web

Поддержка кеширования#

Кеширование в клиентской библиотеке реализовано группой Guava-кешей. Ответы по запросам кешируются целиком. При обновлении любого справочника кеш сбрасывается целиком. Проверка обновлений происходит с помощью pooling со стороны клиента.

Настройка кеширования:

# Включение внутреннего кеширования (по умолчанию false)
nsi.cloud.client.cache.enabled=true
# Спецификация групп кешей
nsi.cloud.client.cache.specification=maximumWeight=20000000
# Периодичность опроса об обновлении справочников, мс (по умолчанию 60000)
nsi.cloud.client.cache.update.delay=60000

Предупреждение

Важно! Использование параметра maximumSize в качестве значения спецификации групп кешей не поддерживается.
Параметр maximumWeight задает лимит суммарного объема всех объектов, хранящихся в сервисе кеширования (CacheService), однако не накладывает ограничений на объем самого сервиса кеширования, обеспечивающего функционирование кеша. Для вычисления размера отдельного объекта используется инструмент org.ehcache.sizeof.SizeOf#deepSizeOf.

Алгоритм сброса кеша в клиенте#

В клиенте кешируются результаты выполнения всех методов API.

По установленному интервалу в параметре nsi.cloud.client.cache.update.delay выполняется алгоритм поиска обновлений справочника. Кеш сбрасывается для всех методов API независимо от того, какой справочник обновился. Но есть исключения для методов API, которые соответствуют маске DictionaryService.*Record*: кеш для данных методов будет сброшен только для обновленных справочников.

Использование NSIC без КМ#

Примеры использования API общего назначения без КМ#

API общего назначения предназначены для получения требуемой информации из любого справочника.

Транспорт: HTTP (REST) Заголовки запроса:

Content-Type=text/plain;charset=UTF-8
Content-Type=application/json;charset=UTF-8

Получение списка записей справочника

DictionaryService#getDictionaryRecords

GET /sbp.com.sbt.nsi.cloud.api.DictionaryService/{dictionary}?offset={offset}&limit={limit}

Где:

  • dictionary – справочник в модели ekpit-model (исходники классов модели);

  • offset, limit – параметры паджинации (опционально).

Ответ: массив объектов – записей справочника. Записи сериализуются по свойствам 1-го уровня модели ekpit-model. Вложенные объекты сериализуются как имя справочника + objectId. Атрибуты java.util.Date возвращаются в формате ISO локальной даты/времени.

Пример ответа

[
  {
    "type": null,
    "kind": null,
    "shortCode": "017",
    "fullCode": "544229017",
    "tbCode": "54",
    "osbCode": "4229",
    "vspCode": "017",
    "statReportCode": "0544229017",
    "casNsiCode": "544229017",
    "headDivision": [
      {
        "__dictionary": "Division",
        "objectId": "16017"
      }
    ],
    "fullName": "Доп.офис №4229/017",
    "individualName": null,
    "openDate": null,
    "closeDate": "2012-10-11T00:00:00",
    "status": null,
    "changePlanDate": "2012-10-11T00:00:00",
    "modificationAttributes": null,
    "addInformation": null,
    "requisites": null,
    "contacts": [],
    "format": [],
    "reformats": [],
    "addresses": [
      {
        "__dictionary": "SFSLegalAddress",
        "objectId": "33910000"
      }
    ],
    "temporaryLocations": [],
    "serving": null,
    "servingWindows": [],
    "operationModes": [],
    "selfServiceDevices": [],
    "facilities": [],
    "overallCount": null,
    "headcount": [],
    "workplaces": [],
    "businessCharacteristicValues": [],
    "successors": [],
    "resubordination": null,
    "multimediaInformation": [],
    "recordId": "33910",
    "objectId": "33910",
    "lastChangeDate": "2019-07-16T12:48:02.674",
    "ownerId": "cdm-ora-ekpit",
    "recModelVersion": null,
    "isDeleted": false,
    "sourceId": null,
    "sourceSystemId": null
  },
  {
    "type": null,
    "kind": null,
    "shortCode": "01760",
    "fullCode": "55663701760",
    "tbCode": "55",
    "osbCode": "6637",
    "vspCode": "01760",
    "statReportCode": "055663701760",
    "casNsiCode": "55663701760",
    "headDivision": [
      {
        "__dictionary": "Division",
        "objectId": "18640",
      }
    ],
    "fullName": "Доп.офис №6637/01760",
    "individualName": null,
    "openDate": "2008-12-25T00:00:00",
    "closeDate": "2010-12-29T00:00:00",
    "status": null,
    "changePlanDate": "2010-12-29T00:00:00",
    "modificationAttributes": null,
    "addInformation": null,
    "requisites": null,
    "contacts": [],
    "format": [],
    "reformats": [],
    "addresses": [
      {
        "__dictionary": "SFSLegalAddress",
        "objectId": "33936000",
      }
    ],
    "temporaryLocations": [],
    "serving": null,
    "servingWindows": [],
    "operationModes": [],
    "selfServiceDevices": [],
    "facilities": [],
    "overallCount": null,
    "headcount": [],
    "workplaces": [],
    "businessCharacteristicValues": [],
    "successors": [],
    "resubordination": null,
    "multimediaInformation": [],
    "recordId": "33936",
    "objectId": "33936",
    "lastChangeDate": "2019-07-16T12:48:02.596",
    "ownerId": "cdm-ora-ekpit",
    "recModelVersion": null,
    "isDeleted": false,
    "sourceId": null,
    "sourceSystemId": null
  }
]

Получение записи справочника по code, objectId

DictionaryService#getRecordByCode, #getRecordById

GET /sbp.com.sbt.nsi.cloud.api.DictionaryService/{dictionary}/byCode/{code}
GET /sbp.com.sbt.nsi.cloud.api.DictionaryService/{dictionary}/byId/{objectId}

Где:
code – значение свойства code;
objectId – значение objectId.

Ответ: объект – запись справочника.

Пример ответа

{
  "type": null,
  "kind": null,
  "shortCode": "4229",
  "fullCode": "544229",
  "tbCode": "54",
  "osbCode": "4229",
  "vspCode": null,
  "statReportCode": "0544229",
  "casNsiCode": "544229",
  "headDivision": [
    {
      "__dictionary": "Division",
      "objectId": "14807"
    }
  ],
  "fullName": "Кваркенское отделение №4229",
  "individualName": null,
  "openDate": null,
  "closeDate": "2012-10-11T00:00:00",
  "status": null,
  "changePlanDate": "2012-10-11T00:00:00",
  "modificationAttributes": null,
  "addInformation": null,
  "requisites": null,
  "contacts": [],
  "format": [],
  "reformats": [],
  "addresses": [
    {
      "__dictionary": "SFSLegalAddress",
      "objectId": "16017000"
    }
  ],
  "temporaryLocations": [],
  "serving": null,
  "servingWindows": [],
  "operationModes": [],
  "selfServiceDevices": [],
  "facilities": [],
  "overallCount": null,
  "headcount": [],
  "workplaces": [],
  "businessCharacteristicValues": [],
  "successors": [],
  "resubordination": null,
  "multimediaInformation": [],
  "recordId": "16017",
  "objectId": "16017",
  "lastChangeDate": "2019-07-16T12:47:14.371",
  "ownerId": "cdm-ora-ekpit",
  "recModelVersion": null,
  "isDeleted": false,
  "sourceId": null,
  "sourceSystemId": null
}

В случае отсутствия записи возвращается ответ HTTP 200 без тела ответа.

Получение записей по HQL (JPQL) запросу

DictionaryService#getRecordsByHql

POST /sbp.com.sbt.nsi.cloud.api.DictionaryService/{dictionary}/hql?offset={offset}&limit={limit}

Где:
offset, limit – параметры паджинации;
тело запроса – HQL (JPQL) запрос.

Пример тела запроса

Content-Type: text/plain;charset=UTF-8
select d 
from Division d where d.fullCode = '99'

Примечание

Примечание:
При обращении к DictionaryService.Division/hql в запросе HQL указывать поля не нужно. Этот API нужен для получения всех полей справочника.

Пример тела JSON запроса

Content-Type: application/json;charset=UTF-8
 
{
  "hql": "select d from Division d where d.fullCode = '99'",
  "limit": 10,
  "offset": 0
}

Ответ: массив объектов – записей справочника.

Получение набора свойств записей по HQL (JPQL) запросу

DictionaryService#getFieldsByHql

POST /sbp.com.sbt.nsi.cloud.api.DictionaryService/{dictionary}/hql/fields?offset={offset}&limit={limit}

Где:
offset, limit – параметры паджинации;
тело запроса – HQL (JPQL) запрос.

Пример тела запрос

Content-Type: text/plain;charset=UTF-8
 
select
    d.fullCode as code,
    d.fullName,
    d.openDate,
    h as head_division
from Division d join d.headDivision h
where h.fullCode = '99'

Примечание

Примечание:
При обращении к DictionaryService.Division/hql/fields в запросе HQL необходимо указывать конкретные поля. Этот API нужен для получения конкретных полей справочника.
Полный перечень полей уточняется у аналитика постановки.

Пример тела JSON запроса

Content-Type: application/json;charset=UTF-8
 
{
  "hql": "select p.code as code1, p.name as name1 from OrganizationBadge p",
  "limit": 10,
  "offset": 0
}

Ответ: массив массивов свойств, перечисленных в запросе. Для свойств с указанным alias он также указывается в ответе. Вложенные записи сериализуются по имени справочника + objectId записи.

Пример ответа

[
  [
    {
      "alias": "code",
      "type": "java.lang.String",
      "value": "38"
    },
    {
      "type": "java.lang.String",
      "value": "Московский банк"
    },
    {
      "type": "java.util.Date",
      "value": null
    },
    {
      "alias": "head_division",
      "type": "Division",
      "value": "137"
    }
  ],
  [
    {
      "alias": "code",
      "type": "java.lang.String",
      "value": "99909901"
    },
    {
      "type": "java.lang.String",
      "value": "Опер.офис №9099/01"
    },
    {
      "type": "java.util.Date",
      "value": "2010-06-01T00:00:00"
    },
    {
      "alias": "head_division",
      "type": "Division",
      "value": "137"
    }
  ]
]

Предупреждение

Важно!
При отправке запроса в формате JSON, значения параметров паджинации берутся из тела запроса.

Пример получения записи с помощью утилиты curl

Запрос:

$ curl -s --request POST --url $TURL'/sbp.com.sbt.nsi.cloud.api.DictionaryService/ClientInvestProfile/hql/fields?offset=0&limit=1' --header 'Content-Type: application/json;charset=UTF-8' --data-raw '{"hql":"select name, recordId, description, code from ClientInvestProfile cip where cip.profileId like '\''%15%'\''"}' | json_pp

Примечание

Примечание:
Полный перечень полей уточняется у аналитика постановки.

Ответ:

[
  [
    {
      "type": "ClientInvestProfile",
      "value": "629603581796247798"
    }
  ],
  [
    {
      "type": "ClientInvestProfile",
      "value": "629603582060488896"
    }
  ],
  [
    {
      "type": "ClientInvestProfile",
      "value": "629603581825607894"
    }
  ],
  [
    {
      "type": "ClientInvestProfile",
      "value": "629603581783664802"
    }
  ],
  [
    {
      "type": "ClientInvestProfile",
      "value": "629603581833996477"
    }
  ]
]

Специализированные API#

Специализированные API содержат дополнительную логику и предназначены для получения требуемой информации из определенных справочников.

В разделе содержится описание использования специализированных API как с помощью КМ, так и без него.

Специализированные API получения продуктов для депозитов юридических лиц (ДЮЛ)#

Входные параметры приведены в таблице ниже:

Аргумент

Тип

Описание

Обязательность задания конкретного значения

productCode

String

Код продукта

Да

parametersTypeCodes

List<String>

Коды типов параметров

Если null, возвращаются все параметры

servicesTypeCodes

List<String>

Коды типов сервисов

Если null, возвращаются все сервисы

Выходные параметры приведены в таблице ниже:

Атрибут класса

Атрибут относительно продукта

Тип

Описание

Обязательность задания конкретного значения

Product.objectId

objectId

string

Идентификатор продукта

Да

Product.code

code

string

Код продукта

Да

Product.name

name

string

Наименование продукта

Да

Product.beginDate

beginDate

date

Дата начала действия

Да

Product.endDate

endDate

date

Дата окончания действия

Нет

ProductDescription.description

productDescription.description

string

Описание продукта

Да

TemplateDynamicParam

parameters

TemplateDynamicParam (0…*)

Параметры: Выбираются только параметры, для которых parameters[*].paramType.code один из: [«crashRateDUL», «durationDUL», «summaDUL»]

Param.code

parameters.paramType.code

string

Код типа параметра

Да

AccessValue

parameters.accessValues

AccessValue (0…*)

Значения параметров

AccessValue.itemNum

parameters.accessValues.itemNum

integer

Для параметра SummaDUL содержит код валюты, Для параметра DurationDUL содержит порядковый номер интервала в значениях startValue и endValue

Нет

AccessValue.startValue

parameters.accessValues.startValue

string

Для параметра SummaDUL содержит минимальное значение суммы Для параметра DurationDUL содержит минимальный срок депозита

Нет

AccessValue.endValue

parameters.accessValues.endValue

string

Для параметра SummaDUL содержит максимальное значение суммы Для параметра DurationDUL содержит максимальный срок депозита

Нет

AccessValue.value

parameters.accessValues.value

string

Для параметра CrushRateDUL содержит значение ставки отзыва

Нет

TemplateService

services

TemplateService

Сервисы продукта Выбираются сервисы, для которых services[*].type.code один из: [„DulRecallDepositContractService“, „DulAdjunctionDepositContractService“] и services[*].visible = true

ObjectType.code

services.type.code

string

Код типа Для Отзываемого депозита содержит значение DulRecallDepositContractService Для Пополняемого депозита содержит DulAdjunctionDepositContractService

Нет

Пример запроса (JSON)

{
"jsonrpc": "2.0",
"id": "123",                                   <- ID запроса, генерируется фабрикой
"method": "getProductsByName",    
"params": {
"name": "Депозит Классический Онлайн",       <- наименование продукта
"parametersTypeCodes" : [                    <- коды типов параметров, которые нужно получить (опционально)
"crashRateDUL", "durationDUL", "summaDUL"
],
"servicesTypeCodes": [                       <- коды типов шаблонов (опционально)
"DulRecallDepositContractService",
"DulAdjunctionDepositContractService"
]
}
}

Пример ответа (JSON)

{
"jsonrpc": "2.0",
"id": "123",
"result": [
{
"objectId": "6100000",
"name": "Депозит Классический Онлайн",
"code": "CLASSIC_DEPOSIT_ONLINE",
"beginDate": "2017-01-01T00:00:00",
"endDate": null,
"productDescription": {
"description": "Депозит Классический Онлайн"
},
"parameters": [
{
"name": null,
"paramType": {
"code": "summaDUL"
},
"value": null,
"accessValues": [
{
"itemNum": 643,
"startValue": null,
"endValue": "99999999.99",
"value": null
},
{
"itemNum": 840,
"startValue": null,
"endValue": "9999999.99",
"value": null
}
]
},
{
"name": null,
"paramType": {
"code": "durationDUL"
},
"value": null,
"accessValues": [
{
"itemNum": 1,
"startValue": "7",
"endValue": "1096",
"value": null
}
]
}
],
"services": [
{
"type": {
"code": "DulAdjunctionDepositContractService"
}
},
{
"type": {
"code": "DulRecallDepositContractService"
}
}
]
}
]
}

Специализированные API получения продукта на индивидуальных условиях#

Входные параметры

Аргумент

Тип

Описание

Обязательность задания конкретного значения

productCode

String

Код продукта

Да

parametersTypeCodes

List<String>

Коды типов параметров

Если null, возвращаются все параметры

Выходные параметры

N

Атрибут класса

Атрибут относительно продукта

Тип

Описание

Обязательность задания конкретного значения

1

Product.objectId

objectId

string

Идентификатор продукта

Да

2

TemplateDynamicParam

parameters

TemplateDynamicParam (0…*)

Выбираются только параметры, для которых parameters[*].paramType.code один из:

-

-

-

-

crashRateDUL

Да

-

-

-

-

ufsConfirmationTermAmount

Нет

-

-

-

-

confirmationDealCurrency

Да

-

-

-

-

lowLimitAmount

Да

-

-

-

-

upLimitAmount

Да

-

-

-

-

lowLimitTerm

Да

-

-

-

-

upLimitTerm

Да

-

-

-

-

requiredClientIndicator

Нет

-

-

-

-

activeTariffZone

Нет

-

-

-

-

minValueDul

Нет

-

-

-

-

maxValueDul

Нет

-

-

-

-

ufsConfirmationInterestPayPeriod

Нет

-

-

-

-

confirmationDealMinTerm

Да

-

-

-

-

availableInterestPayPeriod

Да

-

-

-

-

dulProductCallability

Нет

-

-

-

-

dulProductReplenishable

Нет

2.1.

Param.code

parameters.paramType.code

string

Код типа параметра

Нет

2.2.

TemplateDynamicParam.value

value

string

Значение параметра

Нет

3

AccessValue

parameters.accessValues

AccessValue (0…*)

Значения для параметра (1) crashRateDUL

3.1.

AccessValue.itemNum

parameters.accessValues.itemNum

integer

Содержит код валюты

Да

3.2.

AccessValue.value

parameters.accessValues.value

string

Содержит значение ставки отзыва

Да

Пример запроса (JSON)

{
"jsonrpc": "2.0",
"id": 1,
"method": "getProductsByCodes",
"params": {
"productCodes": [
"RECALLABLE_DEPOSIT_ONLINE_PLUS_IP"
]
}
}

Пример ответа (JSON)

{
      "jsonrpc": "2.0",
      "id": 1,
      "result": [
            {
                  "recordId": "6100009",
                  "objectId": "6100009",
                  "parameters": [
                        {
                              "recordId": "6001880",
                              "name": null,
                              "value": null,
                              "paramType": {
                                    "recordId": "6000411",
                                    "code": "ufsConfirmationTermAmount"
                              },
                              "accessValues": [],
                              "parameters": [
                                    {
                                          "recordId": "6001881",
                                          "name": null,
                                          "value": "200000.00",
                                          "paramType": {
                                                "recordId": "6000412",
                                                "code": "lowLimitAmount"
                                          },
                                          "accessValues": []
                                    }
                              ]
                        }
                  ],
                  "services": [
                        {
                              "recordId": "6100911",
                              "type": {
                                    "recordId": "6030006",
                                    "code": "DulRecallDepositContractService"
                              },
                              "parameters": [
                                    {
                                          "recordId": "6090374",
                                          "name": "null",
                                          "value": "1",
                                          "paramType": {
                                                "recordId": "6000076",
                                                "code": "maxValueDul"
                                          },
                                          "accessValues": []
                                    }
                              ]
                        }
                  ]
            }
      ]
}

Специальные API для доступа к конфиденциальной информации#

Общий перечень реализованных методов API приведен в таблице ниже:

N

Наименование метода

Владелец\потребитель конфиденциальных данных

Справочник

ID модулей, имеющих доступ к API

Требуется создание ACL

Комментарий

1

getProductDUL

Депозиты ЮЛ

Product

1. Dul-module
2. sip-dul-module

Да

Доступ к конфиденциальным данным, принадлежащим ДЮЛ + доступ ко всем неконфиденциальным данным из справочника Product

2

getRateRC

Расчетный центр

RateValue

1. loro-contract-module
2. rko-fi-module
3. loro-payment-module
4. nostro-payment-module
5. mars-bps
6. mars-request

Да

Доступ к конфиденциальным данным, принадлежащим Расчетному Центру + доступ ко всем неконфиденциальным данным из справочника RateValue

3

getRateDUL

Депозиты ЮЛ

RateValue

1. Dul-module
2. sip-dul-module

Да

Доступ к конфиденциальным данным, принадлежащим ДЮЛ + доступ ко всем неконфиденциальным данным из справочника RateValue

4

getProduct

-

Product

-

Нет

Доступ для всех потребителей - не владельцев конфиденциальных данных к данным, не являющимся конфиденциальными

5

getRate

-

RateValue

-

Нет

Доступ для всех потребителей - не владельцев конфиденциальных данных к данным, не являющимся конфиденциальными

6

getProductFull

-

Product

-

Да

Доступ ко всем данным справочника Product

7

getRateFull

Динамический прайсинг

RateValue

1. pricing-service (4е поколение pricing-service-cloud)

Да

Доступ ко всем данным справочника RateValue

8

getFieldsProductDUL

Депозиты ЮЛ

Product

1. Dul-module 2. sip-dul-module

Да

Получение набора свойств записей принадлежащих ДЮЛ по HQL (JPQL) запросу из справочника Product

9

getFieldsRateDUL

Депозиты ЮЛ

RateValue

1. Dul-module 2. sip-dul-module

Да

Получение набора свойств записей принадлежащих ДЮЛ по HQL (JPQL) запросу из справочника RateValue

10

getFieldsRateRC

Расчетный центр

RateValue

1. loro-contract-module
2. rko-fi-module
3. loro-payment-module
4. nostro-payment-module
5. mars-bps
6. mars-request

Да

Получение набора свойств записей принадлежащих Расчетному Центру по HQL (JPQL) запросу из справочника RateValue

11

getFieldsProductFull

-

Product

Да

Получение набора свойств записей по HQL (JPQL) запросу из справочника Product (Доступ ко всем данным справочника Product)

12

getFieldsRateFull

-

RateValue

Да

Получение набора свойств записей по HQL (JPQL) запросу из справочника RateValue (Доступ ко всем данным справочника Product)

13

getFieldsProduct

-

Product

-

-

Получение набора свойств записей по HQL (JPQL) запросу из справочника Product (Доступ для всех потребителей - не владельцев конфиденциальных данных к данным, не являющимся конфиденциальными)

14

getFieldsRate

-

RateValue

-

-

Получение набора свойств записей по HQL (JPQL) запросу из справочника RateValue (Доступ для всех потребителей - не владельцев конфиденциальных данных к данным, не являющимся конфиденциальными)

Описание метода getProductDUL#

Входные параметры:

  • Дата и время запроса (yyyy-mm-ddThh:mm:ss±hh:mm). Параметр заполняется локальным временем потребителя сервиса.

Выходные параметры:

  • Все записи, соответствующие фильтру по типу продукта для потребителя ДЮЛ.

Поиск продуктов по типу:

select OT.code, count(PR.object_Id)
      from d_ekpit_product PR
      join d_ekpit_objecttype OT On PR.type_id = OT.object_id
      where OT.code in ('LegalDeposit', 'LegalNso') -- коды типов продуктов
      and COALESCE(PR.SYS_ISDELETED,0) = 0
      group by OT.code;
Описание метода getRateRC#

Входные параметры:

  • Дата и время запроса (yyyy-mm-ddThh:mm:ss±hh:mm).

Выходные параметры:

  • Из справочника RateValue выбираются все записи, соответствующие фильтру по типу ставки для потребителя «Расчетный Центр».

Поиск значений ставок по типу:

select OT.code, count(RV.object_Id)
from d_ekpit_ratevalue RV
join d_ekpit_templaterate RT On RV.rate_id = RT.object_id
join d_ekpit_objecttype OT On RT.type_id = OT.object_id
where OT.code in ('LegalEntityTransferFeeRateType', 'LoroProductInterimStatementProvidingFeeRate', 'LoroCommission', 'LoroProductProcessingFeeRate', 'LoroProductOpeningFeeRate', 'LoroProductAccountCertificateProvidingFeeRate', 'LoroProductAccountTurnoverReportProvidingFeeRate', 'LoroProductPaperTransferFeeRate', 'LoroProductStatementDeliveryFeeRate', 'PaymentDetailsClarificationFeeRateType', 'LoroProductDocumentDuplicateIssueFeeRate', 'TransactionsReportCompilationFeeRateType', 'SupportingDocumentCopyPreparingAttestingFeeRate', 'LoroProductAccountDebitConfirmationFeeRate', 'LegalEntityTransferCancellationFeeRate', 'SignatureAndSealCardRegistrationFeeRateType', 'LoroProductInterestRate') -- коды типов ставок
and COALESCE(RV.SYS_ISDELETED,0) = 0
group by OT.code;
Описание метода getRateDUL#

Входные параметры:

  • Дата и время запроса (yyyy-mm-ddThh:mm:ss±hh:mm).

Выходные параметры:

  • Все записи, соответствующие фильтру по типу ставки для потребителя ДЮЛ.

Поиск значений ставок по типу:

select OT.code, count(RV.object_Id)
from d_ekpit_ratevalue RV
join d_ekpit_templaterate RT On RV.rate_id = RT.object_id
join d_ekpit_objecttype OT On RT.type_id = OT.object_id
where OT.code in ('PublicRateDul', 'DulCeilingRate') -- коды типов ставок
and COALESCE(RV.SYS_ISDELETED,0) = 0
group by OT.code;
Описание метода getProduct#

Входные параметры:

  • Дата и время запроса (yyyy-mm-ddThh:mm:ss±hh:mm).

Выходные параметры:

  • Из справочника Product выбираются все записи, удовлетворяющие двум условиям:

    • Дата запроса больше или равна значению атрибута privacyEventDate и значению атрибута finalPrivacyCategory.

    • Дата запроса меньше privacyEventDate и значения startPrivacyCategory либо null.

Описание метода getRate#

Входные параметры:

  • Дата и время запроса (yyyy-mm-ddThh:mm:ss±hh:mm).

Выходные параметры:

  • Из справочника RateValue выбираются все записи, удовлетворяющие условиям двум условиям:

    • Дата запроса больше или равна значению атрибута privacyEventDate и значению атрибута finalPrivacyCategory.

    • Дата запроса меньше privacyEventDate и значения startPrivacyCategory либо null.

Описание методов getProductFull и getRateFull#

Получение всех записей из справочников Product и RateValue соответственно (без учета признака конфиденциальности).

Описание метода GetFieldsProductDUL#

Настраивается фильтр на уровне сущности Product для продуктов ДЮЛ:

select OT.code, count(PR.object_Id)
from d_ekpit_product PR
join d_ekpit_objecttype OT On PR.type_id = OT.object_id
where OT.code in ('LegalDeposit', 'LegalNso') -- коды типов продуктов
and COALESCE(PR.SYS_ISDELETED,0) = 0
group by OT.code;
Описание метода getFieldsRateDUL#

Настраивается фильтр на уровне сущности RateValue для ставок ДЮЛ.

Поиск значений ставок по типу:

select OT.code, count(RV.object_Id)
from d_ekpit_ratevalue RV
join d_ekpit_templaterate RT On RV.rate_id = RT.object_id
join d_ekpit_objecttype OT On RT.type_id = OT.object_id
where OT.code in ('PublicRateDul', 'DulCeilingRate') -- коды типов ставок
and COALESCE(RV.SYS_ISDELETED,0) = 0
group by OT.code;
Описание метода getFieldsRateRC#

Настраивается фильтр на уровне сущности RateValue для ставок Расчетного Центра.

Поиск значений ставок по типу:

select OT.code, count(RV.object_Id)
from d_ekpit_ratevalue RV
join d_ekpit_templaterate RT On RV.rate_id = RT.object_id
join d_ekpit_objecttype OT On RT.type_id = OT.object_id
where OT.code in ('LegalEntityTransferFeeRateType', 'LoroProductInterimStatementProvidingFeeRate', 'LoroCommission', 'LoroProductProcessingFeeRate', 'LoroProductOpeningFeeRate', 'LoroProductAccountCertificateProvidingFe eRate', 'LoroProductAccountTurnoverReportProvidingFeeRate', 'LoroProductPaperTransferFeeRate', 'LoroProductStatementDeliveryFeeRate', 'PaymentDetailsClarificationFeeRateType', 'LoroProductDocumentDuplicateIssueFeeRate', 'TransactionsReportCompilationFeeRateType', 'SupportingDocumentCopyPreparingAttestingFeeRate', 'LoroProductAccountDebitConfirmationFeeRate', 'LegalEntityTransferCancellationFeeRate', 'SignatureAndSealCardRegistrationFeeRateType', 'LoroProductInterestRate') -- коды типов ставок
and COALESCE(RV.SYS_ISDELETED,0) = 0
group by OT.code;

Специальные API проверки доступности компонента#

Реализованы два типа API проверки доступности NSIC:

  • Liveness probe;

  • Readiness probe.

Liveness probe#

Предназначен для проверки доступности сервиса.

Пример запроса

GET {{SERVICE}}/health/sayOk


GET {{SERVICE}}/health/sayOk

Где {{SERVICE}} обозначает базовый адрес (доменное имя) сервиса, предоставляющего API. Его необходимо заменить фактическим именем домена.

Пример ответа в случае успешного запуска

HTTP/1.1 200
Content-Length: 0
Keep-Alive: timeout=60
Connection: keep-alive

<Response body is empty>

Response code: 200; Time: 17ms; Content length: 0 bytes
Readiness probes#

Предназначен для проверки готовности компонента принимать и обрабатывать запросы к API.

Пример запроса

GET {{SERVICE}}/health/readiness

Где {{SERVICE}} обозначает базовый адрес (доменное имя) сервиса, предоставляющего API. Его необходимо заменить фактическим именем домена.

Пример ответа в случае готовности к обработке API запросов

HTTP/1.1 200
timeBeforeLogout: 7196
timeoutValue: 7200
Content-Length: 0
Keep-Alive: timeout=60
Connection: keep-alive

<Response body is empty>

Response code: 200; Time: 22ms; Content length: 0 bytes

Пример ответа в случае не готовности сервиса обрабатывать запросы

HTTP/1.1 500
Content-Length: 0
Connection: close

<Response body is empty>

Response code: 500; Time: 11076ms; Content length: 0 bytes

Специальные API для получения подразделений филиальной сети#

Перечень методов:

  • getByObjectId;

  • getByObjectIds;

  • getBySubdivisionCode;

  • getByBranch;

  • getDepartmentBySubdivisionCode;

  • getDepartmentsIdsBySubdivisionCodeAndDtClosed;

  • getDepartmentOrSuccessorBySubdivisionCode.

@ApiLib
public interface DepartmentsApiService {

    /**
     * Получение подразделения по objectId
     * @param objectId objectId подразделения
     * @return подразделение, если найдено и единственно
     */
    @ApiMethod(name = "getByObjectId", major = 1, minor = 0)
    Departments getByObjectId(@JsonRpcParam("objectId") @NotNull String objectId);

    /**
     * Получение подразделений по списку objectId
     * @param objectIds список objectId подразделений
     * @return список подразделений
     */
    @ApiMethod(name = "getByObjectIds", major = 1, minor = 0)
    List<Departments> getByObjectIds(@JsonRpcParam("objectIds") @NotNull List<String> objectIds);

    /**
     * Получение подразделения по полному коду
     * @param subdivisionCode полный код подразделения
     * @return подразделение, если найдено и единственно
     */
    @ApiMethod(name = "getBySubdivisionCode", major = 1, minor = 0)
    Departments getBySubdivisionCode(@JsonRpcParam("subdivisionCode") @NotNull String subdivisionCode);

    /**
     * Получение подразделения по branch
     * @param branch branch подразделения
     * @return подразделение с максимальной датой закрытия
     */
    @ApiMethod(name = "getByBranch", major = 1, minor = 0)
    Departments getByBranch(@JsonRpcParam("branch") @NotNull String branch);

    /**
     * Ищет подразделения, не закрытые на дату закрытия по полным кодам.
     * @param vdate версионная дата
     * @param subdivisionCode код подразделения
     * @param operDay операционный день. Если null, то ставится последняя полночь
     * @return открытые на операционный день подразделения
     */
    @ApiMethod(name = "getDepartmentBySubdivisionCode", major = 1, minor = 0)
    List<Department> getDepartmentBySubdivisionCode(@JsonRpcParam("vdate") @Nullable Date vdate,
                                                    @JsonRpcParam("subdivisionCode") @NotNull String subdivisionCode,
                                                    @JsonRpcParam("operDay") @Nullable Date operDay);

    /**
     * Ищет подразделения, не закрытые на дату закрытия по полным кодам.
     * @param vdate версионная дата
     * @param subdivisionCodes список кодов подразделений
     * @param dtClose дата, после которой может быть закрыто подразделение
     * @return открытые на дата закрытия подразделения
     */
    @ApiMethod(name = "getDepartmentsIdsBySubdivisionCodeAndDtClosed", major = 1, minor = 0)
    Set<String> getDepartmentsIdsBySubdivisionCodeAndDtClosed(@JsonRpcParam("vdate") @Nullable Date vdate,
                                                              @JsonRpcParam("subdivisionCodes") @NotNull Set<String> subdivisionCodes,
                                                              @JsonRpcParam("dtClose") @NotNull Date dtClose);

    /**
     * Ищет открытые на операционный день подразделения по полному коду.
     * Если для данного полного кода подразделение закрыто, то поиск продолжается по кодам подразделений правопреемников.
     * @param subdivisionCode код подразделения
     * @param operDay операционный день. Если null, то ставится последняя полночь
     * @return открытые на операционный день подразделения
     */
    @ApiMethod(name = "getDepartmentOrSuccessorBySubdivisionCode", major = 1, minor = 0)
    List<Department> getDepartmentOrSuccessorBySubdivisionCode(@JsonRpcParam("subdivisionCode") @NotNull String subdivisionCode,
                                                               @JsonRpcParam("operDay") @Nullable Date operDay);
}

Пример получения подразделения по коду

// ...
@Autowired
DepartmentsApiService departmentsApiService;

// ...
Departments departments = departmentsApiService.getBySubdivisionCode("38");

Специальные API сервиса для фабрики Производственный календарь#

Перечень методов:

  • findProductionCalendarByRegionCode;

  • findProductionCalendarByCode;

  • findProductionCalendarDateByCode;

  • getHolidaysByIso2country;

  • getHolidaysIso2countries.

@ApiLib
public interface ProductionCalendarService {

    /**
     * Метод получения производственного календаря, по коду региона
     * @param regionCode код региона
     */
    @ApiMethod(name = "findProductionCalendarByRegionCode", major = 1, minor = 0)
    List<ProductionCalendar> findProductionCalendarByRegionCode(@JsonRpcParam("regionCode") @NotNull String regionCode);

    /**
     * Метод получения производственного календаря, по коду календаря
     * @param code полный код календаряs
     */
    @ApiMethod(name = "findProductionCalendarByCode", major = 1, minor = 0)
    List<ProductionCalendar> findProductionCalendarByCode(@JsonRpcParam("code") @NotNull String code);

    /**
     * Метод получения дат производственного календаря по его коду
     * @param code код календаря
     */
    @ApiMethod(name = "findProductionCalendarDateByCode", major = 1, minor = 0)
    List<ProductionCalendarDate> findProductionCalendarDateByCode(@JsonRpcParam("code") @NotNull String code);

    /**
     * Возвращает Holidays по iso2country
     * @param iso2country
     */
    @ApiMethod(name = "getHolidaysByIso2country", major = 1, minor = 0)
    List<Holidays> getHolidaysByIso2country(@JsonRpcParam("iso2country") @NotNull String iso2country);

    /**
     * Метод возвращает список iso2country по всем Holidays
     */
    @ApiMethod(name = "getHolidaysIso2countries", major = 1, minor = 0)
    List<String> getHolidaysIso2countries();
}

Алгоритм проверки наличия обновлений справочника#

В разделе приведен алгоритм проверки наличия обновлений справочников ClientType и Departments.

При запуске приложения необходимо выполнить первичный запрос с указанием списка системных справочников, по которым планируется отслеживать обновления.

Пример запроса с использованием клиентской библиотеки:

String hql = "select r from RspitVersionDictionary r where r.dictionaryName in ('ClientType', 'Departments')";
int limit = 2; // количество проверяемых справочников
Map<String, String> dictionaryVersion = dictionaryService.getRecordsByHql(RspitVersionDictionary.class, hql, limit, 0).stream().collect(Collectors.toMap(v -> v.getDictionaryName(), v -> v.getVersion()));

Если выбран данный способ, то необходимо отключить клиентский кеш, установив значение параметра nsi.cloud.client.cache.enabledfalse.

Пример REST-запроса:

POST {{SERVICE}}/sbp.com.sbt.nsi.cloud.api.DictionaryService/RspitVersionDictionary/hql/fields
Accept: application/json;charset=UTF-8
Content-Type: application/json;charset=UTF-8

{
  "hql": "select r.dictionaryName as dictionaryName, r.version as version from RspitVersionDictionary r where r.dictionaryName in ('ClientType', 'Departments')",
  "limit": 2,
  "offset": 0
}

Где {{SERVICE}} обозначает базовый адрес (доменное имя) сервиса, предоставляющего API. Его необходимо заменить фактическим именем домена.

Полученные результаты необходимо хранить в контексте приложения. Далее необходимо настроить метод, который по заданному расписанию периодически повторяет первичный запрос и сравнивает по значению ключа RspitVersionDictionary.dictionaryName значение RspitVersionDictionary.version на предмет идентичности. Если значение RspitVersionDictionary.version отличается от предыдущего, значит справочник обновился.

После обработки события обновления версии справочника необходимо обновить текущее значение версии на обновленное и повторить проверку наличия обновлений справочников по обновленному значению версии.

Часто встречающиеся проблемы и пути их устранения#

Проблема

Причина

Способ устранения

Ошибка развертывания pod вида: WARNING: Error creating: pods «nsi-cloud-facade» is forbidden: exceeded quota: core-object-counts, requested: limits.memory=3328Mi, used: limits.memory=62836Mi, limited: limits.memory=64Gi

Недостаток ресурсов в кластере среды контейнеризации

Необходимо увеличить ресурсы в кластере среде контейнеризации

Ошибка подключения к БД вида ERROR: permission denied for relation table_name

У пользователя БД недостаточно прав для доступа к таблице

Необходимо расширить права пользователя

Ошибка InvalidDictionaryException

Возможные причины:
1. Не корректное имя справочника.
2. Несоответствие системного имени справочника в системе распространения данных с системным именем справочника в ekpit-model

Для устранения данной ошибки требуется использовать параметр клиентской библиотеки, в котором можно выставить mapping соответствия имен. Пример: nsi.cloud.client.cache.update.dictionary.mapping='SFSDivisions':'Division'. Данная настройка позволит корректно определять обновления версий справочника и выполнять сброс кешей