Skip to content
Snippets Groups Projects
Commit ca1ee0cc authored by OZGCloud's avatar OZGCloud
Browse files

OZG-4865 use nachricht text from Smartdocuments

parent 5e73f606
Branches
Tags
No related merge requests found
...@@ -81,6 +81,13 @@ ...@@ -81,6 +81,13 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!--dev tools--> <!--dev tools-->
<dependency> <dependency>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
......
package de.ozgcloud.bescheid; package de.ozgcloud.bescheid;
import java.io.File; import java.io.File;
import java.util.Optional;
import de.ozgcloud.bescheid.vorgang.Vorgang; import de.ozgcloud.bescheid.vorgang.Vorgang;
import de.ozgcloud.bescheid.vorgang.VorgangId; import de.ozgcloud.bescheid.vorgang.VorgangId;
...@@ -25,5 +26,8 @@ public class Bescheid { ...@@ -25,5 +26,8 @@ public class Bescheid {
private String contentType; private String contentType;
private long size; private long size;
@Builder.Default
private Optional<String> nachrichtText = Optional.empty();
private Vorgang.ServiceKonto serviceKonto; private Vorgang.ServiceKonto serviceKonto;
} }
package de.ozgcloud.bescheid.smartdocuments; package de.ozgcloud.bescheid.smartdocuments;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Optional;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
...@@ -12,6 +20,8 @@ import org.springframework.stereotype.Service; ...@@ -12,6 +20,8 @@ import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyExtractors; import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
...@@ -21,6 +31,8 @@ import de.ozgcloud.bescheid.Bescheid; ...@@ -21,6 +31,8 @@ import de.ozgcloud.bescheid.Bescheid;
import de.ozgcloud.bescheid.BescheidRemoteService; import de.ozgcloud.bescheid.BescheidRemoteService;
import de.ozgcloud.bescheid.BescheidRequest; import de.ozgcloud.bescheid.BescheidRequest;
import de.ozgcloud.bescheid.common.callcontext.UserProfile; import de.ozgcloud.bescheid.common.callcontext.UserProfile;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsBescheidRemoteService.SmartDocumentsResponse.SmartDocumentDocument;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsBescheidRemoteService.SmartDocumentsResponse.SmartDocumentFile;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData; import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.BescheidData; import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.BescheidData;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.UserData; import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.UserData;
...@@ -40,6 +52,9 @@ import reactor.core.publisher.Mono; ...@@ -40,6 +52,9 @@ import reactor.core.publisher.Mono;
@ConditionalOnProperty("ozgcloud.bescheid.smart-documents.url") @ConditionalOnProperty("ozgcloud.bescheid.smart-documents.url")
class SmartDocumentsBescheidRemoteService implements BescheidRemoteService { class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
@SuppressWarnings("deprecation") // SD requires forced UTF-8 encoding
private static final MediaType JSON_MEDIA_TYPE_FOR_SD = MediaType.APPLICATION_JSON_UTF8;
@Autowired @Autowired
@Qualifier("smartDocuments") @Qualifier("smartDocuments")
private WebClient smartDocumentsWebClient; private WebClient smartDocumentsWebClient;
...@@ -53,7 +68,7 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService { ...@@ -53,7 +68,7 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
LOG.debug(() -> buildLogRequest(sdRequest)); LOG.debug(() -> buildLogRequest(sdRequest));
return smartDocumentsWebClient.post().accept(MediaType.APPLICATION_JSON) return smartDocumentsWebClient.post().accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON_UTF8) .contentType(JSON_MEDIA_TYPE_FOR_SD)
.bodyValue(sdRequest) .bodyValue(sdRequest)
.retrieve() .retrieve()
.onStatus(HttpStatusCode::is4xxClientError, this::handleClientError) .onStatus(HttpStatusCode::is4xxClientError, this::handleClientError)
...@@ -85,16 +100,50 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService { ...@@ -85,16 +100,50 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
.bescheidFileName(smartDocumentsFile.getFilename()) .bescheidFileName(smartDocumentsFile.getFilename())
.size(smartDocumentsFile.getDocument().getData().length()) .size(smartDocumentsFile.getDocument().getData().length())
.contentType(MediaType.APPLICATION_PDF_VALUE) .contentType(MediaType.APPLICATION_PDF_VALUE)
.nachrichtText(getNachrichtText(smartDocumentsResponse))
.genehmigt(request.isGenehmigt()) .genehmigt(request.isGenehmigt())
.createdBy(request.getCreateFor().getId()) .createdBy(request.getCreateFor().getId())
.vorgangId(request.getVorgangId()) .vorgangId(request.getVorgangId())
.build(); .build();
} }
private SmartDocumentsResponse.SmartDocumentFile getSmartDocumentsFile(SmartDocumentsResponse response) { private SmartDocumentFile getSmartDocumentsFile(SmartDocumentsResponse response) {
return getSmartDocumentsFile(response, "PDF")
.orElseThrow(() -> new IllegalStateException("No PDF File in SmartDocuments Response found."));
}
Optional<String> getNachrichtText(SmartDocumentsResponse response) {
return getXMLFile(response).flatMap(this::extractTextFormXmlFile);
}
Optional<String> extractTextFormXmlFile(File xmlFile) {
var xPath = XPathFactory.newInstance().newXPath();
try {
var document = DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().parse(xmlFile);
var expr = xPath.compile("/root/SmartDocument/Fields/NachrichtenText/text()");
var text = (Text) expr.evaluate(document, XPathConstants.NODE);
return Optional.of(text.getTextContent());
} catch (XPathExpressionException | SAXException | IOException | ParserConfigurationException e) {
LOG.error("XML-Parsing error on extracting Nachricht-Text: {}", e.getMessage(), e);
} catch (ClassCastException e) {
LOG.error("Error on extraction Nachricht-Text. XPath return unexpected Type.", e);
} catch (RuntimeException e) {
LOG.error("Unexpected Error on extracting NachrichtText: {}", e.getMessage(), e);
}
return Optional.empty();
}
Optional<File> getXMLFile(SmartDocumentsResponse response) {
return getSmartDocumentsFile(response, "XML")
.map(SmartDocumentFile::getDocument)
.map(SmartDocumentDocument::getData);
}
Optional<SmartDocumentFile> getSmartDocumentsFile(SmartDocumentsResponse response, String fileType) {
return response.getFile().stream() return response.getFile().stream()
.filter(file -> file.getOutputFormat().equals("PDF")) .filter(file -> file.getOutputFormat().equals(fileType))
.findAny().orElseThrow(() -> new IllegalStateException("No PDF File in SmartDocuments Response found.")); .findFirst();
} }
SmartDocumentsRequest createRequest(BescheidRequest request, Vorgang vorgang) { SmartDocumentsRequest createRequest(BescheidRequest request, Vorgang vorgang) {
......
package de.ozgcloud.bescheid.smartdocuments; package de.ozgcloud.bescheid.smartdocuments;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.io.File;
import java.util.Optional;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Spy;
import de.ozgcloud.bescheid.BescheidRequestTestFactory; import de.ozgcloud.bescheid.BescheidRequestTestFactory;
import de.ozgcloud.bescheid.BescheidTestFactory; import de.ozgcloud.bescheid.BescheidTestFactory;
import de.ozgcloud.bescheid.common.callcontext.UserProfileTestFactory; import de.ozgcloud.bescheid.common.callcontext.UserProfileTestFactory;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.UserData; import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.UserData;
import de.ozgcloud.bescheid.vorgang.VorgangTestFactory; import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
import de.ozgcloud.common.binaryfile.TempFileUtils;
import de.ozgcloud.common.test.TestUtils;
class SmartDocumentsBescheidRemoteServiceTest { class SmartDocumentsBescheidRemoteServiceTest {
@Spy
@InjectMocks @InjectMocks
private SmartDocumentsBescheidRemoteService service; private SmartDocumentsBescheidRemoteService service;
...@@ -43,4 +52,37 @@ class SmartDocumentsBescheidRemoteServiceTest { ...@@ -43,4 +52,37 @@ class SmartDocumentsBescheidRemoteServiceTest {
.extracting(UserData::getEmail).isEqualTo(UserProfileTestFactory.EMAIL); .extracting(UserData::getEmail).isEqualTo(UserProfileTestFactory.EMAIL);
} }
} }
@Nested
class TestGetNachrichtText {
private File xmlFile = TempFileUtils.writeTmpFile(TestUtils.loadFile("SD_answer.xml"));
@Test
void shouldCallExtractText() {
doReturn(Optional.of(xmlFile)).when(service).getXMLFile(any());
service.getNachrichtText(SmartDocumentsResponseTestFactory.create());
verify(service).extractTextFormXmlFile(notNull());
}
@Nested
class ExtractingText {
@Test
void shouldReturnText() {
var text = service.extractTextFormXmlFile(xmlFile);
assertThat(text).isPresent().get().isNotNull();
}
@Test
void shouldHandleError() {
var text = service.extractTextFormXmlFile(null);
assertThat(text).isEmpty();
}
}
}
} }
This diff is collapsed.
...@@ -48,7 +48,7 @@ abstract class BayernIdPostfachNachrichtMapper { ...@@ -48,7 +48,7 @@ abstract class BayernIdPostfachNachrichtMapper {
@Mapping(target = "nachrichtenKopf.absender.gemeindeschluessel.schluessel", source = "bayernIdProperties.absender.gemeindeSchluessel") @Mapping(target = "nachrichtenKopf.absender.gemeindeschluessel.schluessel", source = "bayernIdProperties.absender.gemeindeSchluessel")
@Mapping(target = "nachrichtenKopf.empfaenger.postkorbId", source = "nachricht.postfachAddress") @Mapping(target = "nachrichtenKopf.empfaenger.postkorbId", source = "nachricht.postfachAddress")
@Mapping(target = "nachrichtenInhalt.betreff", source = "nachricht.subject") @Mapping(target = "nachrichtenInhalt.betreff", source = "nachricht.subject")
@Mapping(target = "nachrichtenInhalt.storkQaaLevel", constant = "LEVEL_1") @Mapping(target = "nachrichtenInhalt.storkQaaLevel", constant = "LEVEL_1") // FIXME aus Vorgang übernehmen
@Mapping(target = "nachrichtenInhalt.zuVorgang.vorgangsId", source = "nachricht.vorgangId") @Mapping(target = "nachrichtenInhalt.zuVorgang.vorgangsId", source = "nachricht.vorgangId")
@Mapping(target = "nachrichtenInhalt.freiText.encoding.schluessel", constant = TEXT_ENCODING_PLAIN_TEXT) @Mapping(target = "nachrichtenInhalt.freiText.encoding.schluessel", constant = TEXT_ENCODING_PLAIN_TEXT)
@Mapping(target = "nachrichtenInhalt.freiText.encoding.tabelle", constant = TABELLE_NUMMER_TEXT_ENCODING) @Mapping(target = "nachrichtenInhalt.freiText.encoding.tabelle", constant = TABELLE_NUMMER_TEXT_ENCODING)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment