Files
ADMIN/DAKOSY_Worker/DAKOSY/ATLAS/EZA/cDakosyEZA_Greenpulse.vb
2025-10-23 11:33:32 +02:00

290 lines
14 KiB
VB.net

Imports System.Globalization
Imports io.konik.zugferd
Imports Newtonsoft.Json
Imports VERAG_PROG_ALLGEMEIN
Public Class cDakosyEZA_Greenpulse
' ==========================================================
' BuildByMrn_DY: Erzeugt Kafka-Objekt aus cDakosyEZA (DY)
' ==========================================================
Public Shared Function BuildByMrn(eza As cDakosyEZA) As cATEZ_Greenpulse_KafkaDecs
If eza Is Nothing Then Throw New ArgumentNullException(NameOf(eza))
' --- Adressen (Heuristik: CN=Importer, CZ=Exporter, DT=Declarant) ---
Dim importer = GuessAddressByType(eza.eza_ADRESSEN, {"CN", "IM", "IMP"})
Dim exporter = GuessAddressByType(eza.eza_ADRESSEN, {"CZ", "EX", "EXP"})
Dim declarant = GuessAddressByType(eza.eza_ADRESSEN, {"DT", "DEC", "ANM", "DECLARANT"})
' --- Rechnungsdaten (Unterlagen N380) ---
Dim inv = If(eza.eza_UNTERLAGEN IsNot Nothing,
eza.eza_UNTERLAGEN.FirstOrDefault(Function(u) SafeStr(u.ezaUl_Art).Equals("N380", StringComparison.OrdinalIgnoreCase) _
AndAlso Not String.IsNullOrWhiteSpace(SafeStr(u.ezaUl_Nummer))),
Nothing)
' --- Kopf/Zielschema ---
Dim dest As New cATEZ_Greenpulse_KafkaDecs With {
.Declaration = New cATEZ_Greenpulse_KafkaDecs.DeclarationNode With {
.DeclarationSourceId = SafeStr(eza.eza_dyaAnmID),
.DeclarationNo = SafeStr(eza.eza_ANR),
.DeclarationDate = ToDateYMD(FirstNonEmpty(eza.eza_Anmeldedatum, eza.eza_Erstellung)),
.RequestedProcedure = SafeStr(eza.eza_VerfahrenBeantragtCode),
.PreviousProcedure = "",
.Goods = New List(Of cATEZ_Greenpulse_KafkaDecs.GoodItem)()
},
.Parties = New cATEZ_Greenpulse_KafkaDecs.PartiesNode With {
.ImporterIdentificationNumber = FirstNonEmptyStr(If(importer IsNot Nothing, importer.ezaAd_TeilnehmerEORI, Nothing),
If(importer IsNot Nothing, importer.ezaAd_AdressCode, Nothing)),
.ExporterIdentificationNumber = FirstNonEmptyStr(If(exporter IsNot Nothing, exporter.ezaAd_TeilnehmerEORI, Nothing),
If(exporter IsNot Nothing, exporter.ezaAd_AdressCode, Nothing)),
.ReportingDeclarantEORINumber = FirstNonEmptyStr(If(declarant IsNot Nothing, declarant.ezaAd_TeilnehmerEORI, Nothing),
If(declarant IsNot Nothing, declarant.ezaAd_AdressCode, Nothing)),
.TypeOfRepresentation = SafeStr(eza.eza_VertretungsVerhaeltnisCode)
},
.Commercial = New cATEZ_Greenpulse_KafkaDecs.CommercialNode With {
.InvoiceNumbers = If(inv IsNot Nothing, SafeStr(inv.ezaUl_Nummer), ""),
.InvoiceDate = If(inv IsNot Nothing, ToDateYMD(inv.ezaUl_DatumAusstellung), "")
},
.ExporterDetails = New cATEZ_Greenpulse_KafkaDecs.ExporterDetailsNode With {
.ExporterTitle = FirstNonEmptyStr(If(exporter IsNot Nothing, exporter.ezaAd_NameFirma1, Nothing),
If(exporter IsNot Nothing, exporter.ezaAd_NameFirma2, Nothing)),
.ExporterEmail = "",
.ExporterPhone = ""
},
.ImporterDetails = New cATEZ_Greenpulse_KafkaDecs.ImporterDetailsNode With {
.ImporterTitle = FirstNonEmptyStr(If(importer IsNot Nothing, importer.ezaAd_NameFirma1, Nothing),
If(importer IsNot Nothing, importer.ezaAd_NameFirma2, Nothing)),
.ImporterEmail = "",
.ImporterPhone = "",
.ImporterCountryCodeOrMemberState = SafeStr(If(importer IsNot Nothing, importer.ezaAd_LandCode, Nothing)),
.ImporterSubdivision = "",
.ImporterCity = SafeStr(If(importer IsNot Nothing, importer.ezaAd_Ort, Nothing)),
.ImporterStreet = MergeStreet(importer),
.ImporterStreetAdditional = SafeStr(If(importer IsNot Nothing, importer.ezaAd_StrasseHausNr2, Nothing)),
.ImporterAddressNumber = "",
.ImporterPostCode = SafeStr(If(importer IsNot Nothing, importer.ezaAd_PLZ, Nothing)),
.ImporterPoBox = "",
.ImporterCoordinateLongitudeX = "",
.ImporterCoordinateLatitudeY = ""
},
.Documents = New List(Of cATEZ_Greenpulse_KafkaDecs.DocumentNode)()
}
' --- Falls EORI vorhanden: spezifisch befüllen (Lookup/Mapping via Helper) ---
Dim impEori As String = SafeStr(If(importer IsNot Nothing, importer.ezaAd_TeilnehmerEORI, Nothing))
If Not String.IsNullOrWhiteSpace(impEori) Then
PopulateImporterByEori(impEori, dest.Parties, dest.ImporterDetails)
End If
Dim expEori As String = SafeStr(If(exporter IsNot Nothing, exporter.ezaAd_TeilnehmerEORI, Nothing))
If Not String.IsNullOrWhiteSpace(expEori) Then
PopulateExporterByEori(expEori, dest.Parties, dest.ExporterDetails)
End If
Dim decEori As String = SafeStr(If(declarant IsNot Nothing, declarant.ezaAd_TeilnehmerEORI, Nothing))
If Not String.IsNullOrWhiteSpace(decEori) Then
PopulateDeclarantByEori(decEori, dest.Parties)
End If
' --- Warenpositionen -> Goods ---
If eza.eza_WARENPOS IsNot Nothing Then
For Each wp In eza.eza_WARENPOS
Dim gi As New cATEZ_Greenpulse_KafkaDecs.GoodItem With {
.CommodityCode = SafeStr(wp.ezaWP_WarennummerEZT),
.OriginCountryCode = SafeStr(wp.ezaWP_UrsprungslandCode),
.NetMass = ToInvariantStr(wp.ezaWP_Eigenmasse),
.TypeOfMeasurementUnit = UnitCodeToKafkaName(FirstNonEmptyStr(wp.ezaWP_WarenMasseinheit1, wp.ezaWP_AHStatMengeMasseinheit, "KGM")),
.SpecialProcedures = New cATEZ_Greenpulse_KafkaDecs.SpecialProceduresNode With {
.MemberStateAutharization = SafeStr(If(importer IsNot Nothing, importer.ezaAd_LandCode, Nothing)),
.DischargeBillWaiver = "",
.Authorisation = FirstNonEmptyStr(wp.ezaWP_Bewilligungsnummer, eza.eza_BewilligungsIDZLAVUV),
.StartTime = "",
.EndTime = "",
.Deadline = ""
}
}
dest.Declaration.Goods.Add(gi)
Next
End If
' --- Previous/Requested Procedure ggf. aus erster Position ziehen ---
Dim wp0 = If(eza.eza_WARENPOS IsNot Nothing, eza.eza_WARENPOS.FirstOrDefault(), Nothing)
If wp0 IsNot Nothing Then
If String.IsNullOrWhiteSpace(dest.Declaration.RequestedProcedure) Then
dest.Declaration.RequestedProcedure = SafeStr(wp0.ezaWP_Zollverfahren)
End If
dest.Declaration.PreviousProcedure = SafeStr(wp0.ezaWP_VerfahrensCodeVorangegangenesVerfahren)
End If
' --- Dokumente aus Unterlagen übernehmen ---
Dim DY As New cDakosy_Zollanmeldungen(eza.eza_dyaAnmID)
If DY IsNot Nothing Then
If DY.dy_SendungsId IsNot Nothing Then
Dim ANH_LIST As New List(Of cAvisoAnhaenge)
cAvisoAnhaenge.LOAD_LIST_BySendung(ANH_LIST, DY.dy_SendungsId)
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)
}
dest.Documents.Add(d)
End Select
Next
End If
End If
Return dest
End Function
' =========================
' Populate-Helper (mit TODO)
' =========================
' Importer: ergänzt Parties.ImporterIdentificationNumber und ImporterDetails anhand EORI
Private Shared Sub PopulateImporterByEori(eori As String,
ByRef parties As cATEZ_Greenpulse_KafkaDecs.PartiesNode,
ByRef details As cATEZ_Greenpulse_KafkaDecs.ImporterDetailsNode)
' Pflicht: EORI in Parties
parties.ImporterIdentificationNumber = eori
Dim AD As VERAG_PROG_ALLGEMEIN.cAdressen = cZOLL_IMPORT.getAdresseFromEORI(eori, "", "", True)
If AD IsNot Nothing Then
details.ImporterTitle = (If(AD.Name_1, "") & " " & If(AD.Name_2, "")).trim
details.ImporterCountryCodeOrMemberState = VERAG_PROG_ALLGEMEIN.cProgramFunctions.getISO2Land(AD.LandKz)
details.ImporterCity = AD.Ort
details.ImporterStreet = AD.Straße
details.ImporterAddressNumber = ""
details.ImporterPostCode = AD.PLZ
details.ImporterEmail = AD.E_Mail
details.ImporterPhone = AD.Telefon
End If
End Sub
' Exporter: ergänzt Parties.ExporterIdentificationNumber und ExporterDetails anhand EORI
Private Shared Sub PopulateExporterByEori(eori As String,
ByRef parties As cATEZ_Greenpulse_KafkaDecs.PartiesNode,
ByRef details As cATEZ_Greenpulse_KafkaDecs.ExporterDetailsNode)
parties.ExporterIdentificationNumber = eori
Dim AD As VERAG_PROG_ALLGEMEIN.cAdressen = cZOLL_IMPORT.getAdresseFromEORI(eori, "", "", True)
If AD IsNot Nothing Then
details.ExporterTitle = (If(AD.Name_1, "") & " " & If(AD.Name_2, "")).trim
'details.exporterCountryCodeOrMemberState = VERAG_PROG_ALLGEMEIN.cProgramFunctions.getISO2Land(AD.LandKz)
'details.exporterCity = AD.Ort
'details.exporterStreet = AD.Straße
'details.exporterAddressNumber = ""
'details.exporterPostCode = AD.PLZ
details.ExporterEmail = AD.E_Mail
details.ExporterPhone = AD.Telefon
End If
End Sub
' Declarant: ergänzt Parties.ReportingDeclarantEORINumber (weitere Daten optional)
Private Shared Sub PopulateDeclarantByEori(eori As String,
ByRef parties As cATEZ_Greenpulse_KafkaDecs.PartiesNode)
parties.ReportingDeclarantEORINumber = eori
' TODO: Optional Stammdaten-Lookup für weitere deklarantenbezogene Daten,
' z. B. Standard-Vertretungsverhältnis, Niederlassungsnummer etc.
' Dim m = PartnerRepo.GetByEori(eori)
' If m IsNot Nothing Then
' ' ggf. parties.TypeOfRepresentation = m.DefaultRepType
' End If
End Sub
' JSON-Wrapper
Public Shared Function BuildJsonByMrn(eza As cDakosyEZA, Optional pretty As Boolean = True) As String
Dim obj = BuildByMrn(eza)
Return obj.ToJson(pretty)
End Function
' -----------------------------
' Helper (ggf. einmalig zentral)
' -----------------------------
Private Shared Function GuessAddressByType(list As List(Of cDakosy_EZA_Adressen), types As IEnumerable(Of String)) As cDakosy_EZA_Adressen
If list Is Nothing Then Return Nothing
Dim setTypes = New HashSet(Of String)(types.Select(Function(t) t.ToUpperInvariant()))
Dim hit = list.FirstOrDefault(Function(a) setTypes.Contains(SafeStr(a.ezaAd_AdressTyp).ToUpperInvariant()))
If hit IsNot Nothing Then Return hit
Dim hitEori = list.FirstOrDefault(Function(a) Not String.IsNullOrWhiteSpace(SafeStr(a.ezaAd_TeilnehmerEORI)))
If hitEori IsNot Nothing Then
Return hitEori
Else
Return list.FirstOrDefault()
End If
End Function
Private Shared Function MergeStreet(addr As cDakosy_EZA_Adressen) As String
If addr Is Nothing Then Return ""
Dim s1 = SafeStr(addr.ezaAd_StrasseHausNr1)
Dim s2 = SafeStr(addr.ezaAd_StrasseHausNr2)
If s2 <> "" Then Return (s1 & " " & s2).Trim()
Return s1
End Function
Private Shared Function UnitCodeToKafkaName(code As String) As String
Select Case SafeStr(code).ToUpperInvariant()
Case "KGM" : Return "Kilograms"
Case "TNE", "T" : Return "Tonnes"
Case "LTR" : Return "Litres"
Case "NAR", "NMB" : Return "Number of items"
Case Else : Return code
End Select
End Function
Private Shared Function ToDateYMD(value As Object) As String
If value Is Nothing Then Return ""
Dim dt As DateTime
If DateTime.TryParse(SafeStr(value), dt) Then
Return dt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
End If
Return ""
End Function
Private Shared Function ToInvariantStr(value As Object) As String
If value Is Nothing Then Return ""
If TypeOf value Is IFormattable Then
Return DirectCast(value, IFormattable).ToString(Nothing, CultureInfo.InvariantCulture)
End If
Return Convert.ToString(value, CultureInfo.InvariantCulture)
End Function
Private Shared Function SafeStr(o As Object) As String
If o Is Nothing Then Return ""
Dim s = Convert.ToString(o).Trim()
Return If(s, "")
End Function
Private Shared Function FirstNonEmpty(ParamArray values() As Object) As Object
For Each v In values
If v IsNot Nothing AndAlso Not String.IsNullOrWhiteSpace(SafeStr(v)) Then
Return v
End If
Next
Return Nothing
End Function
Private Shared Function FirstNonEmptyStr(ParamArray values() As Object) As String
For Each v In values
Dim s = SafeStr(v)
If Not String.IsNullOrWhiteSpace(s) Then Return s
Next
Return ""
End Function
End Class