using Dapper;
using KarleyLibrary.Attributes;
using KarleyLibrary.Erweiterungen;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using WK5.Core.Basis;
using WK5.Core.Basis.Filter;
using WK5.Core.Models;

namespace WK5.Core.Services
{
    public class ArtikelService : IModelService<Artikel, string>
    {
        public async Task<Artikel?> GetAsync(string artikelnummer, FbController2 fbController)
        {


            string baseSelect = @"SELECT
    A.*,
    ARWE_N_BESTAND,
    ARWE_N_BEDARF,
    ARWE_N_BEDARF_FERT,
    ARWE_N_BEDARF_RUEST,
    ARWE_N_BEDARF_FERT_RUEST,
    ARWE_N_BESTAND_EUR,
    ARWE_N_LAGERUMSCHL,
    ARWE_N_LAGERDAUER,
    ARWE_N_LAGERBESTA,
    ARWE_N_GESABEDARF,
    ARWE_N_OFFBESTELL,
    ARWE_D_LETZBEWEG,
    ARWE_D_LAGERDATUM,
    ARWE_N_LAGMENGDAU,
    ARWE_D_INVENTDATUM,
    ARWE_N_INVENTDIFF,
    ARWE_N_INVENTBEST,
    ARWE_N_INVENTMONEY,
    ARWE_N_LETZTEREK,
    ARWE_D_LETZTEREKDATUM,
    ARWE_N_TIEFSTEREK,
    ARWE_N_HOECHSTEREK,
    ARWE_N_DURCHSCHEK,
    ARWE_N_VKDURCHSCHN,
    ARWE_N_KOMMLAGER,
    MWST_N_NR,
    MWST_N_PROZENT,
    MWST_A_BEMERKUNG,
    MWST_D_GUELTIGAB,
    MWST_N_PROZENTALT,
    WK5_ARTI_N_HOEHE_VERPACKUNG,
    WK5_ARTI_N_LAENGE_VERPACKUNG,
    WK5_ARTI_N_BREITE_VERPACKUNG,
    WK5_ARTI_L_ANFRAGEARTIKEL,
    WK5_ARTI_L_ETIKETTENBRIEF,
    WK5_ARTI_L_AUFGABE_TECHNIK,
    WK5_ARTI_A_SUCHBEGRIFF,
    WK5_ARTI_N_KOSTENSTELLE,
    WK5_ARTI_L_SUPPORT_AGREEMENT,
    WK5_ARTI_D_SUPPORT_VALID_UNTIL, 
    WK5_ARTI_N_SUPPORT_DOCID,    
    WK5_ARTI_L_KEIN_TEXT_UPDATE,
    WK5_ARTI_L_KEIN_ZPU,      
    WK5_ARTI_N_PRODUKTGEWICHT,
    WK5_ARTI_N_MUELL_PLASTIK,
    WK5_ARTI_N_MUELL_VERBUNDSTOFF,
    WK5_ARTI_N_MUELL_PAPIER,
    WK5_ARTI_N_MUELL_ALUMINIUM,
    WK5_ARTI_L_HAUPTARTIKEL,
    0 AS ARTI_N_ANZ_BILDER,
    cast((SELECT MAX(ARBE_TIMESTAMP) from artikelbewegung WHERE arbe_a_artinr = arti_a_nr AND ARBE_A_ART NOT IN ('IN')) as TIMESTAMP) AS LETZTEBEWEGUNG,
    WK5_ARTI_N_GEBINDE,
    (SELECT COALESCE(SUM(CHAR_N_EKPREIS * CHAR_N_MENGEOFFEN) / SUM(CHAR_N_MENGEOFFEN),0) FROM CHARGEN WHERE CHAR_A_ARTINR = a.ARTI_A_NR AND CHAR_N_MENGEOFFEN > 0) AS DURCHSCHNITTSEINKAUFSPREIS
    FROM ARTIKEL a
    LEFT OUTER JOIN ARTIKELWERTE w ON w.ARWE_A_NR = a.ARTI_A_NR
    LEFT OUTER JOIN MEHRWERTSTEUER m ON m.MWST_N_NR = a.ARTI_N_MWSTKENNUNG
WHERE";


            string sql = @$"{baseSelect}
UPPER(ARTI_A_NR) = @ARTI_A_NR";


            var artikel = await fbController.SelectRowAsync<Artikel>(sql, new { ARTI_A_NR = artikelnummer.ToUpper() });

            // Muss so kompliziert sein, da teilweise eine Artikelnummer als Herstellernnummer/EAN bei einem Anderen Artikel eingetragen ist
            if (artikel is null)
            {
                // Artikelnummern werden als leere EAN geparsed
                string ean = StringErweiterung.ParseEan(artikelnummer);

                if (!string.IsNullOrWhiteSpace(ean))
                {
                    artikel = await fbController.SelectRowAsync<Artikel>(@$"{baseSelect}
CAST(UPPER(ARTI_A_EAN) AS VARCHAR(30)) = @ARTI_A_EAN", new { ARTI_A_EAN = ean });
                }


                if (artikel is null)
                {
                    artikel = await fbController.SelectRowAsync<Artikel>(@$"{baseSelect}
UPPER(ARTI_A_HERST_NR) = @ARTI_A_HERST_NR", new { ARTI_A_HERST_NR = artikelnummer });
                }
                if (artikel is null)
                {
                    await foreach (KeyValuePair<string, string> replace in Artikel.GetReplaceArtikelnummernAsync(fbController))
                    {
                        if (replace.Key == artikelnummer)
                        {
                            artikel = await fbController.SelectRowAsync<Artikel>($"{baseSelect} UPPER(ARTI_A_NR) = @ARTI_A_NR", new { ARTI_A_NR = replace.Value });
                            if (artikel is not null)
                            {
                                break;
                            }
                        }
                    }
                }

            }


            if (artikel is not null)
            {

                // Bundle Laden
                if (artikel.IstBundle)
                {
                    await LadeBundleAsync(artikel, fbController);
                }

                artikel.Staffelpreise = artikel.GetStaffelpreise();
                artikel.Bilder = await fbController.SelectDataAsync<ArtikelBild>("SELECT * FROM WK5_ARTIKELBILDER WHERE ARBI_A_ARTINR = @ARBI_A_ARTINR", new { ARBI_A_ARTINR = artikel.Artikelnummer });
                artikel.Dokumente = await fbController.SelectDataAsync<ArtikelDokument>("SELECT * FROM WK5_ARTIKELDOKUMENTE WHERE ARDI_A_ARTINR = @ARDI_A_ARTINR", new { ARDI_A_ARTINR = artikel.Artikelnummer });
                artikel.Sonderangebote = await fbController.SelectDataAsync<ArtikelAngebot>("SELECT * FROM WK5_ARTIKEL_ANGEBOTE WHERE UPPER(ARAN_A_ARTINR) = UPPER(@ARAN_A_ARTINR)", new { ARAN_A_ARTINR = artikel.Artikelnummer });
                return artikel;
            }

            return null;
        }
        public async Task CreateAsync(Artikel input, FbController2 fbController)
        {
            if (String.IsNullOrWhiteSpace(input.Artikelnummer))
            {
                throw new ArgumentException("Es muss eine Artikelnummer angegeben werden damit ein Artikel erstellt werden kann");
            }

            string sql = @"INSERT INTO ARTIKEL
(
ARTI_A_NR, 
ARTI_A_BEZ1, ARTI_A_BEZ2, ARTI_A_BEZ3, ARTI_A_BEZ4, ARTI_A_BEZ5, 
ARTI_A_BEZETIKETT, 
ARTI_A_EAN, 
ARTI_A_EINHEIT, 
ARTI_A_ERSATZART, 
ARTI_A_G_RASTER, 
ARTI_A_HERST_NR, ARTI_A_HERSTELLER, 
ARTI_A_LAGER, ARTI_A_LAGER2, ARTI_A_LAGER3, 
ARTI_A_NACHFOLGER, 
ARTI_A_POSBEZEICH, 
ARTI_A_PREISEINHEIT, 
ARTI_A_PREISGRUPPE, 
ARTI_A_PRODLAGER, 
ARTI_A_SELEKTION1, ARTI_A_SELEKTION2, ARTI_A_SELEKTION3, 
ARTI_A_STAFFELWAEHR, 
ARTI_A_UNTERWARENG, 
ARTI_A_URSPRUNGSLAND, 
ARTI_A_VORGAENGER, 
ARTI_A_WARENGRUPPE,
ARTI_B_LANGTEXT, ARTI_B_NOTIZ,
ARTI_D_ERFASSDATUM,
ARTI_L_ABMASSVERWALTUNG, 
ARTI_L_ABVERKAUF, 
ARTI_L_DIENSTLEIST, 
ARTI_L_ERSATZEIL, 
ARTI_L_FAXLISTE, 
ARTI_L_FERTIGUNG, 
ARTI_L_FIXPREIS, 
ARTI_L_FIXVK3, 
ARTI_L_FIXVK4, 
ARTI_L_FIXVK5, 
ARTI_L_INAKT_ABVER, 
ARTI_L_INAKTIV, 
ARTI_L_INTERNET, 
ARTI_L_KAPAZITAET, 
ARTI_L_LAGERFUEHR, 
ARTI_L_LANGTEXT_DR, 
ARTI_L_NICHT_IN_BELEGEN, 
ARTI_L_NORMTEIL, 
ARTI_L_OHNE_DRUCK, 
ARTI_L_OHNE_PROV, 
ARTI_L_PREISLISTE, 
ARTI_L_PRUEFPLAN, 
ARTI_L_RABATTAUSSCHLUSS, 
ARTI_L_RESTEVERWALTUNG, 
ARTI_L_SCHWVERFUEG, 
ARTI_L_SN, 
ARTI_L_SN_ABGANG, 
ARTI_L_SN_EINGANG, 
ARTI_L_STL_VEREDELUNG, 
ARTI_L_VERBRAUCH, 
ARTI_L_VERSCHLEISS,
ARTI_N_BREITE, 
ARTI_N_BRUTTO, 
ARTI_N_COLLI, 
ARTI_N_EK, 
ARTI_N_ERLOESKONTO, 
ARTI_N_FLAECHE, 
ARTI_N_GEWICHT, 
ARTI_N_HOEHE, 
ARTI_N_LAENGE, 
ARTI_N_LASTUSER, 
ARTI_N_MAXBESTAND, 
ARTI_N_MAXRABATT, 
ARTI_N_MINBESTAND, 
ARTI_N_MIND_VK,
ARTI_N_MINDAUFSCHL, 
ARTI_N_MWSTKENNUNG, 
ARTI_N_PREISEINHEITFAKTOR, 
ARTI_N_RUECKL_ADR, 
ARTI_N_STAERKE, 
ARTI_N_STAFFELM1, ARTI_N_STAFFELM2, ARTI_N_STAFFELM3, ARTI_N_STAFFELM4, ARTI_N_STAFFELM5,
ARTI_N_STAFFELR1, ARTI_N_STAFFELR2, ARTI_N_STAFFELR3, ARTI_N_STAFFELR4, ARTI_N_STAFFELR5, 
ARTI_N_STAFFELP1, ARTI_N_STAFFELP2, ARTI_N_STAFFELP3, ARTI_N_STAFFELP4, ARTI_N_STAFFELP5, 
ARTI_N_VK1, ARTI_N_VK1BRUTTO, ARTI_N_VK2, ARTI_N_VK3, ARTI_N_VK4, ARTI_N_VK5, 
ARTI_N_WO_KAPAZITAET, 
ARTI_N_ZOLLTARIF, 
WK5_ARTI_N_HOEHE_VERPACKUNG, WK5_ARTI_N_LAENGE_VERPACKUNG, WK5_ARTI_N_BREITE_VERPACKUNG,
WK5_ARTI_L_ANFRAGEARTIKEL, 
WK5_ARTI_L_ETIKETTENBRIEF,
WK5_ARTI_L_AUFGABE_TECHNIK, 
WK5_ARTI_A_SUCHBEGRIFF, 
WK5_ARTI_N_KOSTENSTELLE,
WK5_ARTI_L_SUPPORT_AGREEMENT,
WK5_ARTI_D_SUPPORT_VALID_UNTIL,
WK5_ARTI_N_SUPPORT_DOCID,
WK5_ARTI_L_KEIN_TEXT_UPDATE,
WK5_ARTI_L_KEIN_ZPU,
WK5_ARTI_N_PRODUKTGEWICHT,
WK5_ARTI_N_WICHTIGKEIT,
WK5_ARTI_N_MUELL_PLASTIK,
WK5_ARTI_N_MUELL_VERBUNDSTOFF,
WK5_ARTI_N_MUELL_PAPIER,
WK5_ARTI_N_MUELL_ALUMINIUM,
WK5_ARTI_L_HAUPTARTIKEL,
WK5_ARTI_N_VIRT_LAGER,
WK5_ARTI_N_GEBINDE,
WK5_ARTI_A_HINWEIS,
WK5_ARTI_N_ANGEBOTVORLAGE,
ARTI_N_WARTUNGSINTERVALL,
ARTI_B_WARTUNGSTEXT,
ARTI_N_PREISOPTION_ONLINE,
ARTI_L_MIETE,
ARTI_B_PACKTEXT,
WK5_ARTI_L_KEINE_ELEKTRONIK
) 
VALUES
(
@ARTI_A_NR,
@ARTI_A_BEZ1,
@ARTI_A_BEZ2,
@ARTI_A_BEZ3,
@ARTI_A_BEZ4,
@ARTI_A_BEZ5,
@ARTI_A_BEZETIKETT,
@ARTI_A_EAN,
@ARTI_A_EINHEIT,
@ARTI_A_ERSATZART,
@ARTI_A_G_RASTER,
@ARTI_A_HERST_NR,
@ARTI_A_HERSTELLER,
@ARTI_A_LAGER,
@ARTI_A_LAGER2,
@ARTI_A_LAGER3,
@ARTI_A_NACHFOLGER,
@ARTI_A_POSBEZEICH,
@ARTI_A_PREISEINHEIT,
@ARTI_A_PREISGRUPPE,
@ARTI_A_PRODLAGER,
@ARTI_A_SELEKTION1,
@ARTI_A_SELEKTION2,
@ARTI_A_SELEKTION3,
@ARTI_A_STAFFELWAEHR,
@ARTI_A_UNTERWARENG,
@ARTI_A_URSPRUNGSLAND,
@ARTI_A_VORGAENGER,
@ARTI_A_WARENGRUPPE,
@ARTI_B_LANGTEXT,
@ARTI_B_NOTIZ,
@ARTI_D_ERFASSDATUM,
@ARTI_L_ABMASSVERWALTUNG,
@ARTI_L_ABVERKAUF,
@ARTI_L_DIENSTLEIST,
@ARTI_L_ERSATZEIL,
@ARTI_L_FAXLISTE,
@ARTI_L_FERTIGUNG,
@ARTI_L_FIXPREIS,
@ARTI_L_FIXVK3,
@ARTI_L_FIXVK4,
@ARTI_L_FIXVK5,
@ARTI_L_INAKT_ABVER,
@ARTI_L_INAKTIV,
@ARTI_L_INTERNET,
@ARTI_L_KAPAZITAET,
@ARTI_L_LAGERFUEHR,
@ARTI_L_LANGTEXT_DR,
@ARTI_L_NICHT_IN_BELEGEN,
@ARTI_L_NORMTEIL,
@ARTI_L_OHNE_DRUCK,
@ARTI_L_OHNE_PROV,
@ARTI_L_PREISLISTE,
@ARTI_L_PRUEFPLAN,
@ARTI_L_RABATTAUSSCHLUSS,
@ARTI_L_RESTEVERWALTUNG,
@ARTI_L_SCHWVERFUEG,
@ARTI_L_SN,
@ARTI_L_SN_ABGANG,
@ARTI_L_SN_EINGANG,
@ARTI_L_STL_VEREDELUNG,
@ARTI_L_VERBRAUCH,
@ARTI_L_VERSCHLEISS,
@ARTI_N_BREITE,
@ARTI_N_BRUTTO,
@ARTI_N_COLLI,
@ARTI_N_EK,
@ARTI_N_ERLOESKONTO,
@ARTI_N_FLAECHE,
@ARTI_N_GEWICHT,
@ARTI_N_HOEHE,
@ARTI_N_LAENGE,
@ARTI_N_LASTUSER,
@ARTI_N_MAXBESTAND,
@ARTI_N_MAXRABATT,
@ARTI_N_MINBESTAND,
@ARTI_N_MIND_VK,
@ARTI_N_MINDAUFSCHL,
@ARTI_N_MWSTKENNUNG,
@ARTI_N_PREISEINHEITFAKTOR,
@ARTI_N_RUECKL_ADR,
@ARTI_N_STAERKE,
@ARTI_N_STAFFELM1,
@ARTI_N_STAFFELM2,
@ARTI_N_STAFFELM3,
@ARTI_N_STAFFELM4,
@ARTI_N_STAFFELM5,
@ARTI_N_STAFFELR1,
@ARTI_N_STAFFELR2,
@ARTI_N_STAFFELR3,
@ARTI_N_STAFFELR4,
@ARTI_N_STAFFELR5,
@ARTI_N_STAFFELP1,
@ARTI_N_STAFFELP2,
@ARTI_N_STAFFELP3,
@ARTI_N_STAFFELP4,
@ARTI_N_STAFFELP5,
@ARTI_N_VK1,
@ARTI_N_VK1BRUTTO,
@ARTI_N_VK2,
@ARTI_N_VK3,
@ARTI_N_VK4,
@ARTI_N_VK5,
@ARTI_N_WO_KAPAZITAET,
@ARTI_N_ZOLLTARIF,
@WK5_ARTI_N_HOEHE_VERPACKUNG, @WK5_ARTI_N_LAENGE_VERPACKUNG, @WK5_ARTI_N_BREITE_VERPACKUNG,
@WK5_ARTI_L_ANFRAGEARTIKEL,
@WK5_ARTI_L_ETIKETTENBRIEF,
@WK5_ARTI_L_AUFGABE_TECHNIK,
@WK5_ARTI_A_SUCHBEGRIFF,
@WK5_ARTI_N_KOSTENSTELLE,
@WK5_ARTI_L_SUPPORT_AGREEMENT,
@WK5_ARTI_D_SUPPORT_VALID_UNTIL,
@WK5_ARTI_N_SUPPORT_DOCID,
@WK5_ARTI_L_KEIN_TEXT_UPDATE,
@WK5_ARTI_L_KEIN_ZPU,
@WK5_ARTI_N_PRODUKTGEWICHT,
@WK5_ARTI_N_WICHTIGKEIT,
@WK5_ARTI_N_MUELL_PLASTIK,
@WK5_ARTI_N_MUELL_VERBUNDSTOFF,
@WK5_ARTI_N_MUELL_PAPIER,
@WK5_ARTI_N_MUELL_ALUMINIUM,
@WK5_ARTI_L_HAUPTARTIKEL,
@WK5_ARTI_N_VIRT_LAGER,
@WK5_ARTI_N_GEBINDE,
@WK5_ARTI_A_HINWEIS,
@WK5_ARTI_N_ANGEBOTVORLAGE,
@ARTI_N_WARTUNGSINTERVALL,
@ARTI_B_WARTUNGSTEXT,
@ARTI_N_PREISOPTION_ONLINE,
@ARTI_L_MIETE,
@ARTI_B_PACKTEXT,
@WK5_ARTI_L_KEINE_ELEKTRONIK
)";

            fbController.AddParameter("@ARTI_A_NR", input.Artikelnummer);
            fbController.AddParameter("@ARTI_A_BEZ1", input.Bezeichnung1);
            fbController.AddParameter("@ARTI_A_BEZ2", input.Bezeichnung2);
            fbController.AddParameter("@ARTI_A_BEZ3", input.Bezeichnung3);
            fbController.AddParameter("@ARTI_A_BEZ4", input.Bezeichnung4);
            fbController.AddParameter("@ARTI_A_BEZ5", input.Bezeichnung5);
            fbController.AddParameter("@ARTI_A_BEZETIKETT", input.ARTI_A_BEZETIKETT);
            fbController.AddParameter("@ARTI_A_EAN", input.ARTI_A_EAN);
            fbController.AddParameter("@ARTI_A_EINHEIT", input.ARTI_A_EINHEIT);
            fbController.AddParameter("@ARTI_A_ERSATZART", input.ARTI_A_ERSATZART);
            fbController.AddParameter("@ARTI_A_G_RASTER", input.ARTI_A_G_RASTER);
            fbController.AddParameter("@ARTI_A_HERST_NR", input.Herstellernummer);
            fbController.AddParameter("@ARTI_A_HERSTELLER", input.Hersteller);
            fbController.AddParameter("@ARTI_A_LAGER", input.Lagerplatz);
            fbController.AddParameter("@ARTI_A_LAGER2", input.ARTI_A_LAGER2);
            fbController.AddParameter("@ARTI_A_LAGER3", input.ARTI_A_LAGER3);
            fbController.AddParameter("@ARTI_A_NACHFOLGER", input.ARTI_A_NACHFOLGER);
            fbController.AddParameter("@ARTI_A_POSBEZEICH", input.ARTI_A_POSBEZEICH);
            fbController.AddParameter("@ARTI_A_PREISEINHEIT", input.ARTI_A_PREISEINHEIT);
            fbController.AddParameter("@ARTI_A_PREISGRUPPE", input.Preisgruppe);
            fbController.AddParameter("@ARTI_A_PRODLAGER", input.ARTI_A_PRODLAGER);
            fbController.AddParameter("@ARTI_A_SELEKTION1", input.Selektionsmerkmal1);
            fbController.AddParameter("@ARTI_A_SELEKTION2", input.Selektionsmerkmal2);
            fbController.AddParameter("@ARTI_A_SELEKTION3", input.Selektionsmerkmal3);
            fbController.AddParameter("@ARTI_A_STAFFELWAEHR", input.ARTI_A_STAFFELWAEHR);
            fbController.AddParameter("@ARTI_A_UNTERWARENG", input.Unterwarengruppe);
            fbController.AddParameter("@ARTI_A_URSPRUNGSLAND", input.ARTI_A_URSPRUNGSLAND);
            fbController.AddParameter("@ARTI_A_VORGAENGER", input.ARTI_A_VORGAENGER);
            fbController.AddParameter("@ARTI_A_WARENGRUPPE", input.Warengruppe);
            fbController.AddParameter("@ARTI_B_LANGTEXT", input.Langtext);
            fbController.AddParameter("@ARTI_B_NOTIZ", input.Notiz);
            fbController.AddParameter("@ARTI_D_ERFASSDATUM", DateTime.Now);
            fbController.AddParameter("@ARTI_L_ABMASSVERWALTUNG", input.ARTI_L_ABMASSVERWALTUNG);
            fbController.AddParameter("@ARTI_L_ABVERKAUF", input.ARTI_L_ABVERKAUF);
            fbController.AddParameter("@ARTI_L_DIENSTLEIST", input.ARTI_L_DIENSTLEIST);
            fbController.AddParameter("@ARTI_L_ERSATZEIL", input.ARTI_L_ERSATZEIL);
            fbController.AddParameter("@ARTI_L_FAXLISTE", input.ARTI_L_FAXLISTE);
            fbController.AddParameter("@ARTI_L_FERTIGUNG", input.ARTI_L_FERTIGUNG);
            fbController.AddParameter("@ARTI_L_FIXPREIS", input.ARTI_L_FIXPREIS);
            fbController.AddParameter("@ARTI_L_FIXVK3", input.ARTI_L_FIXVK3);
            fbController.AddParameter("@ARTI_L_FIXVK4", input.ARTI_L_FIXVK4);
            fbController.AddParameter("@ARTI_L_FIXVK5", input.ARTI_L_FIXVK5);
            fbController.AddParameter("@ARTI_L_INAKT_ABVER", input.ARTI_L_INAKT_ABVER);
            fbController.AddParameter("@ARTI_L_INAKTIV", input.ARTI_L_INAKTIV);
            fbController.AddParameter("@ARTI_L_INTERNET", input.ARTI_L_INTERNET);
            fbController.AddParameter("@ARTI_L_KAPAZITAET", input.ARTI_L_KAPAZITAET);
            fbController.AddParameter("@ARTI_L_LAGERFUEHR", input.ARTI_L_LAGERFUEHR);
            fbController.AddParameter("@ARTI_L_LANGTEXT_DR", input.ARTI_L_LANGTEXT_DR);
            fbController.AddParameter("@ARTI_L_NICHT_IN_BELEGEN", input.ARTI_L_NICHT_IN_BELEGEN);
            fbController.AddParameter("@ARTI_L_NORMTEIL", input.ARTI_L_NORMTEIL);
            fbController.AddParameter("@ARTI_L_OHNE_DRUCK", input.ARTI_L_OHNE_DRUCK);
            fbController.AddParameter("@ARTI_L_OHNE_PROV", input.ARTI_L_OHNE_PROV);
            fbController.AddParameter("@ARTI_L_PREISLISTE", input.ARTI_L_PREISLISTE);
            fbController.AddParameter("@ARTI_L_PRUEFPLAN", input.ARTI_L_PRUEFPLAN);
            fbController.AddParameter("@ARTI_L_RABATTAUSSCHLUSS", input.ARTI_L_RABATTAUSSCHLUSS);
            fbController.AddParameter("@ARTI_L_RESTEVERWALTUNG", input.ARTI_L_RESTEVERWALTUNG);
            fbController.AddParameter("@ARTI_L_SCHWVERFUEG", input.ARTI_L_SCHWVERFUEG);
            fbController.AddParameter("@ARTI_L_SN", input.ARTI_L_SN);
            fbController.AddParameter("@ARTI_L_SN_ABGANG", input.ARTI_L_SN_ABGANG);
            fbController.AddParameter("@ARTI_L_SN_EINGANG", input.ARTI_L_SN_EINGANG);
            fbController.AddParameter("@ARTI_L_STL_VEREDELUNG", input.ARTI_L_STL_VEREDELUNG);
            fbController.AddParameter("@ARTI_L_VERBRAUCH", input.ARTI_L_VERBRAUCH);
            fbController.AddParameter("@ARTI_L_VERSCHLEISS", input.ARTI_L_VERSCHLEISS);
            fbController.AddParameter("@ARTI_N_BREITE", input.Breite);
            fbController.AddParameter("@ARTI_N_BRUTTO", input.ARTI_N_BRUTTO);
            fbController.AddParameter("@ARTI_N_COLLI", input.ARTI_N_COLLI);
            fbController.AddParameter("@ARTI_N_EK", input.ARTI_N_EK);
            fbController.AddParameter("@ARTI_N_ERLOESKONTO", input.ARTI_N_ERLOESKONTO);
            fbController.AddParameter("@ARTI_N_FLAECHE", input.ARTI_N_FLAECHE);
            fbController.AddParameter("@ARTI_N_GEWICHT", input.ARTI_N_GEWICHT);
            fbController.AddParameter("@ARTI_N_HOEHE", input.ARTI_N_HOEHE);
            fbController.AddParameter("@ARTI_N_LAENGE", input.ARTI_N_LAENGE);
            fbController.AddParameter("@ARTI_N_LASTUSER", input.ARTI_N_LASTUSER);
            fbController.AddParameter("@ARTI_N_MAXBESTAND", input.ARTI_N_MAXBESTAND);
            fbController.AddParameter("@ARTI_N_MAXRABATT", input.ARTI_N_MAXRABATT);
            fbController.AddParameter("@ARTI_N_MINBESTAND", input.Mindestbestand);
            fbController.AddParameter("@ARTI_N_MIND_VK", input.ARTI_N_MIND_VK);
            fbController.AddParameter("@ARTI_N_MINDAUFSCHL", input.ARTI_N_MINDAUFSCHL);
            fbController.AddParameter("@ARTI_N_MWSTKENNUNG", input.ARTI_N_MWSTKENNUNG);
            fbController.AddParameter("@ARTI_N_PREISEINHEITFAKTOR", input.ARTI_N_PREISEINHEITFAKTOR);
            fbController.AddParameter("@ARTI_N_RUECKL_ADR", input.ARTI_N_RUECKL_ADR);
            fbController.AddParameter("@ARTI_N_STAERKE", input.ARTI_N_STAERKE);
            fbController.AddParameter("@ARTI_N_STAFFELM1", input.ARTI_N_STAFFELM1);
            fbController.AddParameter("@ARTI_N_STAFFELM2", input.ARTI_N_STAFFELM2);
            fbController.AddParameter("@ARTI_N_STAFFELM3", input.ARTI_N_STAFFELM3);
            fbController.AddParameter("@ARTI_N_STAFFELM4", input.ARTI_N_STAFFELM4);
            fbController.AddParameter("@ARTI_N_STAFFELM5", input.ARTI_N_STAFFELM5);
            fbController.AddParameter("@ARTI_N_STAFFELR1", input.ARTI_N_STAFFELR1);
            fbController.AddParameter("@ARTI_N_STAFFELR2", input.ARTI_N_STAFFELR2);
            fbController.AddParameter("@ARTI_N_STAFFELR3", input.ARTI_N_STAFFELR3);
            fbController.AddParameter("@ARTI_N_STAFFELR4", input.ARTI_N_STAFFELR4);
            fbController.AddParameter("@ARTI_N_STAFFELR5", input.ARTI_N_STAFFELR5);
            fbController.AddParameter("@ARTI_N_STAFFELP1", 0); // Es gibt nur Rabatte, die Preise werden onfly errechnet
            fbController.AddParameter("@ARTI_N_STAFFELP2", 0); // Es gibt nur Rabatte, die Preise werden onfly errechnet
            fbController.AddParameter("@ARTI_N_STAFFELP3", 0); // Es gibt nur Rabatte, die Preise werden onfly errechnet
            fbController.AddParameter("@ARTI_N_STAFFELP4", 0); // Es gibt nur Rabatte, die Preise werden onfly errechnet
            fbController.AddParameter("@ARTI_N_STAFFELP5", 0); // Es gibt nur Rabatte, die Preise werden onfly errechnet
            fbController.AddParameter("@ARTI_N_VK1", input.ARTI_N_VK1);
            fbController.AddParameter("@ARTI_N_VK1BRUTTO", input.ARTI_N_VK1BRUTTO);
            fbController.AddParameter("@ARTI_N_VK2", input.ARTI_N_VK2);
            fbController.AddParameter("@ARTI_N_VK3", input.ARTI_N_VK3);
            fbController.AddParameter("@ARTI_N_VK4", input.ARTI_N_VK4);
            fbController.AddParameter("@ARTI_N_VK5", input.ARTI_N_VK5);
            fbController.AddParameter("@ARTI_N_WO_KAPAZITAET", input.ARTI_N_WO_KAPAZITAET);
            fbController.AddParameter("@ARTI_N_ZOLLTARIF", input.ZolltarifId);
            fbController.AddParameter("@WK5_ARTI_N_HOEHE_VERPACKUNG", input.WK5_ARTI_N_HOEHE_VERPACKUNG);
            fbController.AddParameter("@WK5_ARTI_N_LAENGE_VERPACKUNG", input.WK5_ARTI_N_LAENGE_VERPACKUNG);
            fbController.AddParameter("@WK5_ARTI_N_BREITE_VERPACKUNG", input.WK5_ARTI_N_BREITE_VERPACKUNG);
            fbController.AddParameter("@WK5_ARTI_L_ANFRAGEARTIKEL", input.WK5_ARTI_L_ANFRAGEARTIKEL);
            fbController.AddParameter("@WK5_ARTI_L_ETIKETTENBRIEF", input.WK5_ARTI_L_ETIKETTENBRIEF);
            fbController.AddParameter("@WK5_ARTI_L_AUFGABE_TECHNIK", input.WK5_ARTI_L_AUFGABE_TECHNIK);
            fbController.AddParameter("@WK5_ARTI_A_SUCHBEGRIFF", input.WK5_ARTI_A_SUCHBEGRIFF);
            fbController.AddParameter("@WK5_ARTI_N_KOSTENSTELLE", input.WK5_ARTI_N_KOSTENSTELLE);
            fbController.AddParameter("@WK5_ARTI_L_SUPPORT_AGREEMENT", input.WK5_ARTI_L_SUPPORT_AGREEMENT);
            fbController.AddParameter("@WK5_ARTI_D_SUPPORT_VALID_UNTIL", input.WK5_ARTI_D_SUPPORT_VALID_UNTIL);
            fbController.AddParameter("@WK5_ARTI_N_SUPPORT_DOCID", input.WK5_ARTI_N_SUPPORT_DOCID);
            fbController.AddParameter("@WK5_ARTI_L_KEIN_TEXT_UPDATE", input.WK5_ARTI_L_KEIN_TEXT_UPDATE);
            fbController.AddParameter("@WK5_ARTI_L_KEIN_ZPU", input.WK5_ARTI_L_KEIN_ZPU);
            fbController.AddParameter("@WK5_ARTI_N_PRODUKTGEWICHT", input.WK5_ARTI_N_PRODUKTGEWICHT);
            fbController.AddParameter("@WK5_ARTI_N_WICHTIGKEIT", input.WK5_ARTI_N_WICHTIGKEIT);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_PLASTIK", input.WK5_ARTI_N_MUELL_PLASTIK);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_VERBUNDSTOFF", input.WK5_ARTI_N_MUELL_VERBUNDSTOFF);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_PAPIER", input.WK5_ARTI_N_MUELL_PAPIER);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_ALUMINIUM", input.WK5_ARTI_N_MUELL_ALUMINIUM);
            fbController.AddParameter("@WK5_ARTI_L_HAUPTARTIKEL", input.WK5_ARTI_L_HAUPTARTIKEL);
            fbController.AddParameter("@WK5_ARTI_N_VIRT_LAGER", input.WK5_ARTI_N_VIRT_LAGER);
            fbController.AddParameter("@WK5_ARTI_N_GEBINDE", input.WK5_ARTI_N_GEBINDE);
            fbController.AddParameter("@WK5_ARTI_A_HINWEIS", input.WK5_ARTI_A_HINWEIS);
            fbController.AddParameter("@WK5_ARTI_N_ANGEBOTVORLAGE", input.AngebotsnummerVorlage);
            fbController.AddParameter("@ARTI_N_WARTUNGSINTERVALL", input.Wartungsintervall);
            fbController.AddParameter("@ARTI_B_WARTUNGSTEXT", input.WartungsText);
            fbController.AddParameter("@ARTI_N_PREISOPTION_ONLINE", input.PreisoptionOnline);
            fbController.AddParameter("@ARTI_L_MIETE", input.ARTI_L_MIETE);
            fbController.AddParameter("@ARTI_B_PACKTEXT", input.ARTI_B_PACKTEXT);
            fbController.AddParameter("@WK5_ARTI_L_KEINE_ELEKTRONIK", input.WK5_ARTI_L_KEINE_ELEKTRONIK);
            await fbController.QueryAsync(sql);
        }
        public async Task UpdateAsync(Artikel input, FbController2 fbController)
        {

            input.Staffelpreise.Clean();
            input.Staffelpreise.Sort();
            for (int i = 0; i < input.Staffelpreise.MaxAnzahl; i++)
            {
                Staffelpreis? preis = input.Staffelpreise.Get(i);
                switch (i)
                {
                    case 0:
                        {
                            input.ARTI_N_STAFFELP1 = input.ARTI_N_VK1;
                            input.ARTI_N_STAFFELM1 = preis?.Menge ?? 0;
                            input.ARTI_N_STAFFELR1 = preis?.Rabatt ?? 0;
                        }
                        break;
                    case 1:
                        {
                            input.ARTI_N_STAFFELP2 = input.ARTI_N_VK1;
                            input.ARTI_N_STAFFELM2 = preis?.Menge ?? 0;
                            input.ARTI_N_STAFFELR2 = preis?.Rabatt ?? 0;
                        }
                        break;
                    case 2:
                        {
                            input.ARTI_N_STAFFELP3 = input.ARTI_N_VK1;
                            input.ARTI_N_STAFFELM3 = preis?.Menge ?? 0;
                            input.ARTI_N_STAFFELR3 = preis?.Rabatt ?? 0;
                        }
                        break;
                    case 3:
                        {
                            input.ARTI_N_STAFFELP4 = input.ARTI_N_VK1;
                            input.ARTI_N_STAFFELM4 = preis?.Menge ?? 0;
                            input.ARTI_N_STAFFELR4 = preis?.Rabatt ?? 0;
                        }
                        break;
                    case 4:
                        {
                            input.ARTI_N_STAFFELP5 = input.ARTI_N_VK1;
                            input.ARTI_N_STAFFELM5 = preis?.Menge ?? 0;
                            input.ARTI_N_STAFFELR5 = preis?.Rabatt ?? 0;
                        }
                        break;
                    default:
                        break;
                }
            }
            string sql = @"UPDATE ARTIKEL SET 
ARTI_A_BEZ1 = @ARTI_A_BEZ1,
ARTI_A_BEZ2 = @ARTI_A_BEZ2,
ARTI_A_BEZ3 = @ARTI_A_BEZ3,
ARTI_A_BEZ4 = @ARTI_A_BEZ4,
ARTI_A_BEZ5 = @ARTI_A_BEZ5,
ARTI_A_BEZETIKETT = @ARTI_A_BEZETIKETT,
ARTI_A_EAN = @ARTI_A_EAN,
ARTI_A_EINHEIT = @ARTI_A_EINHEIT,
ARTI_A_ERSATZART = @ARTI_A_ERSATZART,
ARTI_A_G_RASTER = @ARTI_A_G_RASTER,
ARTI_A_HERST_NR = @ARTI_A_HERST_NR,
ARTI_A_HERSTELLER = @ARTI_A_HERSTELLER,
ARTI_A_LAGER = @ARTI_A_LAGER,
ARTI_A_LAGER2 = @ARTI_A_LAGER2,
ARTI_A_LAGER3 = @ARTI_A_LAGER3,
ARTI_A_NACHFOLGER = @ARTI_A_NACHFOLGER,
ARTI_A_POSBEZEICH = @ARTI_A_POSBEZEICH,
ARTI_A_PREISEINHEIT = @ARTI_A_PREISEINHEIT,
ARTI_A_PREISGRUPPE = @ARTI_A_PREISGRUPPE,
ARTI_A_PRODLAGER = @ARTI_A_PRODLAGER,
ARTI_A_SELEKTION1 = @ARTI_A_SELEKTION1,
ARTI_A_SELEKTION2 = @ARTI_A_SELEKTION2,
ARTI_A_SELEKTION3 = @ARTI_A_SELEKTION3,
ARTI_A_STAFFELWAEHR = @ARTI_A_STAFFELWAEHR,
ARTI_A_UNTERWARENG = @ARTI_A_UNTERWARENG,
ARTI_A_URSPRUNGSLAND = @ARTI_A_URSPRUNGSLAND,
ARTI_A_VORGAENGER = @ARTI_A_VORGAENGER,
ARTI_A_WARENGRUPPE = @ARTI_A_WARENGRUPPE,
ARTI_B_LANGTEXT = @ARTI_B_LANGTEXT,
ARTI_B_NOTIZ = @ARTI_B_NOTIZ,
ARTI_D_ERFASSDATUM = @ARTI_D_ERFASSDATUM,
ARTI_L_ABMASSVERWALTUNG = @ARTI_L_ABMASSVERWALTUNG,
ARTI_L_ABVERKAUF = @ARTI_L_ABVERKAUF,
ARTI_L_DIENSTLEIST = @ARTI_L_DIENSTLEIST,
ARTI_L_ERSATZEIL = @ARTI_L_ERSATZEIL,
ARTI_L_FAXLISTE = @ARTI_L_FAXLISTE,
ARTI_L_FERTIGUNG = @ARTI_L_FERTIGUNG,
ARTI_L_FIXPREIS = @ARTI_L_FIXPREIS,
ARTI_L_FIXVK3 = @ARTI_L_FIXVK3,
ARTI_L_FIXVK4 = @ARTI_L_FIXVK4,
ARTI_L_FIXVK5 = @ARTI_L_FIXVK5,
ARTI_L_INAKT_ABVER = @ARTI_L_INAKT_ABVER,
ARTI_L_INAKTIV = @ARTI_L_INAKTIV,
ARTI_L_INTERNET = @ARTI_L_INTERNET,
ARTI_L_KAPAZITAET = @ARTI_L_KAPAZITAET,
ARTI_L_LAGERFUEHR = @ARTI_L_LAGERFUEHR,
ARTI_L_LANGTEXT_DR = @ARTI_L_LANGTEXT_DR,
ARTI_L_NICHT_IN_BELEGEN = @ARTI_L_NICHT_IN_BELEGEN,
ARTI_L_NORMTEIL = @ARTI_L_NORMTEIL,
ARTI_L_OHNE_DRUCK = @ARTI_L_OHNE_DRUCK,
ARTI_L_OHNE_PROV = @ARTI_L_OHNE_PROV,
ARTI_L_PREISLISTE = @ARTI_L_PREISLISTE,
ARTI_L_PRUEFPLAN = @ARTI_L_PRUEFPLAN,
ARTI_L_RABATTAUSSCHLUSS = @ARTI_L_RABATTAUSSCHLUSS,
ARTI_L_RESTEVERWALTUNG = @ARTI_L_RESTEVERWALTUNG,
ARTI_L_SCHWVERFUEG = @ARTI_L_SCHWVERFUEG,
ARTI_L_SN = @ARTI_L_SN,
ARTI_L_SN_ABGANG = @ARTI_L_SN_ABGANG,
ARTI_L_SN_EINGANG = @ARTI_L_SN_EINGANG,
ARTI_L_STL_VEREDELUNG = @ARTI_L_STL_VEREDELUNG,
ARTI_L_VERBRAUCH = @ARTI_L_VERBRAUCH,
ARTI_L_VERSCHLEISS = @ARTI_L_VERSCHLEISS,
ARTI_N_BREITE = @ARTI_N_BREITE,
ARTI_N_BRUTTO = @ARTI_N_BRUTTO,
ARTI_N_COLLI = @ARTI_N_COLLI,
ARTI_N_EK = @ARTI_N_EK,
ARTI_N_ERLOESKONTO = @ARTI_N_ERLOESKONTO,
ARTI_N_FLAECHE = @ARTI_N_FLAECHE,
ARTI_N_GEWICHT = @ARTI_N_GEWICHT,
ARTI_N_HOEHE = @ARTI_N_HOEHE,
ARTI_N_LAENGE = @ARTI_N_LAENGE,
ARTI_N_LASTUSER = @ARTI_N_LASTUSER,
ARTI_N_MAXBESTAND = @ARTI_N_MAXBESTAND,
ARTI_N_MAXRABATT = @ARTI_N_MAXRABATT,
ARTI_N_MINBESTAND = @ARTI_N_MINBESTAND,
ARTI_N_MIND_VK = @ARTI_N_MIND_VK,
ARTI_N_MINDAUFSCHL = @ARTI_N_MINDAUFSCHL,
ARTI_N_MWSTKENNUNG = @ARTI_N_MWSTKENNUNG,
ARTI_N_PREISEINHEITFAKTOR = @ARTI_N_PREISEINHEITFAKTOR,
ARTI_N_RUECKL_ADR = @ARTI_N_RUECKL_ADR,
ARTI_N_STAERKE = @ARTI_N_STAERKE,
ARTI_N_STAFFELM1 = @ARTI_N_STAFFELM1,
ARTI_N_STAFFELM2 = @ARTI_N_STAFFELM2,
ARTI_N_STAFFELM3 = @ARTI_N_STAFFELM3,
ARTI_N_STAFFELM4 = @ARTI_N_STAFFELM4,
ARTI_N_STAFFELM5 = @ARTI_N_STAFFELM5,
ARTI_N_STAFFELR1 = @ARTI_N_STAFFELR1,
ARTI_N_STAFFELR2 = @ARTI_N_STAFFELR2,
ARTI_N_STAFFELR3 = @ARTI_N_STAFFELR3,
ARTI_N_STAFFELR4 = @ARTI_N_STAFFELR4,
ARTI_N_STAFFELR5 = @ARTI_N_STAFFELR5,
ARTI_N_STAFFELP1 = @ARTI_N_STAFFELP1,
ARTI_N_STAFFELP2 = @ARTI_N_STAFFELP2,
ARTI_N_STAFFELP3 = @ARTI_N_STAFFELP3,
ARTI_N_STAFFELP4 = @ARTI_N_STAFFELP4,
ARTI_N_STAFFELP5 = @ARTI_N_STAFFELP5,
ARTI_N_VK1 = @ARTI_N_VK1,
ARTI_N_VK1BRUTTO = @ARTI_N_VK1BRUTTO,
ARTI_N_VK2 = @ARTI_N_VK2,
ARTI_N_VK3 = @ARTI_N_VK3,
ARTI_N_VK4 = @ARTI_N_VK4,
ARTI_N_VK5 = @ARTI_N_VK5,
ARTI_N_WO_KAPAZITAET = @ARTI_N_WO_KAPAZITAET,
ARTI_N_ZOLLTARIF = @ARTI_N_ZOLLTARIF,
WK5_ARTI_N_HOEHE_VERPACKUNG = @WK5_ARTI_N_HOEHE_VERPACKUNG,
WK5_ARTI_N_LAENGE_VERPACKUNG = @WK5_ARTI_N_LAENGE_VERPACKUNG,
WK5_ARTI_N_BREITE_VERPACKUNG = @WK5_ARTI_N_BREITE_VERPACKUNG,
WK5_ARTI_L_ANFRAGEARTIKEL = @WK5_ARTI_L_ANFRAGEARTIKEL,
WK5_ARTI_L_ETIKETTENBRIEF = @WK5_ARTI_L_ETIKETTENBRIEF,
WK5_ARTI_L_AUFGABE_TECHNIK = @WK5_ARTI_L_AUFGABE_TECHNIK,
WK5_ARTI_A_SUCHBEGRIFF = @WK5_ARTI_A_SUCHBEGRIFF,
WK5_ARTI_N_KOSTENSTELLE = @WK5_ARTI_N_KOSTENSTELLE,
WK5_ARTI_L_SUPPORT_AGREEMENT = @WK5_ARTI_L_SUPPORT_AGREEMENT,
WK5_ARTI_D_SUPPORT_VALID_UNTIL = @WK5_ARTI_D_SUPPORT_VALID_UNTIL, 
WK5_ARTI_N_SUPPORT_DOCID = @WK5_ARTI_N_SUPPORT_DOCID,
WK5_ARTI_L_KEIN_TEXT_UPDATE = @WK5_ARTI_L_KEIN_TEXT_UPDATE,
WK5_ARTI_L_KEIN_ZPU = @WK5_ARTI_L_KEIN_ZPU,
WK5_ARTI_N_PRODUKTGEWICHT = @WK5_ARTI_N_PRODUKTGEWICHT,
WK5_ARTI_N_WICHTIGKEIT = @WK5_ARTI_N_WICHTIGKEIT,
WK5_ARTI_N_MUELL_PLASTIK = @WK5_ARTI_N_MUELL_PLASTIK,
WK5_ARTI_N_MUELL_VERBUNDSTOFF = @WK5_ARTI_N_MUELL_VERBUNDSTOFF,
WK5_ARTI_N_MUELL_PAPIER = @WK5_ARTI_N_MUELL_PAPIER,
WK5_ARTI_N_MUELL_ALUMINIUM = @WK5_ARTI_N_MUELL_ALUMINIUM,
WK5_ARTI_L_HAUPTARTIKEL = @WK5_ARTI_L_HAUPTARTIKEL,
WK5_ARTI_N_VIRT_LAGER = @WK5_ARTI_N_VIRT_LAGER,
WK5_ARTI_N_GEBINDE = @WK5_ARTI_N_GEBINDE,
WK5_ARTI_A_HINWEIS = @WK5_ARTI_A_HINWEIS,
WK5_ARTI_N_ANGEBOTVORLAGE = @WK5_ARTI_N_ANGEBOTVORLAGE,
ARTI_N_WARTUNGSINTERVALL = @ARTI_N_WARTUNGSINTERVALL,
ARTI_B_WARTUNGSTEXT = @ARTI_B_WARTUNGSTEXT,
ARTI_N_PREISOPTION_ONLINE = @ARTI_N_PREISOPTION_ONLINE,
ARTI_L_MIETE = @ARTI_L_MIETE,
ARTI_L_BUNDLE = @ARTI_L_BUNDLE,
ARTI_B_PACKTEXT = @ARTI_B_PACKTEXT,
WK5_ARTI_L_KEINE_ELEKTRONIK = @WK5_ARTI_L_KEINE_ELEKTRONIK
    WHERE UPPER(ARTI_A_NR) = @ARTI_A_NR";

            fbController.AddParameter("@ARTI_A_NR", input.Artikelnummer);
            fbController.AddParameter("@ARTI_A_BEZ1", input.Bezeichnung1);
            fbController.AddParameter("@ARTI_A_BEZ2", input.Bezeichnung2);
            fbController.AddParameter("@ARTI_A_BEZ3", input.Bezeichnung3);
            fbController.AddParameter("@ARTI_A_BEZ4", input.Bezeichnung4);
            fbController.AddParameter("@ARTI_A_BEZ5", input.Bezeichnung5);
            fbController.AddParameter("@ARTI_A_BEZETIKETT", input.ARTI_A_BEZETIKETT);
            fbController.AddParameter("@ARTI_A_EAN", input.ARTI_A_EAN);
            fbController.AddParameter("@ARTI_A_EINHEIT", input.ARTI_A_EINHEIT);
            fbController.AddParameter("@ARTI_A_ERSATZART", input.ARTI_A_ERSATZART);
            fbController.AddParameter("@ARTI_A_G_RASTER", input.ARTI_A_G_RASTER);
            fbController.AddParameter("@ARTI_A_HERST_NR", input.Herstellernummer);
            fbController.AddParameter("@ARTI_A_HERSTELLER", input.Hersteller);
            fbController.AddParameter("@ARTI_A_LAGER", input.Lagerplatz);
            fbController.AddParameter("@ARTI_A_LAGER2", input.ARTI_A_LAGER2);
            fbController.AddParameter("@ARTI_A_LAGER3", input.ARTI_A_LAGER3);
            fbController.AddParameter("@ARTI_A_NACHFOLGER", input.ARTI_A_NACHFOLGER);
            fbController.AddParameter("@ARTI_A_POSBEZEICH", input.ARTI_A_POSBEZEICH);
            fbController.AddParameter("@ARTI_A_PREISEINHEIT", input.ARTI_A_PREISEINHEIT);
            fbController.AddParameter("@ARTI_A_PREISGRUPPE", input.Preisgruppe);
            fbController.AddParameter("@ARTI_A_PRODLAGER", input.ARTI_A_PRODLAGER);
            fbController.AddParameter("@ARTI_A_SELEKTION1", input.Selektionsmerkmal1);
            fbController.AddParameter("@ARTI_A_SELEKTION2", input.Selektionsmerkmal2);
            fbController.AddParameter("@ARTI_A_SELEKTION3", input.Selektionsmerkmal3);
            fbController.AddParameter("@ARTI_A_STAFFELWAEHR", input.ARTI_A_STAFFELWAEHR);
            fbController.AddParameter("@ARTI_A_UNTERWARENG", input.Unterwarengruppe);
            fbController.AddParameter("@ARTI_A_URSPRUNGSLAND", input.ARTI_A_URSPRUNGSLAND);
            fbController.AddParameter("@ARTI_A_VORGAENGER", input.ARTI_A_VORGAENGER);
            fbController.AddParameter("@ARTI_A_WARENGRUPPE", input.Warengruppe);
            fbController.AddParameter("@ARTI_B_LANGTEXT", input.Langtext);
            fbController.AddParameter("@ARTI_B_NOTIZ", input.Notiz);
            fbController.AddParameter("@ARTI_D_ERFASSDATUM", input.ARTI_D_ERFASSDATUM);
            fbController.AddParameter("@ARTI_L_ABMASSVERWALTUNG", input.ARTI_L_ABMASSVERWALTUNG);
            fbController.AddParameter("@ARTI_L_ABVERKAUF", input.ARTI_L_ABVERKAUF);
            fbController.AddParameter("@ARTI_L_DIENSTLEIST", input.ARTI_L_DIENSTLEIST);
            fbController.AddParameter("@ARTI_L_ERSATZEIL", input.ARTI_L_ERSATZEIL);
            fbController.AddParameter("@ARTI_L_FAXLISTE", input.ARTI_L_FAXLISTE);
            fbController.AddParameter("@ARTI_L_FERTIGUNG", input.ARTI_L_FERTIGUNG);
            fbController.AddParameter("@ARTI_L_FIXPREIS", input.ARTI_L_FIXPREIS);
            fbController.AddParameter("@ARTI_L_FIXVK3", input.ARTI_L_FIXVK3);
            fbController.AddParameter("@ARTI_L_FIXVK4", input.ARTI_L_FIXVK4);
            fbController.AddParameter("@ARTI_L_FIXVK5", input.ARTI_L_FIXVK5);
            fbController.AddParameter("@ARTI_L_INAKT_ABVER", input.ARTI_L_INAKT_ABVER);
            fbController.AddParameter("@ARTI_L_INAKTIV", input.ARTI_L_INAKTIV);
            fbController.AddParameter("@ARTI_L_INTERNET", input.ARTI_L_INTERNET);
            fbController.AddParameter("@ARTI_L_KAPAZITAET", input.ARTI_L_KAPAZITAET);
            fbController.AddParameter("@ARTI_L_LAGERFUEHR", input.ARTI_L_LAGERFUEHR);
            fbController.AddParameter("@ARTI_L_LANGTEXT_DR", input.ARTI_L_LANGTEXT_DR);
            fbController.AddParameter("@ARTI_L_NICHT_IN_BELEGEN", input.ARTI_L_NICHT_IN_BELEGEN);
            fbController.AddParameter("@ARTI_L_NORMTEIL", input.ARTI_L_NORMTEIL);
            fbController.AddParameter("@ARTI_L_OHNE_DRUCK", input.ARTI_L_OHNE_DRUCK);
            fbController.AddParameter("@ARTI_L_OHNE_PROV", input.ARTI_L_OHNE_PROV);
            fbController.AddParameter("@ARTI_L_PREISLISTE", input.ARTI_L_PREISLISTE);
            fbController.AddParameter("@ARTI_L_PRUEFPLAN", input.ARTI_L_PRUEFPLAN);
            fbController.AddParameter("@ARTI_L_RABATTAUSSCHLUSS", input.ARTI_L_RABATTAUSSCHLUSS);
            fbController.AddParameter("@ARTI_L_RESTEVERWALTUNG", input.ARTI_L_RESTEVERWALTUNG);
            fbController.AddParameter("@ARTI_L_SCHWVERFUEG", input.ARTI_L_SCHWVERFUEG);
            fbController.AddParameter("@ARTI_L_SN", input.ARTI_L_SN);
            fbController.AddParameter("@ARTI_L_SN_ABGANG", input.ARTI_L_SN_ABGANG);
            fbController.AddParameter("@ARTI_L_SN_EINGANG", input.ARTI_L_SN_EINGANG);
            fbController.AddParameter("@ARTI_L_STL_VEREDELUNG", input.ARTI_L_STL_VEREDELUNG);
            fbController.AddParameter("@ARTI_L_VERBRAUCH", input.ARTI_L_VERBRAUCH);
            fbController.AddParameter("@ARTI_L_VERSCHLEISS", input.ARTI_L_VERSCHLEISS);
            fbController.AddParameter("@ARTI_N_BREITE", input.Breite);
            fbController.AddParameter("@ARTI_N_BRUTTO", input.ARTI_N_BRUTTO);
            fbController.AddParameter("@ARTI_N_COLLI", input.ARTI_N_COLLI);
            fbController.AddParameter("@ARTI_N_EK", input.ARTI_N_EK);
            fbController.AddParameter("@ARTI_N_ERLOESKONTO", input.ARTI_N_ERLOESKONTO);
            fbController.AddParameter("@ARTI_N_FLAECHE", input.ARTI_N_FLAECHE);
            fbController.AddParameter("@ARTI_N_GEWICHT", input.ARTI_N_GEWICHT);
            fbController.AddParameter("@ARTI_N_HOEHE", input.ARTI_N_HOEHE);
            fbController.AddParameter("@ARTI_N_LAENGE", input.ARTI_N_LAENGE);
            fbController.AddParameter("@ARTI_N_LASTUSER", input.ARTI_N_LASTUSER);
            fbController.AddParameter("@ARTI_N_MAXBESTAND", input.ARTI_N_MAXBESTAND);
            fbController.AddParameter("@ARTI_N_MAXRABATT", input.ARTI_N_MAXRABATT);
            fbController.AddParameter("@ARTI_N_MINBESTAND", input.Mindestbestand);
            fbController.AddParameter("@ARTI_N_MIND_VK", input.ARTI_N_MIND_VK);
            fbController.AddParameter("@ARTI_N_MINDAUFSCHL", input.ARTI_N_MINDAUFSCHL);
            fbController.AddParameter("@ARTI_N_MWSTKENNUNG", input.ARTI_N_MWSTKENNUNG);
            fbController.AddParameter("@ARTI_N_PREISEINHEITFAKTOR", input.ARTI_N_PREISEINHEITFAKTOR);
            fbController.AddParameter("@ARTI_N_RUECKL_ADR", input.ARTI_N_RUECKL_ADR);
            fbController.AddParameter("@ARTI_N_STAERKE", input.ARTI_N_STAERKE);
            fbController.AddParameter("@ARTI_N_STAFFELM1", input.ARTI_N_STAFFELM1);
            fbController.AddParameter("@ARTI_N_STAFFELM2", input.ARTI_N_STAFFELM2);
            fbController.AddParameter("@ARTI_N_STAFFELM3", input.ARTI_N_STAFFELM3);
            fbController.AddParameter("@ARTI_N_STAFFELM4", input.ARTI_N_STAFFELM4);
            fbController.AddParameter("@ARTI_N_STAFFELM5", input.ARTI_N_STAFFELM5);
            fbController.AddParameter("@ARTI_N_STAFFELR1", input.ARTI_N_STAFFELR1);
            fbController.AddParameter("@ARTI_N_STAFFELR2", input.ARTI_N_STAFFELR2);
            fbController.AddParameter("@ARTI_N_STAFFELR3", input.ARTI_N_STAFFELR3);
            fbController.AddParameter("@ARTI_N_STAFFELR4", input.ARTI_N_STAFFELR4);
            fbController.AddParameter("@ARTI_N_STAFFELR5", input.ARTI_N_STAFFELR5);
            fbController.AddParameter("@ARTI_N_STAFFELP1", input.ARTI_N_STAFFELP1);
            fbController.AddParameter("@ARTI_N_STAFFELP2", input.ARTI_N_STAFFELP2);
            fbController.AddParameter("@ARTI_N_STAFFELP3", input.ARTI_N_STAFFELP3);
            fbController.AddParameter("@ARTI_N_STAFFELP4", input.ARTI_N_STAFFELP4);
            fbController.AddParameter("@ARTI_N_STAFFELP5", input.ARTI_N_STAFFELP5);
            fbController.AddParameter("@ARTI_N_VK1", input.ARTI_N_VK1);
            fbController.AddParameter("@ARTI_N_VK1BRUTTO", input.ARTI_N_VK1BRUTTO);
            fbController.AddParameter("@ARTI_N_VK2", input.ARTI_N_VK2);
            fbController.AddParameter("@ARTI_N_VK3", input.ARTI_N_VK3);
            fbController.AddParameter("@ARTI_N_VK4", input.ARTI_N_VK4);
            fbController.AddParameter("@ARTI_N_VK5", input.ARTI_N_VK5);
            fbController.AddParameter("@ARTI_N_WO_KAPAZITAET", input.ARTI_N_WO_KAPAZITAET);
            fbController.AddParameter("@ARTI_N_ZOLLTARIF", input.ZolltarifId);
            fbController.AddParameter("@WK5_ARTI_N_HOEHE_VERPACKUNG", input.WK5_ARTI_N_HOEHE_VERPACKUNG);
            fbController.AddParameter("@WK5_ARTI_N_LAENGE_VERPACKUNG", input.WK5_ARTI_N_LAENGE_VERPACKUNG);
            fbController.AddParameter("@WK5_ARTI_N_BREITE_VERPACKUNG", input.WK5_ARTI_N_BREITE_VERPACKUNG);
            fbController.AddParameter("@WK5_ARTI_L_ANFRAGEARTIKEL", input.WK5_ARTI_L_ANFRAGEARTIKEL);
            fbController.AddParameter("@WK5_ARTI_L_ETIKETTENBRIEF", input.WK5_ARTI_L_ETIKETTENBRIEF);
            fbController.AddParameter("@WK5_ARTI_L_AUFGABE_TECHNIK", input.WK5_ARTI_L_AUFGABE_TECHNIK);
            fbController.AddParameter("@WK5_ARTI_A_SUCHBEGRIFF", input.WK5_ARTI_A_SUCHBEGRIFF);
            fbController.AddParameter("@WK5_ARTI_N_KOSTENSTELLE", input.WK5_ARTI_N_KOSTENSTELLE);
            fbController.AddParameter("@WK5_ARTI_L_SUPPORT_AGREEMENT", input.WK5_ARTI_L_SUPPORT_AGREEMENT);
            fbController.AddParameter("@WK5_ARTI_D_SUPPORT_VALID_UNTIL", input.WK5_ARTI_D_SUPPORT_VALID_UNTIL);
            fbController.AddParameter("@WK5_ARTI_N_SUPPORT_DOCID", input.WK5_ARTI_N_SUPPORT_DOCID);
            fbController.AddParameter("@WK5_ARTI_L_KEIN_TEXT_UPDATE", input.WK5_ARTI_L_KEIN_TEXT_UPDATE);
            fbController.AddParameter("@WK5_ARTI_L_KEIN_ZPU", input.WK5_ARTI_L_KEIN_ZPU);
            fbController.AddParameter("@WK5_ARTI_N_PRODUKTGEWICHT", input.WK5_ARTI_N_PRODUKTGEWICHT);
            fbController.AddParameter("@WK5_ARTI_N_WICHTIGKEIT", input.WK5_ARTI_N_WICHTIGKEIT);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_PLASTIK", input.WK5_ARTI_N_MUELL_PLASTIK);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_VERBUNDSTOFF", input.WK5_ARTI_N_MUELL_VERBUNDSTOFF);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_PAPIER", input.WK5_ARTI_N_MUELL_PAPIER);
            fbController.AddParameter("@WK5_ARTI_N_MUELL_ALUMINIUM", input.WK5_ARTI_N_MUELL_ALUMINIUM);
            fbController.AddParameter("@WK5_ARTI_L_HAUPTARTIKEL", input.WK5_ARTI_L_HAUPTARTIKEL);
            fbController.AddParameter("@WK5_ARTI_N_VIRT_LAGER", input.WK5_ARTI_N_VIRT_LAGER);
            fbController.AddParameter("@WK5_ARTI_N_GEBINDE", input.WK5_ARTI_N_GEBINDE);
            fbController.AddParameter("@WK5_ARTI_A_HINWEIS", input.WK5_ARTI_A_HINWEIS);
            fbController.AddParameter("@WK5_ARTI_N_ANGEBOTVORLAGE", input.AngebotsnummerVorlage);
            fbController.AddParameter("@ARTI_N_WARTUNGSINTERVALL", input.Wartungsintervall);
            fbController.AddParameter("@ARTI_B_WARTUNGSTEXT", input.WartungsText);
            fbController.AddParameter("@ARTI_N_PREISOPTION_ONLINE", input.PreisoptionOnline);
            fbController.AddParameter("@ARTI_L_MIETE", input.ARTI_L_MIETE);
            fbController.AddParameter("@ARTI_B_PACKTEXT", input.ARTI_B_PACKTEXT);
            fbController.AddParameter("@WK5_ARTI_L_KEINE_ELEKTRONIK", input.WK5_ARTI_L_KEINE_ELEKTRONIK);
            fbController.AddParameter("@ARTI_L_BUNDLE", input.IstBundle);
            await fbController.QueryAsync(sql);
            await SaveBundleAsync(input, fbController);
        }
        /// <summary>
        /// Kopiert einen Artikel in eine neue Artikelnummer
        /// </summary>
        /// <param name="alteArtikelNr">Artikelnummer die kopiert werden soll</param>
        /// <param name="neueArtikelNr">Neue Artikelnummer</param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException"></exception>
        public async Task CopyAsync(string alteArtikelNr, string neueArtikelNr, FbController2 fbController)
        {

            Artikel neuerArtikel = await GetAsync(alteArtikelNr, fbController) ?? throw new NullReferenceException(nameof(neuerArtikel));
            neuerArtikel.Artikelnummer = neueArtikelNr;
            neuerArtikel.Mindestbestand = 0;
            neuerArtikel.Lagerplatz = string.Empty;
            neuerArtikel.AngebotsnummerVorlage = 0;
            neuerArtikel.ARTI_L_INAKTIV = false;
            neuerArtikel.ARTI_L_ABVERKAUF = false;
            neuerArtikel.ARTI_L_INAKT_ABVER = false;
            neuerArtikel.Herstellernummer = string.Empty;
            neuerArtikel.ARTI_A_EAN = string.Empty;
            neuerArtikel.ARTI_A_ERSATZART = string.Empty;

            if (neuerArtikel.ARTI_N_COLLI < 1)
            {
                neuerArtikel.ARTI_N_COLLI = 1;
            }

            if (neuerArtikel.WK5_ARTI_N_GEBINDE < 1)
            {
                neuerArtikel.WK5_ARTI_N_GEBINDE = 1;
            }


            if (!neuerArtikel.ARTI_L_FIXPREIS)
            {
                neuerArtikel.ARTI_N_VK1 = 0;
                neuerArtikel.ARTI_N_VK2 = 0;
                neuerArtikel.ARTI_N_VK3 = 0;
                neuerArtikel.ARTI_N_VK4 = 0;
                neuerArtikel.ARTI_N_VK5 = 0;
            }

            await CreateAsync(neuerArtikel, fbController);

            await foreach (ArtikelBild bild in ArtikelBild.GetBilderAsync(alteArtikelNr))
            {
                bild.ARBI_A_ARTINR = neueArtikelNr;
                await ArtikelBild.CreateAsync(bild, fbController);
            }

            await foreach (ArtikelDokument dokument in ArtikelDokument.GetArtikelDokumenteAsync(alteArtikelNr))
            {
                dokument.ARDI_A_ARTINR = neueArtikelNr;
                await ArtikelDokument.CreateArtikelDokumentAsync(dokument, fbController);
            }
        }
        /// <summary>
        /// Lädt das Bundle für einen Artikel
        /// </summary>
        /// <param name="artikel"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private async Task LadeBundleAsync(Artikel artikel, FbController2 fbController)
        {
            if (!artikel.IstBundle)
            {
                return;
            }

            // Die Spalten werden extra als AS gekennzeichnet, damit eine automatische Zuordnung über ObjectErweiterung möglich ist.
            // Wir laden hier alle Daten, die wir für den Artikel in einem Bundle benötigen
            var bundleArtikel = await fbController.SelectDataAsync<Artikel>(@"SELECT 
A.*,
BUNDLE_N_MENGE,
BUNDLE_N_SORT, 
    ARWE_N_BESTAND,
    ARWE_N_BEDARF,
    ARWE_N_BEDARF_FERT,
    ARWE_N_BEDARF_RUEST,
    ARWE_N_BEDARF_FERT_RUEST,
    ARWE_N_BESTAND_EUR,
    ARWE_N_LAGERUMSCHL,
    ARWE_N_LAGERDAUER,
    ARWE_N_LAGERBESTA,
    ARWE_N_GESABEDARF,
    ARWE_N_OFFBESTELL,
    ARWE_D_LETZBEWEG,
    ARWE_D_LAGERDATUM,
    ARWE_N_LAGMENGDAU,
    ARWE_D_INVENTDATUM,
    ARWE_N_INVENTDIFF,
    ARWE_N_INVENTBEST,
    ARWE_N_INVENTMONEY,
    ARWE_N_LETZTEREK,
    ARWE_D_LETZTEREKDATUM,
    ARWE_N_TIEFSTEREK,
    ARWE_N_HOECHSTEREK,
    ARWE_N_DURCHSCHEK,
    ARWE_N_VKDURCHSCHN,
    ARWE_N_KOMMLAGER,
    MWST_N_NR,
    MWST_N_PROZENT,
    MWST_A_BEMERKUNG,
    MWST_D_GUELTIGAB,
    MWST_N_PROZENTALT,
    0 AS ARTI_N_ANZ_BILDER,
    cast((SELECT MAX(ARBE_TIMESTAMP) from artikelbewegung WHERE arbe_a_artinr = arti_a_nr AND ARBE_A_ART NOT IN ('IN')) as TIMESTAMP) AS LETZTEBEWEGUNG,
    WK5_ARTI_N_GEBINDE,
    (SELECT COALESCE(SUM(CHAR_N_EKPREIS * CHAR_N_MENGEOFFEN) / SUM(CHAR_N_MENGEOFFEN),0) FROM CHARGEN WHERE CHAR_A_ARTINR = a.ARTI_A_NR AND CHAR_N_MENGEOFFEN > 0) AS DURCHSCHNITTSEINKAUFSPREIS
FROM BUNDLES BUN 
INNER JOIN ARTIKEL A ON (A.ARTI_A_NR = BUN.BUNDLE_A_UNTERARTINR)
INNER JOIN ARTIKELWERTE AW ON AW.ARWE_A_NR = A.ARTI_A_NR
LEFT OUTER JOIN MEHRWERTSTEUER m ON m.MWST_N_NR = a.ARTI_N_MWSTKENNUNG
WHERE BUNDLE_A_ARTINR = @ARTIKELNUMMER", new { ARTIKELNUMMER = artikel.Artikelnummer });

            foreach (Artikel bArtikel in bundleArtikel)
            {
                bArtikel.Parent = artikel; // Damit wir auf die Basis zugreifen können 

                if (artikel.Artikelnummer != bArtikel.Artikelnummer)
                {
                    artikel.BundleArtikel.Add(bArtikel);
                }

            }
        }
        /// <summary>
        /// Speichert das Bundle für einen Artikel
        /// </summary>
        /// <param name="input"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        private async Task SaveBundleAsync(Artikel input, FbController2 fbController)
        {
            // Als erstes werden alte Daten bereinigt
            await fbController.QueryDapperAsync("DELETE FROM BUNDLES WHERE BUNDLE_A_ARTINR = @BUNDLE_A_ARTINR", new { BUNDLE_A_ARTINR = input.Artikelnummer });

            // Einfügen
            int zähler = 0;
            foreach (Artikel artikel in input.BundleArtikel)
            {
                zähler++;
                var parameter = new
                {
                    BUNDLE_A_ARTINR = input.Artikelnummer,
                    BUNDLE_A_UNTERARTINR = artikel.Artikelnummer,
                    BUNDLE_N_MENGE = artikel.BUNDLE_N_MENGE,
                    BUNDLE_N_SORT = zähler,
                    BUNDLE_N_LASTUSER = fbController.UserId,
                    BUNDLE_TIMESTAMP = DateTime.Now
                };

                artikel.BUNDLE_N_SORT = zähler;

                await fbController.QueryDapperAsync(@"INSERT INTO BUNDLES 
(
    BUNDLE_A_ARTINR, 
    BUNDLE_A_UNTERARTINR, 
    BUNDLE_N_MENGE, 
    BUNDLE_N_SORT,
    BUNDLE_N_LASTUSER, 
    BUNDLE_TIMESTAMP
)
VALUES 
(
    @BUNDLE_A_ARTINR, 
    @BUNDLE_A_UNTERARTINR, 
    @BUNDLE_N_MENGE,
    @BUNDLE_N_SORT, 
    @BUNDLE_N_LASTUSER, 
    @BUNDLE_TIMESTAMP
)", parameter);
            }
        }
        /// <summary>
        /// Liefert eine Liste aller Artikel zurück, die ein Kunde jemals bestellt hat.
        /// </summary>
        /// <param name="kundennummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Artikel> GetKundenBestellteArtikel(string kundennummer, FbController2 fbController)
        {
            string sql = @"SELECT DISTINCT ARTIKEL.* FROM BELEGE
LEFT JOIN BELEGPOS ON BPOS_N_NR = BELE_N_NR AND BPOS_A_TYP = BELE_A_TYP
LEFT JOIN ARTIKEL ON ARTI_A_NR = BPOS_A_ARTIKELNR
WHERE BELE_A_KUNDENNR = @KUNDENNR
AND COALESCE(ARTI_A_NR,'') <> '' ";
            fbController.AddParameter("@KUNDENNR", kundennummer);

            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                yield return ObjectErweiterung.DataRowZuObjekt(new Artikel(), row);
            }
        }
        /// <summary>
        /// Liefert alle Hauptartikelnummern als string zurück.
        /// </summary>
        /// <returns></returns>
        public async IAsyncEnumerable<string> GetHauptArtikelnummernAsync()
        {
            using FbController2 fbController = new FbController2();
            DataTable data = await fbController.SelectDataAsync("SELECT ARTI_A_NR FROM ARTIKEL WHERE WK5_ARTI_L_HAUPTARTIKEL = 'Y' AND ARTI_L_INAKTIV = 'N'");
            foreach (DataRow row in data.Rows)
            {
                string? nr = row.Field<string>("ARTI_A_NR");
                if (row is not null && !String.IsNullOrWhiteSpace(nr))
                {
                    yield return nr;
                }
            }

        }
        /// <summary>
        /// Liefert alle Hauptartikel als Objekt zurück
        /// </summary>
        /// <returns></returns>
        public async IAsyncEnumerable<Artikel> GetHauptArtikelAsync()
        {
            using FbController2 fbController = new FbController2();
            DataTable data = await fbController.SelectDataAsync("SELECT * FROM ARTIKEL WHERE WK5_ARTI_L_HAUPTARTIKEL = 'Y' AND ARTI_L_INAKTIV = 'N'");
            foreach (DataRow row in data.Rows)
            {
                if (row is not null)
                {
                    Artikel? arti = ObjectErweiterung.DataRowZuObjekt(new Artikel(), row);

                    if (arti is not null)
                    {
                        yield return arti;
                    }
                }
            }

        }
        /// <summary>
        /// Liefert für einen <see cref="ArtikelFilter"/> die Übersicht der Artikel
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<ArtikelÜbersicht> GetArtikelÜbersichtAsync(ArtikelFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            using FbController2 fbController = new FbController2();
            DataTable data = await fbController.SelectDataAsync(filter.ToSqlQuery(fbController));

            foreach (DataRow row in data.Rows)
            {
                yield return ObjectErweiterung.DataRowZuObjekt(new ArtikelÜbersicht(), row);
            }
        }
        /// <summary>
        /// Liefert für einen <see cref="ArtikelFilter"/> die Anzahl aller gefunden Artikel.
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<int> GetArtikelAnzahlAsync(ArtikelFilter filter, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            using FbController2 fbController = new FbController2();

            object? cObj = await fbController.FetchObjectAsync(filter.ToCountQuery(fbController));
            return Convert.ToInt32(cObj);
        }
        /// <summary>
        /// Liefert alle Seriennummern für einen Artikel
        /// </summary>
        /// <param name="artikel"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<Seriennummer> GetSeriennummernAsync(Artikel artikel, FbController2 fbController)
        {
            fbController.AddParameter("@CHAR_A_ARTINR", artikel.Artikelnummer);
            DataTable data = await fbController.SelectDataAsync("SELECT SNNR_A_SN, SNNR_N_CHARGE, CHAR_A_ARTINR, ZUGA_D_DATUM, SNNR_L_AUSGELIEFERT FROM VIEW_SN WHERE CHAR_A_ARTINR = @CHAR_A_ARTINR");

            foreach (DataRow row in data.Rows)
            {
                yield return ObjectErweiterung.DataRowZuObjekt(new Seriennummer(), row);
            }
        }
        /// <summary>
        /// Erhöht die Wichtigkeit für eine Artikelnummer um 1.
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <returns></returns>
        public async Task UpdateWichtigkeitAsync(string artikelnummer)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@INP_ARTIKELNUMMER", artikelnummer);
            await fbController.RunProcedureAsync("UPDATE_WICHTIGKEIT_ARTIKEL");
        }
        /// <summary>
        /// Ruft den bezahlten Bedarf eines Artikel ab.
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <returns></returns>
        public async Task<decimal> GetBedarfBezahlt(string artikelnummer, ZahlungsbedingungCollection zahlungsbedingungen)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@BPOS_A_ARTIKELNR", artikelnummer);
            return Convert.ToDecimal(await fbController.FetchObjectAsync(@$"SELECT CASE WHEN SUM(MENGE) IS NULL THEN 0 ELSE SUM(MENGE) END AS BEDARF FROM ARTIKEL_BEDARF AB 
LEFT JOIN BELEGE B ON (B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = AB.BPOS_N_NR)
WHERE BPOS_A_ARTIKELNR = @BPOS_A_ARTIKELNR
AND 
(
    (B.BELE_N_ZAHLUNG = 2 AND B.BELE_A_GRUPPE = 'ZAHLUNGERHALTEN')
    OR B.BELE_N_ZAHLUNG IN({String.Join(',', zahlungsbedingungen.GetRechnungsUndLastschriftZahlungsbedingungen().Select(x => x.ZABD_N_NR))})
)"));
        }
        /// <summary>
        /// Ruft die Artikeldetails für das Modal in der ARtikelübersicht ab.
        /// </summary>
        /// <param name="ARTI_A_NR"></param>
        /// <returns></returns>
        public async Task<ArtikelDetails?> GetArtikelDetailsAsync(string ARTI_A_NR)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@INP_ARTIKEL", ARTI_A_NR);
            fbController.AddParameter("@INP_ROLLEN", false);
            DataRow? row = await fbController.SelectRowAsync("SELECT * FROM ARTIKEL_LOAD(@INP_ARTIKEL, @INP_ROLLEN)");
            return row == null ? null : ObjectErweiterung.DataRowZuObjekt(new ArtikelDetails(), row);

        }
        /// <summary>
        /// Ruft die Verbrauchsdaten für eine Artikelnummer ab
        /// </summary>
        /// <param name="ARTI_A_NR">Die ARtikelnummer für die nach Verbrauchsdaten gesucht werden soll.</param>
        /// <param name="jahr">Das Jahr für das die Verbrauchsdaten zurückgegeben werden sollen.</param>
        /// <returns></returns>
        public async IAsyncEnumerable<Verbrauchsdaten> GetArtikelVerbrauchsdaten(string ARTI_A_NR, int jahr)
        {
            using FbController2 fbController = new FbController2();
            string sql = "SELECT * FROM VERBRAUCHSDATEN WHERE VERB_A_ARTIKELNR = @ARTIKEL AND VERB_N_JAHR = @JAHR";

            fbController.AddParameter("@ARTIKEL", ARTI_A_NR);
            fbController.AddParameter("@JAHR", jahr);
            DataTable data = await fbController.SelectDataAsync(sql);


            for (int i = 1; i <= 12; i++)
            {
                DataRow? row = data.Rows.Cast<DataRow>().Where(x => x.Field<int>("VERB_N_MONAT") == i).FirstOrDefault();
                if (row is null)
                {
                    yield return new Verbrauchsdaten
                    {
                        Jahr = jahr,
                        Monat = i,
                        Gewinn = 0.0m,
                        Artikelnummer = ARTI_A_NR,
                        Menge = 0.0m,
                        Umsatz = 0.0m
                    };
                }
                else
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new Verbrauchsdaten(), row);
                }
            }
        }
        /// <summary>
        /// Sucht nach Belegpositionen für eine bestimmte Artikelnummer
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<ArtikelBelegpositionenÜbersicht> SucheArtikelBelegpositionen(ArtikelBelegübersichtFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            using FbController2 fbController = new FbController2();
            string sql = filter.ToSqlQuery(fbController);

            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                if (row is not null && !cancellationToken.IsCancellationRequested)
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new ArtikelBelegpositionenÜbersicht(), row);
                }
            }
        }
        /// <summary>
        /// Gibt die Anzahl aller Ergebnisse für <see cref="SucheArtikelBelegpositionen(ArtikelBelegübersichtFilter, CancellationToken)"/> zurück.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public async Task<int> GetAnzahlArtikelBelegpositionen(ArtikelBelegübersichtFilter filter)
        {
            using FbController2 fbController = new FbController2();
            string sql = filter.ToCountQuery(fbController);

            var row = await fbController.SelectRowAsync(sql);

            if (row is null)
            {
                return 0;
            }

            int.TryParse(row["COUNT"].ToString(), out int anzahl);
            return anzahl;
        }

        public async IAsyncEnumerable<ArtikelBestellungenÜbersicht> GetBestellungenÜbersichtAsync(ArtikelBestellungenFilter filter, [EnumeratorCancellation] CancellationToken cancellationToken)
        {
            using FbController2 fbController = new FbController2();
            string sql = filter.ToSqlQuery(fbController);

            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                if (row is not null && !cancellationToken.IsCancellationRequested)
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new ArtikelBestellungenÜbersicht(), row);
                }
            }
        }

        public async Task<int> GetAnzahlArtikelBestellungen(ArtikelBestellungenFilter filter)
        {
            using FbController2 fbController = new FbController2();
            string sql = filter.ToCountQuery(fbController);

            var row = await fbController.SelectRowAsync(sql);

            if (row is null)
            {
                return 0;
            }

            int.TryParse(row["COUNT"].ToString(), out int anzahl);
            return anzahl;
        }
        public async IAsyncEnumerable<ArtikelChargenÜbersicht> GetChargenÜbersichtAsync(string artikelnummer, int limit, int seite, [EnumeratorCancellation] CancellationToken token)
        {
            using FbController2 fbController = new FbController2();
            string sql = @$"SELECT FIRST {limit} SKIP {(seite - 1) * limit} *  FROM ARTIKEL_CHARGEN WHERE CHAR_A_ARTINR = @CHAR_A_ARTINR ORDER BY CHAR_N_NR DESC";
            fbController.AddParameter("@CHAR_A_ARTINR", artikelnummer);
            DataTable data = await fbController.SelectDataAsync(sql);
            foreach (DataRow row in data.Rows)
            {
                if (row is not null && !token.IsCancellationRequested)
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new ArtikelChargenÜbersicht(), row);
                }
            }
        }

        public async Task<int> GetAnzahlArtikelChargen(string artikelnummer)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@CHAR_A_ARTINR", artikelnummer);
            var row = await fbController.SelectRowAsync("SELECT COUNT(*) FROM ARTIKEL_CHARGEN WHERE CHAR_A_ARTINR = @CHAR_A_ARTINR");

            if (row is null)
            {
                return 0;
            }

            int.TryParse(row["COUNT"].ToString(), out int anzahl);
            return anzahl;
        }
        /// <summary>
        /// Ruft die Artikelbewegungen für eine bestimmte Artikelnummer ab
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <param name="limit"></param>
        /// <param name="seite"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<ArtikelBewegungsÜbersicht> GetArtikelBewegungenAsync(string artikelnummer, int limit, int seite, [EnumeratorCancellation] CancellationToken token)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@ARBE_A_ARTINR", artikelnummer);
            DataTable data = await fbController.SelectDataAsync($"SELECT FIRST {limit} SKIP {(seite - 1) * limit} * FROM VIEW_ARTIKELBEWEGUNG WHERE ARBE_A_ARTINR = @ARBE_A_ARTINR  ORDER BY ARBE_TIMESTAMP DESC");
            foreach (DataRow row in data.Rows)
            {
                if (row is not null && !token.IsCancellationRequested)
                {
                    yield return ObjectErweiterung.DataRowZuObjekt(new ArtikelBewegungsÜbersicht(), row);
                }
            }
        }
        /// <summary>
        /// Ruft die Anzahl aller Ergenisse für <see cref="GetArtikelBewegungenAsync(string, int, int, CancellationToken)"/> ab.
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <returns></returns>
        public async Task<int> GetAnzahlArtikelBewegungen(string artikelnummer)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@ARBE_A_ARTINR", artikelnummer);
            var row = await fbController.SelectRowAsync("SELECT COUNT(*) FROM VIEW_ARTIKELBEWEGUNG WHERE ARBE_A_ARTINR = @ARBE_A_ARTINR");

            if (row is null)
            {
                return 0;
            }

            int.TryParse(row["COUNT"].ToString(), out int anzahl);

            return anzahl;
        }
        /// <summary>
        /// Löscht einen Artikel
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task DeleteArtikel(string artikelnummer, FbController2 fbController)
        {
            List<string> queries = new List<string>
            {
                "DELETE FROM ARTIKEL WHERE ARTI_A_NR = @ARTIKEL",
                "DELETE FROM LIEFERANTENARTIKEL WHERE ARLI_A_ARTIKELNR = @ARTIKEL",
                "DELETE FROM WK5_ARTIKELBILDER WHERE ARBI_A_ARTINR = @ARTIKEL",
                "DELETE FROM ARTIKELZUBEHOER WHERE ARZU_A_AUSGANGSART = @ARTIKEL",
                "DELETE FROM ARTIKELWERTE WHERE ARWE_A_NR = @ARTIKEL",
                "DELETE FROM ARTIKELBEWEGUNG WHERE ARBE_A_ARTINR = @ARTIKEL",
                "DELETE FROM WK5_ARTIKELDOKUMENTE WHERE ARDI_A_ARTINR = @ARTIKEL",
                "DELETE FROM WK5_ARTIKELNUMMER_REPLACE WHERE REPLACE_A_UNSERE = @ARTIKEL",
                "DELETE FROM WK5_ARTIKEL_ANGEBOTE WHERE ARAN_A_ARTINR = @ARTIKEL",
                "DELETE FROM WK5_WICHTIGKEIT_ARTIKEL WHERE WICH_A_ARTIKELNR = @ARTIKEL"
            };

            foreach (string query in queries)
            {
                fbController.AddParameter("@ARTIKEL", artikelnummer);
                await fbController.QueryAsync(query);
            }
        }
        /// <summary>
        /// Liefert eine Liste der Belegnummern zurück, für die ein Artikel einen Bedarf hat.
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<int> GetBelegBedarf(string artikelnummer)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@ARTIKEL", artikelnummer);

            DataTable data = await fbController.SelectDataAsync("SELECT DISTINCT BPOS_N_NR FROM ARTIKEL_BEDARF WHERE BPOS_A_ARTIKELNR = @ARTIKEL");

            foreach (DataRow row in data.Rows)
            {
                if (row is not null)
                {
                    yield return row.Field<int>("BPOS_N_NR");
                }
            }


        }
        /// <summary>
        /// Ruft für einen Artikel den derzeiten externen Lagerbestand ab.
        /// <para>
        /// Der externe Lagerbestand setzt sich zusammen aus der Summe des Feldes <see cref="Lieferantenartikel.WK5_ARLI_N_LIEFBESTAND"/> von allen Lieferantenartikeln zusammen.
        /// </para>
        /// </summary>
        /// <param name="artikel"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<decimal> GetExternenBestand(Artikel artikel, FbController2 fbController)
        {
            decimal menge = 0.0m;
            if (artikel.IstBundle)
            {
                menge = Decimal.MaxValue;
                if (artikel.BundleArtikel.Where(x => x.ARTI_L_LAGERFUEHR).Any())
                {
                    foreach (Artikel bundleArtikel in artikel.BundleArtikel)
                    {
                        if (!bundleArtikel.ARTI_L_LAGERFUEHR)
                            continue;
                        decimal tmpMenge = (await this.GetExternenBestand(bundleArtikel, fbController)) / bundleArtikel.BUNDLE_N_MENGE;

                        if (tmpMenge < menge)
                        {
                            menge = tmpMenge;
                        }
                    }
                }
                else
                {
                    return 9999.0m;
                }
            }
            else
            {
                menge = 0.0m;
                await foreach (Lieferantenartikel lfa in Lieferantenartikel.GetLieferantenartikelAsync(artikel.Artikelnummer, fbController))
                {
                    menge += lfa.WK5_ARLI_N_LIEFBESTAND;
                }
            }
            return menge;
        }
        /// <summary>
        /// Ruft eine Liste von Belegnummern ab, für die der Bedarf bereits bezahlt worden ist.
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <param name="zahlungsbedingungen"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<int> GetBelegBedarfBezahltAsync(string artikelnummer, ZahlungsbedingungCollection zahlungsbedingungen)
        {
            using FbController2 fbController = new FbController2();
            fbController.AddParameter("@ARTIKEL", artikelnummer);


            DataTable data = await fbController.SelectDataAsync(@$"SELECT DISTINCT BPOS_N_NR FROM ARTIKEL_BEDARF AB
LEFT JOIN BELEGE B ON(B.BELE_A_TYP = 'AU' AND B.BELE_N_NR = AB.BPOS_N_NR)
WHERE BPOS_A_ARTIKELNR = @ARTIKEL AND
(
    (B.BELE_N_ZAHLUNG = 2 AND B.BELE_A_GRUPPE = 'ZAHLUNGERHALTEN')
    OR B.BELE_N_ZAHLUNG IN({String.Join(',', zahlungsbedingungen.GetRechnungsUndLastschriftZahlungsbedingungen().Select(x => x.ZABD_N_NR))})
)");

            foreach (DataRow row in data.Rows)
            {
                if (row is not null)
                {
                    yield return row.Field<int>("BPOS_N_NR");
                }
            }


        }

        public async IAsyncEnumerable<ArtikelSNVerlauf> FindSN(string partialSN, [EnumeratorCancellation] CancellationToken token)
        {
            using FbController2 fbController = new FbController2();
            string sql = @"SELECT SNNR_A_SN, CHAR_N_STAPELNR, BPOS_N_NR, BPOS_A_TYP, BPOS_A_ARTIKELNR, SNNR_L_AUSGELIEFERT, AUSLIEFERDAT, AUSLIEFKUNDE, ZUGA_D_DATUM, ZUGA_A_RE_NR  FROM VIEW_SN
LEFT JOIN BELEGSN ON BSNR_A_SN = SNNR_A_SN
LEFT JOIN BELEGPOS ON BPOS_N_POSID = BSNR_N_POSID
WHERE UPPER(SNNR_A_SN) LIKE UPPER(@SN)
ORDER BY SNNR_A_SN DESC";
            fbController.AddParameter("@SN", $"%{partialSN}%");

            List<ArtikelSNResult> results = new List<ArtikelSNResult>();

            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                if (!token.IsCancellationRequested)
                {
                    results.Add(ObjectErweiterung.DataRowZuObjekt(new ArtikelSNResult(), row));
                }
            }

            while (results.Count > 0)
            {
                if (token.IsCancellationRequested)
                {
                    break;
                }

                ArtikelSNResult fRes = results[0];
                ArtikelSNVerlauf tmp = new ArtikelSNVerlauf()
                {
                    Seriennummer = fRes.SN,

                };

                foreach (ArtikelSNResult res in results.Where(x => x.SN == fRes.SN).ToList())
                {
                    switch (res.Typ)
                    {
                        case "RE":
                            tmp.Rechnungsnummer = res.Belegnummer;
                            break;
                        case "LS":
                            tmp.Lieferscheinnummer = res.Belegnummer;
                            break;
                        default:
                            break;
                    }

                    if (res.Stapel > 0)
                    {
                        tmp.Zugangsnummer = res.Stapel;
                    }

                    if (res.Auslieferdatum != default)
                    {
                        tmp.Auslieferdatum = res.Auslieferdatum;
                    }

                    if (res.ZugangsDatum != default)
                    {
                        tmp.Zugangsdatum = res.ZugangsDatum;
                    }

                    tmp.Ausgeliefert = res.Ausgeliefert;

                    if (!String.IsNullOrWhiteSpace(res.Kundennummer))
                    {
                        tmp.Kundennummer = res.Kundennummer;
                    }

                    tmp.ZugangsRechnungsNummer = res.ZugangsRechnungsNummer;
                    tmp.Artikelnummer = res.Artikelnummer;

                    results.Remove(res);
                }

                yield return tmp;
            }
        }
        /// <summary>
        /// Ruft den Verlauf aller Seriennummern für einen Artikel ab.
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async IAsyncEnumerable<ArtikelSNVerlauf> GetSNVerlauf(string artikelnummer, [EnumeratorCancellation] CancellationToken token)
        {
            using FbController2 fbController = new FbController2();
            string sql = @"SELECT SNNR_A_SN, CHAR_N_STAPELNR, BPOS_N_NR, BPOS_A_TYP, BPOS_A_ARTIKELNR, SNNR_L_AUSGELIEFERT, AUSLIEFERDAT, AUSLIEFKUNDE, ZUGA_D_DATUM, ZUGA_A_RE_NR  FROM VIEW_SN
LEFT JOIN BELEGSN ON BSNR_A_SN = SNNR_A_SN
LEFT JOIN BELEGPOS ON BPOS_N_POSID = BSNR_N_POSID
WHERE CHAR_A_ARTINR = @ARTIKEL
ORDER BY SNNR_A_SN DESC";
            fbController.AddParameter("@ARTIKEL", artikelnummer);

            List<ArtikelSNResult> results = new List<ArtikelSNResult>();

            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                if (!token.IsCancellationRequested)
                {
                    results.Add(ObjectErweiterung.DataRowZuObjekt(new ArtikelSNResult(), row));
                }
            }

            while (results.Count > 0)
            {
                if (token.IsCancellationRequested)
                {
                    break;
                }

                ArtikelSNResult fRes = results[0];
                ArtikelSNVerlauf tmp = new ArtikelSNVerlauf()
                {
                    Seriennummer = fRes.SN,

                };

                foreach (ArtikelSNResult res in results.Where(x => x.SN == fRes.SN).ToList())
                {
                    switch (res.Typ)
                    {
                        case "RE":
                            tmp.Rechnungsnummer = res.Belegnummer;
                            break;
                        case "LS":
                            tmp.Lieferscheinnummer = res.Belegnummer;
                            break;
                        default:
                            break;
                    }

                    if (res.Stapel > 0)
                    {
                        tmp.Zugangsnummer = res.Stapel;
                    }

                    if (res.Auslieferdatum != default)
                    {
                        tmp.Auslieferdatum = res.Auslieferdatum;
                    }

                    if (res.ZugangsDatum != default)
                    {
                        tmp.Zugangsdatum = res.ZugangsDatum;
                    }

                    tmp.Ausgeliefert = res.Ausgeliefert;

                    if (!String.IsNullOrWhiteSpace(res.Kundennummer))
                    {
                        tmp.Kundennummer = res.Kundennummer;
                    }

                    tmp.ZugangsRechnungsNummer = res.ZugangsRechnungsNummer;
                    tmp.Artikelnummer = res.Artikelnummer;

                    results.Remove(res);
                }

                yield return tmp;
            }
        }

        public async IAsyncEnumerable<ArtikelSNVerlauf> GetKundenSNVerlauf(string kundennr, [EnumeratorCancellation] CancellationToken token)
        {
            using FbController2 fbController = new FbController2();
            string sql = @"SELECT DISTINCT  
SNNR_A_SN, CHAR_N_STAPELNR, BPOS_N_NR, BPOS_A_TYP, BPOS_A_ARTIKELNR, SNNR_L_AUSGELIEFERT, ZUGA_D_DATUM, ZUGA_A_RE_NR, 
iif(SNNR_L_AUSGELIEFERT = 'N',NULL,(select first(1) cast(sh.snhi_timestamp as date)
     from snhistorie sh where sh.snhi_a_sn = SNNR_A_SN and sh.snhi_n_charge = char_n_nr and sh.snhi_n_aenderung < 0 order by sh.snhi_timestamp desc )) AS AUSLIEFERDAT,
   iif(SNNR_L_AUSGELIEFERT = 'N',NULL,(select first(1) be.bele_a_kundennr
     from snhistorie sh left outer join belege be on be.bele_a_typ = sh.snhi_a_beleart and be.bele_n_nr = sh.snhi_n_belenr
     where sh.snhi_a_sn = SNNR_A_SN and sh.snhi_n_charge = char_n_nr and sh.snhi_n_aenderung < 0 order by sh.snhi_timestamp desc )) AS AUSLIEFKUNDE
FROM BELEGSN
LEFT JOIN BELEGPOS ON BPOS_N_POSID = BSNR_N_POSID
LEFT JOIN BELEGE ON BELE_A_TYP = BPOS_A_TYP AND BELE_N_NR = BPOS_N_NR
LEFT JOIN SN ON SNNR_A_SN = BSNR_A_SN
LEFT JOIN CHARGEN ON CHAR_N_NR = SNNR_N_CHARGE
LEFT JOIN ZUGAENGE ON ZUGA_N_NR = CHAR_N_STAPELNR
LEFT JOIN LIEFERANTEN ON LIEF_N_NR = ZUGA_N_LIEF
WHERE BELE_A_KUNDENNR = @KUNDNR
AND COALESCE(BSNR_A_SN,'') != '' AND COALESCE(SNNR_A_SN, '') != ''";
            fbController.AddParameter("@KUNDNR", kundennr);

            List<ArtikelSNResult> results = new List<ArtikelSNResult>();

            DataTable data = await fbController.SelectDataAsync(sql);

            foreach (DataRow row in data.Rows)
            {
                if (!token.IsCancellationRequested)
                {
                    results.Add(ObjectErweiterung.DataRowZuObjekt(new ArtikelSNResult(), row));
                }
            }

            while (results.Count > 0)
            {
                if (token.IsCancellationRequested)
                {
                    break;
                }

                ArtikelSNResult fRes = results[0];
                ArtikelSNVerlauf tmp = new ArtikelSNVerlauf()
                {
                    Seriennummer = fRes.SN,

                };

                foreach (ArtikelSNResult res in results.Where(x => x.SN == fRes.SN).ToList())
                {
                    switch (res.Typ)
                    {
                        case "RE":
                            tmp.Rechnungsnummer = res.Belegnummer;
                            break;
                        case "LS":
                            tmp.Lieferscheinnummer = res.Belegnummer;
                            break;
                        default:
                            break;
                    }

                    if (res.Stapel > 0)
                    {
                        tmp.Zugangsnummer = res.Stapel;
                    }

                    if (res.Auslieferdatum != default)
                    {
                        tmp.Auslieferdatum = res.Auslieferdatum;
                    }

                    if (res.ZugangsDatum != default)
                    {
                        tmp.Zugangsdatum = res.ZugangsDatum;
                    }

                    tmp.Ausgeliefert = res.Ausgeliefert;

                    if (!String.IsNullOrWhiteSpace(res.Kundennummer))
                    {
                        tmp.Kundennummer = res.Kundennummer;
                    }

                    tmp.ZugangsRechnungsNummer = res.ZugangsRechnungsNummer;
                    tmp.Artikelnummer = res.Artikelnummer;

                    results.Remove(res);
                }

                yield return tmp;
            }
        }
        /// <summary>
        /// Aktualisiert den Einkaufspreis für eine bestimmte Artikelnummer
        /// </summary>
        /// <param name="artikelnummer">Die Artikelnummer, für die der Einkaufspreis aktualisiert werden soll.</param>
        /// <param name="einkaufspreis">Der neue Einkaufspreis.</param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task UpdateArtikelEinkaufspreisAsync(string artikelnummer, decimal einkaufspreis, FbController2 fbController)
        {
            fbController.AddParameter("@ARTI_A_NR", artikelnummer);
            fbController.AddParameter("@ARTI_N_EK", einkaufspreis);
            await fbController.QueryAsync("UPDATE ARTIKEL SET ARTI_N_EK = @ARTI_N_EK WHERE ARTI_A_NR = @ARTI_A_NR");
        }
        /// <summary>
        /// Ruft für eine Artikelnummer alle Termine ab.
        /// </summary>
        /// <param name="artikelnummer">Die Artikelnummer, für die Termine geladen werden sollen.</param>
        /// <param name="nurAktuelle">Gibt an, dass nur Termine in der Zukunft geladen werden sollen.</param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public Task<List<Termin>> GetTermineAsync(string artikelnummer, bool nurAktuelle, FbController2 fbController)
        {
            return fbController.SelectDataAsync<Termin>(@$"SELECT BPOS_A_TYP, BPOS_N_NR, BP.BPOS_D_MIETE_START, BP.BPOS_D_MIETE_ENDE 
FROM ARTIKEL 
LEFT JOIN BELEGPOS BP ON (BP.BPOS_A_ARTIKELNR = ARTI_A_NR) 
LEFT JOIN BELEGE B ON (BELE_A_TYP = BPOS_A_TYP AND BELE_N_NR = BPOS_N_NR) 
WHERE ARTI_A_NR = @ARTI_A_NR 
AND BP.BPOS_D_MIETE_START IS NOT NULL AND BP.BPOS_D_MIETE_ENDE IS NOT NULL 
AND BPOS_A_TYP IN ('AN', 'AU', 'LS')
AND 
(
       (BELE_A_TYP = 'AN' AND coalesce(BELE_N_NR_AU, 0) = 0)
    OR (BELE_A_TYP = 'AU' AND coalesce(BELE_N_NR_LS, 0) = 0)
    OR (BELE_A_TYP = 'LS')
)
AND {(nurAktuelle ? "BPOS_D_MIETE_ENDE >= CURRENT_DATE" : "1 = 1")}
ORDER BY BPOS_D_MIETE_START DESC", new { ARTI_A_NR = artikelnummer });
        }

        /// <summary>
        /// Prüft für eine Belegposition, ob der Miettermin noch verfügbar ist.
        /// <para>
        /// Ein Termin ist dann nicht verfügbar, wenn er bereits in einem anderen Auftrag oder Lieferschein vergeben ist.
        /// </para>
        /// <para>
        /// Termine in Angeboten sind nicht blockiert. Hier gilt das Prinzip, wer zuerst kommt, bekommt den Termin.
        /// </para>
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task<bool> IstTerminVerfügbarAsync(Belegposition pos, FbController2 fbController)
        {
            string sql = @"SELECT 1 FROM BELEGPOS
LEFT JOIN BELEGE B ON(BELE_A_TYP = BPOS_A_TYP AND BELE_N_NR = BPOS_N_NR)
WHERE(BPOS_D_MIETE_START BETWEEN @START AND @ENDE OR BPOS_D_MIETE_ENDE BETWEEN @START AND @ENDE)
AND BPOS_A_TYP IN('AU', 'LS')
AND BPOS_A_ARTIKELNR = @BPOS_A_ARTIKELNR";

            if (pos.BPOS_A_TYP is "AU" && pos.BPOS_N_NR is not 0)
            {
                sql += " AND BPOS_N_NR != @BPOS_N_NR AND BELE_N_NR_AU != @BPOS_N_NR";
            }

            if (pos.BPOS_A_TYP is "LS" && pos.BPOS_N_NR is not 0)
            {
                sql += " AND (BPOS_A_TYP != 'LS' AND BPOS_N_NR != @BPOS_N_NR) AND BELE_N_NR_LS != @BPOS_N_NR";
            }

            int tmp = await fbController.SelectRowAsync<int>(sql, new { START = pos.BPOS_D_MIETE_START, ENDE = pos.BPOS_D_MIETE_ENDE, BPOS_N_NR = pos.BPOS_N_NR, BPOS_A_ARTIKELNR = pos.Artikelnummer });

            return tmp != 1;
        }
        /// <summary>
        /// Setzt das Flag WK5_ARTI_L_KEINE_ELEKTRONIK für einen Artikel
        /// </summary>
        /// <param name="artikelnummer"></param>
        /// <param name="gesetzt"></param>
        /// <param name="fbController"></param>
        /// <returns></returns>
        public async Task KeineElektronikFlagSetzenAsync(string artikelnummer, bool gesetzt, FbController2 fbController)
        {
            string sql = "UPDATE ARTIKEL SET WK5_ARTI_L_KEINE_ELEKTRONIK = @KEINE_ELEKTRONIK WHERE ARTI_A_NR = @ARTINR";
            fbController.AddParameter("@KEINE_ELEKTRONIK", gesetzt.ToFirebirdBool());
            fbController.AddParameter("@ARTINR", artikelnummer);

            await fbController.QueryAsync(sql);
        }
        private class ArtikelSNResult
        {
            [CompareField("SNNR_A_SN")]
            public string SN { get; set; }

            [CompareField("CHAR_N_STAPELNR")]
            public int Stapel { get; set; }
            [CompareField("BPOS_N_NR")]
            public int Belegnummer { get; set; }
            [CompareField("BPOS_A_TYP")]
            public string Typ { get; set; }

            [CompareField("SNNR_L_AUSGELIEFERT")]
            public bool Ausgeliefert { get; set; }

            [CompareField("AUSLIEFERDAT")]
            public DateTime Auslieferdatum { get; set; }
            [CompareField("AUSLIEFKUNDE")]
            public string Kundennummer { get; set; }
            [CompareField("ZUGA_D_DATUM")]
            public DateTime ZugangsDatum { get; set; }

            [CompareField("ZUGA_A_RE_NR")]
            public string ZugangsRechnungsNummer { get; set; }
            [CompareField("BPOS_A_ARTIKELNR")]
            public string Artikelnummer { get; set; }
        }
    }

    public class ArtikelBestellungenÜbersicht
    {
        [CompareField("BEPO_N_BESTNR")]
        public int Nummer { get; set; }
        [CompareField("BEPO_N_POS")]
        public int Position { get; set; }
        [CompareField("BEPO_N_MENGE")]
        public decimal Menge { get; set; }
        [CompareField("BEPO_N_LIEFERMENGE")]
        public decimal Geliefert { get; set; }
        [CompareField("BEPO_D_LIEFERDAT")]
        public DateTime Lieferdatum { get; set; }
        [CompareField("BEPO_N_PREIS")]
        public decimal Preis { get; set; }
        [CompareField("BEPO_L_ERLEDIGT")]
        public bool Erledigt { get; set; }
        [CompareField("BEST_N_LIEFNR")]
        public int Lieferantennummer { get; set; }
        [CompareField("LIEF_A_NAME1")]
        public string LieferantenName1 { get; set; }
        [CompareField("BEST_D_DATE")]
        public DateTime BestellDatum { get; set; }
    }

    public class ArtikelBelegpositionenÜbersicht
    {
        [CompareField("BPOS_A_TYP")]
        public string Typ { get; set; }
        [CompareField("BPOS_N_NR")]
        public int Belegnummer { get; set; }
        [CompareField("BELE_D_DATE")]
        public DateTime Datum { get; set; }
        [CompareField("MENGE")]
        public decimal Menge { get; set; }
        [CompareField("BELE_A_KUNDENNR")]
        public string Kundennummer { get; set; }
        [CompareField("BELE_A_NAME1")]
        public string Name1 { get; set; }
        [CompareField("BELE_A_LAND")]
        public string Land { get; set; }
        [CompareField("BELE_A_ORT")]
        public string Ort { get; set; }
        [CompareField("GELIEFERT")]
        public decimal Geliefert { get; set; }
    }

    public class ArtikelLieferantenÜbersicht
    {
        [CompareField("ARLI_N_LIEFNR")]
        public int Lieferantennummer { get; set; }
        [CompareField("LIEF_A_NAME1")]
        public string Lieferantenname { get; set; }
        [CompareField("ARLI_A_BESTELLNR")]
        public string Bestellnummer { get; set; }
        [CompareField("ARLI_N_PREIS")]
        public decimal Preis { get; set; }
        [CompareField("ARLI_N_RABATT")]
        public decimal Rabatt { get; set; }
        [CompareField("ARLI_D_LETZAEND")]
        public DateTime LetzteÄnderung { get; set; }
        [CompareField("WK5_ARLI_N_LIEFBESTAND")]
        public decimal Lieferantenbestand { get; set; }
        [CompareField("ARLI_L_HAUPTLIEFERANT")]
        public bool Hauptlieferant { get; set; }
    }

    public class ArtikelChargenÜbersicht
    {
        [CompareField("CHAR_N_NR")]
        public int Charge { get; set; }
        [CompareField("ZUGA_L_GEBUCHT")]
        public bool Gebucht { get; set; }
        [CompareField("LIEF_N_NR")]
        public int Lieferant { get; set; }
        [CompareField("LIEF_A_NAME1")]
        public string Lieferantenname { get; set; }
        [CompareField("CHAR_N_BESTNR")]
        public int Bestellung { get; set; }
        [CompareField("ZUGA_A_LS_NR")]
        public string Lieferscheinnummer { get; set; }
        [CompareField("ZUGA_D_LS_DATUM")]
        public DateTime LieferscheinVom { get; set; }
        [CompareField("BESTELLDAT")]
        public DateTime BestelltZum { get; set; }
        [CompareField("ZUGA_D_DATUM")]
        public DateTime Datum { get; set; }
        [CompareField("CHAR_N_MENGE")]
        public decimal Menge { get; set; }
        [CompareField("CHAR_N_MENGEOFFEN")]
        public int Offen { get; set; }
        [CompareField("CHAR_N_EKPREIS")]
        public decimal EK { get; set; }
        [CompareField("ZUGA_N_NR")]
        public int Zugangsnummer { get; set; }
        [CompareField("CHAR_N_RABATT1")]
        public decimal Rabatt { get; set; }

    }

    public class ArtikelBewegungsÜbersicht
    {
        [CompareField("ARBE_TIMESTAMP")]
        public DateTime Zeit { get; set; }
        [CompareField("ARBE_A_ART")]
        public string Art { get; set; }
        [CompareField("ARBE_A_BELEG")]
        public string Beleg { get; set; }
        [CompareField("ARBE_A_NOTIZ")]
        public string Info { get; set; }
        [CompareField("ARBE_A_NOTIZ2")]
        public string Info2 { get; set; }
        [CompareField("ARBE_N_CHARGE")]
        public int Charge { get; set; }
        [CompareField("ARBE_N_AENDERUNG")]
        public decimal Änderung { get; set; }
        [CompareField("ARBE_N_BESTAND")]
        public decimal Bestand { get; set; }
        [CompareField("ARBE_N_EKPREIS")]
        public decimal EK { get; set; }
        [CompareField("ARBE_N_EKPREIS_LAG")]
        public decimal EKLager { get; set; }
        [CompareField("PERS_A_USERNAME")]
        public string User { get; set; }

        [CompareField("ZUGA_A_RE_NR")]
        public string Zugangsrechnung { get; set; }
    }

    public class ArtikelSNVerlauf
    {
        public string? Artikelnummer { get; set; }
        public string Seriennummer { get; set; } = String.Empty;
        public int Zugangsnummer { get; set; }
        public int Lieferscheinnummer { get; set; }
        public int Rechnungsnummer { get; set; }
        public bool Ausgeliefert { get; set; }
        public DateTime Auslieferdatum { get; set; }
        public string? Kundennummer { get; set; }
        public DateTime Zugangsdatum { get; set; }
        public string? ZugangsRechnungsNummer { get; set; }
    }
}
