222 lines
6.2 KiB
VB.net
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 |