Files
SDL/SDL/Classes/cFiskaltrustClient.vb
2026-03-31 16:22:01 +02:00

222 lines
6.2 KiB
VB.net

Imports System.Net.Http
Imports System.Text
Imports Newtonsoft.Json
Imports System.Threading
Public Class cFiskaltrustClient
Private ReadOnly _baseUrl As String
Private ReadOnly _cashboxId As String
Private ReadOnly _accessToken As String
Private ReadOnly _country As String
Private Shared ReadOnly _httpClient As New HttpClient()
Public Sub New(baseUrl As String, cashboxId As String, accessToken As String, country As String)
_baseUrl = baseUrl.TrimEnd("/"c)
_cashboxId = cashboxId
_accessToken = accessToken
_country = country
End Sub
' ================================
' PUBLIC API
' ================================
Public Async Function SignReceiptAsync(amount As Double, vat As Double, POS As List(Of EABelegPositionen)) As Task(Of String)
Dim payload = BuildPayload(amount, vat, POS)
Dim endpoint = GetEndpoint("payment")
Return Await SendAsync(endpoint, payload)
End Function
Public Async Function Echo() As Task(Of String)
Dim payload = "TEST"
Dim endpoint = GetEndpoint("test")
Return Await SendAsync(endpoint, payload)
End Function
' Optional: Storno Beispiel
Public Async Function CancelReceiptAsync(reference As String) As Task(Of String)
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = "POS-1",
.cbTerminalID = "T1",
.cbReceiptReference = reference,
.cbReceiptMoment = DateTime.UtcNow.ToString("o"),
.ftReceiptCase = 4919338172267102210 ' Storno
}
Return Await SendAsync(GetEndpoint("payment"), payload)
End Function
' ================================
' CORE HTTP LOGIC (RETRY!)
' ================================
Private Async Function SendAsync(endpoint As String, payload As Object) As Task(Of String)
Dim exToThrow As Exception = Nothing
Dim json As String = JsonConvert.SerializeObject(payload)
Dim url = _baseUrl & endpoint
Dim retries As Integer = 3
Dim delayMs As Integer = 500
For attempt = 1 To retries
Try
Using request As New HttpRequestMessage(HttpMethod.Post, url)
request.Headers.Add("cashboxid", _cashboxId)
request.Headers.Add("accesstoken", _accessToken)
Select Case _country
Case "AT"
request.Content = New StringContent(json, Encoding.UTF8, "text/xml")
Case Else
request.Content = New StringContent(json, Encoding.UTF8, "application/json")
End Select
Dim response = Await _httpClient.SendAsync(request)
Dim result = Await response.Content.ReadAsStringAsync()
' Logging Hook
Log($"[{DateTime.Now}] Response ({response.StatusCode}): {result}")
If response.IsSuccessStatusCode Then
Return result
End If
' Retry only on transient errors
If CType(response.StatusCode, Integer) >= 500 Then
Throw New Exception("Server error: " & result)
Else
' Client error → no retry
Throw New Exception("Client error: " & result)
End If
End Using
Catch ex As Exception
Log($"[{DateTime.Now}] Attempt {attempt} failed: {ex.Message}")
If attempt = retries Then
exToThrow = ex
End If
End Try
Next
If exToThrow IsNot Nothing Then
Await Task.Delay(1000) ' ✅ jetzt OK
Throw exToThrow
End If
Throw New Exception("Unexpected error")
End Function
' ================================
' PAYLOAD BUILDER
' ================================
Private Function BuildPayload(amount As Double, vat As Double, POS As List(Of EABelegPositionen)) As Object
' ChargeItems Liste vorbereiten
Dim chargeItems = New List(Of Object)
For Each p In POS
chargeItems.Add(New With {
.Quantity = p.Anzahl,
.Amount = p.Preis,
.VATRate = vat,
.Description = p.LeistungsBez,
.ftChargeItemCase = 4919338167972134929
})
Next
' Payload Objekt erstellen
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = "POS-1",
.cbTerminalID = "T1",
.cbReceiptReference = Guid.NewGuid().ToString(),
.cbReceiptMoment = DateTime.UtcNow.ToString("o"),
.cbChargeItems = chargeItems,
.cbPayItems = New Object() {
New With {
.Quantity = 1.0,
.Amount = amount,
.Description = "Cash",
.ftPayItemCase = 4919338167972134913
}
},
.ftReceiptCase = 4919338172267102209
}
Return payload
End Function
' ================================
' ENDPOINT SWITCH
' ================================
Private Function GetEndpoint(type As String) As String
If type = "payment" Then
Select Case _country
Case "DE"
Return "/json/v1/Sign"
Case "AT"
Return "/json/Sign"
Case Else
Throw New Exception("Unsupported country")
End Select
ElseIf type = "test" Then
Select Case _country
Case "DE"
Return "/json/v1/Echo"
Case "AT"
Return "/json/Echo"
Case Else
Throw New Exception("Unsupported country")
End Select
End If
End Function
' ================================
' LOGGING (REPLACE IN PROD!)
' ================================
Private Sub Log(message As String)
' 👉 Hier anschließen:
' - Datei
' - Datenbank
' - Serilog / NLog
Console.WriteLine(message)
End Sub
End Class