Verträge Suche, modal API, Fremd BRG not found

This commit is contained in:
2025-11-26 09:01:41 +01:00
parent d158dc95f1
commit c15c3d0b89
8 changed files with 1616 additions and 39 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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" />