diff --git a/SDL/My Project/Resources.Designer.vb b/SDL/My Project/Resources.Designer.vb
index 47ca005d..9e3c7974 100644
--- a/SDL/My Project/Resources.Designer.vb
+++ b/SDL/My Project/Resources.Designer.vb
@@ -2631,6 +2631,16 @@ Namespace My.Resources
End Get
End Property
+ '''
+ ''' Sucht eine lokalisierte Ressource vom Typ System.Byte[].
+ '''
+ Friend ReadOnly Property VERAG_CBAM_Report_Template() As Byte()
+ Get
+ Dim obj As Object = ResourceManager.GetObject("VERAG_CBAM_Report_Template", resourceCulture)
+ Return CType(obj,Byte())
+ End Get
+ End Property
+
'''
''' Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
'''
diff --git a/SDL/My Project/Resources.resx b/SDL/My Project/Resources.resx
index 69d73ef2..4593efdf 100644
--- a/SDL/My Project/Resources.resx
+++ b/SDL/My Project/Resources.resx
@@ -973,4 +973,7 @@
..\Resources\ambar_boarder_new.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\VERAG_CBAM_Report_Template.xlsx;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
\ No newline at end of file
diff --git a/SDL/Resources/VERAG_CBAM_Report_Template.xlsx b/SDL/Resources/VERAG_CBAM_Report_Template.xlsx
new file mode 100644
index 00000000..dd6f3fa1
Binary files /dev/null and b/SDL/Resources/VERAG_CBAM_Report_Template.xlsx differ
diff --git a/SDL/SDL.vbproj b/SDL/SDL.vbproj
index aacb56cb..6caa65ef 100644
--- a/SDL/SDL.vbproj
+++ b/SDL/SDL.vbproj
@@ -4987,6 +4987,7 @@
+
Always
diff --git a/SDL/kunden/usrCntlCBAM.vb b/SDL/kunden/usrCntlCBAM.vb
index 7c1524fe..38d64056 100644
--- a/SDL/kunden/usrCntlCBAM.vb
+++ b/SDL/kunden/usrCntlCBAM.vb
@@ -2249,7 +2249,8 @@ Public Class usrCntlCBAM
doVERAG_SUM(LIST, EORI(0))
- doVERAG_DETAIL(LIST, EORI(0))
+ doVERAG_DETAIL_OLD(LIST, EORI(0))
+ 'doVERAG_DETAIL(LIST, EORI(0))
If cbxVERAG_GPXLS.Checked Then doVERAG_GREENPULSE_XLS(LIST, EORI(0))
@@ -2410,7 +2411,342 @@ Public Class usrCntlCBAM
End Try
End Sub
- Sub doVERAG_DETAIL(LIST As List(Of VERAG_PROG_ALLGEMEIN.cVERAG_CustomsDeclarations), EORI As String)
+ Public Sub doVERAG_DETAIL(LIST As List(Of VERAG_PROG_ALLGEMEIN.cVERAG_CustomsDeclarations), EORI As String)
+
+ btnCBAM_DS_VERAG_Detail.Enabled = False
+ btnCBAM_DS_VERAG_Detail.Tag = ""
+
+ Try
+
+ ' =========================================================
+ ' Daten holen
+ ' =========================================================
+ Dim details =
+ From za In LIST
+ From it In za.Items
+ Let importer = za.Parties.
+ FirstOrDefault(Function(p) cVERAG_CustomsDeclarations.IMPORTER_ROLES.Contains(p.zaParty_Role))
+ Let exporter = za.Parties.
+ FirstOrDefault(Function(p) cVERAG_CustomsDeclarations.EXPORTER_ROLES.Contains(p.zaParty_Role))
+ Let declarant = za.Parties.
+ FirstOrDefault(Function(p) cVERAG_CustomsDeclarations.DECLARANT_ROLES.Contains(p.zaParty_Role))
+ Let cbamDeclarantTmp = za.Parties.
+ FirstOrDefault(Function(p) p.zaParty_Role = "CBAM")
+ Let cbamDeclarant = If(cbamDeclarantTmp, declarant)
+ Let invoice =
+ it.Documents.FirstOrDefault(Function(d) d.zaDoc_Code = "N380" OrElse d.zaDoc_Code = "N325")
+ Let anmeldedatum = If(za.za_ReleaseDate, za.za_DeclarationDate)
+ Order By anmeldedatum
+ Select New With {
+ .MRN = If(za.za_MRN, ""),
+ .SendungsId = za.za_SendungsId,
+ .PositionsNummer = it.zaItem_PosNo,
+ .Anmeldedatum = anmeldedatum,
+ .BezugsNr = If(za.za_LRN, ""),
+ .VertretungsVerhaeltnis = If(za.za_RepresentationCode, ""),
+ .Tarifnummer = If(LeftStr(it.zaItem_HSCode, 8), ""),
+ .Eigenmasse = it.zaItem_NetMass,
+ .Rohmasse = it.zaItem_GrossMass,
+ .Ursprungsland = If(it.zaItem_OriginCountry, ""),
+ .VersendungsLand = If(za.za_CountryDispatch, ""),
+ .BestimmungsLand = If(za.za_CountryDestination, ""),
+ .Rechnungspreis = If(it.zaItem_InvoiceValueEUR, it.zaItem_StatisticalValueEUR),
+ .Rechnungswaehrung = If(it.zaItem_InvoiceCurrency, ""),
+ .EmpfaengerEORI = If(importer IsNot Nothing, If(importer.zaParty_EORI, ""), ""),
+ .Empfaenger = If(importer IsNot Nothing, If(importer.zaParty_Name, ""), ""),
+ .AbsenderEORI = If(exporter IsNot Nothing, If(exporter.zaParty_EORI, ""), ""),
+ .Absender = If(exporter IsNot Nothing, If(exporter.zaParty_Name, ""), ""),
+ .DeclarantEORI = If(declarant IsNot Nothing, If(declarant.zaParty_EORI, ""), ""),
+ .DeclarantName = If(declarant IsNot Nothing, If(declarant.zaParty_Name, ""), ""),
+ .CBAMDeclarantEORI = If(cbamDeclarant IsNot Nothing, If(cbamDeclarant.zaParty_EORI, ""), ""),
+ .CBAMDeclarantName = If(cbamDeclarant IsNot Nothing, If(cbamDeclarant.zaParty_Name, ""), ""),
+ .Rechnungsnummer = If(invoice IsNot Nothing, If(invoice.zaDoc_Reference, ""), ""),
+ .Rechnungsdatum = If(invoice IsNot Nothing, ParseDateSafe(invoice.zaDoc_Date), Nothing),
+ .RequestedProcedure = If(za.za_MainProcedure, ""),
+ .PreviousProcedure = If(it.zaItem_PrevProcedure, ""),
+ .MeasurementUnit = If(it.zaItem_SuppUnitCode, "")
+ }
+
+ ' =========================================================
+ ' DataTable exakt nach Excel-Template
+ ' =========================================================
+ Dim dt As New DataTable
+
+ dt.Columns.Add("MRN")
+ dt.Columns.Add("position_no")
+ dt.Columns.Add("declaration_date")
+ dt.Columns.Add("reference_no")
+ dt.Columns.Add("customer_reference")
+ dt.Columns.Add("representation_type")
+ dt.Columns.Add("tariff_code")
+ dt.Columns.Add("net_mass_kg")
+ dt.Columns.Add("gross_mass_kg")
+ dt.Columns.Add("origin_country")
+ dt.Columns.Add("dispatch_country")
+ dt.Columns.Add("destination_country")
+ dt.Columns.Add("invoice_number")
+ dt.Columns.Add("invoice_date")
+ dt.Columns.Add("invoice_amount")
+ dt.Columns.Add("invoice_currency")
+ dt.Columns.Add("sender_eori")
+ dt.Columns.Add("sender_name")
+ dt.Columns.Add("sender_address")
+ dt.Columns.Add("sender_country")
+ dt.Columns.Add("recipient_eori")
+ dt.Columns.Add("recipient_name")
+ dt.Columns.Add("recipient_address")
+ dt.Columns.Add("recipient_country")
+ dt.Columns.Add("importer_eori")
+ dt.Columns.Add("importer_name")
+ dt.Columns.Add("importer_address")
+ dt.Columns.Add("importer_country")
+ dt.Columns.Add("importer_email")
+ dt.Columns.Add("importer_phone")
+ dt.Columns.Add("declarant_eori")
+ dt.Columns.Add("declarant_name")
+ dt.Columns.Add("declarant_address")
+ dt.Columns.Add("declarant_country")
+ dt.Columns.Add("requested_procedure")
+ dt.Columns.Add("previous_procedure")
+ dt.Columns.Add("measurement_unit")
+ dt.Columns.Add("member_state_authorisation")
+ dt.Columns.Add("discharge_bill_waiver")
+ dt.Columns.Add("authorisation")
+ dt.Columns.Add("inward_processing_start")
+ dt.Columns.Add("inward_processing_end")
+ dt.Columns.Add("inward_processing_deadline")
+ dt.Columns.Add("Benchmark (Default)")
+ dt.Columns.Add("Emission (Default)")
+ dt.Columns.Add("Factor")
+ dt.Columns.Add("Estimated Cost")
+
+ ' =========================================================
+ ' Befüllen
+ ' =========================================================
+ For Each r In details
+
+ Dim KdAtrNr As String = ""
+
+ If cbxKdAtrNr.Checked AndAlso r.SendungsId IsNot Nothing Then
+ Dim Snd = New VERAG_PROG_ALLGEMEIN.cSendungen(r.SendungsId)
+ If Snd IsNot Nothing Then
+ KdAtrNr = Snd.getKdAtrNr("AUFTRAGGEBER")
+ If KdAtrNr = "" Then
+ KdAtrNr = Snd.getKdAtrNr("EMPFAENGER")
+ End If
+ End If
+
+ If EORI = "DE4991397" AndAlso KdAtrNr.Contains("/") Then
+ KdAtrNr = KdAtrNr.Split("/"c)(0)
+ End If
+ End If
+
+ Dim benchmark As Object = Nothing
+ Dim emission As Object = Nothing
+ Dim faktor As Object = Nothing
+ Dim weight = r.Eigenmasse
+ Dim year = If(txtBis._value <> "", CDate(txtBis._value).Year, Now.Year)
+ Dim cost As String = "0"
+
+ If cbxKosten.Checked Then
+ Dim benchmarkObj As Object = Nothing
+ Dim emissionObj As Object = Nothing
+ Dim faktorObj As Object = Nothing
+ Dim costObj As String = "0"
+
+ ' Dim weight = 0D
+ If IsNumeric(r.Eigenmasse) Then weight = CDbl(r.Eigenmasse)
+
+ 'Dim year = If(txtBis._value <> "", CDate(txtBis._value).Year, Now.Year)
+
+ If IsNumeric(txtVERA_ZertPreis._value) Then
+ cATEZ_Greenpulse_CBAM_CostCalculation.calcCBAM_ByCertificatePrice(
+ cn_code:=Convert.ToString(r.Tarifnummer),
+ weight:=weight / 1000,
+ country_code:=Convert.ToString(r.Ursprungsland),
+ certificate_price:=CDbl(txtVERA_ZertPreis._value),
+ year:=year,
+ costObj,
+ emissionObj,
+ benchmarkObj,
+ faktorObj
+ )
+ Else
+ cATEZ_Greenpulse_CBAM_CostCalculation.calcCBAM(
+ cn_code:=Convert.ToString(r.Tarifnummer),
+ weight:=weight / 1000,
+ country_code:=Convert.ToString(r.Ursprungsland),
+ Nothing,
+ year:=year,
+ Nothing,
+ costObj,
+ emissionObj,
+ benchmarkObj,
+ faktorObj
+ )
+ End If
+
+ benchmark = If(benchmarkObj Is Nothing, "", Convert.ToString(benchmarkObj))
+ emission = If(emissionObj Is Nothing, "", Convert.ToString(emissionObj))
+ faktor = If(faktorObj Is Nothing, "", Convert.ToString(faktorObj))
+
+ If IsNumeric(costObj) Then
+ If CDbl(costObj) >= 0 Then
+ cost = Convert.ToString(costObj)
+ Else
+ cost = ""
+ End If
+ Else
+ cost = ""
+ End If
+ End If
+
+ Dim row = dt.NewRow()
+
+ row("MRN") = If(r.MRN, "")
+ row("position_no") = r.PositionsNummer
+ row("declaration_date") = If(r.Anmeldedatum Is Nothing, "", CDate(r.Anmeldedatum).ToString("yyyy-MM-dd"))
+ row("reference_no") = If(r.BezugsNr, "")
+ row("customer_reference") = If(KdAtrNr, "")
+ row("representation_type") = If(r.VertretungsVerhaeltnis, "")
+ row("tariff_code") = If(r.Tarifnummer, "")
+ row("net_mass_kg") = If(r.Eigenmasse Is Nothing, "", Convert.ToString(r.Eigenmasse))
+ row("gross_mass_kg") = If(r.Rohmasse Is Nothing, "", Convert.ToString(r.Rohmasse))
+ row("origin_country") = If(r.Ursprungsland, "")
+ row("dispatch_country") = If(r.VersendungsLand, "")
+ row("destination_country") = If(r.BestimmungsLand, "")
+
+ row("invoice_number") = If(r.Rechnungsnummer, "")
+ row("invoice_date") = If(r.Rechnungsdatum Is Nothing, "", CDate(r.Rechnungsdatum).ToString("yyyy-MM-dd"))
+ row("invoice_amount") = If(r.Rechnungspreis Is Nothing, "", Convert.ToString(r.Rechnungspreis))
+ row("invoice_currency") = If(r.Rechnungswaehrung, "")
+
+ row("sender_eori") = If(r.AbsenderEORI, "")
+ row("sender_name") = If(r.Absender, "")
+ row("sender_address") = ""
+ row("sender_country") = ""
+
+ row("recipient_eori") = If(r.EmpfaengerEORI, "")
+ row("recipient_name") = If(r.Empfaenger, "")
+ row("recipient_address") = ""
+ row("recipient_country") = ""
+
+ row("importer_eori") = If(r.EmpfaengerEORI, "")
+ row("importer_name") = If(r.Empfaenger, "")
+ row("importer_address") = ""
+ row("importer_country") = ""
+ row("importer_email") = ""
+ row("importer_phone") = ""
+
+ row("declarant_eori") = If(r.DeclarantEORI, "")
+ row("declarant_name") = If(r.DeclarantName, "")
+ row("declarant_address") = ""
+ row("declarant_country") = ""
+
+ row("requested_procedure") = If(r.RequestedProcedure, "")
+ row("previous_procedure") = If(r.PreviousProcedure, "")
+ row("measurement_unit") = If(r.MeasurementUnit, "")
+ row("member_state_authorisation") = ""
+ row("discharge_bill_waiver") = ""
+ row("authorisation") = ""
+ row("inward_processing_start") = ""
+ row("inward_processing_end") = ""
+ row("inward_processing_deadline") = ""
+
+ row("Benchmark (Default)") = benchmark
+ row("Emission (Default)") = emission
+ row("Factor") = faktor
+ row("Estimated Cost") = cost
+
+ dt.Rows.Add(row)
+
+ Next
+
+ ' =========================================================
+ ' Datei vorbereiten
+ ' =========================================================
+ Dim Path_DETAIL As String = ""
+ Dim sPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Personal) & "\VERAG\CBAM_REPORT_DETAIL\"
+
+ If Not My.Computer.FileSystem.DirectoryExists(sPath) Then
+ My.Computer.FileSystem.CreateDirectory(sPath)
+ End If
+
+ Path_DETAIL = sPath & EORI & "_CBAM_Detail_" & txtVon._value & "-" & txtBis._value & ".xlsx"
+ While System.IO.File.Exists(Path_DETAIL)
+ Path_DETAIL = sPath & EORI & "_CBAM_Detail_" & txtVon._value & "-" & txtBis._value & "_" & Now.ToString("ddMMyyyyHHmmss") & ".xlsx"
+ End While
+
+ My.Computer.FileSystem.WriteAllBytes(Path_DETAIL, My.Resources.VERAG_CBAM_Report_Template, False)
+
+ ' =========================================================
+ ' Excel schreiben
+ ' =========================================================
+ Dim wb = New ClosedXML.Excel.XLWorkbook(Path_DETAIL)
+ Dim ws = wb.Worksheet("CBAM_Report")
+
+ ' Header
+ ws.Cell("A3").Value = txtVon._value
+ ws.Cell("C3").Value = txtBis._value
+
+ ' CBAM Declarant
+ ws.Cell("A6").Value = "VERAG"
+ ws.Cell("B6").Value = ""
+ ws.Cell("C6").Value = ""
+ ws.Cell("D6").Value = ""
+ ws.Cell("E6").Value = ""
+ ws.Cell("F6").Value = EORI
+
+ ' Declarant
+ ws.Cell("A8").Value = "VERAG"
+ ws.Cell("B8").Value = ""
+ ws.Cell("C8").Value = ""
+ ws.Cell("D8").Value = ""
+ ws.Cell("E8").Value = ""
+ ws.Cell("F8").Value = EORI
+
+ ' Importer (Default) - aus Parameter / erster Datensatz
+ Dim firstImporterName As String = ""
+ If dt.Rows.Count > 0 Then
+ firstImporterName = Convert.ToString(dt.Rows(0)("importer_name"))
+ End If
+
+ ws.Cell("A10").Value = firstImporterName
+ ws.Cell("B10").Value = ""
+ ws.Cell("C10").Value = ""
+ ws.Cell("D10").Value = ""
+ ws.Cell("E10").Value = ""
+ ws.Cell("F10").Value = EORI
+
+ ' Alte Detaildatenbereich-Inhalte leeren
+ Dim startRow As Integer = 14
+ 'For r As Integer = startRow To Math.max(ws.LastRowUsed().RowNumber(), startRow + 5000)
+ ' For c As Integer = 1 To 47
+ ' ws.Cell(r, c).Clear(XLCellClearOptions.Contents)
+ ' Next
+ 'Next
+
+ ' Detaildaten schreiben
+ For i As Integer = 0 To dt.Rows.Count - 1
+ For j As Integer = 0 To dt.Columns.Count - 1
+ ws.Cell(startRow + i, j + 1).Value = If(dt.Rows(i)(j), "")
+ Next
+ Next
+
+ wb.SaveAs(Path_DETAIL)
+
+ If dt.Rows.Count > 0 Then
+ btnCBAM_DS_VERAG_Detail.Tag = Path_DETAIL
+ btnCBAM_DS_VERAG_Detail.Enabled = True
+ btnCBAM_DS_VERAG_Copy.Enabled = True
+ End If
+
+ Catch ex As Exception
+ VERAG_PROG_ALLGEMEIN.cErrorHandler.ERR(ex.Message, ex.StackTrace, System.Reflection.MethodInfo.GetCurrentMethod.Name)
+ End Try
+
+ End Sub
+ Sub doVERAG_DETAIL_OLD(LIST As List(Of VERAG_PROG_ALLGEMEIN.cVERAG_CustomsDeclarations), EORI As String)
btnCBAM_DS_VERAG_Detail.Enabled = False
btnCBAM_DS_VERAG_Detail.Tag = ""
diff --git a/VERAG_PROG_ALLGEMEIN/VERAG_PROG_ALLGEMEIN.vbproj b/VERAG_PROG_ALLGEMEIN/VERAG_PROG_ALLGEMEIN.vbproj
index 7145d084..18e1309a 100644
--- a/VERAG_PROG_ALLGEMEIN/VERAG_PROG_ALLGEMEIN.vbproj
+++ b/VERAG_PROG_ALLGEMEIN/VERAG_PROG_ALLGEMEIN.vbproj
@@ -762,7 +762,8 @@
True
Reference.svcmap
-
+
+
True
True
diff --git a/VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_Zollanmeldung.vb b/VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_CustomsDeclarations.vb
similarity index 100%
rename from VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_Zollanmeldung.vb
rename to VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_CustomsDeclarations.vb
diff --git a/VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_CustomsDeclarations_Convert.vb b/VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_CustomsDeclarations_Convert.vb
new file mode 100644
index 00000000..dc33680f
--- /dev/null
+++ b/VERAG_PROG_ALLGEMEIN/VERAG_Zollanmeldung/cVERAG_CustomsDeclarations_Convert.vb
@@ -0,0 +1,615 @@
+Imports ClosedXML.Excel
+Imports System.Globalization
+Imports System.IO
+Imports System.Linq
+
+Public Class cVERAG_CustomsDeclarations_Convert
+
+ Public Const EXPECTED_TEMPLATE_VERSION As String = "CBAM-2026-V1.0"
+
+ Public Shared Function LOAD_FROM_CBAM_DETAIL_EXCEL(filePath As String,
+ Optional ByRef errors As List(Of String) = Nothing,
+ Optional stopOnFirstInvalidRow As Boolean = False) As List(Of cVERAG_CustomsDeclarations)
+
+ Dim result As New List(Of cVERAG_CustomsDeclarations)
+
+ Try
+ If errors Is Nothing Then errors = New List(Of String)
+
+ If String.IsNullOrWhiteSpace(filePath) Then
+ errors.Add("Es wurde kein Dateipfad übergeben.")
+ Return result
+ End If
+
+ If Not File.Exists(filePath) Then
+ errors.Add("Datei nicht gefunden: " & filePath)
+ Return result
+ End If
+
+ Using wb As New XLWorkbook(filePath)
+
+ Dim ws As IXLWorksheet = Nothing
+
+ If wb.Worksheets.Any(Function(x) x.Name.Trim().ToUpper() = "CBAM_REPORT") Then
+ ws = wb.Worksheet("CBAM_Report")
+ Else
+ ws = wb.Worksheet(1)
+ End If
+
+ If ws Is Nothing Then
+ errors.Add("Kein Worksheet gefunden.")
+ Return result
+ End If
+
+ ' =========================================================
+ ' Template-Version prüfen
+ ' =========================================================
+ Dim versionInFile As String = TrimSafe(ws.Cell("F3").GetString())
+
+ If Not String.Equals(versionInFile, EXPECTED_TEMPLATE_VERSION, StringComparison.OrdinalIgnoreCase) Then
+ errors.Add("Ungültige Template-Version in F3. Erwartet: '" & EXPECTED_TEMPLATE_VERSION & "', gefunden: '" & versionInFile & "'")
+ Return result
+ End If
+
+ Dim headerRow As Integer = 13
+ Dim dataStartRow As Integer = 14
+
+ Dim lastRow = If(ws.LastRowUsed() Is Nothing, 0, ws.LastRowUsed().RowNumber())
+ Dim lastCol = If(ws.LastColumnUsed() Is Nothing, 0, ws.LastColumnUsed().ColumnNumber())
+
+ If lastRow < dataStartRow OrElse lastCol = 0 Then
+ errors.Add("Keine Positionsdaten gefunden.")
+ Return result
+ End If
+
+ ' =========================================================
+ ' Header-Mapping aufbauen
+ ' =========================================================
+ Dim colMap As New Dictionary(Of String, Integer)(StringComparer.OrdinalIgnoreCase)
+
+ For c As Integer = 1 To lastCol
+ Dim h = TrimSafe(ws.Cell(headerRow, c).GetString())
+ If h <> "" AndAlso Not colMap.ContainsKey(h) Then
+ colMap.Add(h, c)
+ End If
+ Next
+
+ ' =========================================================
+ ' Pflichtspalten im Excel prüfen
+ ' =========================================================
+ Dim requiredHeaders = New String() {"MRN", "declaration_date", "tariff_code"}
+
+ For Each req In requiredHeaders
+ If Not colMap.ContainsKey(req) Then
+ errors.Add("Pflichtspalte im Excel nicht gefunden: " & req)
+ End If
+ Next
+
+ If errors.Any(Function(x) x.StartsWith("Pflichtspalte im Excel nicht gefunden:")) Then
+ Return result
+ End If
+
+ ' =========================================================
+ ' Bereits vorhandene / ungültige MRN verwalten
+ ' =========================================================
+ Dim skippedExistingMrns As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
+ Dim invalidMrns As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
+ Dim dict As New Dictionary(Of String, cVERAG_CustomsDeclarations)(StringComparer.OrdinalIgnoreCase)
+ Dim artificialCounter As Integer = 0
+
+ For r As Integer = dataStartRow To lastRow
+
+ Dim mrn As String = GetCellString(ws, r, colMap, "MRN")
+ Dim referenceNo As String = GetCellString(ws, r, colMap, "reference_no")
+ Dim tariffCode As String = GetCellString(ws, r, colMap, "tariff_code")
+ Dim itemNoTxt As String = GetCellString(ws, r, colMap, "position_no")
+
+ ' Komplette Leerzeile überspringen
+ If mrn = "" AndAlso referenceNo = "" AndAlso tariffCode = "" AndAlso itemNoTxt = "" Then
+ Continue For
+ End If
+
+ ' =====================================================
+ ' Zeilenvalidierung
+ ' =====================================================
+ Dim validationMessage As String = ""
+ If Not ValidateImportRow(ws, r, colMap, validationMessage) Then
+ errors.Add(validationMessage)
+
+ If mrn <> "" Then
+ invalidMrns.Add(mrn)
+ End If
+
+ If stopOnFirstInvalidRow Then
+ Return result
+ End If
+
+ Continue For
+ End If
+
+ ' Wenn MRN bereits als ungültig markiert wurde -> überspringen
+ If mrn <> "" AndAlso invalidMrns.Contains(mrn) Then
+ Continue For
+ End If
+
+ ' =====================================================
+ ' MRN bereits in DB?
+ ' Dann komplette Anmeldung überspringen
+ ' =====================================================
+ If mrn <> "" Then
+ If skippedExistingMrns.Contains(mrn) Then
+ Continue For
+ End If
+
+ If MRN_EXISTS_IN_DB(mrn) Then
+ skippedExistingMrns.Add(mrn)
+ errors.Add("MRN bereits vorhanden - Import übersprungen: " & mrn & " (Zeile " & r & ")")
+ Continue For
+ End If
+ End If
+
+ ' =====================================================
+ ' Gruppenschlüssel
+ ' =====================================================
+ Dim grpKey As String = ""
+ If mrn <> "" Then
+ grpKey = "MRN|" & mrn
+ ElseIf referenceNo <> "" Then
+ grpKey = "REF|" & referenceNo
+ Else
+ artificialCounter += 1
+ grpKey = "AUTO|" & artificialCounter.ToString()
+ End If
+
+ Dim za As cVERAG_CustomsDeclarations = Nothing
+
+ If Not dict.ContainsKey(grpKey) Then
+
+ za = New cVERAG_CustomsDeclarations()
+
+ za.za_MRN = mrn
+ za.za_LRN = referenceNo
+ za.za_ReferenceCustomer = GetCellString(ws, r, colMap, "customer_reference")
+ za.za_RepresentationCode = GetCellString(ws, r, colMap, "representation_type")
+ za.za_DeclarationDate = GetCellDateNullable(ws, r, colMap, "declaration_date")
+ za.za_ReleaseDate = GetCellDateNullable(ws, r, colMap, "declaration_date")
+
+ za.za_CountryDispatch = GetCellString(ws, r, colMap, "dispatch_country")
+ za.za_CountryDestination = GetCellString(ws, r, colMap, "destination_country")
+ za.za_CountryImport = GetCellString(ws, r, colMap, "destination_country")
+
+ za.za_MainProcedure = GetCellString(ws, r, colMap, "requested_procedure")
+ za.za_InvoiceCurrency = GetCellString(ws, r, colMap, "invoice_currency")
+ za.za_InvoiceAmount = GetCellDecimalNullable(ws, r, colMap, "invoice_amount")
+ za.za_IsFinalDeclaration = True
+ za.za_REGIME = "IMPORT"
+
+ za.za_System = "CBAM_EXCEL_IMPORT"
+ za.za_CustomsSystem = ""
+ za.za_CustomsSystemCountry = ""
+ za.za_IsExternalSystem = True
+ za.za_Firma = ""
+ za.za_Niederlassung = ""
+ za.za_AdditionalProcedure = ""
+ za.za_WarehouseCode = ""
+ za.za_Incoterms = ""
+ za.za_IncotermsPlace = ""
+ za.za_TotGrossMass = Nothing
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="EXPORTER",
+ eori:=GetCellString(ws, r, colMap, "sender_eori"),
+ name:=GetCellString(ws, r, colMap, "sender_name"),
+ street:=GetCellString(ws, r, colMap, "sender_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "sender_country"),
+ email:="",
+ phone:=""
+ ))
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="CONSIGNEE",
+ eori:=GetCellString(ws, r, colMap, "recipient_eori"),
+ name:=GetCellString(ws, r, colMap, "recipient_name"),
+ street:=GetCellString(ws, r, colMap, "recipient_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "recipient_country"),
+ email:="",
+ phone:=""
+ ))
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="IMPORTER",
+ eori:=GetCellString(ws, r, colMap, "importer_eori"),
+ name:=GetCellString(ws, r, colMap, "importer_name"),
+ street:=GetCellString(ws, r, colMap, "importer_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "importer_country"),
+ email:=GetCellString(ws, r, colMap, "importer_email"),
+ phone:=GetCellString(ws, r, colMap, "importer_phone")
+ ))
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="DECLARANT",
+ eori:=GetCellString(ws, r, colMap, "declarant_eori"),
+ name:=GetCellString(ws, r, colMap, "declarant_name"),
+ street:=GetCellString(ws, r, colMap, "declarant_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "declarant_country"),
+ email:="",
+ phone:=""
+ ))
+
+ Dim invNo = GetCellString(ws, r, colMap, "invoice_number")
+ Dim invDate = GetCellString(ws, r, colMap, "invoice_date")
+
+ If invNo <> "" OrElse invDate <> "" Then
+ za.Documents.Add(New cVERAG_CustomsDeclarations_Document With {
+ .zaDoc_Code = "N380",
+ .zaDoc_Reference = invNo,
+ .zaDoc_Date = invDate,
+ .zaDoc_Description = "Invoice"
+ })
+ End If
+
+ dict.Add(grpKey, za)
+
+ Else
+ za = dict(grpKey)
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="EXPORTER",
+ eori:=GetCellString(ws, r, colMap, "sender_eori"),
+ name:=GetCellString(ws, r, colMap, "sender_name"),
+ street:=GetCellString(ws, r, colMap, "sender_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "sender_country"),
+ email:="",
+ phone:=""
+ ))
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="CONSIGNEE",
+ eori:=GetCellString(ws, r, colMap, "recipient_eori"),
+ name:=GetCellString(ws, r, colMap, "recipient_name"),
+ street:=GetCellString(ws, r, colMap, "recipient_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "recipient_country"),
+ email:="",
+ phone:=""
+ ))
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="IMPORTER",
+ eori:=GetCellString(ws, r, colMap, "importer_eori"),
+ name:=GetCellString(ws, r, colMap, "importer_name"),
+ street:=GetCellString(ws, r, colMap, "importer_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "importer_country"),
+ email:=GetCellString(ws, r, colMap, "importer_email"),
+ phone:=GetCellString(ws, r, colMap, "importer_phone")
+ ))
+
+ AddOrMergeParty(za.Parties, CreateParty(
+ role:="DECLARANT",
+ eori:=GetCellString(ws, r, colMap, "declarant_eori"),
+ name:=GetCellString(ws, r, colMap, "declarant_name"),
+ street:=GetCellString(ws, r, colMap, "declarant_address"),
+ postalCode:="",
+ city:="",
+ country:=GetCellString(ws, r, colMap, "declarant_country"),
+ email:="",
+ phone:=""
+ ))
+ End If
+
+ Dim it As New cVERAG_CustomsDeclarations_Item()
+
+ it.zaItem_PosNo = GetCellInt(ws, r, colMap, "position_no", za.Items.Count + 1)
+ it.zaItem_HSCode = GetCellString(ws, r, colMap, "tariff_code")
+ it.zaItem_OriginCountry = GetCellString(ws, r, colMap, "origin_country")
+ it.zaItem_GrossMass = GetCellDecimalNullable(ws, r, colMap, "gross_mass_kg")
+ it.zaItem_NetMass = GetCellDecimalNullable(ws, r, colMap, "net_mass_kg")
+ it.zaItem_SuppUnitCode = GetCellString(ws, r, colMap, "measurement_unit")
+ it.zaItem_PrevProcedure = GetCellString(ws, r, colMap, "previous_procedure")
+ it.zaItem_MainProcedure = GetCellString(ws, r, colMap, "requested_procedure")
+ it.zaItem_InvoiceValueEUR = GetCellDecimalNullable(ws, r, colMap, "invoice_amount")
+ it.zaItem_InvoiceCurrency = GetCellString(ws, r, colMap, "invoice_currency")
+ it.zaItem_StatisticalValueEUR = GetCellDecimalNullable(ws, r, colMap, "invoice_amount")
+
+ Dim remarks As String = ""
+ Dim bench = GetCellString(ws, r, colMap, "Benchmark (Default)")
+ Dim emi = GetCellString(ws, r, colMap, "Emission (Default)")
+ Dim fac = GetCellString(ws, r, colMap, "Factor")
+ Dim est = GetCellString(ws, r, colMap, "Estimated Cost")
+
+ If bench <> "" OrElse emi <> "" OrElse fac <> "" OrElse est <> "" Then
+ remarks =
+ "CBAM Import | " &
+ "Benchmark=" & bench & "; " &
+ "Emission=" & emi & "; " &
+ "Factor=" & fac & "; " &
+ "EstimatedCost=" & est
+ End If
+
+ it.zaItem_Remarks = remarks
+
+ Dim itemInvNo = GetCellString(ws, r, colMap, "invoice_number")
+ Dim itemInvDate = GetCellString(ws, r, colMap, "invoice_date")
+
+ If itemInvNo <> "" OrElse itemInvDate <> "" Then
+ it.Documents.Add(New cVERAG_CustomsDeclarations_Document With {
+ .zaDoc_Code = "N380",
+ .zaDoc_Reference = itemInvNo,
+ .zaDoc_Date = itemInvDate,
+ .zaDoc_Description = "Invoice"
+ })
+ End If
+
+ za.Items.Add(it)
+
+ Next
+
+ For Each za In dict.Values
+ If za.Items IsNot Nothing AndAlso za.Items.Count > 0 Then
+ za.za_TotGrossMass = za.Items.Sum(Function(x) If(x.zaItem_GrossMass, 0D))
+
+ If Not za.za_InvoiceAmount.HasValue Then
+ Dim invSum = za.Items.Sum(Function(x) If(x.zaItem_InvoiceValueEUR, 0D))
+ If invSum <> 0D Then
+ za.za_InvoiceAmount = invSum
+ End If
+ End If
+
+ result.Add(za)
+ End If
+ Next
+
+ End Using
+
+ Catch ex As Exception
+ VERAG_PROG_ALLGEMEIN.cErrorHandler.ERR(ex.Message, ex.StackTrace, Reflection.MethodInfo.GetCurrentMethod.Name)
+ End Try
+
+ Return result
+
+ End Function
+
+ Private Shared Function ValidateImportRow(ws As IXLWorksheet,
+ row As Integer,
+ colMap As Dictionary(Of String, Integer),
+ ByRef validationMessage As String) As Boolean
+
+ validationMessage = ""
+
+ Dim mrn As String = GetCellString(ws, row, colMap, "MRN")
+ Dim tariffCode As String = GetCellString(ws, row, colMap, "tariff_code")
+ Dim declarationDate As Date? = GetCellDateNullable(ws, row, colMap, "declaration_date")
+
+ Dim missing As New List(Of String)
+
+ If mrn = "" Then missing.Add("MRN")
+ If Not declarationDate.HasValue Then missing.Add("declaration_date")
+ If tariffCode = "" Then missing.Add("tariff_code")
+
+ If missing.Count > 0 Then
+ validationMessage = "Zeile " & row & " ungültig. Pflichtfeld(er) fehlen oder sind ungültig: " & String.Join(", ", missing)
+ Return False
+ End If
+
+ Return True
+
+ End Function
+
+ Private Shared Function MRN_EXISTS_IN_DB(mrn As String) As Boolean
+
+ Try
+ mrn = TrimSafe(mrn)
+ If mrn = "" Then Return False
+
+ Dim za = cVERAG_CustomsDeclarations.loadByMRN(mrn, False)
+ Return za IsNot Nothing AndAlso za.hasEntry
+
+ Catch ex As Exception
+ VERAG_PROG_ALLGEMEIN.cErrorHandler.ERR(ex.Message, ex.StackTrace, Reflection.MethodInfo.GetCurrentMethod.Name)
+ End Try
+
+ Return False
+
+ End Function
+
+ Private Shared Function CreateParty(role As String,
+ eori As String,
+ name As String,
+ street As String,
+ postalCode As String,
+ city As String,
+ country As String,
+ email As String,
+ phone As String) As cVERAG_CustomsDeclarations_Parties
+
+ If TrimSafe(eori) = "" AndAlso
+ TrimSafe(name) = "" AndAlso
+ TrimSafe(street) = "" AndAlso
+ TrimSafe(country) = "" AndAlso
+ TrimSafe(email) = "" AndAlso
+ TrimSafe(phone) = "" Then
+ Return Nothing
+ End If
+
+ Return New cVERAG_CustomsDeclarations_Parties With {
+ .zaParty_Role = role,
+ .zaParty_EORI = TrimSafe(eori),
+ .zaParty_Name = TrimSafe(name),
+ .zaParty_Street = TrimSafe(street),
+ .zaParty_PostalCode = TrimSafe(postalCode),
+ .zaParty_City = TrimSafe(city),
+ .zaParty_Country = TrimSafe(country),
+ .zaParty_Email = TrimSafe(email),
+ .zaParty_Phone = TrimSafe(phone)
+ }
+
+ End Function
+
+ Private Shared Sub AddOrMergeParty(list As List(Of cVERAG_CustomsDeclarations_Parties),
+ p As cVERAG_CustomsDeclarations_Parties)
+
+ If p Is Nothing Then Exit Sub
+ If list Is Nothing Then Exit Sub
+
+ Dim existing = list.FirstOrDefault(Function(x)
+ Return String.Equals(TrimSafe(x.zaParty_Role), TrimSafe(p.zaParty_Role), StringComparison.OrdinalIgnoreCase) AndAlso
+ String.Equals(TrimSafe(x.zaParty_EORI), TrimSafe(p.zaParty_EORI), StringComparison.OrdinalIgnoreCase) AndAlso
+ String.Equals(TrimSafe(x.zaParty_Name), TrimSafe(p.zaParty_Name), StringComparison.OrdinalIgnoreCase)
+ End Function)
+
+ If existing Is Nothing Then
+ list.Add(p)
+ Else
+ If TrimSafe(existing.zaParty_Street) = "" Then existing.zaParty_Street = p.zaParty_Street
+ If TrimSafe(existing.zaParty_PostalCode) = "" Then existing.zaParty_PostalCode = p.zaParty_PostalCode
+ If TrimSafe(existing.zaParty_City) = "" Then existing.zaParty_City = p.zaParty_City
+ If TrimSafe(existing.zaParty_Country) = "" Then existing.zaParty_Country = p.zaParty_Country
+ If TrimSafe(existing.zaParty_Email) = "" Then existing.zaParty_Email = p.zaParty_Email
+ If TrimSafe(existing.zaParty_Phone) = "" Then existing.zaParty_Phone = p.zaParty_Phone
+ End If
+
+ End Sub
+
+ Private Shared Function GetCellString(ws As IXLWorksheet,
+ row As Integer,
+ colMap As Dictionary(Of String, Integer),
+ header As String) As String
+
+ Try
+ If ws Is Nothing OrElse colMap Is Nothing Then Return ""
+ If Not colMap.ContainsKey(header) Then Return ""
+ Return TrimSafe(ws.Cell(row, colMap(header)).GetString())
+ Catch
+ Return ""
+ End Try
+
+ End Function
+
+ Private Shared Function GetCellDecimalNullable(ws As IXLWorksheet,
+ row As Integer,
+ colMap As Dictionary(Of String, Integer),
+ header As String) As Decimal?
+
+ Try
+ If ws Is Nothing OrElse colMap Is Nothing Then Return Nothing
+ If Not colMap.ContainsKey(header) Then Return Nothing
+
+ Dim cell = ws.Cell(row, colMap(header))
+ If cell Is Nothing OrElse cell.IsEmpty() Then Return Nothing
+
+ If cell.DataType = XLDataType.Number Then
+ Return Convert.ToDecimal(cell.GetDouble())
+ End If
+
+ Dim txt = TrimSafe(cell.GetString())
+ If txt = "" Then Return Nothing
+
+ Dim d As Decimal
+ txt = txt.Replace(" ", "")
+
+ If Decimal.TryParse(txt, NumberStyles.Any, CultureInfo.InvariantCulture, d) Then Return d
+ If Decimal.TryParse(txt, NumberStyles.Any, CultureInfo.GetCultureInfo("de-AT"), d) Then Return d
+ If Decimal.TryParse(txt, NumberStyles.Any, CultureInfo.GetCultureInfo("de-DE"), d) Then Return d
+
+ Catch
+ End Try
+
+ Return Nothing
+
+ End Function
+
+ Private Shared Function GetCellDateNullable(ws As IXLWorksheet,
+ row As Integer,
+ colMap As Dictionary(Of String, Integer),
+ header As String) As Date?
+
+ Try
+ If ws Is Nothing OrElse colMap Is Nothing Then Return Nothing
+ If Not colMap.ContainsKey(header) Then Return Nothing
+
+ Dim cell = ws.Cell(row, colMap(header))
+ If cell Is Nothing OrElse cell.IsEmpty() Then Return Nothing
+
+ If cell.DataType = XLDataType.DateTime Then
+ Return cell.GetDateTime()
+ End If
+
+ If cell.DataType = XLDataType.Number Then
+ Return DateTime.FromOADate(cell.GetDouble())
+ End If
+
+ Dim txt = TrimSafe(cell.GetString())
+ If txt = "" Then Return Nothing
+
+ Dim dt As DateTime
+ If DateTime.TryParse(txt, CultureInfo.InvariantCulture, DateTimeStyles.None, dt) Then Return dt
+ If DateTime.TryParse(txt, CultureInfo.GetCultureInfo("de-AT"), DateTimeStyles.None, dt) Then Return dt
+ If DateTime.TryParse(txt, CultureInfo.GetCultureInfo("de-DE"), DateTimeStyles.None, dt) Then Return dt
+
+ Catch
+ End Try
+
+ Return Nothing
+
+ End Function
+
+ Private Shared Function GetCellInt(ws As IXLWorksheet,
+ row As Integer,
+ colMap As Dictionary(Of String, Integer),
+ header As String,
+ Optional defaultValue As Integer = 0) As Integer
+
+ Try
+ If ws Is Nothing OrElse colMap Is Nothing Then Return defaultValue
+ If Not colMap.ContainsKey(header) Then Return defaultValue
+
+ Dim cell = ws.Cell(row, colMap(header))
+ If cell Is Nothing OrElse cell.IsEmpty() Then Return defaultValue
+
+ If cell.DataType = XLDataType.Number Then
+ Return Convert.ToInt32(Math.Truncate(cell.GetDouble()))
+ End If
+
+ Dim txt = TrimSafe(cell.GetString())
+ If txt = "" Then Return defaultValue
+
+ Dim i As Integer
+ If Integer.TryParse(txt, i) Then Return i
+
+ Dim d As Decimal
+ If Decimal.TryParse(txt, NumberStyles.Any, CultureInfo.InvariantCulture, d) Then
+ Return Convert.ToInt32(Math.Truncate(d))
+ End If
+ If Decimal.TryParse(txt, NumberStyles.Any, CultureInfo.GetCultureInfo("de-AT"), d) Then
+ Return Convert.ToInt32(Math.Truncate(d))
+ End If
+ If Decimal.TryParse(txt, NumberStyles.Any, CultureInfo.GetCultureInfo("de-DE"), d) Then
+ Return Convert.ToInt32(Math.Truncate(d))
+ End If
+
+ Catch
+ End Try
+
+ Return defaultValue
+
+ End Function
+
+ Private Shared Function TrimSafe(value As Object) As String
+ If value Is Nothing Then Return ""
+ Return Convert.ToString(value).Trim()
+ End Function
+
+End Class
\ No newline at end of file