Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
f2f5453a4c
7 changed files with 728 additions and 68 deletions
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
{
|
||||
"version": "3.17.223.119",
|
||||
"version": "3.17.223.120",
|
||||
|
||||
"enums": {
|
||||
|
||||
|
|
@ -10772,6 +10772,253 @@
|
|||
|
||||
,"views": {
|
||||
|
||||
"AccountUnion": {
|
||||
"sources": [
|
||||
"bankAccount"
|
||||
,
|
||||
"account"
|
||||
,
|
||||
"clearingAccount"
|
||||
],"fields":[
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": ""
|
||||
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
,
|
||||
"executionCurrencyView": {
|
||||
"sources": [
|
||||
"executionCurrency"
|
||||
],"fields":[
|
||||
|
||||
{
|
||||
"code": "exchangeExecutionId"
|
||||
,"type": 1,"name": "Идентификационный номер сделки в Торговой системе","shortname": "Номер сделки","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "side"
|
||||
,"type": 12,"dbname": "Код направления сделки","name": "Направление сделки","shortname": "Направление","visible": true,"searchable": true,"sortable": true,"link": "side"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "market"
|
||||
,"type": 12,"dbname": "Код секции валютного инструмента","name": "Секция валютного инструмента","shortname": "Секция","visible": true,"searchable": true,"sortable": true,"link": "market","linkKeyCode": "code","linkCode": "description"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "tradingDate"
|
||||
,"type": 6,"name": "Дата заключения сделки","shortname": "Дата заключения сделки","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "settlementDate"
|
||||
,"type": 6,"name": "Дата расчетов","shortname": "Дата расчетов","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "securitySymbol"
|
||||
,"type": 2,"length": 255,"name": "Код инструмента в Торговой Системе","shortname": "Код инструмента","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "price"
|
||||
,"type": 10,"name": "Цена","shortname": "Цена","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "settlementAmount"
|
||||
,"type": 11,"name": "Объем сделки в валюте лота","shortname": "Объем в валюте","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "lots"
|
||||
,"type": 11,"name": "Количество лотов","shortname": "Лоты","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "quantity"
|
||||
,"type": 11,"name": "Количество штук","shortname": "Количество штук","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "exchangeExecutionTime"
|
||||
,"type": 4,"name": "Время заключения сделки в Торговой системе","shortname": "Время заключения сделки","visible": true,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "partyTradingClearingRegistryId"
|
||||
,"type": 1,"dbname": "Идентификатор торгово-клирингового регистра","name": "Торгово-клиринговый регистр","shortname": "ТКР","visible": true,"searchable": true,"sortable": true,"link": "tradingClearingRegistry","linkCode": "code"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "comment"
|
||||
,"type": 2,"length": 255,"name": "Комментарий","shortname": "Комментарий","searchable": true,"sortable": true,"ignore": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "clientCode"
|
||||
,"type": 2,"length": 255,"name": "Код участника клиринга","shortname": "Код клиента","searchable": true,"sortable": true,"ignore": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "settlementCode"
|
||||
,"type": 2,"length": 12,"name": "Код расчетов при размещении","shortname": "Код расчетов при размещении","visible": false,"searchable": true,"sortable": true,"ignore": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "companyId"
|
||||
,"type": 1,"dbname": "Идентификатор компании","name": "Наименование компании","shortname": "Компания","visible": true,"searchable": true,"sortable": true,"link": "company","linkCode": "shortName"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "companyId"
|
||||
,"type": 1,"dbname": "Идентификатор компании","name": "Наименование компании","shortname": "Компания","visible": true,"searchable": true,"sortable": true,"link": "company","linkCode": "shortName"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "counterPartyId"
|
||||
,"type": 1,"dbname": "Идентификатор компании-партнера, с которой заключена сделка","name": "Наименование компании-партнера, с которой заключена сделка","shortname": "Партнер","visible": false,"searchable": true,"sortable": true,"link": "company","linkCode": "shortName"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "counterPartyId"
|
||||
,"type": 1,"dbname": "Идентификатор компании-партнера, с которой заключена сделка","name": "Наименование компании-партнера, с которой заключена сделка","shortname": "Партнер","visible": false,"searchable": true,"sortable": true,"link": "company","linkCode": "shortName"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "market"
|
||||
,"type": 12,"dbname": "Код секции валютного инструмента","name": "Секция валютного инструмента","shortname": "Секция","visible": true,"searchable": true,"sortable": true,"link": "market","linkKeyCode": "code","linkCode": "description"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "currencyCode"
|
||||
,"type": 12,"name": "Код валюты лота","shortname": "Код валюты лота","searchable": true,"sortable": true,"link": "currencyCode","linkCode": "code"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "market"
|
||||
,"type": 12,"dbname": "Код секции валютного инструмента","name": "Секция валютного инструмента","shortname": "Секция","visible": true,"searchable": true,"sortable": true,"link": "market","linkKeyCode": "code","linkCode": "description"
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "linkedExchangeExecutionId"
|
||||
,"type": 1,"name": "Идентификационный номер витринной сделки в Торговой системе","shortname": "Номер витринной сделки","searchable": true,"sortable": true,"ignore": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "id"
|
||||
,"type": 1,"name": "Идентификатор записи","shortname": "ID","visible": false,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "createdAt"
|
||||
,"field": "created","type": 4,"webtype": "5","dbname": "Дата-время создания записи","name": "Время создания записи","shortname": "Создано","visible": false,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
,
|
||||
|
||||
{
|
||||
"code": "updatedAt"
|
||||
,"field": "updated","type": 4,"webtype": "5","dbname": "Дата-время изменения записи","name": "Время изменения записи","shortname": "Изменено","visible": false,"searchable": true,"sortable": true
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
,"types": [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--?xml-stylesheet type="text/xsl" href="\..\corp-reports\src\data\meta\meta.server.xslt"?-->
|
||||
<meta version="3.17.223.119">
|
||||
<meta version="3.17.223.120">
|
||||
<!-- _xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _xsi:noNamespaceSchemaLocation="file:///E:/d/projects/meta/from/meta.xsd" -->
|
||||
<!--Здесь словари-->
|
||||
<enums>
|
||||
|
|
@ -2526,32 +2526,32 @@
|
|||
</AccountUnion>
|
||||
<executionCurrencyView>
|
||||
<source code="executionCurrency"/>
|
||||
<set><exchangeExecutionId/></set>
|
||||
<set><side/></set>
|
||||
<set><market name="Код класса валютного инструмента" shortname="Код класса" link="market" linkKeyCode="code" linkCode="code"/></set>
|
||||
<set><tradingDate/></set>
|
||||
<set><settlementDate/></set>
|
||||
<set><securitySymbol/></set>
|
||||
<set><price/></set>
|
||||
<set><settlementAmount name="Сумма сделки в рублях" shortname="Сумма сделки"/></set>
|
||||
<set><lots shortname="Объем в лотах"/></set>
|
||||
<set><quantity name="Объем сделки в единицах валюты" shortname="Объем сделки"/></set>
|
||||
<set><exchangeExecutionTime shortname="Время сделки"/></set>
|
||||
<set><partyTradingClearingRegistryId/></set>
|
||||
<set><comment visible="true" ignore="false"/></set>
|
||||
<set><clientCode visible="true" ignore="false"/></set>
|
||||
<set><settlementCode name="Код расчетов при размещении" shortname="Код режима расчетов" visible="true" ignore="false"/></set>
|
||||
<set><companyId name="Код участника клиринга" shortname="Код УК" link="company" linkCode="clearingCode"/></set>
|
||||
<set><companyId name="Название участника клиринга" shortname="Название УК"/></set>
|
||||
<set><counterPartyId name="Код УК контрагента" shortname="Код УК контрагента" visible="true" link="company" linkCode="clearingCode"/></set>
|
||||
<set><counterPartyId name="Название УК контрагента" shortname="Название УК контрагента" visible="true"/></set>
|
||||
<set><market name="Наименование класса валютного инструмента" shortname="Наименование класса"/></set>
|
||||
<set><currencyCode name="Код валюты расчетов" shortname="Валюта расчетов" visible="true"/></set>
|
||||
<set><market name="Код секции в Клиринговой системе" shortname="Код секции в КС" link="market" linkKeyCode="code" linkCode="section"/></set>
|
||||
<set><linkedExchangeExecutionId visible="true" ignore="false"/></set>
|
||||
<set><id/></set>
|
||||
<set><createdAt/></set>
|
||||
<set><updatedAt/></set>
|
||||
<set><exchangeExecutionId type="1" name="Идентификационный номер сделки в Торговой системе" shortname="Номер сделки" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><side type="12" dbname="Код направления сделки" name="Направление сделки" shortname="Направление" visible="true" searchable="true" sortable="true" link="side"/></set>
|
||||
<set><market type="12" dbname="Код секции валютного инструмента" name="Секция валютного инструмента" shortname="Секция" visible="true" searchable="true" sortable="true" link="market" linkKeyCode="code" linkCode="description"/></set>
|
||||
<set><tradingDate type="6" name="Дата заключения сделки" shortname="Дата заключения сделки" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><settlementDate type="6" name="Дата расчетов" shortname="Дата расчетов" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><securitySymbol type="2" length="255" name="Код инструмента в Торговой Системе" shortname="Код инструмента" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><price type="10" name="Цена" shortname ="Цена" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><settlementAmount type="11" name="Объем сделки в валюте лота" shortname="Объем в валюте" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><lots type="11" name="Количество лотов" shortname="Лоты" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><quantity type="11" name="Количество штук" shortname="Количество штук" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><exchangeExecutionTime type="4" name="Время заключения сделки в Торговой системе" shortname="Время заключения сделки" visible="true" searchable="true" sortable="true"/></set>
|
||||
<set><partyTradingClearingRegistryId type="1" dbname="Идентификатор торгово-клирингового регистра" name="Торгово-клиринговый регистр" shortname="ТКР" visible="true" searchable="true" sortable="true" link="tradingClearingRegistry" linkCode="code"/></set>
|
||||
<set><comment type="2" length="255" name="Комментарий" shortname="Комментарий" searchable="true" sortable="true" ignore="true"/></set>
|
||||
<set><clientCode type="2" length="255" name="Код участника клиринга" shortname="Код клиента" searchable="true" sortable="true" ignore="true"/></set>
|
||||
<set><settlementCode type="2" length="12" name="Код расчетов при размещении" shortname="Код расчетов при размещении" visible="false" searchable="true" sortable="true" ignore="true"/></set>
|
||||
<set><companyId type="1" dbname="Идентификатор компании" name="Наименование компании" shortname="Компания" visible="true" searchable="true" sortable="true" link="company" linkCode="shortName"/></set>
|
||||
<set><companyId type="1" dbname="Идентификатор компании" name="Наименование компании" shortname="Компания" visible="true" searchable="true" sortable="true" link="company" linkCode="shortName"/></set>
|
||||
<set><counterPartyId type="1" dbname="Идентификатор компании-партнера, с которой заключена сделка" name="Наименование компании-партнера, с которой заключена сделка" shortname="Партнер" visible="false" searchable="true" sortable="true" link="company" linkCode="shortName"/></set>
|
||||
<set><counterPartyId type="1" dbname="Идентификатор компании-партнера, с которой заключена сделка" name="Наименование компании-партнера, с которой заключена сделка" shortname="Партнер" visible="false" searchable="true" sortable="true" link="company" linkCode="shortName"/></set>
|
||||
<set><market type="12" dbname="Код секции валютного инструмента" name="Секция валютного инструмента" shortname="Секция" visible="true" searchable="true" sortable="true" link="market" linkKeyCode="code" linkCode="description"/></set>
|
||||
<set><currencyCode type="12" name="Код валюты лота" shortname="Код валюты лота" searchable="true" sortable="true" link="currencyCode" linkCode="code"/></set>
|
||||
<set><market type="12" dbname="Код секции валютного инструмента" name="Секция валютного инструмента" shortname="Секция" visible="true" searchable="true" sortable="true" link="market" linkKeyCode="code" linkCode="description"/></set>
|
||||
<set><linkedExchangeExecutionId type="1" name="Идентификационный номер витринной сделки в Торговой системе" shortname="Номер витринной сделки" searchable="true" sortable="true" ignore="true"/></set>
|
||||
<set><id type="1" name="Идентификатор записи" shortname="ID" visible="false" searchable="true" sortable="true"/></set>
|
||||
<set><createdAt field="created" type="4" webtype="5" dbname="Дата-время создания записи" name="Время создания записи" shortname="Создано" visible="false" searchable="true" sortable="true"/></set>
|
||||
<set><updatedAt field="updated" type="4" webtype="5" dbname="Дата-время изменения записи" name="Время изменения записи" shortname="Изменено" visible="false" searchable="true" sortable="true"/></set>
|
||||
</executionCurrencyView>
|
||||
</views>
|
||||
<types>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
<xsl:template match="/">
|
||||
<xsl:apply-templates select="*"/>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="meta">
|
||||
{
|
||||
"version": "<xsl:value-of select="@version"/>",
|
||||
<xsl:apply-templates select="*"/>
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="enums">
|
||||
"enums": {
|
||||
<xsl:apply-templates select="*" mode="enums"/>
|
||||
|
|
@ -26,24 +26,24 @@
|
|||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="views">
|
||||
,"views": {
|
||||
<!--xsl:apply-templates select="*" mode="views"/-->
|
||||
<xsl:apply-templates select="*" mode="views"/>
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="reports"></xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="types">
|
||||
,"types": [
|
||||
<xsl:apply-templates select="*" mode="types"/>
|
||||
]
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
|
||||
<xsl:template match="*" mode="types">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
{
|
||||
|
|
@ -54,8 +54,8 @@
|
|||
</xsl:for-each>
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
|
||||
<xsl:template match="*" mode="enums">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
"<xsl:value-of select="name(.)"/>": {
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
"fields": [<xsl:apply-templates select="*" mode="field"/>]
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="*" mode="objects">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
|
|
@ -84,8 +84,8 @@
|
|||
<xsl:template match="subscription" mode="objects"></xsl:template>
|
||||
<xsl:template match="subscriptionHistory" mode="objects"></xsl:template>
|
||||
<xsl:template match="views" mode="objects"></xsl:template>
|
||||
|
||||
|
||||
|
||||
|
||||
<xsl:template match="actions" mode="objects">
|
||||
<xsl:for-each select="*">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
|
|
@ -97,10 +97,10 @@
|
|||
}
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<xsl:template match="*" mode="views">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
"<xsl:value-of select="name(.)"/>": {
|
||||
|
|
@ -118,32 +118,45 @@
|
|||
"<xsl:value-of select="@code"/>"
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="set" mode="views">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
<xsl:choose>
|
||||
<xsl:when test="count(field)=1">
|
||||
<xsl:apply-templates select="field"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
{<xsl:for-each select="field[position() = 1]">
|
||||
<xsl:for-each select="@*[name()!='source']">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
"<xsl:value-of select="name()"/>":
|
||||
<xsl:variable name="attrName"><xsl:value-of select="name()"/></xsl:variable>
|
||||
{
|
||||
<xsl:for-each select="parent::*/parent::*/field/@*[name()=$attrName]">
|
||||
<xsl:apply-templates select="." mode="withSource"/>
|
||||
<xsl:if test="position() != last()">,</xsl:if>
|
||||
</xsl:for-each>
|
||||
}
|
||||
</xsl:for-each>
|
||||
</xsl:for-each>
|
||||
}
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:variable name="nodeName"><xsl:value-of select="name()"/></xsl:variable>
|
||||
<!-- <xsl:choose>
|
||||
<xsl:when test="count(node())=1">
|
||||
<xsl:apply-templates select="node()"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>-->
|
||||
{<xsl:for-each select="node()[position() = 1]">
|
||||
"code": "<xsl:value-of select="name()"/>"
|
||||
<xsl:for-each select="@*[name()!='source']">
|
||||
<xsl:if test="position() >= 1">,</xsl:if>
|
||||
<xsl:choose>
|
||||
<xsl:when test="name()='type'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='length'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='searchable'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='sortable'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='visible'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='enabled'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='ignore'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='required'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:when test="name()='cacheable'">"<xsl:value-of select="name()"/>": <xsl:value-of select="."/></xsl:when>
|
||||
<xsl:otherwise>"<xsl:value-of select="name()"/>": "<xsl:value-of select="."/>"</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:variable name="attrName"><xsl:value-of select="name()"/></xsl:variable>
|
||||
<!-- {
|
||||
<xsl:for-each select="parent::*/parent::*/*[name()=$nodeName]/@*[name()=$attrName]">
|
||||
<xsl:apply-templates select="." mode="withSource"/>
|
||||
<xsl:if test="position() != last()">,</xsl:if>
|
||||
</xsl:for-each>
|
||||
}-->
|
||||
</xsl:for-each>
|
||||
</xsl:for-each>
|
||||
}
|
||||
<!-- </xsl:otherwise>
|
||||
</xsl:choose>-->
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="*" mode="field">
|
||||
<xsl:if test="position() > 1">,</xsl:if>
|
||||
|
|
@ -181,7 +194,7 @@
|
|||
</xsl:for-each>
|
||||
}}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="@*" mode="withSource">
|
||||
<xsl:choose>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,223 @@
|
|||
package ru.spcex.clearing.utility.service;
|
||||
|
||||
import org.apache.kafka.clients.consumer.Consumer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.clearing.classes.statics.data.registry.TradingClearingRegistry;
|
||||
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest;
|
||||
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.NotificationNewRequest;
|
||||
import ru.spcex.clearing.platform.messaging.serialization.LogFormatter;
|
||||
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
|
||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||
import ru.spcex.platform.enumeration.*;
|
||||
import ru.spcex.platform.imdg.api.Imdg;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
import ru.spcex.platform.imdg.api.predicate.ImdgPredicate;
|
||||
import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder;
|
||||
import ru.spcex.platform.imdg.api.predicate.specific.RegistryCodeSqlBuilder;
|
||||
import ru.spcex.platform.imdg.iml.hazelcast.adapter.predicate.ImdgPredicateBuilderHazelcast;
|
||||
import ru.spcex.platform.utils.collection.Pair;
|
||||
import ru.spcex.platform.utils.number.BigDecimalUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class AmatAmafChecker extends QueueConsumer implements InitializingBean {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
static final DateTimeFormatter MESSAGE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss");
|
||||
|
||||
private final Imdg<Registry> registryImdg;
|
||||
private final Imdg<TradingClearingRegistry> tradingClearingRegistryImdg;
|
||||
private final ImdgProvider imdgProvider;
|
||||
private final KafkaSender kafkaSender;
|
||||
|
||||
@Autowired
|
||||
public AmatAmafChecker(ImdgProvider imdgProvider,
|
||||
KafkaSender kafkaSender,
|
||||
Producer<String, Object> kafkaProducer,
|
||||
Consumer<String, Object> kafkaQueue) {
|
||||
super(kafkaQueue, kafkaProducer);
|
||||
this.imdgProvider = imdgProvider;
|
||||
this.kafkaSender = kafkaSender;
|
||||
this.registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
|
||||
this.tradingClearingRegistryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_TradingClearingRegistry, TradingClearingRegistry.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
callback(LauncherCommandRequest.class)
|
||||
.setConsumer(this::checkOnDate)
|
||||
.forDestination(Task.GVTF.topic(), callbacks::put);
|
||||
init();
|
||||
}
|
||||
|
||||
public void checkOnDate(BaseRequest<LauncherCommandRequest> gvtfEvent) {
|
||||
List<Long> specialId = null;
|
||||
if (gvtfEvent.getRequestPayload() != null && gvtfEvent.getRequestPayload().getIds() != null) {
|
||||
specialId = gvtfEvent.getRequestPayload().getIds();
|
||||
}
|
||||
log.debug("Check AM*T and AM*F (parameter id's = {})", specialId);
|
||||
|
||||
ImdgPredicateBuilder builder = ImdgPredicateBuilderHazelcast.instance();
|
||||
Collection<Registry> checkRegistries;
|
||||
final LocalDateTime checkTime = LocalDateTime.now();
|
||||
|
||||
ImdgPredicate AM_T_AM_F_predicate = RegistryCodeSqlBuilder.getInstance(
|
||||
RegistryTradingParams.AM_T,
|
||||
RegistryTradingParams.AM_F)
|
||||
.buildPredicate(builder);
|
||||
if (specialId == null) {
|
||||
long timer = System.currentTimeMillis();
|
||||
Collection<TradingClearingRegistry> activeTcr = tradingClearingRegistryImdg.getCollectionObjectsByPredicate(
|
||||
builder.equals("status", ServiceStatus.Active.getKey())
|
||||
);
|
||||
List<String> tcrActiveCode = activeTcr.stream()
|
||||
.map(tcr -> tcr.getCode())
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
log.debug("Found {} code's from active TradingClearingRegistry", tcrActiveCode.size());
|
||||
ImdgPredicate predicate = builder.and(
|
||||
AM_T_AM_F_predicate,
|
||||
builder.equals("accountType", AccountType.Info.getKey()),
|
||||
builder.in("tradingClearingRegistry", tcrActiveCode.toArray(new String[0]))
|
||||
);
|
||||
checkRegistries = registryImdg.getCollectionObjectsByPredicate(predicate);
|
||||
timer = System.currentTimeMillis() - timer;
|
||||
log.debug("Select {} Registry by query: {}. Time {} ms.", checkRegistries.size(), predicate, timer);
|
||||
} else {
|
||||
log.debug("Selecting {} AM_T and by tradingClearingRegistry and securitySymbol AM_F for his.", specialId);
|
||||
long timer = System.currentTimeMillis();
|
||||
checkRegistries = new ArrayList<>(specialId.size() * 2);
|
||||
for (Long am_tId : specialId) {
|
||||
if (am_tId == null) { // never
|
||||
log.warn("Received argument ID was null");
|
||||
continue;
|
||||
}
|
||||
Registry am_tRegistry = registryImdg.getSingleObjectByID(am_tId);
|
||||
if (am_tRegistry == null) {
|
||||
log.warn("Registry not found by ID={}", am_tId);
|
||||
} else {
|
||||
checkRegistries.add(am_tRegistry);
|
||||
ImdgPredicate predicate = builder.and(
|
||||
AM_T_AM_F_predicate,
|
||||
builder.equals("accountType", AccountType.Info.getKey()),
|
||||
builder.equals("tradingClearingRegistry", am_tRegistry.getTradingClearingRegistry()),
|
||||
builder.equals("securitySymbol", am_tRegistry.getSecuritySymbol()),
|
||||
builder.not(builder.equals("id", am_tRegistry.getId())) // counter-registry
|
||||
);
|
||||
Collection<Registry> otherRegistry = registryImdg.getCollectionObjectsByPredicate(predicate);
|
||||
log.trace("For Registry.id={} found {} other Registry's by query {}", am_tId, otherRegistry.size(), predicate);
|
||||
for (Registry otherReg : otherRegistry) {
|
||||
if (!am_tId.equals(otherReg.getId()))
|
||||
checkRegistries.add(am_tRegistry);
|
||||
}
|
||||
}
|
||||
}
|
||||
timer = System.currentTimeMillis() - timer;
|
||||
log.debug("Select {} Registry and hi's pairs by ID collection. Time {} ms.", checkRegistries.size(), timer);
|
||||
}
|
||||
|
||||
// Сверка Registry
|
||||
List<String> mismatch = checkRegisters(checkRegistries);
|
||||
|
||||
if (mismatch.isEmpty()) {
|
||||
log.debug("Check registry result: OK");
|
||||
sendMessage(makeSuccessMessage(checkTime), Priority.LOW);
|
||||
} else {
|
||||
log.debug("Check registry result: not match");
|
||||
sendMessage(makeErrorMessage(checkTime, mismatch), Priority.HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
String makeSuccessMessage(LocalDateTime checkTime) {
|
||||
|
||||
return String.format("""
|
||||
Проведена сверка по регистрам AMAT/AMAF.
|
||||
%s.
|
||||
Результат сверки: расхождения отсутствуют.""",
|
||||
MESSAGE_TIME_FORMATTER.format(checkTime));
|
||||
}
|
||||
|
||||
String makeErrorMessage(LocalDateTime checkTime, List<String> mismatch) {
|
||||
assert !mismatch.isEmpty();
|
||||
String msgItems = mismatch.stream().collect(Collectors.joining("; "));
|
||||
return String.format("""
|
||||
Проведена сверка по регистрам AMAT/AMAF.
|
||||
%s.
|
||||
Результат сверки: %s.""",
|
||||
MESSAGE_TIME_FORMATTER.format(checkTime), msgItems);
|
||||
}
|
||||
|
||||
protected List<String> checkRegisters(Collection<Registry> checkRegistries) {
|
||||
List<String> resultMismatch = new ArrayList<>();
|
||||
Map<Pair<String, String>, List<Registry>> regGroup = checkRegistries.stream().collect(Collectors.groupingBy(
|
||||
r -> new Pair<>(r.getTradingClearingRegistry(), r.getSecuritySymbol())
|
||||
));
|
||||
log.trace("Make {} group of TradingClearingRegistry+SecuritySymbol from {} Registry", regGroup.size(), checkRegistries.size());
|
||||
int equalsCount = 0;
|
||||
int mismatchCount = 0;
|
||||
for (Map.Entry<Pair<String, String>, List<Registry>> group : regGroup.entrySet()) {
|
||||
BigDecimal am_tSumm = BigDecimal.ZERO;
|
||||
BigDecimal am_fSumm = BigDecimal.ZERO;
|
||||
for (Registry r : group.getValue()) {
|
||||
if (match(RegistryTradingParams.AM_T, r)) {
|
||||
am_tSumm = am_tSumm.add(BigDecimalUtil.safeBD(r.getBalance()));
|
||||
}
|
||||
if (match(RegistryTradingParams.AM_F, r)) {
|
||||
am_fSumm = am_fSumm.add(BigDecimalUtil.safeBD(r.getBalance()));
|
||||
}
|
||||
}
|
||||
log.trace("Group {} size of {} item: AM_T summ={}, AM_F summ={}",
|
||||
group.getKey(), group.getValue().size(), am_tSumm, am_fSumm);
|
||||
boolean balanceOk = am_tSumm.compareTo(am_fSumm) == 0;
|
||||
if (balanceOk) {
|
||||
equalsCount++;
|
||||
} else {
|
||||
mismatchCount++;
|
||||
String describe = String.format("по ТКР %s выявлено расхождение на регистрах AMAT/AMAF по %s на сумму %s",
|
||||
group.getKey().getFirst(), // TradingClearingRegistry
|
||||
group.getKey().getSecond(), // SecuritySymbol
|
||||
am_tSumm.subtract(am_fSumm)
|
||||
);
|
||||
resultMismatch.add(describe);
|
||||
}
|
||||
}
|
||||
log.debug("Check result: equalsCount = {}, mismatchCount = {}", equalsCount, mismatchCount);
|
||||
return resultMismatch;
|
||||
}
|
||||
|
||||
protected void sendMessage(String message, Priority priority) {
|
||||
final String destination = Consts.NOTIFICATION_NEW;
|
||||
NotificationNewRequest request = new NotificationNewRequest();
|
||||
request.setObjectType(ObjectType.rgst.getKey());
|
||||
request.setPriority(priority.getKey());
|
||||
request.setComment(message);
|
||||
log.debug("Send message to kafka \"{}\": {}", destination, LogFormatter.toStringWrapper(request));
|
||||
kafkaSender.sendRequestToQueue(destination, request);
|
||||
}
|
||||
|
||||
protected boolean match(RegistryTradingParams params, Registry reg) {
|
||||
if (params.registryDesignation() != null && !params.registryDesignation().equalsByKey(reg.getRegistryDesignation()))
|
||||
return false;
|
||||
if (params.registryCapacity() != null && !params.registryCapacity().equalsByKey(reg.getRegistryCapacity()))
|
||||
return false;
|
||||
if (params.registryInstrumentType() != null && !params.registryInstrumentType().equalsByKey(reg.getRegistryInstrumentType()))
|
||||
return false;
|
||||
if (params.registryUnit() != null && !params.registryUnit().equalsByKey(reg.getRegistryUnit()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package ru.spcex.clearing.utility.service;
|
||||
|
||||
import org.apache.kafka.clients.consumer.Consumer;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import ru.clearing.classes.statics.data.registry.Registry;
|
||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||
import ru.spcex.platform.enumeration.RegistryDesignation;
|
||||
import ru.spcex.platform.enumeration.RegistryInstrumentType;
|
||||
import ru.spcex.platform.enumeration.RegistryTradingParams;
|
||||
import ru.spcex.platform.enumeration.RegistryUnit;
|
||||
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class AmatAmafCheckerTest {
|
||||
|
||||
AmatAmafChecker instance() {
|
||||
ImdgProvider imdgProvider = Mockito.mock(ImdgProvider.class);
|
||||
KafkaSender kafkaSender = Mockito.mock(KafkaSender.class);
|
||||
Producer<String, Object> kafkaProducer = Mockito.mock(Producer.class);
|
||||
Consumer<String, Object> kafkaQueue = Mockito.mock(Consumer.class);
|
||||
return new AmatAmafChecker(imdgProvider, kafkaSender, kafkaProducer, kafkaQueue);
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkOnDate() {
|
||||
AmatAmafChecker checker = instance();
|
||||
|
||||
List<Registry> regSrc = new ArrayList<>();
|
||||
List<String> tkr = Arrays.asList("0004CAV00003", "0482CAT00001", "0095CAV00002");
|
||||
List<String> securitySymbol = Arrays.asList("RUB", "CNY");
|
||||
int i = 1;
|
||||
for (String tcrCode : tkr)
|
||||
for (String secSymbol : securitySymbol) {
|
||||
Registry reg1 = new Registry();
|
||||
reg1.setId(1L);
|
||||
reg1.setRegistryDesignation("A");
|
||||
reg1.setRegistryInstrumentType("M");
|
||||
reg1.setRegistryCapacity("A");
|
||||
reg1.setRegistryUnit("T");
|
||||
reg1.setRegistryCode("AMAT"); // RegistryUtil.clearingCode(reg1)
|
||||
reg1.setTradingClearingRegistry(tcrCode);
|
||||
reg1.setSecuritySymbol(secSymbol);
|
||||
reg1.setBalance(BigDecimal.valueOf(100 * i));
|
||||
if ("RUB".equals(secSymbol))
|
||||
reg1.setBalanceRub(reg1.getBalance());
|
||||
else
|
||||
reg1.setBalanceRub(reg1.getBalance().multiply(BigDecimal.valueOf(0.1)));
|
||||
regSrc.add(reg1);
|
||||
Registry reg2 = new Registry();
|
||||
reg2.setId(1L);
|
||||
reg2.setRegistryDesignation("A");
|
||||
reg2.setRegistryInstrumentType("M");
|
||||
reg2.setRegistryCapacity("A");
|
||||
reg2.setRegistryUnit("F");
|
||||
reg2.setRegistryCode("AMAF");
|
||||
reg2.setTradingClearingRegistry(tcrCode);
|
||||
reg2.setSecuritySymbol(secSymbol);
|
||||
reg2.setBalance(reg1.getBalance());
|
||||
reg2.setBalanceRub(reg1.getBalanceRub());
|
||||
regSrc.add(reg2);
|
||||
}
|
||||
|
||||
// All OK
|
||||
List<String> errors = checker.checkRegisters(regSrc);
|
||||
assertEquals(0, errors.size());
|
||||
|
||||
|
||||
// Error in data
|
||||
regSrc.get(0).setBalance(regSrc.get(0).getBalance().add(BigDecimal.valueOf(100)));
|
||||
regSrc.get(4).setBalance(BigDecimal.valueOf(10.25));
|
||||
errors = checker.checkRegisters(regSrc);
|
||||
assertEquals(2, errors.size());
|
||||
assertEquals("[по ТКР 0004CAV00003 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму 100, по ТКР 0482CAT00001 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму -89.75]",
|
||||
errors.toString());
|
||||
|
||||
// next test makeErrorMessage:
|
||||
assertEquals("Проведена сверка по регистрам AMAT/AMAF.\n" +
|
||||
"2025.05.05 12:37:56.\n" +
|
||||
"Результат сверки: по ТКР 0004CAV00003 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму 100; по ТКР 0482CAT00001 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму -89.75.",
|
||||
checker.makeErrorMessage(
|
||||
LocalDateTime.of(2025, 5, 5, 12, 37, 56), errors));
|
||||
}
|
||||
|
||||
@Test
|
||||
void makeSuccessMessage() {
|
||||
AmatAmafChecker checker = instance();
|
||||
assertEquals("Проведена сверка по регистрам AMAT/AMAF.\n" +
|
||||
"2025.05.05 12:37:56.\n" +
|
||||
"Результат сверки: расхождения отсутствуют.",
|
||||
checker.makeSuccessMessage(LocalDateTime.of(2025, 5, 5, 12, 37, 56)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void makeErrorMessage() {
|
||||
AmatAmafChecker checker = instance();
|
||||
|
||||
assertEquals("Проведена сверка по регистрам AMAT/AMAF.\n" +
|
||||
"2025.05.05 12:37:56.\n" +
|
||||
"Результат сверки: по ТКР 0004CAV00003 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму 100; по ТКР 0482CAT00001 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму -89.75.",
|
||||
checker.makeErrorMessage(
|
||||
LocalDateTime.of(2025, 5, 5, 12, 37, 56),
|
||||
Arrays.asList(
|
||||
"по ТКР 0004CAV00003 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму 100",
|
||||
"по ТКР 0482CAT00001 выявлено расхождение на регистрах AMAT/AMAF по RUB на сумму -89.75"
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void match() {
|
||||
AmatAmafChecker checker = instance();
|
||||
|
||||
Registry reg1 = new Registry();
|
||||
reg1.setId(1L);
|
||||
reg1.setRegistryDesignation("A");
|
||||
reg1.setRegistryInstrumentType("M");
|
||||
reg1.setRegistryCapacity("A");
|
||||
reg1.setRegistryUnit("T");
|
||||
reg1.setRegistryCode("AMAT"); // RegistryUtil.clearingCode(reg1)
|
||||
Registry reg2 = new Registry();
|
||||
reg2.setId(1L);
|
||||
reg2.setRegistryDesignation("A");
|
||||
reg2.setRegistryInstrumentType("M");
|
||||
reg2.setRegistryCapacity("A");
|
||||
reg2.setRegistryUnit("F");
|
||||
reg2.setRegistryCode("AMAF");
|
||||
|
||||
assertTrue(checker.match(RegistryTradingParams.AM_T, reg1));
|
||||
assertTrue(checker.match(RegistryTradingParams.AM_F, reg2));
|
||||
assertTrue(checker.match(RegistryTradingParams.AM__, reg1));
|
||||
assertTrue(checker.match(RegistryTradingParams.AM__, reg2));
|
||||
|
||||
assertFalse(checker.match(RegistryTradingParams.AS__, reg1));
|
||||
assertFalse(checker.match(RegistryTradingParams.AM_F, reg1));
|
||||
assertFalse(checker.match(RegistryTradingParams.AM_T, reg2));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package ru.spcex.clearing.platform.messaging.domain.cud.schedule;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
|
|
@ -12,6 +11,7 @@ import ru.spcex.clearing.platform.messaging.domain.json.serialize.LocalTimeSeria
|
|||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
|
||||
public class LauncherCommandRequest {
|
||||
|
||||
|
|
@ -66,6 +66,9 @@ public class LauncherCommandRequest {
|
|||
@JsonProperty
|
||||
public LocalDate toDate;
|
||||
|
||||
@JsonProperty
|
||||
private List<Long> ids;
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
|
@ -233,4 +236,12 @@ public class LauncherCommandRequest {
|
|||
public void setToDate(LocalDate toDate) {
|
||||
this.toDate = toDate;
|
||||
}
|
||||
|
||||
public List<Long> getIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void setIds(List<Long> ids) {
|
||||
this.ids = ids;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.spcex.platform.utils.collection;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Pair<T1, T2> {
|
||||
|
|
@ -40,4 +41,22 @@ public class Pair<T1, T2> {
|
|||
secondConsumer.accept(second);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return Objects.equals(first, pair.first) && Objects.equals(second, pair.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (first == null ? 0 : first.hashCode()) * 31 ^ (second == null ? 0 : second.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pair{" + first + "; " + second + "}";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue