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 Public Shared Function BuildByMrnInvoices(eza As cDakosyEZA) As cATEZ_Greenpulse_KafkaInvoices If eza Is Nothing Then Throw New ArgumentNullException(NameOf(eza)) ' Zielobjekt NUR für Dokumente Dim dest As New cATEZ_Greenpulse_KafkaInvoices() With { .Documents = New List(Of cATEZ_Greenpulse_KafkaInvoices.DocumentNode)() } ' --- Dokumente aus Unterlagen / Aviso übernehmen --- Dim DY As New cDakosy_Zollanmeldungen(eza.eza_dyaAnmID) If DY IsNot Nothing AndAlso DY.dy_SendungsId IsNot Nothing Then Dim sendungsId As Integer If Integer.TryParse(DY.dy_SendungsId.ToString(), sendungsId) AndAlso sendungsId > 0 Then Dim ANH_LIST As New List(Of cAvisoAnhaenge) cAvisoAnhaenge.LOAD_LIST_BySendung(ANH_LIST, sendungsId) For Each doc In ANH_LIST Select Case doc.anh_Art Case "Rechnung", "eFatura" Dim pfad As String = VERAG_PROG_ALLGEMEIN.cDATENSERVER.GET_PDFPath_BY_DocID(doc.anh_docId) Dim dateiBytes As Byte() = System.IO.File.ReadAllBytes(pfad) Dim d As New cATEZ_Greenpulse_KafkaInvoices.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