Verträge Suche, modal API, Fremd BRG not found
This commit is contained in:
@@ -0,0 +1,374 @@
|
||||
Imports System.IO
|
||||
Imports System.Net
|
||||
Imports System.Net.Http
|
||||
Imports System.Net.Http.Headers
|
||||
Imports System.Text
|
||||
Imports System.Windows.Forms
|
||||
Imports System.Collections.Generic
|
||||
Imports Newtonsoft.Json
|
||||
Imports Newtonsoft.Json.Linq
|
||||
|
||||
' ==========================================
|
||||
' Custom-Exception für T1 API Fehler
|
||||
' ==========================================
|
||||
Public Class T1ApiException
|
||||
Inherits Exception
|
||||
|
||||
Public ReadOnly Property StatusCode As HttpStatusCode
|
||||
Public ReadOnly Property ErrorKey As String
|
||||
Public ReadOnly Property RawResponse As String
|
||||
|
||||
Public Sub New(statusCode As HttpStatusCode,
|
||||
message As String,
|
||||
Optional errorKey As String = Nothing,
|
||||
Optional rawResponse As String = Nothing,
|
||||
Optional inner As Exception = Nothing)
|
||||
|
||||
MyBase.New(message, inner)
|
||||
Me.StatusCode = statusCode
|
||||
Me.ErrorKey = errorKey
|
||||
Me.RawResponse = rawResponse
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
|
||||
Public Class cATEZ_Read_T1
|
||||
|
||||
' ==========================
|
||||
' Zentrale Konfiguration
|
||||
' ==========================
|
||||
Private Const BaseUrl As String = "https://t1.declarant.ai/"
|
||||
|
||||
' lt. API-Dokumentation
|
||||
Private Const Username As String = "verag"
|
||||
Private Const Password As String = "verag_password123"
|
||||
Private Const ClientId As String = "client3"
|
||||
Private Const GrantType As String = "password"
|
||||
|
||||
Private Shared ReadOnly client As HttpClient = New HttpClient With {
|
||||
.BaseAddress = New Uri(BaseUrl)
|
||||
}
|
||||
|
||||
' ==========================
|
||||
' Zentrale Error-Auswertung
|
||||
' ==========================
|
||||
Private Async Function CreateAndThrowApiExceptionAsync(response As HttpResponseMessage,
|
||||
context As String) As Task
|
||||
Dim raw As String = String.Empty
|
||||
Try
|
||||
raw = Await response.Content.ReadAsStringAsync()
|
||||
Catch
|
||||
' Ignorieren, wenn Lesen des Inhalts fehlschlägt
|
||||
End Try
|
||||
|
||||
Dim errorKey As String = Nothing
|
||||
Dim message As String = Nothing
|
||||
|
||||
If Not String.IsNullOrWhiteSpace(raw) Then
|
||||
Try
|
||||
Dim jo = JObject.Parse(raw)
|
||||
|
||||
errorKey = jo.Value(Of String)("error_key")
|
||||
If String.IsNullOrEmpty(errorKey) Then
|
||||
errorKey = jo.Value(Of String)("error")
|
||||
End If
|
||||
|
||||
message = jo.Value(Of String)("message")
|
||||
If String.IsNullOrEmpty(message) Then
|
||||
message = jo.Value(Of String)("detail")
|
||||
End If
|
||||
|
||||
If String.IsNullOrEmpty(message) Then
|
||||
message = jo.ToString()
|
||||
End If
|
||||
|
||||
Catch
|
||||
' Inhalt war kein gültiges JSON – unten als Text verwenden
|
||||
End Try
|
||||
End If
|
||||
|
||||
If String.IsNullOrWhiteSpace(message) Then
|
||||
message = $"API-Fehler {CInt(response.StatusCode)} in {context}."
|
||||
If Not String.IsNullOrWhiteSpace(raw) Then
|
||||
message &= " Response: " & raw
|
||||
End If
|
||||
Else
|
||||
message = $"API-Fehler in {context}: " & message
|
||||
End If
|
||||
|
||||
Throw New T1ApiException(response.StatusCode, message, errorKey, raw)
|
||||
End Function
|
||||
|
||||
' ==========================
|
||||
' TOKEN
|
||||
' ==========================
|
||||
Private Async Function GetTokenAsync() As Task(Of String)
|
||||
|
||||
Dim data = New Dictionary(Of String, String) From {
|
||||
{"username", Username},
|
||||
{"password", Password},
|
||||
{"client_id", ClientId},
|
||||
{"grant_type", GrantType}
|
||||
}
|
||||
|
||||
Dim content = New FormUrlEncodedContent(data)
|
||||
|
||||
Dim response As HttpResponseMessage
|
||||
Try
|
||||
response = Await client.PostAsync("token", content)
|
||||
Catch ex As TaskCanceledException
|
||||
Throw New T1ApiException(0, "Zeitüberschreitung beim Aufruf von /token.", Nothing, Nothing, ex)
|
||||
Catch ex As Exception
|
||||
Throw New T1ApiException(0, "Fehler beim Aufruf von /token.", Nothing, Nothing, ex)
|
||||
End Try
|
||||
|
||||
If Not response.IsSuccessStatusCode Then
|
||||
Await CreateAndThrowApiExceptionAsync(response, "/token")
|
||||
End If
|
||||
|
||||
Dim json = Await response.Content.ReadAsStringAsync()
|
||||
Dim tokenObj = JObject.Parse(json)
|
||||
|
||||
Dim token = tokenObj.Value(Of String)("access_token")
|
||||
If String.IsNullOrEmpty(token) Then
|
||||
Throw New T1ApiException(response.StatusCode,
|
||||
"Kein access_token im /token-Response gefunden.",
|
||||
Nothing,
|
||||
json)
|
||||
End If
|
||||
|
||||
Return token
|
||||
End Function
|
||||
|
||||
' ==========================
|
||||
' PROCESS PDF
|
||||
' ==========================
|
||||
Public Async Function ProcessPdfAsync(pdfPath As String) As Task(Of T1ProcessResult)
|
||||
|
||||
If Not File.Exists(pdfPath) Then
|
||||
Throw New FileNotFoundException("PDF-Datei nicht gefunden.", pdfPath)
|
||||
End If
|
||||
|
||||
' Token holen
|
||||
Dim token = Await GetTokenAsync()
|
||||
|
||||
' PDF → Base64
|
||||
Dim base64 = Convert.ToBase64String(File.ReadAllBytes(pdfPath))
|
||||
|
||||
Dim payload = New With {
|
||||
.document_base64 = base64
|
||||
}
|
||||
|
||||
Dim jsonBody = JsonConvert.SerializeObject(payload)
|
||||
Dim content = New StringContent(jsonBody, Encoding.UTF8, "application/json")
|
||||
|
||||
Dim request = New HttpRequestMessage(HttpMethod.Post, "process")
|
||||
request.Headers.Authorization = New AuthenticationHeaderValue("Bearer", token)
|
||||
request.Content = content
|
||||
|
||||
Dim response As HttpResponseMessage
|
||||
Try
|
||||
response = Await client.SendAsync(request)
|
||||
Catch ex As TaskCanceledException
|
||||
Throw New T1ApiException(0, "Zeitüberschreitung beim Aufruf von /process.", Nothing, Nothing, ex)
|
||||
Catch ex As Exception
|
||||
Throw New T1ApiException(0, "Fehler beim Aufruf von /process.", Nothing, Nothing, ex)
|
||||
End Try
|
||||
|
||||
If Not response.IsSuccessStatusCode Then
|
||||
Await CreateAndThrowApiExceptionAsync(response, "/process")
|
||||
End If
|
||||
|
||||
Dim resultJson = Await response.Content.ReadAsStringAsync()
|
||||
|
||||
' JSON → Klasse
|
||||
Dim result As T1ProcessResult
|
||||
Try
|
||||
result = JsonConvert.DeserializeObject(Of T1ProcessResult)(resultJson)
|
||||
Catch ex As Exception
|
||||
Throw New T1ApiException(response.StatusCode,
|
||||
"Konnte /process-Response nicht in T1ProcessResult deserialisieren.",
|
||||
Nothing,
|
||||
resultJson,
|
||||
ex)
|
||||
End Try
|
||||
|
||||
If result Is Nothing Then
|
||||
Throw New T1ApiException(response.StatusCode,
|
||||
"Leeres /process-Ergebnis nach Deserialisierung.",
|
||||
Nothing,
|
||||
resultJson)
|
||||
End If
|
||||
|
||||
Return result
|
||||
End Function
|
||||
|
||||
|
||||
' Sync Wrapper falls du ihn brauchst
|
||||
Public Function ProcessPdf(pdfPath As String) As T1ProcessResult
|
||||
Return ProcessPdfAsync(pdfPath).GetAwaiter().GetResult()
|
||||
End Function
|
||||
|
||||
|
||||
' ==========================
|
||||
' TEST-Methode – ruft ProcessPdfAsync auf und gibt ALLES aus
|
||||
' ==========================
|
||||
Private Async Sub TEST(pdfPath As String)
|
||||
Try
|
||||
' dieselbe Instanz verwenden
|
||||
Dim result As T1ProcessResult = Await Me.ProcessPdfAsync(pdfPath)
|
||||
|
||||
Dim sb As New StringBuilder()
|
||||
|
||||
sb.AppendLine("=== Grunddaten ===")
|
||||
sb.AppendLine("Status: " & If(result.Status, ""))
|
||||
sb.AppendLine("Document Count: " & result.DocumentCount)
|
||||
sb.AppendLine("Document Type: " & If(result.DocumentType, ""))
|
||||
sb.AppendLine("Processing Time (s): " & result.ProcessingTimeSeconds)
|
||||
|
||||
sb.AppendLine()
|
||||
sb.AppendLine("=== Kopf-T1-Daten ===")
|
||||
sb.AppendLine("Date: " & If(result.DateField, ""))
|
||||
sb.AppendLine("Dispatch Country: " & If(result.DispatchCountry, ""))
|
||||
sb.AppendLine("Dispatch Place: " & If(result.DispatchPlace, ""))
|
||||
sb.AppendLine("Loading Place: " & If(result.LoadingPlace, ""))
|
||||
sb.AppendLine("Destination Country: " & If(result.DestinationCountry, ""))
|
||||
sb.AppendLine("Destination Customs Authority: " & If(result.DestinationCustomsAuthority, ""))
|
||||
sb.AppendLine("Mode of Transport: " & If(result.ModeOfTransport, ""))
|
||||
sb.AppendLine("Type of Transport: " & If(result.TypeOfTransport, ""))
|
||||
sb.AppendLine("Transit ID: " & If(result.TransitId, ""))
|
||||
sb.AppendLine("Truck ID Border: " & If(result.TruckIdBorder, ""))
|
||||
sb.AppendLine("Truck ID Transit: " & If(result.TruckIdTransit, ""))
|
||||
|
||||
sb.AppendLine()
|
||||
sb.AppendLine("=== Items ===")
|
||||
If result.Items IsNot Nothing AndAlso result.Items.Count > 0 Then
|
||||
For i As Integer = 0 To result.Items.Count - 1
|
||||
Dim it = result.Items(i)
|
||||
sb.AppendLine($"Item #{i + 1}")
|
||||
sb.AppendLine($" Export ID: {it.ExportId}")
|
||||
sb.AppendLine($" Invoice No: {it.InvoiceNo}")
|
||||
sb.AppendLine($" Item Index: {it.ItemIndex}")
|
||||
sb.AppendLine($" Sender: {it.Sender}")
|
||||
sb.AppendLine($" Total Package: {it.TotalPackage}")
|
||||
sb.AppendLine($" Total Weight: {it.TotalWeight}")
|
||||
sb.AppendLine()
|
||||
Next
|
||||
Else
|
||||
sb.AppendLine("Keine Items vorhanden.")
|
||||
End If
|
||||
|
||||
sb.AppendLine("=== Additional Data (ungeparst) ===")
|
||||
If result.AdditionalData IsNot Nothing AndAlso result.AdditionalData.Count > 0 Then
|
||||
For Each kvp In result.AdditionalData
|
||||
sb.AppendLine($" {kvp.Key}: {kvp.Value.ToString()}")
|
||||
Next
|
||||
Else
|
||||
sb.AppendLine("Keine zusätzlichen Felder.")
|
||||
End If
|
||||
|
||||
MessageBox.Show(sb.ToString(), "T1 Dokument verarbeitet", MessageBoxButtons.OK, MessageBoxIcon.Information)
|
||||
|
||||
Catch apiEx As T1ApiException
|
||||
Dim sbErr As New StringBuilder()
|
||||
sbErr.AppendLine("T1 API Fehler")
|
||||
sbErr.AppendLine("HTTP-Status: " & CInt(apiEx.StatusCode))
|
||||
If Not String.IsNullOrEmpty(apiEx.ErrorKey) Then
|
||||
sbErr.AppendLine("Error Key: " & apiEx.ErrorKey)
|
||||
End If
|
||||
sbErr.AppendLine("Nachricht: " & apiEx.Message)
|
||||
If Not String.IsNullOrEmpty(apiEx.RawResponse) Then
|
||||
sbErr.AppendLine()
|
||||
sbErr.AppendLine("Raw Response:")
|
||||
sbErr.AppendLine(apiEx.RawResponse)
|
||||
End If
|
||||
|
||||
MessageBox.Show(sbErr.ToString(), "T1 API Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
|
||||
|
||||
Catch ex As Exception
|
||||
MessageBox.Show(ex.ToString(), "Allgemeiner Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
||||
|
||||
Public Class T1ProcessItem
|
||||
<JsonProperty("export_id")>
|
||||
Public Property ExportId As String
|
||||
|
||||
<JsonProperty("invoice_no")>
|
||||
Public Property InvoiceNo As String
|
||||
|
||||
<JsonProperty("item_index")>
|
||||
Public Property ItemIndex As Integer
|
||||
|
||||
<JsonProperty("sender")>
|
||||
Public Property Sender As String
|
||||
|
||||
<JsonProperty("total_package")>
|
||||
Public Property TotalPackage As Integer
|
||||
|
||||
<JsonProperty("total_weight")>
|
||||
Public Property TotalWeight As Decimal
|
||||
End Class
|
||||
|
||||
|
||||
Public Class T1ProcessResult
|
||||
|
||||
' ---- Basic processing info ----
|
||||
<JsonProperty("document_count")>
|
||||
Public Property DocumentCount As Integer
|
||||
|
||||
<JsonProperty("document_type")>
|
||||
Public Property DocumentType As String
|
||||
|
||||
<JsonProperty("processing_time_seconds")>
|
||||
Public Property ProcessingTimeSeconds As Decimal
|
||||
|
||||
<JsonProperty("status")>
|
||||
Public Property Status As String
|
||||
|
||||
' ---- Main data from T1 ----
|
||||
<JsonProperty("date")>
|
||||
Public Property DateField As String
|
||||
|
||||
<JsonProperty("destination_country")>
|
||||
Public Property DestinationCountry As String
|
||||
|
||||
<JsonProperty("destination_customs_authority")>
|
||||
Public Property DestinationCustomsAuthority As String
|
||||
|
||||
<JsonProperty("dispatch_country")>
|
||||
Public Property DispatchCountry As String
|
||||
|
||||
<JsonProperty("dispatch_place")>
|
||||
Public Property DispatchPlace As String
|
||||
|
||||
<JsonProperty("loading_place")>
|
||||
Public Property LoadingPlace As String
|
||||
|
||||
<JsonProperty("mode_of_transport")>
|
||||
Public Property ModeOfTransport As String
|
||||
|
||||
<JsonProperty("transit_id")>
|
||||
Public Property TransitId As String
|
||||
|
||||
<JsonProperty("truck_id_border")>
|
||||
Public Property TruckIdBorder As String
|
||||
|
||||
<JsonProperty("truck_id_transit")>
|
||||
Public Property TruckIdTransit As String
|
||||
|
||||
<JsonProperty("type_of_transport")>
|
||||
Public Property TypeOfTransport As String
|
||||
|
||||
' ---- Items ----
|
||||
<JsonProperty("items")>
|
||||
Public Property Items As List(Of T1ProcessItem)
|
||||
|
||||
' ---- Catch all remaining fields (if API expands) ----
|
||||
<JsonExtensionData>
|
||||
Public Property AdditionalData As IDictionary(Of String, JToken)
|
||||
|
||||
End Class
|
||||
@@ -309,7 +309,7 @@ Public Class cModalTransIMPORT
|
||||
.goods_location = "GBFXT",
|
||||
.border_transport_type = "3", ' z. B. Straße
|
||||
.total_packages = 5,
|
||||
.trader_ref = LRN,
|
||||
.commercial_ref = LRN, ' .trader_ref = LRN,
|
||||
.ducr = LRN
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ Public Class cModalTransIMPORT
|
||||
.import_country_id = "GB",
|
||||
.total_packages = 5,
|
||||
.nature_of_transaction = "11", ' Kaufgeschäft 11 Outright purchase/sale
|
||||
.trader_ref = LRN,
|
||||
.commercial_ref = LRN, ' .trader_ref = LRN,
|
||||
.ducr = LRN
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ Public Class cModalTransIMPORT
|
||||
.goods_location = "GBAUDEUDEUDEU",
|
||||
.total_packages = 5,
|
||||
.nature_of_transaction = "11", ' Kaufgeschäft 11 Outright purchase/sale
|
||||
.trader_ref = LRN,
|
||||
.commercial_ref = LRN, ' .trader_ref = LRN,
|
||||
.ducr = LRN
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,7 @@
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Schnittstellen\ATEZ\GREENPULSE\cATEZ_Greenpulse_KafkaDecs.vb" />
|
||||
<Compile Include="Schnittstellen\ATEZ\Read_T1\cATEZ_Read_T1.vb" />
|
||||
<Compile Include="Schnittstellen\ATEZ\RELAYHUB\cRelayHub.vb" />
|
||||
<Compile Include="Schnittstellen\ATEZ\RELAYHUB\cRelayHubToken.vb" />
|
||||
<Compile Include="Schnittstellen\BZST\cBZST_UID_XML.vb" />
|
||||
|
||||
Reference in New Issue
Block a user