This commit is contained in:
akulikov 2023-07-18 15:37:48 +03:00
parent 2399cfd8cc
commit a8fb21f599
12 changed files with 392 additions and 17 deletions

View file

@ -25,7 +25,8 @@ public class ReportBuildersConfig {
KSRepDepoRegisterQuantitiesReportBuilder ksRepDepoRegisterQuantitiesReportBuilder,
KSRepTradesReportBuilder ksRepTradesReportBuilder,
KSRepFirmDetailsReportBuilder ksRepFirmDetailsReportBuilder,
KSSessionListReportBuilder ksSessionListReportBuilder
KSSessionListReportBuilder ksSessionListReportBuilder,
KSCommissionTradesReportBuilder ksCommissionTradesReportBuilder
) {
Map<ReportBuilderType, List<CSVReportBuilder<EmptyParams, ?>>> resultMap = new HashMap<>();
resultMap.put(ReportBuilderType.KS_REP_CASH_REGISTERS, List.of(ksRepCashRegistersReportBuilder));
@ -35,6 +36,7 @@ public class ReportBuildersConfig {
resultMap.put(ReportBuilderType.KS_REP_TRADES, List.of(ksRepTradesReportBuilder));
resultMap.put(ReportBuilderType.KS_REP_FIRM_DETAILS, List.of(ksRepFirmDetailsReportBuilder));
resultMap.put(ReportBuilderType.KS_SESSION_LIST, List.of(ksSessionListReportBuilder));
resultMap.put(ReportBuilderType.KS_COMMISSION_TRADES, List.of(ksCommissionTradesReportBuilder));
return resultMap;
}
@ -73,7 +75,8 @@ public class ReportBuildersConfig {
KSRepFirmDetailsReportBuilder ksRepFirmDetailsReportBuilder,
KSRepCashNettoReportBuilder ksRepCashNettoReportBuilder,
KSRepDepoNettoReportBuilder ksRepDepoNettoReportBuilder,
KSSessionListReportBuilder ksSessionListReportBuilder
KSSessionListReportBuilder ksSessionListReportBuilder,
KSCommissionTradesReportBuilder ksCommissionTradesReportBuilder
) {
Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> resultMap = new HashMap<>();
resultMap.put(ReportBuilderType.KS_REP_CASH_REGISTERS, List.of(ksRepCashRegistersReportBuilder));
@ -85,6 +88,7 @@ public class ReportBuildersConfig {
resultMap.put(ReportBuilderType.KS_REP_CASH_NETTO, List.of(ksRepCashNettoReportBuilder));
resultMap.put(ReportBuilderType.KS_REP_DEPO_NETTO, List.of(ksRepDepoNettoReportBuilder));
resultMap.put(ReportBuilderType.KS_SESSION_LIST, List.of(ksSessionListReportBuilder));
resultMap.put(ReportBuilderType.KS_COMMISSION_TRADES, List.of(ksCommissionTradesReportBuilder));
return resultMap;
}
@ -98,7 +102,8 @@ public class ReportBuildersConfig {
KSRepFirmDetailsReportBuilder ksRepFirmDetailsReportBuilder,
KSRepCashNettoReportBuilder ksRepCashNettoReportBuilder,
KSRepDepoNettoReportBuilder ksRepDepoNettoReportBuilder,
KSSessionListReportBuilder ksSessionListReportBuilder
KSSessionListReportBuilder ksSessionListReportBuilder,
KSCommissionTradesReportBuilder ksCommissionTradesReportBuilder
) {
Map<ReportBuilderType, List<CSVReportBuilder<?, ?>>> resultMap = new HashMap<>();
resultMap.put(ReportBuilderType.KS_REP_CASH_REGISTERS, List.of(ksRepCashRegistersReportBuilder));
@ -110,6 +115,7 @@ public class ReportBuildersConfig {
resultMap.put(ReportBuilderType.KS_REP_CASH_NETTO, List.of(ksRepCashNettoReportBuilder));
resultMap.put(ReportBuilderType.KS_REP_DEPO_NETTO, List.of(ksRepDepoNettoReportBuilder));
resultMap.put(ReportBuilderType.KS_SESSION_LIST, List.of(ksSessionListReportBuilder));
resultMap.put(ReportBuilderType.KS_COMMISSION_TRADES, List.of(ksCommissionTradesReportBuilder));
return resultMap;
}

View file

@ -62,7 +62,8 @@ public class ValidationConfig {
ReportBuilderType.KS_REP_DEPO_REGISTER_QUANTITIES,
ReportBuilderType.KS_REP_TRADES,
ReportBuilderType.KS_REP_FIRM_DETAILS,
ReportBuilderType.KS_SESSION_LIST
ReportBuilderType.KS_SESSION_LIST,
ReportBuilderType.KS_COMMISSION_TRADES
},
ReportError.WrongFieldValue,
ReportError.RequiredFieldEmpty)

View file

@ -61,8 +61,18 @@ public abstract class CSVReportBuilder<P, R> {
*/
public abstract Class<P> getParamsClass();
/**
* Класс отчета
*/
public abstract Class<R> getReportClass();
/**
* Секция отчета (для конкретного отчета может быть перегружена)
*/
public String getSection() {
return null;
}
/**
* Формирование отчета на основе параметров
*

View file

@ -0,0 +1,11 @@
package ru.spcex.clearing.reports.reports;
public record ReportInfo(String reportKey, String section) {
@Override
public String toString() {
return "ReportInfo{" +
"reportKey='" + reportKey + '\'' +
", section='" + section + '\'' +
'}';
}
}

View file

@ -0,0 +1,111 @@
package ru.spcex.clearing.reports.reports.bean;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.CsvBindByPosition;
import com.opencsv.bean.CsvDate;
import com.opencsv.bean.CsvNumber;
import java.math.BigDecimal;
import java.time.LocalDate;
public class KSCommissionTradesReport {
@CsvBindByName(column = "FIRMID")
@CsvBindByPosition(position = 0)
private String firmId;
@CsvBindByName(column = "FIRM_INITIATOR")
@CsvBindByPosition(position = 1)
private String firmInitiator;
@CsvBindByName(column = "SECCODE")
@CsvBindByPosition(position = 2)
private String secCode;
@CsvBindByName(column = "AGREEMENT_NUMBER")
@CsvBindByPosition(position = 3)
private String agreementNumber;
@CsvBindByName(column = "AGREEMENT_NUMBER_PREFIX")
@CsvBindByPosition(position = 4)
private String agreementNumberPrefix;
@CsvBindByName(column = "AGREEMENT_DATE")
@CsvBindByPosition(position = 5)
@CsvDate(value = "dd.MM.yyyy")
private LocalDate agreementDate;
@CsvBindByName(column = "SUM")
@CsvBindByPosition(position = 6)
@CsvNumber(value = "#0.00", writeFormat = "#0.00")
private BigDecimal sum;
@CsvBindByName(column = "SUM_DATE")
@CsvBindByPosition(position = 7)
@CsvDate(value = "dd.MM.yyyy")
private LocalDate sumDate;
public String getFirmId() {
return firmId;
}
public void setFirmId(String firmId) {
this.firmId = firmId;
}
public String getFirmInitiator() {
return firmInitiator;
}
public void setFirmInitiator(String firmInitiator) {
this.firmInitiator = firmInitiator;
}
public String getSecCode() {
return secCode;
}
public void setSecCode(String secCode) {
this.secCode = secCode;
}
public String getAgreementNumber() {
return agreementNumber;
}
public void setAgreementNumber(String agreementNumber) {
this.agreementNumber = agreementNumber;
}
public String getAgreementNumberPrefix() {
return agreementNumberPrefix;
}
public void setAgreementNumberPrefix(String agreementNumberPrefix) {
this.agreementNumberPrefix = agreementNumberPrefix;
}
public LocalDate getAgreementDate() {
return agreementDate;
}
public void setAgreementDate(LocalDate agreementDate) {
this.agreementDate = agreementDate;
}
public BigDecimal getSum() {
return sum;
}
public void setSum(BigDecimal sum) {
this.sum = sum;
}
public LocalDate getSumDate() {
return sumDate;
}
public void setSumDate(LocalDate sumDate) {
this.sumDate = sumDate;
}
}

View file

@ -0,0 +1,159 @@
package ru.spcex.clearing.reports.reports.ks;
import org.springframework.stereotype.Component;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.registry.Registry;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.reports.reports.CSVReportBuilder;
import ru.spcex.clearing.reports.reports.EmptyParams;
import ru.spcex.clearing.reports.reports.bean.KSCommissionTradesReport;
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 java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Component
public class KSCommissionTradesReportBuilder extends CSVReportBuilder<EmptyParams, KSCommissionTradesReport> {
protected DateTimeFormatter dateFormatter_ddMMyy = DateTimeFormatter.ofPattern("ddMMyy");
private final Imdg<Registry> registryImdg;
private final Imdg<Company> companyImdg;
private final Imdg<CompanySymbols> companySymbolsImdg;
private List<KSCommissionTradesReport> rows = null;
public KSCommissionTradesReportBuilder(ImdgProvider imdgProvider) {
registryImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Registry, Registry.class);
companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class);
companySymbolsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class);
}
@Override
protected List<KSCommissionTradesReport> getRows() {
return rows;
}
@Override
public ReportBuilderType getReportType() {
return ReportBuilderType.KS_COMMISSION_TRADES;
}
@Override
public ReportKeys getReportKey() {
return ReportKeys.KS_COMMISSION_TRADES;
}
@Override
public Class<EmptyParams> getParamsClass() {
return EmptyParams.class;
}
@Override
public Class<KSCommissionTradesReport> getReportClass() {
return KSCommissionTradesReport.class;
}
@Override
public String getSection() {
return Section.MKR.getKey();
}
@Override
protected void collect(EmptyParams params) {
LocalDate nowDate = LocalDate.now();
ImdgPredicateBuilder pb = registryImdg.predicateBuilder();
String sql = RegistryCodeSqlBuilder.getInstance(RegistryTradingParams.DM_T, RegistryTradingParams.DM_X).build();
ImdgPredicate finalPredicate = pb.and(
pb.sql(sql),
pb.equals("refundDate", nowDate),
pb.equals("registryStatus", RegistryStatus.OK.getKey()),
pb.notNull("clearingDate")
);
Collection<Registry> registries = registryImdg.getCollectionObjectsByPredicate(finalPredicate);
rows = new ArrayList<>(registries.size());
for (Registry registry : registries) {
try {
Company company = companyImdg.getSingleObjectByID(registry.getCompanyId());
if (!WorkflowStatus.Active.equalsByKey(company.getWorkflowStatus())) continue;
CompanySymbols companySymbols = companySymbolsImdg.getFirstObjectByFieldValues(
Map.of(
"companyId", registry.getCompanyId(),
"companySymbol", CompanySymbol.INTC.getKey()
)
);
if (companySymbols == null) {
log.warn("Can't find CompanySymbols {} for companyId = {}. Registry id = {} skipped",
CompanySymbol.INTC.getKey(),
registry.getCompanyId(),
registry.getId());
continue;
}
sql = RegistryCodeSqlBuilder.getInstance(RegistryTradingParams.OM_T).build();
Registry omtRegistry = registryImdg.getFirstObjectByPredicate(
pb.and(
pb.sql(sql),
pb.equals("contract", registry.getContract()),
pb.notNull("groupId")
)
);
if (omtRegistry == null) {
log.warn("Can't find pair OM_T registry for contract = {}. Registry id = {} skipped",
registry.getContract(),
registry.getId());
continue;
}
String extracted = extractPartAgreementNumber(String.valueOf(omtRegistry.getGroupId()));
if (extracted == null) {
log.warn("Can't extract ExchangeExecutionId from GroupId (groupId = {} for OM_T registry id = {}). " +
"Registry id = {} skipped",
omtRegistry.getGroupId(),
omtRegistry.getId(),
registry.getId());
continue;
}
String agreementNumber = "%s/%s/%s%s".formatted(
registry.getSecuritySymbol(),
dateFormatter_ddMMyy.format(registry.getClearingDate()),
registry.getClearingCode(),
extracted
);
KSCommissionTradesReport ksCommissionTradesReport = new KSCommissionTradesReport();
ksCommissionTradesReport.setFirmId(registry.getClearingCode());
ksCommissionTradesReport.setFirmInitiator(companySymbols.getCompanySymbolValue());
ksCommissionTradesReport.setSecCode(registry.getSecuritySymbol());
ksCommissionTradesReport.setAgreementNumber(agreementNumber);
ksCommissionTradesReport.setAgreementNumberPrefix("");
ksCommissionTradesReport.setAgreementDate(registry.getClearingDate());
ksCommissionTradesReport.setSum(registry.getBalance());
ksCommissionTradesReport.setSumDate(registry.getRefundDate());
rows.add(ksCommissionTradesReport);
} catch (Throwable e) {
log.error("Can't create report row for registry (id = %d), skipped".formatted(registry.getId()), e);
}
}
}
private String extractPartAgreementNumber(String groupId) {
if (groupId.length() < 8) return null;
int datePartLength = 6;
int marketIdPartLength = 2;
return groupId.substring(datePartLength, groupId.length() - marketIdPartLength);
}
}

View file

@ -22,11 +22,11 @@ import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
import ru.spcex.clearing.reports.config.element.ReportsServiceSettings;
import ru.spcex.clearing.reports.reports.CSVReportBuilder;
import ru.spcex.clearing.reports.reports.EmptyParams;
import ru.spcex.clearing.reports.reports.ReportInfo;
import ru.spcex.clearing.reports.reports.SessionIdParam;
import ru.spcex.clearing.util.security.UserRoleVerification;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.enumeration.ReportBuilderType;
import ru.spcex.platform.enumeration.ReportKeys;
import ru.spcex.platform.enumeration.ReportType;
import ru.spcex.platform.enumeration.Task;
import ru.spcex.platform.imdg.api.Imdg;
@ -223,7 +223,7 @@ public class ReportService extends QueueConsumer implements InitializingBean {
} else {
sessionIds = getSessionIdsForDate(LocalDate.now());
}
Map<String, ReportKeys> outFilenames = createReportsForTask(sessionIds, reportBuildersForGREP.values());
Map<String, ReportInfo> outFilenames = createReportsForTask(sessionIds, reportBuildersForGREP.values());
sendReportsToGateway(sessionIds, outFilenames, ReportType.REPORT_KS_TMP.getKey());
return null;
@ -244,7 +244,7 @@ public class ReportService extends QueueConsumer implements InitializingBean {
} else {
sessionIds = getSessionIdsForDate(LocalDate.now());
}
Map<String, ReportKeys> outFilenames = createReportsForTask(sessionIds, reportBuildersForGRET.values());
Map<String, ReportInfo> outFilenames = createReportsForTask(sessionIds, reportBuildersForGRET.values());
sendReportsToGateway(sessionIds, outFilenames, null);
return null;
@ -265,35 +265,36 @@ public class ReportService extends QueueConsumer implements InitializingBean {
} else {
sessionIds = getSessionIdsForDate(LocalDate.now());
}
Map<String, ReportKeys> outFilenames = createReportsForTask(sessionIds, reportBuildersForGREF.values());
Map<String, ReportInfo> outFilenames = createReportsForTask(sessionIds, reportBuildersForGREF.values());
sendReportsToGateway(sessionIds, outFilenames, ReportType.REPORT_KS_FINAL.getKey());
return null;
}
private Map<String, ReportKeys> createReportsForTask(List<Long> sessionIds, Collection<List<CSVReportBuilder<?, ?>>> buildersForTask) {
Map<String, ReportKeys> outFilenames = new HashMap<>();
private Map<String, ReportInfo> createReportsForTask(List<Long> sessionIds, Collection<List<CSVReportBuilder<?, ?>>> buildersForTask) {
Map<String, ReportInfo> outFilenames = new HashMap<>();
int cntErrors = 0;
for (List<CSVReportBuilder<?, ?>> builders : buildersForTask) {
for (CSVReportBuilder<?, ?> builder : builders) {
ReportInfo reportInfo = new ReportInfo(builder.getReportKey().getKey(), builder.getSection());
if (builder.getParamsClass() == EmptyParams.class) {
File outFile = ((CSVReportBuilder<EmptyParams, ?>) builder).createReport(new EmptyParams(), outFolder);
if (outFile == null) {
log.warn("Something wrong, report type: {}", builder.getReportType().getKey());
log.warn("Something wrong for {}", reportInfo);
cntErrors++;
continue;
}
outFilenames.put(outFile.getName(), builder.getReportKey());
outFilenames.put(outFile.getName(), new ReportInfo(builder.getReportKey().getKey(), builder.getSection()));
} else if (builder.getParamsClass() == SessionIdParam.class) {
SessionIdParam sessionIdParam = new SessionIdParam();
sessionIdParam.setSessionId(sessionIds);
File outFile = ((CSVReportBuilder<SessionIdParam, ?>) builder).createReport(sessionIdParam, outFolder);
if (outFile == null) {
log.warn("Something wrong, report type: {}", builder.getReportType().getKey());
log.warn("Something wrong for {}", reportInfo);
cntErrors++;
continue;
}
outFilenames.put(outFile.getName(), builder.getReportKey());
outFilenames.put(outFile.getName(), reportInfo);
}
}
}
@ -303,15 +304,19 @@ public class ReportService extends QueueConsumer implements InitializingBean {
return outFilenames;
}
private void sendReportsToGateway(List<Long> sessionIds, Map<String, ReportKeys> reportsWithReportType, String type) {
private void sendReportsToGateway(List<Long> sessionIds, Map<String, ReportInfo> reportsWithReportType, String type) {
SendReportRequest sendReportRequest = new SendReportRequest();
sendReportRequest.setSessionId(sessionIds);
sendReportRequest.setType(type);
List<ReportPart> reports = new ArrayList<>(reportsWithReportType.size());
for (Map.Entry<String, ReportKeys> entry : reportsWithReportType.entrySet()) {
for (Map.Entry<String, ReportInfo> entry : reportsWithReportType.entrySet()) {
ReportInfo reportInfo = entry.getValue();
ReportPart reportPart = new ReportPart();
reportPart.setReportType(entry.getValue().getKey());
reportPart.setReportType(reportInfo.reportKey());
reportPart.setSection(reportInfo.section());
reportPart.setFileName(entry.getKey());
reports.add(reportPart);
}
sendReportRequest.setReports(reports);

View file

@ -601,6 +601,63 @@ public class ReportServiceTest_KS {
}
@Test
@Order(10)
public void createReportTest_KSCommissionReport() throws IOException, CsvValidationException {
clearTestDir();
ReportRequest reportRequest = new ReportRequest();
reportRequest.setReportId(ReportBuilderType.KS_COMMISSION_TRADES.getKey());
CompanySymbols companySymbols = new CompanySymbols();
companySymbols.setCompanyId(COMPANY_ID);
companySymbols.setCompanySymbol(CompanySymbol.INTC.getKey());
companySymbols.setCompanySymbolValue("COMPANY_SYMBOL_VALUE");
companySymbolsImdg.insert(companySymbols);
Registry registry = new Registry();
registry.setRegistryStatus(RegistryStatus.OK.getKey());
registry.setCompanyId(COMPANY_ID);
registry.setRegistryCode("DM_T");
registry.setRegistryDesignation(RegistryDesignation.D.getKey());
registry.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
registry.setRegistryUnit(RegistryUnit.T.getKey());
registry.setBalance(BigDecimal.valueOf(77.777777777));
registry.setSecuritySymbol("SECURITY_SYMBOL");
registry.setClearingDate(LocalDate.of(1991, 1, 1));
registry.setRefundDate(LocalDate.now());
registry.setContract("CONTRACT");
registry.setClearingCode("CLEARING_CODE");
registryImdg.insert(registry);
Registry omtRegistry = new Registry();
omtRegistry.setRegistryCode("OM_T");
omtRegistry.setRegistryDesignation(RegistryDesignation.O.getKey());
omtRegistry.setRegistryInstrumentType(RegistryInstrumentType.M.getKey());
omtRegistry.setRegistryUnit(RegistryUnit.T.getKey());
omtRegistry.setContract("CONTRACT");
omtRegistry.setGroupId(23071877700L);
registryImdg.insert(omtRegistry);
String jsonString = TestUtils.getJsonStringForSystem(reportRequest, 0L);
TestUtils.addRecordToKafka((MockConsumer) reportService.getConsumer(),
Consts.CREATE_REPORT,
reportRequestCnt++,
0,
jsonString);
TestUtils.waitingSendAndCheckRecord(0L, producer);
File outFile = outFolder.listFiles()[0];
File expectedFile = new File(getClass().getClassLoader().getResource("expected_reports_csv/ks/KS_COMMISSION_TRADES_expected.csv").getFile());
compareCSVFiles(expectedFile, outFile, Arrays.asList("SUM_DATE"));
registryImdg.delete(registry);
registryImdg.delete(omtRegistry);
companySymbolsImdg.insert(companySymbols);
}
private void compareCSVFiles(File expectedFile, File actualFile, List<String> columnsForSkip) throws IOException, CsvValidationException {
if (columnsForSkip == null) columnsForSkip = Collections.emptyList();

View file

@ -0,0 +1,2 @@
"FIRMID","FIRM_INITIATOR","SECCODE","AGREEMENT_NUMBER","AGREEMENT_NUMBER_PREFIX","AGREEMENT_DATE","SUM","SUM_DATE"
"CLEARING_CODE","COMPANY_SYMBOL_VALUE","SECURITY_SYMBOL","SECURITY_SYMBOL/010191/CLEARING_CODE777","","01.01.1991","77.78","18.07.2023"
1 FIRMID FIRM_INITIATOR SECCODE AGREEMENT_NUMBER AGREEMENT_NUMBER_PREFIX AGREEMENT_DATE SUM SUM_DATE
2 CLEARING_CODE COMPANY_SYMBOL_VALUE SECURITY_SYMBOL SECURITY_SYMBOL/010191/CLEARING_CODE777 01.01.1991 77.78 18.07.2023

View file

@ -18,6 +18,7 @@ public enum ReportBuilderType implements IEnumKey {
KS_REP_DEPO_NETTO("ks_rep_depo_netto"),
KS_REP_FIRM_DETAILS("ks_rep_firm_details"),
KS_SESSION_LIST("ks_session_list"),
KS_COMMISSION_TRADES("KS_COMMISSION_TRADES_"),
;
private final String key;

View file

@ -18,6 +18,7 @@ public enum ReportKeys implements IEnumKey {
KS_REP_DEPO_NETTO("KS_REP_DEPO_NETTO"),
KS_REP_FIRM_DETAILS("KS_REP_FIRM_DETAILS"),
KS_SESSION_LIST("KS_SESSION_LIST"),
KS_COMMISSION_TRADES("KS_COMMISSION_TRADES"),
;
private final String key;

View file

@ -9,6 +9,9 @@ public class ReportPart {
@JsonProperty
public String fileName;
@JsonProperty
public String section;
public String getReportType() {
return reportType;
}
@ -24,4 +27,12 @@ public class ReportPart {
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
}