Neu HGB-konforme Stichtagsbewertung inkl. Niederstwertprinzip (JTL-Wawi / MSSQL)

scenix26

Aktives Mitglied
5. Juni 2022
13
5
Hallo zusammen,


ich möchte hier eine SQL-basierte Lösung zur stichtagsbezogenen Lagerbewertung nach HGB teilen, die ich für JTL-Wawi (MSSQL) umgesetzt habe.


Ziel war keine warenwirtschaftliche Bewertung, sondern eine bilanzielle Stichtagsbewertung zur Übergabe an Buchhaltung / Steuerberater.




🎯 Zielsetzung​


  • Bewertung der Lagerbestände zum festen Stichtag
  • HGB-konform nach § 253 HGB
  • Anwendung des strengen Niederstwertprinzips
  • keine pauschalen Altersabschläge
  • keine Rückschreibung in JTL, reine Auswertung



🧠 Bewertungslogik (Kurzfassung)​


Bestand



Summe(Wareneingang) – Summe(Warenausgang bis Stichtag)


Anschaffungskosten (AK)



Summe(Eingangsmenge × EK)
– Summe(Ausgangsmenge × EK)


Marktwert (Vergleichswert)



Bestand × Vergleichspreis (hier: Artikel.fEKNetto)


Bilanzwert (HGB)



MIN(Anschaffungskosten, Marktwert)


➡️ Bewertung erfolgt artikelweise, nicht pauschal.
➡️ Durchschnittsbewertung (keine FIFO-Simulation, HGB-zulässig).




🗂️ Verwendete Tabellen (Auszug)​


  • tWarenLagerEingang
  • tWarenLagerAusgang
  • tArtikel
  • tArtikelBeschreibung
  • tWarenLager
  • tWarenLagerPlatz

Stichtagslogik sauber über:



dErstellt < DATEADD(DAY, 1, @Stichtag)




💶 Wichtiger Hinweis zur Formatierung​


  • Alle Berechnungen erfolgen numerisch (DECIMAL)
  • FORMAT('C','de-DE') ausschließlich in der finalen SELECT-Ausgabe
  • Keine Aggregationen auf formatierten Feldern
    → verhindert Klassiker wie Fehler 8114 nvarchar → numeric



📄 Ausgabe​


  • Bestand
  • Anschaffungskosten (AK)
  • Marktwert
  • HGB-Bilanzwert (Niederstwert)
  • Letztes Lieferdatum
  • Altersklasse (nur Dokumentation, nicht wertrelevant)



⚠️ Abgrenzung​


  • JTL-interne Lagerwerte (GLD etc.) werden bewusst nicht verwendet
  • Das Script dient ausschließlich der Bilanzierung
  • Keine automatische Rückschreibung nach JTL

Grüße

scenix26

SQL:
DECLARE @Stichtag DATE = CONVERT(DATE, '2025-12-31');
DECLARE @warenlager VARCHAR(500) = 'WMS';

SELECT tartikel.cartnr                                              AS
       Artikelnummer,
       Max(tartikelbeschreibung.cname)                              AS
       Artikelname,
       twarenlager.cname                                            AS Lager,
       /* ===== Bestand ===== */
       Cast(Sum(twarenlagereingang.fanzahl) - ( Sum(
            Isnull(Warenausgang.fanzahl, 0.0))
                                              ) AS
            DECIMAL(18, 0))                                         AS Bestand,
       /* ===== Anschaffungskosten (AK) ===== */
       Format(Cast(Round(Sum(twarenlagereingang.fanzahl *
                             twarenlagereingang.fekeinzel)
                         -
                                     Sum(Isnull(Warenausgang.fanzahl, 0.0) *
                                         twarenlagereingang.fekeinzel), 2) AS
                   DECIMAL(
                   18, 2)), 'C', 'de-DE')                           AS
       Anschaffungskosten,
       /* ===== Marktwert ===== */
       Format(Cast(Round(Sum(twarenlagereingang.fanzahl) - Sum(
                                Isnull(Warenausgang.fanzahl, 0.0)),
                               2) AS DECIMAL(18, 2)), 'C', 'de-DE') AS Marktwert
       ,
       /* ===== Niederstwert (HGB) ===== */
       Format(Cast(Round(CASE
                           WHEN ( ( Sum(twarenlagereingang.fanzahl) - Sum(
                                    Isnull(Warenausgang.fanzahl, 0.0)) ) *
                                         Isnull(vk.feknetto, 0) ) < ( Sum(
                                twarenlagereingang.fanzahl *
                                twarenlagereingang.fekeinzel) -
                                   Sum(
                                Isnull(Warenausgang.fanzahl, 0.0) *
                                twarenlagereingang.fekeinzel) )
                         THEN (
                         ( Sum(twarenlagereingang.fanzahl) - Sum(
                           Isnull(Warenausgang.fanzahl, 0.0))
                         ) *
                         Isnull
                         (vk.feknetto, 0) )
                           ELSE ( Sum(twarenlagereingang.fanzahl *
                                      twarenlagereingang.fekeinzel) -
                                         Sum(Isnull(Warenausgang.fanzahl, 0.0) *
                                             twarenlagereingang.fekeinzel) )
                         END, 2) AS DECIMAL(18, 2)), 'C', 'de-DE')  AS
       HGB_Bilanzwert,
       /* ===== Letzter Zugang ===== */
       Max(twarenlagereingang.dgeliefertam)                         AS
       LetztesLieferdatum,
       /* ===== Altersindikator (NICHT wertrelevant) ===== */
       CASE
         WHEN Year(Max(twarenlagereingang.dgeliefertam)) = Year(@Stichtag) THEN
         '0–12 Monate'
         WHEN Year(Max(twarenlagereingang.dgeliefertam)) = Year(@Stichtag) - 1
       THEN
         '13–24 Monate'
         WHEN Year(Max(twarenlagereingang.dgeliefertam)) = Year(@Stichtag) - 2
       THEN
         '25–36 Monate'
         ELSE 'älter als 12 Monate'
       END                                                          AS
       Altersklasse
FROM   dbo.twarenlagereingang
       JOIN dbo.tartikel
         ON twarenlagereingang.kartikel = tartikel.kartikel
       JOIN dbo.tspracheused
         ON nstandard = 1
       JOIN dbo.tartikelbeschreibung
         ON tartikel.kartikel = tartikelbeschreibung.kartikel
            AND tspracheused.ksprache = tartikelbeschreibung.ksprache
            AND tartikelbeschreibung.kplattform = 1
       JOIN dbo.twarenlagerplatz
         ON twarenlagereingang.kwarenlagerplatz =
            twarenlagerplatz.kwarenlagerplatz
       JOIN dbo.twarenlager
         ON twarenlagerplatz.kwarenlager = twarenlager.kwarenlager
       LEFT JOIN tartikel vk
              ON vk.kartikel = tartikel.kartikel
       LEFT JOIN (SELECT twarenlagerausgang.kwarenlagereingang,
                         Sum(twarenlagerausgang.fanzahl) AS fAnzahl
                  FROM   dbo.twarenlagerausgang
                  WHERE  twarenlagerausgang.derstellt <
                         Dateadd(day, 1, @Stichtag)
                  GROUP  BY twarenlagerausgang.kwarenlagereingang) Warenausgang
              ON twarenlagereingang.kwarenlagereingang =
                 Warenausgang.kwarenlagereingang
WHERE  twarenlagereingang.derstellt < Dateadd(day, 1, @Stichtag)
       AND twarenlager.cname = @warenlager
GROUP  BY tartikel.cartnr,
          twarenlager.cname,
          vk.feknetto
HAVING Sum(twarenlagereingang.fanzahl - Isnull(Warenausgang.fanzahl, 0.0)) > 0
ORDER  BY letzteslieferdatum ASC