Files
SDL/VERAG_PROG_ALLGEMEIN/Schnittstellen/ATEZ/RELAYHUB/cRelayHub.vb

518 lines
25 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
Public Property avisoId As String ' <--- NEU
Public Property shipmentId 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
' DAKOSY
Public Property declarantIsConsignee As Boolean?
Public Property representationRelationshipCode As String
Public Property inputTaxDeduction As Boolean?
Public Property procedureCodeRequested As String
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
' MODALTRANS
Public Property serviceCode As String
Public Property docType As String
Public Property declarationType As String
Public Property declarantEori As String
Public Property additionalProcedureCode As String
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
Public Property district 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 micImportShipment As cRelayHubMicImportShipment
Public Property declaration As List(Of cRelayHubDeclaration)
End Class
Public Class cRelayHubMicImportShipment
Public Property company As String
Public Property plant As String
Public Property connectionId As String
Public Property partnerId As String
Public Property partyId As String
Public Property messageId As String
Public Property transactionId As String
Public Property dateTime As String
Public Property sequenceNum As Integer?
Public Property actionCode As String
Public Property shipmentId As String
Public Property shipmentPartial As String
Public Property shipmentVersion As Integer?
Public Property documentNumber As Integer?
Public Property shipmentType As String
Public Property customsDate As String
End Class
Public Class cRelayHubAdditionalSettings
Public Property combineOptions As List(Of String)
Public Property combineItemsPriorityDocumentType As String
Public Property disableOutbound As Boolean?
Public Property disableDocumentConverter As Boolean?
Public Property disableAiToCommon As Boolean?
Public Property disableValidation As Boolean?
Public Property targetLang As String
End Class
Public Class cRelayHubJobOrderRequest
<JsonIgnore>
Public Property environment As cRelayHubEnvironment = cRelayHubEnvironment.PROD
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"
' "modaltrans/customs/declaration"
End Class
Public Class cRelayHubOutputApplication
Public Const Dakosy As String = "dakosy/sftp/verg"
Public Const Modaltrans As String = "modaltrans/customs/declaration"
Public Const MIC_NL_IMPORT As String = "mic/import"
End Class
Public Enum cRelayHubEnvironment
TEST
PROD
End Enum
Public Class cRelayHubJobOrderResponse
Public Property id As String
Public Property status As String
Public Property createdAt As String
Public Property referenceNo As String
Public Property jobOrderProcessingId As String
Public Property jobOrderNo 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
Private Shared ReadOnly ENVIRONMENT As cRelayHubEnvironment = cRelayHubEnvironment.PROD
Shared API_URL As String = "https://declaranthub.singlewindow.io/api/v1-0"
Private Shared Function GetApiUrl(environment As cRelayHubEnvironment) As String
Select Case environment
Case cRelayHubEnvironment.TEST
Return "https://test-relayhub.singlewindow.io/api/v1-0"
Case cRelayHubEnvironment.PROD
Return "https://declaranthub.singlewindow.io/api/v1-0"
Case Else
Throw New ApplicationException("Unbekannte RelayHub-Umgebung.")
End Select
End Function
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, environment As cRelayHubEnvironment) As Chilkat.HttpResponse
Dim http As New Chilkat.Http
http.SetRequestHeader("Accept", "application/json")
Dim token As String = cRelayHubToken.GetAccessToken(environment)
http.AuthToken = token
Dim apiUrl As String = GetApiUrl(environment)
Dim fullUrl As String = apiUrl & "/job-orders/init"
Console.WriteLine("API_URL =: " & apiUrl)
Debug.WriteLine("RelayHub Environment: " & environment.ToString())
Debug.WriteLine("RelayHub URL: " & fullUrl)
Debug.WriteLine("RelayHub OutputApplication: " & If(JsonConvert.DeserializeObject(Of cRelayHubJobOrderRequest)(jsonPayload).outputApplication, ""))
Return http.PostJson2(apiUrl & "/job-orders/init", "application/json", jsonPayload)
End Function
' Public API: erstellt Job-Order mit 401-Retry
Public Shared Function getJSON(request As cRelayHubJobOrderRequest) As String
Try
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)
Return jsonPayload
Catch ex As Exception
VERAG_PROG_ALLGEMEIN.cErrorHandler.ERR(
ex.Message,
ex.StackTrace,
System.Reflection.MethodInfo.GetCurrentMethod.Name)
Return "Error"
End Try
End Function
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, request.environment)
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" : fileType = "atr"
Case "Vorpapier", "T1" : fileType = "transit_declaration"
Case "Ursprungszeugnis", "CoO" : fileType = "origin"
Case "Lieferschein" : fileType = "delivery_note"
Case "Packliste" : fileType = "packing_list"
Case "Freihandelszone", "FTZ" : fileType = "ftz"
Case "EUR1", "EUR", "EUR.1" : fileType = "eur"
Case "GGED_D", "GGED-D" : fileType = "gged_p"
Case Else : fileType = "unknown" '"other"
End Select
End If
Return fileType
End Function
Private Shared Function IsModaltrans(req As cRelayHubJobOrderRequest) As Boolean
Return String.Equals(req.outputApplication, "modaltrans/customs/declaration", StringComparison.OrdinalIgnoreCase)
End Function
Private Shared Function IsMIC_NL_IMPORT(req As cRelayHubJobOrderRequest) As Boolean
Return String.Equals(req.outputApplication, cRelayHubOutputApplication.MIC_NL_IMPORT, StringComparison.OrdinalIgnoreCase)
End Function
Private Shared Sub SetMIC_NL_IMPORT(req As cRelayHubJobOrderRequest)
If req.environment = cRelayHubEnvironment.PROD Then Throw New ApplicationException("MIC NL Import ist derzeit nur im RelayHub-Testsystem verfügbar.")
req.outputApplication = "mic/import"
req.regimeType = "IM"
If req.additionalData Is Nothing Then req.additionalData = New cRelayHubAdditionalData
If req.additionalData.micImportShipment Is Nothing Then req.additionalData.micImportShipment = New cRelayHubMicImportShipment
Dim mic = req.additionalData.micImportShipment
mic.company = "NL"
mic.plant = "IN"
mic.connectionId = "MICWebService"
mic.actionCode = "DIF"
If String.IsNullOrWhiteSpace(mic.partnerId) Then mic.partnerId = req.referenceNo
If String.IsNullOrWhiteSpace(mic.shipmentId) Then mic.shipmentId = req.referenceNo
If String.IsNullOrWhiteSpace(mic.messageId) Then mic.messageId = req.referenceNo
If String.IsNullOrWhiteSpace(mic.transactionId) Then mic.transactionId = req.referenceNo
If String.IsNullOrWhiteSpace(mic.dateTime) Then mic.dateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
If String.IsNullOrWhiteSpace(mic.shipmentType) Then mic.shipmentType = "E"
If req.additionalSettings Is Nothing Then req.additionalSettings = New cRelayHubAdditionalSettings
req.additionalSettings.disableOutbound = False
End Sub
Private Shared Function Sanitize(req As cRelayHubJobOrderRequest) As cRelayHubJobOrderRequest
If req Is Nothing Then Throw New ApplicationException("RelayHub Request fehlt.")
Dim isMicNlImport As Boolean = IsMIC_NL_IMPORT(req)
If isMicNlImport Then SetMIC_NL_IMPORT(req)
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.")
If isMicNlImport Then
If req.additionalData Is Nothing OrElse req.additionalData.micImportShipment Is Nothing Then Throw New ApplicationException("micImportShipment für MIC NL Import erforderlich.")
Dim mic = req.additionalData.micImportShipment
mic.partnerId = If(mic.partnerId, "").Trim()
mic.partyId = If(mic.partyId, "").Trim()
mic.shipmentId = If(mic.shipmentId, "").Trim()
If mic.partnerId = "" Then Throw New ApplicationException("MIC partnerId erforderlich.")
If mic.partyId = "" Then Throw New ApplicationException("MIC partyId erforderlich.")
If mic.shipmentId = "" Then Throw New ApplicationException("MIC shipmentId erforderlich.")
ElseIf IsModaltrans(req) Then
If req.additionalData IsNot Nothing Then
req.additionalData.transaction = Nothing
If req.additionalData.declaration IsNot Nothing Then
For Each declaration In req.additionalData.declaration
declaration.objectIdentification = Nothing
Next
End If
End If
If req.additionalSettings IsNot Nothing AndAlso req.additionalSettings.combineOptions Is Nothing Then req.additionalSettings.combineOptions = New List(Of String)
Else
Dim allowed As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {
"description",
"commodity_code",
"country_of_origin",
"unit_type"
}
If req.additionalSettings IsNot Nothing Then
If req.additionalSettings.combineOptions IsNot Nothing Then req.additionalSettings.combineOptions = 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.combineItemsPriorityDocumentType = If(req.additionalSettings.combineItemsPriorityDocumentType, "").Trim()
If req.additionalSettings.combineItemsPriorityDocumentType = "" Then req.additionalSettings.combineItemsPriorityDocumentType = Nothing
End If
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