Merge branch 'newMaster2024' of https://git.it.verag.ag/edv/SDL into newMaster2024
This commit is contained in:
@@ -319,4 +319,184 @@ Public Class MyDatagridview
|
||||
End Sub
|
||||
|
||||
|
||||
' ========================================================
|
||||
' ================== COPY/PASTE SUPPORT ==================
|
||||
' ========================================================
|
||||
' Standard: Nur erste Spalte (MRN) befüllen. Auf False setzen, um Blöcke (mehrere Spalten) zuzulassen.
|
||||
<Browsable(True), DefaultValue(True)>
|
||||
Public Property _PasteSingleColumn As Boolean = True
|
||||
|
||||
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
|
||||
' Strg+V oder Shift+Insert => Einfügen
|
||||
If (e.Control AndAlso e.KeyCode = Keys.V) OrElse (e.Shift AndAlso e.KeyCode = Keys.Insert) Then
|
||||
PasteFromClipboard()
|
||||
e.Handled = True
|
||||
Return
|
||||
End If
|
||||
MyBase.OnKeyDown(e)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Fügt den Clipboard-Text (Excel: TAB/CRLF) in die DGV ein.
|
||||
''' </summary>
|
||||
Public Sub PasteFromClipboard()
|
||||
Dim text As String = Clipboard.GetText()
|
||||
If String.IsNullOrWhiteSpace(text) Then Exit Sub
|
||||
|
||||
Dim lines = text.Split({vbCrLf, vbLf, vbCr}, StringSplitOptions.None)
|
||||
If lines.Length > 0 AndAlso lines(lines.Length - 1).Trim() = "" Then
|
||||
ReDim Preserve lines(lines.Length - 2)
|
||||
End If
|
||||
If lines.Length = 0 Then Exit Sub
|
||||
|
||||
Dim startRow As Integer = If(Me.CurrentCell IsNot Nothing, Me.CurrentCell.RowIndex, 0)
|
||||
Dim startCol As Integer = If(Me.CurrentCell IsNot Nothing, Me.CurrentCell.ColumnIndex, 0)
|
||||
If startRow < 0 Then startRow = 0
|
||||
If startCol < 0 Then startCol = 0
|
||||
|
||||
' Temporär das „Neue-Zeile“-Verhalten und Binding einfrieren
|
||||
Dim oldAddRows = Me.AllowUserToAddRows
|
||||
Me.AllowUserToAddRows = False
|
||||
Me.SuspendLayout()
|
||||
Dim cm As CurrencyManager = Nothing
|
||||
Try
|
||||
If TypeOf Me.DataSource Is DataTable Then
|
||||
Dim bs As CurrencyManager = TryCast(Me.BindingContext(Me.DataSource), CurrencyManager)
|
||||
cm = bs
|
||||
cm?.SuspendBinding()
|
||||
End If
|
||||
|
||||
For i As Integer = 0 To lines.Length - 1
|
||||
Dim r As Integer = startRow + i
|
||||
Dim rowText As String = lines(i)
|
||||
If String.IsNullOrWhiteSpace(rowText) Then Continue For
|
||||
|
||||
Dim cells = rowText.Split(vbTab)
|
||||
EnsureRowExists(r)
|
||||
|
||||
If _PasteSingleColumn Then
|
||||
Dim targetCol As Integer = 0 ' MRN-Spalte
|
||||
If targetCol >= 0 AndAlso targetCol < Me.Columns.Count Then
|
||||
SetCellValueSafe(r, targetCol, cells(0))
|
||||
End If
|
||||
Else
|
||||
For j As Integer = 0 To cells.Length - 1
|
||||
Dim c As Integer = startCol + j
|
||||
If c >= 0 AndAlso c < Me.Columns.Count Then
|
||||
SetCellValueSafe(r, c, cells(j))
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Next
|
||||
|
||||
Me.EndEdit() ' Commits pending edits im Grid
|
||||
If TypeOf Me.DataSource Is DataTable Then
|
||||
DirectCast(Me.DataSource, DataTable).AcceptChanges()
|
||||
End If
|
||||
Finally
|
||||
cm?.ResumeBinding()
|
||||
Me.ResumeLayout()
|
||||
Me.AllowUserToAddRows = oldAddRows
|
||||
Me.Refresh()
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
Private Sub SetCellValueSafe(rowIndex As Integer, colIndex As Integer, raw As String)
|
||||
If rowIndex < 0 OrElse rowIndex >= Me.Rows.Count Then Exit Sub
|
||||
Dim col = Me.Columns(colIndex)
|
||||
Dim v As String = If(raw, String.Empty).Trim()
|
||||
|
||||
' Fall A: Datengebunden -> direkt in DataTable schreiben (über DataPropertyName)
|
||||
If TypeOf Me.DataSource Is DataTable Then
|
||||
Dim dt = DirectCast(Me.DataSource, DataTable)
|
||||
Dim prop = If(String.IsNullOrWhiteSpace(col.DataPropertyName), col.Name, col.DataPropertyName)
|
||||
If Not dt.Columns.Contains(prop) Then
|
||||
' Kein gebundenes Feld vorhanden -> fallback auf Zellenwert
|
||||
GoTo FallbackCell
|
||||
End If
|
||||
|
||||
Dim targetType As Type = dt.Columns(prop).DataType
|
||||
Dim obj As Object = DBNull.Value
|
||||
|
||||
Try
|
||||
If targetType Is GetType(String) Then
|
||||
obj = If(v = "", DBNull.Value, CType(v, String))
|
||||
ElseIf targetType Is GetType(Date) OrElse targetType Is GetType(DateTime) Then
|
||||
If v = "" Then
|
||||
obj = DBNull.Value
|
||||
Else
|
||||
Dim d As DateTime
|
||||
obj = If(DateTime.TryParse(v, d), d.Date, CType(v, Object))
|
||||
End If
|
||||
ElseIf targetType Is GetType(Integer) Then
|
||||
Dim n As Integer
|
||||
obj = If(Integer.TryParse(v, n), n, If(v = "", DBNull.Value, CType(v, Object)))
|
||||
ElseIf targetType Is GetType(Decimal) OrElse targetType Is GetType(Double) OrElse targetType Is GetType(Single) Then
|
||||
Dim decv As Decimal
|
||||
obj = If(Decimal.TryParse(v, Globalization.NumberStyles.Any, Globalization.CultureInfo.CurrentCulture, decv),
|
||||
Convert.ChangeType(decv, targetType),
|
||||
If(v = "", DBNull.Value, CType(v, Object)))
|
||||
Else
|
||||
' generischer Versuch
|
||||
obj = If(v = "", DBNull.Value, Convert.ChangeType(v, targetType))
|
||||
End If
|
||||
Catch
|
||||
obj = If(v = "", DBNull.Value, v)
|
||||
End Try
|
||||
|
||||
' DataRow sichern (bei neu erzeugten Zeilen existiert sie sicher)
|
||||
Dim drv As DataRowView = TryCast(Me.Rows(rowIndex).DataBoundItem, DataRowView)
|
||||
If drv IsNot Nothing Then
|
||||
drv(prop) = obj
|
||||
Else
|
||||
' Falls kein DataRowView (unwahrscheinlich): direkt über Index
|
||||
dt.Rows(rowIndex)(prop) = obj
|
||||
End If
|
||||
|
||||
Return
|
||||
End If
|
||||
|
||||
FallbackCell:
|
||||
' Fall B: Ungebunden -> direkt in die Zelle schreiben
|
||||
Dim cell = Me.Rows(rowIndex).Cells(colIndex)
|
||||
If cell Is Nothing OrElse cell.ReadOnly Then Exit Sub
|
||||
|
||||
Try
|
||||
If cell.ValueType Is GetType(Date) OrElse cell.ValueType Is GetType(DateTime) Then
|
||||
If v = "" Then
|
||||
cell.Value = Nothing
|
||||
Else
|
||||
Dim d As DateTime
|
||||
cell.Value = If(DateTime.TryParse(v, d), d.Date, CType(v, Object))
|
||||
End If
|
||||
ElseIf cell.ValueType Is GetType(Integer) Then
|
||||
Dim n As Integer
|
||||
cell.Value = If(Integer.TryParse(v, n), n, If(v = "", Nothing, v))
|
||||
ElseIf cell.ValueType Is GetType(Decimal) OrElse cell.ValueType Is GetType(Double) Then
|
||||
Dim decv As Decimal
|
||||
cell.Value = If(Decimal.TryParse(v, Globalization.NumberStyles.Any, Globalization.CultureInfo.CurrentCulture, decv), decv, If(v = "", Nothing, v))
|
||||
Else
|
||||
cell.Value = If(v = "", Nothing, v)
|
||||
End If
|
||||
Catch
|
||||
cell.Value = If(v = "", Nothing, v)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
Private Sub EnsureRowExists(targetRow As Integer)
|
||||
If targetRow < Me.Rows.Count Then Exit Sub
|
||||
|
||||
If TypeOf Me.DataSource Is DataTable Then
|
||||
Dim dt = DirectCast(Me.DataSource, DataTable)
|
||||
Do While targetRow >= (If(Me.AllowUserToAddRows, Me.Rows.Count - 1, Me.Rows.Count))
|
||||
dt.Rows.Add(dt.NewRow())
|
||||
Loop
|
||||
Else
|
||||
Do While targetRow >= (If(Me.AllowUserToAddRows, Me.Rows.Count - 1, Me.Rows.Count))
|
||||
Me.Rows.Add()
|
||||
Loop
|
||||
End If
|
||||
End Sub
|
||||
' ========================================================
|
||||
' ========================================================
|
||||
End Class
|
||||
|
||||
@@ -200,4 +200,29 @@ Public Class cZollArtikel
|
||||
|
||||
Return result
|
||||
End Function
|
||||
Public Shared Function FindZollArtikelByNummer(artikelListe As List(Of cZollArtikel), artikelnummer As String) As cZollArtikel
|
||||
If artikelListe Is Nothing OrElse artikelnummer Is Nothing Then Return Nothing
|
||||
|
||||
Dim suchNr As String = artikelnummer.Trim().ToUpperInvariant()
|
||||
|
||||
' Finde alle Artikel mit gleicher Artikelnummer
|
||||
Dim treffer = artikelListe.
|
||||
Where(Function(a) a IsNot Nothing AndAlso
|
||||
a.zollArt_Artikelnummer IsNot Nothing AndAlso
|
||||
a.zollArt_Artikelnummer.ToString().Trim().ToUpperInvariant() = suchNr).
|
||||
ToList()
|
||||
|
||||
If treffer.Count = 0 Then Return Nothing
|
||||
If treffer.Count = 1 Then Return treffer(0)
|
||||
|
||||
' Wenn mehrere gefunden: wähle den mit längster Warencodenummer (zollArt_Warencodenummer)
|
||||
Dim bester = treffer.OrderByDescending(Function(a)
|
||||
Dim code = If(a.zollArt_Warencodenummer, "").ToString().Trim()
|
||||
Return code.Length
|
||||
End Function).
|
||||
FirstOrDefault()
|
||||
|
||||
Return bester
|
||||
End Function
|
||||
|
||||
End Class
|
||||
|
||||
@@ -23,8 +23,8 @@ Public Class cATEZ_Greenpulse_KafkaDecs
|
||||
'== Kafka: Konfiguration (Klassenebene)
|
||||
'========================
|
||||
Public Shared BootstrapServers As String = "192.168.85.250:9092" 'http://192.168.85.250:8888
|
||||
Public Shared TopicName As String = "greenpulse.declarationdata.v1"
|
||||
' Public Shared TopicName As String = "dev.greenpulse.declarationdata.v1"
|
||||
' Public Shared TopicName As String = "greenpulse.declarationdata.v1"
|
||||
Public Shared TopicName As String = "dev.greenpulse.declarationdata.v1"
|
||||
' Falls SASL/TLS benötigt:
|
||||
Public Shared UseSasl As Boolean = False
|
||||
Public Shared SaslUsername As String = ""
|
||||
@@ -66,6 +66,11 @@ Public Class cATEZ_Greenpulse_KafkaDecs
|
||||
<JsonProperty("importerDetails")>
|
||||
Public Property ImporterDetails As ImporterDetailsNode
|
||||
|
||||
'--- documents ---
|
||||
<JsonProperty("documents")>
|
||||
Public Property Documents As List(Of DocumentNode)
|
||||
|
||||
|
||||
'--- declaration ---
|
||||
Public Class DeclarationNode
|
||||
<JsonProperty("declarationsourceId")>
|
||||
@@ -201,6 +206,19 @@ Public Class cATEZ_Greenpulse_KafkaDecs
|
||||
<JsonProperty("importerCoordinateLatitudeY")>
|
||||
Public Property ImporterCoordinateLatitudeY As String
|
||||
End Class
|
||||
Public Class DocumentNode
|
||||
<JsonProperty("reference")>
|
||||
Public Property Reference As String
|
||||
|
||||
<JsonProperty("doc-type")>
|
||||
Public Property DocType As String
|
||||
|
||||
<JsonProperty("mime-type")>
|
||||
Public Property MimeType As String
|
||||
|
||||
<JsonProperty("blob")>
|
||||
Public Property Blob As String
|
||||
End Class
|
||||
|
||||
'========================
|
||||
'== Serialisierung
|
||||
@@ -267,7 +285,8 @@ Public Class cATEZ_Greenpulse_KafkaDecs
|
||||
.ImporterPoBox = "PO DCL-123",
|
||||
.ImporterCoordinateLongitudeX = "41.0091982",
|
||||
.ImporterCoordinateLatitudeY = "28.9662187"
|
||||
}
|
||||
},
|
||||
.Documents = New List(Of cATEZ_Greenpulse_KafkaDecs.DocumentNode)()
|
||||
}
|
||||
End Function
|
||||
|
||||
@@ -298,6 +317,8 @@ Public Class cATEZ_Greenpulse_KafkaDecs
|
||||
.MaxInFlight = 5,
|
||||
.MessageTimeoutMs = Math.Max(waitMs, 60000),
|
||||
.RequestTimeoutMs = 30000,
|
||||
.CompressionType = Confluent.Kafka.CompressionType.Zstd, ' gute Kompression
|
||||
.MessageMaxBytes = 20971520, ' ≈ 20 MB – darf Topic/Broker nicht übersteigen
|
||||
.EnableDeliveryReports = True,
|
||||
.AllowAutoCreateTopics = True
|
||||
}
|
||||
@@ -379,7 +400,7 @@ Public Class cATEZ_Greenpulse_KafkaDecsBuilder_DAKOSY
|
||||
|
||||
Dim obj As New cATEZ_Greenpulse_KafkaDecs() With {
|
||||
.Declaration = New cATEZ_Greenpulse_KafkaDecs.DeclarationNode() With {
|
||||
.DeclarationSourceId = SafeStr(head("Bezugsnummer_LRN")),
|
||||
.DeclarationSourceId = SafeStr(head("Registriernummer_MRN")),
|
||||
.DeclarationNo = SafeStr(head("Registriernummer_MRN")),
|
||||
.DeclarationDate = FirstNonEmptyDateStr(head, {"Annahmedatum", "Überlassungsdatum"}),
|
||||
.RequestedProcedure = SafeStr(head("Verfahren")),
|
||||
@@ -412,7 +433,8 @@ Public Class cATEZ_Greenpulse_KafkaDecsBuilder_DAKOSY
|
||||
.ImporterPoBox = "",
|
||||
.ImporterCoordinateLongitudeX = "",
|
||||
.ImporterCoordinateLatitudeY = ""
|
||||
}
|
||||
},
|
||||
.Documents = New List(Of cATEZ_Greenpulse_KafkaDecs.DocumentNode)()
|
||||
}
|
||||
|
||||
' 2) Commercial (Rechnung) – aus Unterlagen N380, falls vorhanden
|
||||
@@ -424,6 +446,38 @@ Public Class cATEZ_Greenpulse_KafkaDecsBuilder_DAKOSY
|
||||
.DefaultIfEmpty(Nothing) _
|
||||
.FirstOrDefault()
|
||||
|
||||
' --- Dokumente aus Unterlagen übernehmen ---
|
||||
Dim SQLS As New VERAG_PROG_ALLGEMEIN.SQL
|
||||
Dim SenungsId = SQLS.getValueTxtBySql("SELECT dy_SendungsId from [tblDakosy_Zollanmeldungen] where dy_BezugsNr=''", "FMZOLL",,, Nothing)
|
||||
|
||||
|
||||
If SenungsId IsNot Nothing Then
|
||||
If IsNumeric(SenungsId) AndAlso SenungsId > 0 Then
|
||||
Dim ANH_LIST As New List(Of cAvisoAnhaenge)
|
||||
cAvisoAnhaenge.LOAD_LIST_BySendung(ANH_LIST, SenungsId)
|
||||
|
||||
|
||||
For Each doc In ANH_LIST
|
||||
Select Case doc.anh_Art
|
||||
Case "Rechnung", "eFatura"
|
||||
|
||||
Dim dateiBytes As Byte() = System.IO.File.ReadAllBytes(VERAG_PROG_ALLGEMEIN.cDATENSERVER.GET_PDFPath_BY_DocID(doc.anh_docId))
|
||||
|
||||
Dim d As New cATEZ_Greenpulse_KafkaDecs.DocumentNode With {
|
||||
.Reference = doc.anh_Name,
|
||||
.DocType = "invoice",
|
||||
.MimeType = cATEZ_Greenpulse_KafkaDecsBuilder_DAKOSY.GuessMimeTypeFromNumber(doc.anh_Typ),
|
||||
.Blob = Convert.ToBase64String(dateiBytes)
|
||||
}
|
||||
obj.Documents.Add(d)
|
||||
End Select
|
||||
|
||||
Next
|
||||
End If
|
||||
|
||||
End If
|
||||
|
||||
|
||||
If invRow IsNot Nothing Then
|
||||
obj.Commercial.InvoiceNumbers = SafeStr(invRow("Unterlagennummer"))
|
||||
obj.Commercial.InvoiceDate = SafeDateStr(invRow("Unterlagendatum"))
|
||||
@@ -519,4 +573,15 @@ Public Class cATEZ_Greenpulse_KafkaDecsBuilder_DAKOSY
|
||||
Return String.IsNullOrWhiteSpace(Convert.ToString(value))
|
||||
End Function
|
||||
|
||||
|
||||
Public Shared Function GuessMimeTypeFromNumber(num As Object) As String
|
||||
' Wenn du Dateiendungen erkennst (z. B. .pdf oder .jpg im Namen)
|
||||
Dim s As String = SafeStr(num).ToLowerInvariant()
|
||||
If s.EndsWith(".pdf") Or s.ToLower = "PDF" Then Return "application/pdf"
|
||||
If s.EndsWith(".jpg") Or s.EndsWith(".jpeg") Or s.ToLower = "JPG" Or s.ToLower = "JPEG" Then Return "image/jpeg"
|
||||
If s.EndsWith(".png") Or s.ToLower = "PNG" Then Return "image/png"
|
||||
Return "application/octet-stream"
|
||||
End Function
|
||||
|
||||
|
||||
End Class
|
||||
|
||||
@@ -62,7 +62,7 @@ Public Class cRelayHub
|
||||
Public Class cRelayHubAddress
|
||||
Public Property addressType As String
|
||||
Public Property participantEORI As String
|
||||
Public Property participantSubsidiaryNumber As String
|
||||
Public Property participantSubsidiaryNumber As Integer
|
||||
Public Property companyName As String
|
||||
Public Property streetAndNumber As String
|
||||
Public Property countryCode As String
|
||||
@@ -131,7 +131,21 @@ Public Class cRelayHub
|
||||
Try
|
||||
VERAG_PROG_ALLGEMEIN.cChilkat_Helper.UnlockCilkat()
|
||||
|
||||
Dim jsonPayload As String = JsonConvert.SerializeObject(request)
|
||||
|
||||
Dim sanitized = Sanitize(request)
|
||||
Dim settings As New JsonSerializerSettings With {
|
||||
.NullValueHandling = NullValueHandling.Ignore,
|
||||
.ContractResolver = New Newtonsoft.Json.Serialization.DefaultContractResolver With {
|
||||
.NamingStrategy = New Newtonsoft.Json.Serialization.CamelCaseNamingStrategy()
|
||||
}
|
||||
}
|
||||
Dim jsonPayload As String = JsonConvert.SerializeObject(sanitized, settings)
|
||||
Console.WriteLine("JSON → " & jsonPayload)
|
||||
|
||||
|
||||
'Dim jsonPayload As String = JsonConvert.SerializeObject(request)
|
||||
|
||||
|
||||
|
||||
' 1. Versuch
|
||||
Dim response As Chilkat.HttpResponse = SendJobOrder(jsonPayload)
|
||||
@@ -208,6 +222,26 @@ Public Class cRelayHub
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Shared Function Sanitize(req As cRelayHub.cRelayHubJobOrderRequest) As cRelayHub.cRelayHubJobOrderRequest
|
||||
req.outputApplication = If(req.outputApplication, "").Trim()
|
||||
req.dispatchCountry = If(req.dispatchCountry, "").Trim().ToUpperInvariant()
|
||||
req.destinationCountry = If(req.destinationCountry, "").Trim().ToUpperInvariant()
|
||||
|
||||
' lokale Fail-fast Checks
|
||||
If req.dispatchCountry.Length <> 2 Then Throw New ApplicationException("dispatchCountry ISO-2 erforderlich.")
|
||||
If req.destinationCountry.Length <> 2 Then Throw New ApplicationException("destinationCountry ISO-2 erforderlich.")
|
||||
Dim allowed = New HashSet(Of String)(StringComparer.Ordinal) From {
|
||||
"test", "dakosy/sftp/vera", "evrim/excel", "sec/import/integration"
|
||||
}
|
||||
If Not allowed.Contains(req.outputApplication) Then
|
||||
Throw New ApplicationException("outputApplication muss 'test' | 'dakosy/sftp/vera' | 'evrim/excel' | 'sec/import/integration' sein.")
|
||||
End If
|
||||
If req.regimeType <> "IMPORT" AndAlso req.regimeType <> "EXPORT" Then
|
||||
Throw New ApplicationException("regimeType muss 'IMPORT' oder 'EXPORT' sein.")
|
||||
End If
|
||||
Return req
|
||||
End Function
|
||||
|
||||
' Beispielfall
|
||||
Function CreateSampleJobOrderRequest() As cRelayHubJobOrderRequest
|
||||
Dim req As New cRelayHubJobOrderRequest With {
|
||||
|
||||
Reference in New Issue
Block a user