From f069bab18a64a4eab2b016b6f63f7e2ebf69aae2 Mon Sep 17 00:00:00 2001 From: akulikov Date: Thu, 29 Dec 2022 14:00:35 +0300 Subject: [PATCH] RRPC, REX notification --- .../notifications/NotificationBuilder.java | 43 +++++++ .../notifications/REXNotificationBuilder.java | 106 +++++++++++++++++ .../RRPCNotificationBuilder.java | 112 ++++++++++++++++++ .../reports/services/DOCXService.java | 72 +++++++---- .../reports/services/QCommandExecutor.java | 2 + .../resources/templates/REX_TEMPLATE.docx | Bin 0 -> 10193 bytes .../resources/templates/RRPC_TEMPLATE.docx | Bin 0 -> 10517 bytes .../reports/services/DOCXServiceTest.java | 5 +- .../cud/reports/NotificationRequest.java | 23 ++++ 9 files changed, 338 insertions(+), 25 deletions(-) create mode 100644 clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/NotificationBuilder.java create mode 100644 clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/REXNotificationBuilder.java create mode 100644 clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/RRPCNotificationBuilder.java create mode 100644 clearing-parent/reports-service/src/main/resources/templates/REX_TEMPLATE.docx create mode 100644 clearing-parent/reports-service/src/main/resources/templates/RRPC_TEMPLATE.docx create mode 100644 platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/reports/NotificationRequest.java diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/NotificationBuilder.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/NotificationBuilder.java new file mode 100644 index 000000000..cc212b236 --- /dev/null +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/NotificationBuilder.java @@ -0,0 +1,43 @@ +package ru.spcex.clearing.reports.notifications; + +import ru.spcex.clearing.reports.exceptions.ConfigException; +import ru.spcex.clearing.reports.services.DOCXService; + +import java.io.File; +import java.net.URL; +import java.time.format.DateTimeFormatter; + +public abstract class NotificationBuilder { + protected final DateTimeFormatter filenameDateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy'T'HH:mm:ss"); + protected final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + protected final DOCXService docxService; + + protected NotificationBuilder(String keyPattern) { + this.docxService = new DOCXService(); + if (!docxService.init(getTemplateFile(), keyPattern)) + throw new ConfigException("Can't create NotificationBuilder: docxService not initialized"); + } + + abstract public File buildNotification(Long consumerId); + + protected File getTemplateFile() { + File templateFile; + String templateResourceName = getTemplateResourceName(); + try { + URL resource = getClass().getClassLoader().getResource(templateResourceName); + if (resource == null) throw new Exception(); + templateFile = new File(resource.toURI()); + } catch (Exception e) { + throw new ConfigException("Can't read template resource " + templateResourceName, e); + } + return templateFile; + } + + protected String normalizeFilenameForOS(String filename) { + if (System.getProperty("os.name").toLowerCase().contains("windows")) + return filename.replace(":", "_"); + return filename; + } + + abstract protected String getTemplateResourceName(); +} diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/REXNotificationBuilder.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/REXNotificationBuilder.java new file mode 100644 index 000000000..e53754c09 --- /dev/null +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/REXNotificationBuilder.java @@ -0,0 +1,106 @@ +package ru.spcex.clearing.reports.notifications; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.profile.ProfileDocument; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +import java.io.File; +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Component +public class REXNotificationBuilder extends NotificationBuilder { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Imdg profileDocumentImdg; + private final Imdg companyImdg; + + public REXNotificationBuilder(ImdgProvider imdgProvider) { + super(null); + profileDocumentImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class); + companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + } + + @Override + public File buildNotification(Long consumerId) { + String sql = "companyId = %d AND documentType = 'XCNT'".formatted(consumerId); + Collection profileDocuments = profileDocumentImdg.getCollectionObjectsBySQL(sql); + ProfileDocument currentProfileDocument = null; + if (profileDocuments.size() >= 1) { + Optional profileDocumentOptional = profileDocuments.stream().max((o1, o2) -> { + LocalDate o1ValidFromDate = o1.getValidFromDate(); + LocalDate o2ValidFromDate = o2.getValidFromDate(); + o1ValidFromDate = o1ValidFromDate == null ? LocalDate.MIN : o1ValidFromDate; + o2ValidFromDate = o2ValidFromDate == null ? LocalDate.MIN : o2ValidFromDate; + return o1ValidFromDate.compareTo(o2ValidFromDate); + }); + currentProfileDocument = profileDocumentOptional.get(); + } else { + log.warn("Profile_document with sql {} not found", sql); + return null; + } + + Long notificationId = currentProfileDocument.getId(); + LocalDate validFromDate = currentProfileDocument.getValidFromDate(); + if (validFromDate == null) { + log.error("validFromDate is null for profile_document {}", currentProfileDocument); + return null; + } + Long companyId = currentProfileDocument.getCompanyId(); + if (companyId == null) { + log.error("companyId is null for profile_document {}", currentProfileDocument); + return null; + } + Company company = companyImdg.getSingleObjectByID(companyId); + if (company == null) { + log.error("Company for companyId={} is null", companyId); + return null; + } + String companyClearingCode = company.getClearingCode(); + if (StringUtils.isBlank(companyClearingCode)) { + log.error("Company.clearing_code for companyId={} is null", companyId); + return null; + } + + LocalDate notificationDate = LocalDate.now(); + int day = notificationDate.getDayOfMonth(); + int month = notificationDate.getMonthValue(); + int year = notificationDate.getYear(); + String dateStr = "%02d%02d%04d".formatted(day, month, year); + + Map valuesForTemplate = new HashMap<>(); + valuesForTemplate.put("${dateStr}", dateStr); + valuesForTemplate.put("${count}", String.valueOf(notificationId)); + valuesForTemplate.put("${currDay}", "%02d".formatted(day)); + valuesForTemplate.put("${currMonth}", "%02d".formatted(month)); + valuesForTemplate.put("${currYear}", "%04d".formatted(year % 100)); + valuesForTemplate.put("${validFromDate}", "%02d.%02d.%04d".formatted(day, month, year)); + + String outputFilename = "REX.%s.%s.docx".formatted(companyClearingCode, filenameDateTimeFormatter.format(notificationDate)); + outputFilename = normalizeFilenameForOS(outputFilename); + + File outputFile = new File(outputFilename); + try { + docxService.insertValues(outputFile, valuesForTemplate, true); + } catch (Exception e) { + log.error("Can't insert values into template.", e); + return null; + } + + return outputFile; + } + + @Override + protected String getTemplateResourceName() { + return "templates/REX_TEMPLATE.docx"; + } + +} diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/RRPCNotificationBuilder.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/RRPCNotificationBuilder.java new file mode 100644 index 000000000..46ff76f60 --- /dev/null +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/notifications/RRPCNotificationBuilder.java @@ -0,0 +1,112 @@ +package ru.spcex.clearing.reports.notifications; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import ru.clearing.classes.objects.BusinessObject; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.CompanySymbols; +import ru.clearing.classes.statics.data.company.relation.Relation; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +import java.io.File; +import java.time.Instant; +import java.time.LocalDate; +import java.util.*; + +@Component +public class RRPCNotificationBuilder extends NotificationBuilder { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Imdg companyImdg; + private final Imdg relationImdg; + private final Imdg companySymbolsImdg; + + public RRPCNotificationBuilder(ImdgProvider imdgProvider) { + super(null); + companyImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Company, Company.class); + relationImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); + companySymbolsImdg = imdgProvider.getImdg(IMDGDistributedNames.Map_CompanySymbols, CompanySymbols.class); + } + + @Override + public File buildNotification(Long consumerId) { + Company company = companyImdg.getSingleObjectByID(consumerId); + if (company == null) { + log.error("Company for companyId={} is null", consumerId); + return null; + } + String companyClearingCode = company.getClearingCode(); + if (StringUtils.isBlank(companyClearingCode)) { + log.error("Company.clearing_code for companyId={} is null", consumerId); + return null; + } + + String relationsSql = "consumerId = %d".formatted(consumerId); + Relation relation = null; + Collection relations = relationImdg.getCollectionObjectsBySQL(relationsSql); + if (relations.size() >= 1) { + Optional relationOptional = relations.stream().max(Comparator.comparing(BusinessObject::getUpdated)); + relation = relationOptional.get(); + } else { + log.warn("Relation with sql {} not found", relationsSql); + return null; + } + Long notificationId = relation.getId(); + Instant updatedAt = relation.getUpdated(); + if (updatedAt == null) { + log.error("updated_at is null for relation {}", relation); + return null; + } + + String companySymbolsSql = "companyId = %d AND companySymbol = INN"; + CompanySymbols companySymbols = null; + Collection companySymbolsCollection = companySymbolsImdg.getCollectionObjectsBySQL(companySymbolsSql); + if (companySymbolsCollection.size() >= 1) { + companySymbols = companySymbolsCollection.iterator().next(); + } else { + log.warn("CompanySymbols with sql {} not found", companySymbolsSql); + return null; + } + + LocalDate notificationDate = LocalDate.now(); + int day = notificationDate.getDayOfMonth(); + int month = notificationDate.getMonthValue(); + int year = notificationDate.getYear(); + String dateStr = "%02d%02d%04d".formatted(day, month, year); + + Map valuesForTemplate = new HashMap<>(); + valuesForTemplate.put("${dateStr}", dateStr); + valuesForTemplate.put("${count}", String.valueOf(notificationId)); + valuesForTemplate.put("${currDay}", "%02d".formatted(day)); + valuesForTemplate.put("${currMonth}", "%02d".formatted(month)); + valuesForTemplate.put("${currYear}", "%04d".formatted(year % 100)); + + valuesForTemplate.put("${relationUpdatedAt}", dateFormatter.format(updatedAt)); + valuesForTemplate.put("${companyFullName}", company.getFullName()); + valuesForTemplate.put("${companyShortName}", company.getShortName()); + valuesForTemplate.put("${companySymbolsINN}", companySymbols.getCompanySymbolValue()); + valuesForTemplate.put("${companyClearingCode}", companyClearingCode); + + String outputFilename = "RRPC.%s.%s.docx".formatted(companyClearingCode, filenameDateTimeFormatter.format(notificationDate)); + outputFilename = normalizeFilenameForOS(outputFilename); + + File outputFile = new File(outputFilename); + try { + docxService.insertValues(outputFile, valuesForTemplate, true); + } catch (Exception e) { + log.error("Can't insert values into template.", e); + return null; + } + + return outputFile; + } + + @Override + protected String getTemplateResourceName() { + return "templates/RRPC_TEMPLATE.docx"; + } + +} diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/DOCXService.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/DOCXService.java index 86483a38b..02e1813eb 100644 --- a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/DOCXService.java +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/DOCXService.java @@ -2,6 +2,7 @@ package ru.spcex.clearing.reports.services; import org.apache.poi.xwpf.usermodel.*; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.*; import java.util.LinkedList; @@ -10,6 +11,7 @@ import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; /** @@ -22,58 +24,86 @@ import java.util.stream.Collectors; * идентификатору потом можно установить стиль, который будет применён к вставляемой строке. */ public class DOCXService { + private final Logger log = LoggerFactory.getLogger(getClass()); /** * При инициализации сохраняет все имеющиеся ключи (ищет по маске keyPattern), найденные в текстовых элементах документа */ private List keyPositions = new LinkedList<>(); + /** + * Паттерн поиска ключей в файле по умолчанию + */ + private final Pattern DEFAULT_KEY_PATTERN = Pattern.compile("\\$\\{.*?}"); + /** * Паттерн поиска ключей в файле */ - private Pattern KEY_PATTERN = Pattern.compile("\\$\\{.*?}"); + private Pattern keyPattern = DEFAULT_KEY_PATTERN; + + /** + * Файл шаблона + */ + private File templateFile; + + /** + * Флаг инициализации + */ + private boolean initialized = false; /** * (ре)Инициализация сервиса */ - public void init(String keyPattern) { - KEY_PATTERN = Pattern.compile(keyPattern); + public boolean init(File templateFile, String keyPattern) { + initialized = false; + if (templateFile == null || !templateFile.exists() || !templateFile.isFile()) { + log.warn("Invalid templateFile"); + return false; + } + this.templateFile = templateFile; + if (keyPattern != null) { + try { + this.keyPattern = Pattern.compile(keyPattern); + } catch (PatternSyntaxException e) { + log.warn("Invalid keyPattern"); + return false; + } + } else { + this.keyPattern = DEFAULT_KEY_PATTERN; + } keyPositions = new LinkedList<>(); + initialized = true; + return true; } /** * Вставка значений в шаблон. Шаблон может содержать любое количество ключей, при этом эти ключи должны содержаться в * valuesMap. * - * @param templateFile Файл шаблона * @param outputFile Выходной файл. Должен быть либо файлом (будет перезаписан), либо отсутствовать * @param valuesMap Мапа значений. В файле шаблона будут искаться ключи этой мапы и заменяться на соответствующие значения. - * @param log Если будет передан null, то метод будет выбрасывать исключения. В противном случае будет записан лог и возвращено false * @param checkKeys True - строгий режим, где будет проверено наличие всех ключей из файла в valuesMap. * False - мягкий режим, отсутствующие ключи будут пропущены * * @return true - если вставка прошла успешно */ - public boolean insertValues(File templateFile, - File outputFile, + public boolean insertValues(File outputFile, Map valuesMap, - Logger log, boolean checkKeys) throws Exception { - assert templateFile != null && templateFile.exists() && templateFile.isFile(); + if (!initialized) { + log.warn("DOCXService not initialized"); + return false; + } if (outputFile == null || outputFile.isDirectory()) { - String logMsg = "Can't open output file. Output file: %s".formatted(outputFile == null ? "null" : outputFile.getAbsolutePath()); - if (log == null) throw new Exception(logMsg); - log.error(logMsg); + log.error("Can't open output file. Output file: {}", outputFile == null ? "null" : outputFile.getAbsolutePath()); return false; } if (outputFile.exists()) { - if (log != null) log.warn("Output file {} exist and will be overwritten", outputFile.getAbsolutePath()); + log.warn("Output file {} exist and will be overwritten", outputFile.getAbsolutePath()); boolean deleteOk = outputFile.delete(); if (!deleteOk) { - String logMsg = "Can't delete file %s".formatted(outputFile.getAbsolutePath()); - if (log == null) throw new Exception(logMsg); - log.error(logMsg); + log.error("Can't delete file {}", outputFile.getAbsolutePath()); return false; } } @@ -94,11 +124,9 @@ public class DOCXService { List notPresentInMap = new LinkedList<>(); boolean checkOk = checkIntersection(valuesMap, notPresentInMap); if (!checkOk) { - String logMsg = "Can't insert values in file %s. Keys not in map: %s." - .formatted(templateFile.getAbsolutePath(), - String.join(", ", notPresentInMap)); - if (log == null) throw new Exception(logMsg); - log.error(logMsg); + log.error("Can't insert values in file {}. Keys not in map: {}.", + templateFile.getAbsolutePath(), + String.join(", ", notPresentInMap)); return false; } } @@ -178,7 +206,7 @@ public class DOCXService { for (int currPos = 0; currPos < MAX_POSITION; currPos++) { String currText = run.getText(currPos); if (currText == null) break; - Matcher matcher = KEY_PATTERN.matcher(currText); + Matcher matcher = keyPattern.matcher(currText); while (matcher.find()) { String key = matcher.group(); keyPositions.add(new KeyPositionInDoc(key, run, currPos)); diff --git a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/QCommandExecutor.java b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/QCommandExecutor.java index 90b95ed39..3d5e55548 100644 --- a/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/QCommandExecutor.java +++ b/clearing-parent/reports-service/src/main/java/ru/spcex/clearing/reports/services/QCommandExecutor.java @@ -23,6 +23,7 @@ import java.util.Map; public class QCommandExecutor extends QueueConsumer implements InitializingBean { private final Logger log = LoggerFactory.getLogger(getClass()); private final Map collectorForReport = new HashMap<>(); + // private final ImdgId idGenerator; // private final KafkaSender kafkaReqProducer; @@ -71,4 +72,5 @@ public class QCommandExecutor extends QueueConsumer implements InitializingBean } log.debug("successfully processed"); } + } diff --git a/clearing-parent/reports-service/src/main/resources/templates/REX_TEMPLATE.docx b/clearing-parent/reports-service/src/main/resources/templates/REX_TEMPLATE.docx new file mode 100644 index 0000000000000000000000000000000000000000..363dc25682bd2d347e95ab064f450805b0c29b86 GIT binary patch literal 10193 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 z z22QVcM!%)d6=zo-#bC`ws$O21+hnioB*V;T21O?QGjLR(TE7KO2k3;iJ;soe`?+^W zP;fm}Y}Gt%j;bjZJ9Xrza~!2fYfQZ+n6Q9K#^~=q=N9xk$6uzMDsF?^lhL0`zC{tY zu0&m)eX%?&GeeUY=a5{s3s1TOe)VeEE4CFp3l`esO{2;RkoU3k=bXiO=L6*(hu@)z zRTL2Y6h|e5k3u`hDx=QMdy`_iW4F}-fcnva^VlSLVC=U0Yr!Wrc1?R#RF6R?2^q_aqp1{-`OE4vs-Q=Cz=e^KuJ@5zh%po&B#zaHv0d{ool@)A?OqQyi}! z`fIXH=ZD~sA_61GNAW_E3*dz=++0{OK1R=v@cvb#7JPv(wFV%_8HU5l8J?i!M{K;L z-zs04`^6hZE*;D!?=LLZ+%1DeNHnLe;PC7H^x3Qx{miTR#8JqvFZJI zY)*|vunH-gxrZjo-bR*7(YAJ~3RpS$dob8+IXGR8n(r+JXZ%0nZ{*^eVRxdM4-Wei z;jiVonqnV2Ia#|Kx6E26lOG%aKr;pi5Ib8_#YvtG@%W;Czu#mEgA~GJ!2t-#+p=^`0h=+VFAOfYSaj~v_lbj8O z?NC58sAL>q9fd2Q_p645R5Rz8ok->VpBU98tsH-d;;9JF7+kc!g5(AaU)jBa{2?d` zKzr3*c*WvoCT7owNG}zUb>Y{+Fe6yKsniMp{P52ZsL}n(sQ`fLs8IG+ZjcA$8k$dk zFGy9X(H;D$KnKdbT$rP*^_uxD7m_ti)f*Q`7+>?+6~*pn_sRnl3aqAOvR`mn z#^EZ`O^b%UR@zJccwr>}@^p%lrBvBC`lV_<=LKRXvsswK@rp~CBB0Q%`xo@rOO=3M z(BEJB|2Whe4^aQXo<+>8AolKBg+X(0{!U(Nzi+QAXm@mt)jWP&BL#Y=DAIeQBKtO> zeTm&7P_Y%R@FCLN(y3GGS*=xYUmXI-(-zDgo3WDG_Pwx@?i(%Dv9+AaImNE)AaK^T zf_56Y=0_d=rN7Hv^){^sJvzhckM13+aQWcE0}=OA8q@w=qxqvsjOVr!@N*l#qOd)_ z@uU++d~SjsEN7c|d*q+|PyDwL8r&E~))_#j+5^1G!n}D__ULWY`o>GV*;02k|G^z! z`?IE!$@zA+(71FKy8<3+TZ9;f4Cckho9n(b!spAI)jo}>HjhG&Pgq})-cS36ORF^t z-cFJZ9YNZU;(m5WF5|&&D^u^#_m{+Y+jXYki{PLl)a4g{R`0kq8!Z%wiovpKs=8C@ zjFWzCVBb3{ZH*6)>C6^+s@L8!L}fYQgG<3}xNGvI^AJ>vb(F(hB7DEcVRSd^F_7hL z=z(yPN*Z~(Q`5H zM#04G3`*k9omc_+{ouXU{L?)GC)1o9`LQo1`!jDevvFW#YTnG$G zXQHL(2d%>-LMlFG#mVK<+POFO~5-CgYqsVVkG=X7tgPsASdwlE7M~RF4P^!2Xs5Pf;to!F&~l7DZ@|k<}NDE z%=o^JMy^?rw7dJZyhfYU!`5pTe(dCa%#;6@lVqJ&-tZ|o~^Bsxxufk zWsPiy`644i%QX$cGF}sSEe2moW?VX6EaKM*WKG&eqIZE{LbEn)?jcp_Jy3@-7vy`~ zz_ZAyk)tx~LW*eqWMzjMLsh>59m%~4JLIOz?V6$>ejp0F)&V)~vAvxYGd+AEZjoFp zQOx#SqmQxrjNKj*b_OlG4pXr~V7h%wpR?|nQhk>U?Faumfl1dw5-DpM!0j-8kyU~; zhq&?fhtQ&M&ptx`bj~@8m@4Vich$!>Hg4WpQmtt~&^P(F?3>i!sW1e62zS;Csm5&D z-iDMPTRnWg>oOdgsYO6N>Oc5@b>NloSuF(B1N;2b^^(q@D7>+ zrB}1!LA*A4YyEut8b+^SR#+cG8!r!7WZ+Xot`T?8^b--{KD`a&gAqD`<2wke<92%U z7`5?WqR{rstGC_`mTdi^Fz0`C`(XU>d)ON4ndve7%HO}92OKFa1}zF>zj*dwmN_{9 zS7;XHdYnd8Nxp~VWN|u9v|qR;utyvnzQFj7$Xh7G8SM#yn^`zZi(w^BNa5bW{a~gg zt==?Ayyd<4>>XNbS0QJ|B4=bq+olP~PaLDUDR5XDKUgPgSpm%s}B z{l=mm5VFGWp4ckd9)9W-aH#Lm|1A*df1A)B~wF#%*ylFhT|W1k>pZiOZ9T@7p8j1ncZiyvUQq< zmT1lne3ES{;Iq)&u{WAa!CR=+X$o!ds5)&6GI24hJNogs4T1vUy3-3cV>FXUXAp$J zD{ z92v}f7d)hqO2%Fa`^=9W0yd*riS07X{A~5mWH*P4UlSgzqtOuVrRl5CsK8>)plZTSC#bP;^_N8=fE{`O*%7ZSufd2r}??^E-XadsN;` zAre@s&%F91e0554{2F-R2&DDow0&pxgWCd7&0LKt#LZYaB>trBMbfHZ$7tS3q%lAC zj9Fu`{iM+bp(RC#kI6xxD=QvzXzN4-T9G4$bKZ8Kjo`)S;rlXri4WZMgYXB=6Znc* zEer99QSLEsBgrI!hzeAOH;S9vLiTVm=-}|Bp2(QmThM&*);m@?O%K^}0oP0b1OT*} z5rh%CWqRNB5?e!;e-^g3NQTPslN!3=^4Hg zI0oSt)D1>>faw;XGKdx=z7pVA1E5o~!9;z3w@vVU+KG_2l6AQbRo9}n&cX`kJ3~aV zLG)lP1nKr8d#@Wv)ZU)d#3eS_Gc^zZJWft)wn23}yWF&ix)=#|A`zNcuBKf-upH_< zimLv$;|l z*3GVmI*~arwZ&iyH?tG8`ohab#KlCHhoc5x5i@Re;oia!r8FWHFp);5VeBif-YPK% zIf#}SvV_bp)3AY8N9yJLaweei;GSIeI!b( zN`h}W0?C-q&He(|tX7%lF(?>v_=W)-2RSKd+(B1*L#D_utz)p>IfhIu?>pkzhK! z)@q-rrY&qPvm`!p16V2$kw`c*>=RI{afw-g5mNRsSAtxj=$#v0Nm0`t3!%qt88>18 zB&RV|(ATseaw&o+cObbKM)zRO`xEF##iIPm@$6Zx_Me)@zZ;f*7f06?q#F7*1a2ymi=m)TD^mq!pU-K z#J-A+U5FBp)6^)haQ+K$+K6VUhM$#y}bA6F9*!!xc_7a zyn3%y1YRtz7uT+aoRg)VjoRy?(h~E_>=L?u4C+^juGjNI5nF%^C$p8F>7R?5LiwcI zl=JA)D=J5Xo*0YC8o80+GRj3vk!B{BQrzKWWXnfBA5WUzfGVR1>7>q;J*&$~upL|i znWkBK1*zn(X+e4E3LA7g{B;bQDpZzst*9tp?;%B=m!WTyW-t^fT>v)|I$_5_s#2cd z`#mCIooaN{R_#b|zBi+Z$$(NjW2p2(k&V&Ynm0>3qT@>ajNB#1l;GHVLy>vMz7Xx2}AoG_q)%Xrwz~3u_;U*z{95g!jh<68jRhD|<H0;czxw`n md-Crre*ZN8sz?cv|8?$=0zkfq6$AwSwMYY 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 literal 0 HcmV?d00001 diff --git a/clearing-parent/reports-service/src/test/java/ru/spcex/clearing/reports/services/DOCXServiceTest.java b/clearing-parent/reports-service/src/test/java/ru/spcex/clearing/reports/services/DOCXServiceTest.java index 528d64be2..ffd640744 100644 --- a/clearing-parent/reports-service/src/test/java/ru/spcex/clearing/reports/services/DOCXServiceTest.java +++ b/clearing-parent/reports-service/src/test/java/ru/spcex/clearing/reports/services/DOCXServiceTest.java @@ -19,10 +19,9 @@ class DOCXServiceTest { valuesMap.put("${test3}", "======== TEST 3 ========="); DOCXService service = new DOCXService(); - service.insertValues(new File(getClass().getClassLoader().getResource("REC.ACTV_TEST.docx").getPath()), - new File("output.docx"), + service.init(new File(getClass().getClassLoader().getResource("REC.ACTV_TEST.docx").getPath()), null); + service.insertValues(new File("output.docx"), valuesMap, - null, false); File file = new File("output.docx"); diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/reports/NotificationRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/reports/NotificationRequest.java new file mode 100644 index 000000000..f09103e1d --- /dev/null +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/reports/NotificationRequest.java @@ -0,0 +1,23 @@ +package ru.spcex.clearing.platform.messaging.domain.cud.reports; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Запрос на формирование уведомления + */ +public class NotificationRequest { + /** + * Идентификатор участника клиринга + */ + @JsonProperty + protected String consumerId; + + + public String getConsumerId() { + return consumerId; + } + + public void setConsumerId(String consumerId) { + this.consumerId = consumerId; + } +}