diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteService.java index b802c22a4c05327040d6ecb17440c889ddc9632b..a15cc77ef67b28a92b84309856aef6f3e4aea9d3 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteService.java @@ -24,6 +24,7 @@ package de.ozgcloud.nachrichten.postfach.muk.transfer; import static de.ozgcloud.nachrichten.postfach.muk.transfer.MukPostfachMessageMapper.*; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -36,8 +37,10 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.UUID; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.bson.types.ObjectId; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; @@ -67,20 +70,39 @@ import lombok.extern.log4j.Log4j2; @ConditionalOnProperty(prefix = MukPostfachProperties.PREFIX, name = { "server" }) public class ElsterTransferRemoteService { public static final String POSTFACH = "postfach"; - private final ElsterRestClient restClient; - private final MukPostfachProperties postfachProperties; - private final MukPostfachMessageMapper mapper; - private final MukOzgCloudFileMapper fileMapper; - private final AttachmentService attachmentService; - + public static final String VORGANG_ID_REFIX = "VorgangId["; public static final String ANTWORTEN_ENDPOINT = "/rest/eingang/antworten"; public static final String BEREITSTELLUNGS_ENDPUNKT = "/rest/bereitstellungsauftrag/v3"; public static final String BEREITSTELLUNG_UPLOAD_ENDPUNKT = "/rest/bereitstellungsauftrag/file-upload"; - static final Set<PostfachNachricht.ReplyOption> REPLY_POSSIBLE_OPTION = EnumSet.of(PostfachNachricht.ReplyOption.POSSIBLE, PostfachNachricht.ReplyOption.MANDATORY); static final Set<String> MITTEILUNG_DATENARTEN = Set.of(DATENART_KURZMITTEILUNG, DATENART_MITTEILUNG); static final Set<String> NACHRICHTEN_MIT_ANHANG = Set.of(DATENART_BESCHEID, DATENART_MITTEILUNG); + private final ElsterRestClient restClient; + private final MukPostfachProperties postfachProperties; + private final MukPostfachMessageMapper mapper; + private final MukOzgCloudFileMapper fileMapper; + private final AttachmentService attachmentService; + + private static boolean anhangNeedToBeUploaded(final BereitstellungAuftragNeuV3 bereitstellungAuftrag) { + return NACHRICHTEN_MIT_ANHANG.contains(bereitstellungAuftrag.getDatenart()); + } + + private static boolean isMitteilung(final BereitstellungAuftragNeuV3 bereitstellungAuftrag) { + return MITTEILUNG_DATENARTEN.contains(bereitstellungAuftrag.getDatenart()); + } + + private static boolean isReplyPossible(final PostfachNachricht nachricht) { + return REPLY_POSSIBLE_OPTION.contains(nachricht.getReplyOption()); + } + + static OzgCloudUploadFile createOzgCloudUploadFile(final DownloadAnhangDetails downloadAnhangDetails, final String vorgangId) { + return OzgCloudUploadFile.builder() + .fileName(downloadAnhangDetails.getDatei()) + .fieldName(POSTFACH) + .vorgangId(vorgangId) + .contentType(downloadAnhangDetails.getMimeType()).build(); + } public AuftragAngelegt send(PostfachNachricht nachricht) { var auftrag = createBereitstellungsAuftrag(nachricht); @@ -93,7 +115,8 @@ public class ElsterTransferRemoteService { bereitstellungAuftrag.setAbsender(getAbsender()); if (anhangNeedToBeUploaded(bereitstellungAuftrag)) { - bereitstellungAuftrag.setAnhaenge(nachricht.getAttachments().stream().map(fileId -> uploadAnhang(fileId, nachricht.getVorgangId())).toList()); + bereitstellungAuftrag.setAnhaenge( + nachricht.getAttachments().stream().map(fileId -> uploadAnhang(fileId, nachricht.getVorgangId())).toList()); } if (isMitteilung(bereitstellungAuftrag)) { @@ -107,18 +130,6 @@ public class ElsterTransferRemoteService { return bereitstellungAuftrag; } - private static boolean anhangNeedToBeUploaded(final BereitstellungAuftragNeuV3 bereitstellungAuftrag) { - return NACHRICHTEN_MIT_ANHANG.contains(bereitstellungAuftrag.getDatenart()); - } - - private static boolean isMitteilung(final BereitstellungAuftragNeuV3 bereitstellungAuftrag) { - return MITTEILUNG_DATENARTEN.contains(bereitstellungAuftrag.getDatenart()); - } - - private static boolean isReplyPossible(final PostfachNachricht nachricht) { - return REPLY_POSSIBLE_OPTION.contains(nachricht.getReplyOption()); - } - String getAbsender() { return postfachProperties.getSender(); } @@ -152,9 +163,17 @@ public class ElsterTransferRemoteService { BereitstellungAntwort createAntwort(PostfachNachricht nachricht) { var antwort = new BereitstellungAntwort(); // FIXME: nachricht needs to have a nachricht id already set. Needs to be fixed in de.ozgcloud.nachrichten.postfach.PostfachService or de.ozgcloud.nachrichten.postfach.PostfachEventListener.buildNachricht - antwort.setZuordnungskriterium(ObjectIdToUUIDConverter.toUUID(Objects.isNull(nachricht.getId()) ? ObjectId.get().toHexString() : nachricht.getId())); - antwort.setAntwortBetreffe(Set.of(postfachProperties.getReplySubjectPrefix() + nachricht.getSubject() + " VorgangId: " + nachricht.getVorgangId())); + if (Objects.isNull(nachricht.getId())) { + antwort.setZuordnungskriterium(Objects.isNull(nachricht.getId()) ? UUID.randomUUID() : ObjectIdToUUIDConverter.toUUID(nachricht.getId())); + antwort.setAntwortBetreffe( + Set.of(VORGANG_ID_REFIX + nachricht.getVorgangId() + "]" + postfachProperties.getReplySubjectPrefix() + nachricht.getSubject())); + } else { + antwort.setZuordnungskriterium(ObjectIdToUUIDConverter.toUUID(nachricht.getId())); + antwort.setAntwortBetreffe(Set.of(postfachProperties.getReplySubjectPrefix() + nachricht.getSubject())); + } + antwort.setAntwortFrist(LocalDate.now().plusDays(postfachProperties.getReplyInDays())); + return antwort; } @@ -199,7 +218,7 @@ public class ElsterTransferRemoteService { if (Objects.nonNull(antwortDetails.getAnhaenge())) { var idList = antwortDetails.getAnhaenge().stream() .filter(Objects::nonNull) - .map(downloadAnhangDetails -> saveAnhang(downloadAnhang(downloadAnhangDetails), downloadAnhangDetails, nachrichtId.toHexString())) + .map(downloadAnhangDetails -> saveAnhang(downloadAnhang(downloadAnhangDetails), downloadAnhangDetails, nachrichtId)) .filter(Optional::isPresent) .map(Optional::get) .toList(); @@ -216,13 +235,24 @@ public class ElsterTransferRemoteService { return restClient.getForObject(url, byte[].class); } - Optional<String> saveAnhang(byte[] data, DownloadAnhangDetails downloadAnhangDetails, String nachrichtId) { + Optional<String> saveAnhang(byte[] data, DownloadAnhangDetails downloadAnhangDetails, ObjectId nachrichtId) { LOG.info("Saving Attachment from DownloadAnhangDetails {}", downloadAnhangDetails); Optional<String> fileIdOptional = Optional.empty(); if (Objects.nonNull(data)) { // TODO update to new API as soon the new api is available. Save to file here and then upload attachment try (var dataIn = new ByteArrayInputStream(data)) { - fileIdOptional = storeToOzgCloud(downloadAnhangDetails, nachrichtId, dataIn); + if (Objects.isNull(nachrichtId) && Objects.nonNull(downloadAnhangDetails) && StringUtils.isNotEmpty( + downloadAnhangDetails.getDateiBezeichnung())) { + // can be removed when new api is available + var dateiBezeichnung = downloadAnhangDetails.getDateiBezeichnung(); + var vorgangId = dateiBezeichnung.substring(VORGANG_ID_REFIX.length(), + VORGANG_ID_REFIX.length() + ObjectId.get().toHexString().length()); + fileIdOptional = storeToOzgCloud(downloadAnhangDetails, vorgangId, dataIn); + } else { + // use new api here + // fileIdOptional = storeToOzgCloud(downloadAnhangDetails, nachrichtId, dataIn); + LOG.warn("Saving with NachrichtId not implemented yet."); + } } catch (IOException e) { LOG.error("Error transferring attachment body from Elster-Transfer to OZG-Cloud.", e); throw new TechnicalException("Error downloading anhang", e); @@ -237,8 +267,8 @@ public class ElsterTransferRemoteService { Optional<String> storeToOzgCloud(DownloadAnhangDetails downloadAnhangDetails, String vorgangId, ByteArrayInputStream dataIn) throws IOException { OzgCloudFileId ozgCloudFileId; - // TODO update to new API as soon the new api is available. Use saved temp file - /*try (BufferedInputStream dataStream = new BufferedInputStream(dataIn)) { + + try (BufferedInputStream dataStream = new BufferedInputStream(dataIn)) { ozgCloudFileId = attachmentService.store(createOzgCloudUploadFile(downloadAnhangDetails, vorgangId), dataStream); } @@ -247,16 +277,8 @@ public class ElsterTransferRemoteService { } LOG.error("Received no OzgCloudFileId when saving attachment {} to vorgangId {}", downloadAnhangDetails, vorgangId); - */ return Optional.empty(); } - - static OzgCloudUploadFile createOzgCloudUploadFile(final DownloadAnhangDetails downloadAnhangDetails, final String nachrichtId) { - return OzgCloudUploadFile.builder() - .fileName(downloadAnhangDetails.getDatei()) - .fieldName(POSTFACH) - .contentType(downloadAnhangDetails.getMimeType()).build(); - } } diff --git a/src/main/resources/elster-transfer-24.07-rest-api-docs.yaml b/src/main/resources/elster-transfer-24.07-rest-api-docs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..853d61a1f9b9732ae6cbff9ec9bf82cabcbea763 --- /dev/null +++ b/src/main/resources/elster-transfer-24.07-rest-api-docs.yaml @@ -0,0 +1,2120 @@ +openapi: 3.0.1 +info: + title: ELSTER-Transfer (ETR) REST-Schnittstelle + version: "24.07" +servers: +- description: Generated server url + url: http://localhost:8081 +tags: +- description: Abholen von bereitgestellten Dokumenten + name: abholauftrag +- description: Senden von Dokumenten (zur Altanwendung kompatibles Verfahren "ElsterFT") + name: sendeauftrag +- description: Bereitstellung von Dokumenten + name: bereitstellungsauftrag +- description: Zugriff auf bereits abgeholte eingehende Dokumente + name: eingang +paths: + /rest/abholauftrag: + post: + description: Erzeugung eines Auftrags (Einzelausführung) zum Abholen bereitgestellter + Dokumente der angegebenen Datenart + operationId: createAbholAuftrag + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/AbholAuftragNeu" + required: true + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AuftragAngelegt" + description: Wenn der Auftrag in ELSTER-Transfer angelegt wurde. Die eigentliche + Abholung der Dokumente erfolgt allerdings asynchron. Der Status kann mit + der zurückgegebenen Id abgefragt werden. + "400": + $ref: "#/components/responses/400" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - abholauftrag + /rest/abholauftrag/{auftragId}/download/{downloadId}: + get: + description: Lädt die nach Ausführung eines bestehenden Einzel- oder Dauerabholauftrags + abgeholten Daten (entweder Nutzdatendatei oder Beschreibungsdatei) auf die + in einem Web-Browser übliche Weise (als HTTP-Download). Der Client kann die + Daten speichern oder anders weiterverarbeiten. + operationId: download + parameters: + - description: Id des Abholauftrags. Die Id erhält man als Antwort nach der + Erstellung eines neuen Abholauftrags per REST-Aufruf. Für bestehende Abholaufträge + (Einzelausführung) oder bestehende Dauerabholaufträge ist sie auch in der + ELSTER-Transfer-Oberfläche in der entsprechenden Spalte der Tabelle zu sehen. + example: 12345 + in: path + name: auftragId + required: true + schema: + type: integer + format: int64 + - description: Id des Downloads innerhalb des angegebenen Abholauftrags + example: be0517ip48bhcy04ckhii9i43va0259m + in: path + name: downloadId + required: true + schema: + type: string + - description: "Auswahl, welche der abgeholten Informationen ('ndatei' = Nutzdatendatei\ + \ oder 'bdatei' = Beschreibungsdatei) heruntergeladen werden sollen. Ohne\ + \ Angabe wird die Nutzdatendatei heruntergeladen." + in: query + name: art + required: false + schema: + type: string + enum: + - ndatei + - bdatei + - description: "Auswahl des Anhangs/Dokumententeils, der heruntergeladen werden\ + \ soll (relevant nur bei Abholungen mit mehreren Anhängen/Dokumententeilen).\ + \ Angabe als 0-basierter Index (d.h. 0 = 1. Anhang/Dokumententeil, 1 = 2.\ + \ Anhang/Dokumententeil usw.). Falls nicht angegeben, wird der erste bzw.\ + \ einzige Anhang/Dokumententeil heruntergeladen. Wird ignoriert, wenn 'art'\ + \ = 'bdatei'." + in: query + name: anhang + required: false + schema: + type: integer + format: int32 + minimum: 0 + responses: + "200": + content: + application/octet-stream: + schema: + type: string + format: binary + description: "Binärinhalt des abgeholten Dokuments (welchen Art von Inhalt\ + \ konkret geliefert wird, ist im HTTP-HeaderContent-Type angegeben)" + headers: + Content-Disposition: + description: "Zusatzangabe zur client-seitigen Verwendung der erhaltenen\ + \ Daten nach RFC 1806. Die Rückgabe des Inhalts erfolgt immer als\ + \ Download (Angabe \"attachment\"), wenn möglich mit Angabe eines\ + \ Dateinamens." + required: true + schema: + example: attachment; filename="GMB-be0856hnr5qz775zu9s72iv3x9ag5xrc.ndatei" + style: simple + Content-Length: + description: "Erwartete Länge der Server-Antwort (in Bytes). Kann z.B.\ + \ verwendet werden, um client-seitig Speicherplatz zu reservieren\ + \ oder die Übertragungszeit abzuschätzen." + required: true + schema: + type: integer + format: int64 + style: simple + Content-Type: + description: "MIME-Type nach RFC 2046 (und zugehörigen Spezifikationen),\ + \ wie er in HTTP und den gängigen Internetprotokollen verwendet wird" + required: true + schema: + example: application/octet-stream + style: simple + "400": + $ref: "#/components/responses/400" + "404": + description: Abholauftrag oder Download zum Abholauftrag nicht vorhanden + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - abholauftrag + /rest/abholauftrag/{id}: + get: + description: Abfrage von Statusinformationen zu einem bestehenden Einzel- oder + Dauerabholauftrag (inkl. Informationen zu den zuletzt durchgeführten Downloads) + operationId: getAbholAuftragById + parameters: + - description: Id des Abholauftrags. Die Id erhält man als Antwort nach der + Erstellung eines neuen Abholauftrags per REST-Aufruf. Für bestehende Abholaufträge + (Einzelausführung) oder bestehende Dauerabholaufträge ist sie auch in der + ELSTER-Transfer-Oberfläche in der entsprechenden Spalte der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + - description: "Begrenzt die Anzahl der abgefragten Informationen zu den im\ + \ Rahmen des Auftrags zuletzt durchgeführten Downloads (Vorgabe ist der\ + \ Maximalwert: 100000)." + example: 1000 + in: query + name: maxDownloads + required: false + schema: + type: integer + format: int32 + default: 100000 + maximum: 100000 + minimum: 1 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AbholAuftragInfo" + description: Statusinformationen zum Abholauftrag + "400": + $ref: "#/components/responses/400" + "404": + description: Abholauftrag nicht vorhanden + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - abholauftrag + /rest/bereitstellungsauftrag: + post: + deprecated: true + description: "Erzeugung eines Auftrags zur Bereitstellung eines Dokuments in\ + \ das elektronische Postfach eines Steuerpflichtigen oder Unternehmens. [VERALTET]\ + \ wird zukünftig ersetzt durch die weitgehend kompatible Version 2 der Bereitstellungsaufträ\ + ge-API ('BereitstellungAuftragNeu_V2') mit erweiterten Funktionen und neuer\ + \ URL; bestehende Client-Implementierungen sollten zeitnah auf die neue URL\ + \ und Syntax umgestellt werden" + operationId: createBereitstellungAuftrag + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BereitstellungAuftragNeu" + required: true + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AuftragAngelegt" + description: Wenn der Auftrag in ELSTER-Transfer angelegt wurde. Die eigentliche + Bereitstellung erfolgt allerdings asynchron. Der Status kann mit der zurückgegebenen + Id abgefragt werden. + "400": + $ref: "#/components/responses/400" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/file-upload: + post: + description: "Überträgt eine Binärdatei, die bei späteren Aufrufen z.B. dem\ + \ Bereitstellen von Dokumenten über eine eindeutige ID als Anhang referenziert\ + \ werden kann. Angaben im HTTP-Header wie Inhaltstyp (MIME-Type) und Größ\ + e dienen lediglich der Information und werden vom Server fachlich nicht ausgewertet\ + \ oder validiert. Die Daten werden direkt übertragen (keine Komprimierung\ + \ oder BASE64-Kodierung des Inhalts). Dateigrößen bis 629145600 Bytes sind\ + \ erlaubt. Das Übertragen leerer Dateien ist nicht erlaubt." + operationId: uploadFile + requestBody: + content: + application/pdf: + schema: + type: string + format: binary + image/jpeg: + schema: + type: string + format: binary + image/png: + schema: + type: string + format: binary + text/csv;charset=utf-8: + schema: + type: string + text/xml: + schema: + type: string + format: xml + required: true + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/UploadInfo" + description: "Wenn die übertragene Datei erfolgreich empfangen und zwischengespeichert\ + \ wurde. Zur weiteren Verwendung wird im JSON eine 'uploadId' zurückgegeben,\ + \ welche den Upload eindeutig identifiziert." + "400": + description: Fehlerhafte Anfrage (wenn der Request z.B. keinen Inhalt aufweist) + "413": + description: Inhalt des Requests (der Datei) überschreitet die geltende + Größenlimitierung der Schnittstelle von 629145600 Bytes + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/v2: + post: + description: Erzeugung eines Auftrags zur Bereitstellung eines Dokuments in + das elektronische Postfach eines Steuerpflichtigen oder Unternehmens + operationId: createBereitstellungAuftrag_V2 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BereitstellungAuftragNeu_V2" + required: true + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AuftragAngelegt" + description: Wenn der Auftrag in ELSTER-Transfer angelegt wurde. Die eigentliche + Bereitstellung erfolgt allerdings asynchron. Der Status kann mit der zurückgegebenen + Id abgefragt werden. + "400": + $ref: "#/components/responses/400" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/v2/{id}: + get: + description: Abfrage von Statusinformationen zu einer Bereitstellung + operationId: getBereitstellungAuftragById_V2 + parameters: + - description: Id des Bereitstellungsauftrags. Die Id erhält man als Antwort + auf die Bereitstellung eines Dokuments per REST-Aufruf. Für bestehende Bereitstellungsaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/BereitstellungInfo" + description: Bereitstellungsinformationen + "400": + $ref: "#/components/responses/400" + "404": + description: Bereitstellung nicht vorhanden + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/v2/{id}/restart: + post: + description: "Setzt den Zustand eines fehlgeschlagenen Bereitstellungsauftrags\ + \ zurück, sodass er (im Hintergrund) erneut ausgeführt wird" + operationId: restartBereitstellungAuftrag_V2 + parameters: + - description: Id des Bereitstellungsauftrags. Die Id erhält man als Antwort + auf die Bereitstellung eines Dokuments per REST-Aufruf. Für bestehende Bereitstellungsaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/BereitstellungInfo" + description: Aktualisierte Statusinformationen zum Bereitstellungsauftrag + "400": + description: "Fehlerhafte Anfrage oder es wurde ein Bereitstellungsauftrag\ + \ angegeben, dessen Zustand kein Zurücksetzen erlaubt" + "404": + description: Bereitstellungsauftrag nicht vorhanden + "409": + description: "Abbruch wegen eines gleichzeitigen (parallelen) Zugriffs,\ + \ der ebenfalls den Zustand des Auftrags veränderte (z.B. wenn der Auftrag\ + \ gleichzeitig über die Weboberfläche gelöscht oder neu gestartet wird)" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/v3: + post: + description: Erzeugung eines Auftrags zur Bereitstellung eines Dokuments in + das elektronische Postfach eines Steuerpflichtigen oder Unternehmens. Ab Version + V3 werden die Binärdaten der Anhänge über eine eigene URL (/rest/bereitstellungsauftrag/file-upload) + vorab separat übertragen. + operationId: createBereitstellungAuftrag_V3 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BereitstellungAuftragNeu_V3" + required: true + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AuftragAngelegt" + description: Wenn der Auftrag in ELSTER-Transfer angelegt wurde. Die eigentliche + Bereitstellung erfolgt allerdings asynchron. Der Status kann mit der zurückgegebenen + Id abgefragt werden. + "400": + $ref: "#/components/responses/400" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/v3/{id}: + get: + description: Abfrage von Statusinformationen zu einer Bereitstellung + operationId: getBereitstellungAuftragById_V3 + parameters: + - description: Id des Bereitstellungsauftrags. Die Id erhält man als Antwort + auf die Bereitstellung eines Dokuments per REST-Aufruf. Für bestehende Bereitstellungsaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/BereitstellungInfo" + description: Bereitstellungsinformationen + "400": + $ref: "#/components/responses/400" + "404": + description: Bereitstellung nicht vorhanden + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/v3/{id}/restart: + post: + description: "Setzt den Zustand eines fehlgeschlagenen Bereitstellungsauftrags\ + \ zurück, sodass er (im Hintergrund) erneut ausgeführt wird" + operationId: restartBereitstellungAuftrag_V3 + parameters: + - description: Id des Bereitstellungsauftrags. Die Id erhält man als Antwort + auf die Bereitstellung eines Dokuments per REST-Aufruf. Für bestehende Bereitstellungsaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/BereitstellungInfo" + description: Aktualisierte Statusinformationen zum Bereitstellungsauftrag + "400": + description: "Fehlerhafte Anfrage oder es wurde ein Bereitstellungsauftrag\ + \ angegeben, dessen Zustand kein Zurücksetzen erlaubt" + "404": + description: Bereitstellungsauftrag nicht vorhanden + "409": + description: "Abbruch wegen eines gleichzeitigen (parallelen) Zugriffs,\ + \ der ebenfalls den Zustand des Auftrags veränderte (z.B. wenn der Auftrag\ + \ gleichzeitig über die Weboberfläche gelöscht oder neu gestartet wird)" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/{id}: + get: + deprecated: true + description: "Abfrage von Statusinformationen zu einer Bereitstellung. [VERALTET]\ + \ wird zukünftig ersetzt durch die inhaltlich gleiche Version 2 der Bereitstellungsaufträ\ + ge-API unter neuer URL; bestehende Client-Implementierungen sollten zeitnah\ + \ auf die neue URL umgestellt werden" + operationId: getBereitstellungAuftragById + parameters: + - description: Id des Bereitstellungsauftrags. Die Id erhält man als Antwort + auf die Bereitstellung eines Dokuments per REST-Aufruf. Für bestehende Bereitstellungsaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/BereitstellungInfo" + description: Bereitstellungsinformationen + "400": + $ref: "#/components/responses/400" + "404": + description: Bereitstellung nicht vorhanden + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/bereitstellungsauftrag/{id}/restart: + post: + deprecated: true + description: "Setzt den Zustand eines fehlgeschlagenen Bereitstellungsauftrags\ + \ zurück, sodass er (im Hintergrund) erneut ausgeführt wird. [VERALTET] wird\ + \ zukünftig ersetzt durch die inhaltlich gleiche Version 2 der Bereitstellungsaufträ\ + ge-API ('BereitstellungAuftragNeu_V2') unter neuer URL; bestehende Client-Implementierungen\ + \ sollten zeitnah auf die neue URL umgestellt werden" + operationId: restartBereitstellungAuftrag + parameters: + - description: Id des Bereitstellungsauftrags. Die Id erhält man als Antwort + auf die Bereitstellung eines Dokuments per REST-Aufruf. Für bestehende Bereitstellungsaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/BereitstellungInfo" + description: Aktualisierte Statusinformationen zum Bereitstellungsauftrag + "400": + description: "Fehlerhafte Anfrage oder es wurde ein Bereitstellungsauftrag\ + \ angegeben, dessen Zustand kein Zurücksetzen erlaubt" + "404": + description: Bereitstellungsauftrag nicht vorhanden + "409": + description: "Abbruch wegen eines gleichzeitigen (parallelen) Zugriffs,\ + \ der ebenfalls den Zustand des Auftrags veränderte (z.B. wenn der Auftrag\ + \ gleichzeitig über die Weboberfläche gelöscht oder neu gestartet wird)" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - bereitstellungsauftrag + /rest/eingang/antworten: + get: + description: "Ermittelt alle bereits im Hintergrund vom Server abgeholten Antworten,\ + \ die den angegebenen Filterkriterien entsprechen. Die Sortierung erfolgt\ + \ nach dem Zeitpunkt, an dem der Download durchgeführt wurde. Neueste (jü\ + ngste) Downloads werden zuerst ausgegeben." + operationId: getAntworten + parameters: + - in: query + name: filter + required: true + schema: + $ref: "#/components/schemas/AntwortRequestParams" + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AntwortDetailsList" + description: "Liste der vorhandenen Antworten, die den angegebenen Filterkriterien\ + \ entsprechen" + "400": + $ref: "#/components/responses/400" + "404": + description: Anfrage liefert mit den gegebenen Kriterien keine Ergebnisse + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - eingang + /rest/eingang/downloads: + get: + description: "Ermittelt alle bereits im Hintergrund vom Server abgeholten Downloads,\ + \ die den angegebenen Filterkriterien entsprechen. Die Einschränkung kann\ + \ u.a. durch Angabe der abgeholten 'Datenart' oder eines Zeitraums erfolgen.\ + \ Die Sortierung erfolgt nach dem Zeitpunkt, an dem der Download durchgefü\ + hrt wurde. Neueste (jüngste) Downloads werden zuerst ausgegeben." + operationId: getDownloads + parameters: + - in: query + name: filter + required: true + schema: + $ref: "#/components/schemas/DownloadDetailsRequestParams" + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/DownloadDetailsList" + description: "Liste der vorhandenen Downloads, die den angegebenen Filterkriterien\ + \ entsprechen" + "400": + $ref: "#/components/responses/400" + "404": + description: Anfrage liefert mit den gegebenen Kriterien keine Ergebnisse + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - eingang + /rest/sendeauftrag: + post: + description: Erzeugung eines Auftrags zum Senden eines Dokuments an den angegebenen + Empfänger der Steuerverwaltung + operationId: createSendeAuftrag + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SendeAuftragNeu" + required: true + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/AuftragAngelegt" + description: Wenn der Auftrag in ELSTER-Transfer angelegt wurde. Das eigentliche + Senden erfolgt allerdings asynchron. Der Status kann mit der zurückgegebenen + Id abgefragt werden. + "400": + $ref: "#/components/responses/400" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - sendeauftrag + /rest/sendeauftrag/{id}: + get: + description: Abfrage von Statusinformationen zu einem Sendeauftrag + operationId: getSendeAuftragById + parameters: + - description: Id des Sendeauftrags. Die Id erhält man als Antwort nach der + Erstellung eines neuen Sendeauftrags per REST-Aufruf. Für bestehende Sendeaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/SendeAuftragInfo" + description: Statusinformationen zum Sendeauftrag + "400": + $ref: "#/components/responses/400" + "404": + description: Sendeauftrag nicht vorhanden + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - sendeauftrag + /rest/sendeauftrag/{id}/restart: + post: + description: "Setzt den Zustand eines fehlgeschlagenen Sendeauftrags zurück,\ + \ sodass er (im Hintergrund) erneut ausgeführt wird" + operationId: restartSendeAuftrag + parameters: + - description: Id des Sendeauftrags. Die Id erhält man als Antwort nach der + Erstellung eines neuen Sendeauftrags per REST-Aufruf. Für bestehende Sendeaufträge + ist sie auch in der ELSTER-Transfer-Oberfläche in der entsprechenden Spalte + der Tabelle zu sehen. + example: 12345 + in: path + name: id + required: true + schema: + type: integer + format: int64 + responses: + "200": + content: + '*/*': + schema: + $ref: "#/components/schemas/SendeAuftragInfo" + description: Aktualisierte Statusinformationen zum Sendeauftrag + "400": + description: "Fehlerhafte Anfrage oder es wurde ein Sendeauftrag angegeben,\ + \ dessen Zustand kein Zurücksetzen erlaubt" + "404": + description: Sendeauftrag nicht vorhanden + "409": + description: "Abbruch wegen eines gleichzeitigen (parallelen) Zugriffs,\ + \ der ebenfalls den Zustand des Auftrags veränderte (z.B. wenn der Auftrag\ + \ gleichzeitig über die Weboberfläche gelöscht oder neu gestartet wird)" + "500": + $ref: "#/components/responses/500" + "503": + $ref: "#/components/responses/503" + tags: + - sendeauftrag +components: + responses: + "400": + description: Ungültige Anfrage (Anfrage entspricht nicht der Schnittstellenbeschreibung + oder die angegebenen Werte sind nicht gültig) + "500": + description: Technischer Fehler bei der Verarbeitung oder Fehlkonfiguration + auf Seite von ETR (Server). Bitte wenden Sie sich an Ihren Administrator (Details + im Server-Logfile). + "503": + description: Der Dienst ist derzeit nicht verfügbar. Wiederholen Sie Ihre Anfrage + bitte zu einem späteren Zeitpunkt oder wenden Sie sich an Ihren Administrator. + schemas: + AbholAuftragInfo: + type: object + properties: + datenart: + type: string + example: GMB + downloads: + type: array + description: Auflistung der während der bisherigen Verarbeitung des Auftrags + durchgeführten Abholungen + items: + $ref: "#/components/schemas/DownloadInfo" + id: + type: integer + format: int64 + example: 12345 + status: + $ref: "#/components/schemas/AuftragStatus" + required: + - datenart + - id + - status + AbholAuftragNeu: + type: object + properties: + art: + $ref: "#/components/schemas/ArtAbholung" + bis: + type: string + format: date + description: "Wenn angegeben werden nur Dokumente abgeholt, die nicht spä\ + ter als das angegebenen Datum bereitgestellt wurden" + datenart: + type: string + description: Die gültigen Datenarten hängen von den Berechtigungen des eingestellten + Zertifikats ab. Es sind nur Datenarten für das Verfahren 'ElsterDatenabholung' + zulässig. + example: GMB + testmerker: + $ref: "#/components/schemas/Testmerker" + von: + type: string + format: date + description: "Wenn angegeben werden nur Dokumente abgeholt, die ab dem angegebenen\ + \ Datum bereitgestellt wurden" + required: + - art + - datenart + AnhangInfo: + type: object + description: Informationen zu einem angehängten Dokument des Bereitstellungsauftrags + properties: + dateiBezeichnung: + type: string + description: Bezeichnung des übermittelten Dokuments + example: Bescheid + mimeType: + $ref: "#/components/schemas/AnhangMimeType" + required: + - dateiBezeichnung + - mimeType + AnhangMimeType: + type: string + description: "MIME-Type, der den Inhaltstyp des Dokuments explizit angibt. Sollte\ + \ bei Aufruf über REST-API immer angegeben werden (kann aus Kompatiblitätsgrü\ + nden mit älteren Versionen zunächst leer bleiben, wobei fest 'application/pdf'\ + \ als MIME-Type angenommen wird; diese Aufrufvariante wird allerdings in spä\ + teren ETR-Versionen entfallen)" + enum: + - application/pdf + - text/xml + - text/csv + - image/jpeg + - image/png + example: application/pdf + AntwortDetails: + type: object + properties: + anhaenge: + type: array + description: "Bereits abgeholte Nutzdaten-Anhänge im Eingangsverzeichnis,\ + \ d.h. die Binärdateien, aus denen sich Gesamtdokument zusammensetzt." + items: + $ref: "#/components/schemas/DownloadAnhangDetails" + anzahlAnhaenge: + type: integer + format: int32 + description: "Anzahl der Anhänge/Dokumentteile/Nutzdatendateien, aus denen\ + \ das Dokument besteht" + example: 1 + minimum: 0 + auftragId: + type: integer + format: int64 + description: "Id des Auftrags, mit dem dieses Dokument ursprünglich abgeholt\ + \ wurde" + example: 12345 + minimum: 1 + beschreibungsdatei: + type: string + deprecated: true + description: "Name der Datei mit den Metadaten (BDatei) relativ zum Eingangsverzeichnis.Fü\ + r Antworten immer leer (null), sollte daher nicht mehr verwendet werden\ + \ und wird zukünftig entfallen." + dateiBezeichnung: + type: string + deprecated: true + description: "Bezeichnung des abgeholten Dokuments. null, falls nicht bekannt.\ + \ Sollte ab ETR 3.5.0 nicht mehr verwendet werden, da die einzelnen Anhä\ + nge/Dokumentteile eines Downloads unterschiedliche Dateibezeichnungen\ + \ aufweisen können." + example: Einspruch + dateiTyp: + type: string + format: mime-type + deprecated: true + description: "MIME-Type (nach RFC 6838), der den Inhaltstyp der abgeholten\ + \ (Nutzdaten-)Datei angibt. null, falls nicht bekannt (in der Regel handelt\ + \ es sich dann um ZIP-Archive, die mehrere unterschiedliche Inhalte enthalten).\ + \ Sollte ab ETR 3.5.0 nicht mehr verwendet werden, da nicht zwingend alle\ + \ Anhänge/Dokumentteile eines Downloads den gleichen MIME-TYP aufweisen\ + \ müssen." + example: application/pdf + downloadUrl: + type: string + format: uri + description: "URL-Suffix ('URI Reference') der REST-API, unter der die Binä\ + r-Nutzdaten des Dokuments heruntergeladen werden können. Standardmäßig\ + \ wird der erste Nutzdaten-Anhang/Dokumentteil heruntergeladen. Umfasst\ + \ das Dokument mehr als 1 solcher Anhänge/Dokumentteile, müssen diese\ + \ jeweils einzeln durch Ergänzen des 'anhang'-Parameters heruntergeladen\ + \ werden. Detailangaben zu den Anhängen/Dokumentteilen siehe 'anhaenge'.\ + \ Analog zu den anderen REST-Operationen muss der Aufrufer in jedem Fall\ + \ die Basis-URL (Protokoll, Server, Port und ggf. Kontextpfad) als Prä\ + fix ergänzen." + example: /rest/abholauftrag/12345/download/be123456789011122233301234567890 + downloadZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit), zu dem die Abholung durchgefü\ + hrt wurde" + id: + type: string + description: "Id, die ein abgeholtes Dokument (Download) identifiziert.\ + \ Über die Id kann zur weiteren Verarbeitung auf die Nutzdaten (und ggf.\ + \ vorhandene Beschreibungsdaten) des Dokuments zugegriffen werden." + example: be0856hnr5qz775zu9s72iv3x9ag5xrc + maxLength: 32 + meta: + type: array + description: "Metadaten, die im Rahmen der Abholung mitgegeben wurden, gruppiert\ + \ nach Typ. Bei einfachen Metadaten ist als Schlüssel kein Typ angegeben.\ + \ Im Ausnahmefall können für den gleichen Typ mehrere Gruppen von Metadaten-Angaben\ + \ vorliegen." + items: + $ref: "#/components/schemas/DownloadMetaMap" + nutzdatendatei: + type: string + deprecated: true + description: "Dateiname eines der Anhänge/Dokumentteile relativ zum Eingangsverzeichnis.\ + \ Da nicht unterschieden werden kann, um welchen Anhang/Dokumentteil es\ + \ sich handelt, sollte diese Eigenschaft ab ETR 3.5.0 nicht mehr verwendet\ + \ werden. Stattdessen kann auf die Anhänge/Dokumentteile in 'anhaenge'\ + \ einzeln zugegriffen werden." + example: EPAntwort/be1580k8tb22v04if2q0xxcc8vto1v7m.0.pdf + zuordnungskriterium: + type: string + format: uuid + description: Zuordnungskriterium aus der korrespondierenden ursprünglichen + Bereitstellung + required: + - id + AntwortDetailsList: + type: object + properties: + anzahlDatensaetze: + type: integer + format: int64 + description: Die Anzahl der auf allen Seiten in Summe vorhandenen Ergebnisdatensätze + minimum: 1 + anzahlSeiten: + type: integer + format: int32 + description: Die Anzahl der insgesamt vorhandenen Seiten des Ergebnisses + (inklusive der aktuell abgefragten Seite) + minimum: 1 + datensaetze: + type: array + description: Ergebnis der zuvor ausgeführten Suchanfrage. Enthält maximal + 'seitenGroesse' viele Einträge. Weitere Datensätze müssen ggf. mit weiteren + Aufrufen und passendem 'seitenIndex' abgefragt werden. + items: + $ref: "#/components/schemas/AntwortDetails" + minItems: 1 + seitenGroesse: + type: integer + format: int32 + default: 1000 + description: Anzahl der auf einer Seite zurück zuliefernder Ergebnisdatensätze. + maximum: 10000 + minimum: 1 + seitenIndex: + type: integer + format: int32 + default: 0 + description: "0-basierter Index der Ergebnisseite, die zurückgeliefert werden\ + \ soll. Eine erste Abfrage erfolgt normalerweise mit Seitenindex '0'.\ + \ Die Anzahl der vorhandenen Seiten wird im Abfrageergebnis der ersten\ + \ Seite mitgeliefert." + minimum: 0 + required: + - anzahlDatensaetze + - anzahlSeiten + - datensaetze + AntwortRequestParams: + type: object + description: "Definiert die Kriterien für eine Abfrage von bereits abgeholten\ + \ 'Antworten' zu vorherigen Bereitstellungen. Die einzelnen Kriterien, die\ + \ angegeben werden können, sind OPTIONAL und UND-verknüpft. Nicht angegebene\ + \ Kriterien werden bei der Abfrage nicht berücksichtigt. Die Anzahl der zurü\ + ckgelieferten Datensätze ist auf 'seitenGroesse' viele beschränkt. Durch Iterieren\ + \ des 'seitenIndex'-Parameters kann der Aufrufer ggf. weitere Ergebnisdatensä\ + tze abfragen." + properties: + downloadId: + type: string + description: Einschränkung der Ergebnisse anhand der Id (Best-ID) eines + einzelnen Downloads + example: be0517ip48bhcy04ckhii9i43va0259m + pattern: "^be[0-9a-zA-Z]{30}$" + downloadZeitpunktBis: + type: string + format: date + description: "Einschränkung der Ergebnisse anhand des spätesten Datums,\ + \ an dem der Download ausgeführt wurde" + downloadZeitpunktVon: + type: string + format: date + description: "Einschränkung der Ergebnisse anhand des frühestens Datums,\ + \ an dem der Download ausgeführt wurde" + seitenGroesse: + type: integer + format: int32 + default: 1000 + description: Anzahl der auf einer Seite zurück zuliefernder Ergebnisdatensätze. + maximum: 10000 + minimum: 1 + seitenIndex: + type: integer + format: int32 + default: 0 + description: "0-basierter Index der Ergebnisseite, die zurückgeliefert werden\ + \ soll. Eine erste Abfrage erfolgt normalerweise mit Seitenindex '0'.\ + \ Die Anzahl der vorhandenen Seiten wird im Abfrageergebnis der ersten\ + \ Seite mitgeliefert." + minimum: 0 + zuordnungskriterium: + type: string + format: uuid + description: Einschränkung der Ergebnisse auf 'Antworten' mit dem (in der + ursprünglichen Bereitstellung) angegebenen 'Zuordnungskriterium'. + ArtAbholung: + type: string + description: "Bestimmt, welche Dokumente abgeholt werden bzw. ob bereits quittierte\ + \ (abgeholte) Dokumente erneut abgeholt werden sollen" + enum: + - ALLE + - NUR_NEUE + AuftragAngelegt: + type: object + properties: + id: + type: integer + format: int64 + example: 12345 + required: + - id + AuftragStatus: + type: string + description: "Aktueller Status für Sende- bzw. Abholaufträge mit folgenden Werten:\ + \ \nNEU: Initialer Status bei neu angelegten Aufträgen. Aufträge verbleiben\ + \ in diesem Status bis die etr-seitige \"Bearbeitung\" abgeschlossen ist (d.h.\ + \ der Versand erfolgreich war oder ein Fehler auftrat).\nERLEDIGT: Das Dokument\ + \ wurde erfolgreich versandt (Sendeaufträge) bzw. abgeholt und im Eingangsverzeichnis\ + \ gespeichert (Abholaufträge).\nFEHLER: Es kam zu einem internen Fehler wä\ + hrend der Bearbeitung des Auftrags.\nINVALID: Es kann nicht exakt ermittelt\ + \ werden, welcher Statuswert zutreffend ist (nur noch zur Kompatiblität mit\ + \ älteren ETR-Versionen)." + enum: + - NEU + - ERLEDIGT + - FEHLER + - INVALID + BereitstellungAnhangDirectUpload: + type: object + description: "Dokument (Anhang) mit Binärdaten, die als BASE64 kodiert direkt\ + \ im JSON enthalten sind und im Rahmen eines Bereitstellungsauftrags von ETR\ + \ an einen Empfänger übermittelt werden sollen" + properties: + dateiBezeichnung: + type: string + description: Bezeichnung der zu übermittelnden Datei + example: Hundesteuerbescheid Mustermann vom 29.08.2023 + maxLength: 50 + minLength: 1 + pattern: "[ -~¡-£¥-¥§-§ª-¬®-³µ-µ¹-»¿-ÿŒ-œŠ-šŸ-ŸŽ-ž€-€]*" + dateiInhalt: + type: string + format: byte + description: Zu übermittelnder Dateiinhalt als Base64-kodierter String + example: TURFeU16UTFOamM0T1E9PQ== + maxLength: 8388608 + minLength: 0 + dateinameMitErweiterung: + type: string + description: "Vorgeschlagener Dateiname, der beim Speichern des Anhangs\ + \ / Dokumentteils im Dateisystem des Empfängers verwendet werden soll.\ + \ Nach Möglichkeit soll der Originaldateiname im Dateisystem des Absenders\ + \ verwendet werden, sodass die Benennung im Dateisystem auf Empfängerseite\ + \ analog zur ursprünglichen Benennung auf Absenderseite ist. Damit sichergestellt\ + \ ist, dass der Dateiname bei allen potenziellen Empfängern gleich gehandhabt\ + \ wird, muss er bestimmte technische Mindestkriterien (Längenvorgaben,\ + \ Ausschluss von Verzeichnispfaden und bestimmten Sonderzeichen) erfü\ + llen. Andernfalls kann er weggelassen werden, wobei dann der Empfänger\ + \ (falls benötigt) einen Dateinamen selbst generiert." + example: HSteuer_Mustermann_29082023.pdf + maxLength: 255 + minLength: 5 + pattern: "[ -!#-)+-.0-9;=@-\\[\\]-{}-~¡-£¥-¥§-§ª-¬®-³µ-µ¹-»¿-ÿŒ-œŠ-šŸ-ŸŽ\ + -ž€-€]*" + mimeType: + $ref: "#/components/schemas/AnhangMimeType" + required: + - dateiBezeichnung + - dateiInhalt + BereitstellungAnhangWithUploadId: + type: object + description: "Dokument (Anhang), dessen Binärdaten zuvor in einer separaten\ + \ POST-Anfrage (unter /rest/bereitstellungsauftrag/file-upload) hochgeladen\ + \ wurden" + properties: + dateiBezeichnung: + type: string + description: Bezeichnung der zu übermittelnden Datei + example: Hundesteuerbescheid Mustermann vom 29.08.2023 + maxLength: 50 + minLength: 1 + pattern: "[ -~¡-£¥-¥§-§ª-¬®-³µ-µ¹-»¿-ÿŒ-œŠ-šŸ-ŸŽ-ž€-€]*" + dateinameMitErweiterung: + type: string + description: "Vorgeschlagener Dateiname, der beim Speichern des Anhangs\ + \ / Dokumentteils im Dateisystem des Empfängers verwendet werden soll.\ + \ Nach Möglichkeit soll der Originaldateiname im Dateisystem des Absenders\ + \ verwendet werden, sodass die Benennung im Dateisystem auf Empfängerseite\ + \ analog zur ursprünglichen Benennung auf Absenderseite ist. Damit sichergestellt\ + \ ist, dass der Dateiname bei allen potenziellen Empfängern gleich gehandhabt\ + \ wird, muss er bestimmte technische Mindestkriterien (Längenvorgaben,\ + \ Ausschluss von Verzeichnispfaden und bestimmten Sonderzeichen) erfü\ + llen. Andernfalls kann er weggelassen werden, wobei dann der Empfänger\ + \ (falls benötigt) einen Dateinamen selbst generiert." + example: HSteuer_Mustermann_29082023.pdf + maxLength: 255 + minLength: 5 + pattern: "[ -!#-)+-.0-9;=@-\\[\\]-{}-~¡-£¥-¥§-§ª-¬®-³µ-µ¹-»¿-ÿŒ-œŠ-šŸ-ŸŽ\ + -ž€-€]*" + mimeType: + $ref: "#/components/schemas/AnhangMimeType" + uploadId: + type: string + format: uuid + description: "Eindeutige Id, die bereits zuvor separat hochgeladenen Binä\ + rdaten dieses Anhangs referenziert. Wird beim Hochladen des Anhangs generiert\ + \ und zurückgegeben" + required: + - dateiBezeichnung + - mimeType + - uploadId + BereitstellungAntwort: + type: object + description: Optional. Bietet dem Nachrichtenempfänger die Möglichkeit auf den + bereitgestellten Bescheid/Mitteilung zu antworten. + properties: + antwortBetreffe: + type: array + description: Der Nachrichtenempfänger muss für seine Antwort einen Betreff + der hier genannten Optionen wählen. + items: + type: string + description: Betreffmöglichkeit der Antwort + example: Betreff 1 - Novemberbescheid + maxLength: 255 + minLength: 1 + maxItems: 100 + minItems: 1 + uniqueItems: true + antwortFrist: + type: string + format: date + description: "Optionale Frist, bis wann der Nachrichtenempfänger eine Antwort\ + \ verfassen kann. Wird kein Wert angegeben ist die maximale Speicherdauer\ + \ (Mitteilungen 90 Tage, Bescheide 4 Jahre) maßgeblich." + zuordnungskriterium: + type: string + format: uuid + description: "Optional; UUID dient für die Zuordnung der erhaltenen Antwort.\ + \ Wird ebenfalls dem Nachrichtenempfänger angezeigt. Wenn nicht angegeben,\ + \ wird eine UUID generiert" + BereitstellungAntwortlink: + type: object + description: "Web-Link und zugehörige Informationen, die eine Möglichkeit beschreiben,\ + \ wie der Kunde, an den ein Dokument bereitgestellt wurde, eine Rückantwort\ + \ durchführen kann." + properties: + beschreibung: + type: string + example: Mouse - Hover-Over Text + maxLength: 32768 + minLength: 0 + titel: + type: string + example: Einspruch xxx + maxLength: 56 + minLength: 0 + url: + type: string + format: uri + example: http://www.Elster.de/Antwortlink + maxLength: 32768 + minLength: 0 + required: + - titel + - url + BereitstellungAuftragNeu: + type: object + deprecated: true + description: "[VERALTET] wird zukünftig ersetzt durch die weitgehend kompatible\ + \ Version 2 der Bereitstellungsaufträge-API ('BereitstellungAuftragNeu_V2')\ + \ mit erweiterten Funktionen und neuer URL; bestehende Client-Implementierungen\ + \ sollten zeitnah auf die neue URL und Syntax umgestellt werden" + properties: + absender: + type: string + example: Stadt Mühldorf + maxLength: 128 + minLength: 0 + accountId: + type: string + description: gibt den ELSTER-Account des Empfängers an + example: "1234567890" + antwort: + $ref: "#/components/schemas/BereitstellungAntwort" + antwortlinks: + type: array + description: "Informationen u.a. ein Web-Link, die dem Kunden, an den das\ + \ Dokument bereitgestellt wurde, eine Rückantwort ermöglicht." + items: + $ref: "#/components/schemas/BereitstellungAntwortlink" + maxItems: 10 + minItems: 0 + bescheidDatum: + type: string + format: date + description: "Pflichtangabe bei rechtsverbindlichen Bescheiden, sonst nicht\ + \ zulässig" + betreff: + type: string + description: "Pflicht bei Datenarten, bei denen der Betreff nicht automatisch\ + \ ermittelt werden kann (z.\_B. bei \"EPBescheid\", \"EPMitteilung\",\ + \ \"EPKurzmitteilung\"). Sonst ist die Angabe nicht zulässig." + example: Bescheid über Abfallgebühren + maxLength: 255 + minLength: 0 + dateiBezeichnung: + type: string + description: Bezeichnung der zu übermittelnden Datei + example: Hundesteuerbescheid Mustermann vom 29.08.2023 + maxLength: 50 + minLength: 1 + pattern: "[ -~¡-£¥-¥§-§ª-¬®-³µ-µ¹-»¿-ÿŒ-œŠ-šŸ-ŸŽ-ž€-€]*" + dateiInhalt: + type: string + format: byte + description: Zu übermittelnder Dateiinhalt als Base64-kodierter String + example: TURFeU16UTFOamM0T1E9PQ== + maxLength: 8388608 + minLength: 0 + dateinameMitErweiterung: + type: string + description: "Vorgeschlagener Dateiname, der beim Speichern des Anhangs\ + \ / Dokumentteils im Dateisystem des Empfängers verwendet werden soll.\ + \ Nach Möglichkeit soll der Originaldateiname im Dateisystem des Absenders\ + \ verwendet werden, sodass die Benennung im Dateisystem auf Empfängerseite\ + \ analog zur ursprünglichen Benennung auf Absenderseite ist. Damit sichergestellt\ + \ ist, dass der Dateiname bei allen potenziellen Empfängern gleich gehandhabt\ + \ wird, muss er bestimmte technische Mindestkriterien (Längenvorgaben,\ + \ Ausschluss von Verzeichnispfaden und bestimmten Sonderzeichen) erfü\ + llen. Andernfalls kann er weggelassen werden, wobei dann der Empfänger\ + \ (falls benötigt) einen Dateinamen selbst generiert." + example: HSteuer_Mustermann_29082023.pdf + maxLength: 255 + minLength: 5 + pattern: "[ -!#-)+-.0-9;=@-\\[\\]-{}-~¡-£¥-¥§-§ª-¬®-³µ-µ¹-»¿-ÿŒ-œŠ-šŸ-ŸŽ\ + -ž€-€]*" + datenart: + type: string + description: Die gültigen Datenarten hängen von den Berechtigungen des eingestellten + Zertifikats ab. Es sind nur Datenarten für das Verfahren 'ElsterBereitstellung' + zulässig. + example: EPBescheid + emailAdresse: + type: string + description: "E-Mail-Adresse des Empfängers, die bei Bereitstellung eines\ + \ Bescheids über dessen Eingang benachrichtigt wird. Je nach Datenart:\ + \ Optional (z.\_B. bei \"EPBescheid\"), Pflichtfeld (z.\_B. bei \"Gewerbesteuerbescheid\"\ + ), sonst nicht zulässig." + example: test@elster.de + maxLength: 255 + minLength: 0 + emailZusatzText: + type: string + description: "Ergänzender Freitext für die Benachrichtigungsemails, der\ + \ zusätzlich zum Vorlagentext verwendet wird. Nur für bestimmte Datenarten\ + \ (z.\_B. \"EPMitteilung\") und Nutzergruppen (in Abhängigkeit der Anwendungskonfiguration)\ + \ gedacht, sonst nicht zulässig." + example: Bitte beachten Sie § 29 Absatz 3 StVO. Gute Fahrt mit Ihrem Rasenmäher! + maxLength: 500 + minLength: 0 + empfaengerreferenz: + type: string + description: Optionales Feld bei allen Datenarten; Anhand der Referenz kann + der Empfänger den Auftrag zuordnen + example: "Kunde: 134984" + maxLength: 255 + minLength: 0 + geschaeftszeichen: + type: string + description: "Pflichtangabe bei rechtsverbindlichen Bescheiden, sonst optional" + example: XA-123 + maxLength: 60 + minLength: 0 + htmlAnschreiben: + type: string + description: "Optionales formatiertes Anschreiben, das beim Empfänger im\ + \ Posteingang angezeigt werden soll. Als Syntax der Formatierung wird\ + \ eine echten Teilmenge des HTML-Standards verwendet. Zulässig sind HTML-Tags\ + \ der Form: <br> <p>Absatz</p> <ul><li>erster Punkt</li><li>zweiter Punkt</li></ul><ol><li>erster\ + \ Punkt</li><li>zweiter Punkt</li></ol> <strong>starke Hervorhebung (fett\ + \ dargestellt)</strong><em>Hervorhebung (kursiv dargestellt)</em>. Unformatierter\ + \ Text ist als Sonderfall ebenfalls zulässig." + example: "<p>Guten Tag EMPFÄNGER,<br>in den Anhängen finden Sie Ihren Bescheid\ + \ für eine Rasenmähgenehmigung.</p><ul><li>1. Genehmigung</li><li>2.\ + \ Darstellung der betroffenen Rasenfläche</li></ul><p>Mit freundlichen\ + \ Grüßen,<br>Ihr ABSENDER</p>" + maxLength: 5000 + minLength: 0 + lieferTicket: + type: string + description: "Eindeutige Kennung, um mit diesem (Antwort-)Dokument einen\ + \ Bezug zu einem vorhergehenden Antrag herzustellen" + example: ie2391sg5syh4s146jjrb1qatnvwf4w9 + maxLength: 32 + minLength: 0 + mimeType: + $ref: "#/components/schemas/AnhangMimeType" + testmerker: + $ref: "#/components/schemas/Testmerker" + required: + - absender + - accountId + - dateiBezeichnung + - dateiInhalt + - datenart + BereitstellungAuftragNeu_V2: + type: object + description: "Erweiterte Version 2 der Bereitstellungsaufträge-API, erlaubt\ + \ u.a. mehrere Anhänge innerhalb einer Bereitstellung" + properties: + absender: + type: string + example: Stadt Mühldorf + maxLength: 128 + minLength: 0 + accountId: + type: string + description: gibt den ELSTER-Account des Empfängers an + example: "1234567890" + anhaenge: + type: array + description: Liefert die Anhänge (bereitzustellende Binärdaten) dieses Auftrags. + items: + $ref: "#/components/schemas/BereitstellungAnhangDirectUpload" + antwort: + $ref: "#/components/schemas/BereitstellungAntwort" + antwortlinks: + type: array + description: "Informationen u.a. ein Web-Link, die dem Kunden, an den das\ + \ Dokument bereitgestellt wurde, eine Rückantwort ermöglicht." + items: + $ref: "#/components/schemas/BereitstellungAntwortlink" + maxItems: 10 + minItems: 0 + bescheidDatum: + type: string + format: date + description: "Pflichtangabe bei rechtsverbindlichen Bescheiden, sonst nicht\ + \ zulässig" + betreff: + type: string + description: "Pflicht bei Datenarten, bei denen der Betreff nicht automatisch\ + \ ermittelt werden kann (z.\_B. bei \"EPBescheid\", \"EPMitteilung\",\ + \ \"EPKurzmitteilung\"). Sonst ist die Angabe nicht zulässig." + example: Bescheid über Abfallgebühren + maxLength: 255 + minLength: 0 + datenart: + type: string + description: Die gültigen Datenarten hängen von den Berechtigungen des eingestellten + Zertifikats ab. Es sind nur Datenarten für das Verfahren 'ElsterBereitstellung' + zulässig. + example: EPBescheid + emailAdresse: + type: string + description: "E-Mail-Adresse des Empfängers, die bei Bereitstellung eines\ + \ Bescheids über dessen Eingang benachrichtigt wird. Je nach Datenart:\ + \ Optional (z.\_B. bei \"EPBescheid\"), Pflichtfeld (z.\_B. bei \"Gewerbesteuerbescheid\"\ + ), sonst nicht zulässig." + example: test@elster.de + maxLength: 255 + minLength: 0 + emailZusatzText: + type: string + description: "Ergänzender Freitext für die Benachrichtigungsemails, der\ + \ zusätzlich zum Vorlagentext verwendet wird. Nur für bestimmte Datenarten\ + \ (z.\_B. \"EPMitteilung\") und Nutzergruppen (in Abhängigkeit der Anwendungskonfiguration)\ + \ gedacht, sonst nicht zulässig." + example: Bitte beachten Sie § 29 Absatz 3 StVO. Gute Fahrt mit Ihrem Rasenmäher! + maxLength: 500 + minLength: 0 + empfaengerreferenz: + type: string + description: Optionales Feld bei allen Datenarten; Anhand der Referenz kann + der Empfänger den Auftrag zuordnen + example: "Kunde: 134984" + maxLength: 255 + minLength: 0 + geschaeftszeichen: + type: string + description: "Pflichtangabe bei rechtsverbindlichen Bescheiden, sonst optional" + example: XA-123 + maxLength: 60 + minLength: 0 + htmlAnschreiben: + type: string + description: "Optionales formatiertes Anschreiben, das beim Empfänger im\ + \ Posteingang angezeigt werden soll. Als Syntax der Formatierung wird\ + \ eine echten Teilmenge des HTML-Standards verwendet. Zulässig sind HTML-Tags\ + \ der Form: <br> <p>Absatz</p> <ul><li>erster Punkt</li><li>zweiter Punkt</li></ul><ol><li>erster\ + \ Punkt</li><li>zweiter Punkt</li></ol> <strong>starke Hervorhebung (fett\ + \ dargestellt)</strong><em>Hervorhebung (kursiv dargestellt)</em>. Unformatierter\ + \ Text ist als Sonderfall ebenfalls zulässig." + example: "<p>Guten Tag EMPFÄNGER,<br>in den Anhängen finden Sie Ihren Bescheid\ + \ für eine Rasenmähgenehmigung.</p><ul><li>1. Genehmigung</li><li>2.\ + \ Darstellung der betroffenen Rasenfläche</li></ul><p>Mit freundlichen\ + \ Grüßen,<br>Ihr ABSENDER</p>" + maxLength: 5000 + minLength: 0 + lieferTicket: + type: string + description: "Eindeutige Kennung, um mit diesem (Antwort-)Dokument einen\ + \ Bezug zu einem vorhergehenden Antrag herzustellen" + example: ie2391sg5syh4s146jjrb1qatnvwf4w9 + maxLength: 32 + minLength: 0 + testmerker: + $ref: "#/components/schemas/Testmerker" + required: + - absender + - accountId + - anhaenge + - datenart + BereitstellungAuftragNeu_V3: + type: object + description: "Erweiterte Version V3 der Bereitstellungsaufträge-API, bei denen\ + \ die Anhänge (Binärdaten der Dokumente) im Gegensatz zu älteren Versionen\ + \ bereits zuvor in separaten HTTP-Requests gesendet wurden." + properties: + absender: + type: string + example: Stadt Mühldorf + maxLength: 128 + minLength: 0 + accountId: + type: string + description: gibt den ELSTER-Account des Empfängers an + example: "1234567890" + anhaenge: + type: array + description: Liefert die Anhänge (bereitzustellende Binärdaten) dieses Auftrags. + items: + $ref: "#/components/schemas/BereitstellungAnhangWithUploadId" + antwort: + $ref: "#/components/schemas/BereitstellungAntwort" + antwortlinks: + type: array + description: "Informationen u.a. ein Web-Link, die dem Kunden, an den das\ + \ Dokument bereitgestellt wurde, eine Rückantwort ermöglicht." + items: + $ref: "#/components/schemas/BereitstellungAntwortlink" + maxItems: 10 + minItems: 0 + bescheidDatum: + type: string + format: date + description: "Pflichtangabe bei rechtsverbindlichen Bescheiden, sonst nicht\ + \ zulässig" + betreff: + type: string + description: "Pflicht bei Datenarten, bei denen der Betreff nicht automatisch\ + \ ermittelt werden kann (z.\_B. bei \"EPBescheid\", \"EPMitteilung\",\ + \ \"EPKurzmitteilung\"). Sonst ist die Angabe nicht zulässig." + example: Bescheid über Abfallgebühren + maxLength: 255 + minLength: 0 + datenart: + type: string + description: Die gültigen Datenarten hängen von den Berechtigungen des eingestellten + Zertifikats ab. Es sind nur Datenarten für das Verfahren 'ElsterBereitstellung' + zulässig. + example: EPBescheid + emailAdresse: + type: string + description: "E-Mail-Adresse des Empfängers, die bei Bereitstellung eines\ + \ Bescheids über dessen Eingang benachrichtigt wird. Je nach Datenart:\ + \ Optional (z.\_B. bei \"EPBescheid\"), Pflichtfeld (z.\_B. bei \"Gewerbesteuerbescheid\"\ + ), sonst nicht zulässig." + example: test@elster.de + maxLength: 255 + minLength: 0 + emailZusatzText: + type: string + description: "Ergänzender Freitext für die Benachrichtigungsemails, der\ + \ zusätzlich zum Vorlagentext verwendet wird. Nur für bestimmte Datenarten\ + \ (z.\_B. \"EPMitteilung\") und Nutzergruppen (in Abhängigkeit der Anwendungskonfiguration)\ + \ gedacht, sonst nicht zulässig." + example: Bitte beachten Sie § 29 Absatz 3 StVO. Gute Fahrt mit Ihrem Rasenmäher! + maxLength: 500 + minLength: 0 + empfaengerreferenz: + type: string + description: Optionales Feld bei allen Datenarten; Anhand der Referenz kann + der Empfänger den Auftrag zuordnen + example: "Kunde: 134984" + maxLength: 255 + minLength: 0 + geschaeftszeichen: + type: string + description: "Pflichtangabe bei rechtsverbindlichen Bescheiden, sonst optional" + example: XA-123 + maxLength: 60 + minLength: 0 + htmlAnschreiben: + type: string + description: "Optionales formatiertes Anschreiben, das beim Empfänger im\ + \ Posteingang angezeigt werden soll. Als Syntax der Formatierung wird\ + \ eine echten Teilmenge des HTML-Standards verwendet. Zulässig sind HTML-Tags\ + \ der Form: <br> <p>Absatz</p> <ul><li>erster Punkt</li><li>zweiter Punkt</li></ul><ol><li>erster\ + \ Punkt</li><li>zweiter Punkt</li></ol> <strong>starke Hervorhebung (fett\ + \ dargestellt)</strong><em>Hervorhebung (kursiv dargestellt)</em>. Unformatierter\ + \ Text ist als Sonderfall ebenfalls zulässig." + example: "<p>Guten Tag EMPFÄNGER,<br>in den Anhängen finden Sie Ihren Bescheid\ + \ für eine Rasenmähgenehmigung.</p><ul><li>1. Genehmigung</li><li>2.\ + \ Darstellung der betroffenen Rasenfläche</li></ul><p>Mit freundlichen\ + \ Grüßen,<br>Ihr ABSENDER</p>" + maxLength: 5000 + minLength: 0 + lieferTicket: + type: string + description: "Eindeutige Kennung, um mit diesem (Antwort-)Dokument einen\ + \ Bezug zu einem vorhergehenden Antrag herzustellen" + example: ie2391sg5syh4s146jjrb1qatnvwf4w9 + maxLength: 32 + minLength: 0 + testmerker: + $ref: "#/components/schemas/Testmerker" + required: + - absender + - accountId + - anhaenge + - datenart + BereitstellungAuftragStatus: + type: string + description: |- + Aktueller Status für Bereitstellungsaufträge mit folgenden Werten: + IN_BEARBEITUNG: Initialer Status bei neu angelegten Aufträgen. + VERSENDET: Die Nachricht wurde erfolgreich an ELSTER übermittelt. Ein Status wurde noch nicht erzeugt. + EINGESTELLT: Die Nachricht wurde eingestellt, die Benachrichtigung an den Empfänger wurde jedoch noch nicht zugestellt. + BEREIT_ZUR_ABHOLUNG: Die Nachricht wurde an den Empfänger bereitgestellt. Die Benachrichtigung an den Empfänger ist erfolgt. + VOM_EMPFAENGER_ABGEHOLT: Die Nachricht wurde vom Empfänger abgeholt. + EINGANG_BESTAETIGT: Die Anwendung des Empfängers hat die Abholung bestätigt. + GELOESCHT: Die Nachricht wurde aus dem Postfach gelöscht. + + UEBERTRAGUNGSFEHLER: Es ist ein technischer Fehler aufgetreten. + DATEN_FEHLERHAFT: Die Daten konnten aufgrund eines Fehlers nicht an den Empfänger bereitgestellt werden. Mögliche Gründe: Datei invalide, Dateiformat passt nicht zur Dateinamenerweiterung, Virenfund. + INTERNAL_ERROR: Es kam zu einem internen Fehler. + UNBEKANNT: Die Bereitstellung konnte nicht im System gefunden werden. + enum: + - IN_BEARBEITUNG + - UEBERTRAGUNGSFEHLER + - VERSENDET + - EINGESTELLT + - DATEN_FEHLERHAFT + - BEREIT_ZUR_ABHOLUNG + - VOM_EMPFAENGER_ABGEHOLT + - EINGANG_BESTAETIGT + - GELOESCHT + - INTERNAL_ERROR + - UNBEKANNT + BereitstellungInfo: + type: object + properties: + abrufZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit) des Dokumentenabrufs durch den\ + \ Empfänger, sofern bereits abgerufen und ETR bekannt. In zeitlicher Nä\ + he zur Umstellung von Sommer- auf Winterzeit können Abweichungen auftreten,\ + \ da Zeitzoneninformationen nicht an ETR übermittelt werden." + absender: + type: string + description: Anzeigetext des Absenders + example: Stadt Mühldorf + accountId: + type: string + description: Gibt den ELSTER-Account des Empfängers an + example: "1234567890" + anhaenge: + type: array + description: Listet die Anhänge zu dem Bereitstellungsauftrag auf. + items: + $ref: "#/components/schemas/AnhangInfo" + antwort: + $ref: "#/components/schemas/BereitstellungAntwort" + antwortlinks: + type: array + description: "Informationen u.a. ein Web-Link, die dem Kunden, an den das\ + \ Dokument bereitgestellt wurde, eine Rückantwort ermöglicht." + items: + $ref: "#/components/schemas/BereitstellungAntwortlink" + bekanntgabeVorgangsId: + type: string + description: Die Bekanntgabe-Vorgangs-ID wird von ETR beim Erzeugen des + Auftrags generiert. + example: 1bf1c5329c80649f71579db73d549fdb7c12e76624014915eafc4b673decb532 + bescheidDatum: + type: string + format: date + description: "Bei rechtsverbindlichen Bescheiden gesetzt, sonst leer" + example: 2020-12-31 + betreff: + type: string + description: "Betreff (Bezeichnung der Nachricht) je nach Datenart entweder\ + \ frei eingegeben (z.\_B. bei \"EPBescheid\", \"EPMitteilung\", \"EPKurzmitteilung\"\ + ) oder als fester Text aus der Definition der Datenart übernommen" + example: Steuerbescheid + datenart: + type: string + description: Datenart des Bereitstellungsauftrags + example: EPBescheid + emailAdresse: + type: string + format: email + description: "E-Mail-Adresse des Empfängers, die bei Bereitstellung eines\ + \ Bescheids über dessen Eingang benachrichtigt wird." + example: test@elster.de + emailVersandZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit) des Versands von der E-Mail-Benachrichtigung,\ + \ sofern vorhanden und ETR bekannt. Zeitpunkt kann zur Zeitumstellung\ + \ um eine Stunde abweichen, da der Wert nicht wohldefiniert vorliegt." + emailZusatzText: + type: string + description: "Ergänzender Freitext für die Benachrichtigungsemails, der\ + \ zusätzlich zum Vorlagentext verwendet wird. Nur für bestimmte Datenarten\ + \ (z.\_B. \"EPMitteilung\") und Nutzergruppen (in Abhängigkeit der Anwendungskonfiguration)." + example: Bitte beachten Sie § 29 Absatz 3 StVO. Gute Fahrt mit Ihrem Rasenmäher! + empfaengerreferenz: + type: string + description: "Enthält eine Referenz, damit der Empfänger das Dokument zuordnen\ + \ kann" + example: "Kunde: 134984" + erstellZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit), an dem die Bereitstellung erstellt\ + \ worden ist" + fehlerNummer: + type: string + description: "Aus dem Bereitstellungsvorgang zurückgemeldete Fehlernummer,\ + \ sofern bekannt. Relevant nur bei fehlerhaften Datensätzen." + example: "900300008" + fehlerText: + type: string + description: Ausformulierter Text zur 'fehlerNummer'. Relevant nur bei fehlerhaften + Datensätzen. + example: Der Account ist nicht aktiv + geschaeftszeichen: + type: string + description: "Bei rechtsverbindlichen Bescheiden ist dieses Feld Pflicht,\ + \ sonst optional" + example: XA-123 + id: + type: integer + format: int64 + description: ETR interne ID des Auftrags + example: 12345 + lieferTicket: + type: string + description: "Eindeutige Kennung, um mit diesem (Antwort-)Dokument einen\ + \ Bezug zu einem vorhergehenden Antrag herzustellen" + example: ie2391sg5syh4s146jjrb1qatnvwf4w9 + status: + $ref: "#/components/schemas/BereitstellungAuftragStatus" + statusAbfrageZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit), der letzten Statusabfrage" + testmerker: + $ref: "#/components/schemas/TestmerkerInfo" + transferTicket: + type: string + example: ep0104fdrdmr702ki4a1m508vih9v7am + required: + - absender + - accountId + - anhaenge + - antwortlinks + - betreff + - datenart + - erstellZeitpunkt + - id + - status + DownloadAnhangDetails: + type: object + properties: + datei: + type: string + description: "Pfad der Datei relativ zum Eingangsverzeichnis, welche den\ + \ vorliegenden Nutzdaten-Anhang/Dokumentteil enthält." + example: EPAntwort/be1580k8tb22v04if2q0xxcc8vto1v7m.0.pdf + dateiBezeichnung: + type: string + description: "Innerhalb des abgeholten Gesamtdokuments eindeutige Bezeichnung\ + \ des vorliegenden Nutzdaten-Anhangs/Dokumentteils. null, falls vom Absender\ + \ nicht angegeben." + example: Einspruch + downloadUrl: + type: string + format: uri + description: "URL-Suffix ('URI Reference') der REST-API, unter der die Binä\ + r-Nutzdaten des vorliegenden Nutzdaten-Anhangs/Dokumentteils heruntergeladen\ + \ werden können. Umfasst das Dokument mehr als 1 solcher Anhänge/Dokumentteile,\ + \ müssen diese jeweils einzeln heruntergeladen werden. Analog zu den anderen\ + \ REST-Operationen muss der Aufrufer die Basis-URL (Protokoll, Server,\ + \ Port und ggf. Kontextpfad) als Präfix ergänzen." + example: /rest/abholauftrag/12345/download/be123456789011122233301234567890?anhang=3 + mimeType: + type: string + format: mime-type + description: "MIME-Type (nach RFC 6838), in dem der Inhalt des vorliegenden\ + \ Nutzdaten-Anhangs/Dokumentteils kodiert ist. Die Anhänge/Dokumentteile\ + \ können grundsätzlich verschiedene MIME-Type aufweisen (je nach Bereitstellung\ + \ durch den Absender). null, falls vom Absender nicht angegeben." + example: application/pdf + DownloadDetails: + type: object + properties: + ags: + type: string + description: "AGS (Amtlicher Gemeindeschlüssel) der Gemeinde, für die die\ + \ Abholung erfolgte. Nur für bestimmte Datenarten relevant/gesetzt." + example: "09162000" + pattern: "^(?:[0-9]{8})?$" + anhaenge: + type: array + description: "Bereits abgeholte Nutzdaten-Anhänge im Eingangsverzeichnis,\ + \ d.h. die Binärdateien, aus denen sich Gesamtdokument zusammensetzt." + items: + $ref: "#/components/schemas/DownloadAnhangDetails" + anzahlAnhaenge: + type: integer + format: int32 + description: "Anzahl der Anhänge/Dokumentteile/Nutzdatendateien, aus denen\ + \ das Dokument besteht" + example: 1 + minimum: 0 + auftragId: + type: integer + format: int64 + description: "Id des Auftrags, mit dem dieses Dokument ursprünglich abgeholt\ + \ wurde" + example: 12345 + minimum: 1 + beschreibungsdatei: + type: string + description: Name der Datei mit den Metadaten (BDatei) relativ zum Eingangsverzeichnis. + BDateien sind optional und nur bei bestimmten Arten von Downloads vorhanden. + example: GMB/GMB-be0856hnr5qz775zu9s72iv3w7ag5xrc.bdatei + dateiBezeichnung: + type: string + deprecated: true + description: "Bezeichnung des abgeholten Dokuments. null, falls nicht bekannt.\ + \ Sollte ab ETR 3.5.0 nicht mehr verwendet werden, da die einzelnen Anhä\ + nge/Dokumentteile eines Downloads unterschiedliche Dateibezeichnungen\ + \ aufweisen können." + example: Einspruch + dateiTyp: + type: string + format: mime-type + deprecated: true + description: "MIME-Type (nach RFC 6838), der den Inhaltstyp der abgeholten\ + \ (Nutzdaten-)Datei angibt. null, falls nicht bekannt (in der Regel handelt\ + \ es sich dann um ZIP-Archive, die mehrere unterschiedliche Inhalte enthalten).\ + \ Sollte ab ETR 3.5.0 nicht mehr verwendet werden, da nicht zwingend alle\ + \ Anhänge/Dokumentteile eines Downloads den gleichen MIME-TYP aufweisen\ + \ müssen." + example: application/pdf + downloadUrl: + type: string + format: uri + description: "URL-Suffix ('URI Reference') der REST-API, unter der die Binä\ + r-Nutzdaten des Dokuments heruntergeladen werden können. Standardmäßig\ + \ wird der erste Nutzdaten-Anhang/Dokumentteil heruntergeladen. Umfasst\ + \ das Dokument mehr als 1 solcher Anhänge/Dokumentteile, müssen diese\ + \ jeweils einzeln durch Ergänzen des 'anhang'-Parameters heruntergeladen\ + \ werden. Detailangaben zu den Anhängen/Dokumentteilen siehe 'anhaenge'.\ + \ Analog zu den anderen REST-Operationen muss der Aufrufer in jedem Fall\ + \ die Basis-URL (Protokoll, Server, Port und ggf. Kontextpfad) als Prä\ + fix ergänzen." + example: /rest/abholauftrag/12345/download/be123456789011122233301234567890 + downloadZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit), zu dem die Abholung durchgefü\ + hrt wurde" + id: + type: string + description: "Id, die ein abgeholtes Dokument (Download) identifiziert.\ + \ Über die Id kann zur weiteren Verarbeitung auf die Nutzdaten (und ggf.\ + \ vorhandene Beschreibungsdaten) des Dokuments zugegriffen werden." + example: be0856hnr5qz775zu9s72iv3x9ag5xrc + maxLength: 32 + meta: + type: array + description: "Metadaten, die im Rahmen der Abholung mitgegeben wurden, gruppiert\ + \ nach Typ. Bei einfachen Metadaten ist als Schlüssel kein Typ angegeben.\ + \ Im Ausnahmefall können für den gleichen Typ mehrere Gruppen von Metadaten-Angaben\ + \ vorliegen." + items: + $ref: "#/components/schemas/DownloadMetaMap" + nutzdatendatei: + type: string + description: Name der Datei mit den Nutzdaten (NDatei) relativ zum Eingangsverzeichnis + example: GMB/GMB-be0856hnr5qz775zu9s72iv3w7ag5xrc.ndatei + required: + - id + DownloadDetailsList: + type: object + properties: + anzahlDatensaetze: + type: integer + format: int64 + description: Die Anzahl der auf allen Seiten in Summe vorhandenen Ergebnisdatensätze + minimum: 1 + anzahlSeiten: + type: integer + format: int32 + description: Die Anzahl der insgesamt vorhandenen Seiten des Ergebnisses + (inklusive der aktuell abgefragten Seite) + minimum: 1 + datensaetze: + type: array + description: Ergebnis der zuvor ausgeführten Suchanfrage. Enthält maximal + 'seitenGroesse' viele Einträge. Weitere Datensätze müssen ggf. mit weiteren + Aufrufen und passendem 'seitenIndex' abgefragt werden. + items: + $ref: "#/components/schemas/DownloadDetails" + minItems: 1 + seitenGroesse: + type: integer + format: int32 + default: 1000 + description: Anzahl der auf einer Seite zurück zuliefernder Ergebnisdatensätze. + maximum: 10000 + minimum: 1 + seitenIndex: + type: integer + format: int32 + default: 0 + description: "0-basierter Index der Ergebnisseite, die zurückgeliefert werden\ + \ soll. Eine erste Abfrage erfolgt normalerweise mit Seitenindex '0'.\ + \ Die Anzahl der vorhandenen Seiten wird im Abfrageergebnis der ersten\ + \ Seite mitgeliefert." + minimum: 0 + required: + - anzahlDatensaetze + - anzahlSeiten + - datensaetze + DownloadDetailsRequestParams: + type: object + description: "Definiert die Kriterien für eine Abfrage von bereits abgeholten\ + \ Dokumenten (Downloads). Die einzelnen Kriterien, die angegeben werden kö\ + nnen, sind OPTIONAL und UND-verknüpft. Nicht angegebene Kriterien werden bei\ + \ der Abfrage nicht berücksichtigt. Die Anzahl der zurückgelieferten Datensä\ + tze ist auf 'seitenGroesse' viele beschränkt. Durch Iterieren des 'seitenIndex'-Parameters\ + \ kann der Aufrufer ggf. weitere Ergebnisdatensätze abfragen." + properties: + ags: + type: string + description: "Einschränkung der Ergebnisse anhand des AGS (Amtlicher Gemeindeschlü\ + ssels) der Gemeinde, für die die Abholung erfolgte. Angabe ohne Leerstellen\ + \ und ggf. mit führender Null. Zurückgeliefert werden nur Downloads, deren\ + \ AGS exakt mit dem angegebenen Wert übereinstimmt." + example: "09162000" + pattern: "^[0-9]{8}$" + auftragId: + type: integer + format: int64 + description: "Einschränkung der Ergebnisse anhand der Id des Auftrags, mit\ + \ dem dieses Dokument ursprünglich abgeholt wurde" + example: 12345 + datenart: + type: string + description: "Einschränkung der Ergebnisse über die Datenart der abgeholten\ + \ Dokumente. Damit ein Datensatz zurückgeliefert wird, muss der angegebene\ + \ Wert der Datenart (dem Nutzdatentyp) des Einzel- oder Dauerabholauftrags\ + \ entsprechen, mit dem die Abholung erfolgte." + example: GMBX + downloadId: + type: string + description: Einschränkung der Ergebnisse anhand der Id (Best-ID) eines + einzelnen Downloads + example: be0517ip48bhcy04ckhii9i43va0259m + pattern: "^be[0-9a-zA-Z]{30}$" + downloadZeitpunktBis: + type: string + format: date + description: "Einschränkung der Ergebnisse anhand des spätesten Datums,\ + \ an dem der Download ausgeführt wurde" + downloadZeitpunktVon: + type: string + format: date + description: "Einschränkung der Ergebnisse anhand des frühestens Datums,\ + \ an dem der Download ausgeführt wurde" + seitenGroesse: + type: integer + format: int32 + default: 1000 + description: Anzahl der auf einer Seite zurück zuliefernder Ergebnisdatensätze. + maximum: 10000 + minimum: 1 + seitenIndex: + type: integer + format: int32 + default: 0 + description: "0-basierter Index der Ergebnisseite, die zurückgeliefert werden\ + \ soll. Eine erste Abfrage erfolgt normalerweise mit Seitenindex '0'.\ + \ Die Anzahl der vorhandenen Seiten wird im Abfrageergebnis der ersten\ + \ Seite mitgeliefert." + minimum: 0 + DownloadInfo: + type: object + description: Abgeholtes Dokument (Download) + properties: + ags: + type: string + description: "AGS (Amtlicher Gemeindeschlüssel) der Gemeinde, für die die\ + \ Abholung erfolgte. Nur für bestimmte Datenarten relevant/gesetzt." + example: "09162000" + pattern: "^(?:[0-9]{8})?$" + anzahlAnhaenge: + type: integer + format: int32 + description: "Anzahl der Anhänge/Dokumentteile/Nutzdatendateien, aus denen\ + \ das Dokument besteht" + example: 1 + minimum: 0 + dateiBezeichnung: + type: string + deprecated: true + description: "Bezeichnung des abgeholten Dokuments. null, falls nicht bekannt.\ + \ Sollte ab ETR 3.5.0 nicht mehr verwendet werden, da die einzelnen Anhä\ + nge/Dokumentteile eines Downloads unterschiedliche Dateibezeichnungen\ + \ aufweisen können." + example: Einspruch + dateiTyp: + type: string + format: mime-type + deprecated: true + description: "MIME-Type (nach RFC 6838), der den Inhaltstyp der abgeholten\ + \ (Nutzdaten-)Datei angibt. null, falls nicht bekannt (in der Regel handelt\ + \ es sich dann um ZIP-Archive, die mehrere unterschiedliche Inhalte enthalten).\ + \ Sollte ab ETR 3.5.0 nicht mehr verwendet werden, da nicht zwingend alle\ + \ Anhänge/Dokumentteile eines Downloads den gleichen MIME-TYP aufweisen\ + \ müssen." + example: application/pdf + downloadZeitpunkt: + type: string + format: date-time + description: "Zeitpunkt (Datum und Uhrzeit), zu dem die Abholung durchgefü\ + hrt wurde" + id: + type: string + description: "Id, die ein abgeholtes Dokument (Download) identifiziert.\ + \ Über die Id kann zur weiteren Verarbeitung auf die Nutzdaten (und ggf.\ + \ vorhandene Beschreibungsdaten) des Dokuments zugegriffen werden." + example: be0856hnr5qz775zu9s72iv3x9ag5xrc + maxLength: 32 + required: + - id + DownloadMetaAttribut: + type: object + description: Beschreibt generisch das Metadaten-Attribut mit dem angegebenen + Namen und seinen Werten + properties: + name: + type: string + description: Name des technischen oder fachlichen Metadaten-Attributs (eindeutig + innerhalb einer Gruppe) + example: sendername + werte: + type: array + description: "Werte, die das Metadaten-Attribut aufweist. In der Regel 1\ + \ Wert, bei manchen Metadaten-Attributen sind auch mehrere Werte möglich." + items: + $ref: "#/components/schemas/DownloadMetaWert" + minItems: 1 + required: + - name + - werte + DownloadMetaMap: + type: object + description: "Zusammenfassung von entweder einfachen (untypisierten) Metadaten-Attributen\ + \ oder einer zusammengehörigen Gruppe von Metadaten-Attributen eines bestimmten\ + \ Typs, die jeweils zu einem bereits abgeholten Dokument (Download) gehören." + properties: + attributeSortiertNachNamen: + type: array + description: "Metadaten-Attribute, die zu dieser Gruppe von Metadaten-Attributen\ + \ gehören" + items: + $ref: "#/components/schemas/DownloadMetaAttribut" + minItems: 1 + typ: + type: string + description: Gibt den Typ der Metadaten-Attribute an. Wird bei einfachen + (untypisierten) Metadaten im JSON weggelassen. + example: ANTWORT + required: + - attributeSortiertNachNamen + DownloadMetaWert: + type: object + description: Beschreibt den Wert eines Metadaten-Attribut (als generischen Textwert) + properties: + name: + type: string + description: "Optionale Benamung des Werts, sofern im Rahmen der Abholung\ + \ des Dokuments mitgeliefert. Kann bei mehrwertigen Metadaten-Attributen\ + \ zur besseren Unterscheidung verwendet werden." + example: sendername_1 + wert: + type: string + description: Wert eines Metadaten-Attributs (als generischen Textwert). + Der konkrete Datentyp und seine Darstellung/Formatierung sind abhängig + vom konkreten Metadaten-Attribut. + example: Stadt Mühldorf + required: + - wert + Empfaenger: + type: string + description: "Alias oder Kürzel des Empfängers. Dabei wird die Eingabe zunä\ + chst als Alias interpretiert, anschließend, falls kein Alias definiert ist,\ + \ als Kürzel" + enum: + - BW + - BADV + - BY + - BE + - BB + - HB + - Bundeskassen/KKR + - BZST + - HH + - HE + - MV + - NI + - NW + - RP + - SL + - SN + - ST + - SH + - TH + - ZPS ZANS + - CS + SendeAuftragInfo: + type: object + properties: + datenart: + type: string + example: TOT + id: + type: integer + format: int64 + example: 12345 + status: + $ref: "#/components/schemas/AuftragStatus" + required: + - datenart + - id + - status + SendeAuftragNeu: + type: object + properties: + dateiInhalt: + type: string + format: byte + description: Inhalt der Quelldatei als Base64-encodierter String + example: TURFeU16UTFOamM0T1E9PQ== + maxLength: 10485760 + minLength: 0 + datenart: + type: string + description: Die gültigen Datenarten hängen von den Berechtigungen des eingestellten + Zertifikats und vom angegebenen Empfänger ab. Es sind nur Datenarten für + das Verfahren 'ElsterFT' zulässig. Aus Kompatibilitätsgründen zu ElsterFT + und ETR 1.x kann beim Senden im JSON statt "datenart" synonym bis auf + Weiteres auch der Name "nutzdatentyp" für diese Eigenschaft verwendet + werden. + example: TOT + empfaenger: + $ref: "#/components/schemas/Empfaenger" + testmerker: + $ref: "#/components/schemas/Testmerker" + required: + - dateiInhalt + - datenart + - empfaenger + Testmerker: + type: string + description: |- + NUR FÜR INTERNE ZWECKE! + Testmerker manipulieren das Verhalten der nachgelagerten Backend-Systeme: + 370000001 = Test-Datenbank verwenden (nur bei Verwendung eines Testkontos sinnvoll). + 700000001 = Aussteuerung im Land. + 700000004 = Aussteuerung in der Clearing-Stelle. + Im Echtfall braucht kein Testmerker angeben werden. + enum: + - "370000001" + - "700000001" + - "700000004" + TestmerkerInfo: + type: object + description: Informationen zum ausgewählten Testmerker + properties: + id: + type: string + description: "Numerische ID des Testmerkers, wie bei Auftragsanlage angegeben" + example: "700000001" + name: + type: string + description: Identifikation des Testmerkers in Textform + example: AUSSTEUERUNG_LAND + UploadInfo: + type: object + description: "Informationen zu einer zuvor hochgeladenen, temporär auf dem Server\ + \ zwischengespeicherten Binärdatei" + properties: + uploadId: + type: string + format: uuid + description: "Eindeutige Id der hochgeladenen, auf dem Server zwischengespeicherten\ + \ Datei, die bereits zuvor separat hochgeladenen Binärdaten dieses Anhangs\ + \ referenziert. Wird beim Hochladen des Anhangs generiert und zurückgegeben" + required: + - uploadId + securitySchemes: + basicAuth: + scheme: basic + type: http diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/AntwortDetailsTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/AntwortDetailsTestFactory.java index 44dcc3fd847856ea973a965567be4c96736d1595..cb4655d24609b358765dad038031ef563bbf0a7d 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/AntwortDetailsTestFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/AntwortDetailsTestFactory.java @@ -28,13 +28,16 @@ import java.net.URI; import java.util.List; import java.util.UUID; +import org.bson.types.ObjectId; + import de.ozgcloud.muk.elster.transfer.AntwortDetails; import de.ozgcloud.muk.elster.transfer.AntwortDetailsList; import de.ozgcloud.muk.elster.transfer.DownloadAnhangDetails; public class AntwortDetailsTestFactory { public static final String DATEI = "test-data.csv"; - public static final String DATEI_BEZEICHNUNG = "test daten"; + public static final String VORGANG_OBJECT_ID = ObjectId.get().toHexString(); + public static final String DATEI_BEZEICHNUNG = "VorgangId[" + VORGANG_OBJECT_ID + "] Test"; public static final URI DOWNLOAD_URI = URI.create("/download"); public static final String TEXT_CSV = "text/csv"; public static final UUID ZUORDNUNG = ObjectIdToUUIDConverter.toUUID(NACHRICHT_ID); diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteServiceTest.java index d6d65edcc3daba5246c7f03da54cc5c930e4d0da..2229a4bab8dd9e0f10cb7a51a32dcf9fd94f4cb0 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/muk/transfer/ElsterTransferRemoteServiceTest.java @@ -307,7 +307,7 @@ class ElsterTransferRemoteServiceTest { downloadAnhangDetails.setDateiBezeichnung(OzgCloudFileTestFactory.NAME); downloadAnhangDetails.setDatei(""); - var res = elsterTransferService.saveAnhang(data, downloadAnhangDetails, ObjectId.get().toHexString()); + var res = elsterTransferService.saveAnhang(data, downloadAnhangDetails, new ObjectId(NACHRICHT_ID)); assertThat(res).isNotPresent(); @@ -391,7 +391,7 @@ class ElsterTransferRemoteServiceTest { doThrow(IOException.class).when(elsterTransferService).storeToOzgCloud(any(), any(), any()); assertThatExceptionOfType(TechnicalException.class).isThrownBy( - () -> elsterTransferService.saveAnhang(data, downloadAnhangDetails, NACHRICHT_ID) + () -> elsterTransferService.saveAnhang(data, downloadAnhangDetails, null) ); } } @@ -405,7 +405,7 @@ class ElsterTransferRemoteServiceTest { void setUp() { downloadAnhangDetails.setMimeType(OzgCloudFileTestFactory.CONTENT_TYPE); downloadAnhangDetails.setDownloadUrl(URI.create("/download")); - downloadAnhangDetails.setDateiBezeichnung(OzgCloudFileTestFactory.NAME); + downloadAnhangDetails.setDateiBezeichnung(DATEI_BEZEICHNUNG); downloadAnhangDetails.setDatei(OzgCloudFileTestFactory.NAME); } @@ -424,7 +424,6 @@ class ElsterTransferRemoteServiceTest { } @Test - @Disabled("Needs to be reimplemented when the new File API is available") void shouldHaveVorgangId() { var file = ElsterTransferRemoteService.createOzgCloudUploadFile(downloadAnhangDetails, vorgangId); @@ -444,5 +443,27 @@ class ElsterTransferRemoteServiceTest { assertThat(file.getFieldName()).isEqualTo(POSTFACH); } + + } + + @Nested + class TestSaveFile { + @Test + void shouldExtractVorgangIdFromDateibezeichnung() throws IOException { + when(attachmentService.store(any(), any())).thenReturn(new OzgCloudFileId(UUID.randomUUID().toString())); + + elsterTransferService.saveAnhang("Test,Data".getBytes(), AntwortDetailsTestFactory.createDownloadAnhangDetails(), null); + + verify(elsterTransferService).storeToOzgCloud(any(), eq(VORGANG_OBJECT_ID), any()); + } + + @Test + void shouldSaveAttachment() { + when(attachmentService.store(any(), any())).thenReturn(new OzgCloudFileId(UUID.randomUUID().toString())); + + var fileIdOpt = elsterTransferService.saveAnhang("Test,Data".getBytes(), AntwortDetailsTestFactory.createDownloadAnhangDetails(), null); + + assertThat(fileIdOpt).isPresent(); + } } } \ No newline at end of file