Imports System.Data.SqlClient
Imports System.Reflection


' ===========================================================
' ===============   KOPF  (imDHFAnm)   ======================
' ===========================================================
Public Class cDHF_Import
    ' ====== Primärschlüssel (zusammengesetzt) ======

    Public LizenzNr As String = "S01122"
    Public Property OperatorID As String
    Public Property VorgangID As String
    Public Property AnmID As String
    Public Property Kennung As String

    ' ====== Datenfelder Kopf imDHFAnm (wie geliefert) ======
    Public Property DatenKomplett As Object
    Public Property LRN As Object
    Public Property TotPack As Object
    Public Property TotGross As Object
    Public Property Dest As Object
    Public Property InMo As Object
    Public Property BordMo As Object
    Public Property DepIdnt As Object
    Public Property DepNat As Object
    Public Property CrossIdnt As Object
    Public Property CrossIdntNat As Object
    Public Property TermDelCd As Object
    Public Property TermDelSit As Object
    Public Property InvCurr As Object
    Public Property InvVal As Object
    Public Property ConeeTraNa As Object
    Public Property ConeeTraStrt As Object
    Public Property ConeeTraPst As Object
    Public Property ConeeTraCty As Object
    Public Property ConeeTraCtry As Object
    Public Property ConeeTraFremdAdressID As Object
    Public Property ExitCORef As Object
    Public Property RechnungsNr As Object
    Public Property RechnungsDatum As Object
    Public Property DecTy As Object
    Public Property Disp As Object
    Public Property ArrLocAuth As Object
    Public Property ContInd As Object
    Public Property TransacCd As Object
    Public Property ConorTraNa As Object
    Public Property ConorTraStrt As Object
    Public Property ConorTraPst As Object
    Public Property ConorTraCty As Object
    Public Property ConorTraCtry As Object
    Public Property ConorTraFremdAdressID As Object
    Public Property KzPool As Object
    Public Property ConeeTraUIDCtry As Object
    Public Property ConeeTraUID As Object
    Public Property EntryCORef As Object
    Public Property SendungsDatum As Object
    Public Property PDTy As Object
    Public Property DRef As Object
    Public Property CInf As Object
    Public Property Cat As Object
    Public Property InfoText As Object
    Public Property SendungsNr As Object
    Public Property ConorTraUIDCtry As Object
    Public Property ConorTraUID As Object
    Public Property AnschreibeNr As Object
    Public Property RIN As Object
    Public Property KzAutomatik As Object
    Public Property SecInd As Object
    Public Property SpecCirc As Object
    Public Property TransPayTy As Object
    Public Property ComRef As Object
    Public Property LodCoRef As Object
    Public Property ResCd As Object
    Public Property DLimit As Object
    Public Property Route As Object
    Public Property SNr As Object
    Public Property KzEigenmassenaufteilung As Object
    Public Property MusterName As Object
    Public Property ConvRef As Object
    Public Property ProArrDT As Object
    Public Property LoadPlc As Object
    Public Property UnloadPlcCd As Object
    Public Property UnloadPlc As Object
    Public Property FirEntryCoRef As Object
    Public Property CarrTraNa As Object
    Public Property CarrTraStrt As Object
    Public Property CarrTraPst As Object
    Public Property CarrTraCty As Object
    Public Property CarrTraCtry As Object
    Public Property CarrTraFremdAdressID As Object
    Public Property NotifyTraNa As Object
    Public Property NotifyTraStrt As Object
    Public Property NotifyTraPst As Object
    Public Property NotifyTraCty As Object
    Public Property NotifyTraCtry As Object
    Public Property NotifyTraFremdAdressID As Object
    Public Property RepTraFremdAdressID As Object
    Public Property SumDecTraFremdAdressID As Object
    Public Property DecPlc As Object
    Public Property DecDT As Object
    Public Property RelationsID As Object
    Public Property SSt_LizenzNr As Object
    Public Property SSt_ID As Object
    Public Property SSt_ArtID As Object
    Public Property SSt_ProtokollKopfID As Object
    Public Property KzPredeclaration As Object
    Public Property AccDT As Object
    Public Property PayTy As Object
    Public Property DepoCd As Object
    Public Property WarTy As Object
    Public Property WarCtry As Object
    Public Property War As Object
    Public Property ZLID As Object
    Public Property TermDelCtry As Object
    Public Property TermDelPlc As Object

    ' ====== Navigation / Unterobjekte ======
    Public Property GdsItems As New List(Of cDHF_Import_GdsItem)

    Private Const TBL As String = "imDHFAnm"
    Private ReadOnly SQL As New SQL

    ' ---- Konstruktor (Leeres Objekt) ----
    Public Sub New()
    End Sub

    ' ---- Konstruktor mit Schlüssel + Auto-Load ----
    Public Sub New(lizenzNr As String, operatorId As String, vorgangId As String, anmId As String, kennung As String)
        Me.LizenzNr = lizenzNr : Me.OperatorID = operatorId : Me.VorgangID = vorgangId : Me.AnmID = anmId : Me.Kennung = kennung
        Load()
    End Sub

    ' ---- Parameterliste dynamisch erzeugen (PK markiert) ----
    Private Function GetVarList(Optional includePK As Boolean = True) As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        Dim l As New List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)

        ' PK
        If includePK Then
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("LizenzNr", LizenzNr, "LizenzNr", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("OperatorID", OperatorID, "OperatorID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("VorgangID", VorgangID, "VorgangID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("AnmID", AnmID, "AnmID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("Kennung", Kennung, "Kennung", True))
        End If

        ' Alle Felder (Non-PK)
        Dim allProps = Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance).
                       Where(Function(p) p.CanRead AndAlso p.CanWrite AndAlso p.Name <> NameOf(GdsItems))
        For Each p In allProps
            If {"LizenzNr", "OperatorID", "VorgangID", "AnmID", "Kennung"}.Contains(p.Name) Then Continue For
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable(p.Name, p.GetValue(Me), p.Name, False))
        Next
        Return l
    End Function

    ' ---- Save: Upsert + Kinder in Transaktion ----
    Public Function Save() As Boolean
        Using conn As SqlConnection = SQL.GetNewOpenConnectionFMZOLL()
            Using tr = conn.BeginTransaction()
                Try
                    ' Upsert Kopf
                    Dim vars = GetVarList(includePK:=True)
                    Dim wherePk = "WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung"
                    Dim sqlCheck = $"IF EXISTS(SELECT 1 FROM [{TBL}] {wherePk}) BEGIN {_SqlDyn.BuildUpdateCmd(TBL, vars)} END ELSE BEGIN {_SqlDyn.BuildInsertCmd(TBL, vars)} END"

                    Using cmd As New SqlCommand(sqlCheck, conn, tr)
                        _SqlDyn.AddParams(cmd, vars)
                        cmd.ExecuteNonQuery()
                    End Using

                    ' Kinder neu schreiben: erst löschen, dann einfügen (vereinfachte Konsistenz)
                    DeleteChildren(conn, tr)

                    ' Positionen + Unterpositionen schreiben
                    For Each it In GdsItems
                        it.LizenzNr = Me.LizenzNr
                        it.OperatorID = Me.OperatorID
                        it.VorgangID = Me.VorgangID
                        it.AnmID = Me.AnmID
                        it.Kennung = Me.Kennung
                        it.Save(conn, tr)
                    Next

                    tr.Commit()
                    Return True
                Catch ex As Exception
                    tr.Rollback()
                    VERAG_PROG_ALLGEMEIN.cErrorHandler.ERR(ex.Message, ex.StackTrace, MethodBase.GetCurrentMethod().Name)
                    Return False
                End Try
            End Using
        End Using
    End Function

    Private Sub DeleteChildren(conn As SqlConnection, tr As SqlTransaction)
        ' Löscht alle abhängigen Einträge (DocCerts + Pack zuerst, dann GdsItems)
        Dim pkWhere = "WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung"
        Dim delDoc = $"DELETE d FROM [imDHFAnmGdsItemDocCerts] d INNER JOIN [imDHFAnmGdsItem] i ON d.LizenzNr=i.LizenzNr AND d.OperatorID=i.OperatorID AND d.VorgangID=i.VorgangID AND d.AnmID=i.AnmID AND d.Kennung=i.Kennung AND d.GdsItemID=i.GdsItemID {pkWhere.Replace("WHERE", "WHERE i.")}"
        Dim delPack = $"DELETE p FROM [imDHFAnmGdsItemPack] p INNER JOIN [imDHFAnmGdsItem] i ON p.LizenzNr=i.LizenzNr AND p.OperatorID=i.OperatorID AND p.VorgangID=i.VorgangID AND p.AnmID=i.AnmID AND p.Kennung=i.Kennung AND p.GdsItemID=i.GdsItemID {pkWhere.Replace("WHERE", "WHERE i.")}"
        Dim delIt = $"DELETE FROM [imDHFAnmGdsItem] {pkWhere}"

        Dim pars As New List(Of VERAG_PROG_ALLGEMEIN.SQLVariable) From {
            New VERAG_PROG_ALLGEMEIN.SQLVariable("LizenzNr", LizenzNr, "LizenzNr", True),
            New VERAG_PROG_ALLGEMEIN.SQLVariable("OperatorID", OperatorID, "OperatorID", True),
            New VERAG_PROG_ALLGEMEIN.SQLVariable("VorgangID", VorgangID, "VorgangID", True),
            New VERAG_PROG_ALLGEMEIN.SQLVariable("AnmID", AnmID, "AnmID", True),
            New VERAG_PROG_ALLGEMEIN.SQLVariable("Kennung", Kennung, "Kennung", True)
        }

        For Each s In {delDoc, delPack, delIt}
            Using cmd As New SqlCommand(s, conn, tr)
                _SqlDyn.AddParams(cmd, pars)
                cmd.ExecuteNonQuery()
            End Using
        Next
    End Sub

    ' ---- Load: Kopf + Kinder ----
    Public Sub Load()
        Using conn As SqlConnection = SQL.GetNewOpenConnectionFMZOLL()
            ' Kopf
            Dim selectHead = $"SELECT * FROM [{TBL}] WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung"
            Using cmd As New SqlCommand(selectHead, conn)
                cmd.Parameters.AddWithValue("@LizenzNr", LizenzNr)
                cmd.Parameters.AddWithValue("@OperatorID", OperatorID)
                cmd.Parameters.AddWithValue("@VorgangID", VorgangID)
                cmd.Parameters.AddWithValue("@AnmID", AnmID)
                cmd.Parameters.AddWithValue("@Kennung", Kennung)
                Using dr = cmd.ExecuteReader()
                    If dr.Read() Then
                        _SqlDyn.DataReaderToObject(dr, Me, GetVarList(includePK:=False))
                    End If
                End Using
            End Using

            ' Kinder laden
            Me.GdsItems.Clear()
            Dim selectIt = "SELECT * FROM [imDHFAnmGdsItem] WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung ORDER BY ItNr"
            Using cmd As New SqlCommand(selectIt, conn)
                cmd.Parameters.AddWithValue("@LizenzNr", LizenzNr)
                cmd.Parameters.AddWithValue("@OperatorID", OperatorID)
                cmd.Parameters.AddWithValue("@VorgangID", VorgangID)
                cmd.Parameters.AddWithValue("@AnmID", AnmID)
                cmd.Parameters.AddWithValue("@Kennung", Kennung)
                Using dr = cmd.ExecuteReader()
                    While dr.Read()
                        Dim it As New cDHF_Import_GdsItem() With {
                            .LizenzNr = dr("LizenzNr").ToString(),
                            .OperatorID = dr("OperatorID").ToString(),
                            .VorgangID = dr("VorgangID").ToString(),
                            .AnmID = dr("AnmID").ToString(),
                            .Kennung = dr("Kennung").ToString(),
                            .GdsItemID = dr("GdsItemID").ToString()
                        }
                        it.FillFromReader(dr)
                        GdsItems.Add(it)
                    End While
                End Using
            End Using

            ' Unterobjekte je Position laden
            For Each it In GdsItems
                it.LoadChildren(conn)
            Next
        End Using
    End Sub
End Class

' ===========================================================
' ===============   POSITION  (imDHFAnmGdsItem)   ===========
' ===========================================================
Public Class cDHF_Import_GdsItem
    ' ====== FK/PK-Teil (Kopfbezug + pos-ID) ======
    Public Property LizenzNr As String
    Public Property OperatorID As String
    Public Property VorgangID As String
    Public Property AnmID As String
    Public Property Kennung As String
    Public Property GdsItemID As String

    ' ====== Positionsfelder ======
    Public Property ItNr As Object
    Public Property ComCd As Object
    Public Property GdsDes As Object
    Public Property Gross As Object
    Public Property Net As Object
    Public Property ProcCd As Object
    Public Property ProcAddCd As Object
    Public Property ItVal As Object
    Public Property Orig As Object
    Public Property Pref As Object
    Public Property Quota As Object
    Public Property ValMet As Object
    Public Property VATInd As Object
    Public Property ArtikelCode As Object
    Public Property InfoText As Object
    Public Property ArtikelMenge As Object
    Public Property ArtikelMengenEH As Object
    Public Property RezOrt As Object
    Public Property SNr As Object
    Public Property ProcTxt As Object
    Public Property ComplPer As Object
    Public Property ProsYield As Object
    Public Property SpecMod As Object
    Public Property RecCd As Object
    Public Property SurvCORef As Object
    Public Property EndCORef As Object
    Public Property ComRef As Object
    Public Property UNDangCd As Object
    Public Property GlobCd As Object
    Public Property GlobPer As Object
    Public Property CondCd As Object
    Public Property TransPayTy As Object
    Public Property ConorTraNa As Object
    Public Property ConorTraStrt As Object
    Public Property ConorTraPst As Object
    Public Property ConorTraCty As Object
    Public Property ConorTraCtry As Object
    Public Property ConorTraTIN As Object
    Public Property ConorTraAdressIDDHF As Object
    Public Property ConeeTraNa As Object
    Public Property ConeeTraStrt As Object
    Public Property ConeeTraPst As Object
    Public Property ConeeTraCty As Object
    Public Property ConeeTraCtry As Object
    Public Property ConeeTraTIN As Object
    Public Property ConeeTraAdressIDDHF As Object
    Public Property ExtraDEBundesland As Object

    ' ====== Unterlisten ======
    Public Property DocCerts As New List(Of cDHF_Import_GdsItemDocCerts)
    Public Property Packs As New List(Of cDHF_Import_GdsItemPack)

    Private Const TBL As String = "imDHFAnmGdsItem"

    Friend Sub FillFromReader(dr As SqlDataReader)
        Dim props = Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance).
            Where(Function(p) p.CanRead AndAlso p.CanWrite AndAlso p.Name <> NameOf(DocCerts) AndAlso p.Name <> NameOf(Packs))
        For Each p In props
            If dr.GetSchemaTable().Rows.Cast(Of DataRow)().Any(Function(r) r("ColumnName").ToString() = p.Name) Then
                If dr.IsDBNull(dr.GetOrdinal(p.Name)) Then
                    p.SetValue(Me, Nothing)
                Else
                    p.SetValue(Me, dr(p.Name))
                End If
            End If
        Next
    End Sub

    Private Function GetVarList(Optional includePK As Boolean = True) As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        Dim l As New List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        If includePK Then
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("LizenzNr", LizenzNr, "LizenzNr", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("OperatorID", OperatorID, "OperatorID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("VorgangID", VorgangID, "VorgangID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("AnmID", AnmID, "AnmID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("Kennung", Kennung, "Kennung", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("GdsItemID", GdsItemID, "GdsItemID", True))
        End If

        Dim skip = New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {
            "LizenzNr", "OperatorID", "VorgangID", "AnmID", "Kennung", "GdsItemID",
            NameOf(DocCerts), NameOf(Packs)
        }
        For Each p In Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance)
            If Not p.CanRead OrElse Not p.CanWrite OrElse skip.Contains(p.Name) Then Continue For
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable(p.Name, p.GetValue(Me), p.Name, False))
        Next
        Return l
    End Function

    Friend Sub Save(conn As SqlConnection, tr As SqlTransaction)
        ' Upsert Position
        Dim vars = GetVarList(includePK:=True)
        Dim wherePk = "WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung AND [GdsItemID]=@GdsItemID"
        Dim sqlCheck = $"IF EXISTS(SELECT 1 FROM [{TBL}] {wherePk}) BEGIN {_SqlDyn.BuildUpdateCmd(TBL, vars)} END ELSE BEGIN {_SqlDyn.BuildInsertCmd(TBL, vars)} END"
        Using cmd As New SqlCommand(sqlCheck, conn, tr)
            _SqlDyn.AddParams(cmd, vars)
            cmd.ExecuteNonQuery()
        End Using

        ' Kinder neu schreiben (DocCerts, Packs): delete + insert
        DeleteChildren(conn, tr)

        For Each d In DocCerts
            d.LizenzNr = LizenzNr : d.OperatorID = OperatorID : d.VorgangID = VorgangID : d.AnmID = AnmID : d.Kennung = Kennung
            d.GdsItemID = GdsItemID
            d.Save(conn, tr)
        Next
        For Each p In Packs
            p.LizenzNr = LizenzNr : p.OperatorID = OperatorID : p.VorgangID = VorgangID : p.AnmID = AnmID : p.Kennung = Kennung
            p.GdsItemID = GdsItemID
            p.Save(conn, tr)
        Next
    End Sub

    Private Sub DeleteChildren(conn As SqlConnection, tr As SqlTransaction)
        Dim wherePk = "WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung AND [GdsItemID]=@GdsItemID"
        For Each ttt In {"imDHFAnmGdsItemDocCerts", "imDHFAnmGdsItemPack"}
            Using cmd As New SqlCommand($"DELETE FROM [{ttt}] {wherePk}", conn, tr)
                cmd.Parameters.AddWithValue("@LizenzNr", LizenzNr)
                cmd.Parameters.AddWithValue("@OperatorID", OperatorID)
                cmd.Parameters.AddWithValue("@VorgangID", VorgangID)
                cmd.Parameters.AddWithValue("@AnmID", AnmID)
                cmd.Parameters.AddWithValue("@Kennung", Kennung)
                cmd.Parameters.AddWithValue("@GdsItemID", GdsItemID)
                cmd.ExecuteNonQuery()
            End Using
        Next
    End Sub

    Friend Sub LoadChildren(conn As SqlConnection)
        ' DocCerts
        DocCerts.Clear()
        Dim sDoc = "SELECT * FROM [imDHFAnmGdsItemDocCerts] WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung AND [GdsItemID]=@GdsItemID ORDER BY DocCertsID"
        Using cmd As New SqlCommand(sDoc, conn)
            cmd.Parameters.AddWithValue("@LizenzNr", LizenzNr)
            cmd.Parameters.AddWithValue("@OperatorID", OperatorID)
            cmd.Parameters.AddWithValue("@VorgangID", VorgangID)
            cmd.Parameters.AddWithValue("@AnmID", AnmID)
            cmd.Parameters.AddWithValue("@Kennung", Kennung)
            cmd.Parameters.AddWithValue("@GdsItemID", GdsItemID)
            Using dr = cmd.ExecuteReader()
                While dr.Read()
                    Dim d As New cDHF_Import_GdsItemDocCerts() With {
                        .LizenzNr = LizenzNr, .OperatorID = OperatorID, .VorgangID = VorgangID,
                        .AnmID = AnmID, .Kennung = Kennung, .GdsItemID = GdsItemID,
                        .DocCertsID = dr("DocCertsID").ToString()
                    }
                    d.FillFromReader(dr)
                    DocCerts.Add(d)
                End While
            End Using
        End Using

        ' Packs
        Packs.Clear()
        Dim sPack = "SELECT * FROM [imDHFAnmGdsItemPack] WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung AND [GdsItemID]=@GdsItemID ORDER BY PackID"
        Using cmd As New SqlCommand(sPack, conn)
            cmd.Parameters.AddWithValue("@LizenzNr", LizenzNr)
            cmd.Parameters.AddWithValue("@OperatorID", OperatorID)
            cmd.Parameters.AddWithValue("@VorgangID", VorgangID)
            cmd.Parameters.AddWithValue("@AnmID", AnmID)
            cmd.Parameters.AddWithValue("@Kennung", Kennung)
            cmd.Parameters.AddWithValue("@GdsItemID", GdsItemID)
            Using dr = cmd.ExecuteReader()
                While dr.Read()
                    Dim p As New cDHF_Import_GdsItemPack() With {
                        .LizenzNr = LizenzNr, .OperatorID = OperatorID, .VorgangID = VorgangID,
                        .AnmID = AnmID, .Kennung = Kennung, .GdsItemID = GdsItemID,
                        .PackID = dr("PackID").ToString()
                    }
                    p.FillFromReader(dr)
                    Packs.Add(p)
                End While
            End Using
        End Using
    End Sub
End Class

' ===========================================================
' ============   DOC/CERTS  (imDHFAnmGdsItemDocCerts)   =====
' ===========================================================
Public Class cDHF_Import_GdsItemDocCerts
    ' FK/PK
    Public Property LizenzNr As String
    Public Property OperatorID As String
    Public Property VorgangID As String
    Public Property AnmID As String
    Public Property Kennung As String
    Public Property GdsItemID As String
    Public Property DocCertsID As String

    ' Felder
    Public Property DocCd As Object
    Public Property DTy As Object
    Public Property DRef As Object
    Public Property IssD As Object
    Public Property IssCtry As Object
    Public Property DTIN As Object
    Public Property Curr As Object
    Public Property Avail As Object
    Public Property UidVid As Object
    Public Property IssAdm As Object
    Public Property ValD As Object
    Public Property MaxValD As Object
    Public Property CInf As Object
    Public Property InfoLNG As Object
    Public Property Unit As Object
    Public Property Quant As Object
    Public Property MaxQuant As Object
    Public Property WOUnit As Object
    Public Property WOoUnit As Object
    Public Property WOCurr As Object
    Public Property WOInQuant As Object
    Public Property WOQuant As Object
    Public Property WORemQunat As Object
    Public Property CRefTy As Object
    Public Property CRefRef As Object
    Public Property CRefIt As Object
    Public Property CRefLNG As Object
    Public Property AvailDT As Object
    Public Property AdressIDDHF As Object
    Public Property Na As Object
    Public Property Strt As Object
    Public Property Pst As Object
    Public Property Cty As Object
    Public Property Ctry As Object
    Public Property LNG As Object

    Private Const TBL As String = "imDHFAnmGdsItemDocCerts"

    Private Function GetVarList(Optional includePK As Boolean = True) As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        Dim l As New List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        If includePK Then
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("LizenzNr", LizenzNr, "LizenzNr", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("OperatorID", OperatorID, "OperatorID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("VorgangID", VorgangID, "VorgangID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("AnmID", AnmID, "AnmID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("Kennung", Kennung, "Kennung", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("GdsItemID", GdsItemID, "GdsItemID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("DocCertsID", DocCertsID, "DocCertsID", True))
        End If

        Dim skip = New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {
            "LizenzNr", "OperatorID", "VorgangID", "AnmID", "Kennung", "GdsItemID", "DocCertsID"
        }
        For Each p In Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance)
            If Not p.CanRead OrElse Not p.CanWrite OrElse skip.Contains(p.Name) Then Continue For
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable(p.Name, p.GetValue(Me), p.Name, False))
        Next
        Return l
    End Function

    Friend Sub Save(conn As SqlConnection, tr As SqlTransaction)
        Dim vars = GetVarList(includePK:=True)
        Dim wherePk = "WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung AND [GdsItemID]=@GdsItemID AND [DocCertsID]=@DocCertsID"
        Dim sqlCheck = $"IF EXISTS(SELECT 1 FROM [{TBL}] {wherePk}) BEGIN {_SqlDyn.BuildUpdateCmd(TBL, vars)} END ELSE BEGIN {_SqlDyn.BuildInsertCmd(TBL, vars)} END"
        Using cmd As New SqlCommand(sqlCheck, conn, tr)
            _SqlDyn.AddParams(cmd, vars)
            cmd.ExecuteNonQuery()
        End Using
    End Sub

    Friend Sub FillFromReader(dr As SqlDataReader)
        Dim props = Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance)
        For Each p In props
            If {"LizenzNr", "OperatorID", "VorgangID", "AnmID", "Kennung", "GdsItemID", "DocCertsID"}.Contains(p.Name) Then Continue For
            If dr.GetSchemaTable().Rows.Cast(Of DataRow)().Any(Function(r) r("ColumnName").ToString() = p.Name) Then
                If dr.IsDBNull(dr.GetOrdinal(p.Name)) Then
                    p.SetValue(Me, Nothing)
                Else
                    p.SetValue(Me, dr(p.Name))
                End If
            End If
        Next
    End Sub
End Class

' ===========================================================
' ================   PACK  (imDHFAnmGdsItemPack)   ==========
' ===========================================================
Public Class cDHF_Import_GdsItemPack
    ' FK/PK
    Public Property LizenzNr As String
    Public Property OperatorID As String
    Public Property VorgangID As String
    Public Property AnmID As String
    Public Property Kennung As String
    Public Property GdsItemID As String
    Public Property PackID As String

    ' Felder
    Public Property Mark As Object
    Public Property Kind As Object
    Public Property Nr As Object
    Public Property Piec As Object

    Private Const TBL As String = "imDHFAnmGdsItemPack"

    Private Function GetVarList(Optional includePK As Boolean = True) As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        Dim l As New List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)
        If includePK Then
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("LizenzNr", LizenzNr, "LizenzNr", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("OperatorID", OperatorID, "OperatorID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("VorgangID", VorgangID, "VorgangID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("AnmID", AnmID, "AnmID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("Kennung", Kennung, "Kennung", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("GdsItemID", GdsItemID, "GdsItemID", True))
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable("PackID", PackID, "PackID", True))
        End If

        Dim skip = New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {
            "LizenzNr", "OperatorID", "VorgangID", "AnmID", "Kennung", "GdsItemID", "PackID"
        }
        For Each p In Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance)
            If Not p.CanRead OrElse Not p.CanWrite OrElse skip.Contains(p.Name) Then Continue For
            l.Add(New VERAG_PROG_ALLGEMEIN.SQLVariable(p.Name, p.GetValue(Me), p.Name, False))
        Next
        Return l
    End Function

    Friend Sub Save(conn As SqlConnection, tr As SqlTransaction)
        Dim vars = GetVarList(includePK:=True)
        Dim wherePk = "WHERE [LizenzNr]=@LizenzNr AND [OperatorID]=@OperatorID AND [VorgangID]=@VorgangID AND [AnmID]=@AnmID AND [Kennung]=@Kennung AND [GdsItemID]=@GdsItemID AND [PackID]=@PackID"
        Dim sqlCheck = $"IF EXISTS(SELECT 1 FROM [{TBL}] {wherePk}) BEGIN {_SqlDyn.BuildUpdateCmd(TBL, vars)} END ELSE BEGIN {_SqlDyn.BuildInsertCmd(TBL, vars)} END"
        Using cmd As New SqlCommand(sqlCheck, conn, tr)
            _SqlDyn.AddParams(cmd, vars)
            cmd.ExecuteNonQuery()
        End Using
    End Sub

    Friend Sub FillFromReader(dr As SqlDataReader)
        Dim props = Me.GetType().GetProperties(BindingFlags.Public Or BindingFlags.Instance)
        For Each p In props
            If {"LizenzNr", "OperatorID", "VorgangID", "AnmID", "Kennung", "GdsItemID", "PackID"}.Contains(p.Name) Then Continue For
            If dr.GetSchemaTable().Rows.Cast(Of DataRow)().Any(Function(r) r("ColumnName").ToString() = p.Name) Then
                If dr.IsDBNull(dr.GetOrdinal(p.Name)) Then
                    p.SetValue(Me, Nothing)
                Else
                    p.SetValue(Me, dr(p.Name))
                End If
            End If
        Next
    End Sub


End Class


' -----------------------------------------------
' Gemeinsame Utilities für dynamische SQLs nach dem Muster aus _BASE
' -----------------------------------------------
Friend Module _SqlDyn
    Friend Function BuildUpdateCmd(tableName As String, vars As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)) As String
        Dim sets As New List(Of String)
        Dim wheres As New List(Of String)
        For Each v In vars
            If v.isPrimaryParam Then
                wheres.Add("[" & v.Text & "] = @" & v.Scalarvariable)
            Else
                sets.Add("[" & v.Text & "] = @" & v.Scalarvariable)
            End If
        Next
        If sets.Count = 0 Then Throw New Exception("Keine Non-PK-Spalten für UPDATE.")
        Return $"UPDATE [{tableName}] SET {String.Join(",", sets)} WHERE {String.Join(" AND ", wheres)}"
    End Function

    Friend Function BuildInsertCmd(tableName As String, vars As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable)) As String
        Dim cols As New List(Of String)
        Dim pars As New List(Of String)
        For Each v In vars
            If Not v.isPrimaryParam Then
                cols.Add("[" & v.Text & "]")
                pars.Add("@" & v.Scalarvariable)
            Else
                ' PK-Spalten oft ebenfalls explizit spaltenseitig – hier mit aufnehmen,
                ' sofern in DB nicht als IDENTITY definiert:
                cols.Add("[" & v.Text & "]")
                pars.Add("@" & v.Scalarvariable)
            End If
        Next
        Return $"INSERT INTO [{tableName}] ({String.Join(",", cols)}) VALUES({String.Join(",", pars)})"
    End Function

    Friend Sub AddParams(cmd As SqlCommand, vars As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable))
        For Each v In vars
            cmd.Parameters.AddWithValue("@" & v.Scalarvariable, If(v.Value, DBNull.Value))
        Next
    End Sub

    Friend Sub DataReaderToObject(dr As SqlDataReader, target As Object, vars As List(Of VERAG_PROG_ALLGEMEIN.SQLVariable))
        Dim t = target.GetType()
        For Each v In vars
            Dim pi = t.GetProperty(v.Text)
            If pi IsNot Nothing AndAlso Not dr.IsDBNull(dr.GetOrdinal(v.Text)) Then
                pi.SetValue(target, dr(v.Text))
            ElseIf pi IsNot Nothing Then
                pi.SetValue(target, Nothing)
            End If
        Next
    End Sub


    Sub test()

        ''        Verwendung(Beispiel)

        ' Kopf anlegen
        Dim imp As New cDHF_Import("LIC", "OP", "VORG", "ANM", "KENN")
        imp.RechnungsNr = "INV-2025-001"
        imp.InvCurr = "EUR"
        imp.InvVal = 12345D

        ' Position hinzufügen
        Dim it = New cDHF_Import_GdsItem() With {
        .GdsItemID = "1",
        .ItNr = 1,
        .ComCd = "85044030",
        .GdsDes = "Power Supply",
        .Net = 12.34D,
        .ItVal = 999D
    }
        ' Doc/Certs
        it.DocCerts.Add(New cDHF_Import_GdsItemDocCerts() With {
        .DocCertsID = "1",
        .DocCd = "N380",
        .DRef = "REF-123",
        .Avail = 1
    })
        ' Packstücke
        it.Packs.Add(New cDHF_Import_GdsItemPack() With {
        .PackID = "1",
        .Kind = "PK",
        .Piec = 3
    })

        imp.GdsItems.Add(it)

        ' Speichern -> speichert Kopf + Position + Unterzeilen in einer Transaktion
        Dim ok = imp.Save()

        ' Laden
        Dim imp2 As New cDHF_Import("S01122", "1", "VORG", "ANM", "KENN")
        ' -> imp2 ist nun inkl. GdsItems, DocCerts und Packs befüllt

    End Sub
End Module
