kAssenbuch, etc.

This commit is contained in:
2026-05-28 14:30:36 +02:00
parent d1ceb61efe
commit 62d776f00a
6 changed files with 366 additions and 116 deletions

View File

@@ -23,9 +23,9 @@ Public Class cFiskaltrustClient
' ================================
' PUBLIC API
' ================================
Public Async Function SignReceiptAsync(amount As Double, vat As Double, POS As List(Of EABelegPositionen)) As Task(Of String)
Public Async Function SignReceiptAsync(amount As Decimal, vat As Decimal, POS As List(Of EABelegPositionen), KindOfPayment As String, posSystemId As String) As Task(Of String)
Dim payload = BuildPayloadReceipt(amount, vat, POS)
Dim payload = BuildPayloadReceipt(amount, vat, POS, KindOfPayment, posSystemId)
Dim endpoint = GetEndpoint("payment")
Dim requestContent As StringContent
@@ -46,9 +46,119 @@ Public Class cFiskaltrustClient
End Function
Public Async Function SignNullReceiptAsync() As Task(Of String)
Public Async Function Echo(KassenName As String) As Task(Of String)
Dim payload = BuildPayloadNullReceipt()
Dim payload = KassenName & " - VERBINDUNG OK"
Dim endpoint = GetEndpoint("test")
Dim requestContent As StringContent
If _country = "AT" Then
' Plaintext
Dim text As String = If(payload?.ToString(), "")
Dim json As String = JsonConvert.SerializeObject(text)
requestContent = New StringContent(json, Encoding.UTF8, "text/plain")
Else
' JSON Objekt
Dim obj = New With {
.Message = payload
}
Dim json As String = JsonConvert.SerializeObject(obj)
requestContent = New StringContent(json, Encoding.UTF8, "application/json")
End If
Return Await SendAsync(endpoint, payload, requestContent)
End Function
' Optional: Storno Beispiel
'reference unique id!
Public Async Function CancelReceiptAsync(reference As String, POS As List(Of EABelegPositionen), amount As Decimal, kindOfPayment As String) As Task(Of String)
' 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 = 0,
.Description = p.LeistungsBez,
.ftChargeItemCase = 4919338167972134929
})
Next
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = "POS-1",
.cbTerminalID = "T1",
.cbReceiptReference = reference,
.cbReceiptMoment = DateTime.UtcNow.ToString("o"),
.ftReceiptCase = 4919338172267102210,
.cbChargeItems = chargeItems,
.cbPayItems = New Object() {
New With {
.Quantity = 1.0,
.Amount = amount,
.Description = kindOfPayment,
.ftPayItemCase = 4919338167972134913
}
}
}
Dim requestContent As StringContent
If _country = "AT" Then
' Plaintext
Dim text As String = If(payload?.ToString(), "")
Dim json As String = JsonConvert.SerializeObject(text)
requestContent = New StringContent(json, Encoding.UTF8, "text/plain")
Else
' JSON Objekt
Dim json As String = JsonConvert.SerializeObject(payload)
requestContent = New StringContent(json, Encoding.UTF8, "application/json")
End If
Return Await SendAsync(GetEndpoint("payment"), payload, requestContent)
End Function
Public Async Function SignNullReceiptAsync(posSystemId As String) As Task(Of String)
Dim payload = BuildPayloadNullReceipt(posSystemId, _country)
Dim endpoint = GetEndpoint("payment")
Dim requestContent As StringContent
If _country = "AT" Then
' Plaintext
Dim text As String = If(payload?.ToString(), "")
Dim json As String = JsonConvert.SerializeObject(text)
requestContent = New StringContent(json, Encoding.UTF8, "text/plain")
Else
' JSON Objekt
Dim json As String = JsonConvert.SerializeObject(payload)
requestContent = New StringContent(json, Encoding.UTF8, "application/json")
End If
Return Await SendAsync(endpoint, payload, requestContent)
End Function
Public Async Function SignClosinglReceiptAsync(type As String, posSystemId As String) As Task(Of String)
Dim payload = BuildPayloadCosinglReceipt(type, posSystemId)
Dim endpoint = GetEndpoint("payment")
Dim requestContent As StringContent
@@ -70,6 +180,7 @@ Public Class cFiskaltrustClient
End Function
Public Async Function Journal(type As String) As Task(Of String)
@@ -99,7 +210,7 @@ Public Class cFiskaltrustClient
End Function
Public Async Function SignReceiptAsync_test() As Task(Of String)
Public Async Function SignReceiptAsync_test(posSystemId As String) As Task(Of String)
Dim LIST = New List(Of EABelegPositionen)
Dim p = New EABelegPositionen
@@ -116,7 +227,7 @@ Public Class cFiskaltrustClient
p.Anzahl = 1
LIST.Add(p)
Dim payload = BuildPayloadReceipt(100, 0, LIST)
Dim payload = BuildPayloadReceipt(100, 0, LIST, "Cash", posSystemId)
Dim endpoint = GetEndpoint("payment")
Dim requestContent As StringContent
@@ -140,52 +251,26 @@ Public Class cFiskaltrustClient
End Function
Public Async Function Echo() As Task(Of String)
Dim payload = "VERBINDUNGSPRÜFUNG ERFOLGREICH"
Dim endpoint = GetEndpoint("test")
Dim requestContent As StringContent
If _country = "AT" Then
' Plaintext
Dim text As String = If(payload?.ToString(), "")
Dim json As String = JsonConvert.SerializeObject(text)
requestContent = New StringContent(json, Encoding.UTF8, "text/plain")
Else
' JSON Objekt
Dim obj = New With {
.Message = payload
}
Dim json As String = JsonConvert.SerializeObject(obj)
requestContent = New StringContent(json, Encoding.UTF8, "application/json")
End If
Public Async Function CancelReceiptAsync_test(reference As String, amount As Decimal, kindOfPayment As String) As Task(Of String)
Dim LIST = New List(Of EABelegPositionen)
Dim p = New EABelegPositionen
p.Mandant = "VERA"
p.Niederlassung = "SUB"
p.Benutzer = 74
p.BelegDat = Now
p.BelegNr = 1
p.PreislistenNr = 1
p.PreislistenPos = 1
p.LeistungsNr = 300
p.LeistungsBez = "TEST"
p.Preis = 10
p.Anzahl = 1
LIST.Add(p)
Return Await SendAsync(endpoint, payload, requestContent)
End Function
' Optional: Storno Beispiel
'reference unique id!
Public Async Function CancelReceiptAsync(reference As String, POS As List(Of EABelegPositionen), amount As Double) As Task(Of String)
' 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 = 0,
.Description = p.LeistungsBez,
.ftChargeItemCase = 4919338167972134929
})
Next
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = "POS-1",
@@ -198,7 +283,7 @@ Public Class cFiskaltrustClient
New With {
.Quantity = 1.0,
.Amount = amount,
.Description = "Cash",
.Description = kindOfPayment,
.ftPayItemCase = 4919338167972134913
}
}
@@ -224,66 +309,73 @@ Public Class cFiskaltrustClient
End Function
Private Async Function SendAsync(endpoint As String, payload As Object, requestContent As StringContent) As Task(Of String)
Dim exToThrow As Exception = Nothing
Dim url = _baseUrl & endpoint
Dim retries As Integer = 3
Dim delayMs As Integer = 500
For attempt = 1 To retries
Dim lastException As Exception = Nothing
Dim shouldRetry As Boolean = False
For attempt As Integer = 1 To retries
shouldRetry = False
Try
Using request As New HttpRequestMessage(HttpMethod.Post, url)
request.Headers.Add("cashboxid", _cashboxId)
request.Headers.Add("accesstoken", _accessToken)
If payload <> "" Then
If requestContent IsNot Nothing Then
request.Content = requestContent
End If
Dim response = Await _httpClient.SendAsync(request)
Dim result = Await response.Content.ReadAsStringAsync()
' Logging Hook
Log($"[{DateTime.Now}] Response ({response.StatusCode}): {result}")
Log($"[{DateTime.Now}] Response ({CInt(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)
Dim statusCode As Integer = CInt(response.StatusCode)
If statusCode >= 500 Then
shouldRetry = True
Throw New Exception($"Server error ({statusCode}): {result}")
Else
' Client error → no retry
Throw New Exception("Client error: " & result)
Throw New Exception($"Client error ({statusCode}): {result}")
End If
End Using
Catch ex As Exception
Log($"[{DateTime.Now}] Attempt {attempt} failed: {ex.Message}")
lastException = ex
If attempt = retries Then
exToThrow = ex
End If
Log($"[{DateTime.Now}] Attempt {attempt} failed: {ex.Message}")
End Try
' Await außerhalb von Catch
If shouldRetry AndAlso attempt < retries Then
Await Task.Delay(delayMs)
End If
Next
If exToThrow IsNot Nothing Then
Await Task.Delay(1000)
Throw exToThrow
If lastException IsNot Nothing Then
Throw lastException
End If
Throw New Exception("Unexpected error")
@@ -291,11 +383,19 @@ Public Class cFiskaltrustClient
End Function
Private Function BuildPayloadReceipt(amount As Double, vat As Double, POS As List(Of EABelegPositionen)) As Object
Private Function BuildPayloadReceipt(amount As Decimal, vat As Decimal, POS As List(Of EABelegPositionen), KindOfPayment As String, posSystemId As String) As Object
' ChargeItems Liste vorbereiten
Dim chargeItems = New List(Of Object)
Dim PayItemCase As Long
Select Case KindOfPayment
Case "Cash" : PayItemCase = 4919338167972134913
Case "Card" : PayItemCase = 4919338167972134913 '-> richtigen Type finden
End Select
For Each p In POS
chargeItems.Add(New With {
.Quantity = p.Anzahl,
@@ -309,7 +409,7 @@ Public Class cFiskaltrustClient
' Payload Objekt erstellen
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = "POS-1",
.ftPosSystemId = posSystemId,
.cbTerminalID = "T1",
.cbReceiptReference = Guid.NewGuid().ToString(),
.cbReceiptMoment = DateTime.UtcNow.ToString("o"),
@@ -318,28 +418,71 @@ Public Class cFiskaltrustClient
New With {
.Quantity = 1.0,
.Amount = amount,
.Description = "Cash",
.ftPayItemCase = 4919338167972134913
.Description = KindOfPayment,
.ftPayItemCase = PayItemCase
}
},
.ftReceiptCase = 4919338172267102209
.ftReceiptCase = 4919338172267102209 'IMPLICIT-FLOW -> STANDARD-BARVERKAUF
}
Return payload
End Function
Private Function BuildPayloadNullReceipt() As Object
Private Function BuildPayloadNullReceipt(posSystemId As String, country As String) As Object
Dim ftReceiptCase_ As Long
Dim cbReceiptReference_ As String
Select Case country
Case "DE"
ftReceiptCase_ = 4919338172267102210 'NULL-BELEG DE
cbReceiptReference_ = "ZeroReceiptAfterFailure"
Case Else
ftReceiptCase_ = 4707387510509010946 'NULL-BELEG AT
cbReceiptReference_ = "2"
End Select
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = "POS-1",
.ftPosSystemId = posSystemId,
.cbTerminalID = "T1",
.cbReceiptReference = "ZeroReceiptAfterFailure",
.cbReceiptReference = cbReceiptReference_,
.cbReceiptMoment = DateTime.UtcNow.ToString("o"),
.cbChargeItems = New Object() {},
.cbPayItems = New Object() {},
.ftReceiptCase = 4919338172267102210
.ftReceiptCase = ftReceiptCase_
}
Return payload
End Function
Private Function BuildPayloadCosinglReceipt(type As String, posSystemId As String)
'Kassenabschlussbelege
Dim caseID As Long
Select Case type
Case "daily" : caseID = 4919338172267102210
Case "monthly" : caseID = 4919338172267102213
Case "yearly" : caseID = 4919338172267102214
End Select
Dim payload = New With {
.ftCashBoxID = _cashboxId,
.ftPosSystemId = posSystemId,
.cbTerminalID = "T1",
.cbReceiptReference = type & "-closing-" & DateTime.UtcNow.ToString("o"),
.cbReceiptMoment = DateTime.UtcNow.ToString("o"),
.cbChargeItems = New Object() {},
.cbPayItems = New Object() {},
.ftReceiptCase = caseID
}
@@ -442,9 +585,8 @@ Public Class cFiskaltrustClient
Dim numSignatures As Integer = Signatures.Size
For i = 0 To numSignatures
For i = 0 To numSignatures - 1
While i < numSignatures
Dim SignObj As Chilkat.JsonObject = Signatures.ObjectAt(i)
Dim ftSigPos As New cFiskaltrustSignaturPositions()
@@ -461,8 +603,6 @@ Public Class cFiskaltrustClient
End With
i = i + 1
End While
Next

View File

@@ -125,9 +125,11 @@ Public Class cRKSV
Dim BetragSatzBesonders = IIf(steuersatz = 0.19, summeBRUTTO, 0.0)
Dim StandUmsatzzaehler = umsatzZaehler 'KASSE.rksv_Umsatzzaehler
Dim countryID As String
Dim client As New cFiskaltrustClient(kasse.rksv_FT_RestServiceURL, kasse.rksv_FT_CashboxID, kasse.rksv_FT_AccessToken, kasse.rksv_FT_Country)
Dim result = Await client.SignReceiptAsync(summeBRUTTO, steuersatz, POS)
Dim result = Await client.SignReceiptAsync(summeBRUTTO, steuersatz, POS, "Cash", kasse.rksv_id)
client.saveRKSV_FT(result, QR_CodeString)

View File

@@ -146,6 +146,7 @@ Partial Class frmBelegNeu
Me.DataGridViewTextBoxColumn9 = New System.Windows.Forms.DataGridViewTextBoxColumn()
Me.FlowLayoutPanel2 = New System.Windows.Forms.FlowLayoutPanel()
Me.ContextMenuStrip1 = New System.Windows.Forms.ContextMenuStrip(Me.components)
Me.cm_FT = New System.Windows.Forms.ContextMenuStrip(Me.components)
CType(Me.dgvBelegPos, System.ComponentModel.ISupportInitialize).BeginInit()
Me.pnl.SuspendLayout()
Me.pnlData.SuspendLayout()
@@ -1778,6 +1779,11 @@ Partial Class frmBelegNeu
Me.ContextMenuStrip1.Name = "ContextMenuStrip1"
Me.ContextMenuStrip1.Size = New System.Drawing.Size(61, 4)
'
'cm_FT
'
Me.cm_FT.Name = "ContextMenuStrip1"
Me.cm_FT.Size = New System.Drawing.Size(61, 4)
'
'frmBelegNeu
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
@@ -1928,4 +1934,5 @@ Partial Class frmBelegNeu
Friend WithEvents LinkLabel1 As LinkLabel
Friend WithEvents cboBuchungsoforterzeugen As CheckBox
Friend WithEvents Button4 As Button
Friend WithEvents cm_FT As ContextMenuStrip
End Class

View File

@@ -159,6 +159,9 @@
<metadata name="ContextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="cm_FT.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>173, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>86</value>
</metadata>

View File

@@ -1712,8 +1712,10 @@ Public Class frmBelegNeu
If Not verarbeitet Then
If Not TESTBUCHUNG Then
KASSE.DECREASE_BELEG_UMSATZ(oldBelegZaehler, If(EA = "E", summeBRUTTO * -1, summeBRUTTO))
cRKSV.DELETE(BELEG, KASSE.rksv_firma)
End If
Dim Errmsg = "Programmfehler bei der digitalen Signatur." & vbNewLine & vbNewLine & answer
MsgBox(Errmsg, MsgBoxStyle.Critical)
@@ -1887,40 +1889,136 @@ Public Class frmBelegNeu
Process.Start("https://wiki.verag.ag/de/software/aviso/howtos/Bankomat")
End Sub
Private Async Function Button4_ClickAsync(sender As Object, e As EventArgs) As Task Handles Button4.Click
Try
Dim QR_CodeString As String = ""
Dim LastJWS As String = ""
KASSE.LOAD(cboKassen._value)
If KASSE.rksv_FT_RestServiceURL <> "" Then
Dim client As New cFiskaltrustClient(KASSE.rksv_FT_RestServiceURL, KASSE.rksv_FT_CashboxID, KASSE.rksv_FT_AccessToken, KASSE.rksv_FT_Country)
Dim result_verbindungstest As String = Await client.Echo()
Dim result_zahlung As String = Await client.SignReceiptAsync_test()
client.saveRKSV_FT(result_zahlung, QR_CodeString)
MsgBox(result_verbindungstest)
Else
MsgBox("keine Rest-Service URL hinterlegt!")
End If
Catch ex As Exception
End Try
End Function
Private Sub cboKassen_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboKassen.SelectedIndexChanged
KASSE.LOAD(cboKassen._value)
Button4.Visible = KASSE.rksv_FT_RestServiceURL <> ""
End Sub
Private Sub Button4_ClickAsync(sender As Object, e As EventArgs) Handles Button4.Click
If Not cm_FT.Items.ContainsKey("null") Then
Dim plose = New ToolStripMenuItem() With {.Text = "Nullbeleg", .Name = "null", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
cm_FT.Items.Add(plose)
AddHandler plose.Click, AddressOf mnuItemAuftrauege_Clicked
End If
If Not cm_FT.Items.ContainsKey("monthly") Then
Dim rmc = New ToolStripMenuItem() With {.Text = "Monatabschluss", .Name = "monthly", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler rmc.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(rmc)
End If
If Not cm_FT.Items.ContainsKey("daily") Then
Dim rmc = New ToolStripMenuItem() With {.Text = "Tagesabschluss", .Name = "daily", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler rmc.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(rmc)
End If
If Not cm_FT.Items.ContainsKey("yearly") Then
Dim uta = New ToolStripMenuItem() With {.Text = "Jahresabschluss", .Name = "yearly", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler uta.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(uta)
End If
If Not cm_FT.Items.ContainsKey("bar") Then
Dim ids = New ToolStripMenuItem() With {.Text = "Barverkauf", .Name = "bar", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler ids.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(ids)
End If
If Not cm_FT.Items.ContainsKey("storno") Then
Dim ids = New ToolStripMenuItem() With {.Text = "Storno", .Name = "storno", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler ids.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(ids)
End If
If Not cm_FT.Items.ContainsKey("test") Then
Dim ids = New ToolStripMenuItem() With {.Text = "Verbindungstest", .Name = "test", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler ids.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(ids)
End If
If Not cm_FT.Items.ContainsKey("journal") Then
Dim ids = New ToolStripMenuItem() With {.Text = "Journal", .Name = "journal", .Font = New Font(Me.Font.FontFamily, Me.Font.Size)}
AddHandler ids.Click, AddressOf mnuItemAuftrauege_Clicked
cm_FT.Items.Add(ids)
End If
cm_FT.Show(Cursor.Position)
End Sub
Private Async Function mnuItemAuftrauege_Clicked(sender As Object, e As EventArgs) As Task(Of Object)
cm_FT.Hide()
Dim item As ToolStripMenuItem = TryCast(sender, ToolStripMenuItem)
If item IsNot Nothing Then
KASSE.LOAD(cboKassen._value)
Dim client As New cFiskaltrustClient(KASSE.rksv_FT_RestServiceURL, KASSE.rksv_FT_CashboxID, KASSE.rksv_FT_AccessToken, KASSE.rksv_FT_Country)
If item.Name = "null" Then
'beide
Dim result As String = Await client.SignNullReceiptAsync(KASSE.rksv_id)
MsgBox(result)
ElseIf item.Name = "test" Then
'beide
Dim result As String = Await client.Echo(KASSE.rksv_bez & " " & KASSE.rksv_FT_Country & " - ")
MsgBox(result)
ElseIf item.Name = "storno" Then
'beide
Dim result As String = Await client.CancelReceiptAsync_test("-1", 100, "Cash")
MsgBox(result)
ElseIf item.Name = "bar" Then
'beide
Dim result As String = Await client.SignReceiptAsync_test(KASSE.rksv_id)
MsgBox(result)
ElseIf item.Name = "monthly" Then
'beide
Dim result As String = Await client.SignClosinglReceiptAsync(item.Name, KASSE.rksv_id)
MsgBox(result)
ElseIf item.Name = "daily" Then
'Nur DE
If KASSE.rksv_FT_Country = "DE" Then
Dim result As String = Await client.SignClosinglReceiptAsync(item.Name, KASSE.rksv_id)
MsgBox(result)
Else
MsgBox("nicht für AT-Kassen möglich!")
End If
ElseIf item.Name = "yearly" Then
Dim result As String = Await client.SignClosinglReceiptAsync(item.Name, KASSE.rksv_id)
MsgBox(result)
ElseIf item.Name = "journal" Then
Dim result As String = Await client.Journal(2)
MsgBox(result)
End If
End If
End Function
End Class
Class TestRKSVW

View File

@@ -1150,7 +1150,7 @@ Public Class frmKassenbuch
If KASSE.rksv_FT_RestServiceURL <> "" Then
Dim client As New cFiskaltrustClient(KASSE.rksv_FT_RestServiceURL, KASSE.rksv_FT_CashboxID, KASSE.rksv_FT_AccessToken, KASSE.rksv_FT_Country)
Dim result = Await client.SignNullReceiptAsync()
Dim result = Await client.SignNullReceiptAsync(RKSV.rksv_id)
Dim QR_CodeString As String = ""
client.saveRKSV_FT(result, QR_CodeString)
Else