Imports System.Data Imports System.Data.SqlClient Imports System.Globalization Imports ClosedXML.Excel Public Class cTRCustStat Private ReadOnly _connectionString As String Private ReadOnly _de As CultureInfo = CultureInfo.GetCultureInfo("de-DE") Public Sub New(connectionString As String) _connectionString = connectionString End Sub ' Mehrere Dateien importieren Public Sub ImportFiles(filePaths As IEnumerable(Of String)) For Each p In filePaths ImportSingleFile(p) Next End Sub Private Sub ImportSingleFile(filePath As String) Using wb As New XLWorkbook(filePath) Dim ws = wb.Worksheets.First() ' Header (Zeile 1) normalisieren Dim lastCol = ws.Row(1).LastCellUsed().Address.ColumnNumber Dim headers As New List(Of String) For c = 1 To lastCol headers.Add(NormalizeHeader(ws.Cell(1, c).GetString())) Next Dim layout = DetectLayout(headers) Select Case layout Case LayoutType.Exports Dim dt = CreateExportsDataTable() ' Spaltennamen = SQL-Spalten EN FillDataTable(ws, headers, dt, isExport:=True, sourceFile:=filePath) BulkInsert(dt, "dbo.Customs_Exports") Case LayoutType.Imports Dim dt = CreateImportsDataTable() FillDataTable(ws, headers, dt, isExport:=False, sourceFile:=filePath) BulkInsert(dt, "dbo.Customs_Imports") Case Else Throw New InvalidOperationException($"Unknown layout in file: {filePath}") End Select End Using End Sub Private Enum LayoutType Unknown = 0 Exports = 1 [Imports] = 2 End Enum Private Function DetectLayout(headers As List(Of String)) As LayoutType ' Export: hat "tcgb statü açıklaması" ODER "gümrük istatistik tarihi" If headers.Any(Function(h) h.Contains("tcgb statu aciklamasi") OrElse h.Contains("gumruk istatistik tarihi")) Then Return LayoutType.Exports End If ' Import: hat "gümrük idaresi kodu" und "tcgb kapanış tarihi" If headers.Any(Function(h) h.Contains("gumruk idaresi kodu")) AndAlso headers.Any(Function(h) h.Contains("tcgb kapanis tarihi")) Then Return LayoutType.Imports End If Return LayoutType.Unknown End Function Private Function NormalizeHeader(raw As String) As String If raw Is Nothing Then Return "" Dim s = raw.Trim().ToLowerInvariant() s = s.Replace("ı", "i").Replace("ş", "s").Replace("ğ", "g").Replace("ü", "u").Replace("ö", "o").Replace("ç", "c") s = System.Text.RegularExpressions.Regex.Replace(s, "\s+", " ") Return s End Function ' --- DataTables: Spaltennamen = EN-Tabellenschema --- Private Function CreateExportsDataTable() As DataTable Dim dt As New DataTable("Customs_Exports") dt.Columns.Add("CustomsOfficeName", GetType(String)) dt.Columns.Add("RegistrationNo", GetType(String)) dt.Columns.Add("RegistrationDate", GetType(Date)) dt.Columns.Add("StatisticsDate", GetType(Date)) dt.Columns.Add("ConsignorConsigneeTaxNo", GetType(String)) dt.Columns.Add("ConsignorConsigneeName", GetType(String)) dt.Columns.Add("ConsigneeName", GetType(String)) dt.Columns.Add("DestinationCountryCode", GetType(String)) dt.Columns.Add("DestinationCountryName", GetType(String)) dt.Columns.Add("OriginCountryCode", GetType(String)) dt.Columns.Add("OriginCountryName", GetType(String)) dt.Columns.Add("IncotermCode", GetType(String)) dt.Columns.Add("LineNo", GetType(Integer)) dt.Columns.Add("RegimeCode", GetType(String)) dt.Columns.Add("RegimeDescription", GetType(String)) dt.Columns.Add("HSCode", GetType(String)) dt.Columns.Add("HSDescription", GetType(String)) dt.Columns.Add("CommercialDescription", GetType(String)) dt.Columns.Add("DeclarationStatus", GetType(String)) dt.Columns.Add("InvoiceAmount", GetType(Decimal)) dt.Columns.Add("InvoiceCurrencyCode", GetType(String)) dt.Columns.Add("Quantity", GetType(Decimal)) dt.Columns.Add("QuantityUnit", GetType(String)) dt.Columns.Add("NetWeightKg", GetType(Decimal)) dt.Columns.Add("CalculatedLineValueUSD", GetType(Decimal)) dt.Columns.Add("StatisticalValueUSD", GetType(Decimal)) dt.Columns.Add("SourceFile", GetType(String)) dt.Columns.Add("ImportedAtUtc", GetType(DateTime)) Return dt End Function Private Function CreateImportsDataTable() As DataTable Dim dt As New DataTable("Customs_Imports") dt.Columns.Add("CustomsOfficeCode", GetType(String)) dt.Columns.Add("CustomsOfficeName", GetType(String)) dt.Columns.Add("RegistrationNo", GetType(String)) dt.Columns.Add("RegistrationDate", GetType(Date)) dt.Columns.Add("ClosingDate", GetType(Date)) dt.Columns.Add("ConsignorConsigneeTaxNo", GetType(String)) dt.Columns.Add("ConsignorConsigneeName", GetType(String)) dt.Columns.Add("SenderName", GetType(String)) dt.Columns.Add("DispatchCountryCode", GetType(String)) dt.Columns.Add("DispatchCountryName", GetType(String)) dt.Columns.Add("OriginCountryCode", GetType(String)) dt.Columns.Add("OriginCountryName", GetType(String)) dt.Columns.Add("IncotermCode", GetType(String)) dt.Columns.Add("LineNo", GetType(Integer)) dt.Columns.Add("RegimeCode", GetType(String)) dt.Columns.Add("RegimeDescription", GetType(String)) dt.Columns.Add("HSCode", GetType(String)) dt.Columns.Add("HSDescription", GetType(String)) dt.Columns.Add("CommercialDescription", GetType(String)) dt.Columns.Add("InvoiceAmount", GetType(Decimal)) dt.Columns.Add("InvoiceCurrencyCode", GetType(String)) dt.Columns.Add("Quantity", GetType(Decimal)) dt.Columns.Add("QuantityUnit", GetType(String)) dt.Columns.Add("NetWeightKg", GetType(Decimal)) dt.Columns.Add("CalculatedLineValueUSD", GetType(Decimal)) dt.Columns.Add("StatisticalValueUSD", GetType(Decimal)) dt.Columns.Add("SourceFile", GetType(String)) dt.Columns.Add("ImportedAtUtc", GetType(DateTime)) Return dt End Function ' --- Excel -> DataTable --- Private Sub FillDataTable(ws As IXLWorksheet, headers As List(Of String), dt As DataTable, isExport As Boolean, sourceFile As String) Dim rowFirst = 2 Dim rowLast = ws.LastRowUsed().RowNumber() Dim colLast = ws.Row(1).LastCellUsed().Address.ColumnNumber Dim map As Dictionary(Of String, String) = If(isExport, GetExportHeaderMap(), GetImportHeaderMap()) For r = rowFirst To rowLast Dim dr = dt.NewRow() dr("SourceFile") = sourceFile dr("ImportedAtUtc") = DateTime.UtcNow For c = 1 To colLast Dim rawHeader = NormalizeHeader(ws.Cell(1, c).GetString()) If Not map.ContainsKey(rawHeader) Then Continue For Dim targetCol = map(rawHeader) Dim txt = ws.Cell(r, c).GetFormattedString().Trim() If String.IsNullOrWhiteSpace(txt) Then ' skip ElseIf dt.Columns(targetCol).DataType Is GetType(Date) Then dr(targetCol) = ParseDate(txt) ElseIf dt.Columns(targetCol).DataType Is GetType(Decimal) Then dr(targetCol) = ParseDecimal(txt) ElseIf dt.Columns(targetCol).DataType Is GetType(Integer) Then Dim i As Integer If Integer.TryParse(txt, NumberStyles.Any, _de, i) OrElse Integer.TryParse(txt, NumberStyles.Any, CultureInfo.InvariantCulture, i) Then dr(targetCol) = i End If Else dr(targetCol) = txt End If Next ' Mindestprüfung: RegistrationNo muss da sein If dt.Columns.Contains("RegistrationNo") AndAlso Not IsDBNull(dr("RegistrationNo")) AndAlso Not String.IsNullOrWhiteSpace(CStr(dr("RegistrationNo"))) Then dt.Rows.Add(dr) End If Next End Sub Private Function ParseDecimal(s As String) As Decimal Dim d As Decimal If Decimal.TryParse(s, NumberStyles.Any, _de, d) Then Return d ' 3.499,09 If Decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, d) Then Return d ' 3499.09 Return 0D End Function Private Function ParseDate(s As String) As Date Dim d As Date Dim formats = { "dd.MMM.yyyy", "d.MMM.yyyy", "dd.MM.yyyy", "d.MM.yyyy", "dd.MMM.yy", "dd.MM.yy", "yyyy-MM-dd", "dd-MMM-yyyy" } If Date.TryParseExact(s, formats, _de, DateTimeStyles.None, d) Then Return d If Date.TryParse(s, _de, DateTimeStyles.None, d) Then Return d If Date.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, d) Then Return d Return Date.MinValue End Function Private Sub BulkInsert(dt As DataTable, targetTable As String) Using cn As New SqlConnection(_connectionString) cn.Open() Using bulk As New SqlBulkCopy(cn) bulk.DestinationTableName = targetTable bulk.BulkCopyTimeout = 0 bulk.BatchSize = 10000 For Each col As DataColumn In dt.Columns bulk.ColumnMappings.Add(col.ColumnName, col.ColumnName) Next bulk.WriteToServer(dt) End Using End Using End Sub ' --- Header-Mappings: Türkischer Exceltitel -> EN-Spalte --- Private Function GetExportHeaderMap() As Dictionary(Of String, String) Return New Dictionary(Of String, String) From { {"tcgb", "CustomsOfficeName"}, {"gümrük idaresi adı", "CustomsOfficeName"}, ' manche Dateien haben beide {"tcgb tescil no", "RegistrationNo"}, {"tcgb tescil tarihi", "RegistrationDate"}, {"gümrük istatistik tarihi (bordro tarihi)", "StatisticsDate"}, {"gonderici / alici vergi no", "ConsignorConsigneeTaxNo"}, {"gonderici/alici adi", "ConsignorConsigneeName"}, {"alici adi", "ConsigneeName"}, {"gidecegi ulke (17) kodu", "DestinationCountryCode"}, {"gidecegi ulke (17) adi", "DestinationCountryName"}, {"mense ulke kodu", "OriginCountryCode"}, {"mense ulke adi", "OriginCountryName"}, {"teslim sekli kodu", "IncotermCode"}, {"kalem sira no", "LineNo"}, {"kalem rejim kodu", "RegimeCode"}, {"kalem rejim aciklamasi", "RegimeDescription"}, {"gtip kodu", "HSCode"}, {"gtip aciklamasi", "HSDescription"}, {"31. ticari tanimi", "CommercialDescription"}, {"tcgb statu aciklamasi", "DeclarationStatus"}, {"fatura tutari", "InvoiceAmount"}, {"fatura tutari doviz turu kodu", "InvoiceCurrencyCode"}, {"olcu (esya) miktari", "Quantity"}, {"olcu birimi aciklamasi", "QuantityUnit"}, {"net agirlik (kg)", "NetWeightKg"}, {"hesaplanmis kalem kiymeti usd degeri", "CalculatedLineValueUSD"}, {"istatistiki kiymet usd degeri", "StatisticalValueUSD"} } End Function Private Function GetImportHeaderMap() As Dictionary(Of String, String) Return New Dictionary(Of String, String) From { {"gümrük idaresi kodu", "CustomsOfficeCode"}, {"gumruk idaresi kodu", "CustomsOfficeCode"}, {"gümrük idaresi adı", "CustomsOfficeName"}, {"gumruk idaresi adi", "CustomsOfficeName"}, {"tcgb tescil no", "RegistrationNo"}, {"tcgb tescil tarihi", "RegistrationDate"}, {"tcgb kapanis tarihi", "ClosingDate"}, {"gonderici / alici vergi no", "ConsignorConsigneeTaxNo"}, {"gonderici/alici adi", "ConsignorConsigneeName"}, {"gonderen adi", "SenderName"}, {"cikis ulkesi kodu", "DispatchCountryCode"}, {"cikis ulkesi adi", "DispatchCountryName"}, {"mense ulke kodu", "OriginCountryCode"}, {"mense ulke adi", "OriginCountryName"}, {"teslim sekli kodu", "IncotermCode"}, {"kalem sira no", "LineNo"}, {"kalem rejim kodu", "RegimeCode"}, {"kalem rejim aciklamasi", "RegimeDescription"}, {"gtip kodu", "HSCode"}, {"gtip aciklamasi", "HSDescription"}, {"31. ticari tanimi", "CommercialDescription"}, {"fatura tutari", "InvoiceAmount"}, {"fatura doviz kodu", "InvoiceCurrencyCode"}, {"olcu (esya) miktari", "Quantity"}, {"olcu birimi aciklamasi", "QuantityUnit"}, {"net agirlik (kg)", "NetWeightKg"}, {"hesaplanmis kalem kiymeti usd degeri", "CalculatedLineValueUSD"}, {"istatistiki kiymet usd degeri", "StatisticalValueUSD"} } End Function End Class