Imports Newtonsoft.Json Public Class cRelayHub Public Class cRelayHubDocument Public Property type As String Public Property base64String As String Public Property filename As String Public Property fileType As String End Class Public Class cRelayHubTransaction Public Property ioPartner As String Public Property ioDivision3 As String Public Property ioReference As String End Class Public Class cRelayHubObjectIdentification Public Property objectName As String Public Property objectAlias As String Public Property declarationType As String Public Property referenceNumberOverlay As String ' <--- NEU Public Property username As String ' <--- NEU End Class Public Class cRelayHubDv1CostAllocation Public Property costType As String Public Property costs As Decimal Public Property currencyCode As String End Class Public Class cRelayHubAgentContact Public Property contactPersonName As String Public Property contactPersonPhoneNumber As String Public Property contactPersonPosition As String Public Property contactPersonEmail As String ' <--- NEU End Class Public Class cRelayHubCost Public Property costAmount As String Public Property costCurrency As String End Class Public Class cRelayHubHeaderData Public Property agentContact As cRelayHubAgentContact Public Property declarantIsConsignee As Boolean Public Property representationRelationshipCode As String ' <- war String Public Property inputTaxDeduction As Boolean ' <- war String Public Property procedureCodeRequested As String ' Entfernt: goodsStatus, costs (nicht im Schema an dieser Stelle) Public Property transportMeansArrivalIdentity As String Public Property transportMeansNationalityCode As String Public Property previousAdministrativeReferenceType As String Public Property previousAdministrativeReferenceNumber As String Public Property destinationFederalState As String Public Property destinationCountry As String Public Property departureCountry As String Public Property addressedCustomsOffice As String Public Property dv1CostAllocation As cRelayHubDv1CostAllocation End Class Public Class cRelayHubAddress Public Property addressType As String Public Property participantEORI As String Public Property participantSubsidiaryNumber As String Public Property companyName As String Public Property streetAndNumber As String Public Property countryCode As String Public Property postalCode As String Public Property city As String End Class Public Class cRelayHubDeclaration Public Property objectIdentification As cRelayHubObjectIdentification Public Property headerData As cRelayHubHeaderData Public Property addresses As List(Of cRelayHubAddress) End Class Public Class cRelayHubAdditionalData Public Property transaction As cRelayHubTransaction Public Property declaration As List(Of cRelayHubDeclaration) End Class Public Class cRelayHubJobOrderRequest Public Property referenceNo As String Public Property dispatchCountry As String Public Property destinationCountry As String Public Property regimeType As String ' Entfernt: customer (vom Schema abgelehnt) Public Property documents As List(Of cRelayHubDocument) Public Property additionalData As cRelayHubAdditionalData ' Neu: Pflichtfeld lt. Fehlermeldung Public Property outputApplication As String ' "test" | "dakosy/sftp/vera" | "evrim/excel" | "sec/import/integration" End Class Public Class cRelayHubJobOrderResponse Public Property id As String Public Property status As String Public Property createdAt As String Public Property referenceNo As String End Class Public Class cRelayHubApiResult Public Property Success As Boolean Public Property StatusCode As Integer Public Property Message As String ' Zusammenfassung Public Property Details As String ' Volltext/Fehlermeldung Public Property Data As cRelayHubJobOrderResponse ' Nur bei 201 End Class Public Class cRelayHub_sendToRelayHub_JobOrderRequest Shared API_URL As String = "https://declaranthub.singlewindow.io/api/v1-0" ' Low-level Sender: holt Access-Token aus cRelayHubToken und sendet JSON Private Shared Function SendJobOrder(jsonPayload As String) As Chilkat.HttpResponse Dim http As New Chilkat.Http http.SetRequestHeader("Accept", "application/json") ' *** Token aus der separaten Token-Klasse beziehen *** Dim token As String = cRelayHubToken.GetAccessToken() http.AuthToken = token 'http.AuthToken = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJqdkkzQ3BfbTVTb3JpdUFmSEZkZzJWUGgxcDFNWHA3ZnpjNFhyVHpGWVc4In0.eyJleHAiOjE3NjEzMDE4NTQsImlhdCI6MTc2MTIxNTQ1NCwianRpIjoiNWY3MjdkZTUtMmQ2MS00MThkLWJhYWQtNmY5ODM0NDk2NjY2IiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5zaW5nbGV3aW5kb3cuaW8vYXV0aC9yZWFsbXMvYWdzdyIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI5OWMwOTFmMy01Mjg1LTRhNzUtODdjNC0zODJlNThlNTBmNGMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhZ3N3LWFkbWluIiwic2lkIjoiMzRjMDY4ZGMtNjY3My00NDk5LTgzODAtMjVkOGYyNjI1NGY4IiwiYWxsb3dlZC1vcmlnaW5zIjpbImh0dHBzOi8vc2luZ2xld2luZG93LmlvIiwiaHR0cHM6Ly9hZ3N3LnNpbmdsZXdpbmRvdy5pbyIsImh0dHA6Ly9sb2NhbGhvc3Q6MzAwMSJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1hZ3N3Iiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZHVjdC1jYXRhbG9nLXNjcCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJEaHViLVByb2QgVXNlciIsInByZWZlcnJlZF91c2VybmFtZSI6ImRodWJAdmVyYWcuYWciLCJnaXZlbl9uYW1lIjoiRGh1Yi1Qcm9kIiwiZmFtaWx5X25hbWUiOiJVc2VyIiwiZW1haWwiOiJkaHViQHZlcmFnLmFnIn0.TZ8GkXrL7SSz1CEOnLB2eAAuVcYu3wlNtnAF6Y3wt0lnMGyse5tsI0YYSfGZG_Ae8zVcPqHqVT4rhDOgIPooBkq71z35ppd6b-FUaS6hSy4cMWQaidsHZr3hkID8amVQcB2vz9Yg985h3MOCSIn86d0x9i0euew3wEpF8eEHSfk_Wqf8jeJbiXAPHfy92K4Xh8IIuh-GXUTyN-NmGM94_NhcQwb4e7YMXjPPuslUsjABEfOvT7v4-AnO5B3ZczX0h0UgafmfiIyXSaL4IzYZojoMJ0CRsHdAK-j4gzXqz4lW0A9KMmHGHn01Oftt9mXfrEmCj0XGWF9xvBuYhxMUAQ" Console.WriteLine("Using Token =: " & http.AuthToken) Console.WriteLine("API_URL =: " & API_URL) Return http.PostJson2(API_URL & "/job-orders/init", "application/json", jsonPayload) End Function ' Public API: erstellt Job-Order mit 401-Retry Public Shared Function query_declarations(request As cRelayHubJobOrderRequest) As cRelayHubApiResult Dim result As New cRelayHubApiResult() Try VERAG_PROG_ALLGEMEIN.cChilkat_Helper.UnlockCilkat() Dim sanitized = Sanitize(request) Dim settings As New JsonSerializerSettings With { .NullValueHandling = NullValueHandling.Ignore, .ContractResolver = New Newtonsoft.Json.Serialization.DefaultContractResolver With { .NamingStrategy = New Newtonsoft.Json.Serialization.CamelCaseNamingStrategy() } } Dim jsonPayload As String = JsonConvert.SerializeObject(sanitized, settings) Console.WriteLine("JSON → " & jsonPayload) 'Dim jsonPayload As String = JsonConvert.SerializeObject(request) ' 1. Versuch Dim response As Chilkat.HttpResponse = SendJobOrder(jsonPayload) If response Is Nothing Then Return New cRelayHubApiResult With { .Success = False, .StatusCode = 0, .Message = "Verbindungsfehler", .Details = "Keine Antwort erhalten." } End If '' 401 → Token-Cache invalidieren und genau 1x erneut probieren 'If response.StatusCode = 401 Then ' ' WICHTIG: ' ' Diese Methode sollte in cRelayHubToken als Public verfügbar sein: ' ' Public Shared Sub ResetTokenCache() : ClearToken() : End Sub ' ' → Falls noch nicht vorhanden, bitte dort ergänzen. ' Try ' cRelayHubToken.ResetTokenCache() ' Catch ' ' Falls die Methode (noch) nicht existiert, kann man als Fallback ' ' hier eine kurze Wartezeit einbauen und anschließend erneut GetValidAccessToken() aufrufen. ' ' Threading.Thread.Sleep(100) ' End Try ' ' Retry ' response = SendJobOrder(jsonPayload) ' If response Is Nothing Then ' Return New cRelayHubApiResult With { ' .Success = False, .StatusCode = 0, .Message = "Verbindungsfehler (nach Refresh)", ' .Details = "Keine Antwort erhalten." ' } ' End If 'End If ' Auswertung result.StatusCode = response.StatusCode Console.WriteLine("result.StatusCode → " & result.StatusCode) Select Case response.StatusCode Case 201 Try Dim jobResponse As cRelayHubJobOrderResponse = JsonConvert.DeserializeObject(Of cRelayHubJobOrderResponse)(response.BodyStr) result.Success = True result.Message = "Job Order erfolgreich erstellt" result.Data = jobResponse result.Details = $"ID: {jobResponse.id}, Referenz: {jobResponse.referenceNo}" Catch ex As Exception result.Success = False result.StatusCode = 999 result.Message = "Antwort konnte nicht gelesen werden" result.Details = ex.Message End Try Case 400 To 499 result.Success = False result.Message = "Client-Fehler" result.Details = response.BodyStr Case 500 To 599 result.Success = False result.Message = "Server-Fehler" result.Details = response.BodyStr Case Else result.Success = False result.Message = $"Unbekannter Fehler (Status {response.StatusCode})" result.Details = response.BodyStr End Select Return result Catch ex As Exception VERAG_PROG_ALLGEMEIN.cErrorHandler.ERR(ex.Message, ex.StackTrace, System.Reflection.MethodInfo.GetCurrentMethod.Name) Return New cRelayHubApiResult With {.Success = False, .StatusCode = 0, .Message = "Exception", .Details = ex.ToString()} End Try End Function Private Shared Function Sanitize(req As cRelayHub.cRelayHubJobOrderRequest) As cRelayHub.cRelayHubJobOrderRequest req.outputApplication = If(req.outputApplication, "").Trim() req.dispatchCountry = If(req.dispatchCountry, "").Trim().ToUpperInvariant() req.destinationCountry = If(req.destinationCountry, "").Trim().ToUpperInvariant() ' lokale Fail-fast Checks If req.dispatchCountry.Length <> 2 Then Throw New ApplicationException("dispatchCountry ISO-2 erforderlich.") If req.destinationCountry.Length <> 2 Then Throw New ApplicationException("destinationCountry ISO-2 erforderlich.") Return req End Function ' Beispielfall Function CreateSampleJobOrderRequest() As cRelayHubJobOrderRequest Dim req As New cRelayHubJobOrderRequest With { .referenceNo = "1001K", .dispatchCountry = "TR", ' ISO-2 .destinationCountry = "DE", ' ISO-2 (nicht "EN") .regimeType = "IMPORT", ' "IMPORT" | "EXPORT" .outputApplication = "test", ' Pflichtfeld lt. Validator .documents = New List(Of cRelayHubDocument) From { New cRelayHubDocument With {.type = "base64", .base64String = "SGVsbG8sIHRoaXMgaXMgYSBzYW1wbGUgYmFzZTY0IHN0cmluZy4=", .filename = "test.txt", .fileType = "invoice"}, New cRelayHubDocument With {.type = "base64", .base64String = "SGVsbG8sIHRoaXMgaXMgYSBzYW1wbGUgYmFzZTY0IHN0cmluZy4=", .filename = "test2.txt", .fileType = "atr"}, New cRelayHubDocument With {.type = "base64", .base64String = "SGVsbG8sIHRoaXMgaXMgYSBzYW1wbGUgYmFzZTY0IHN0cmluZy4=", .filename = "test3.txt", .fileType = "cmr"} }, .additionalData = New cRelayHubAdditionalData With { .transaction = New cRelayHubTransaction With { .ioPartner = "VERA", .ioDivision3 = "SUB", .ioReference = "4803/25001763_1301250935SS/samimx" }, .declaration = New List(Of cRelayHubDeclaration) From { New cRelayHubDeclaration With { .objectIdentification = New cRelayHubObjectIdentification With { .objectName = "4803/25001763", .objectAlias = "1349846", .declarationType = "EZA-D" }, .headerData = New cRelayHubHeaderData With { .agentContact = New cRelayHubAgentContact With { .contactPersonName = "AMANN", .contactPersonPhoneNumber = "+49 123 456 789", .contactPersonPosition = "Manager", .contactPersonEmail = "a@example.com" }, .declarantIsConsignee = True, .representationRelationshipCode = 1, ' Integer .inputTaxDeduction = True, ' Boolean .procedureCodeRequested = "42", ' goodsStatus/costs entfernt .transportMeansArrivalIdentity = "PB1552EC", .transportMeansNationalityCode = "BG", .previousAdministrativeReferenceType = "T1", .previousAdministrativeReferenceNumber = "25TR160100001472M0", .destinationFederalState = "07", .destinationCountry = "DE", .departureCountry = "TR" }, .addresses = New List(Of cRelayHubAddress) From { New cRelayHubAddress With {.addressType = "CZ", .participantEORI = "EORI12345", .participantSubsidiaryNumber = "001", .companyName = "SISECAM DIS TIC.A.S.", .streetAndNumber = "D-100 KARAYOLU CD.YAYLA MH.NO.70/C", .countryCode = "TR", .postalCode = "34949", .city = "TUZLA ISTANBUL"}, New cRelayHubAddress With {.addressType = "CN", .participantEORI = "EORI67890", .participantSubsidiaryNumber = "002", .companyName = "POLYNT COMPOSITES GERMANY GMBH", .streetAndNumber = "KIESELSTRASSE 2", .countryCode = "DE", .postalCode = "56357", .city = "MIEHLEN"} } } } } } Return req End Function End Class End Class