Files
SDL/VERAG_PROG_ALLGEMEIN/Schnittstellen/ATEZ/RELAYHUB/cRelayHub.vb
2025-11-14 10:24:45 +01:00

356 lines
18 KiB
VB.net

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 cRelayHubAdditionalSettings
Public Property combineOptions As List(Of String)
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
Public Property additionalSettings As cRelayHubAdditionalSettings
' 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
Public Shared Function getRelayHub_AnhDesc(anh_Art) As String
Dim fileType = "other"
If anh_Art IsNot Nothing AndAlso anh_Art IsNot DBNull.Value Then
Select Case anh_Art
Case "eFatura", "INVOICE" : fileType = "invoice"
Case "Rechnung", "Konsi-Rechnung", "INVOICE" : fileType = "commercial_invoice"
Case "CMR" : fileType = "cmr"
Case "Ausfuhr", "EXPORT" : fileType = "tr_export_declaration"
Case "ATR", "A.TR", "ATR-EUR1", "EUR1" : fileType = "atr"
Case "Vorpapier", "T1" : fileType = "transit_declaration"
Case "Ursprungszeugnis", "CoO" : fileType = "origin"
Case "Lieferschein" : fileType = "delivery_note"
Case "Packliste" : fileType = "packaging_list"
Case Else : fileType = "other"
End Select
End If
Return fileType
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()
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.")
' AdditionalSettings -> combineOptions: nur erlaubte Keys, distinct, lower-case
Dim allowed As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {
"description", "commodity_code", "country_of_origin", "unit_type"
}
If req.additionalSettings IsNot Nothing AndAlso req.additionalSettings.combineOptions IsNot Nothing Then
Dim cleaned = req.additionalSettings.combineOptions.
Where(Function(o) Not String.IsNullOrWhiteSpace(o)).
Select(Function(o) o.Trim().ToLowerInvariant()).
Where(Function(o) allowed.Contains(o)).
Distinct().
ToList()
req.additionalSettings.combineOptions = cleaned
End If
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"}
}
}
}
},
.additionalSettings = New cRelayHubAdditionalSettings With {
.combineOptions = New List(Of String) From {
"description",
"commodity_code",
"country_of_origin",
"unit_type"
}
}
}
Return req
End Function
End Class
End Class